erigontech / erigontech/erigon
txpool: deduplicate addTxns and addTxnsOnNewBlock
- Dominant language
- Go
- Stars
- 3.6k
- Forks
- 1.5k
- Avg merge
- 1d 16h
- Merged PRs (30d)
- 455
Description
The `// TODO: Looks like a copy of the above` comment at [`txnprovider/txpool/pool.go:1520`](https://github.com/erigontech/erigon/blob/main/txnprovider/txpool/pool.go#L1520) has been outstanding since 2023 (added in adef9719957). The two functions — `addTxns` (used by `AddLocalTxns` and `processRemoteTxns`) and `addTxnsOnNewBlock` (used by `OnNewBlock` for unwound reorg txs) — share the bulk of their structure but diverge in several specifics, which makes the duplication non-trivial to collapse.
## Material differences today
| | `addTxns` | `addTxnsOnNewBlock` |
|---|---|---|
| Return value | `(Announcements, []DiscardReason, error)` | `(Announcements, error)` |
| Duplicate-hash handling | Records `DuplicateHash`; pokes rebroadcast for stuck local txs | Silently skips |
| `addLocked` failure | Records reason; does **not** call `discardLocked` | Calls `discardLocked` |
| Sender source | New-tx senders only | New-tx senders **plus** `stateChanges.ChangeBatch` UPSERTs **plus** queued-tx senders (added in #20996) |
| `senderLastActivity` | Initialized to `blockNum` only if absent (preserve existing) | Reset to `blockNum` for state-change senders; **not touched** for queued-only senders (#20996) |
| `promote()` | Called inline | Called by `OnNewBlock` after this function returns |
| `collect` parameter | Yes | No |
The shared scaffolding is the new-tx loop (`byHash` check → `newMetaTxn` → `addLocked` → collect senderID), the per-sender `senders.info` + `onSenderStateChange` loop, and the announcements bookkeeping.
## Why this is worth doing now
#20996 added the queued-sender re-evaluation pass to `addTxnsOnNewBlock` only. Strictly speaking the same race that pass exists to recover from can also be hit by `processRemoteTxns` (which goes through `addTxns`) — though in practice the next `OnNewBlock` covers it. A shared helper would make it natural to have one canonical re-evaluation site rather than two slightly-different ones, and would make future invariants easier to keep consistent across both paths.
It would also clear the TODO that's been sitting in the file for two years.
## Suggested approach
Extract a `addTxnsCore` (or similar) helper that takes the new txs and a set of additional senders to re-evaluate, plus a small struct of behavior knobs:
- whether duplicate hashes should produce `DiscardReasons` or be silent;
- whether `addLocked` failure should call `discardLocked`;
- the `senderLastActivity` policy (initialize-if-absent vs reset);
- whether to call `promote()` inline.
`addTxns` and `addTxnsOnNewBlock` then become thin wrappers that compose the additional senders (stateChanges UPSERTs + queued-tx senders for the OnNewBlock path) and pass the appropriate behavior flags. The existing test suite (especially `TestStalePendingEvictionViaMineNonce`, `TestQueuedTxnPromotedAfterStaleAddLocal`, the unwind-related tests) should catch regressions in the consolidation.
Not urgent — pure refactor with no behavior change intended. Picking up "good first issue" only if someone is already comfortable with this corner of the txpool, since the divergences are subtle.
Contributor guide
Assessment
This issue has not been assessed yet.