diff --git a/cmd/geth/main.go b/cmd/geth/main.go index d4280144e4..ac0c8df1fe 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -131,6 +131,7 @@ var ( utils.MinerRecommitIntervalFlag, utils.MinerNoVerifyFlag, utils.MinerStoreSkippedTxTracesFlag, + utils.MinerMaxAccountsNumFlag, utils.NATFlag, utils.NoDiscoverFlag, utils.DiscoveryV5Flag, diff --git a/cmd/geth/usage.go b/cmd/geth/usage.go index c3748aca88..8c2e17218e 100644 --- a/cmd/geth/usage.go +++ b/cmd/geth/usage.go @@ -194,6 +194,7 @@ var AppHelpFlagGroups = []flags.FlagGroup{ utils.MinerRecommitIntervalFlag, utils.MinerNoVerifyFlag, utils.MinerStoreSkippedTxTracesFlag, + utils.MinerMaxAccountsNumFlag, }, }, { diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index 24f64f1c3d..4d2224d652 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -500,6 +500,11 @@ var ( Name: "miner.storeskippedtxtraces", Usage: "Store the wrapped traces when storing a skipped tx", } + MinerMaxAccountsNumFlag = cli.IntFlag{ + Name: "miner.maxaccountsnum", + Usage: "Maximum number of accounts that miner will fetch the pending transactions of when building a new block", + Value: math.MaxInt, + } // Account settings UnlockedAccountFlag = cli.StringFlag{ Name: "unlock", @@ -1519,6 +1524,9 @@ func setMiner(ctx *cli.Context, cfg *miner.Config) { if ctx.GlobalIsSet(MinerStoreSkippedTxTracesFlag.Name) { cfg.StoreSkippedTxTraces = ctx.GlobalBool(MinerStoreSkippedTxTracesFlag.Name) } + if ctx.GlobalIsSet(MinerMaxAccountsNumFlag.Name) { + cfg.MaxAccountsNum = ctx.GlobalInt(MinerMaxAccountsNumFlag.Name) + } if ctx.GlobalIsSet(LegacyMinerGasTargetFlag.Name) { log.Warn("The generic --miner.gastarget flag is deprecated and will be removed in the future!") } diff --git a/core/tx_pool.go b/core/tx_pool.go index 273c31e50c..a8454204ab 100644 --- a/core/tx_pool.go +++ b/core/tx_pool.go @@ -537,6 +537,16 @@ func (pool *TxPool) ContentFrom(addr common.Address) (types.Transactions, types. // 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 { + return pool.pendingWithMax(enforceTips, math.MaxInt) +} + +// PendingWithMax works similar to Pending but allows setting an upper limit on how many +// accounts to return +func (pool *TxPool) PendingWithMax(enforceTips bool, maxAccountsNum int) map[common.Address]types.Transactions { + return pool.pendingWithMax(enforceTips, maxAccountsNum) +} + +func (pool *TxPool) pendingWithMax(enforceTips bool, maxAccountsNum int) map[common.Address]types.Transactions { pool.mu.Lock() defer pool.mu.Unlock() @@ -555,6 +565,9 @@ func (pool *TxPool) Pending(enforceTips bool) map[common.Address]types.Transacti } if len(txs) > 0 { pending[addr] = txs + if len(pending) >= maxAccountsNum { + break + } } } return pending diff --git a/core/tx_pool_test.go b/core/tx_pool_test.go index 5ccc304cc1..1662a57f65 100644 --- a/core/tx_pool_test.go +++ b/core/tx_pool_test.go @@ -28,6 +28,8 @@ import ( "testing" "time" + "github.com/stretchr/testify/assert" + "github.com/scroll-tech/go-ethereum/common" "github.com/scroll-tech/go-ethereum/core/rawdb" "github.com/scroll-tech/go-ethereum/core/state" @@ -2575,3 +2577,27 @@ func BenchmarkPoolMultiAccountBatchInsert(b *testing.B) { pool.AddRemotesSync([]*types.Transaction{tx}) } } + +func TestPoolPending(t *testing.T) { + // Generate a batch of transactions to enqueue into the pool + pool, _ := setupTxPool() + defer pool.Stop() + numTxns := 100 + batches := make(types.Transactions, numTxns) + for i := 0; i < numTxns; i++ { + key, _ := crypto.GenerateKey() + account := crypto.PubkeyToAddress(key.PublicKey) + pool.currentState.AddBalance(account, big.NewInt(1000000)) + tx := transaction(uint64(0), 100000, key) + batches[i] = tx + } + // Benchmark importing the transactions into the queue + for _, tx := range batches { + pool.AddRemotesSync([]*types.Transaction{tx}) + } + + assert.Len(t, pool.Pending(false), numTxns) + + maxAccounts := 10 + assert.Len(t, pool.PendingWithMax(false, maxAccounts), maxAccounts) +} diff --git a/miner/miner.go b/miner/miner.go index 1f3f9d0d77..95992b9000 100644 --- a/miner/miner.go +++ b/miner/miner.go @@ -58,6 +58,7 @@ type Config struct { Noverify bool // Disable remote mining solution verification(only useful in ethash). StoreSkippedTxTraces bool // Whether store the wrapped traces when storing a skipped tx + MaxAccountsNum int // Maximum number of accounts that miner will fetch the pending transactions of when building a new block } // Miner creates blocks and searches for proof-of-work values. diff --git a/miner/miner_test.go b/miner/miner_test.go index a83fc2c8b1..56f6c1f2da 100644 --- a/miner/miner_test.go +++ b/miner/miner_test.go @@ -18,6 +18,7 @@ package miner import ( + "math" "testing" "time" @@ -244,7 +245,8 @@ func waitForMiningState(t *testing.T, m *Miner, mining bool) { func createMiner(t *testing.T) (*Miner, *event.TypeMux) { // Create Ethash config config := Config{ - Etherbase: common.HexToAddress("123456789"), + Etherbase: common.HexToAddress("123456789"), + MaxAccountsNum: math.MaxInt, } // Create chainConfig memdb := memorydb.New() diff --git a/miner/worker.go b/miner/worker.go index ef9166af26..330fb2cbbb 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -1446,7 +1446,7 @@ func (w *worker) commitNewWork(interrupt *int32, noempty bool, timestamp int64) tidyPendingStart := time.Now() // Fill the block with all available pending transactions. - pending := w.eth.TxPool().Pending(false) + pending := w.eth.TxPool().PendingWithMax(false, w.config.MaxAccountsNum) // Short circuit if there is no available pending transactions. // But if we disable empty precommit already, ignore it. Since // empty block is necessary to keep the liveness of the network. diff --git a/miner/worker_test.go b/miner/worker_test.go index 7e3cb337b9..6e099905f3 100644 --- a/miner/worker_test.go +++ b/miner/worker_test.go @@ -17,6 +17,7 @@ package miner import ( + "math" "math/big" "math/rand" "sync/atomic" @@ -70,8 +71,9 @@ var ( newTxs []*types.Transaction testConfig = &Config{ - Recommit: time.Second, - GasCeil: params.GenesisGasLimit, + Recommit: time.Second, + GasCeil: params.GenesisGasLimit, + MaxAccountsNum: math.MaxInt, } ) diff --git a/params/version.go b/params/version.go index bd7afb495a..235ecb9214 100644 --- a/params/version.go +++ b/params/version.go @@ -24,7 +24,7 @@ import ( const ( VersionMajor = 5 // Major version component of the current release VersionMinor = 3 // Minor version component of the current release - VersionPatch = 14 // Patch version component of the current release + VersionPatch = 15 // Patch version component of the current release VersionMeta = "mainnet" // Version metadata to append to the version string )