core/txpool/legacypool: fix double release

Release was called twice when promoteExecutables was called
with already released addresses.

Signed-off-by: Csaba Kiraly <csaba.kiraly@gmail.com>
This commit is contained in:
Csaba Kiraly 2025-10-13 15:08:30 +02:00
parent 1ed0e5e95d
commit e479de1e72
No known key found for this signature in database
GPG key ID: 0FE274EE8C95166E
2 changed files with 9 additions and 6 deletions

View file

@ -1400,7 +1400,7 @@ func (pool *LegacyPool) reset(oldHead, newHead *types.Header) {
// invalidated transactions (low nonce, low balance) are deleted. // invalidated transactions (low nonce, low balance) are deleted.
func (pool *LegacyPool) promoteExecutables(accounts []common.Address) []*types.Transaction { func (pool *LegacyPool) promoteExecutables(accounts []common.Address) []*types.Transaction {
gasLimit := pool.currentHead.Load().GasLimit gasLimit := pool.currentHead.Load().GasLimit
promotable, dropped := pool.queue.promoteExecutables(accounts, gasLimit, pool.currentState, pool.pendingNonces) promotable, dropped, removedAddresses := pool.queue.promoteExecutables(accounts, gasLimit, pool.currentState, pool.pendingNonces)
promoted := make([]*types.Transaction, 0, len(promotable)) promoted := make([]*types.Transaction, 0, len(promotable))
// promote all promoteable transactions // promote all promoteable transactions
@ -1417,7 +1417,7 @@ func (pool *LegacyPool) promoteExecutables(accounts []common.Address) []*types.T
} }
// release all accounts that have no more transactions in the pool // release all accounts that have no more transactions in the pool
for _, addr := range accounts { for _, addr := range removedAddresses {
_, hasPending := pool.pending[addr] _, hasPending := pool.pending[addr]
_, hasQueued := pool.queue.get(addr) _, hasQueued := pool.queue.get(addr)
if !hasPending && !hasQueued { if !hasPending && !hasQueued {

View file

@ -149,12 +149,14 @@ func (q *queue) add(hash common.Hash, tx *types.Transaction) (*common.Hash, erro
// for promotion any that are now executable. It also drops any transactions that are // for promotion any that are now executable. It also drops any transactions that are
// deemed too old (nonce too low) or too costly (insufficient funds or over gas limit). // deemed too old (nonce too low) or too costly (insufficient funds or over gas limit).
// //
// Returns two lists: all transactions that were removed from the queue and selected // Returns three lists: all transactions that were removed from the queue and selected
// for promotion; all other transactions that were removed from the queue and dropped. // for promotion; all other transactions that were removed from the queue and dropped;
func (q *queue) promoteExecutables(accounts []common.Address, gasLimit uint64, currentState *state.StateDB, nonces *noncer) ([]*types.Transaction, []common.Hash) { // the list of addresses removed.
func (q *queue) promoteExecutables(accounts []common.Address, gasLimit uint64, currentState *state.StateDB, nonces *noncer) ([]*types.Transaction, []common.Hash, []common.Address) {
// Track the promotable transactions to broadcast them at once // Track the promotable transactions to broadcast them at once
var promotable []*types.Transaction var promotable []*types.Transaction
var dropped []common.Hash var dropped []common.Hash
var removedAddresses []common.Address
// Iterate over all accounts and promote any executable transactions // Iterate over all accounts and promote any executable transactions
for _, addr := range accounts { for _, addr := range accounts {
@ -196,9 +198,10 @@ func (q *queue) promoteExecutables(accounts []common.Address, gasLimit uint64, c
if list.Empty() { if list.Empty() {
delete(q.queued, addr) delete(q.queued, addr)
delete(q.beats, addr) delete(q.beats, addr)
removedAddresses = append(removedAddresses, addr)
} }
} }
return promotable, dropped return promotable, dropped, removedAddresses
} }
// truncate drops the oldest transactions from the queue until the total // truncate drops the oldest transactions from the queue until the total