Skip to content

fix(mempool): tolerate missing/foreign edges on eviction#234

Merged
EddieHouston merged 5 commits into
new-indexfrom
mempool-evict-tolerant
Jul 16, 2026
Merged

fix(mempool): tolerate missing/foreign edges on eviction#234
EddieHouston merged 5 commits into
new-indexfrom
mempool-evict-tolerant

Conversation

@DeviaVir

@DeviaVir DeviaVir commented Jul 15, 2026

Copy link
Copy Markdown

The strict assert! in Mempool::remove() (from the eviction-accounting work in 477c1a3) panics when an evicted tx's input outpoint is missing from edges, which legitimately happens when conflicting (RBF) spends transiently coexist across mempool snapshot rounds: the later add() overwrites the earlier tx's entry, so the earlier tx's eviction finds the entry gone or owned by its replacement.

This crashed the server about once per hour:

thread 'main' (1) panicked at src/new_index/mempool.rs:519:17:
missing mempool edge for outpoint 0f330630...:0 (tx 04458627...)

Fix: only remove the edge if the evicted tx still owns it, warn otherwise. The worst case of a clobbered entry (replacement tx's edge stays live) is identical to today's behavior between snapshot rounds, and a warning beats a full restart + mempool re-sync.

Conflicting (RBF) spends can transiently coexist in the local mempool view
across snapshot rounds; add() then overwrites the earlier tx's entry in
`edges`, so evicting the earlier tx finds its outpoint entry missing or
owned by the conflicting tx. This tripped the eviction assert roughly once
an hour on mainnet (electrum.blockstream.info canary, 2026-07-15), taking
the whole server down for a recoverable bookkeeping inconsistency.

Only remove an edge if the evicted tx still owns it; warn otherwise.
test_rest_address asserted the prefix search returns exactly one address,
but other randomly-generated wallet addresses (change outputs) can share
the 8-char prefix (~1/1024 per address), failing the run by lottery.
Assert addr1 is among the matches instead.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR prevents Mempool::remove() from panicking when an evicted transaction’s input outpoint is missing from (or no longer owned in) edges, which can legitimately occur when conflicting (RBF) spends transiently overlap across mempool snapshot rounds.

Changes:

  • Replaces a strict assert! on edge removal with conditional removal only when the evicted tx still owns the edge.
  • Adds a warning log when an edge is missing or owned by a different transaction instead of crashing.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/new_index/mempool.rs Outdated
DeviaVir added 3 commits July 15, 2026 14:06
Addresses review: avoid the get+remove double hash lookup and split the
warning into explicit missing vs conflicting-owner cases.
The conflicting-spend coexistence isn't produced by update() itself
(evictions precede additions against one consistent snapshot); the
injector is broadcast_raw()/submit_package() adding transactions via
add_by_txid(s) outside the sync loop. Point the comment at the real
mechanism, drop the dated incident detail (lives in the fix's commit
message), and remove a test assert made redundant by the any() below it.
Reproduces the two-step failure exactly as seen in production:

1. tx A is indexed; its replacement B (same outpoint) is injected via the
   broadcast endpoint while A is still indexed, clobbering A's edges entry.
2. The sync evicting A passed the old assert by STEALING B's edge (any
   Some() satisfied it), silently corrupting spend lookups for B.
3. When B itself leaves the mempool (confirmed/replaced/expired), its edge
   is already gone and the old assert panicked with 'missing mempool edge
   for outpoint', killing the sync loop.

Fails on the pre-fix code with that exact panic; passes with the
ownership-checked eviction.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated no new comments.

@EddieHouston EddieHouston left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

utACK 96d2174

@Randy808

Randy808 commented Jul 15, 2026

Copy link
Copy Markdown
Collaborator

Seems related to this:
#172 (comment)

I'll open a formal issue for it

Edit: Issue is now being tracked here

@PeteClubSeven

Copy link
Copy Markdown

I just tested this branch and I was able to RBF a TRUC transaction so it fixes the issue 👍

@EddieHouston

Copy link
Copy Markdown
Collaborator

Seems related to this: #172 (comment)

I'll open a formal issue for it

Edit: Issue is now being tracked here

replied with more info here: #236 (comment)

@EddieHouston
EddieHouston merged commit ef44179 into new-index Jul 16, 2026
7 checks passed
@DeviaVir
DeviaVir deleted the mempool-evict-tolerant branch July 16, 2026 07:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants