Skip to content

refactor(hindsight): make per-transaction decode RPC-free - #391

Open
kayibal wants to merge 2 commits into
feat/hindsight-relay-revertsfrom
feat/hindsight-pure-decode
Open

refactor(hindsight): make per-transaction decode RPC-free#391
kayibal wants to merge 2 commits into
feat/hindsight-relay-revertsfrom
feat/hindsight-pure-decode

Conversation

@kayibal

@kayibal kayibal commented Jul 31, 2026

Copy link
Copy Markdown
Contributor

What

Removes the last RPC escape hatch from DecodeContext: decoding a matched transaction is now a
pure function of its receipt, trace, and calldata. No TradeDecoder issues RPC of its own.

Changes

  • The one RPC use inside decoding, intents/netting.rs's is_contract check
    (eth_getCode, used to tell an intent-fill candidate EOA apart from a contract), is hoisted to
    the decoder driver: Decoder::prefetch_contract_flags runs once per block, before per-tx
    decode, for exactly the candidates intents::netting::intent_candidates would enumerate for
    each intent-role transaction in that block — not every address in every ledger, since intent
    fills are a small fraction of matched transactions. Results join the existing cross-block
    code_cache, so a recurring candidate (a router, a pool) costs one RPC call for the life of the
    run.
  • DecodeContext.provider and .code_cache are replaced by contract_flags: &HashMap<Address, bool> — a plain lookup, prefetched ahead of decode. find_intent_trade becomes a synchronous
    function taking that map instead of a provider.
  • Dropping DecodeContext's RPC dependency removes the now-unused P: Provider generic from
    TradeDecoder, DecodeContext, decoders_for, recover, try_decoders, and every
    TradeDecoder impl (SenderNetting, every venues/* decoder, CowSettlement,
    IntentNetting) — along with the mocked-provider test scaffolding each of those carried solely
    to satisfy the type.
  • decode_transaction takes &self instead of &mut self, since it no longer needs mutable
    access to the code cache during decode.

Behavior

Unchanged: same decode results, same trades. Covered by a new end-to-end test
(decoder::tests::test_intent_fill_prefetches_the_candidate_contract_flag) that runs
decode_block for an intent-fill transaction through a mocked provider and confirms the
prefetched eth_getCode result reaches IntentNetting via contract_flags.

Testing

  • cargo check --workspace --all-features, cargo clippy --locked --workspace --all-targets --all-features -- -D warnings, cargo nextest run -p hindsight (303 passed, 1 skipped),
    cargo +nightly fmt --check, and RUSTDOCFLAGS="-D warnings" cargo doc --no-deps -p hindsight -p fynd-core -p fynd-rpc-types -p fynd-rpc -p fynd-client — all clean.

Pre-commit hook not used for the commits on this branch: cargo nextest run --workspace --bin fynd SIGABRTs on this machine on an unrelated fynd-core test (a conda/cc PATH issue
breaking Rust panic unwinding, environmental). Verified manually instead; see above.

🤖 Generated with Claude Code

@kayibal
kayibal force-pushed the feat/hindsight-relay-reverts branch from 134e666 to 1792c69 Compare July 31, 2026 14:42
@kayibal
kayibal force-pushed the feat/hindsight-pure-decode branch from 283da8d to 53eefb8 Compare July 31, 2026 14:48
@kayibal
kayibal force-pushed the feat/hindsight-relay-reverts branch from 1792c69 to 44908ea Compare July 31, 2026 17:41
@kayibal
kayibal force-pushed the feat/hindsight-pure-decode branch from 53eefb8 to ac9a2fe Compare July 31, 2026 17:52

@tamaralipows tamaralipows left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Just stumbled upon this. This is a great idea and looks so much cleaner

@kayibal
kayibal force-pushed the feat/hindsight-relay-reverts branch from 44908ea to 4aa0fea Compare August 2, 2026 12:12
@kayibal
kayibal force-pushed the feat/hindsight-pure-decode branch from ac9a2fe to dfe4f9a Compare August 2, 2026 12:14
@kayibal
kayibal force-pushed the feat/hindsight-relay-reverts branch 2 times, most recently from 10616a3 to 29c9ec7 Compare August 3, 2026 17:32
kayibal and others added 2 commits August 3, 2026 18:32
Remove the last RPC escape hatch from DecodeContext: decode is now a
pure function of a receipt, its trace, and its calldata. The only
production RPC use inside decoding was intents/netting.rs's is_contract
check (eth_getCode via DecodeContext.provider + .code_cache), used to
tell an intent-fill candidate EOA apart from a contract.

Hoist that check to the decoder driver: Decoder::prefetch_contract_flags
runs once per block, before per-tx decode, for exactly the candidates
intents::netting::intent_candidates would enumerate for each settled,
intent-role transaction in the block -- not every address in every
ledger, and not reverted candidates, which never reach the TraderFlow
decoder chain at all (decode_reverted reads only the trace and the
solver frame's calldata). Results join the existing cross-block
code_cache. DecodeContext.provider and .code_cache are replaced by
contract_flags: &HashMap<Address, bool>, a plain lookup; find_intent_trade
becomes a synchronous function taking that map instead of a provider.

Dropping DecodeContext's RPC dependency removes the now-unused P:
Provider generic from TradeDecoder, DecodeContext, decoders_for, recover,
try_decoders, and every TradeDecoder impl (netting_decoders::SenderNetting,
every venues/* decoder, intents::cow::CowSettlement,
intents::netting::IntentNetting), along with the mocked-provider test
scaffolding each of those carried solely to satisfy the type.
decode_settled now takes &self (not &mut self) for the same reason,
matching decode_reverted and the decode_transaction dispatcher that
calls either.

Behavior is unchanged: same decode results, same trades. Verified with a
new end-to-end test (decoder::tests::test_intent_fill_prefetches_the_candidate_contract_flag)
that runs decode_block for an intent-fill transaction through a mocked
provider and confirms the prefetched eth_getCode result reaches
IntentNetting via contract_flags.

Manual verification (pre-commit hook not run -- cargo nextest run
--workspace SIGABRTs on an unrelated fynd-core sim_guard test on this
machine, a known conda/cc PATH issue breaking panic unwinding):
- cargo check --workspace --all-features: pass
- cargo clippy --locked --workspace --all-targets --all-features
  -- -D warnings: pass
- cargo nextest run -p hindsight --all-features: 311 passed, 1 skipped
- cargo +nightly fmt --all -- --check: pass
- RUSTDOCFLAGS="-D warnings" cargo doc for hindsight, fynd-core,
  fynd-rpc-types, fynd-rpc, fynd-client: pass

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Update the decode pipeline section and the TradeDecoder trait sketch
for DecodeContext dropping its RPC provider and code_cache in favor
of contract_flags, and the decoder driver's prefetch_contract_flags
step that gathers them before per-tx decode runs.

Pre-commit hook not run (see prior commits: cargo nextest run
--workspace --bin fynd SIGABRTs on an unrelated fynd-core test on this
machine). Docs-only change; no code checks apply.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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