Problem
AddLocalTxns and processRemoteTxns open their core-state transaction and cache view before acquiring p.lock. An admission request can therefore:
- obtain a view of state version N;
- wait for
p.lock;
- be overtaken by
OnNewBlock, which applies state version N+1 and completes sender re-evaluation;
- acquire the lock and mutate the pool using the old view.
This can bypass validation that depends on current sender state. For example, if the new block installs EIP-7702 delegation, the old view still reports empty code and several contiguous transactions can be admitted after the delegated-sender cleanup has already run. They enter pending, so the existing fallback that re-evaluates untouched queued senders on later blocks does not revisit them.
Pool reload has the same ordering risk: start opens coreTx before fromDB acquires the pool lock.
Reproduction
A deterministic test can use a blocking cache or DB wrapper:
- initialize an EOA at nonce 0 with empty code;
- start local admission, remote admission, or pool reload and pause after it opens the old state view;
- update the account to nonce 1 with delegation code and let
OnNewBlock finish;
- release the paused operation with transactions at nonces 0, 1, and 2.
Expected: only nonce 1 remains.
Actual:
- local admission returns
Success for all three transactions;
- remote admission retains all three transactions;
- reload restores all three transactions;
- the transactions are pending rather than queued.
The stale pending chain also survives a following block that does not change this sender.
Suggested direction
Establish a consistent ordering between the state view and p.lock. If OnNewBlock advances while admission or reload is waiting for the lock, reopen or retry the state transaction and cache view before mutating the pool.
Cover local admission, remote admission, and pool reload with deterministic regression tests.
Context
Found while reviewing #23294. That PR handles steady-state delegated senders and normal state-transition ordering; this race is a broader synchronization concern and should be handled separately.
#20998 describes a related re-evaluation refactor, but it does not prevent an operation from mutating the pool through an older state view after OnNewBlock completes.
Problem
AddLocalTxnsandprocessRemoteTxnsopen their core-state transaction and cache view before acquiringp.lock. An admission request can therefore:p.lock;OnNewBlock, which applies state version N+1 and completes sender re-evaluation;This can bypass validation that depends on current sender state. For example, if the new block installs EIP-7702 delegation, the old view still reports empty code and several contiguous transactions can be admitted after the delegated-sender cleanup has already run. They enter
pending, so the existing fallback that re-evaluates untouched queued senders on later blocks does not revisit them.Pool reload has the same ordering risk:
startopenscoreTxbeforefromDBacquires the pool lock.Reproduction
A deterministic test can use a blocking cache or DB wrapper:
OnNewBlockfinish;Expected: only nonce 1 remains.
Actual:
Successfor all three transactions;The stale pending chain also survives a following block that does not change this sender.
Suggested direction
Establish a consistent ordering between the state view and
p.lock. IfOnNewBlockadvances while admission or reload is waiting for the lock, reopen or retry the state transaction and cache view before mutating the pool.Cover local admission, remote admission, and pool reload with deterministic regression tests.
Context
Found while reviewing #23294. That PR handles steady-state delegated senders and normal state-transition ordering; this race is a broader synchronization concern and should be handled separately.
#20998 describes a related re-evaluation refactor, but it does not prevent an operation from mutating the pool through an older state view after
OnNewBlockcompletes.