core/types: optimize modernSigner.Equal (#32971)
Some checks are pending
/ Docker Image (push) Waiting to run
/ Linux Build (push) Waiting to run
/ Linux Build (arm) (push) Waiting to run
/ Keeper Build (push) Waiting to run
/ Windows Build (push) Waiting to run

Equal is called every time the transaction sender is accessed,
even when the sender is cached, so it is worth optimizing.

---------

Co-authored-by: Felix Lange <fjl@twurst.com>
This commit is contained in:
cui 2025-10-27 23:04:06 +08:00 committed by GitHub
parent 447b5f7e19
commit 33dbd64a23
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 34 additions and 11 deletions

View file

@ -20,7 +20,6 @@ import (
"crypto/ecdsa" "crypto/ecdsa"
"errors" "errors"
"fmt" "fmt"
"maps"
"math/big" "math/big"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
@ -183,18 +182,31 @@ type Signer interface {
// modernSigner is the signer implementation that handles non-legacy transaction types. // modernSigner is the signer implementation that handles non-legacy transaction types.
// For legacy transactions, it defers to one of the legacy signers (frontier, homestead, eip155). // For legacy transactions, it defers to one of the legacy signers (frontier, homestead, eip155).
type modernSigner struct { type modernSigner struct {
txtypes map[byte]struct{} txtypes txtypeSet
chainID *big.Int chainID *big.Int
legacy Signer legacy Signer
} }
// txtypeSet is a bitmap for transaction types.
type txtypeSet [2]uint64
func (v *txtypeSet) set(txType byte) {
v[txType/64] |= 1 << (txType % 64)
}
func (v *txtypeSet) has(txType byte) bool {
if txType >= byte(len(v)*64) {
return false
}
return v[txType/64]&(1<<(txType%64)) != 0
}
func newModernSigner(chainID *big.Int, fork forks.Fork) Signer { func newModernSigner(chainID *big.Int, fork forks.Fork) Signer {
if chainID == nil || chainID.Sign() <= 0 { if chainID == nil || chainID.Sign() <= 0 {
panic(fmt.Sprintf("invalid chainID %v", chainID)) panic(fmt.Sprintf("invalid chainID %v", chainID))
} }
s := &modernSigner{ s := &modernSigner{
chainID: chainID, chainID: chainID,
txtypes: make(map[byte]struct{}, 4),
} }
// configure legacy signer // configure legacy signer
switch { switch {
@ -205,19 +217,19 @@ func newModernSigner(chainID *big.Int, fork forks.Fork) Signer {
default: default:
s.legacy = FrontierSigner{} s.legacy = FrontierSigner{}
} }
s.txtypes[LegacyTxType] = struct{}{} s.txtypes.set(LegacyTxType)
// configure tx types // configure tx types
if fork >= forks.Berlin { if fork >= forks.Berlin {
s.txtypes[AccessListTxType] = struct{}{} s.txtypes.set(AccessListTxType)
} }
if fork >= forks.London { if fork >= forks.London {
s.txtypes[DynamicFeeTxType] = struct{}{} s.txtypes.set(DynamicFeeTxType)
} }
if fork >= forks.Cancun { if fork >= forks.Cancun {
s.txtypes[BlobTxType] = struct{}{} s.txtypes.set(BlobTxType)
} }
if fork >= forks.Prague { if fork >= forks.Prague {
s.txtypes[SetCodeTxType] = struct{}{} s.txtypes.set(SetCodeTxType)
} }
return s return s
} }
@ -228,7 +240,7 @@ func (s *modernSigner) ChainID() *big.Int {
func (s *modernSigner) Equal(s2 Signer) bool { func (s *modernSigner) Equal(s2 Signer) bool {
other, ok := s2.(*modernSigner) other, ok := s2.(*modernSigner)
return ok && s.chainID.Cmp(other.chainID) == 0 && maps.Equal(s.txtypes, other.txtypes) && s.legacy.Equal(other.legacy) return ok && s.chainID.Cmp(other.chainID) == 0 && s.txtypes == other.txtypes && s.legacy.Equal(other.legacy)
} }
func (s *modernSigner) Hash(tx *Transaction) common.Hash { func (s *modernSigner) Hash(tx *Transaction) common.Hash {
@ -236,8 +248,7 @@ func (s *modernSigner) Hash(tx *Transaction) common.Hash {
} }
func (s *modernSigner) supportsType(txtype byte) bool { func (s *modernSigner) supportsType(txtype byte) bool {
_, ok := s.txtypes[txtype] return s.txtypes.has(txtype)
return ok
} }
func (s *modernSigner) Sender(tx *Transaction) (common.Address, error) { func (s *modernSigner) Sender(tx *Transaction) (common.Address, error) {

View file

@ -25,6 +25,7 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/params/forks"
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
) )
@ -188,3 +189,14 @@ func createTestLegacyTxInner() *LegacyTx {
Data: nil, Data: nil,
} }
} }
func Benchmark_modernSigner_Equal(b *testing.B) {
signer1 := newModernSigner(big.NewInt(1), forks.Amsterdam)
signer2 := newModernSigner(big.NewInt(1), forks.Amsterdam)
for b.Loop() {
if !signer1.Equal(signer2) {
b.Fatal("expected signers to be equal")
}
}
}