Skip to content

Chore/openvm v21 - #257

Draft
lispc wants to merge 15 commits into
masterfrom
chore/openvm-v21
Draft

lispc wants to merge 15 commits into
masterfrom
chore/openvm-v21

Conversation

@lispc

@lispc lispc commented Jul 14, 2026

Copy link
Copy Markdown
Collaborator

No description provided.

lispc added 2 commits July 14, 2026 09:52
- Retarget all openvm-org/openvm.git deps to branch develop-v2.1.0
  (locked at fd569c7); stark-backend stays on tag v2.0.0 as pinned by
  that branch
- Migrate guest to RV64: riscv64im-unknown-openvm-elf target via the
  openvm-1.94.0 toolchain, openvm-rv32im-* -> openvm-riscv-* renames,
  openvm.toml rv32i/rv32m -> rv64i/rv64m
- SDK API: Sdk::riscv64, compile-then-execute for execute* calls
- Hint stream is now u64-based; user public values are u16 cells
  (2 LE bytes each), pi hash fills the first 16 of 32 cells
- Patch locally generated EVM verifier for 2-bytes-per-PV calldata
  (upstream template bug on this branch); regenerate all guest assets
  (commitments, openVmVk.json, verifier.sol/bin)
- Host toolchain: nightly-2026-01-18 (openvm-sdk tco feature)

GPU e2e: single-chunk, multi-chunk, batch, bundle all pass
@github-actions github-actions Bot added crate-chunk-circuit Updates to the guest program chunk-circuit crate-batch-circuit Updates to the guest program batch-circuit crate-bundle-circuit Updates to the guest grogram bundle-circuit crate-prover Updates to the prover crate crate-integration Updates to the integration crate crate-build-guest Updates to building of guest programs crate-circuits Any update made to the circuits, i.e. commitments reflect a change labels Jul 14, 2026
- Update Cargo.lock openvm entries to d193688d
- Adapt save_stdin_as_json to new Vec<u8> StdIn buffer
- Cache SdkCachedProvingKey instead of AggProvingKey for new SDK builder
- Use circuit-specific app_config in tester_execute
- Regenerate guest assets and commitments
@github-actions github-actions Bot added the crate-verifier Updates to the verifier crate label Jul 16, 2026
lispc added 12 commits July 17, 2026 14:55
- Bump openvm (and stark-backend/sdk) to branch develop-v2.1.0 latest.
- Bump snark-verifier-sdk to branch develop-v2.1.0 to avoid duplicate
  snark-verifier / halo2-base / halo2-ecc versions in Cargo.lock.
- Rebuild guest assets and refresh commitment files.
- Verified: cargo check, test-single-chunk, test-e2e-bundle all pass.
- Rebuild chunk/batch/bundle guest assets against openvm fc1a0001
  (previous assets were stale: 'Executor not found for opcode 544'),
  refreshing exe commitment files.
