@ -1272,9 +1272,10 @@ func (pool *LegacyPool) runReorg(done chan struct{}, reset *txpoolResetRequest,
promoteAddrs = dirtyAccounts . flatten ( )
}
pool . mu . Lock ( )
var demoteAddrs map [ common . Address ] bool
if reset != nil {
// Reset from the old head to the new, rescheduling any reorged transactions
pool . reset ( reset . oldHead , reset . newHead )
demoteAddrs = pool . reset ( reset . oldHead , reset . newHead )
// Nonces were reset, discard any events that became stale
for addr := range events {
@ -1296,7 +1297,7 @@ func (pool *LegacyPool) runReorg(done chan struct{}, reset *txpoolResetRequest,
// remove any transaction that has been included in the block or was invalidated
// because of another transaction (e.g. higher gas price).
if reset != nil {
pool . demoteUnexecutables ( )
pool . demoteUnexecutables ( demoteAddrs )
if reset . newHead != nil {
if pool . chainconfig . IsLondon ( new ( big . Int ) . Add ( reset . newHead . Number , big . NewInt ( 1 ) ) ) {
pendingBaseFee := eip1559 . CalcBaseFee ( pool . chainconfig , reset . newHead )
@ -1340,10 +1341,18 @@ func (pool *LegacyPool) runReorg(done chan struct{}, reset *txpoolResetRequest,
// reset retrieves the current state of the blockchain and ensures the content
// of the transaction pool is valid with regard to the chain state.
func ( pool * LegacyPool ) reset ( oldHead , newHead * types . Header ) {
func ( pool * LegacyPool ) reset ( oldHead , newHead * types . Header ) map [ common . Address ] bool {
// If we're reorging an old state, reinject all dropped transactions
var reinject types . Transactions
demoteAddrs := make ( map [ common . Address ] bool )
collectDemoteAddrs := func ( txs types . Transactions ) {
if demoteAddrs != nil {
for _ , tx := range txs {
addr , _ := types . Sender ( pool . signer , tx )
demoteAddrs [ addr ] = true
}
}
}
if oldHead != nil && oldHead . Hash ( ) != newHead . ParentHash {
// If the reorg is too deep, avoid doing it (will happen during fast sync)
oldNum := oldHead . Number . Uint64 ( )
@ -1351,6 +1360,7 @@ func (pool *LegacyPool) reset(oldHead, newHead *types.Header) {
if depth := uint64 ( math . Abs ( float64 ( oldNum ) - float64 ( newNum ) ) ) ; depth > 64 {
log . Debug ( "Skipping deep transaction reorg" , "depth" , depth )
demoteAddrs = nil // do a deep txPool reorg
} else {
// Reorg seems shallow enough to pull in all transactions into memory
var (
@ -1366,7 +1376,7 @@ func (pool *LegacyPool) reset(oldHead, newHead *types.Header) {
// If we reorged to a same or higher number, then it's not a case of setHead
log . Warn ( "Transaction pool reset with missing old head" ,
"old" , oldHead . Hash ( ) , "oldnum" , oldNum , "new" , newHead . Hash ( ) , "newnum" , newNum )
return
return nil
}
// If the reorg ended up on a lower number, it's indicative of setHead being the cause
log . Debug ( "Skipping transaction reset caused by setHead" ,
@ -1379,33 +1389,33 @@ func (pool *LegacyPool) reset(oldHead, newHead *types.Header) {
// reorg caused by sync-reversion or explicit sethead back to an
// earlier block.
log . Warn ( "Transaction pool reset with missing new head" , "number" , newHead . Number , "hash" , newHead . Hash ( ) )
return
return nil
}
var discarded , included types . Transactions
for rem . NumberU64 ( ) > add . NumberU64 ( ) {
discarded = append ( discarded , rem . Transactions ( ) ... )
if rem = pool . chain . GetBlock ( rem . ParentHash ( ) , rem . NumberU64 ( ) - 1 ) ; rem == nil {
log . Error ( "Unrooted old chain seen by tx pool" , "block" , oldHead . Number , "hash" , oldHead . Hash ( ) )
return
return nil
}
}
for add . NumberU64 ( ) > rem . NumberU64 ( ) {
included = append ( included , add . Transactions ( ) ... )
if add = pool . chain . GetBlock ( add . ParentHash ( ) , add . NumberU64 ( ) - 1 ) ; add == nil {
log . Error ( "Unrooted new chain seen by tx pool" , "block" , newHead . Number , "hash" , newHead . Hash ( ) )
return
return nil
}
}
for rem . Hash ( ) != add . Hash ( ) {
discarded = append ( discarded , rem . Transactions ( ) ... )
if rem = pool . chain . GetBlock ( rem . ParentHash ( ) , rem . NumberU64 ( ) - 1 ) ; rem == nil {
log . Error ( "Unrooted old chain seen by tx pool" , "block" , oldHead . Number , "hash" , oldHead . Hash ( ) )
return
return nil
}
included = append ( included , add . Transactions ( ) ... )
if add = pool . chain . GetBlock ( add . ParentHash ( ) , add . NumberU64 ( ) - 1 ) ; add == nil {
log . Error ( "Unrooted new chain seen by tx pool" , "block" , newHead . Number , "hash" , newHead . Hash ( ) )
return
return nil
}
}
lost := make ( [ ] * types . Transaction , 0 , len ( discarded ) )
@ -1415,26 +1425,31 @@ func (pool *LegacyPool) reset(oldHead, newHead *types.Header) {
}
}
reinject = lost
collectDemoteAddrs ( discarded )
collectDemoteAddrs ( included )
}
}
}
// Initialize the internal state to the current head
if newHead == nil {
newHead = pool . chain . CurrentBlock ( ) // Special case during testing
demoteAddrs = nil
}
statedb , err := pool . chain . StateAt ( newHead . Root )
if err != nil {
log . Error ( "Failed to reset txpool state" , "err" , err )
return
return nil
}
pool . currentHead . Store ( newHead )
pool . currentState = statedb
pool . pendingNonces = newNoncer ( statedb )
collectDemoteAddrs ( pool . chain . GetBlock ( newHead . Hash ( ) , newHead . Number . Uint64 ( ) ) . Transactions ( ) )
// Inject any transactions discarded due to reorgs
log . Debug ( "Reinjecting stale transactions" , "count" , len ( reinject ) )
core . SenderCacher . Recover ( pool . signer , reinject )
pool . addTxsLocked ( reinject , false )
return demoteAddrs
}
// promoteExecutables moves transactions that have become processable from the
@ -1646,10 +1661,14 @@ func (pool *LegacyPool) truncateQueue() {
// Note: transactions are not marked as removed in the priced list because re-heaping
// is always explicitly triggered by SetBaseFee and it would be unnecessary and wasteful
// to trigger a re-heap is this function
func ( pool * LegacyPool ) demoteUnexecutables ( ) {
func ( pool * LegacyPool ) demoteUnexecutables ( demoteAddrs map [ common . Address ] bool ) {
// Iterate over all accounts and demote any non-executable transactions
gasLimit := pool . currentHead . Load ( ) . GasLimit
for addr , list := range pool . pending {
if demoteAddrs != nil && ! demoteAddrs [ addr ] {
continue
}
nonce := pool . currentState . GetNonce ( addr )
// Drop all transactions that are deemed too old (low nonce)