@@ -377,7 +377,7 @@ func (pool *LegacyPool) loop() {
377377 if time .Since (pool .beats [addr ]) > pool .config .Lifetime {
378378 list := pool .queue [addr ].Flatten ()
379379 for _ , tx := range list {
380- pool .RemoveTx (tx .Hash (), true , true )
380+ pool .removeTx (tx .Hash (), true , true )
381381 }
382382 queuedEvictionMeter .Mark (int64 (len (list )))
383383 }
@@ -430,7 +430,7 @@ func (pool *LegacyPool) SetGasTip(tip *big.Int) {
430430 // pool.priced is sorted by GasFeeCap, so we have to iterate through pool.all instead
431431 drop := pool .all .TxsBelowTip (tip )
432432 for _ , tx := range drop {
433- pool .RemoveTx (tx .Hash (), false , true )
433+ pool .removeTx (tx .Hash (), false , true )
434434 }
435435 pool .priced .Removed (len (drop ))
436436 }
@@ -770,7 +770,7 @@ func (pool *LegacyPool) add(tx *types.Transaction) (replaced bool, err error) {
770770 underpricedTxMeter .Mark (1 )
771771
772772 sender , _ := types .Sender (pool .signer , tx )
773- dropped := pool .RemoveTx (tx .Hash (), false , sender != from ) // Don't unreserve the sender of the tx being added if last from the acc
773+ dropped := pool .removeTx (tx .Hash (), false , sender != from ) // Don't unreserve the sender of the tx being added if last from the acc
774774
775775 pool .changesSinceReorg += dropped
776776 }
@@ -1087,6 +1087,23 @@ func (pool *LegacyPool) Has(hash common.Hash) bool {
10871087//
10881088// Returns the number of transactions removed from the pending queue.
10891089func (pool * LegacyPool ) RemoveTx (hash common.Hash , outofbound bool , unreserve bool ) int {
1090+ pool .mu .Lock ()
1091+ defer pool .mu .Unlock ()
1092+ return pool .removeTx (hash , outofbound , unreserve )
1093+ }
1094+
1095+ // removeTx removes a single transaction from the queue, moving all subsequent
1096+ // transactions back to the future queue.
1097+ //
1098+ // If unreserve is false, the account will not be relinquished to the main txpool
1099+ // even if there are no more references to it. This is used to handle a race when
1100+ // a tx being added, and it evicts a previously scheduled tx from the same account,
1101+ // which could lead to a premature release of the lock.
1102+ //
1103+ // Returns the number of transactions removed from the pending queue.
1104+ //
1105+ // The transaction pool lock must be held.
1106+ func (pool * LegacyPool ) removeTx (hash common.Hash , outofbound bool , unreserve bool ) int {
10901107 // Fetch the transaction we wish to delete
10911108 tx := pool .all .Get (hash )
10921109 if tx == nil {
@@ -1533,7 +1550,7 @@ func (pool *LegacyPool) truncateQueue() {
15331550 // Drop all transactions if they are less than the overflow
15341551 if size := uint64 (list .Len ()); size <= drop {
15351552 for _ , tx := range list .Flatten () {
1536- pool .RemoveTx (tx .Hash (), true , true )
1553+ pool .removeTx (tx .Hash (), true , true )
15371554 }
15381555 drop -= size
15391556 queuedRateLimitMeter .Mark (int64 (size ))
@@ -1542,7 +1559,7 @@ func (pool *LegacyPool) truncateQueue() {
15421559 // Otherwise drop only last few transactions
15431560 txs := list .Flatten ()
15441561 for i := len (txs ) - 1 ; i >= 0 && drop > 0 ; i -- {
1545- pool .RemoveTx (txs [i ].Hash (), true , true )
1562+ pool .removeTx (txs [i ].Hash (), true , true )
15461563 drop --
15471564 queuedRateLimitMeter .Mark (1 )
15481565 }
0 commit comments