Skip to content

apollo_consensus_orchestrator: use HashSet instead of IndexSet for duplicate-tx tracking#14856

Open
gkaempfer wants to merge 1 commit into
mainfrom
claude/perf/apollo_consensus_orchestrator-dedup-set-choice-39764
Open

apollo_consensus_orchestrator: use HashSet instead of IndexSet for duplicate-tx tracking#14856
gkaempfer wants to merge 1 commit into
mainfrom
claude/perf/apollo_consensus_orchestrator-dedup-set-choice-39764

Conversation

@gkaempfer

Copy link
Copy Markdown
Contributor

Summary

Follow-up performance review of #14840, scoped to the duplicate-transaction-hash tracking it added to the proposal validation hot path in crates/apollo_consensus_orchestrator/src/validate_proposal.rs.

#14840 introduced seen_tx_hashes: IndexSet<TransactionHash> in validate_proposal, populated once per transaction in every proposal part received during consensus proposal validation (handle_proposal_part) — a genuine per-transaction, per-block hot path.

seen_tx_hashes is only ever inserted into and queried for membership (!seen_tx_hashes.insert(tx_hash)); it is never iterated or indexed anywhere in the file (verified via grep -n "seen_tx_hashes" -r crates/apollo_consensus_orchestrator/src/). IndexSet (from indexmap) exists specifically to provide insertion-order iteration, at the cost of an auxiliary dense-vector layer on top of the hash table — overhead this call site never benefits from. Swapping to std::collections::HashSet removes that bookkeeping from every transaction insertion, with a smaller memory footprint, while leaving behavior identical (insert returns bool = "was newly inserted" on both types; TransactionHash: Hash + Eq satisfies both).

The removed use indexmap::IndexSet; was the only use of IndexSet in this file; indexmap remains a dependency of the crate for unrelated usage elsewhere (cende/central_objects.rs).

Test plan

  • cargo build -p apollo_consensus_orchestrator — clean
  • SEED=0 cargo test -p apollo_consensus_orchestrator — 177 passed, 0 failed, including duplicate_transaction_hash_in_proposal_is_rejected_before_batcher, which exercises this exact code path
  • Reviewed by an independent Opus pass: confirmed the set is never iterated elsewhere, the substitution is behavior-preserving, and the import removal breaks nothing — no blocking or suggestion findings

🤖 Generated with Claude Code


Generated by Claude Code

…plicate-tx tracking

Follow-up performance review of #14840. The seen_tx_hashes set added to
validate_proposal for duplicate-transaction detection is only ever
inserted into and queried for membership, never iterated, so it gains
nothing from IndexSet's insertion-order bookkeeping. Using a plain
HashSet avoids that overhead on every transaction in every validated
proposal.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PZ8grrsVcz9dQaaTWDafeT
@gkaempfer
gkaempfer requested a review from dan-starkware July 21, 2026 14:33
@cursor

cursor Bot commented Jul 21, 2026

Copy link
Copy Markdown

PR Summary

Low Risk
Behavior-preserving type swap on membership-only duplicate detection; consensus validation logic is unchanged aside from data structure choice.

Overview
Swaps IndexSet<TransactionHash> for std::collections::HashSet<TransactionHash> when tracking transaction hashes during consensus proposal validation in validate_proposal.rs.

Duplicate detection still uses !seen_tx_hashes.insert(tx_hash) in handle_proposal_part; insertion order was never used, so dropping indexmap’s extra ordering layer should cut per-tx overhead on that hot path without changing rejection behavior.

Reviewed by Cursor Bugbot for commit 9affa3b. Bugbot is set up for automated code reviews on this repo. Configure here.

@reviewable-StarkWare

Copy link
Copy Markdown

This change is Reviewable

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.

4 participants