From 1f774139593d5cee57655284984be9e6da097159 Mon Sep 17 00:00:00 2001 From: Csaba Kiraly Date: Mon, 22 Jun 2026 21:04:37 +0200 Subject: [PATCH] eth/txtracker: rename txEntry to TxInfo, align field names with richer model No functional change. Prepares the minimal model to mirror the field naming of the richer txtracker variants on adjacent branches so that upcoming cherry-picks (lastFinalNum seed, IncludedDeliverer freeze, collectFinalization pivot to iterate t.txs) can apply with smaller deltas. Changes: - txEntry -> TxInfo (exported, pointer in t.txs map) - txEntry.peer -> TxInfo.Deliverer - txEntry.addedAt -> TxInfo.AddedAt - add TxStatus enum (StatusUnknown / StatusIncluded / StatusFinalized); not yet assigned on any code path here - add TxInfo.BlockNum and TxInfo.BlockHash; not yet assigned --- eth/txtracker/tracker.go | 43 +++++++++++++++++++++-------------- eth/txtracker/tracker_test.go | 6 ++--- 2 files changed, 29 insertions(+), 20 deletions(-) diff --git a/eth/txtracker/tracker.go b/eth/txtracker/tracker.go index f034bf8ccf..26b08a5076 100644 --- a/eth/txtracker/tracker.go +++ b/eth/txtracker/tracker.go @@ -68,20 +68,29 @@ type peerStats struct { recentIncluded float64 } -// txEntry tracks the deliverer of a transaction and when delivery was -// recorded. addedAt is unix seconds; it is compared against block.Time() -// to suppress credit for txs delivered at or after the slot of their -// inclusion block (e.g., re-broadcasts of just-mined txs). -type txEntry struct { - peer string - addedAt uint64 +// TxInfo records the per-transaction state the tracker maintains. +// +// Deliverer is the peer that first handed us this tx via NotifyAccepted. +// AddedAt is the unix-seconds wall-clock at that moment; it is compared +// against block.Time() to suppress credit for txs delivered at or after +// the slot of their inclusion block (re-broadcasts of just-mined txs). +// +// BlockNum / BlockHash are populated when the tracker first sees the tx +// in a head block (BlockNum == 0 means not yet seen on chain). BlockHash +// is re-checked against canonical-at-height at finalization time so +// reorgs do not yield credit. +type TxInfo struct { + Deliverer string + AddedAt uint64 + BlockNum uint64 + BlockHash common.Hash } // Tracker records which peer delivered each transaction and credits peers // when their transactions appear on chain. type Tracker struct { mu sync.Mutex - txs map[common.Hash]txEntry // hash → deliverer + arrival time + txs map[common.Hash]*TxInfo // hash → per-tx state peers map[string]*peerStats order []common.Hash // insertion order for LRU eviction @@ -100,7 +109,7 @@ type Tracker struct { // New creates a new tracker. func New() *Tracker { return &Tracker{ - txs: make(map[common.Hash]txEntry), + txs: make(map[common.Hash]*TxInfo), peers: make(map[string]*peerStats), quit: make(chan struct{}), step: make(chan struct{}, 1), @@ -153,7 +162,7 @@ func (t *Tracker) NotifyAccepted(peer string, hashes []common.Hash) { if _, ok := t.txs[hash]; ok { continue // already tracked, keep first deliverer } - t.txs[hash] = txEntry{peer: peer, addedAt: addedAt} + t.txs[hash] = &TxInfo{Deliverer: peer, AddedAt: addedAt} t.order = append(t.order, hash) } // Ensure the delivering peer has a stats entry. @@ -225,11 +234,11 @@ func (t *Tracker) handleChainHead(ev core.ChainHeadEvent) { blockTime := block.Time() blockIncl := make(map[string]int) for _, tx := range block.Transactions() { - entry, ok := t.txs[tx.Hash()] - if !ok || entry.addedAt >= blockTime { + ti, ok := t.txs[tx.Hash()] + if !ok || ti.AddedAt >= blockTime { continue } - blockIncl[entry.peer]++ + blockIncl[ti.Deliverer]++ } // Accumulate per-peer finalization credits over the newly-finalized // range (possibly zero blocks). Only counts peers still tracked. @@ -266,14 +275,14 @@ func (t *Tracker) collectFinalizationCredits() map[string]int { } blockTime := block.Time() for _, tx := range block.Transactions() { - entry, ok := t.txs[tx.Hash()] - if !ok || entry.addedAt >= blockTime { + ti, ok := t.txs[tx.Hash()] + if !ok || ti.AddedAt >= blockTime { continue // unknown, or post-slot re-broadcast } - if _, ok := t.peers[entry.peer]; !ok { + if _, ok := t.peers[ti.Deliverer]; !ok { continue // peer disconnected, skip credit } - credits[entry.peer]++ + credits[ti.Deliverer]++ } } if total := sumCounts(credits); total > 0 { diff --git a/eth/txtracker/tracker_test.go b/eth/txtracker/tracker_test.go index 3942581d95..c79a185599 100644 --- a/eth/txtracker/tracker_test.go +++ b/eth/txtracker/tracker_test.go @@ -197,8 +197,8 @@ func TestNotifyReceived(t *testing.T) { t.Fatalf("expected order length 3, got %d", len(tr.order)) } for i, h := range hashes { - if got := tr.txs[h]; got.peer != "peerA" { - t.Fatalf("tx %d: expected deliverer=peerA, got %q", i, got.peer) + if got := tr.txs[h]; got.Deliverer != "peerA" { + t.Fatalf("tx %d: expected deliverer=peerA, got %q", i, got.Deliverer) } if tr.order[i] != h { t.Fatalf("order[%d] mismatch", i) @@ -468,7 +468,7 @@ func TestRecentFinalizedDecays(t *testing.T) { // post-block-propagation re-broadcast attribution attack: a peer that // learns a tx from the just-mined block and re-broadcasts it to our pool // should not gain credit when that block is processed. The finalization -// path applies the same gate (entry.addedAt >= blockTime) and is exercised +// path applies the same gate (ti.AddedAt >= blockTime) and is exercised // by the existing TestFinalization with the new clock semantics. func TestPreSlotGate(t *testing.T) { tr := New()