Repository navigation
perf(lez): run guests in-process on the node via the memoized image cache - #872
Merged
Merged
Conversation
schouhy
approved these changes
Sep 10, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
🎯 Purpose
The sequencer and indexer build without
prove, solee/state_machine/src/program/mod.rs:122resolves to risc0'sExternalProver: a fresh r0vm subprocess per guest execution, anr0vm --versionprobe per call, and an ELF-to-memory-image rebuild every time. Withprovethe same call site usesimage_cache::execute, which runs in-process against a memoized image. The two are selected by a hardcfg, and onlyunit-tests(via--all-features) has ever exercised the fast one.Measured on one machine,
RISC0_DEV_MODE=1, release:storagereplay test (~1300 executions)tps_test, 1500 charged txsThe last row is the headline: the node as it ships cannot reach the repo's own 8 TPS target, and reaches 23 TPS with this change.
Binary size is unchanged (40,707,392 vs 40,707,600 bytes) because only the executor is reachable and the proving circuits are dead-stripped. The cost is build time: 77 additional crates, seven of them native.
⚙️ Approach
provefeature tochain_state,sequencer_core,sequencer_service,indexer_core,indexer_service, each forwarding tolee/prove, reusing the existingstorage/proveFEATUREStoprovein both service DockerfilesFEATURES=prove,mdnsfor thesequencer_service-mdnsimage, which passedFEATURES=mdnsand would otherwise have overridden the default and silently stayed on the subprocess path🧪 How to Test
Confirm the executor actually changes, not just the feature:
client,stdvsclient,prove,std. Then reproduce the throughput difference:🔜 Future Work
Cargo.toml:105pinswallet-ffiwithdefault-features = false. Wiringproveinto the 35 CI shards was tried and abandoned: enabling it also flipsdefault_prover()toLocalProver, whose dev-mode path unwraps atdev_mode.rs:167instead of returning an error, soauth_transfer::private::ppt_cant_chain_call_faucetpanics where it used to get a cleanErr. The speedup also looks small there, since integration tests wait on block timers rather than being executor-bound. Neither issue affects this PR: the services never calldefault_prover().RISC0_SERVER_PATHfrom both images once nothing can fall back toExternalProver.📋 PR Completion Checklist