Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

core/types: fix and test handling of faulty nil-returning signer #28879

Merged
merged 1 commit into from
Jan 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions core/types/transaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package types
import (
"bytes"
"errors"
"fmt"
"io"
"math/big"
"sync/atomic"
Expand Down Expand Up @@ -320,6 +321,7 @@ func (tx *Transaction) Cost() *big.Int {

// RawSignatureValues returns the V, R, S signature values of the transaction.
// The return values should not be modified by the caller.
// The return values may be nil or zero, if the transaction is unsigned.
func (tx *Transaction) RawSignatureValues() (v, r, s *big.Int) {
return tx.inner.rawSignatureValues()
}
Expand Down Expand Up @@ -508,6 +510,9 @@ func (tx *Transaction) WithSignature(signer Signer, sig []byte) (*Transaction, e
if err != nil {
return nil, err
}
if r == nil || s == nil || v == nil {
return nil, fmt.Errorf("%w: r: %s, s: %s, v: %s", ErrInvalidSig, r, s, v)
}
cpy := tx.inner.copy()
cpy.setSignatureValues(signer.ChainID(), v, r, s)
return &Transaction{inner: cpy, time: tx.time}, nil
Expand Down
52 changes: 52 additions & 0 deletions core/types/transaction_signing_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,13 @@ package types

import (
"errors"
"fmt"
"math/big"
"testing"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/rlp"
)

Expand Down Expand Up @@ -136,3 +138,53 @@ func TestChainId(t *testing.T) {
t.Error("expected no error")
}
}

type nilSigner struct {
v, r, s *big.Int
Signer
}

func (ns *nilSigner) SignatureValues(tx *Transaction, sig []byte) (r, s, v *big.Int, err error) {
return ns.v, ns.r, ns.s, nil
}

// TestNilSigner ensures a faulty Signer implementation does not result in nil signature values or panics.
func TestNilSigner(t *testing.T) {
key, _ := crypto.GenerateKey()
innerSigner := LatestSignerForChainID(big.NewInt(1))
for i, signer := range []Signer{
&nilSigner{v: nil, r: nil, s: nil, Signer: innerSigner},
&nilSigner{v: big.NewInt(1), r: big.NewInt(1), s: nil, Signer: innerSigner},
&nilSigner{v: big.NewInt(1), r: nil, s: big.NewInt(1), Signer: innerSigner},
&nilSigner{v: nil, r: big.NewInt(1), s: big.NewInt(1), Signer: innerSigner},
} {
t.Run(fmt.Sprintf("signer_%d", i), func(t *testing.T) {
t.Run("legacy", func(t *testing.T) {
legacyTx := createTestLegacyTxInner()
_, err := SignNewTx(key, signer, legacyTx)
if !errors.Is(err, ErrInvalidSig) {
t.Fatal("expected signature values error, no nil result or panic")
}
})
// test Blob tx specifically, since the signature value types changed
t.Run("blobtx", func(t *testing.T) {
blobtx := createEmptyBlobTxInner(false)
_, err := SignNewTx(key, signer, blobtx)
if !errors.Is(err, ErrInvalidSig) {
t.Fatal("expected signature values error, no nil result or panic")
}
})
})
}
}

func createTestLegacyTxInner() *LegacyTx {
return &LegacyTx{
Nonce: uint64(0),
To: nil,
Value: big.NewInt(0),
Gas: params.TxGas,
GasPrice: big.NewInt(params.GWei),
Data: nil,
}
}
9 changes: 7 additions & 2 deletions core/types/tx_blob_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,12 @@ var (
)

func createEmptyBlobTx(key *ecdsa.PrivateKey, withSidecar bool) *Transaction {
blobtx := createEmptyBlobTxInner(withSidecar)
signer := NewCancunSigner(blobtx.ChainID.ToBig())
return MustSignNewTx(key, signer, blobtx)
}

func createEmptyBlobTxInner(withSidecar bool) *BlobTx {
sidecar := &BlobTxSidecar{
Blobs: []kzg4844.Blob{emptyBlob},
Commitments: []kzg4844.Commitment{emptyBlobCommit},
Expand All @@ -85,6 +91,5 @@ func createEmptyBlobTx(key *ecdsa.PrivateKey, withSidecar bool) *Transaction {
if withSidecar {
blobtx.Sidecar = sidecar
}
signer := NewCancunSigner(blobtx.ChainID.ToBig())
return MustSignNewTx(key, signer, blobtx)
return blobtx
}
Loading