Skip to content

perf: eliminate redundant read_dispair calls in try_into_call#2793

Open
thedavidmeister wants to merge 6 commits into
mainfrom
2026-06-29-issue-2776-dispair-cache
Open

perf: eliminate redundant read_dispair calls in try_into_call#2793
thedavidmeister wants to merge 6 commits into
mainfrom
2026-06-29-issue-2776-dispair-cache

Conversation

@thedavidmeister

@thedavidmeister thedavidmeister commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Summary

try_into_call previously called read_dispair three times — once inline and once inside each try_parse_rainlang call — totalling 12 sequential RPC round-trips just to read 4 immutable deployer addresses. At 300ms RTT (remote RPC) that is ~3.6s of avoidable latency.

Changes

  • Add parse_bytecode_with_dispair: the parsing body extracted from try_parse_rainlang, takes a pre-fetched DISPaiR (no additional dispair reads).
  • try_parse_rainlang is now a thin wrapper: read_dispair + parse_bytecode_with_dispair. All existing tests remain unchanged.
  • try_into_call calls read_dispair once, clones for the first parse, moves for the second parse, and extracts interpreter/store upfront.

Result

RPC calls per generate_deposit_and_add_order_calldatas (dispair portion):

Before After
12 (3× read_dispair) 4 (1× read_dispair)

Total for a single deposit+addOrder: 14 → 6 sequential eth_call round-trips, saving ~2.4s at 300ms RTT.

Test

Adds assertions to test_into_add_order_call verifying both config.evaluable.interpreter/store and tasks[0].evaluable.interpreter/store match the expected interpreter/store addresses (and match each other). This mutation-validates that both evaluables receive the correct dispair from the single shared read.

Closes #2776

Co-Authored-By: Claude noreply@anthropic.com

Summary by CodeRabbit

  • Bug Fixes
    • Reduced unnecessary network calls when preparing orders, which should make order creation faster and more reliable.
    • Ensured both the main order logic and follow-up action use the same resolved interpreter and store values.

try_into_call previously called read_dispair 3 times (once directly and
once inside each try_parse_rainlang call), totalling 12 sequential RPC
round-trips just to read 4 immutable deployer addresses.

Add parse_bytecode_with_dispair, which takes a pre-fetched DISPaiR and
skips the read_dispair step. try_parse_rainlang becomes a wrapper around
read_dispair + parse_bytecode_with_dispair. try_into_call now calls
read_dispair once and passes the result to both parse calls via clone/move.

RPC calls for a single deposit+addOrder submission: 14 → 6 (saves 8
sequential round-trips, ~2.4s at 300ms RTT).

Adds assertions to test_into_add_order_call verifying both config.evaluable
and tasks[0].evaluable carry the correct interpreter and store addresses
from the single shared dispair read.

Closes #2776

Co-Authored-By: Claude <noreply@anthropic.com>
@thedavidmeister thedavidmeister self-assigned this Jun 29, 2026
@coderabbitai

coderabbitai Bot commented Jun 29, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@thedavidmeister, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 59 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 55d12ce7-64df-464e-9a6c-f6f826693473

📥 Commits

Reviewing files that changed from the base of the PR and between e4ca835 and 1bbbc20.

📒 Files selected for processing (3)
  • crates/common/src/raindex_order_builder/order_operations.rs
  • crates/common/src/raindex_order_builder/select_tokens.rs
  • packages/raindex/test/js_api/builder.test.ts
📝 Walkthrough

Walkthrough

The rainlang parsing flow in AddOrderArgs is refactored to eliminate redundant DISPaiR RPC calls. A new parse_bytecode_with_dispair method accepts a pre-fetched DISPaiR instance, and try_into_call now fetches DISPaiR once, reusing cached interpreter and store values for both main and post-task evaluables.

Changes

DISPaiR reuse in rainlang parsing

Layer / File(s) Summary
Extract parse_bytecode_with_dispair
crates/common/src/add_order.rs
New public async method accepts a pre-fetched DISPaiR and parses rainlang into bytecode; test-only try_parse_rainlang now reads dispair and delegates to it.
Single dispair fetch in try_into_call
crates/common/src/add_order.rs
read_dispair is called once at the start, caching interpreter and store; both main and post-task rainlang parsing reuse the shared dispair, and both evaluable structures use the cached values instead of separate fetches.
Test assertions for shared addresses
crates/common/src/add_order.rs
New test assertions verify config.evaluable and tasks[0].evaluable use identical interpreter and store addresses from the single shared fetch.

Estimated code review effort: 2 (Simple) | ~10 minutes

Related issues: Addresses redundant read_dispair RPC round-trips described in "RaindexOrderBuilder: sequential RPC round-trips inflate order prep."

Suggested reviewers: rainlanguage core maintainers familiar with add_order.rs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title is specific and accurately summarizes the main performance refactor in try_into_call.
Linked Issues check ✅ Passed The PR implements the core #2776 fix by reusing a pre-fetched DISPair and removing redundant read_dispair calls.
Out of Scope Changes check ✅ Passed The changes stay focused on the RPC reduction refactor and corresponding tests, with no unrelated scope visible.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch 2026-06-29-issue-2776-dispair-cache

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

