eth/txtracker: fetch head block by hash to avoid reorg-stale EMA

handleChainHead fetched the block by number only. If the tracker
goroutine lagged and that height was reorged before processing,
the EMA was computed from the wrong canonical block.

Use GetBlock(hash, number) with the header hash from the event to
fetch the exact block the event refers to, not whatever is currently
canonical at that height.
This commit is contained in:
Csaba Kiraly 2026-04-10 10:34:33 +02:00
parent a1a5d73324
commit 3785d43db4
2 changed files with 9 additions and 2 deletions

View file

@ -37,6 +37,7 @@ type PeerStats struct {
type Chain interface {
SubscribeChainHeadEvent(ch chan<- core.ChainHeadEvent) event.Subscription
GetBlockByNumber(number uint64) *types.Block
GetBlock(hash common.Hash, number uint64) *types.Block
CurrentFinalBlock() *types.Header
}
@ -146,8 +147,9 @@ func (t *Tracker) loop() {
}
func (t *Tracker) handleChainHead(ev core.ChainHeadEvent) {
// Update recent-inclusion EMA from the new head block.
block := t.chain.GetBlockByNumber(ev.Header.Number.Uint64())
// Fetch the head block by hash (not just number) to avoid using a
// reorged block if the tracker goroutine lags behind the chain.
block := t.chain.GetBlock(ev.Header.Hash(), ev.Header.Number.Uint64())
if block == nil {
return
}

View file

@ -35,6 +35,11 @@ func (c *mockChain) GetBlockByNumber(number uint64) *types.Block {
return c.blocks[number]
}
func (c *mockChain) GetBlock(hash common.Hash, number uint64) *types.Block {
// In tests we only key by number; ignore hash.
return c.GetBlockByNumber(number)
}
func (c *mockChain) CurrentFinalBlock() *types.Header {
c.mu.Lock()
defer c.mu.Unlock()