core: more efficient nonce-update in txpool (#22231)

* Adjust pending nonce update operation

Benchmark the speed of transaction insertion under multiple accounts

core: fix rebase issues + docstring

core: make benchmark test use sync:ed method

* core: address review comments

* core: add memreport to benchmark

Co-authored-by: WeiLoy <wei_loy@163.com>
This commit is contained in:
Martin Holst Swende 2021-11-02 18:32:23 +01:00 committed by GitHub
parent f49e90e32c
commit 03bc8b7858
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 36 additions and 5 deletions

@ -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
}

@ -1182,16 +1182,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()

@ -2540,3 +2540,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})
}
}