Skip to content

Commit 2e947b7

Browse files
authored
core/types: fix and test handling of faulty nil-returning signer (#28879)
This adds an error if the signer returns a nil value for one of the signature value fields.
1 parent bc0b87c commit 2e947b7

File tree

3 files changed

+64
-2
lines changed

3 files changed

+64
-2
lines changed

core/types/transaction.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ package types
1919
import (
2020
"bytes"
2121
"errors"
22+
"fmt"
2223
"io"
2324
"math/big"
2425
"sync/atomic"
@@ -320,6 +321,7 @@ func (tx *Transaction) Cost() *big.Int {
320321

321322
// RawSignatureValues returns the V, R, S signature values of the transaction.
322323
// The return values should not be modified by the caller.
324+
// The return values may be nil or zero, if the transaction is unsigned.
323325
func (tx *Transaction) RawSignatureValues() (v, r, s *big.Int) {
324326
return tx.inner.rawSignatureValues()
325327
}
@@ -508,6 +510,9 @@ func (tx *Transaction) WithSignature(signer Signer, sig []byte) (*Transaction, e
508510
if err != nil {
509511
return nil, err
510512
}
513+
if r == nil || s == nil || v == nil {
514+
return nil, fmt.Errorf("%w: r: %s, s: %s, v: %s", ErrInvalidSig, r, s, v)
515+
}
511516
cpy := tx.inner.copy()
512517
cpy.setSignatureValues(signer.ChainID(), v, r, s)
513518
return &Transaction{inner: cpy, time: tx.time}, nil

core/types/transaction_signing_test.go

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,13 @@ package types
1818

1919
import (
2020
"errors"
21+
"fmt"
2122
"math/big"
2223
"testing"
2324

2425
"github.com/ethereum/go-ethereum/common"
2526
"github.com/ethereum/go-ethereum/crypto"
27+
"github.com/ethereum/go-ethereum/params"
2628
"github.com/ethereum/go-ethereum/rlp"
2729
)
2830

@@ -136,3 +138,53 @@ func TestChainId(t *testing.T) {
136138
t.Error("expected no error")
137139
}
138140
}
141+
142+
type nilSigner struct {
143+
v, r, s *big.Int
144+
Signer
145+
}
146+
147+
func (ns *nilSigner) SignatureValues(tx *Transaction, sig []byte) (r, s, v *big.Int, err error) {
148+
return ns.v, ns.r, ns.s, nil
149+
}
150+
151+
// TestNilSigner ensures a faulty Signer implementation does not result in nil signature values or panics.
152+
func TestNilSigner(t *testing.T) {
153+
key, _ := crypto.GenerateKey()
154+
innerSigner := LatestSignerForChainID(big.NewInt(1))
155+
for i, signer := range []Signer{
156+
&nilSigner{v: nil, r: nil, s: nil, Signer: innerSigner},
157+
&nilSigner{v: big.NewInt(1), r: big.NewInt(1), s: nil, Signer: innerSigner},
158+
&nilSigner{v: big.NewInt(1), r: nil, s: big.NewInt(1), Signer: innerSigner},
159+
&nilSigner{v: nil, r: big.NewInt(1), s: big.NewInt(1), Signer: innerSigner},
160+
} {
161+
t.Run(fmt.Sprintf("signer_%d", i), func(t *testing.T) {
162+
t.Run("legacy", func(t *testing.T) {
163+
legacyTx := createTestLegacyTxInner()
164+
_, err := SignNewTx(key, signer, legacyTx)
165+
if !errors.Is(err, ErrInvalidSig) {
166+
t.Fatal("expected signature values error, no nil result or panic")
167+
}
168+
})
169+
// test Blob tx specifically, since the signature value types changed
170+
t.Run("blobtx", func(t *testing.T) {
171+
blobtx := createEmptyBlobTxInner(false)
172+
_, err := SignNewTx(key, signer, blobtx)
173+
if !errors.Is(err, ErrInvalidSig) {
174+
t.Fatal("expected signature values error, no nil result or panic")
175+
}
176+
})
177+
})
178+
}
179+
}
180+
181+
func createTestLegacyTxInner() *LegacyTx {
182+
return &LegacyTx{
183+
Nonce: uint64(0),
184+
To: nil,
185+
Value: big.NewInt(0),
186+
Gas: params.TxGas,
187+
GasPrice: big.NewInt(params.GWei),
188+
Data: nil,
189+
}
190+
}

core/types/tx_blob_test.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,12 @@ var (
6565
)
6666

6767
func createEmptyBlobTx(key *ecdsa.PrivateKey, withSidecar bool) *Transaction {
68+
blobtx := createEmptyBlobTxInner(withSidecar)
69+
signer := NewCancunSigner(blobtx.ChainID.ToBig())
70+
return MustSignNewTx(key, signer, blobtx)
71+
}
72+
73+
func createEmptyBlobTxInner(withSidecar bool) *BlobTx {
6874
sidecar := &BlobTxSidecar{
6975
Blobs: []kzg4844.Blob{emptyBlob},
7076
Commitments: []kzg4844.Commitment{emptyBlobCommit},
@@ -85,6 +91,5 @@ func createEmptyBlobTx(key *ecdsa.PrivateKey, withSidecar bool) *Transaction {
8591
if withSidecar {
8692
blobtx.Sidecar = sidecar
8793
}
88-
signer := NewCancunSigner(blobtx.ChainID.ToBig())
89-
return MustSignNewTx(key, signer, blobtx)
94+
return blobtx
9095
}

0 commit comments

Comments
 (0)