Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

core/txpool/legacypool: add overflowpool for txs #2660

Merged
merged 59 commits into from
Oct 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
59 commits
Select commit Hold shift + click to select a range
dfb046e
txpool: incomplete pool2 and pool3
emailtovamos Jul 16, 2024
e30248b
pool: optimise sending in reorg
emailtovamos Jul 29, 2024
f80ac01
pool: add static info and simplify transfer
emailtovamos Aug 1, 2024
8655d30
pool: remove comments, use queue not pool23
emailtovamos Aug 1, 2024
4538e92
pool: remove unused function
emailtovamos Aug 1, 2024
4369e3d
pool: refactor and bugfix
emailtovamos Aug 1, 2024
d0d6a27
pool: buffer test and size logic
emailtovamos Aug 2, 2024
5faf413
pool: add discarded ones to pool3 by default.
emailtovamos Aug 2, 2024
5bb78b3
pool: minor refactor
emailtovamos Aug 20, 2024
6b4e16b
pool: make slots config
emailtovamos Aug 21, 2024
d03f7e5
pool: initialise pool3 slots
emailtovamos Aug 21, 2024
94a60a9
pool: add underpriced to pool2 or 3
emailtovamos Aug 23, 2024
ed2d1d7
pool: enqueue in pool2 & drop properly
emailtovamos Aug 25, 2024
6daecfb
pool: bugfix:always drop drop and pool2 size
emailtovamos Aug 27, 2024
9d7298f
pool: TestDualHeapEviction passing partly
emailtovamos Aug 27, 2024
a1a25e9
pool: TestDualHeapEviction fully pass
emailtovamos Aug 27, 2024
253d9a5
pool: some cleanups
emailtovamos Aug 27, 2024
0692a99
pool: fix the TestTransactionFutureAttack test
emailtovamos Aug 28, 2024
40dcfcd
pool: cleanup debug logs
emailtovamos Aug 28, 2024
6673f3e
pool: fix TestUnderpricingDynamicFee based on new pool
emailtovamos Aug 28, 2024
ebd8f59
pool: fix all old tests
emailtovamos Aug 28, 2024
bdb4cc2
pool: lint
emailtovamos Aug 29, 2024
e45e7eb
pool: include static in flatten
emailtovamos Aug 29, 2024
069eaf2
pool: proper use of AsyncSendPooledTransactionHashes
emailtovamos Aug 29, 2024
70ece93
pool: flags for pool2 and 3 capacity
emailtovamos Aug 29, 2024
e7d0a16
pool: fix test as now by default pool2 and pool3 aren't empty
emailtovamos Aug 30, 2024
16a2a53
Merge remote-tracking branch 'origin/develop' into txpool-new
emailtovamos Sep 2, 2024
0f8a1b5
pool: test for transfer
emailtovamos Sep 3, 2024
76d157d
pool: set transfer time in config
emailtovamos Sep 3, 2024
aeec0c7
pool: remove unused criticalpathpool
emailtovamos Sep 3, 2024
53042e1
buffer: make private
emailtovamos Sep 3, 2024
8e6833c
pool: bug fix and test fix
emailtovamos Sep 3, 2024
5f398db
pool: pool2 can have 0 size
emailtovamos Sep 3, 2024
706a24e
pool: lint fix
emailtovamos Sep 4, 2024
0e61543
test: requestPromoteExecutables after every enqueue for testing
emailtovamos Sep 6, 2024
0a5dbef
pool: queued goes to 0 locally after this change
emailtovamos Sep 6, 2024
248bb6b
pool: fastcache, interface, metrics modify
emailtovamos Sep 11, 2024
cf10c5c
eth: send to some peers of pool2, not just static
emailtovamos Sep 11, 2024
b818cb7
pool: transfer on block import and simplify it
emailtovamos Sep 12, 2024
774e314
pool: truly discard underpriced, Transfer after lock is over
emailtovamos Sep 18, 2024
629af6d
pool: else ifs instead of ifs
emailtovamos Sep 18, 2024
3e3c56b
pool: address minor issues
emailtovamos Sep 19, 2024
0957562
pool: heap map as pool3
emailtovamos Sep 25, 2024
846e55b
pool: remove pool2 from legacypool
emailtovamos Sep 25, 2024
6a6e09c
pool: remove pool2 related code
emailtovamos Sep 26, 2024
355dee9
pool: edit tests and remove remaining pool2 logic
emailtovamos Sep 26, 2024
1ad40cd
pool: add back removed logic
emailtovamos Sep 26, 2024
d5b10e0
pool: remove fastcache which is no longer required
emailtovamos Sep 26, 2024
4e69ac4
pool: remove event and debug logs
emailtovamos Sep 26, 2024
31c9465
pool: remove old buffer for pool3
emailtovamos Sep 26, 2024
a8959fe
pool: minor refactors
emailtovamos Sep 26, 2024
9c72c02
pool: preallocate pool3
emailtovamos Sep 26, 2024
5d44ba9
pool: remove sequence, more sturdy, maxsize
emailtovamos Oct 1, 2024
7a929d6
pool: refactor to overflow pool
emailtovamos Oct 14, 2024
8170d99
Merge branch 'develop' into txpool-new
emailtovamos Oct 14, 2024
0e67514
pool: remove debug logs
emailtovamos Oct 14, 2024
f41bb13
pool: refactoring, addressing comments
emailtovamos Oct 15, 2024
0dd0bd7
pool: remove extra new lines
emailtovamos Oct 15, 2024
60bdc25
pool: fail fast, disable by default, no interface
emailtovamos Oct 16, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions cmd/geth/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ var (
utils.TxPoolGlobalSlotsFlag,
utils.TxPoolAccountQueueFlag,
utils.TxPoolGlobalQueueFlag,
utils.TxPoolOverflowPoolSlotsFlag,
utils.TxPoolLifetimeFlag,
utils.TxPoolReannounceTimeFlag,
utils.BlobPoolDataDirFlag,
Expand Down
30 changes: 20 additions & 10 deletions cmd/utils/flags.go
Original file line number Diff line number Diff line change
Expand Up @@ -458,6 +458,12 @@ var (
Value: ethconfig.Defaults.TxPool.GlobalQueue,
Category: flags.TxPoolCategory,
}
TxPoolOverflowPoolSlotsFlag = &cli.Uint64Flag{
Name: "txpool.overflowpoolslots",
Usage: "Maximum number of transaction slots in overflow pool",
Value: ethconfig.Defaults.TxPool.OverflowPoolSlots,
Category: flags.TxPoolCategory,
}
TxPoolLifetimeFlag = &cli.DurationFlag{
Name: "txpool.lifetime",
Usage: "Maximum amount of time non-executable transaction are queued",
Expand Down Expand Up @@ -1789,6 +1795,9 @@ func setTxPool(ctx *cli.Context, cfg *legacypool.Config) {
if ctx.IsSet(TxPoolGlobalQueueFlag.Name) {
cfg.GlobalQueue = ctx.Uint64(TxPoolGlobalQueueFlag.Name)
}
if ctx.IsSet(TxPoolOverflowPoolSlotsFlag.Name) {
cfg.OverflowPoolSlots = ctx.Uint64(TxPoolOverflowPoolSlotsFlag.Name)
}
if ctx.IsSet(TxPoolLifetimeFlag.Name) {
cfg.Lifetime = ctx.Duration(TxPoolLifetimeFlag.Name)
}
Expand Down Expand Up @@ -2310,16 +2319,17 @@ func EnableNodeInfo(poolConfig *legacypool.Config, nodeInfo *p2p.NodeInfo) Setup
return func() {
// register node info into metrics
metrics.NewRegisteredLabel("node-info", nil).Mark(map[string]interface{}{
"Enode": nodeInfo.Enode,
"ENR": nodeInfo.ENR,
"ID": nodeInfo.ID,
"PriceLimit": poolConfig.PriceLimit,
"PriceBump": poolConfig.PriceBump,
"AccountSlots": poolConfig.AccountSlots,
"GlobalSlots": poolConfig.GlobalSlots,
"AccountQueue": poolConfig.AccountQueue,
"GlobalQueue": poolConfig.GlobalQueue,
"Lifetime": poolConfig.Lifetime,
"Enode": nodeInfo.Enode,
"ENR": nodeInfo.ENR,
"ID": nodeInfo.ID,
"PriceLimit": poolConfig.PriceLimit,
"PriceBump": poolConfig.PriceBump,
"AccountSlots": poolConfig.AccountSlots,
"GlobalSlots": poolConfig.GlobalSlots,
"AccountQueue": poolConfig.AccountQueue,
"GlobalQueue": poolConfig.GlobalQueue,
"OverflowPoolSlots": poolConfig.OverflowPoolSlots,
"Lifetime": poolConfig.Lifetime,
})
}
}
Expand Down
119 changes: 105 additions & 14 deletions core/txpool/legacypool/legacypool.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package legacypool

import (
"errors"
"fmt"
"math"
"math/big"
"sort"
Expand Down Expand Up @@ -99,10 +100,11 @@ var (
// that this number is pretty low, since txpool reorgs happen very frequently.
dropBetweenReorgHistogram = metrics.NewRegisteredHistogram("txpool/dropbetweenreorg", nil, metrics.NewExpDecaySample(1028, 0.015))

pendingGauge = metrics.NewRegisteredGauge("txpool/pending", nil)
queuedGauge = metrics.NewRegisteredGauge("txpool/queued", nil)
localGauge = metrics.NewRegisteredGauge("txpool/local", nil)
slotsGauge = metrics.NewRegisteredGauge("txpool/slots", nil)
pendingGauge = metrics.NewRegisteredGauge("txpool/pending", nil)
queuedGauge = metrics.NewRegisteredGauge("txpool/queued", nil)
localGauge = metrics.NewRegisteredGauge("txpool/local", nil)
slotsGauge = metrics.NewRegisteredGauge("txpool/slots", nil)
OverflowPoolGauge = metrics.NewRegisteredGauge("txpool/overflowpool", nil)

reheapTimer = metrics.NewRegisteredTimer("txpool/reheap", nil)
)
Expand Down Expand Up @@ -133,10 +135,11 @@ type Config struct {
PriceLimit uint64 // Minimum gas price to enforce for acceptance into the pool
PriceBump uint64 // Minimum price bump percentage to replace an already existing transaction (nonce)

AccountSlots uint64 // Number of executable transaction slots guaranteed per account
GlobalSlots uint64 // Maximum number of executable transaction slots for all accounts
AccountQueue uint64 // Maximum number of non-executable transaction slots permitted per account
GlobalQueue uint64 // Maximum number of non-executable transaction slots for all accounts
AccountSlots uint64 // Number of executable transaction slots guaranteed per account
GlobalSlots uint64 // Maximum number of executable transaction slots for all accounts
AccountQueue uint64 // Maximum number of non-executable transaction slots permitted per account
GlobalQueue uint64 // Maximum number of non-executable transaction slots for all accounts
OverflowPoolSlots uint64 // Maximum number of transaction slots in overflow pool

Lifetime time.Duration // Maximum amount of time non-executable transaction are queued
ReannounceTime time.Duration // Duration for announcing local pending transactions again
Expand All @@ -150,10 +153,11 @@ var DefaultConfig = Config{
PriceLimit: 1,
PriceBump: 10,

AccountSlots: 16,
GlobalSlots: 4096 + 1024, // urgent + floating queue capacity with 4:1 ratio
AccountQueue: 64,
GlobalQueue: 1024,
AccountSlots: 16,
GlobalSlots: 4096 + 1024, // urgent + floating queue capacity with 4:1 ratio
AccountQueue: 64,
GlobalQueue: 1024,
OverflowPoolSlots: 0,

Lifetime: 3 * time.Hour,
ReannounceTime: 10 * 365 * 24 * time.Hour,
Expand Down Expand Up @@ -235,6 +239,8 @@ type LegacyPool struct {
all *lookup // All transactions to allow lookups
priced *pricedList // All transactions sorted by price

localBufferPool *TxOverflowPool // Local buffer transactions

reqResetCh chan *txpoolResetRequest
reqPromoteCh chan *accountSet
queueTxEventCh chan *types.Transaction
Expand Down Expand Up @@ -272,6 +278,7 @@ func New(config Config, chain BlockChain) *LegacyPool {
reorgDoneCh: make(chan chan struct{}),
reorgShutdownCh: make(chan struct{}),
initDoneCh: make(chan struct{}),
localBufferPool: NewTxOverflowPoolHeap(config.OverflowPoolSlots),
}
pool.locals = newAccountSet(pool.signer)
for _, addr := range config.Locals {
Expand Down Expand Up @@ -408,7 +415,6 @@ func (pool *LegacyPool) loop() {
if !pool.locals.contains(addr) {
continue
}

for _, tx := range list.Flatten() {
// Default ReannounceTime is 10 years, won't announce by default.
if time.Since(tx.Time()) < pool.config.ReannounceTime {
Expand Down Expand Up @@ -517,6 +523,17 @@ func (pool *LegacyPool) Stats() (int, int) {
return pool.stats()
}

func (pool *LegacyPool) statsOverflowPool() int {
pool.mu.RLock()
defer pool.mu.RUnlock()

if pool.localBufferPool == nil {
return 0
}

return pool.localBufferPool.Size()
}

// stats retrieves the current pool stats, namely the number of pending and the
// number of queued (non-executable) transactions.
func (pool *LegacyPool) stats() (int, int) {
Expand Down Expand Up @@ -831,6 +848,8 @@ func (pool *LegacyPool) add(tx *types.Transaction, local bool) (replaced bool, e
}
}

pool.addToOverflowPool(drop, isLocal)

// Kick out the underpriced remote transactions.
for _, tx := range drop {
log.Trace("Discarding freshly underpriced transaction", "hash", tx.Hash(), "gasTipCap", tx.GasTipCap(), "gasFeeCap", tx.GasFeeCap())
Expand Down Expand Up @@ -887,6 +906,29 @@ func (pool *LegacyPool) add(tx *types.Transaction, local bool) (replaced bool, e
return replaced, nil
}

func (pool *LegacyPool) addToOverflowPool(drop types.Transactions, isLocal bool) {
// calculate total number of slots in drop. Accordingly add them to OverflowPool (if there is space)
availableSlotsOverflowPool := pool.availableSlotsOverflowPool()
if availableSlotsOverflowPool > 0 {
// transfer availableSlotsOverflowPool number of transactions slots from drop to OverflowPool
currentSlotsUsed := 0
for i, tx := range drop {
txSlots := numSlots(tx)
if currentSlotsUsed+txSlots <= availableSlotsOverflowPool {
from, _ := types.Sender(pool.signer, tx)
pool.localBufferPool.Add(tx)
log.Debug("adding to OverflowPool", "transaction", tx.Hash().String(), "from", from.String())
currentSlotsUsed += txSlots
} else {
log.Debug("not all got added to OverflowPool", "totalAdded", i+1)
return
}
}
} else {
log.Debug("adding to OverflowPool unsuccessful", "availableSlotsOverflowPool", availableSlotsOverflowPool)
}
}

// isGapped reports whether the given transaction is immediately executable.
func (pool *LegacyPool) isGapped(from common.Address, tx *types.Transaction) bool {
// Short circuit if transaction falls within the scope of the pending list
Expand Down Expand Up @@ -1333,7 +1375,6 @@ func (pool *LegacyPool) runReorg(done chan struct{}, reset *txpoolResetRequest,
reorgDurationTimer.Update(time.Since(t0))
}(time.Now())
defer close(done)

var promoteAddrs []common.Address
if dirtyAccounts != nil && reset == nil {
// Only dirty accounts need to be promoted, unless we're resetting.
Expand Down Expand Up @@ -1391,6 +1432,9 @@ func (pool *LegacyPool) runReorg(done chan struct{}, reset *txpoolResetRequest,
pool.changesSinceReorg = 0 // Reset change counter
pool.mu.Unlock()

// Transfer transactions from OverflowPool to MainPool for new block import
pool.transferTransactions()
zzzckck marked this conversation as resolved.
Show resolved Hide resolved

// Notify subsystems for newly added transactions
for _, tx := range promoted {
addr, _ := types.Sender(pool.signer, tx)
Expand Down Expand Up @@ -2038,3 +2082,50 @@ func (t *lookup) RemotesBelowTip(threshold *big.Int) types.Transactions {
func numSlots(tx *types.Transaction) int {
return int((tx.Size() + txSlotSize - 1) / txSlotSize)
}

// transferTransactions moves transactions from OverflowPool to MainPool
func (pool *LegacyPool) transferTransactions() {
zzzckck marked this conversation as resolved.
Show resolved Hide resolved
// Fail fast if the overflow pool is empty
if pool.localBufferPool.Size() == 0 {
return
}

maxMainPoolSize := int(pool.config.GlobalSlots + pool.config.GlobalQueue)
// Use pool.all.Slots() to get the total slots used by all transactions
currentMainPoolSize := pool.all.Slots()
if currentMainPoolSize >= maxMainPoolSize {
return
}

extraSlots := maxMainPoolSize - currentMainPoolSize
extraTransactions := (extraSlots + 3) / 4 // Since a transaction can take up to 4 slots
log.Debug("Will attempt to transfer from OverflowPool to MainPool", "transactions", extraTransactions)
txs := pool.localBufferPool.Flush(extraTransactions)
if len(txs) == 0 {
return
}

pool.Add(txs, true, false)
}

func (pool *LegacyPool) availableSlotsOverflowPool() int {
maxOverflowPoolSize := int(pool.config.OverflowPoolSlots)
availableSlots := maxOverflowPoolSize - pool.localBufferPool.Size()
if availableSlots > 0 {
return availableSlots
}
return 0
}

func (pool *LegacyPool) PrintTxStats() {
for _, l := range pool.pending {
for _, transaction := range l.txs.items {
from, _ := types.Sender(pool.signer, transaction)
fmt.Println("from: ", from, " Pending:", transaction.Hash().String(), transaction.GasFeeCap(), transaction.GasTipCap())
}
}

pool.localBufferPool.PrintTxStats()
fmt.Println("length of all: ", pool.all.Slots())
fmt.Println("----------------------------------------------------")
}
Loading
Loading