diff --git a/core/tx_noncer.go b/core/tx_noncer.go index cbadc39354a37..60779dd3121ef 100644 --- a/core/tx_noncer.go +++ b/core/tx_noncer.go @@ -77,3 +77,11 @@ func (txn *txNoncer) setIfLower(addr common.Address, nonce uint64) { } txn.nonces[addr] = nonce } + +// setAll sets the nonces for all accounts to the given map. +func (txn *txNoncer) setAll(all map[common.Address]uint64) { + txn.lock.Lock() + defer txn.lock.Unlock() + + txn.nonces = all +} diff --git a/core/tx_pool.go b/core/tx_pool.go index d97bbcfe9004b..cdd2afdbdea6d 100644 --- a/core/tx_pool.go +++ b/core/tx_pool.go @@ -1332,16 +1332,18 @@ func (pool *TxPool) runReorg(done chan struct{}, reset *txpoolResetRequest, dirt pendingBaseFee := misc.CalcBaseFee(pool.chainconfig, reset.newHead) pool.priced.SetBaseFee(pendingBaseFee) } + // Update all accounts to the latest known pending nonce + nonces := make(map[common.Address]uint64, len(pool.pending)) + for addr, list := range pool.pending { + highestPending := list.LastElement() + nonces[addr] = highestPending.Nonce() + 1 + } + pool.pendingNonces.setAll(nonces) } // Ensure pool.queue and pool.pending sizes stay within the configured limits. pool.truncatePending() pool.truncateQueue() - // Update all accounts to the latest known pending nonce - for addr, list := range pool.pending { - highestPending := list.LastElement() - pool.pendingNonces.set(addr, highestPending.Nonce()+1) - } dropBetweenReorgHistogram.Update(int64(pool.changesSinceReorg)) pool.changesSinceReorg = 0 // Reset change counter pool.mu.Unlock() diff --git a/core/tx_pool_test.go b/core/tx_pool_test.go index 2f01735edf01e..b3942e6d2f51f 100644 --- a/core/tx_pool_test.go +++ b/core/tx_pool_test.go @@ -2576,3 +2576,24 @@ func BenchmarkInsertRemoteWithAllLocals(b *testing.B) { pool.Stop() } } + +// Benchmarks the speed of batch transaction insertion in case of multiple accounts. +func BenchmarkPoolMultiAccountBatchInsert(b *testing.B) { + // Generate a batch of transactions to enqueue into the pool + pool, _ := setupTxPool() + defer pool.Stop() + b.ReportAllocs() + batches := make(types.Transactions, b.N) + for i := 0; i < b.N; 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 + b.ResetTimer() + for _, tx := range batches { + pool.AddRemotesSync([]*types.Transaction{tx}) + } +}