From 3785d43db4476a34ae9fb65264038ec0cdcde65f Mon Sep 17 00:00:00 2001 From: Csaba Kiraly Date: Fri, 10 Apr 2026 10:34:33 +0200 Subject: [PATCH] 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. --- eth/txtracker/tracker.go | 6 ++++-- eth/txtracker/tracker_test.go | 5 +++++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/eth/txtracker/tracker.go b/eth/txtracker/tracker.go index beaab60977..8458c8253d 100644 --- a/eth/txtracker/tracker.go +++ b/eth/txtracker/tracker.go @@ -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 } diff --git a/eth/txtracker/tracker_test.go b/eth/txtracker/tracker_test.go index 35c315ac8f..36d72def23 100644 --- a/eth/txtracker/tracker_test.go +++ b/eth/txtracker/tracker_test.go @@ -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()