mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-27 15:16:43 +00:00
Merge branch 'master' into enhance-simulation-api
This commit is contained in:
commit
e7b76daee7
19 changed files with 395 additions and 294 deletions
|
|
@ -102,7 +102,7 @@ func signUnsignedTransactions(txs []*txWithKey, signer types.Signer) (types.Tran
|
||||||
if tx.protected {
|
if tx.protected {
|
||||||
signed, err = types.SignTx(tx.tx, signer, tx.key)
|
signed, err = types.SignTx(tx.tx, signer, tx.key)
|
||||||
} else {
|
} else {
|
||||||
signed, err = types.SignTx(tx.tx, types.FrontierSigner{}, tx.key)
|
signed, err = types.SignTx(tx.tx, types.HomesteadSigner{}, tx.key)
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, NewError(ErrorJson, fmt.Errorf("tx %d: failed to sign tx: %v", i, err))
|
return nil, NewError(ErrorJson, fmt.Errorf("tx %d: failed to sign tx: %v", i, err))
|
||||||
|
|
|
||||||
|
|
@ -1189,8 +1189,7 @@ func (p *BlobPool) Has(hash common.Hash) bool {
|
||||||
return p.lookup.exists(hash)
|
return p.lookup.exists(hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get returns a transaction if it is contained in the pool, or nil otherwise.
|
func (p *BlobPool) getRLP(hash common.Hash) []byte {
|
||||||
func (p *BlobPool) Get(hash common.Hash) *types.Transaction {
|
|
||||||
// Track the amount of time waiting to retrieve a fully resolved blob tx from
|
// Track the amount of time waiting to retrieve a fully resolved blob tx from
|
||||||
// the pool and the amount of time actually spent on pulling the data from disk.
|
// the pool and the amount of time actually spent on pulling the data from disk.
|
||||||
getStart := time.Now()
|
getStart := time.Now()
|
||||||
|
|
@ -1212,14 +1211,31 @@ func (p *BlobPool) Get(hash common.Hash) *types.Transaction {
|
||||||
log.Error("Tracked blob transaction missing from store", "hash", hash, "id", id, "err", err)
|
log.Error("Tracked blob transaction missing from store", "hash", hash, "id", id, "err", err)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get returns a transaction if it is contained in the pool, or nil otherwise.
|
||||||
|
func (p *BlobPool) Get(hash common.Hash) *types.Transaction {
|
||||||
|
data := p.getRLP(hash)
|
||||||
|
if len(data) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
item := new(types.Transaction)
|
item := new(types.Transaction)
|
||||||
if err = rlp.DecodeBytes(data, item); err != nil {
|
if err := rlp.DecodeBytes(data, item); err != nil {
|
||||||
log.Error("Blobs corrupted for traced transaction", "hash", hash, "id", id, "err", err)
|
id, _ := p.lookup.storeidOfTx(hash)
|
||||||
|
|
||||||
|
log.Error("Blobs corrupted for traced transaction",
|
||||||
|
"hash", hash, "id", id, "err", err)
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return item
|
return item
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetRLP returns a RLP-encoded transaction if it is contained in the pool.
|
||||||
|
func (p *BlobPool) GetRLP(hash common.Hash) []byte {
|
||||||
|
return p.getRLP(hash)
|
||||||
|
}
|
||||||
|
|
||||||
// GetBlobs returns a number of blobs are proofs for the given versioned hashes.
|
// GetBlobs returns a number of blobs are proofs for the given versioned hashes.
|
||||||
// This is a utility method for the engine API, enabling consensus clients to
|
// This is a utility method for the engine API, enabling consensus clients to
|
||||||
// retrieve blobs from the pools directly instead of the network.
|
// retrieve blobs from the pools directly instead of the network.
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/log"
|
"github.com/ethereum/go-ethereum/log"
|
||||||
"github.com/ethereum/go-ethereum/metrics"
|
"github.com/ethereum/go-ethereum/metrics"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
"github.com/holiman/uint256"
|
"github.com/holiman/uint256"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -1010,6 +1011,20 @@ func (pool *LegacyPool) get(hash common.Hash) *types.Transaction {
|
||||||
return pool.all.Get(hash)
|
return pool.all.Get(hash)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetRLP returns a RLP-encoded transaction if it is contained in the pool.
|
||||||
|
func (pool *LegacyPool) GetRLP(hash common.Hash) []byte {
|
||||||
|
tx := pool.all.Get(hash)
|
||||||
|
if tx == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
encoded, err := rlp.EncodeToBytes(tx)
|
||||||
|
if err != nil {
|
||||||
|
log.Error("Failed to encoded transaction in legacy pool", "hash", hash, "err", err)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
return encoded
|
||||||
|
}
|
||||||
|
|
||||||
// GetBlobs is not supported by the legacy transaction pool, it is just here to
|
// GetBlobs is not supported by the legacy transaction pool, it is just here to
|
||||||
// implement the txpool.SubPool interface.
|
// implement the txpool.SubPool interface.
|
||||||
func (pool *LegacyPool) GetBlobs(vhashes []common.Hash) ([]*kzg4844.Blob, []*kzg4844.Proof) {
|
func (pool *LegacyPool) GetBlobs(vhashes []common.Hash) ([]*kzg4844.Blob, []*kzg4844.Proof) {
|
||||||
|
|
|
||||||
|
|
@ -124,6 +124,9 @@ type SubPool interface {
|
||||||
// Get returns a transaction if it is contained in the pool, or nil otherwise.
|
// Get returns a transaction if it is contained in the pool, or nil otherwise.
|
||||||
Get(hash common.Hash) *types.Transaction
|
Get(hash common.Hash) *types.Transaction
|
||||||
|
|
||||||
|
// GetRLP returns a RLP-encoded transaction if it is contained in the pool.
|
||||||
|
GetRLP(hash common.Hash) []byte
|
||||||
|
|
||||||
// GetBlobs returns a number of blobs are proofs for the given versioned hashes.
|
// GetBlobs returns a number of blobs are proofs for the given versioned hashes.
|
||||||
// This is a utility method for the engine API, enabling consensus clients to
|
// This is a utility method for the engine API, enabling consensus clients to
|
||||||
// retrieve blobs from the pools directly instead of the network.
|
// retrieve blobs from the pools directly instead of the network.
|
||||||
|
|
|
||||||
|
|
@ -309,6 +309,17 @@ func (p *TxPool) Get(hash common.Hash) *types.Transaction {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetRLP returns a RLP-encoded transaction if it is contained in the pool.
|
||||||
|
func (p *TxPool) GetRLP(hash common.Hash) []byte {
|
||||||
|
for _, subpool := range p.subpools {
|
||||||
|
encoded := subpool.GetRLP(hash)
|
||||||
|
if len(encoded) != 0 {
|
||||||
|
return encoded
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// GetBlobs returns a number of blobs are proofs for the given versioned hashes.
|
// GetBlobs returns a number of blobs are proofs for the given versioned hashes.
|
||||||
// This is a utility method for the engine API, enabling consensus clients to
|
// This is a utility method for the engine API, enabling consensus clients to
|
||||||
// retrieve blobs from the pools directly instead of the network.
|
// retrieve blobs from the pools directly instead of the network.
|
||||||
|
|
|
||||||
|
|
@ -100,6 +100,9 @@ type TxData interface {
|
||||||
|
|
||||||
encode(*bytes.Buffer) error
|
encode(*bytes.Buffer) error
|
||||||
decode([]byte) error
|
decode([]byte) error
|
||||||
|
|
||||||
|
// sigHash returns the hash of the transaction that is ought to be signed
|
||||||
|
sigHash(*big.Int) common.Hash
|
||||||
}
|
}
|
||||||
|
|
||||||
// EncodeRLP implements rlp.Encoder
|
// EncodeRLP implements rlp.Encoder
|
||||||
|
|
|
||||||
|
|
@ -20,11 +20,13 @@ 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"
|
||||||
"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"
|
||||||
)
|
)
|
||||||
|
|
||||||
var ErrInvalidChainId = errors.New("invalid chain id for signer")
|
var ErrInvalidChainId = errors.New("invalid chain id for signer")
|
||||||
|
|
@ -178,7 +180,101 @@ type Signer interface {
|
||||||
Equal(Signer) bool
|
Equal(Signer) bool
|
||||||
}
|
}
|
||||||
|
|
||||||
type pragueSigner struct{ cancunSigner }
|
// 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).
|
||||||
|
type modernSigner struct {
|
||||||
|
txtypes map[byte]struct{}
|
||||||
|
chainID *big.Int
|
||||||
|
legacy Signer
|
||||||
|
}
|
||||||
|
|
||||||
|
func newModernSigner(chainID *big.Int, fork forks.Fork) Signer {
|
||||||
|
if chainID == nil || chainID.Sign() <= 0 {
|
||||||
|
panic(fmt.Sprintf("invalid chainID %v", chainID))
|
||||||
|
}
|
||||||
|
s := &modernSigner{
|
||||||
|
chainID: chainID,
|
||||||
|
txtypes: make(map[byte]struct{}, 4),
|
||||||
|
}
|
||||||
|
// configure legacy signer
|
||||||
|
switch {
|
||||||
|
case fork >= forks.SpuriousDragon:
|
||||||
|
s.legacy = NewEIP155Signer(chainID)
|
||||||
|
case fork >= forks.Homestead:
|
||||||
|
s.legacy = HomesteadSigner{}
|
||||||
|
default:
|
||||||
|
s.legacy = FrontierSigner{}
|
||||||
|
}
|
||||||
|
s.txtypes[LegacyTxType] = struct{}{}
|
||||||
|
// configure tx types
|
||||||
|
if fork >= forks.Berlin {
|
||||||
|
s.txtypes[AccessListTxType] = struct{}{}
|
||||||
|
}
|
||||||
|
if fork >= forks.London {
|
||||||
|
s.txtypes[DynamicFeeTxType] = struct{}{}
|
||||||
|
}
|
||||||
|
if fork >= forks.Cancun {
|
||||||
|
s.txtypes[BlobTxType] = struct{}{}
|
||||||
|
}
|
||||||
|
if fork >= forks.Prague {
|
||||||
|
s.txtypes[SetCodeTxType] = struct{}{}
|
||||||
|
}
|
||||||
|
return s
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *modernSigner) ChainID() *big.Int {
|
||||||
|
return s.chainID
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *modernSigner) Equal(s2 Signer) bool {
|
||||||
|
other, ok := s2.(*modernSigner)
|
||||||
|
return ok && s.chainID.Cmp(other.chainID) == 0 && maps.Equal(s.txtypes, other.txtypes) && s.legacy.Equal(other.legacy)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *modernSigner) Hash(tx *Transaction) common.Hash {
|
||||||
|
return tx.inner.sigHash(s.chainID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *modernSigner) supportsType(txtype byte) bool {
|
||||||
|
_, ok := s.txtypes[txtype]
|
||||||
|
return ok
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *modernSigner) Sender(tx *Transaction) (common.Address, error) {
|
||||||
|
tt := tx.Type()
|
||||||
|
if !s.supportsType(tt) {
|
||||||
|
return common.Address{}, ErrTxTypeNotSupported
|
||||||
|
}
|
||||||
|
if tt == LegacyTxType {
|
||||||
|
return s.legacy.Sender(tx)
|
||||||
|
}
|
||||||
|
if tx.ChainId().Cmp(s.chainID) != 0 {
|
||||||
|
return common.Address{}, fmt.Errorf("%w: have %d want %d", ErrInvalidChainId, tx.ChainId(), s.chainID)
|
||||||
|
}
|
||||||
|
// 'modern' txs are defined to use 0 and 1 as their recovery
|
||||||
|
// id, add 27 to become equivalent to unprotected Homestead signatures.
|
||||||
|
V, R, S := tx.RawSignatureValues()
|
||||||
|
V = new(big.Int).Add(V, big.NewInt(27))
|
||||||
|
return recoverPlain(s.Hash(tx), R, S, V, true)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *modernSigner) SignatureValues(tx *Transaction, sig []byte) (R, S, V *big.Int, err error) {
|
||||||
|
tt := tx.Type()
|
||||||
|
if !s.supportsType(tt) {
|
||||||
|
return nil, nil, nil, ErrTxTypeNotSupported
|
||||||
|
}
|
||||||
|
if tt == LegacyTxType {
|
||||||
|
return s.legacy.SignatureValues(tx, sig)
|
||||||
|
}
|
||||||
|
// Check that chain ID of tx matches the signer. We also accept ID zero here,
|
||||||
|
// because it indicates that the chain ID was not specified in the tx.
|
||||||
|
if tx.inner.chainID().Sign() != 0 && tx.inner.chainID().Cmp(s.chainID) != 0 {
|
||||||
|
return nil, nil, nil, fmt.Errorf("%w: have %d want %d", ErrInvalidChainId, tx.inner.chainID(), s.chainID)
|
||||||
|
}
|
||||||
|
R, S, _ = decodeSignature(sig)
|
||||||
|
V = big.NewInt(int64(sig[64]))
|
||||||
|
return R, S, V, nil
|
||||||
|
}
|
||||||
|
|
||||||
// NewPragueSigner returns a signer that accepts
|
// NewPragueSigner returns a signer that accepts
|
||||||
// - EIP-7702 set code transactions
|
// - EIP-7702 set code transactions
|
||||||
|
|
@ -188,69 +284,9 @@ type pragueSigner struct{ cancunSigner }
|
||||||
// - EIP-155 replay protected transactions, and
|
// - EIP-155 replay protected transactions, and
|
||||||
// - legacy Homestead transactions.
|
// - legacy Homestead transactions.
|
||||||
func NewPragueSigner(chainId *big.Int) Signer {
|
func NewPragueSigner(chainId *big.Int) Signer {
|
||||||
signer, _ := NewCancunSigner(chainId).(cancunSigner)
|
return newModernSigner(chainId, forks.Prague)
|
||||||
return pragueSigner{signer}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s pragueSigner) Sender(tx *Transaction) (common.Address, error) {
|
|
||||||
if tx.Type() != SetCodeTxType {
|
|
||||||
return s.cancunSigner.Sender(tx)
|
|
||||||
}
|
|
||||||
V, R, S := tx.RawSignatureValues()
|
|
||||||
|
|
||||||
// Set code txs are defined to use 0 and 1 as their recovery
|
|
||||||
// id, add 27 to become equivalent to unprotected Homestead signatures.
|
|
||||||
V = new(big.Int).Add(V, big.NewInt(27))
|
|
||||||
if tx.ChainId().Cmp(s.chainId) != 0 {
|
|
||||||
return common.Address{}, fmt.Errorf("%w: have %d want %d", ErrInvalidChainId, tx.ChainId(), s.chainId)
|
|
||||||
}
|
|
||||||
return recoverPlain(s.Hash(tx), R, S, V, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s pragueSigner) Equal(s2 Signer) bool {
|
|
||||||
x, ok := s2.(pragueSigner)
|
|
||||||
return ok && x.chainId.Cmp(s.chainId) == 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s pragueSigner) SignatureValues(tx *Transaction, sig []byte) (R, S, V *big.Int, err error) {
|
|
||||||
txdata, ok := tx.inner.(*SetCodeTx)
|
|
||||||
if !ok {
|
|
||||||
return s.cancunSigner.SignatureValues(tx, sig)
|
|
||||||
}
|
|
||||||
// Check that chain ID of tx matches the signer. We also accept ID zero here,
|
|
||||||
// because it indicates that the chain ID was not specified in the tx.
|
|
||||||
if txdata.ChainID.Sign() != 0 && txdata.ChainID.CmpBig(s.chainId) != 0 {
|
|
||||||
return nil, nil, nil, fmt.Errorf("%w: have %d want %d", ErrInvalidChainId, txdata.ChainID, s.chainId)
|
|
||||||
}
|
|
||||||
R, S, _ = decodeSignature(sig)
|
|
||||||
V = big.NewInt(int64(sig[64]))
|
|
||||||
return R, S, V, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hash returns the hash to be signed by the sender.
|
|
||||||
// It does not uniquely identify the transaction.
|
|
||||||
func (s pragueSigner) Hash(tx *Transaction) common.Hash {
|
|
||||||
if tx.Type() != SetCodeTxType {
|
|
||||||
return s.cancunSigner.Hash(tx)
|
|
||||||
}
|
|
||||||
return prefixedRlpHash(
|
|
||||||
tx.Type(),
|
|
||||||
[]interface{}{
|
|
||||||
s.chainId,
|
|
||||||
tx.Nonce(),
|
|
||||||
tx.GasTipCap(),
|
|
||||||
tx.GasFeeCap(),
|
|
||||||
tx.Gas(),
|
|
||||||
tx.To(),
|
|
||||||
tx.Value(),
|
|
||||||
tx.Data(),
|
|
||||||
tx.AccessList(),
|
|
||||||
tx.SetCodeAuthorizations(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
type cancunSigner struct{ londonSigner }
|
|
||||||
|
|
||||||
// NewCancunSigner returns a signer that accepts
|
// NewCancunSigner returns a signer that accepts
|
||||||
// - EIP-4844 blob transactions
|
// - EIP-4844 blob transactions
|
||||||
// - EIP-1559 dynamic fee transactions
|
// - EIP-1559 dynamic fee transactions
|
||||||
|
|
@ -258,215 +294,27 @@ type cancunSigner struct{ londonSigner }
|
||||||
// - EIP-155 replay protected transactions, and
|
// - EIP-155 replay protected transactions, and
|
||||||
// - legacy Homestead transactions.
|
// - legacy Homestead transactions.
|
||||||
func NewCancunSigner(chainId *big.Int) Signer {
|
func NewCancunSigner(chainId *big.Int) Signer {
|
||||||
return cancunSigner{londonSigner{eip2930Signer{NewEIP155Signer(chainId)}}}
|
return newModernSigner(chainId, forks.Cancun)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s cancunSigner) Sender(tx *Transaction) (common.Address, error) {
|
|
||||||
if tx.Type() != BlobTxType {
|
|
||||||
return s.londonSigner.Sender(tx)
|
|
||||||
}
|
|
||||||
V, R, S := tx.RawSignatureValues()
|
|
||||||
// Blob txs are defined to use 0 and 1 as their recovery
|
|
||||||
// id, add 27 to become equivalent to unprotected Homestead signatures.
|
|
||||||
V = new(big.Int).Add(V, big.NewInt(27))
|
|
||||||
if tx.ChainId().Cmp(s.chainId) != 0 {
|
|
||||||
return common.Address{}, fmt.Errorf("%w: have %d want %d", ErrInvalidChainId, tx.ChainId(), s.chainId)
|
|
||||||
}
|
|
||||||
return recoverPlain(s.Hash(tx), R, S, V, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s cancunSigner) Equal(s2 Signer) bool {
|
|
||||||
x, ok := s2.(cancunSigner)
|
|
||||||
return ok && x.chainId.Cmp(s.chainId) == 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s cancunSigner) SignatureValues(tx *Transaction, sig []byte) (R, S, V *big.Int, err error) {
|
|
||||||
txdata, ok := tx.inner.(*BlobTx)
|
|
||||||
if !ok {
|
|
||||||
return s.londonSigner.SignatureValues(tx, sig)
|
|
||||||
}
|
|
||||||
// Check that chain ID of tx matches the signer. We also accept ID zero here,
|
|
||||||
// because it indicates that the chain ID was not specified in the tx.
|
|
||||||
if txdata.ChainID.Sign() != 0 && txdata.ChainID.CmpBig(s.chainId) != 0 {
|
|
||||||
return nil, nil, nil, fmt.Errorf("%w: have %d want %d", ErrInvalidChainId, txdata.ChainID, s.chainId)
|
|
||||||
}
|
|
||||||
R, S, _ = decodeSignature(sig)
|
|
||||||
V = big.NewInt(int64(sig[64]))
|
|
||||||
return R, S, V, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hash returns the hash to be signed by the sender.
|
|
||||||
// It does not uniquely identify the transaction.
|
|
||||||
func (s cancunSigner) Hash(tx *Transaction) common.Hash {
|
|
||||||
if tx.Type() != BlobTxType {
|
|
||||||
return s.londonSigner.Hash(tx)
|
|
||||||
}
|
|
||||||
return prefixedRlpHash(
|
|
||||||
tx.Type(),
|
|
||||||
[]interface{}{
|
|
||||||
s.chainId,
|
|
||||||
tx.Nonce(),
|
|
||||||
tx.GasTipCap(),
|
|
||||||
tx.GasFeeCap(),
|
|
||||||
tx.Gas(),
|
|
||||||
tx.To(),
|
|
||||||
tx.Value(),
|
|
||||||
tx.Data(),
|
|
||||||
tx.AccessList(),
|
|
||||||
tx.BlobGasFeeCap(),
|
|
||||||
tx.BlobHashes(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
type londonSigner struct{ eip2930Signer }
|
|
||||||
|
|
||||||
// NewLondonSigner returns a signer that accepts
|
// NewLondonSigner returns a signer that accepts
|
||||||
// - EIP-1559 dynamic fee transactions
|
// - EIP-1559 dynamic fee transactions
|
||||||
// - EIP-2930 access list transactions,
|
// - EIP-2930 access list transactions,
|
||||||
// - EIP-155 replay protected transactions, and
|
// - EIP-155 replay protected transactions, and
|
||||||
// - legacy Homestead transactions.
|
// - legacy Homestead transactions.
|
||||||
func NewLondonSigner(chainId *big.Int) Signer {
|
func NewLondonSigner(chainId *big.Int) Signer {
|
||||||
return londonSigner{eip2930Signer{NewEIP155Signer(chainId)}}
|
return newModernSigner(chainId, forks.London)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s londonSigner) Sender(tx *Transaction) (common.Address, error) {
|
|
||||||
if tx.Type() != DynamicFeeTxType {
|
|
||||||
return s.eip2930Signer.Sender(tx)
|
|
||||||
}
|
|
||||||
V, R, S := tx.RawSignatureValues()
|
|
||||||
// DynamicFee txs are defined to use 0 and 1 as their recovery
|
|
||||||
// id, add 27 to become equivalent to unprotected Homestead signatures.
|
|
||||||
V = new(big.Int).Add(V, big.NewInt(27))
|
|
||||||
if tx.ChainId().Cmp(s.chainId) != 0 {
|
|
||||||
return common.Address{}, fmt.Errorf("%w: have %d want %d", ErrInvalidChainId, tx.ChainId(), s.chainId)
|
|
||||||
}
|
|
||||||
return recoverPlain(s.Hash(tx), R, S, V, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s londonSigner) Equal(s2 Signer) bool {
|
|
||||||
x, ok := s2.(londonSigner)
|
|
||||||
return ok && x.chainId.Cmp(s.chainId) == 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s londonSigner) SignatureValues(tx *Transaction, sig []byte) (R, S, V *big.Int, err error) {
|
|
||||||
txdata, ok := tx.inner.(*DynamicFeeTx)
|
|
||||||
if !ok {
|
|
||||||
return s.eip2930Signer.SignatureValues(tx, sig)
|
|
||||||
}
|
|
||||||
// Check that chain ID of tx matches the signer. We also accept ID zero here,
|
|
||||||
// because it indicates that the chain ID was not specified in the tx.
|
|
||||||
if txdata.ChainID.Sign() != 0 && txdata.ChainID.Cmp(s.chainId) != 0 {
|
|
||||||
return nil, nil, nil, fmt.Errorf("%w: have %d want %d", ErrInvalidChainId, txdata.ChainID, s.chainId)
|
|
||||||
}
|
|
||||||
R, S, _ = decodeSignature(sig)
|
|
||||||
V = big.NewInt(int64(sig[64]))
|
|
||||||
return R, S, V, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hash returns the hash to be signed by the sender.
|
|
||||||
// It does not uniquely identify the transaction.
|
|
||||||
func (s londonSigner) Hash(tx *Transaction) common.Hash {
|
|
||||||
if tx.Type() != DynamicFeeTxType {
|
|
||||||
return s.eip2930Signer.Hash(tx)
|
|
||||||
}
|
|
||||||
return prefixedRlpHash(
|
|
||||||
tx.Type(),
|
|
||||||
[]interface{}{
|
|
||||||
s.chainId,
|
|
||||||
tx.Nonce(),
|
|
||||||
tx.GasTipCap(),
|
|
||||||
tx.GasFeeCap(),
|
|
||||||
tx.Gas(),
|
|
||||||
tx.To(),
|
|
||||||
tx.Value(),
|
|
||||||
tx.Data(),
|
|
||||||
tx.AccessList(),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
type eip2930Signer struct{ EIP155Signer }
|
|
||||||
|
|
||||||
// NewEIP2930Signer returns a signer that accepts EIP-2930 access list transactions,
|
// NewEIP2930Signer returns a signer that accepts EIP-2930 access list transactions,
|
||||||
// EIP-155 replay protected transactions, and legacy Homestead transactions.
|
// EIP-155 replay protected transactions, and legacy Homestead transactions.
|
||||||
func NewEIP2930Signer(chainId *big.Int) Signer {
|
func NewEIP2930Signer(chainId *big.Int) Signer {
|
||||||
return eip2930Signer{NewEIP155Signer(chainId)}
|
return newModernSigner(chainId, forks.Berlin)
|
||||||
}
|
|
||||||
|
|
||||||
func (s eip2930Signer) ChainID() *big.Int {
|
|
||||||
return s.chainId
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s eip2930Signer) Equal(s2 Signer) bool {
|
|
||||||
x, ok := s2.(eip2930Signer)
|
|
||||||
return ok && x.chainId.Cmp(s.chainId) == 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s eip2930Signer) Sender(tx *Transaction) (common.Address, error) {
|
|
||||||
V, R, S := tx.RawSignatureValues()
|
|
||||||
switch tx.Type() {
|
|
||||||
case LegacyTxType:
|
|
||||||
return s.EIP155Signer.Sender(tx)
|
|
||||||
case AccessListTxType:
|
|
||||||
// AL txs are defined to use 0 and 1 as their recovery
|
|
||||||
// id, add 27 to become equivalent to unprotected Homestead signatures.
|
|
||||||
V = new(big.Int).Add(V, big.NewInt(27))
|
|
||||||
default:
|
|
||||||
return common.Address{}, ErrTxTypeNotSupported
|
|
||||||
}
|
|
||||||
if tx.ChainId().Cmp(s.chainId) != 0 {
|
|
||||||
return common.Address{}, fmt.Errorf("%w: have %d want %d", ErrInvalidChainId, tx.ChainId(), s.chainId)
|
|
||||||
}
|
|
||||||
return recoverPlain(s.Hash(tx), R, S, V, true)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s eip2930Signer) SignatureValues(tx *Transaction, sig []byte) (R, S, V *big.Int, err error) {
|
|
||||||
switch txdata := tx.inner.(type) {
|
|
||||||
case *LegacyTx:
|
|
||||||
return s.EIP155Signer.SignatureValues(tx, sig)
|
|
||||||
case *AccessListTx:
|
|
||||||
// Check that chain ID of tx matches the signer. We also accept ID zero here,
|
|
||||||
// because it indicates that the chain ID was not specified in the tx.
|
|
||||||
if txdata.ChainID.Sign() != 0 && txdata.ChainID.Cmp(s.chainId) != 0 {
|
|
||||||
return nil, nil, nil, fmt.Errorf("%w: have %d want %d", ErrInvalidChainId, txdata.ChainID, s.chainId)
|
|
||||||
}
|
|
||||||
R, S, _ = decodeSignature(sig)
|
|
||||||
V = big.NewInt(int64(sig[64]))
|
|
||||||
default:
|
|
||||||
return nil, nil, nil, ErrTxTypeNotSupported
|
|
||||||
}
|
|
||||||
return R, S, V, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hash returns the hash to be signed by the sender.
|
|
||||||
// It does not uniquely identify the transaction.
|
|
||||||
func (s eip2930Signer) Hash(tx *Transaction) common.Hash {
|
|
||||||
switch tx.Type() {
|
|
||||||
case LegacyTxType:
|
|
||||||
return s.EIP155Signer.Hash(tx)
|
|
||||||
case AccessListTxType:
|
|
||||||
return prefixedRlpHash(
|
|
||||||
tx.Type(),
|
|
||||||
[]interface{}{
|
|
||||||
s.chainId,
|
|
||||||
tx.Nonce(),
|
|
||||||
tx.GasPrice(),
|
|
||||||
tx.Gas(),
|
|
||||||
tx.To(),
|
|
||||||
tx.Value(),
|
|
||||||
tx.Data(),
|
|
||||||
tx.AccessList(),
|
|
||||||
})
|
|
||||||
default:
|
|
||||||
// This _should_ not happen, but in case someone sends in a bad
|
|
||||||
// json struct via RPC, it's probably more prudent to return an
|
|
||||||
// empty hash instead of killing the node with a panic
|
|
||||||
//panic("Unsupported transaction type: %d", tx.typ)
|
|
||||||
return common.Hash{}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// EIP155Signer implements Signer using the EIP-155 rules. This accepts transactions which
|
// EIP155Signer implements Signer using the EIP-155 rules. This accepts transactions which
|
||||||
// are replay-protected as well as unprotected homestead transactions.
|
// are replay-protected as well as unprotected homestead transactions.
|
||||||
|
// Deprecated: always use the Signer interface type
|
||||||
type EIP155Signer struct {
|
type EIP155Signer struct {
|
||||||
chainId, chainIdMul *big.Int
|
chainId, chainIdMul *big.Int
|
||||||
}
|
}
|
||||||
|
|
@ -525,19 +373,12 @@ func (s EIP155Signer) SignatureValues(tx *Transaction, sig []byte) (R, S, V *big
|
||||||
// Hash returns the hash to be signed by the sender.
|
// Hash returns the hash to be signed by the sender.
|
||||||
// It does not uniquely identify the transaction.
|
// It does not uniquely identify the transaction.
|
||||||
func (s EIP155Signer) Hash(tx *Transaction) common.Hash {
|
func (s EIP155Signer) Hash(tx *Transaction) common.Hash {
|
||||||
return rlpHash([]interface{}{
|
return tx.inner.sigHash(s.chainId)
|
||||||
tx.Nonce(),
|
|
||||||
tx.GasPrice(),
|
|
||||||
tx.Gas(),
|
|
||||||
tx.To(),
|
|
||||||
tx.Value(),
|
|
||||||
tx.Data(),
|
|
||||||
s.chainId, uint(0), uint(0),
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// HomesteadSigner implements Signer interface using the
|
// HomesteadSigner implements Signer using the homestead rules. The only valid reason to
|
||||||
// homestead rules.
|
// use this type is creating legacy transactions which are intentionally not
|
||||||
|
// replay-protected.
|
||||||
type HomesteadSigner struct{ FrontierSigner }
|
type HomesteadSigner struct{ FrontierSigner }
|
||||||
|
|
||||||
func (hs HomesteadSigner) ChainID() *big.Int {
|
func (hs HomesteadSigner) ChainID() *big.Int {
|
||||||
|
|
@ -563,8 +404,8 @@ func (hs HomesteadSigner) Sender(tx *Transaction) (common.Address, error) {
|
||||||
return recoverPlain(hs.Hash(tx), r, s, v, true)
|
return recoverPlain(hs.Hash(tx), r, s, v, true)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FrontierSigner implements Signer interface using the
|
// FrontierSigner implements Signer using the frontier rules.
|
||||||
// frontier rules.
|
// Deprecated: always use the Signer interface type
|
||||||
type FrontierSigner struct{}
|
type FrontierSigner struct{}
|
||||||
|
|
||||||
func (fs FrontierSigner) ChainID() *big.Int {
|
func (fs FrontierSigner) ChainID() *big.Int {
|
||||||
|
|
@ -597,7 +438,7 @@ func (fs FrontierSigner) SignatureValues(tx *Transaction, sig []byte) (r, s, v *
|
||||||
// Hash returns the hash to be signed by the sender.
|
// Hash returns the hash to be signed by the sender.
|
||||||
// It does not uniquely identify the transaction.
|
// It does not uniquely identify the transaction.
|
||||||
func (fs FrontierSigner) Hash(tx *Transaction) common.Hash {
|
func (fs FrontierSigner) Hash(tx *Transaction) common.Hash {
|
||||||
return rlpHash([]interface{}{
|
return rlpHash([]any{
|
||||||
tx.Nonce(),
|
tx.Nonce(),
|
||||||
tx.GasPrice(),
|
tx.GasPrice(),
|
||||||
tx.Gas(),
|
tx.Gas(),
|
||||||
|
|
|
||||||
|
|
@ -576,3 +576,20 @@ func TestYParityJSONUnmarshalling(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func BenchmarkHash(b *testing.B) {
|
||||||
|
signer := NewLondonSigner(big.NewInt(1))
|
||||||
|
to := common.Address{}
|
||||||
|
tx := NewTx(&DynamicFeeTx{
|
||||||
|
ChainID: big.NewInt(123),
|
||||||
|
Nonce: 1,
|
||||||
|
Gas: 1000000,
|
||||||
|
To: &to,
|
||||||
|
Value: big.NewInt(1),
|
||||||
|
GasTipCap: big.NewInt(500),
|
||||||
|
GasFeeCap: big.NewInt(500),
|
||||||
|
})
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
signer.Hash(tx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -127,3 +127,18 @@ func (tx *AccessListTx) encode(b *bytes.Buffer) error {
|
||||||
func (tx *AccessListTx) decode(input []byte) error {
|
func (tx *AccessListTx) decode(input []byte) error {
|
||||||
return rlp.DecodeBytes(input, tx)
|
return rlp.DecodeBytes(input, tx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (tx *AccessListTx) sigHash(chainID *big.Int) common.Hash {
|
||||||
|
return prefixedRlpHash(
|
||||||
|
AccessListTxType,
|
||||||
|
[]any{
|
||||||
|
chainID,
|
||||||
|
tx.Nonce,
|
||||||
|
tx.GasPrice,
|
||||||
|
tx.Gas,
|
||||||
|
tx.To,
|
||||||
|
tx.Value,
|
||||||
|
tx.Data,
|
||||||
|
tx.AccessList,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -259,3 +259,21 @@ func (tx *BlobTx) decode(input []byte) error {
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (tx *BlobTx) sigHash(chainID *big.Int) common.Hash {
|
||||||
|
return prefixedRlpHash(
|
||||||
|
BlobTxType,
|
||||||
|
[]any{
|
||||||
|
chainID,
|
||||||
|
tx.Nonce,
|
||||||
|
tx.GasTipCap,
|
||||||
|
tx.GasFeeCap,
|
||||||
|
tx.Gas,
|
||||||
|
tx.To,
|
||||||
|
tx.Value,
|
||||||
|
tx.Data,
|
||||||
|
tx.AccessList,
|
||||||
|
tx.BlobFeeCap,
|
||||||
|
tx.BlobHashes,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -123,3 +123,19 @@ func (tx *DynamicFeeTx) encode(b *bytes.Buffer) error {
|
||||||
func (tx *DynamicFeeTx) decode(input []byte) error {
|
func (tx *DynamicFeeTx) decode(input []byte) error {
|
||||||
return rlp.DecodeBytes(input, tx)
|
return rlp.DecodeBytes(input, tx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (tx *DynamicFeeTx) sigHash(chainID *big.Int) common.Hash {
|
||||||
|
return prefixedRlpHash(
|
||||||
|
DynamicFeeTxType,
|
||||||
|
[]any{
|
||||||
|
chainID,
|
||||||
|
tx.Nonce,
|
||||||
|
tx.GasTipCap,
|
||||||
|
tx.GasFeeCap,
|
||||||
|
tx.Gas,
|
||||||
|
tx.To,
|
||||||
|
tx.Value,
|
||||||
|
tx.Data,
|
||||||
|
tx.AccessList,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -123,3 +123,16 @@ func (tx *LegacyTx) encode(*bytes.Buffer) error {
|
||||||
func (tx *LegacyTx) decode([]byte) error {
|
func (tx *LegacyTx) decode([]byte) error {
|
||||||
panic("decode called on LegacyTx)")
|
panic("decode called on LegacyTx)")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// OBS: This is the post-EIP155 hash, the pre-EIP155 does not contain a chainID.
|
||||||
|
func (tx *LegacyTx) sigHash(chainID *big.Int) common.Hash {
|
||||||
|
return rlpHash([]any{
|
||||||
|
tx.Nonce,
|
||||||
|
tx.GasPrice,
|
||||||
|
tx.Gas,
|
||||||
|
tx.To,
|
||||||
|
tx.Value,
|
||||||
|
tx.Data,
|
||||||
|
chainID, uint(0), uint(0),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -223,3 +223,20 @@ func (tx *SetCodeTx) encode(b *bytes.Buffer) error {
|
||||||
func (tx *SetCodeTx) decode(input []byte) error {
|
func (tx *SetCodeTx) decode(input []byte) error {
|
||||||
return rlp.DecodeBytes(input, tx)
|
return rlp.DecodeBytes(input, tx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (tx *SetCodeTx) sigHash(chainID *big.Int) common.Hash {
|
||||||
|
return prefixedRlpHash(
|
||||||
|
SetCodeTxType,
|
||||||
|
[]any{
|
||||||
|
chainID,
|
||||||
|
tx.Nonce,
|
||||||
|
tx.GasTipCap,
|
||||||
|
tx.GasFeeCap,
|
||||||
|
tx.Gas,
|
||||||
|
tx.To,
|
||||||
|
tx.Value,
|
||||||
|
tx.Data,
|
||||||
|
tx.AccessList,
|
||||||
|
tx.AuthList,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -67,6 +67,10 @@ type txPool interface {
|
||||||
// tx hash.
|
// tx hash.
|
||||||
Get(hash common.Hash) *types.Transaction
|
Get(hash common.Hash) *types.Transaction
|
||||||
|
|
||||||
|
// GetRLP retrieves the RLP-encoded transaction from local txpool
|
||||||
|
// with given tx hash.
|
||||||
|
GetRLP(hash common.Hash) []byte
|
||||||
|
|
||||||
// Add should add the given transactions to the pool.
|
// Add should add the given transactions to the pool.
|
||||||
Add(txs []*types.Transaction, sync bool) []error
|
Add(txs []*types.Transaction, sync bool) []error
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
"github.com/ethereum/go-ethereum/event"
|
"github.com/ethereum/go-ethereum/event"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
"github.com/holiman/uint256"
|
"github.com/holiman/uint256"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -78,6 +79,20 @@ func (p *testTxPool) Get(hash common.Hash) *types.Transaction {
|
||||||
return p.pool[hash]
|
return p.pool[hash]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Get retrieves the transaction from local txpool with given
|
||||||
|
// tx hash.
|
||||||
|
func (p *testTxPool) GetRLP(hash common.Hash) []byte {
|
||||||
|
p.lock.Lock()
|
||||||
|
defer p.lock.Unlock()
|
||||||
|
|
||||||
|
tx := p.pool[hash]
|
||||||
|
if tx != nil {
|
||||||
|
blob, _ := rlp.EncodeToBytes(tx)
|
||||||
|
return blob
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// Add appends a batch of transactions to the pool, and notifies any
|
// Add appends a batch of transactions to the pool, and notifies any
|
||||||
// listeners if the addition channel is non nil
|
// listeners if the addition channel is non nil
|
||||||
func (p *testTxPool) Add(txs []*types.Transaction, sync bool) []error {
|
func (p *testTxPool) Add(txs []*types.Transaction, sync bool) []error {
|
||||||
|
|
|
||||||
|
|
@ -86,6 +86,10 @@ type Backend interface {
|
||||||
type TxPool interface {
|
type TxPool interface {
|
||||||
// Get retrieves the transaction from the local txpool with the given hash.
|
// Get retrieves the transaction from the local txpool with the given hash.
|
||||||
Get(hash common.Hash) *types.Transaction
|
Get(hash common.Hash) *types.Transaction
|
||||||
|
|
||||||
|
// GetRLP retrieves the RLP-encoded transaction from the local txpool with
|
||||||
|
// the given hash.
|
||||||
|
GetRLP(hash common.Hash) []byte
|
||||||
}
|
}
|
||||||
|
|
||||||
// MakeProtocols constructs the P2P protocol definitions for `eth`.
|
// MakeProtocols constructs the P2P protocol definitions for `eth`.
|
||||||
|
|
|
||||||
|
|
@ -18,9 +18,11 @@ package eth
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
"crypto/sha256"
|
||||||
"math"
|
"math"
|
||||||
"math/big"
|
"math/big"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
|
@ -30,15 +32,18 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core"
|
"github.com/ethereum/go-ethereum/core"
|
||||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
"github.com/ethereum/go-ethereum/core/txpool"
|
"github.com/ethereum/go-ethereum/core/txpool"
|
||||||
|
"github.com/ethereum/go-ethereum/core/txpool/blobpool"
|
||||||
"github.com/ethereum/go-ethereum/core/txpool/legacypool"
|
"github.com/ethereum/go-ethereum/core/txpool/legacypool"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
"github.com/ethereum/go-ethereum/crypto/kzg4844"
|
||||||
"github.com/ethereum/go-ethereum/ethdb"
|
"github.com/ethereum/go-ethereum/ethdb"
|
||||||
"github.com/ethereum/go-ethereum/p2p"
|
"github.com/ethereum/go-ethereum/p2p"
|
||||||
"github.com/ethereum/go-ethereum/p2p/enode"
|
"github.com/ethereum/go-ethereum/p2p/enode"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/rlp"
|
"github.com/ethereum/go-ethereum/rlp"
|
||||||
|
"github.com/holiman/uint256"
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
@ -62,12 +67,12 @@ type testBackend struct {
|
||||||
|
|
||||||
// newTestBackend creates an empty chain and wraps it into a mock backend.
|
// newTestBackend creates an empty chain and wraps it into a mock backend.
|
||||||
func newTestBackend(blocks int) *testBackend {
|
func newTestBackend(blocks int) *testBackend {
|
||||||
return newTestBackendWithGenerator(blocks, false, nil)
|
return newTestBackendWithGenerator(blocks, false, false, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
// newTestBackendWithGenerator creates a chain with a number of explicitly defined blocks and
|
// newTestBackendWithGenerator creates a chain with a number of explicitly defined blocks and
|
||||||
// wraps it into a mock backend.
|
// wraps it into a mock backend.
|
||||||
func newTestBackendWithGenerator(blocks int, shanghai bool, generator func(int, *core.BlockGen)) *testBackend {
|
func newTestBackendWithGenerator(blocks int, shanghai bool, cancun bool, generator func(int, *core.BlockGen)) *testBackend {
|
||||||
var (
|
var (
|
||||||
// Create a database pre-initialize with a genesis block
|
// Create a database pre-initialize with a genesis block
|
||||||
db = rawdb.NewMemoryDatabase()
|
db = rawdb.NewMemoryDatabase()
|
||||||
|
|
@ -99,9 +104,21 @@ func newTestBackendWithGenerator(blocks int, shanghai bool, generator func(int,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if cancun {
|
||||||
|
config.CancunTime = u64(0)
|
||||||
|
config.BlobScheduleConfig = ¶ms.BlobScheduleConfig{
|
||||||
|
Cancun: ¶ms.BlobConfig{
|
||||||
|
Target: 3,
|
||||||
|
Max: 6,
|
||||||
|
UpdateFraction: params.DefaultCancunBlobConfig.UpdateFraction,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
gspec := &core.Genesis{
|
gspec := &core.Genesis{
|
||||||
Config: config,
|
Config: config,
|
||||||
Alloc: types.GenesisAlloc{testAddr: {Balance: big.NewInt(100_000_000_000_000_000)}},
|
Alloc: types.GenesisAlloc{testAddr: {Balance: big.NewInt(100_000_000_000_000_000)}},
|
||||||
|
Difficulty: common.Big0,
|
||||||
}
|
}
|
||||||
chain, _ := core.NewBlockChain(db, nil, gspec, nil, engine, vm.Config{}, nil)
|
chain, _ := core.NewBlockChain(db, nil, gspec, nil, engine, vm.Config{}, nil)
|
||||||
|
|
||||||
|
|
@ -115,8 +132,12 @@ func newTestBackendWithGenerator(blocks int, shanghai bool, generator func(int,
|
||||||
txconfig := legacypool.DefaultConfig
|
txconfig := legacypool.DefaultConfig
|
||||||
txconfig.Journal = "" // Don't litter the disk with test journals
|
txconfig.Journal = "" // Don't litter the disk with test journals
|
||||||
|
|
||||||
pool := legacypool.New(txconfig, chain)
|
storage, _ := os.MkdirTemp("", "blobpool-")
|
||||||
txpool, _ := txpool.New(txconfig.PriceLimit, chain, []txpool.SubPool{pool})
|
defer os.RemoveAll(storage)
|
||||||
|
|
||||||
|
blobPool := blobpool.New(blobpool.Config{Datadir: storage}, chain)
|
||||||
|
legacyPool := legacypool.New(txconfig, chain)
|
||||||
|
txpool, _ := txpool.New(txconfig.PriceLimit, chain, []txpool.SubPool{legacyPool, blobPool})
|
||||||
|
|
||||||
return &testBackend{
|
return &testBackend{
|
||||||
db: db,
|
db: db,
|
||||||
|
|
@ -351,7 +372,7 @@ func testGetBlockBodies(t *testing.T, protocol uint) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
backend := newTestBackendWithGenerator(maxBodiesServe+15, true, gen)
|
backend := newTestBackendWithGenerator(maxBodiesServe+15, true, false, gen)
|
||||||
defer backend.close()
|
defer backend.close()
|
||||||
|
|
||||||
peer, _ := newTestPeer("peer", protocol, backend)
|
peer, _ := newTestPeer("peer", protocol, backend)
|
||||||
|
|
@ -471,7 +492,7 @@ func testGetBlockReceipts(t *testing.T, protocol uint) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Assemble the test environment
|
// Assemble the test environment
|
||||||
backend := newTestBackendWithGenerator(4, false, generator)
|
backend := newTestBackendWithGenerator(4, false, false, generator)
|
||||||
defer backend.close()
|
defer backend.close()
|
||||||
|
|
||||||
peer, _ := newTestPeer("peer", protocol, backend)
|
peer, _ := newTestPeer("peer", protocol, backend)
|
||||||
|
|
@ -548,7 +569,7 @@ func setup() (*testBackend, *testPeer) {
|
||||||
block.SetExtra([]byte("yeehaw"))
|
block.SetExtra([]byte("yeehaw"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
backend := newTestBackendWithGenerator(maxBodiesServe+15, true, gen)
|
backend := newTestBackendWithGenerator(maxBodiesServe+15, true, false, gen)
|
||||||
peer, _ := newTestPeer("peer", ETH68, backend)
|
peer, _ := newTestPeer("peer", ETH68, backend)
|
||||||
// Discard all messages
|
// Discard all messages
|
||||||
go func() {
|
go func() {
|
||||||
|
|
@ -573,3 +594,80 @@ func FuzzEthProtocolHandlers(f *testing.F) {
|
||||||
handler(backend, decoder{msg: msg}, peer.Peer)
|
handler(backend, decoder{msg: msg}, peer.Peer)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestGetPooledTransaction(t *testing.T) {
|
||||||
|
t.Run("blobTx", func(t *testing.T) {
|
||||||
|
testGetPooledTransaction(t, true)
|
||||||
|
})
|
||||||
|
t.Run("legacyTx", func(t *testing.T) {
|
||||||
|
testGetPooledTransaction(t, false)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func testGetPooledTransaction(t *testing.T, blobTx bool) {
|
||||||
|
var (
|
||||||
|
emptyBlob = kzg4844.Blob{}
|
||||||
|
emptyBlobs = []kzg4844.Blob{emptyBlob}
|
||||||
|
emptyBlobCommit, _ = kzg4844.BlobToCommitment(&emptyBlob)
|
||||||
|
emptyBlobProof, _ = kzg4844.ComputeBlobProof(&emptyBlob, emptyBlobCommit)
|
||||||
|
emptyBlobHash = kzg4844.CalcBlobHashV1(sha256.New(), &emptyBlobCommit)
|
||||||
|
)
|
||||||
|
backend := newTestBackendWithGenerator(0, true, true, nil)
|
||||||
|
defer backend.close()
|
||||||
|
|
||||||
|
peer, _ := newTestPeer("peer", ETH68, backend)
|
||||||
|
defer peer.close()
|
||||||
|
|
||||||
|
var (
|
||||||
|
tx *types.Transaction
|
||||||
|
err error
|
||||||
|
signer = types.NewCancunSigner(params.TestChainConfig.ChainID)
|
||||||
|
)
|
||||||
|
if blobTx {
|
||||||
|
tx, err = types.SignNewTx(testKey, signer, &types.BlobTx{
|
||||||
|
ChainID: uint256.MustFromBig(params.TestChainConfig.ChainID),
|
||||||
|
Nonce: 0,
|
||||||
|
GasTipCap: uint256.NewInt(20_000_000_000),
|
||||||
|
GasFeeCap: uint256.NewInt(21_000_000_000),
|
||||||
|
Gas: 21000,
|
||||||
|
To: testAddr,
|
||||||
|
BlobHashes: []common.Hash{emptyBlobHash},
|
||||||
|
BlobFeeCap: uint256.MustFromBig(common.Big1),
|
||||||
|
Sidecar: &types.BlobTxSidecar{
|
||||||
|
Blobs: emptyBlobs,
|
||||||
|
Commitments: []kzg4844.Commitment{emptyBlobCommit},
|
||||||
|
Proofs: []kzg4844.Proof{emptyBlobProof},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
tx, err = types.SignTx(
|
||||||
|
types.NewTransaction(0, testAddr, big.NewInt(10_000), params.TxGas, big.NewInt(1_000_000_000), nil),
|
||||||
|
signer,
|
||||||
|
testKey,
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
errs := backend.txpool.Add([]*types.Transaction{tx}, true)
|
||||||
|
for _, err := range errs {
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send the hash request and verify the response
|
||||||
|
p2p.Send(peer.app, GetPooledTransactionsMsg, GetPooledTransactionsPacket{
|
||||||
|
RequestId: 123,
|
||||||
|
GetPooledTransactionsRequest: []common.Hash{tx.Hash()},
|
||||||
|
})
|
||||||
|
if err := p2p.ExpectMsg(peer.app, PooledTransactionsMsg, PooledTransactionsPacket{
|
||||||
|
RequestId: 123,
|
||||||
|
PooledTransactionsResponse: []*types.Transaction{tx},
|
||||||
|
}); err != nil {
|
||||||
|
t.Errorf("pooled transaction mismatch: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -397,19 +397,14 @@ func answerGetPooledTransactions(backend Backend, query GetPooledTransactionsReq
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
// Retrieve the requested transaction, skipping if unknown to us
|
// Retrieve the requested transaction, skipping if unknown to us
|
||||||
tx := backend.TxPool().Get(hash)
|
encoded := backend.TxPool().GetRLP(hash)
|
||||||
if tx == nil {
|
if len(encoded) == 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// If known, encode and queue for response packet
|
|
||||||
if encoded, err := rlp.EncodeToBytes(tx); err != nil {
|
|
||||||
log.Error("Failed to encode transaction", "err", err)
|
|
||||||
} else {
|
|
||||||
hashes = append(hashes, hash)
|
hashes = append(hashes, hash)
|
||||||
txs = append(txs, encoded)
|
txs = append(txs, encoded)
|
||||||
bytes += len(encoded)
|
bytes += len(encoded)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return hashes, txs
|
return hashes, txs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,8 +24,8 @@ const (
|
||||||
FrontierThawing
|
FrontierThawing
|
||||||
Homestead
|
Homestead
|
||||||
DAO
|
DAO
|
||||||
TangerineWhistle
|
TangerineWhistle // a.k.a. the EIP150 fork
|
||||||
SpuriousDragon
|
SpuriousDragon // a.k.a. the EIP155 fork
|
||||||
Byzantium
|
Byzantium
|
||||||
Constantinople
|
Constantinople
|
||||||
Petersburg
|
Petersburg
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue