resolve merge conflict

This commit is contained in:
Sina Mahmoodi 2024-02-21 14:34:23 +01:00
commit 49bf257ce5
27 changed files with 273 additions and 115 deletions

View file

@ -24,7 +24,7 @@ import (
"github.com/ethereum/go-ethereum/trie" "github.com/ethereum/go-ethereum/trie"
) )
// NewStateSync create a new state trie download scheduler. // NewStateSync creates a new state trie download scheduler.
func NewStateSync(root common.Hash, database ethdb.KeyValueReader, onLeaf func(keys [][]byte, leaf []byte) error, scheme string) *trie.Sync { func NewStateSync(root common.Hash, database ethdb.KeyValueReader, onLeaf func(keys [][]byte, leaf []byte) error, scheme string) *trie.Sync {
// Register the storage slot callback if the external callback is specified. // Register the storage slot callback if the external callback is specified.
var onSlot func(keys [][]byte, path []byte, leaf []byte, parent common.Hash, parentPath []byte) error var onSlot func(keys [][]byte, path []byte, leaf []byte, parent common.Hash, parentPath []byte) error

View file

@ -67,7 +67,7 @@ func (result *ExecutionResult) Revert() []byte {
} }
// IntrinsicGas computes the 'intrinsic gas' for a message with the given data. // IntrinsicGas computes the 'intrinsic gas' for a message with the given data.
func IntrinsicGas(data []byte, accessList types.AccessList, isContractCreation bool, isHomestead, isEIP2028 bool, isEIP3860 bool) (uint64, error) { func IntrinsicGas(data []byte, accessList types.AccessList, isContractCreation bool, isHomestead, isEIP2028, isEIP3860 bool) (uint64, error) {
// Set the starting gas for the raw transaction // Set the starting gas for the raw transaction
var gas uint64 var gas uint64
if isContractCreation && isHomestead { if isContractCreation && isHomestead {

View file

@ -360,7 +360,7 @@ func (p *BlobPool) Init(gasTip uint64, head *types.Header, reserve txpool.Addres
} }
} }
// Initialize the state with head block, or fallback to empty one in // Initialize the state with head block, or fallback to empty one in
// case the head state is not available(might occur when node is not // case the head state is not available (might occur when node is not
// fully synced). // fully synced).
state, err := p.chain.StateAt(head.Root) state, err := p.chain.StateAt(head.Root)
if err != nil { if err != nil {
@ -371,7 +371,7 @@ func (p *BlobPool) Init(gasTip uint64, head *types.Header, reserve txpool.Addres
} }
p.head, p.state = head, state p.head, p.state = head, state
// Index all transactions on disk and delete anything inprocessable // Index all transactions on disk and delete anything unprocessable
var fails []uint64 var fails []uint64
index := func(id uint64, size uint32, blob []byte) { index := func(id uint64, size uint32, blob []byte) {
if p.parseTransaction(id, size, blob) != nil { if p.parseTransaction(id, size, blob) != nil {
@ -540,7 +540,7 @@ func (p *BlobPool) recheck(addr common.Address, inclusions map[common.Hash]uint6
} }
delete(p.index, addr) delete(p.index, addr)
delete(p.spent, addr) delete(p.spent, addr)
if inclusions != nil { // only during reorgs will the heap will be initialized if inclusions != nil { // only during reorgs will the heap be initialized
heap.Remove(p.evict, p.evict.index[addr]) heap.Remove(p.evict, p.evict.index[addr])
} }
p.reserve(addr, false) p.reserve(addr, false)
@ -693,7 +693,7 @@ func (p *BlobPool) recheck(addr common.Address, inclusions map[common.Hash]uint6
if len(txs) == 0 { if len(txs) == 0 {
delete(p.index, addr) delete(p.index, addr)
delete(p.spent, addr) delete(p.spent, addr)
if inclusions != nil { // only during reorgs will the heap will be initialized if inclusions != nil { // only during reorgs will the heap be initialized
heap.Remove(p.evict, p.evict.index[addr]) heap.Remove(p.evict, p.evict.index[addr])
} }
p.reserve(addr, false) p.reserve(addr, false)
@ -809,7 +809,7 @@ func (p *BlobPool) Reset(oldHead, newHead *types.Header) {
} }
} }
// Recheck the account's pooled transactions to drop included and // Recheck the account's pooled transactions to drop included and
// invalidated one // invalidated ones
p.recheck(addr, inclusions) p.recheck(addr, inclusions)
} }
if len(adds) > 0 { if len(adds) > 0 {
@ -1226,7 +1226,7 @@ func (p *BlobPool) Add(txs []*types.Transaction, local bool, sync bool) []error
// consensus validity and pool restrictions). // consensus validity and pool restrictions).
func (p *BlobPool) add(tx *types.Transaction) (err error) { func (p *BlobPool) add(tx *types.Transaction) (err error) {
// The blob pool blocks on adding a transaction. This is because blob txs are // The blob pool blocks on adding a transaction. This is because blob txs are
// only even pulled form the network, so this method will act as the overload // only even pulled from the network, so this method will act as the overload
// protection for fetches. // protection for fetches.
waitStart := time.Now() waitStart := time.Now()
p.lock.Lock() p.lock.Lock()
@ -1446,7 +1446,12 @@ func (p *BlobPool) drop() {
// //
// The transactions can also be pre-filtered by the dynamic fee components to // The transactions can also be pre-filtered by the dynamic fee components to
// reduce allocations and load on downstream subsystems. // reduce allocations and load on downstream subsystems.
func (p *BlobPool) Pending(minTip *uint256.Int, baseFee *uint256.Int, blobFee *uint256.Int) map[common.Address][]*txpool.LazyTransaction { func (p *BlobPool) Pending(filter txpool.PendingFilter) map[common.Address][]*txpool.LazyTransaction {
// If only plain transactions are requested, this pool is unsuitable as it
// contains none, don't even bother.
if filter.OnlyPlainTxs {
return nil
}
// Track the amount of time waiting to retrieve the list of pending blob txs // Track the amount of time waiting to retrieve the list of pending blob txs
// from the pool and the amount of time actually spent on assembling the data. // from the pool and the amount of time actually spent on assembling the data.
// The latter will be pretty much moot, but we've kept it to have symmetric // The latter will be pretty much moot, but we've kept it to have symmetric
@ -1456,29 +1461,30 @@ func (p *BlobPool) Pending(minTip *uint256.Int, baseFee *uint256.Int, blobFee *u
pendwaitHist.Update(time.Since(pendStart).Nanoseconds()) pendwaitHist.Update(time.Since(pendStart).Nanoseconds())
defer p.lock.RUnlock() defer p.lock.RUnlock()
defer func(start time.Time) { execStart := time.Now()
pendtimeHist.Update(time.Since(start).Nanoseconds()) defer func() {
}(time.Now()) pendtimeHist.Update(time.Since(execStart).Nanoseconds())
}()
pending := make(map[common.Address][]*txpool.LazyTransaction) pending := make(map[common.Address][]*txpool.LazyTransaction, len(p.index))
for addr, txs := range p.index { for addr, txs := range p.index {
var lazies []*txpool.LazyTransaction lazies := make([]*txpool.LazyTransaction, 0, len(txs))
for _, tx := range txs { for _, tx := range txs {
// If transaction filtering was requested, discard badly priced ones // If transaction filtering was requested, discard badly priced ones
if minTip != nil && baseFee != nil { if filter.MinTip != nil && filter.BaseFee != nil {
if tx.execFeeCap.Lt(baseFee) { if tx.execFeeCap.Lt(filter.BaseFee) {
break // basefee too low, cannot be included, discard rest of txs from the account break // basefee too low, cannot be included, discard rest of txs from the account
} }
tip := new(uint256.Int).Sub(tx.execFeeCap, baseFee) tip := new(uint256.Int).Sub(tx.execFeeCap, filter.BaseFee)
if tip.Gt(tx.execTipCap) { if tip.Gt(tx.execTipCap) {
tip = tx.execTipCap tip = tx.execTipCap
} }
if tip.Lt(minTip) { if tip.Lt(filter.MinTip) {
break // allowed or remaining tip too low, cannot be included, discard rest of txs from the account break // allowed or remaining tip too low, cannot be included, discard rest of txs from the account
} }
} }
if blobFee != nil { if filter.BlobFee != nil {
if tx.blobFeeCap.Lt(blobFee) { if tx.blobFeeCap.Lt(filter.BlobFee) {
break // blobfee too low, cannot be included, discard rest of txs from the account break // blobfee too low, cannot be included, discard rest of txs from the account
} }
} }
@ -1486,9 +1492,9 @@ func (p *BlobPool) Pending(minTip *uint256.Int, baseFee *uint256.Int, blobFee *u
lazies = append(lazies, &txpool.LazyTransaction{ lazies = append(lazies, &txpool.LazyTransaction{
Pool: p, Pool: p,
Hash: tx.hash, Hash: tx.hash,
Time: time.Now(), // TODO(karalabe): Maybe save these and use that? Time: execStart, // TODO(karalabe): Maybe save these and use that?
GasFeeCap: tx.execFeeCap.ToBig(), GasFeeCap: tx.execFeeCap,
GasTipCap: tx.execTipCap.ToBig(), GasTipCap: tx.execTipCap,
Gas: tx.execGas, Gas: tx.execGas,
BlobGas: tx.blobGas, BlobGas: tx.blobGas,
}) })
@ -1548,7 +1554,7 @@ func (p *BlobPool) updateStorageMetrics() {
} }
// updateLimboMetrics retrieves a bunch of stats from the limbo store and pushes // updateLimboMetrics retrieves a bunch of stats from the limbo store and pushes
// // them out as metrics. // them out as metrics.
func (p *BlobPool) updateLimboMetrics() { func (p *BlobPool) updateLimboMetrics() {
stats := p.limbo.store.Infos() stats := p.limbo.store.Infos()

View file

@ -185,7 +185,7 @@ func makeTx(nonce uint64, gasTipCap uint64, gasFeeCap uint64, blobFeeCap uint64,
return types.MustSignNewTx(key, types.LatestSigner(testChainConfig), blobtx) return types.MustSignNewTx(key, types.LatestSigner(testChainConfig), blobtx)
} }
// makeUnsignedTx is a utility method to construct a random blob tranasaction // makeUnsignedTx is a utility method to construct a random blob transaction
// without signing it. // without signing it.
func makeUnsignedTx(nonce uint64, gasTipCap uint64, gasFeeCap uint64, blobFeeCap uint64) *types.BlobTx { func makeUnsignedTx(nonce uint64, gasTipCap uint64, gasFeeCap uint64, blobFeeCap uint64) *types.BlobTx {
return &types.BlobTx{ return &types.BlobTx{
@ -391,7 +391,7 @@ func TestOpenDrops(t *testing.T) {
id, _ := store.Put(blob) id, _ := store.Put(blob)
filled[id] = struct{}{} filled[id] = struct{}{}
} }
// Insert a sequence of transactions with partially passed nonces to veirfy // Insert a sequence of transactions with partially passed nonces to verify
// that the included part of the set will get dropped (case 4). // that the included part of the set will get dropped (case 4).
var ( var (
overlapper, _ = crypto.GenerateKey() overlapper, _ = crypto.GenerateKey()
@ -1288,3 +1288,65 @@ func TestAdd(t *testing.T) {
pool.Close() pool.Close()
} }
} }
// Benchmarks the time it takes to assemble the lazy pending transaction list
// from the pool contents.
func BenchmarkPoolPending100Mb(b *testing.B) { benchmarkPoolPending(b, 100_000_000) }
func BenchmarkPoolPending1GB(b *testing.B) { benchmarkPoolPending(b, 1_000_000_000) }
func BenchmarkPoolPending10GB(b *testing.B) { benchmarkPoolPending(b, 10_000_000_000) }
func benchmarkPoolPending(b *testing.B, datacap uint64) {
// Calculate the maximum number of transaction that would fit into the pool
// and generate a set of random accounts to seed them with.
capacity := datacap / params.BlobTxBlobGasPerBlob
var (
basefee = uint64(1050)
blobfee = uint64(105)
signer = types.LatestSigner(testChainConfig)
statedb, _ = state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewDatabase(memorydb.New())), nil)
chain = &testBlockChain{
config: testChainConfig,
basefee: uint256.NewInt(basefee),
blobfee: uint256.NewInt(blobfee),
statedb: statedb,
}
pool = New(Config{Datadir: ""}, chain)
)
if err := pool.Init(1, chain.CurrentBlock(), makeAddressReserver()); err != nil {
b.Fatalf("failed to create blob pool: %v", err)
}
// Fill the pool up with one random transaction from each account with the
// same price and everything to maximize the worst case scenario
for i := 0; i < int(capacity); i++ {
blobtx := makeUnsignedTx(0, 10, basefee+10, blobfee)
blobtx.R = uint256.NewInt(1)
blobtx.S = uint256.NewInt(uint64(100 + i))
blobtx.V = uint256.NewInt(0)
tx := types.NewTx(blobtx)
addr, err := types.Sender(signer, tx)
if err != nil {
b.Fatal(err)
}
statedb.AddBalance(addr, uint256.NewInt(1_000_000_000))
pool.add(tx)
}
statedb.Commit(0, true)
defer pool.Close()
// Benchmark assembling the pending
b.ResetTimer()
b.ReportAllocs()
for i := 0; i < b.N; i++ {
p := pool.Pending(txpool.PendingFilter{
MinTip: uint256.NewInt(1),
BaseFee: chain.basefee,
BlobFee: chain.blobfee,
})
if len(p) != int(capacity) {
b.Fatalf("have %d want %d", len(p), capacity)
}
}
}

View file

@ -30,7 +30,7 @@ import (
// transaction from each account to determine which account to evict from. // transaction from each account to determine which account to evict from.
// //
// The heap internally tracks a slice of cheapest transactions from each account // The heap internally tracks a slice of cheapest transactions from each account
// and a mapping from addresses to indices for direct removals/udates. // and a mapping from addresses to indices for direct removals/updates.
// //
// The goal of the heap is to decide which account has the worst bottleneck to // The goal of the heap is to decide which account has the worst bottleneck to
// evict transactions from. // evict transactions from.

View file

@ -64,7 +64,7 @@ func BenchmarkDynamicFeeJumpCalculation(b *testing.B) {
// Benchmarks how many priority recalculations can be done. // Benchmarks how many priority recalculations can be done.
func BenchmarkPriorityCalculation(b *testing.B) { func BenchmarkPriorityCalculation(b *testing.B) {
// The basefee and blob fee is constant for all transactions across a block, // The basefee and blob fee is constant for all transactions across a block,
// so we can assume theit absolute jump counts can be pre-computed. // so we can assume their absolute jump counts can be pre-computed.
basefee := uint256.NewInt(17_200_000_000) // 17.2 Gwei is the 22.03.2023 zero-emission basefee, random number basefee := uint256.NewInt(17_200_000_000) // 17.2 Gwei is the 22.03.2023 zero-emission basefee, random number
blobfee := uint256.NewInt(123_456_789_000) // Completely random, no idea what this will be blobfee := uint256.NewInt(123_456_789_000) // Completely random, no idea what this will be

View file

@ -296,7 +296,7 @@ func (pool *LegacyPool) Init(gasTip uint64, head *types.Header, reserve txpool.A
pool.gasTip.Store(uint256.NewInt(gasTip)) pool.gasTip.Store(uint256.NewInt(gasTip))
// Initialize the state with head block, or fallback to empty one in // Initialize the state with head block, or fallback to empty one in
// case the head state is not available(might occur when node is not // case the head state is not available (might occur when node is not
// fully synced). // fully synced).
statedb, err := pool.chain.StateAt(head.Root) statedb, err := pool.chain.StateAt(head.Root)
if err != nil { if err != nil {
@ -522,7 +522,12 @@ func (pool *LegacyPool) ContentFrom(addr common.Address) ([]*types.Transaction,
// //
// The transactions can also be pre-filtered by the dynamic fee components to // The transactions can also be pre-filtered by the dynamic fee components to
// reduce allocations and load on downstream subsystems. // reduce allocations and load on downstream subsystems.
func (pool *LegacyPool) Pending(minTip *uint256.Int, baseFee *uint256.Int, blobFee *uint256.Int) map[common.Address][]*txpool.LazyTransaction { func (pool *LegacyPool) Pending(filter txpool.PendingFilter) map[common.Address][]*txpool.LazyTransaction {
// If only blob transactions are requested, this pool is unsuitable as it
// contains none, don't even bother.
if filter.OnlyBlobTxs {
return nil
}
pool.mu.Lock() pool.mu.Lock()
defer pool.mu.Unlock() defer pool.mu.Unlock()
@ -531,13 +536,12 @@ func (pool *LegacyPool) Pending(minTip *uint256.Int, baseFee *uint256.Int, blobF
minTipBig *big.Int minTipBig *big.Int
baseFeeBig *big.Int baseFeeBig *big.Int
) )
if minTip != nil { if filter.MinTip != nil {
minTipBig = minTip.ToBig() minTipBig = filter.MinTip.ToBig()
} }
if baseFee != nil { if filter.BaseFee != nil {
baseFeeBig = baseFee.ToBig() baseFeeBig = filter.BaseFee.ToBig()
} }
pending := make(map[common.Address][]*txpool.LazyTransaction, len(pool.pending)) pending := make(map[common.Address][]*txpool.LazyTransaction, len(pool.pending))
for addr, list := range pool.pending { for addr, list := range pool.pending {
txs := list.Flatten() txs := list.Flatten()
@ -559,8 +563,8 @@ func (pool *LegacyPool) Pending(minTip *uint256.Int, baseFee *uint256.Int, blobF
Hash: txs[i].Hash(), Hash: txs[i].Hash(),
Tx: txs[i], Tx: txs[i],
Time: txs[i].Time(), Time: txs[i].Time(),
GasFeeCap: txs[i].GasFeeCap(), GasFeeCap: uint256.MustFromBig(txs[i].GasFeeCap()),
GasTipCap: txs[i].GasTipCap(), GasTipCap: uint256.MustFromBig(txs[i].GasTipCap()),
Gas: txs[i].Gas(), Gas: txs[i].Gas(),
BlobGas: txs[i].BlobGas(), BlobGas: txs[i].BlobGas(),
} }

View file

@ -278,7 +278,7 @@ type list struct {
totalcost *uint256.Int // Total cost of all transactions in the list totalcost *uint256.Int // Total cost of all transactions in the list
} }
// newList create a new transaction list for maintaining nonce-indexable fast, // newList creates a new transaction list for maintaining nonce-indexable fast,
// gapped, sortable transaction lists. // gapped, sortable transaction lists.
func newList(strict bool) *list { func newList(strict bool) *list {
return &list{ return &list{

View file

@ -36,8 +36,8 @@ type LazyTransaction struct {
Tx *types.Transaction // Transaction if already resolved Tx *types.Transaction // Transaction if already resolved
Time time.Time // Time when the transaction was first seen Time time.Time // Time when the transaction was first seen
GasFeeCap *big.Int // Maximum fee per gas the transaction may consume GasFeeCap *uint256.Int // Maximum fee per gas the transaction may consume
GasTipCap *big.Int // Maximum miner tip per gas the transaction can pay GasTipCap *uint256.Int // Maximum miner tip per gas the transaction can pay
Gas uint64 // Amount of gas required by the transaction Gas uint64 // Amount of gas required by the transaction
BlobGas uint64 // Amount of blob gas required by the transaction BlobGas uint64 // Amount of blob gas required by the transaction
@ -70,6 +70,21 @@ type LazyResolver interface {
// may request (and relinquish) exclusive access to certain addresses. // may request (and relinquish) exclusive access to certain addresses.
type AddressReserver func(addr common.Address, reserve bool) error type AddressReserver func(addr common.Address, reserve bool) error
// PendingFilter is a collection of filter rules to allow retrieving a subset
// of transactions for announcement or mining.
//
// Note, the entries here are not arbitrary useful filters, rather each one has
// a very specific call site in mind and each one can be evaluated very cheaply
// by the pool implementations. Only add new ones that satisfy those constraints.
type PendingFilter struct {
MinTip *uint256.Int // Minimum miner tip required to include a transaction
BaseFee *uint256.Int // Minimum 1559 basefee needed to include a transaction
BlobFee *uint256.Int // Minimum 4844 blobfee needed to include a blob transaction
OnlyPlainTxs bool // Return only plain EVM transactions (peer-join announces, block space filling)
OnlyBlobTxs bool // Return only blob transactions (block blob-space filling)
}
// SubPool represents a specialized transaction pool that lives on its own (e.g. // SubPool represents a specialized transaction pool that lives on its own (e.g.
// blob pool). Since independent of how many specialized pools we have, they do // blob pool). Since independent of how many specialized pools we have, they do
// need to be updated in lockstep and assemble into one coherent view for block // need to be updated in lockstep and assemble into one coherent view for block
@ -118,7 +133,7 @@ type SubPool interface {
// //
// The transactions can also be pre-filtered by the dynamic fee components to // The transactions can also be pre-filtered by the dynamic fee components to
// reduce allocations and load on downstream subsystems. // reduce allocations and load on downstream subsystems.
Pending(minTip *uint256.Int, baseFee *uint256.Int, blobFee *uint256.Int) map[common.Address][]*LazyTransaction Pending(filter PendingFilter) map[common.Address][]*LazyTransaction
// SubscribeTransactions subscribes to new transaction events. The subscriber // SubscribeTransactions subscribes to new transaction events. The subscriber
// can decide whether to receive notifications only for newly seen transactions // can decide whether to receive notifications only for newly seen transactions

View file

@ -28,7 +28,6 @@ import (
"github.com/ethereum/go-ethereum/event" "github.com/ethereum/go-ethereum/event"
"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/holiman/uint256"
) )
// TxStatus is the current status of a transaction as seen by the pool. // TxStatus is the current status of a transaction as seen by the pool.
@ -357,10 +356,10 @@ func (p *TxPool) Add(txs []*types.Transaction, local bool, sync bool) []error {
// //
// The transactions can also be pre-filtered by the dynamic fee components to // The transactions can also be pre-filtered by the dynamic fee components to
// reduce allocations and load on downstream subsystems. // reduce allocations and load on downstream subsystems.
func (p *TxPool) Pending(minTip *uint256.Int, baseFee *uint256.Int, blobFee *uint256.Int) map[common.Address][]*LazyTransaction { func (p *TxPool) Pending(filter PendingFilter) map[common.Address][]*LazyTransaction {
txs := make(map[common.Address][]*LazyTransaction) txs := make(map[common.Address][]*LazyTransaction)
for _, subpool := range p.subpools { for _, subpool := range p.subpools {
for addr, set := range subpool.Pending(minTip, baseFee, blobFee) { for addr, set := range subpool.Pending(filter) {
txs[addr] = set txs[addr] = set
} }
} }

View file

@ -187,7 +187,12 @@ func makeCallVariantGasCallEIP2929(oldCalculator gasFunc) gasFunc {
// outside of this function, as part of the dynamic gas, and that will make it // outside of this function, as part of the dynamic gas, and that will make it
// also become correctly reported to tracers. // also become correctly reported to tracers.
contract.Gas += coldCost contract.Gas += coldCost
return gas + coldCost, nil
var overflow bool
if gas, overflow = math.SafeAdd(gas, coldCost); overflow {
return 0, ErrGasUintOverflow
}
return gas, nil
} }
} }

View file

@ -292,7 +292,7 @@ func (b *EthAPIBackend) SendTx(ctx context.Context, signedTx *types.Transaction)
} }
func (b *EthAPIBackend) GetPoolTransactions() (types.Transactions, error) { func (b *EthAPIBackend) GetPoolTransactions() (types.Transactions, error) {
pending := b.eth.txPool.Pending(nil, nil, nil) pending := b.eth.txPool.Pending(txpool.PendingFilter{})
var txs types.Transactions var txs types.Transactions
for _, batch := range pending { for _, batch := range pending {
for _, lazy := range batch { for _, lazy := range batch {

View file

@ -29,7 +29,7 @@ type MinerAPI struct {
e *Ethereum e *Ethereum
} }
// NewMinerAPI create a new MinerAPI instance. // NewMinerAPI creates a new MinerAPI instance.
func NewMinerAPI(e *Ethereum) *MinerAPI { func NewMinerAPI(e *Ethereum) *MinerAPI {
return &MinerAPI{e} return &MinerAPI{e}
} }

View file

@ -25,6 +25,7 @@ import (
"github.com/ethereum/go-ethereum/beacon/engine" "github.com/ethereum/go-ethereum/beacon/engine"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/txpool"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/eth" "github.com/ethereum/go-ethereum/eth"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
@ -263,7 +264,7 @@ func (c *SimulatedBeacon) Rollback() {
// Fork sets the head to the provided hash. // Fork sets the head to the provided hash.
func (c *SimulatedBeacon) Fork(parentHash common.Hash) error { func (c *SimulatedBeacon) Fork(parentHash common.Hash) error {
if len(c.eth.TxPool().Pending(nil, nil, nil)) != 0 { if len(c.eth.TxPool().Pending(txpool.PendingFilter{})) != 0 {
return errors.New("pending block dirty") return errors.New("pending block dirty")
} }
parent := c.eth.BlockChain().GetBlockByHash(parentHash) parent := c.eth.BlockChain().GetBlockByHash(parentHash)
@ -275,7 +276,7 @@ func (c *SimulatedBeacon) Fork(parentHash common.Hash) error {
// AdjustTime creates a new block with an adjusted timestamp. // AdjustTime creates a new block with an adjusted timestamp.
func (c *SimulatedBeacon) AdjustTime(adjustment time.Duration) error { func (c *SimulatedBeacon) AdjustTime(adjustment time.Duration) error {
if len(c.eth.TxPool().Pending(nil, nil, nil)) != 0 { if len(c.eth.TxPool().Pending(txpool.PendingFilter{})) != 0 {
return errors.New("could not adjust time on non-empty block") return errors.New("could not adjust time on non-empty block")
} }
parent := c.eth.BlockChain().CurrentBlock() parent := c.eth.BlockChain().CurrentBlock()

View file

@ -38,7 +38,7 @@ type DownloaderAPI struct {
uninstallSyncSubscription chan *uninstallSyncSubscriptionRequest uninstallSyncSubscription chan *uninstallSyncSubscriptionRequest
} }
// NewDownloaderAPI create a new DownloaderAPI. The API has an internal event loop that // NewDownloaderAPI creates a new DownloaderAPI. The API has an internal event loop that
// listens for events from the downloader through the global event mux. In case it receives one of // listens for events from the downloader through the global event mux. In case it receives one of
// these events it broadcasts it to all syncing subscriptions that are installed through the // these events it broadcasts it to all syncing subscriptions that are installed through the
// installSyncSubscription channel. // installSyncSubscription channel.

View file

@ -42,7 +42,6 @@ import (
"github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/metrics"
"github.com/ethereum/go-ethereum/p2p" "github.com/ethereum/go-ethereum/p2p"
"github.com/ethereum/go-ethereum/triedb/pathdb" "github.com/ethereum/go-ethereum/triedb/pathdb"
"github.com/holiman/uint256"
) )
const ( const (
@ -74,7 +73,7 @@ type txPool interface {
// Pending should return pending transactions. // Pending should return pending transactions.
// The slice should be modifiable by the caller. // The slice should be modifiable by the caller.
Pending(minTip *uint256.Int, baseFee *uint256.Int, blobFee *uint256.Int) map[common.Address][]*txpool.LazyTransaction Pending(filter txpool.PendingFilter) map[common.Address][]*txpool.LazyTransaction
// SubscribeTransactions subscribes to new transaction events. The subscriber // SubscribeTransactions subscribes to new transaction events. The subscriber
// can decide whether to receive notifications only for newly seen transactions // can decide whether to receive notifications only for newly seen transactions

View file

@ -93,7 +93,7 @@ func (p *testTxPool) Add(txs []*types.Transaction, local bool, sync bool) []erro
} }
// Pending returns all the transactions known to the pool // Pending returns all the transactions known to the pool
func (p *testTxPool) Pending(minTip *uint256.Int, baseFee *uint256.Int, blobFee *uint256.Int) map[common.Address][]*txpool.LazyTransaction { func (p *testTxPool) Pending(filter txpool.PendingFilter) map[common.Address][]*txpool.LazyTransaction {
p.lock.RLock() p.lock.RLock()
defer p.lock.RUnlock() defer p.lock.RUnlock()
@ -112,8 +112,8 @@ func (p *testTxPool) Pending(minTip *uint256.Int, baseFee *uint256.Int, blobFee
Hash: tx.Hash(), Hash: tx.Hash(),
Tx: tx, Tx: tx,
Time: tx.Time(), Time: tx.Time(),
GasFeeCap: tx.GasFeeCap(), GasFeeCap: uint256.MustFromBig(tx.GasFeeCap()),
GasTipCap: tx.GasTipCap(), GasTipCap: uint256.MustFromBig(tx.GasTipCap()),
Gas: tx.Gas(), Gas: tx.Gas(),
BlobGas: tx.BlobGas(), BlobGas: tx.BlobGas(),
}) })

View file

@ -92,7 +92,7 @@ type Peer struct {
lock sync.RWMutex // Mutex protecting the internal fields lock sync.RWMutex // Mutex protecting the internal fields
} }
// NewPeer create a wrapper for a network connection and negotiated protocol // NewPeer creates a wrapper for a network connection and negotiated protocol
// version. // version.
func NewPeer(version uint, p *p2p.Peer, rw p2p.MsgReadWriter, txpool TxPool) *Peer { func NewPeer(version uint, p *p2p.Peer, rw p2p.MsgReadWriter, txpool TxPool) *Peer {
peer := &Peer{ peer := &Peer{

View file

@ -33,7 +33,7 @@ type Peer struct {
logger log.Logger // Contextual logger with the peer id injected logger log.Logger // Contextual logger with the peer id injected
} }
// NewPeer create a wrapper for a network connection and negotiated protocol // NewPeer creates a wrapper for a network connection and negotiated protocol
// version. // version.
func NewPeer(version uint, p *p2p.Peer, rw p2p.MsgReadWriter) *Peer { func NewPeer(version uint, p *p2p.Peer, rw p2p.MsgReadWriter) *Peer {
id := p.ID().String() id := p.ID().String()
@ -46,7 +46,7 @@ func NewPeer(version uint, p *p2p.Peer, rw p2p.MsgReadWriter) *Peer {
} }
} }
// NewFakePeer create a fake snap peer without a backing p2p peer, for testing purposes. // NewFakePeer creates a fake snap peer without a backing p2p peer, for testing purposes.
func NewFakePeer(version uint, id string, rw p2p.MsgReadWriter) *Peer { func NewFakePeer(version uint, id string, rw p2p.MsgReadWriter) *Peer {
return &Peer{ return &Peer{
id: id, id: id,

View file

@ -23,6 +23,7 @@ import (
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"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/eth/downloader" "github.com/ethereum/go-ethereum/eth/downloader"
"github.com/ethereum/go-ethereum/eth/protocols/eth" "github.com/ethereum/go-ethereum/eth/protocols/eth"
"github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/log"
@ -36,7 +37,7 @@ const (
// syncTransactions starts sending all currently pending transactions to the given peer. // syncTransactions starts sending all currently pending transactions to the given peer.
func (h *handler) syncTransactions(p *eth.Peer) { func (h *handler) syncTransactions(p *eth.Peer) {
var hashes []common.Hash var hashes []common.Hash
for _, batch := range h.txpool.Pending(nil, nil, nil) { for _, batch := range h.txpool.Pending(txpool.PendingFilter{OnlyPlainTxs: true}) {
for _, tx := range batch { for _, tx := range batch {
hashes = append(hashes, tx.Hash) hashes = append(hashes, tx.Hash)
} }

View file

@ -288,7 +288,7 @@ type PersonalAccountAPI struct {
b Backend b Backend
} }
// NewPersonalAccountAPI create a new PersonalAccountAPI. // NewPersonalAccountAPI creates a new PersonalAccountAPI.
func NewPersonalAccountAPI(b Backend, nonceLock *AddrLocker) *PersonalAccountAPI { func NewPersonalAccountAPI(b Backend, nonceLock *AddrLocker) *PersonalAccountAPI {
return &PersonalAccountAPI{ return &PersonalAccountAPI{
am: b.AccountManager(), am: b.AccountManager(),

View file

@ -2747,6 +2747,7 @@ func setupReceiptBackend(t *testing.T, genBlocks int) (*testBackend, []common.Ha
tx *types.Transaction tx *types.Transaction
err error err error
) )
b.SetPoS()
switch i { switch i {
case 0: case 0:
// transfer 1000wei // transfer 1000wei
@ -2795,7 +2796,6 @@ func setupReceiptBackend(t *testing.T, genBlocks int) (*testBackend, []common.Ha
b.AddTx(tx) b.AddTx(tx)
txHashes[i] = tx.Hash() txHashes[i] = tx.Hash()
} }
b.SetPoS()
}) })
return backend, txHashes return backend, txHashes
} }

View file

@ -221,6 +221,13 @@ func TestSetFeeDefaults(t *testing.T) {
&TransactionArgs{BlobHashes: []common.Hash{}, BlobFeeCap: (*hexutil.Big)(big.NewInt(4)), MaxFeePerGas: maxFee, MaxPriorityFeePerGas: fortytwo}, &TransactionArgs{BlobHashes: []common.Hash{}, BlobFeeCap: (*hexutil.Big)(big.NewInt(4)), MaxFeePerGas: maxFee, MaxPriorityFeePerGas: fortytwo},
nil, nil,
}, },
{
"fill maxFeePerBlobGas when dynamic fees are set",
"cancun",
&TransactionArgs{BlobHashes: []common.Hash{}, MaxFeePerGas: maxFee, MaxPriorityFeePerGas: fortytwo},
&TransactionArgs{BlobHashes: []common.Hash{}, BlobFeeCap: (*hexutil.Big)(big.NewInt(4)), MaxFeePerGas: maxFee, MaxPriorityFeePerGas: fortytwo},
nil,
},
} }
ctx := context.Background() ctx := context.Background()
@ -233,12 +240,13 @@ func TestSetFeeDefaults(t *testing.T) {
if err != nil { if err != nil {
if test.err == nil { if test.err == nil {
t.Fatalf("test %d (%s): unexpected error: %s", i, test.name, err) t.Fatalf("test %d (%s): unexpected error: %s", i, test.name, err)
} else if err.Error() != test.err.Error() {
t.Fatalf("test %d (%s): unexpected error: (got: %s, want: %s)", i, test.name, err, test.err)
} }
if err.Error() == test.err.Error() { // Matching error.
// Test threw expected error.
continue continue
} } else if test.err != nil {
t.Fatalf("test %d (%s): unexpected error: %s", i, test.name, err) t.Fatalf("test %d (%s): expected error: %s", i, test.name, test.err)
} }
if !reflect.DeepEqual(got, test.want) { if !reflect.DeepEqual(got, test.want) {
t.Fatalf("test %d (%s): did not fill defaults as expected: (got: %v, want: %v)", i, test.name, got, test.want) t.Fatalf("test %d (%s): did not fill defaults as expected: (got: %v, want: %v)", i, test.name, got, test.want)

View file

@ -21,28 +21,31 @@ import (
"math/big" "math/big"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/math"
"github.com/ethereum/go-ethereum/core/txpool" "github.com/ethereum/go-ethereum/core/txpool"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/holiman/uint256"
) )
// txWithMinerFee wraps a transaction with its gas price or effective miner gasTipCap // txWithMinerFee wraps a transaction with its gas price or effective miner gasTipCap
type txWithMinerFee struct { type txWithMinerFee struct {
tx *txpool.LazyTransaction tx *txpool.LazyTransaction
from common.Address from common.Address
fees *big.Int fees *uint256.Int
} }
// newTxWithMinerFee creates a wrapped transaction, calculating the effective // newTxWithMinerFee creates a wrapped transaction, calculating the effective
// miner gasTipCap if a base fee is provided. // miner gasTipCap if a base fee is provided.
// Returns error in case of a negative effective miner gasTipCap. // Returns error in case of a negative effective miner gasTipCap.
func newTxWithMinerFee(tx *txpool.LazyTransaction, from common.Address, baseFee *big.Int) (*txWithMinerFee, error) { func newTxWithMinerFee(tx *txpool.LazyTransaction, from common.Address, baseFee *uint256.Int) (*txWithMinerFee, error) {
tip := new(big.Int).Set(tx.GasTipCap) tip := new(uint256.Int).Set(tx.GasTipCap)
if baseFee != nil { if baseFee != nil {
if tx.GasFeeCap.Cmp(baseFee) < 0 { if tx.GasFeeCap.Cmp(baseFee) < 0 {
return nil, types.ErrGasFeeCapTooLow return nil, types.ErrGasFeeCapTooLow
} }
tip = math.BigMin(tx.GasTipCap, new(big.Int).Sub(tx.GasFeeCap, baseFee)) tip = new(uint256.Int).Sub(tx.GasFeeCap, baseFee)
if tip.Gt(tx.GasTipCap) {
tip = tx.GasTipCap
}
} }
return &txWithMinerFee{ return &txWithMinerFee{
tx: tx, tx: tx,
@ -87,7 +90,7 @@ type transactionsByPriceAndNonce struct {
txs map[common.Address][]*txpool.LazyTransaction // Per account nonce-sorted list of transactions txs map[common.Address][]*txpool.LazyTransaction // Per account nonce-sorted list of transactions
heads txByPriceAndTime // Next transaction for each unique account (price heap) heads txByPriceAndTime // Next transaction for each unique account (price heap)
signer types.Signer // Signer for the set of transactions signer types.Signer // Signer for the set of transactions
baseFee *big.Int // Current base fee baseFee *uint256.Int // Current base fee
} }
// newTransactionsByPriceAndNonce creates a transaction set that can retrieve // newTransactionsByPriceAndNonce creates a transaction set that can retrieve
@ -96,10 +99,15 @@ type transactionsByPriceAndNonce struct {
// Note, the input map is reowned so the caller should not interact any more with // Note, the input map is reowned so the caller should not interact any more with
// if after providing it to the constructor. // if after providing it to the constructor.
func newTransactionsByPriceAndNonce(signer types.Signer, txs map[common.Address][]*txpool.LazyTransaction, baseFee *big.Int) *transactionsByPriceAndNonce { func newTransactionsByPriceAndNonce(signer types.Signer, txs map[common.Address][]*txpool.LazyTransaction, baseFee *big.Int) *transactionsByPriceAndNonce {
// Convert the basefee from header format to uint256 format
var baseFeeUint *uint256.Int
if baseFee != nil {
baseFeeUint = uint256.MustFromBig(baseFee)
}
// Initialize a price and received time based heap with the head transactions // Initialize a price and received time based heap with the head transactions
heads := make(txByPriceAndTime, 0, len(txs)) heads := make(txByPriceAndTime, 0, len(txs))
for from, accTxs := range txs { for from, accTxs := range txs {
wrapped, err := newTxWithMinerFee(accTxs[0], from, baseFee) wrapped, err := newTxWithMinerFee(accTxs[0], from, baseFeeUint)
if err != nil { if err != nil {
delete(txs, from) delete(txs, from)
continue continue
@ -114,12 +122,12 @@ func newTransactionsByPriceAndNonce(signer types.Signer, txs map[common.Address]
txs: txs, txs: txs,
heads: heads, heads: heads,
signer: signer, signer: signer,
baseFee: baseFee, baseFee: baseFeeUint,
} }
} }
// Peek returns the next transaction by price. // Peek returns the next transaction by price.
func (t *transactionsByPriceAndNonce) Peek() (*txpool.LazyTransaction, *big.Int) { func (t *transactionsByPriceAndNonce) Peek() (*txpool.LazyTransaction, *uint256.Int) {
if len(t.heads) == 0 { if len(t.heads) == 0 {
return nil, nil return nil, nil
} }
@ -145,3 +153,14 @@ func (t *transactionsByPriceAndNonce) Shift() {
func (t *transactionsByPriceAndNonce) Pop() { func (t *transactionsByPriceAndNonce) Pop() {
heap.Pop(&t.heads) heap.Pop(&t.heads)
} }
// Empty returns if the price heap is empty. It can be used to check it simpler
// than calling peek and checking for nil return.
func (t *transactionsByPriceAndNonce) Empty() bool {
return len(t.heads) == 0
}
// Clear removes the entire content of the heap.
func (t *transactionsByPriceAndNonce) Clear() {
t.heads, t.txs = nil, nil
}

View file

@ -27,6 +27,7 @@ import (
"github.com/ethereum/go-ethereum/core/txpool" "github.com/ethereum/go-ethereum/core/txpool"
"github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/crypto"
"github.com/holiman/uint256"
) )
func TestTransactionPriceNonceSortLegacy(t *testing.T) { func TestTransactionPriceNonceSortLegacy(t *testing.T) {
@ -92,8 +93,8 @@ func testTransactionPriceNonceSort(t *testing.T, baseFee *big.Int) {
Hash: tx.Hash(), Hash: tx.Hash(),
Tx: tx, Tx: tx,
Time: tx.Time(), Time: tx.Time(),
GasFeeCap: tx.GasFeeCap(), GasFeeCap: uint256.MustFromBig(tx.GasFeeCap()),
GasTipCap: tx.GasTipCap(), GasTipCap: uint256.MustFromBig(tx.GasTipCap()),
Gas: tx.Gas(), Gas: tx.Gas(),
BlobGas: tx.BlobGas(), BlobGas: tx.BlobGas(),
}) })
@ -160,8 +161,8 @@ func TestTransactionTimeSort(t *testing.T) {
Hash: tx.Hash(), Hash: tx.Hash(),
Tx: tx, Tx: tx,
Time: tx.Time(), Time: tx.Time(),
GasFeeCap: tx.GasFeeCap(), GasFeeCap: uint256.MustFromBig(tx.GasFeeCap()),
GasTipCap: tx.GasTipCap(), GasTipCap: uint256.MustFromBig(tx.GasTipCap()),
Gas: tx.Gas(), Gas: tx.Gas(),
BlobGas: tx.BlobGas(), BlobGas: tx.BlobGas(),
}) })

View file

@ -206,7 +206,7 @@ type worker struct {
mu sync.RWMutex // The lock used to protect the coinbase and extra fields mu sync.RWMutex // The lock used to protect the coinbase and extra fields
coinbase common.Address coinbase common.Address
extra []byte extra []byte
tip *big.Int // Minimum tip needed for non-local transaction to include them tip *uint256.Int // Minimum tip needed for non-local transaction to include them
pendingMu sync.RWMutex pendingMu sync.RWMutex
pendingTasks map[common.Hash]*task pendingTasks map[common.Hash]*task
@ -253,7 +253,7 @@ func newWorker(config *Config, chainConfig *params.ChainConfig, engine consensus
isLocalBlock: isLocalBlock, isLocalBlock: isLocalBlock,
coinbase: config.Etherbase, coinbase: config.Etherbase,
extra: config.ExtraData, extra: config.ExtraData,
tip: config.GasPrice, tip: uint256.MustFromBig(config.GasPrice),
pendingTasks: make(map[common.Hash]*task), pendingTasks: make(map[common.Hash]*task),
txsCh: make(chan core.NewTxsEvent, txChanSize), txsCh: make(chan core.NewTxsEvent, txChanSize),
chainHeadCh: make(chan core.ChainHeadEvent, chainHeadChanSize), chainHeadCh: make(chan core.ChainHeadEvent, chainHeadChanSize),
@ -334,7 +334,7 @@ func (w *worker) setExtra(extra []byte) {
func (w *worker) setGasTip(tip *big.Int) { func (w *worker) setGasTip(tip *big.Int) {
w.mu.Lock() w.mu.Lock()
defer w.mu.Unlock() defer w.mu.Unlock()
w.tip = tip w.tip = uint256.MustFromBig(tip)
} }
// setRecommitInterval updates the interval for miner sealing work recommitting. // setRecommitInterval updates the interval for miner sealing work recommitting.
@ -556,15 +556,17 @@ func (w *worker) mainLoop() {
Hash: tx.Hash(), Hash: tx.Hash(),
Tx: nil, // Do *not* set this! We need to resolve it later to pull blobs in Tx: nil, // Do *not* set this! We need to resolve it later to pull blobs in
Time: tx.Time(), Time: tx.Time(),
GasFeeCap: tx.GasFeeCap(), GasFeeCap: uint256.MustFromBig(tx.GasFeeCap()),
GasTipCap: tx.GasTipCap(), GasTipCap: uint256.MustFromBig(tx.GasTipCap()),
Gas: tx.Gas(), Gas: tx.Gas(),
BlobGas: tx.BlobGas(), BlobGas: tx.BlobGas(),
}) })
} }
txset := newTransactionsByPriceAndNonce(w.current.signer, txs, w.current.header.BaseFee) plainTxs := newTransactionsByPriceAndNonce(w.current.signer, txs, w.current.header.BaseFee) // Mixed bag of everrything, yolo
blobTxs := newTransactionsByPriceAndNonce(w.current.signer, nil, w.current.header.BaseFee) // Empty bag, don't bother optimising
tcount := w.current.tcount tcount := w.current.tcount
w.commitTransactions(w.current, txset, nil, new(big.Int)) w.commitTransactions(w.current, plainTxs, blobTxs, nil)
// Only update the snapshot if any new transactions were added // Only update the snapshot if any new transactions were added
// to the pending block // to the pending block
@ -802,7 +804,7 @@ func (w *worker) applyTransaction(env *environment, tx *types.Transaction) (*typ
return receipt, err return receipt, err
} }
func (w *worker) commitTransactions(env *environment, txs *transactionsByPriceAndNonce, interrupt *atomic.Int32, minTip *big.Int) error { func (w *worker) commitTransactions(env *environment, plainTxs, blobTxs *transactionsByPriceAndNonce, interrupt *atomic.Int32) error {
gasLimit := env.header.GasLimit gasLimit := env.header.GasLimit
if env.gasPool == nil { if env.gasPool == nil {
env.gasPool = new(core.GasPool).AddGas(gasLimit) env.gasPool = new(core.GasPool).AddGas(gasLimit)
@ -821,8 +823,33 @@ func (w *worker) commitTransactions(env *environment, txs *transactionsByPriceAn
log.Trace("Not enough gas for further transactions", "have", env.gasPool, "want", params.TxGas) log.Trace("Not enough gas for further transactions", "have", env.gasPool, "want", params.TxGas)
break break
} }
// If we don't have enough blob space for any further blob transactions,
// skip that list altogether
if !blobTxs.Empty() && env.blobs*params.BlobTxBlobGasPerBlob >= params.MaxBlobGasPerBlock {
log.Trace("Not enough blob space for further blob transactions")
blobTxs.Clear()
// Fall though to pick up any plain txs
}
// Retrieve the next transaction and abort if all done. // Retrieve the next transaction and abort if all done.
ltx, tip := txs.Peek() var (
ltx *txpool.LazyTransaction
txs *transactionsByPriceAndNonce
)
pltx, ptip := plainTxs.Peek()
bltx, btip := blobTxs.Peek()
switch {
case pltx == nil:
txs, ltx = blobTxs, bltx
case bltx == nil:
txs, ltx = plainTxs, pltx
default:
if ptip.Lt(btip) {
txs, ltx = blobTxs, bltx
} else {
txs, ltx = plainTxs, pltx
}
}
if ltx == nil { if ltx == nil {
break break
} }
@ -837,11 +864,6 @@ func (w *worker) commitTransactions(env *environment, txs *transactionsByPriceAn
txs.Pop() txs.Pop()
continue continue
} }
// If we don't receive enough tip for the next transaction, skip the account
if tip.Cmp(minTip) < 0 {
log.Trace("Not enough tip for transaction", "hash", ltx.Hash, "tip", tip, "needed", minTip)
break // If the next-best is too low, surely no better will be available
}
// Transaction seems to fit, pull it up from the pool // Transaction seems to fit, pull it up from the pool
tx := ltx.Resolve() tx := ltx.Resolve()
if tx == nil { if tx == nil {
@ -1005,35 +1027,49 @@ func (w *worker) fillTransactions(interrupt *atomic.Int32, env *environment) err
w.mu.RUnlock() w.mu.RUnlock()
// Retrieve the pending transactions pre-filtered by the 1559/4844 dynamic fees // Retrieve the pending transactions pre-filtered by the 1559/4844 dynamic fees
var baseFee *uint256.Int filter := txpool.PendingFilter{
MinTip: tip,
}
if env.header.BaseFee != nil { if env.header.BaseFee != nil {
baseFee = uint256.MustFromBig(env.header.BaseFee) filter.BaseFee = uint256.MustFromBig(env.header.BaseFee)
} }
var blobFee *uint256.Int
if env.header.ExcessBlobGas != nil { if env.header.ExcessBlobGas != nil {
blobFee = uint256.MustFromBig(eip4844.CalcBlobFee(*env.header.ExcessBlobGas)) filter.BlobFee = uint256.MustFromBig(eip4844.CalcBlobFee(*env.header.ExcessBlobGas))
} }
pending := w.eth.TxPool().Pending(uint256.MustFromBig(tip), baseFee, blobFee) filter.OnlyPlainTxs, filter.OnlyBlobTxs = true, false
pendingPlainTxs := w.eth.TxPool().Pending(filter)
filter.OnlyPlainTxs, filter.OnlyBlobTxs = false, true
pendingBlobTxs := w.eth.TxPool().Pending(filter)
// Split the pending transactions into locals and remotes. // Split the pending transactions into locals and remotes.
localTxs, remoteTxs := make(map[common.Address][]*txpool.LazyTransaction), pending localPlainTxs, remotePlainTxs := make(map[common.Address][]*txpool.LazyTransaction), pendingPlainTxs
for _, account := range w.eth.TxPool().Locals() { localBlobTxs, remoteBlobTxs := make(map[common.Address][]*txpool.LazyTransaction), pendingBlobTxs
if txs := remoteTxs[account]; len(txs) > 0 {
delete(remoteTxs, account)
localTxs[account] = txs
}
}
for _, account := range w.eth.TxPool().Locals() {
if txs := remotePlainTxs[account]; len(txs) > 0 {
delete(remotePlainTxs, account)
localPlainTxs[account] = txs
}
if txs := remoteBlobTxs[account]; len(txs) > 0 {
delete(remoteBlobTxs, account)
localBlobTxs[account] = txs
}
}
// Fill the block with all available pending transactions. // Fill the block with all available pending transactions.
if len(localTxs) > 0 { if len(localPlainTxs) > 0 || len(localBlobTxs) > 0 {
txs := newTransactionsByPriceAndNonce(env.signer, localTxs, env.header.BaseFee) plainTxs := newTransactionsByPriceAndNonce(env.signer, localPlainTxs, env.header.BaseFee)
if err := w.commitTransactions(env, txs, interrupt, new(big.Int)); err != nil { blobTxs := newTransactionsByPriceAndNonce(env.signer, localBlobTxs, env.header.BaseFee)
if err := w.commitTransactions(env, plainTxs, blobTxs, interrupt); err != nil {
return err return err
} }
} }
if len(remoteTxs) > 0 { if len(remotePlainTxs) > 0 || len(remoteBlobTxs) > 0 {
txs := newTransactionsByPriceAndNonce(env.signer, remoteTxs, env.header.BaseFee) plainTxs := newTransactionsByPriceAndNonce(env.signer, remotePlainTxs, env.header.BaseFee)
if err := w.commitTransactions(env, txs, interrupt, tip); err != nil { blobTxs := newTransactionsByPriceAndNonce(env.signer, remoteBlobTxs, env.header.BaseFee)
if err := w.commitTransactions(env, plainTxs, blobTxs, interrupt); err != nil {
return err return err
} }
} }

View file

@ -467,7 +467,7 @@ func (c *ChainConfig) Description() string {
banner += fmt.Sprintf(" - Shanghai: @%-10v (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/shanghai.md)\n", *c.ShanghaiTime) banner += fmt.Sprintf(" - Shanghai: @%-10v (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/shanghai.md)\n", *c.ShanghaiTime)
} }
if c.CancunTime != nil { if c.CancunTime != nil {
banner += fmt.Sprintf(" - Cancun: @%-10v\n", *c.CancunTime) banner += fmt.Sprintf(" - Cancun: @%-10v (https://github.com/ethereum/execution-specs/blob/master/network-upgrades/mainnet-upgrades/cancun.md)\n", *c.CancunTime)
} }
if c.PragueTime != nil { if c.PragueTime != nil {
banner += fmt.Sprintf(" - Prague: @%-10v\n", *c.PragueTime) banner += fmt.Sprintf(" - Prague: @%-10v\n", *c.PragueTime)
@ -910,6 +910,8 @@ func (c *ChainConfig) Rules(num *big.Int, isMerge bool, timestamp uint64) Rules
if chainID == nil { if chainID == nil {
chainID = new(big.Int) chainID = new(big.Int)
} }
// disallow setting Merge out of order
isMerge = isMerge && c.IsLondon(num)
return Rules{ return Rules{
ChainID: new(big.Int).Set(chainID), ChainID: new(big.Int).Set(chainID),
IsHomestead: c.IsHomestead(num), IsHomestead: c.IsHomestead(num),
@ -923,9 +925,9 @@ func (c *ChainConfig) Rules(num *big.Int, isMerge bool, timestamp uint64) Rules
IsBerlin: c.IsBerlin(num), IsBerlin: c.IsBerlin(num),
IsLondon: c.IsLondon(num), IsLondon: c.IsLondon(num),
IsMerge: isMerge, IsMerge: isMerge,
IsShanghai: c.IsShanghai(num, timestamp), IsShanghai: isMerge && c.IsShanghai(num, timestamp),
IsCancun: c.IsCancun(num, timestamp), IsCancun: isMerge && c.IsCancun(num, timestamp),
IsPrague: c.IsPrague(num, timestamp), IsPrague: isMerge && c.IsPrague(num, timestamp),
IsVerkle: c.IsVerkle(num, timestamp), IsVerkle: isMerge && c.IsVerkle(num, timestamp),
} }
} }