Skip to content

Commit 593e303

Browse files
karalabeholiman
andauthored
core/txpool, eth, miner: pre-filter dynamic fees during pending tx retrieval (#29005)
* core/txpool, eth, miner: pre-filter dynamic fees during pending tx retrieval * miner: fix typo * core/txpool: handle init-error in blobpool without panicing --------- Co-authored-by: Martin Holst Swende <[email protected]>
1 parent 95741b1 commit 593e303

File tree

10 files changed

+79
-25
lines changed

10 files changed

+79
-25
lines changed

core/txpool/blobpool/blobpool.go

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -436,8 +436,10 @@ func (p *BlobPool) Init(gasTip uint64, head *types.Header, reserve txpool.Addres
436436
// Close closes down the underlying persistent store.
437437
func (p *BlobPool) Close() error {
438438
var errs []error
439-
if err := p.limbo.Close(); err != nil {
440-
errs = append(errs, err)
439+
if p.limbo != nil { // Close might be invoked due to error in constructor, before p,limbo is set
440+
if err := p.limbo.Close(); err != nil {
441+
errs = append(errs, err)
442+
}
441443
}
442444
if err := p.store.Close(); err != nil {
443445
errs = append(errs, err)
@@ -1441,7 +1443,10 @@ func (p *BlobPool) drop() {
14411443

14421444
// Pending retrieves all currently processable transactions, grouped by origin
14431445
// account and sorted by nonce.
1444-
func (p *BlobPool) Pending(enforceTips bool) map[common.Address][]*txpool.LazyTransaction {
1446+
//
1447+
// The transactions can also be pre-filtered by the dynamic fee components to
1448+
// reduce allocations and load on downstream subsystems.
1449+
func (p *BlobPool) Pending(minTip *uint256.Int, baseFee *uint256.Int, blobFee *uint256.Int) map[common.Address][]*txpool.LazyTransaction {
14451450
// Track the amount of time waiting to retrieve the list of pending blob txs
14461451
// from the pool and the amount of time actually spent on assembling the data.
14471452
// The latter will be pretty much moot, but we've kept it to have symmetric
@@ -1459,6 +1464,25 @@ func (p *BlobPool) Pending(enforceTips bool) map[common.Address][]*txpool.LazyTr
14591464
for addr, txs := range p.index {
14601465
var lazies []*txpool.LazyTransaction
14611466
for _, tx := range txs {
1467+
// If transaction filtering was requested, discard badly priced ones
1468+
if minTip != nil && baseFee != nil {
1469+
if tx.execFeeCap.Lt(baseFee) {
1470+
break // basefee too low, cannot be included, discard rest of txs from the account
1471+
}
1472+
tip := new(uint256.Int).Sub(tx.execFeeCap, baseFee)
1473+
if tip.Gt(tx.execTipCap) {
1474+
tip = tx.execTipCap
1475+
}
1476+
if tip.Lt(minTip) {
1477+
break // allowed or remaining tip too low, cannot be included, discard rest of txs from the account
1478+
}
1479+
}
1480+
if blobFee != nil {
1481+
if tx.blobFeeCap.Lt(blobFee) {
1482+
break // blobfee too low, cannot be included, discard rest of txs from the account
1483+
}
1484+
}
1485+
// Transaction was accepted according to the filter, append to the pending list
14621486
lazies = append(lazies, &txpool.LazyTransaction{
14631487
Pool: p,
14641488
Hash: tx.hash,

core/txpool/legacypool/legacypool.go

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -518,24 +518,34 @@ func (pool *LegacyPool) ContentFrom(addr common.Address) ([]*types.Transaction,
518518
}
519519

520520
// Pending retrieves all currently processable transactions, grouped by origin
521-
// account and sorted by nonce. The returned transaction set is a copy and can be
522-
// freely modified by calling code.
521+
// account and sorted by nonce.
523522
//
524-
// The enforceTips parameter can be used to do an extra filtering on the pending
525-
// transactions and only return those whose **effective** tip is large enough in
526-
// the next pending execution environment.
527-
func (pool *LegacyPool) Pending(enforceTips bool) map[common.Address][]*txpool.LazyTransaction {
523+
// The transactions can also be pre-filtered by the dynamic fee components to
524+
// reduce allocations and load on downstream subsystems.
525+
func (pool *LegacyPool) Pending(minTip *uint256.Int, baseFee *uint256.Int, blobFee *uint256.Int) map[common.Address][]*txpool.LazyTransaction {
528526
pool.mu.Lock()
529527
defer pool.mu.Unlock()
530528

529+
// Convert the new uint256.Int types to the old big.Int ones used by the legacy pool
530+
var (
531+
minTipBig *big.Int
532+
baseFeeBig *big.Int
533+
)
534+
if minTip != nil {
535+
minTipBig = minTip.ToBig()
536+
}
537+
if baseFee != nil {
538+
baseFeeBig = baseFee.ToBig()
539+
}
540+
531541
pending := make(map[common.Address][]*txpool.LazyTransaction, len(pool.pending))
532542
for addr, list := range pool.pending {
533543
txs := list.Flatten()
534544

535545
// If the miner requests tip enforcement, cap the lists now
536-
if enforceTips && !pool.locals.contains(addr) {
546+
if minTipBig != nil && !pool.locals.contains(addr) {
537547
for i, tx := range txs {
538-
if tx.EffectiveGasTipIntCmp(pool.gasTip.Load().ToBig(), pool.priced.urgent.baseFee) < 0 {
548+
if tx.EffectiveGasTipIntCmp(minTipBig, baseFeeBig) < 0 {
539549
txs = txs[:i]
540550
break
541551
}

core/txpool/subpool.go

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424
"github.com/ethereum/go-ethereum/core"
2525
"github.com/ethereum/go-ethereum/core/types"
2626
"github.com/ethereum/go-ethereum/event"
27+
"github.com/holiman/uint256"
2728
)
2829

2930
// LazyTransaction contains a small subset of the transaction properties that is
@@ -114,7 +115,10 @@ type SubPool interface {
114115

115116
// Pending retrieves all currently processable transactions, grouped by origin
116117
// account and sorted by nonce.
117-
Pending(enforceTips bool) map[common.Address][]*LazyTransaction
118+
//
119+
// The transactions can also be pre-filtered by the dynamic fee components to
120+
// reduce allocations and load on downstream subsystems.
121+
Pending(minTip *uint256.Int, baseFee *uint256.Int, blobFee *uint256.Int) map[common.Address][]*LazyTransaction
118122

119123
// SubscribeTransactions subscribes to new transaction events. The subscriber
120124
// can decide whether to receive notifications only for newly seen transactions

core/txpool/txpool.go

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import (
2828
"github.com/ethereum/go-ethereum/event"
2929
"github.com/ethereum/go-ethereum/log"
3030
"github.com/ethereum/go-ethereum/metrics"
31+
"github.com/holiman/uint256"
3132
)
3233

3334
// TxStatus is the current status of a transaction as seen by the pool.
@@ -353,10 +354,13 @@ func (p *TxPool) Add(txs []*types.Transaction, local bool, sync bool) []error {
353354

354355
// Pending retrieves all currently processable transactions, grouped by origin
355356
// account and sorted by nonce.
356-
func (p *TxPool) Pending(enforceTips bool) map[common.Address][]*LazyTransaction {
357+
//
358+
// The transactions can also be pre-filtered by the dynamic fee components to
359+
// reduce allocations and load on downstream subsystems.
360+
func (p *TxPool) Pending(minTip *uint256.Int, baseFee *uint256.Int, blobFee *uint256.Int) map[common.Address][]*LazyTransaction {
357361
txs := make(map[common.Address][]*LazyTransaction)
358362
for _, subpool := range p.subpools {
359-
for addr, set := range subpool.Pending(enforceTips) {
363+
for addr, set := range subpool.Pending(minTip, baseFee, blobFee) {
360364
txs[addr] = set
361365
}
362366
}

eth/api_backend.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,7 @@ func (b *EthAPIBackend) SendTx(ctx context.Context, signedTx *types.Transaction)
292292
}
293293

294294
func (b *EthAPIBackend) GetPoolTransactions() (types.Transactions, error) {
295-
pending := b.eth.txPool.Pending(false)
295+
pending := b.eth.txPool.Pending(nil, nil, nil)
296296
var txs types.Transactions
297297
for _, batch := range pending {
298298
for _, lazy := range batch {

eth/catalyst/simulated_beacon.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,7 @@ func (c *SimulatedBeacon) Rollback() {
263263

264264
// Fork sets the head to the provided hash.
265265
func (c *SimulatedBeacon) Fork(parentHash common.Hash) error {
266-
if len(c.eth.TxPool().Pending(false)) != 0 {
266+
if len(c.eth.TxPool().Pending(nil, nil, nil)) != 0 {
267267
return errors.New("pending block dirty")
268268
}
269269
parent := c.eth.BlockChain().GetBlockByHash(parentHash)
@@ -275,7 +275,7 @@ func (c *SimulatedBeacon) Fork(parentHash common.Hash) error {
275275

276276
// AdjustTime creates a new block with an adjusted timestamp.
277277
func (c *SimulatedBeacon) AdjustTime(adjustment time.Duration) error {
278-
if len(c.eth.TxPool().Pending(false)) != 0 {
278+
if len(c.eth.TxPool().Pending(nil, nil, nil)) != 0 {
279279
return errors.New("could not adjust time on non-empty block")
280280
}
281281
parent := c.eth.BlockChain().CurrentBlock()

eth/handler.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ import (
4242
"github.com/ethereum/go-ethereum/metrics"
4343
"github.com/ethereum/go-ethereum/p2p"
4444
"github.com/ethereum/go-ethereum/triedb/pathdb"
45+
"github.com/holiman/uint256"
4546
)
4647

4748
const (
@@ -73,7 +74,7 @@ type txPool interface {
7374

7475
// Pending should return pending transactions.
7576
// The slice should be modifiable by the caller.
76-
Pending(enforceTips bool) map[common.Address][]*txpool.LazyTransaction
77+
Pending(minTip *uint256.Int, baseFee *uint256.Int, blobFee *uint256.Int) map[common.Address][]*txpool.LazyTransaction
7778

7879
// SubscribeTransactions subscribes to new transaction events. The subscriber
7980
// can decide whether to receive notifications only for newly seen transactions

eth/handler_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import (
3434
"github.com/ethereum/go-ethereum/ethdb"
3535
"github.com/ethereum/go-ethereum/event"
3636
"github.com/ethereum/go-ethereum/params"
37+
"github.com/holiman/uint256"
3738
)
3839

3940
var (
@@ -92,7 +93,7 @@ func (p *testTxPool) Add(txs []*types.Transaction, local bool, sync bool) []erro
9293
}
9394

9495
// Pending returns all the transactions known to the pool
95-
func (p *testTxPool) Pending(enforceTips bool) map[common.Address][]*txpool.LazyTransaction {
96+
func (p *testTxPool) Pending(minTip *uint256.Int, baseFee *uint256.Int, blobFee *uint256.Int) map[common.Address][]*txpool.LazyTransaction {
9697
p.lock.RLock()
9798
defer p.lock.RUnlock()
9899

eth/sync.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ const (
3636
// syncTransactions starts sending all currently pending transactions to the given peer.
3737
func (h *handler) syncTransactions(p *eth.Peer) {
3838
var hashes []common.Hash
39-
for _, batch := range h.txpool.Pending(false) {
39+
for _, batch := range h.txpool.Pending(nil, nil, nil) {
4040
for _, tx := range batch {
4141
hashes = append(hashes, tx.Hash)
4242
}

miner/worker.go

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ import (
3737
"github.com/ethereum/go-ethereum/log"
3838
"github.com/ethereum/go-ethereum/params"
3939
"github.com/ethereum/go-ethereum/trie"
40+
"github.com/holiman/uint256"
4041
)
4142

4243
const (
@@ -999,7 +1000,20 @@ func (w *worker) prepareWork(genParams *generateParams) (*environment, error) {
9991000
// into the given sealing block. The transaction selection and ordering strategy can
10001001
// be customized with the plugin in the future.
10011002
func (w *worker) fillTransactions(interrupt *atomic.Int32, env *environment) error {
1002-
pending := w.eth.TxPool().Pending(true)
1003+
w.mu.RLock()
1004+
tip := w.tip
1005+
w.mu.RUnlock()
1006+
1007+
// Retrieve the pending transactions pre-filtered by the 1559/4844 dynamic fees
1008+
var baseFee *uint256.Int
1009+
if env.header.BaseFee != nil {
1010+
baseFee = uint256.MustFromBig(env.header.BaseFee)
1011+
}
1012+
var blobFee *uint256.Int
1013+
if env.header.ExcessBlobGas != nil {
1014+
blobFee = uint256.MustFromBig(eip4844.CalcBlobFee(*env.header.ExcessBlobGas))
1015+
}
1016+
pending := w.eth.TxPool().Pending(uint256.MustFromBig(tip), baseFee, blobFee)
10031017

10041018
// Split the pending transactions into locals and remotes.
10051019
localTxs, remoteTxs := make(map[common.Address][]*txpool.LazyTransaction), pending
@@ -1011,10 +1025,6 @@ func (w *worker) fillTransactions(interrupt *atomic.Int32, env *environment) err
10111025
}
10121026

10131027
// Fill the block with all available pending transactions.
1014-
w.mu.RLock()
1015-
tip := w.tip
1016-
w.mu.RUnlock()
1017-
10181028
if len(localTxs) > 0 {
10191029
txs := newTransactionsByPriceAndNonce(env.signer, localTxs, env.header.BaseFee)
10201030
if err := w.commitTransactions(env, txs, interrupt, new(big.Int)); err != nil {

0 commit comments

Comments
 (0)