Skip to content

Commit f0cedd6

Browse files
authored
fix(mempool): legacy subpool panic on skipped header during reset (#668)
* add test to demonstrate subpool reset being called with invalid block hashes * make test fail on hash mismatch * update txpool cosmos reorg test to use real legacypool as the subpool * update comment * fix chan pointer madness * remove logic that would only panic for cosmos chains from legacypool when reset was called with a skipped header * remove unnecessary long sleep from test for success case * fix race in test * changelog * reference pr link in log
1 parent 61eedfc commit f0cedd6

File tree

7 files changed

+1481
-72
lines changed

7 files changed

+1481
-72
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
- [\#658](https://github.com/cosmos/evm/pull/658) Fix race condition between legacypool's RemoveTx and runReorg.
2222
- [\#687](https://github.com/cosmos/evm/pull/687) Avoid blocking node shutdown when evm indexer is enabled, log startup failures instead of using errgroup.
2323
- [\#689](https://github.com/cosmos/evm/pull/689) Align debug addr for hex address.
24+
- [\#668](https://github.com/cosmos/evm/pull/668) Fix panic in legacy mempool when Reset() was called with a skipped header between old and new block.
2425

2526
### IMPROVEMENTS
2627

mempool/txpool/legacypool/mocks/BlockChain.go

Lines changed: 124 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

mempool/txpool/legacypool/reset_production.go

Lines changed: 9 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@
33
package legacypool
44

55
import (
6-
"math"
7-
86
"github.com/ethereum/go-ethereum/core/types"
97
"github.com/ethereum/go-ethereum/log"
108
)
@@ -16,76 +14,15 @@ func (pool *LegacyPool) reset(oldHead, newHead *types.Header) {
1614
var reinject types.Transactions
1715

1816
if oldHead != nil && oldHead.Hash() != newHead.ParentHash {
19-
// If the reorg is too deep, avoid doing it (will happen during fast sync)
20-
oldNum := oldHead.Number.Uint64()
21-
newNum := newHead.Number.Uint64()
22-
23-
if depth := uint64(math.Abs(float64(oldNum) - float64(newNum))); depth > 64 {
24-
log.Debug("Skipping deep transaction reorg", "depth", depth)
25-
} else {
26-
// Reorg seems shallow enough to pull in all transactions into memory
27-
var (
28-
rem = pool.chain.GetBlock(oldHead.Hash(), oldHead.Number.Uint64())
29-
add = pool.chain.GetBlock(newHead.Hash(), newHead.Number.Uint64())
30-
)
31-
if rem == nil {
32-
// This can happen if a setHead is performed, where we simply discard the old
33-
// head from the chain.
34-
if newNum >= oldNum {
35-
// If we reorged to a same or higher number, then it's not a case of setHead
36-
log.Warn("Transaction pool reset with missing old head",
37-
"old", oldHead.Hash(), "oldnum", oldNum, "new", newHead.Hash(), "newnum", newNum)
38-
return
39-
}
40-
// If the reorg ended up on a lower number, it's indicative of setHead being the cause
41-
log.Debug("Skipping transaction reset caused by setHead",
42-
"old", oldHead.Hash(), "oldnum", oldNum, "new", newHead.Hash(), "newnum", newNum)
43-
// We still need to update the current state s.th. the lost transactions can be readded by the user
44-
} else {
45-
if add == nil {
46-
// if the new head is nil, it means that something happened between
47-
// the firing of newhead-event and _now_: most likely a
48-
// reorg caused by sync-reversion or explicit sethead back to an
49-
// earlier block.
50-
log.Warn("Transaction pool reset with missing new head", "number", newHead.Number, "hash", newHead.Hash())
51-
return
52-
}
53-
var discarded, included types.Transactions
54-
for rem.NumberU64() > add.NumberU64() {
55-
discarded = append(discarded, rem.Transactions()...)
56-
if rem = pool.chain.GetBlock(rem.ParentHash(), rem.NumberU64()-1); rem == nil {
57-
log.Error("Unrooted old chain seen by tx pool", "block", oldHead.Number, "hash", oldHead.Hash())
58-
return
59-
}
60-
}
61-
for add.NumberU64() > rem.NumberU64() {
62-
included = append(included, add.Transactions()...)
63-
if add = pool.chain.GetBlock(add.ParentHash(), add.NumberU64()-1); add == nil {
64-
log.Error("Unrooted new chain seen by tx pool", "block", newHead.Number, "hash", newHead.Hash())
65-
return
66-
}
67-
}
68-
for rem.Hash() != add.Hash() {
69-
discarded = append(discarded, rem.Transactions()...)
70-
if rem = pool.chain.GetBlock(rem.ParentHash(), rem.NumberU64()-1); rem == nil {
71-
log.Error("Unrooted old chain seen by tx pool", "block", oldHead.Number, "hash", oldHead.Hash())
72-
return
73-
}
74-
included = append(included, add.Transactions()...)
75-
if add = pool.chain.GetBlock(add.ParentHash(), add.NumberU64()-1); add == nil {
76-
log.Error("Unrooted new chain seen by tx pool", "block", newHead.Number, "hash", newHead.Hash())
77-
return
78-
}
79-
}
80-
lost := make([]*types.Transaction, 0, len(discarded))
81-
for _, tx := range types.TxDifference(discarded, included) {
82-
if pool.Filter(tx) {
83-
lost = append(lost, tx)
84-
}
85-
}
86-
reinject = lost
87-
}
88-
}
17+
// this is a strange reorg check from geth, it is possible for cosmos
18+
// chains to call this function with newHead=oldHead+2, so
19+
// newHead.ParentHash != oldHead.Hash. This would incorrectly be seen
20+
// as a reorg on a cosmos chain and would therefore panic. Since this
21+
// logic would only panic for cosmos chains in a valid state, we have
22+
// removed it and replaced with a debug log.
23+
//
24+
// see https://github.com/cosmos/evm/pull/668 for more context.
25+
log.Debug("leacypool saw skipped block (reorg) on cosmos chain, doing nothing...", "oldHead", oldHead.Hash(), "newHead", newHead.Hash(), "newParent", newHead.ParentHash)
8926
}
9027
pool.resetInternalState(newHead, reinject)
9128
}

mempool/txpool/mocks/BlockChain.go

Lines changed: 127 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)