Skip to content

fix(backend): prevent panic when txn_idx exceeds fixed buffer size - #115

Merged
iamvukasin merged 2 commits into
monad-developers:mainfrom
ayushsingh82:fix/txn-hash-tracker-panic
Sep 8, 2026
Merged

fix(backend): prevent panic when txn_idx exceeds fixed buffer size#115
iamvukasin merged 2 commits into
monad-developers:mainfrom
ayushsingh82:fix/txn-hash-tracker-panic

Conversation

@ayushsingh82

@ayushsingh82 ayushsingh82 commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

Summary

current_txn_hashes in run_event_forwarder_task tracked per-transaction hashes in a Vec<Option<[u8; 32]>> fixed at 10,000 entries, indexed directly by txn_idx. txn_idx comes straight off the event ring with no upper bound. Two of the three call sites wrote via [] indexing with no bounds check (a third, read-only, site already used .get() defensively) — so any block with txn_idx >= 10_000 panics and kills the event-forwarder task, cutting off all live data to connected clients until the health check's exit threshold restarts the process.

Changes

  • Added TxnHashTracker (backend/src/lib/txn_hash_tracker.rs), backed by a HashMap<usize, [u8; 32]> instead of a fixed-size Vec, so there's no capacity to exceed.
  • Replaced the three inline call sites in run_event_forwarder_task (server.rs) with record/get/clear on the tracker.
  • As a side effect, entries are now removed on TxnEnd instead of sitting as None forever in the old buffer.
  • Added unit tests for the new struct, including one exercising txn_idx = 50_000 to cover the exact scenario that used to panic.

Behavior for txn_idx < 10_000 is unchanged.

Test plan

  • cargo fmt --check passes on the crate
  • New unit tests pass (verified in isolation via rustc --test, since the full crate's monad-event-ring dependency requires a native toolchain — cmake + Linux hugetlbfs headers per the CI container — not available on my local macOS setup)
  • CI (cargo clippy, cargo build, cargo test in the Linux CI container) — deferred to this PR's CI run, since I could not run the full workspace build locally

Greptile Summary

The PR replaces fixed transaction-hash indexing with a map-backed tracker and completes the earlier memory-retention fix by clearing stale entries at block boundaries.

  • Adds TxnHashTracker with record, lookup, per-transaction removal, and full reset operations.
  • Resets tracked hashes on BlockStart and removes entries on TxnEnd.
  • Adds unit coverage for large transaction indices and orphan cleanup.

Confidence Score: 5/5

The PR appears safe to merge.

No blocking failure remains.

Important Files Changed

Filename Overview
backend/src/lib.rs Exposes the new transaction-hash tracker module.
backend/src/lib/server.rs Replaces fixed-buffer accesses with tracker operations and clears stale entries at block boundaries.
backend/src/lib/txn_hash_tracker.rs Implements the map-backed tracker and tests large indices, removal, replacement, and block reset behavior.

Reviews (5): Last reviewed commit: "fix(backend): reset TxnHashTracker on Bl..." | Re-trigger Greptile

@vercel

vercel Bot commented Aug 6, 2026

Copy link
Copy Markdown

@ayushsingh82 is attempting to deploy a commit to the MF Flagship Team on Vercel.

A member of the Team first needs to authorize it.

Comment thread backend/src/lib/txn_hash_tracker.rs
@ayushsingh82

Copy link
Copy Markdown
Contributor Author

Addressed in 6cbf1b3: added TxnHashTracker::reset(), called on every BlockStart. Since txn_idx is scoped to a single block, this bounds memory regardless of a missed TxnEnd (e.g. from an event-ring gap) — no orphaned entries can survive past the block they were recorded in.

@vercel

vercel Bot commented Sep 8, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
monode Ready Ready Preview Sep 8, 2026 11:16am UTC

Request Review

@iamvukasin

Copy link
Copy Markdown
Contributor

@ayushsingh82 Can you use verified signatures for commits?

Motivation:

current_txn_hashes tracked per-transaction hashes in a Vec fixed at
10_000 entries, indexed directly by txn_idx (unbounded, taken straight
off the event ring). Two of the three call sites wrote via `[]`
indexing with no bounds check, so any block with txn_idx >= 10_000
panics and kills the event-forwarder task, silently cutting off all
live data until the health check's exit threshold restarts the
process.

Modifications:

Extract the tracking into a new TxnHashTracker (backend/src/lib/txn_hash_tracker.rs),
backed by a HashMap<usize, [u8; 32]> instead of a fixed-size Vec, so
there is no capacity to exceed. Replace the three inline call sites in
run_event_forwarder_task with record/get/clear on the tracker. Added
unit tests, including one that exercises a txn_idx of 50_000 to cover
the exact scenario that used to panic.

Result:

Transaction hash tracking no longer has an upper bound on txn_idx.
Existing behavior for txn_idx < 10_000 is unchanged.
Motivation:

Per review feedback on this PR (Greptile): switching from a fixed-size
Vec to a HashMap removes the panic on txn_idx >= 10_000, but on its
own it trades that crash for unbounded growth in the other direction.
If a transaction's TxnEnd is ever missed (e.g. the event-ring reader
hits a Gap and calls reset(), per event_listener.rs), record() has no
matching clear() and that entry is retained for the life of the
forwarder task.

Modifications:

Add TxnHashTracker::reset(), and call it on every BlockStart in
run_event_forwarder_task. txn_idx is scoped to a single block, so
nothing left over from a previous block is ever valid to keep -
resetting on BlockStart bounds memory regardless of what gets missed
mid-block. Added a test covering a txn_idx whose TxnEnd is never
cleared, verifying reset() drops it.

Result:

Memory used by transaction hash tracking is now bounded by the
transaction count of a single block, independent of any missed
TxnEnd events.
@ayushsingh82
ayushsingh82 force-pushed the fix/txn-hash-tracker-panic branch from 84aafb2 to 7c250f3 Compare September 8, 2026 11:08
@ayushsingh82

Copy link
Copy Markdown
Contributor Author

@iamvukasin done, both commits are signed and show as verified now.

@iamvukasin
iamvukasin merged commit a160500 into monad-developers:main Sep 8, 2026
12 checks passed
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.

2 participants