- Dockerfile: install nightly-2026-01-18 host toolchain and cargo-openvm
  (pinned rev fc1a0001) with the openvm-1.94.1 RV64 guest toolchain;
  symlink cargo into the custom toolchain (rustup >= 1.29 no longer
  falls back to the default toolchain's cargo for linked toolchains).
- Makefile/AGENTS.md: default OPENVM_RUST_TOOLCHAIN openvm-1.94.0 ->
  openvm-1.94.1 (what cargo-openvm currently installs).
Pin openvm/stark-backend to develop-v2.1.0 commit b3c95cd0. The true latest
(a935d8b3d) is not usable yet: its new "sparse initial memory snapshot and GPU
Merkle build" asserts on DEFERRAL_AS being touched with num_cells=0 during the
bundle root/SNARK stage, because the SDK's compute_root_proof_heights builds a
deferral=None root config whose apply_optimizations zeroes DEFERRAL_AS. b3c95cd0
is the newest commit that passes the full GPU suite.

Changes needed for this range of develop-v2.1.0:

- Add patches/openvm-mem override (via [patch] on the openvm git source).
  Upstream openvm-mem copy_forward/copy_backward use 64-byte aggregate copies
  (load::<64>/store::<64>) that LLVM lowers back into memmove calls, making
  memmove recurse until the guest stack wraps ("upper 4 bytes must be zero").
  The override does block copies with 8x u64 loads-then-stores.
- Upstream restored byte-sized user public values (1 byte per cell). Update
  verify_proof, pi_hash_to_public_values, and aggregated_pi_hashes in
  batch/bundle circuits to match, and drop the now-obsolete
  patch_verifier_for_u16_public_values workaround.
- setup.rs: VmExe gained cfg_block_starts; default it in the old-format
  fallback path.
- Rebuild guest assets, commitments, and EVM verifier.

Verified on GPU: test-execute-chunk, test-single-chunk, test-e2e-bundle all pass.
Includes upstream fix 46709d24 (#3118) for the DEFERRAL_AS root-keygen
leaf-count assert that blocked test-e2e-bundle, plus #3112 sparse memory
snapshot and #3109 field-independent instructions (VmExe/Program/
Instruction are now non-generic; app.vmexe format changed).

- adapt host code to non-generic VmExe; drop legacy exe format shim
- rebuild all guest assets and the EVM verifier
- mount host SRS params in build-guest.sh for local verifier generation
- update AGENTS.md (fix landed upstream; openvm-mem patch still needed)

Verified: GPU=1 make test-single-chunk / test-e2e-batch / test-e2e-bundle
The committed value was stale (built at b3c95cd0). The 29fc511e bump made
instructions field-independent (#3109), changing the vmexe format; rebuilt
guest assets produce a different app exe commitment.
…ement

The prebuilt guest toolchain cannot run on Ubuntu 22.04 (glibc 2.35).
Document the install path (~/.openvm/toolchains + rustup symlink) and an
Ubuntu 24.04 container workaround with the required mounts, plus the
OPENVM_GUEST_LOGFILE tip for capturing inner build output.
Guest-side zstd decoding in the batch circuit now uses the standard
pure-Rust ruzstd crate instead of the in-house vm-zstd decoder.
Batch e2e total cycles drop 31.4% (12,989,579 -> 8,905,075), STARK
proving time ~5.66s -> ~4.85s on RTX 4090.

The scroll envelope stores a zstd frame without the 4-byte magic
number, so the magic is prepended zero-copy before decoding.

vm-zstd is removed from the dependency graph completely: its only
remaining use was host-side test encoding in the integration crate,
where zstd_encode was a thin wrapper around da-codec's
encoder-standard. Depend on encoder-standard directly (same locked
commit, byte-identical output) and inline the wrapper.

Cargo.lock edited by hand (adds ruzstd 0.9.0 + twox-hash 2.1.4,
removes vm-zstd and orphaned bitstream-io/strum 0.25/strum_macros
0.25/heck 0.4.1) and validated with cargo metadata --locked to avoid
a global re-resolve bumping revm.
Optimizations (driven by new per-function cycle profiles):

- batch: 8,905,075 -> 5,397,474 cycles (-39.4%); STARK prove 4.7-4.9s ->
  4.44s on RTX 4090.
  * BatchWitness.blob_bytes: serde helper that decodes bincode byte arrays
    in one shot (length prefix + bulk copy) instead of element-by-element
    (same wire format). Was 26% of batch cycles.
  * BlobPolynomial::new: pack 31-byte coefficients with chunked copies
    instead of a byte-at-a-time loop. Was 17%.
  * builder/v7: borrow witness blob bytes when already padded instead of
    copying into a fresh 126KB buffer.
- bundle: 61,613 -> 18,200 cycles (-70.5%): link openvm-keccak256 (provides
  the native_keccak256 extern) and enable alloy-primitives/native-keccak,
  mirroring batch-circuit. Previously bundle guest fell back to software
  tiny-keccak (63% of its cycles in keccakf).
- chunk: profiled but unchanged this round; hotspots are upstream
  (risc0-ethereum-trie node RLP decode ~30%, memcpy 15%, revm bytecode
  analysis ~6-11%, interpreter ops). See AGENTS.md.

Profiling infrastructure:
- New perf-metrics feature chain (build-guest/prover/integration) wiring
  openvm-sdk/perf-metrics: guests built with the feature carry fn_bounds +
  a demangled guest.symbols table (build-guest sets GUEST_SYMBOLS_PATH and
  inserts a synthetic bound for entry PCs to avoid an openvm unwrap panic).
- scroll-zkvm-prover installs a DebuggingRecorder when PROFILE_METRICS_DIR
  is set and dumps per-proof counter deltas as metrics JSON after every
  proof (gen_proof_stark / gen_proof_snark).
- scripts/profile_top.py: aggregates the JSON into top functions / spans.
- AGENTS.md: profiling how-to + the native_keccak256 link failure pattern.

Cargo.lock hand-edited (metrics/metrics-util into prover deps, bundle-circuit
keccak dep swap) and validated with cargo metadata --locked.
…t paths

Two local patch crates (see AGENTS.md 'Local patch crates'):

- patches/risc0-ethereum-trie: hand-written MPT node parser replacing the
  alloy-rlp PayloadView based decoder (no per-list Vec alloc, single-copy
  compact-path decode), plus an inline fast path for 33-byte digest children.
  Per chunk the witness MPTs contain ~11.5k real nodes but ~111k digest
  children, so skipping the generic recursion for digests is the biggest win.
- patches/openvm-keccak256-guest: native_xorin stages unaligned input in an
  aligned zero-padded stack buffer instead of heap AlignedBuf round-trips
  (27% of the 87k absorbs per chunk take it).

Also keeps an execute-path profiling hook: tester_execute honors
PROFILE_METRICS_DIR under the perf-metrics feature, and profile_dump is pub.
AGENTS.md documents that the GPU-prove replay profile truncates after ~26% of
the execution (use a CPU prove for a full-execution profile).

chunk circuit (GalileoV2 preset, 6 blocks / 630 txs / 35.2M gas):
  cycles 202,969,694 -> 178,400,161 (-12.1%)
  e2e STARK prove 44.15s -> 41.40s (-6.2%, RTX 4090)
batch circuit: 5,397,474 -> 5,394,332 cycles (keccak patch only)
pi hashes unchanged; test_execute + e2e chunk/batch/bundle all pass;
risc0-ethereum-trie unit tests (17) pass; jumpdest analysis was fuzzed
against revm's analyze_legacy for equivalence during development.
Reverts the two fork patches from 430b7ac (risc0-ethereum-trie MPT decoder,
openvm-keccak256-guest xorin staging). The measured win (chunk cycles
-12.1%, e2e prove -6.2%) was judged not worth carrying forked dependencies.

Kept, documented in AGENTS.md ('Cycle-optimization experiments'):
- the measured per-patch numbers and the full-execution bottleneck profile
  (revm interpreter ~50%+, keccak cells ~32%, memory-merkle ~23%)
- rejected directions: SWAR jumpdest scan (83% of words contain a PUSH byte),
  witness-code dedup (already done host-side), keccak-count reduction
  (proof-model-inherent), revm-bytecode patching (path deps inside git repo)
- methodology: GPU prove profiles truncate after ~26% of execution (use a CPU
  prove for full profiles); Cargo.lock discipline for [patch] edits
The execute-path PROFILE_METRICS_DIR hook in tester_execute stays.

Guests rebuilt clean: commitments match 3e1f42e, chunk cycles back to
202,969,694, e2e chunk proves and verifies (43.89s on RTX 4090).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

crate-batch-circuit Updates to the guest program batch-circuit crate-build-guest Updates to building of guest programs crate-bundle-circuit Updates to the guest grogram bundle-circuit crate-chunk-circuit Updates to the guest program chunk-circuit crate-circuits Any update made to the circuits, i.e. commitments reflect a change crate-integration Updates to the integration crate crate-prover Updates to the prover crate crate-verifier Updates to the verifier crate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant