diff --git a/core/tx_pool.go b/core/tx_pool.go index 0b0241aa67..13c13ae3ec 100644 --- a/core/tx_pool.go +++ b/core/tx_pool.go @@ -26,6 +26,7 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/prque" + "github.com/ethereum/go-ethereum/consensus/misc" "github.com/ethereum/go-ethereum/core/state" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/event" @@ -496,13 +497,30 @@ func (pool *TxPool) Content() (map[common.Address]types.Transactions, map[common // Pending retrieves all currently processable transactions, grouped by origin // account and sorted by nonce. The returned transaction set is a copy and can be // freely modified by calling code. -func (pool *TxPool) Pending() (map[common.Address]types.Transactions, error) { +// +// The enforceTips parameter can be used to do an extra filtering on the pending +// transactions and only return those whose **effective** tip is large enough in +// the next pending execution environment. +func (pool *TxPool) Pending(enforceTips bool) (map[common.Address]types.Transactions, error) { pool.mu.Lock() defer pool.mu.Unlock() pending := make(map[common.Address]types.Transactions) for addr, list := range pool.pending { - pending[addr] = list.Flatten() + txs := list.Flatten() + + // If the miner requests tip enforcement, cap the lists now + if enforceTips && !pool.locals.contains(addr) { + for i, tx := range txs { + if tx.EffectiveTipIntCmp(pool.gasPrice, pool.priced.urgent.baseFee) < 0 { + txs = txs[:i] + break + } + } + } + if len(txs) > 0 { + pending[addr] = txs + } } return pending, nil } @@ -562,7 +580,7 @@ func (pool *TxPool) validateTx(tx *types.Transaction, local bool) error { if tx.Tip().BitLen() > 256 { return ErrTipVeryHigh } - // Ensure feeCap is less than or equal to tip. + // Ensure feeCap is greater than or equal to tip. if tx.FeeCapIntCmp(tx.Tip()) < 0 { return ErrTipAboveFeeCap } @@ -1114,8 +1132,9 @@ func (pool *TxPool) runReorg(done chan struct{}, reset *txpoolResetRequest, dirt // because of another transaction (e.g. higher gas price). if reset != nil { pool.demoteUnexecutables() - if reset.newHead != nil { - pool.priced.SetBaseFee(reset.newHead.BaseFee) + if reset.newHead != nil && pool.chainconfig.IsLondon(new(big.Int).Add(reset.newHead.Number, big.NewInt(1))) { + pendingBaseFee := misc.CalcBaseFee(pool.chainconfig, reset.newHead) + pool.priced.SetBaseFee(pendingBaseFee) } } // Ensure pool.queue and pool.pending sizes stay within the configured limits. diff --git a/core/tx_pool_test.go b/core/tx_pool_test.go index b23d40cd42..34877f42e0 100644 --- a/core/tx_pool_test.go +++ b/core/tx_pool_test.go @@ -252,7 +252,7 @@ func TestStateChangeDuringTransactionPoolReset(t *testing.T) { trigger = true <-pool.requestReset(nil, nil) - _, err := pool.Pending() + _, err := pool.Pending(false) if err != nil { t.Fatalf("Could not fetch pending transactions: %v", err) } diff --git a/core/types/transaction.go b/core/types/transaction.go index 2b0435bc63..03c9c28751 100644 --- a/core/types/transaction.go +++ b/core/types/transaction.go @@ -356,6 +356,14 @@ func (tx *Transaction) EffectiveTipCmp(other *Transaction, baseFee *big.Int) int return tx.EffectiveTipValue(baseFee).Cmp(other.EffectiveTipValue(baseFee)) } +// EffectiveTipIntCmp compares the effective tip of a transaction to the given tip. +func (tx *Transaction) EffectiveTipIntCmp(other *big.Int, baseFee *big.Int) int { + if baseFee == nil { + return tx.TipIntCmp(other) + } + return tx.EffectiveTipValue(baseFee).Cmp(other) +} + // Hash returns the transaction hash. func (tx *Transaction) Hash() common.Hash { if hash := tx.hash.Load(); hash != nil { diff --git a/eth/api_backend.go b/eth/api_backend.go index 7a2e649cf0..e6810f2a9b 100644 --- a/eth/api_backend.go +++ b/eth/api_backend.go @@ -231,7 +231,7 @@ func (b *EthAPIBackend) SendTx(ctx context.Context, signedTx *types.Transaction) } func (b *EthAPIBackend) GetPoolTransactions() (types.Transactions, error) { - pending, err := b.eth.txPool.Pending() + pending, err := b.eth.txPool.Pending(false) if err != nil { return nil, err } diff --git a/eth/catalyst/api.go b/eth/catalyst/api.go index 1e487d7781..bf717ed280 100644 --- a/eth/catalyst/api.go +++ b/eth/catalyst/api.go @@ -127,7 +127,7 @@ func (api *consensusAPI) AssembleBlock(params assembleBlockParams) (*executableD time.Sleep(wait) } - pending, err := pool.Pending() + pending, err := pool.Pending(true) if err != nil { return nil, err } diff --git a/eth/handler.go b/eth/handler.go index cd16538044..aff4871afa 100644 --- a/eth/handler.go +++ b/eth/handler.go @@ -66,7 +66,7 @@ type txPool interface { // Pending should return pending transactions. // The slice should be modifiable by the caller. - Pending() (map[common.Address]types.Transactions, error) + Pending(enforceTips bool) (map[common.Address]types.Transactions, error) // SubscribeNewTxsEvent should return an event subscription of // NewTxsEvent and send events to the given channel. diff --git a/eth/handler_test.go b/eth/handler_test.go index a90ef5c348..090bd9239c 100644 --- a/eth/handler_test.go +++ b/eth/handler_test.go @@ -91,7 +91,7 @@ func (p *testTxPool) AddRemotes(txs []*types.Transaction) []error { } // Pending returns all the transactions known to the pool -func (p *testTxPool) Pending() (map[common.Address]types.Transactions, error) { +func (p *testTxPool) Pending(enforceTips bool) (map[common.Address]types.Transactions, error) { p.lock.RLock() defer p.lock.RUnlock() diff --git a/eth/sync.go b/eth/sync.go index 4520ec6879..ab114b59f3 100644 --- a/eth/sync.go +++ b/eth/sync.go @@ -54,7 +54,7 @@ func (h *handler) syncTransactions(p *eth.Peer) { // // TODO(karalabe): Figure out if we could get away with random order somehow var txs types.Transactions - pending, _ := h.txpool.Pending() + pending, _ := h.txpool.Pending(false) for _, batch := range pending { txs = append(txs, batch...) } diff --git a/miner/worker.go b/miner/worker.go index f9aae0fdc9..0b08b73364 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -963,7 +963,7 @@ func (w *worker) commitNewWork(interrupt *int32, noempty bool, timestamp int64) } // Fill the block with all available pending transactions. - pending, err := w.eth.TxPool().Pending() + pending, err := w.eth.TxPool().Pending(true) if err != nil { log.Error("Failed to fetch pending transactions", "err", err) return