From 51a0144aff76f7c6e531b55552e6cd83b83688d7 Mon Sep 17 00:00:00 2001 From: Lucca Martins Date: Wed, 10 Jun 2026 13:25:51 -0300 Subject: [PATCH] txpool/legacypool: fix fillPool TOCTOU + remove debug prints fillPool read pool.Stats() (pool.mu.RLock) and pool.all.Slots() (t.lock.RLock) as two separate critical sections, creating a narrow window where a concurrent pool mutation could make pending != slots even with a healthy pool. Hold pool.mu.RLock across both reads so the snapshot is consistent; all paths that modify pool.all require pool.mu.Lock, so this is sufficient. Also removes three leftover fmt.Println debug statements from list_test.go that polluted CI output. --- core/txpool/legacypool/legacypool2_test.go | 9 ++++++++- core/txpool/legacypool/list_test.go | 7 +++---- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/core/txpool/legacypool/legacypool2_test.go b/core/txpool/legacypool/legacypool2_test.go index 3d86345627..419203f521 100644 --- a/core/txpool/legacypool/legacypool2_test.go +++ b/core/txpool/legacypool/legacypool2_test.go @@ -66,8 +66,15 @@ func fillPool(t testing.TB, pool *LegacyPool) { // Import the batch and verify that limits have been enforced pool.addRemotesSync(executableTxs) pool.addRemotesSync(nonExecutableTxs) - pending, queued := pool.Stats() + + // Read pending, queued, and all.Slots() under pool.mu.RLock so the three + // values are consistent: no concurrent mutation can interleave between the + // two calls because all paths that modify pool.all require pool.mu.Lock. + pool.mu.RLock() + pending, queued := pool.stats() slots := pool.all.Slots() + pool.mu.RUnlock() + // sanity-check that the test prerequisites are ok (pending full) if have, want := pending, slots; have != want { t.Fatalf("have %d, want %d", have, want) diff --git a/core/txpool/legacypool/list_test.go b/core/txpool/legacypool/list_test.go index 938ebb8189..ce325faaeb 100644 --- a/core/txpool/legacypool/list_test.go +++ b/core/txpool/legacypool/list_test.go @@ -17,7 +17,6 @@ package legacypool import ( - "fmt" "math/big" "math/rand" "testing" @@ -145,14 +144,14 @@ func TestFilterTxConditionalKnownAccounts(t *testing.T) { state.AddBalance(common.Address{19: 1}, uint256.NewInt(1000), tracing.BalanceChangeTransfer) trie, _ := state.StorageTrie(common.Address{19: 1}) - fmt.Println("before", trie) + _ = trie state.SetState(common.Address{19: 1}, common.Hash{}, common.Hash{30: 1}) state.Finalise(true) trie, _ = state.StorageTrie(common.Address{19: 1}) - fmt.Println("after", trie.Hash()) + _ = trie tx2.PutOptions(&options) list.Add(tx2, DefaultConfig.PriceBump) @@ -169,7 +168,7 @@ func TestFilterTxConditionalKnownAccounts(t *testing.T) { state.Finalise(true) trie, _ = state.StorageTrie(common.Address{19: 1}) - fmt.Println("after2", trie.Hash()) + _ = trie // tx2 should be the single transaction filtered out drops = list.FilterTxConditional(state, header)