thedavidmeister and others added 2 commits June 29, 2026 17:49
Mark try_parse_rainlang as #[cfg(test)] — after the try_into_call
refactor it is only called from tests, so the production build flags
it as dead code under -D warnings.

Co-Authored-By: Claude <noreply@anthropic.com>
@thedavidmeister thedavidmeister added the ai:ready AI vetter: passes review, ready for human decision label Jul 6, 2026
@thedavidmeister

thedavidmeister commented Jul 7, 2026

Copy link
Copy Markdown
Contributor Author

🤖 ai:vetter
Reviewed e4ca835: ready — single read_dispair call cloned for first parse moved for second; parse_bytecode_with_dispair takes
cost 480 — perf change in Rust async RPC code

@thedavidmeister thedavidmeister added human:reject Human reviewer: needs rework and removed ai:ready AI vetter: passes review, ready for human decision labels Jul 8, 2026
@thedavidmeister

Copy link
Copy Markdown
Contributor Author

Rework note (human): incomplete coverage of #2776. The issue names three redundant RPC-fetch sources; this PR dedups only read_dispair (12→4). Still duplicated: set_select_token fetches token_info twice when the same token is selected for both input and output slots, and generate_approval_calldatas refetches decimals that set_select_token already has. Dedup those two as well to close #2776.

thedavidmeister and others added 2 commits July 10, 2026 01:09
…decimals fetches

set_select_token reuses a complete token record already in the yaml for
the same network+address (recorded by an earlier selection) instead of
refetching token_info, so selecting one token for both the input and
output slot costs a single multicall (2 -> 1). Incomplete records and
records on other networks never shortcut the fetch, and re-selecting a
key with its current address also skips it.

generate_approval_calldatas reads decimals from the deposits map (which
now carries them from get_token_info) instead of issuing a decimals()
RPC per token (1 -> 0); the only remaining round-trip per token is the
allowance read. This also aligns the approval amount's decimals source
with the deposit calldata path (yaml-first with on-chain fallback).

Both behaviors are pinned by mock hit-count tests, mutation-validated
against reintroduced duplicate fetches, dropped network/address/
completeness guards, lookup-after-removal ordering, and corrupted map
decimals.

Co-Authored-By: Claude <noreply@anthropic.com>
@thedavidmeister

Copy link
Copy Markdown
Contributor Author

🤖 ai:producer
Producer note: rework executed — (1) set_select_token now reuses a complete same-network yaml token record instead of refetching token_info: same token selected for input+output slots = 1 multicall instead of 2 (test_set_select_token_same_address_fetches_once, mock hit-count pinned; cross-network/incomplete records never shortcut, re-selection reuses its own record). (2) generate_approval_calldatas reads decimals from the deposits map instead of a per-token decimals() RPC: 1 -> 0, only the allowance read remains (test_generate_approval_calldatas_reuses_deposit_token_decimals, 0-hit + exact-amount pinned). Branch merged current with main; raindex_common suite locally green (1161 passed); all 7 mutants (reintroduced duplicate fetches, dropped guards, reordered removal, corrupted decimals) killed. With the earlier read_dispair dedup this covers all three fetch sources named in #2776. Remaining CI reds are the known raindex main-state failures.

…lldata dedup [3b-attempt]

generate_approval_calldatas no longer issues a per-token decimals() RPC
(decimals come from the deposits map), so the sequence-based mocked
decimals responses in the approval tests were consumed by the allowance
reads instead, turning a 1000e18 allowance into 18 wei and producing an
extra approval calldata (AssertionError: 2 == 1 at builder.test.ts:1463).
Remove the now-dead decimals mocks so each deposited token mocks exactly
its allowance read.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@thedavidmeister

Copy link
Copy Markdown
Contributor Author

🤖 ai:producer
Producer note: post-rework CI triage. test-js-bindings was the one PR-caused red — the approval-calldata dedup left sequence-based decimals mocks stale in builder.test.ts, so the allowance reads consumed the 0x12 decimals responses (allowance became 18 wei, emitting an extra approval: 2 != 1). Fixed by 1bbbc20 fix(ci): test-js-bindings drop stale decimals mocks after approval-calldata dedup [3b-attempt]. The remaining reds (rainix-sol/static, rainix-sol/test, rs-static) are red inherited from main (rainix no-skips vm.skip gate on 5 pre-existing test/lib/deploy files + missing 0.1.13 soldeer constant pins), not PR-caused; fixed by #2804 (green, ai:ready); greens on branch update once it lands. flag-blocked-on refused (human decision present), so classification posted as comment.

@thedavidmeister

Copy link
Copy Markdown
Contributor Author

🤖 ai:producer
Producer note (state change — correction to the prior note): the [3b-attempt] fix 1bbbc20 did NOT green test-js-bindings — the check re-ran at that exact head (run 29226076755, 2026-07-13) and still fails at test/js_api/builder.test.ts:1451 with the same signature (expected 1 approval call, received 2). One fix attempt is spent, so back-off forbids a second push. flag-blocked-infra was refused (human decision present), so this stays parked under human:reject for human re-adjudication. The other three reds remain the main-state trio fixed by #2804.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

human:reject Human reviewer: needs rework

Projects

None yet

Development

Successfully merging this pull request may close these issues.

RaindexOrderBuilder: sequential RPC round-trips inflate order prep

1 participant