Skip to content

Upgrade EthProofs to Ziren 2.0 and integrate the Fleet app worker - #23

Merged
eigmax merged 35 commits into
statelessfrom
chore/ziren-v2-stateless
Oct 21, 2026
Merged

eigmax merged 35 commits into
statelessfrom
chore/ziren-v2-stateless

Conversation

@eigmax

@eigmax eigmax commented Oct 10, 2026 •

Copy link
Copy Markdown
Member

Upgrade the EthProofs host and guest to the matching Ziren 2.0 graph and let Fleet run the complete EthProofs pipeline beside a dedicated local GPU server. This branch is based on stateless; GOAT changes remain in Fleet's separate compatibility path.

  • Lock host/guest Ziren to 0dd65a15, accept structured or RLP-encoded witness headers, preserve untouched storage roots and remove empty accounts. Missing non-empty authenticated storage remains an error. When the execution witness omits bytecode, fetch it at the parent block, verify its hash against the authenticated account, cache it and export it into the guest input.
  • Add the integrated worker with persistent, checksummed prepared inputs, committed proof/public-value outputs, an execution cursor and a retryable reporting outbox. Proof failures retain the same input and cursor for restart.
  • Keep GPU proving serial. Sequential mode prepares each successive block through a bounded queue and retries that block on witness failure. Optional latest-head mode supports a bounded preparation pool and newest-ready selection, including retry while the witness RPC catches up; production currently runs sequential mode.
  • Acknowledge HTTP 409 duplicates only after authenticated cluster/block lookup and exact downloaded proof-byte verification. App-owned outputs and reporting avoid control-host payload transfers.

Validation: 11 worker tests passed, including persistence/recovery, bounded concurrency, out-of-order readiness, same-head retry and duplicate verification. Earlier correctness checks passed 15 trie, three guest storage and two RPC format tests. Release packaging and real local GPU proofs passed with the immutable image resolved from ghcr.io/projectzkm/ziren-gpu:latest on 2026-10-11.

Fleet pins source 85a0c17. The validated guest has SHA-256 334b45b88d6c60e3354e983a5b26ef39b18feee65da828f277a93e646c78c73b, built from fd9589c; subsequent worker-only changes retain that guest identity. The matching GPU image digest is sha256:d4b8ef78d59935d024c034f11f28c26718a1890181f42be2954f31b74e252655.

Production now proves every successive block from its saved cursor with --block-interval 1 --prepare-concurrency 1 --prefetch-depth 1, without --latest-block or nonzero lag skipping. After draining 26,166,879, it published 81 consecutive blocks from 26,166,880 through 26,166,960 on four GPUs and 48 CPUs. Their checksums passed, a downloaded production proof matched local bytes, and the outbox was empty. Historical gaps made under the earlier latest-head policy are not backfilled by this change. The legacy EthProofs client and endpoint are stopped; GOAT is unchanged.

The initial worker is machine-pinned and does not automatically transfer its state or rewind already-published proofs after deep reorgs. Missing bytecode is recovered with hash verification; other incomplete witness data is retried for the same block and still requires diagnosis if persistent.

Bytecode regression validation: all four RPC DB tests pass, including parent-block lookup, cache/export and rejection of mismatched code. Captured block 26,167,642 now passes host execution, state-root validation and native guest verification with 349 code entries (the original witness supplied 348). The release worker builds with the existing guest ELF and GPU image.

Enable reqwest gzip response decoding in the host RPC provider to reduce execution-witness transfer size. Plain JSON responses remain supported. The locked release worker builds on ant-5090-2; the actual provider advertises gzip and passes gzip/plain-response transport checks and a live witness decode. The binary embeds the unchanged registered guest ELF byte for byte.

@eigmax eigmax changed the title chore: upgrade ziren to v2.0 Upgrade EthProofs to Ziren 2.0 and integrate the Fleet app worker Oct 11, 2026
@eigmax
eigmax changed the base branch from stateless to main October 11, 2026 02:45
@eigmax
eigmax changed the base branch from main to stateless October 11, 2026 03:05
…syscalls) (#26)

* Prepare consecutive EthProofs blocks in parallel

* guest: the optimised guest line in the Ziren 2.0 EthProofs worker

The Fleet worker (4849354, chore/ziren-v2-stateless + fix/ethproofs-consecutive)
forked from the guest optimisation line at 9215aa6 and shipped the older guest:
no in-guest JUMPDEST table (the host's revm JumpTable was trusted under a code
hash that covers only the code bytes), no zkVM syscalls for 256-bit arithmetic
and the curves, no arena tries. This squashes perf/guest-hashed-key-memo (7147f4e:
feat/guest-syscalls 4a15fee plus the trie-key memo and the checked logs bloom).

Resolution:
- bin/eth-proofs, the root Cargo.toml and Cargo.lock: the worker's. The worker
  keeps the git-locked Ziren 2.0 graph; the opt line's sibling-checkout [patch]
  section is dropped.
- Guest, mpt and the witness RPC db: the opt line's. The worker's
  2c0245a (preserve untouched storage roots, remove empty accounts) was already
  in ArenaState::update; its 41317cd (omitted storage of an absent account or
  an authenticated empty storage root reads zero, any other missing storage
  trie is an error) is now ArenaState::storage, with its three tests.
  a75cb33 (verified bytecode recovery) is the opt line's complete_account_code;
  the duplicated structured-header decoder is kept once.
- bin/guest keeps the opt line's graph (precompile forks); its zkm-zkvm/zkm-lib
  [patch] points at the sibling Ziren checkout, whose guest-side crates
  (crates/zkvm, crates/build) are identical to 0dd65a15 and 31f6e8eb.

Validation:
- cargo test -p mpt: 24 passed (the arena storage rule and the update rule).
- host (this tree) fetched and executed 26184581-26184583 natively: 278.70M,
  269.57M, 52.72M cycles, block hashes as the chain's.
- GPU, one card through Fleet (image e786dd = Ziren 31f6e8eb), guest
  941629f6: 53.73/53.40/18.01 s, every proof verified against a 31f6e8eb
  client, public values identical to the deployed guest's
  (334b45b8: 73.97/73.64/20.61 s on the same blocks, -24.5% overall).

* perf(guest): bind the chain to mainnet, gate the precompile tracker

The proof commits only the block hash, so the chain spec and the
beneficiary override in the input came from the prover unchecked. The
guest now accepts mainnet inputs only, with no custom beneficiary.

The cycle-tracker wrapper around every precompile call turned the
precompile set into a map probed on each call. It is now behind the
precompile-tracking feature, for profiling builds.

Measured on the executor (blocks 26184948 / 26184949, same committed
hashes): cycles -0.19% / -0.28%, main-trace area -0.11% / -0.16%.

* perf(guest): walk the JUMPDEST map in assembly on the zkVM

The guest derives every executed code's jump table itself, a walk over
~3 M opcodes per mainnet block. Compiled, the walk is nine instructions
per opcode, two of them nops in branch delay slots. jumpdest.s fills the
slots (the cursor advance, and the next opcode's load, which reads at
most 32 bytes into the code's zero padding): six per opcode. Off the
zkVM the Rust walk stays.

Checked in the executor against the Rust walk on every code of two
mainnet blocks and 2,000 random codes. Measured (blocks 26184948 /
26184949, same committed hashes): cycles -1.39% / -1.79%, main-trace
area -0.80% / -1.00%.

* perf(guest): revm fork with cheaper dispatch and jumps

Moves the guest to the fork's patch-31.0.2-mips32-dispatch branch, which
adds to the 32-bit fast paths: static gas charged on the low word of the
remaining gas, JUMPDEST folded into the taken jump that lands on it, and
PUSH2 + JUMP / JUMPI run as one instruction.

Measured on the executor (blocks 26184948 / 26184949, same committed
hashes): cycles -3.20% / -3.44%, main-trace area -2.06% / -2.16%.

* deps: Ziren from perf/shamir-msm

Every Ziren dependency now names the perf/shamir-msm branch (Ziren
#562: Shamir's trick in the zkVM lib's two-point MSM, which ECDSA
recovery runs per transaction), and the guest's comment says the Ziren
checkout next to this repo, which its zkvm crates come from, is to be
on that branch.

The precompile patches still declare Ziren unbranched, and cargo cannot
redirect a git source to another branch of it, so the lockfile also
keeps their main-branch zkm-lib, zkm-primitives and zkm-zkvm. Those
edges exist only for the zkVM target, where the guest's path patch
replaces both with the one checkout. Back to main when #562 lands.

Measured on the executor (blocks 26184948 / 26184949, same committed
hashes): main-trace area -1.83% / -1.71%, cycles -1.05% / -1.00%.

* deps: Ziren from perf/glv-msm, revm compare + PUSH2 + JUMPI fusion

Ziren moves to perf/glv-msm (Ziren #563, stacked on #562): the zkVM
lib's secp256k1 two-point MSM uses the GLV endomorphism, about half the
doublings and two thirds of the additions per signature recovery, each a
precompile call. The guest's revm fork moves to 2a9844a0 on
patch-31.0.2-mips32-dispatch (ziren-patches/revm#4): ISZERO / EQ / LT /
GT + PUSH2 + JUMPI run as one instruction, and the stack pushes in
place. The lock also picks up the bn patch's newer branch tip, whose
only change is its zkm-lib dependency losing a pinned tag; the guest
path-patches zkm-lib, so its code is unchanged.

Measured on the executor (blocks 26184948 / 26184949, same committed
hashes) against the previous commit: cycles +0.46% / +0.34%, main-trace
cells -0.23% / -0.26%. On one GPU, with every proof verified, proving
time is -1.4% / -5.6% (GLV alone -2.5% / -5.0%): a secp256k1 precompile
call costs about 30 us there, far more than its cells suggest.

* deps: Ziren from perf/shamir-msm (Ziren #562)

The Ziren optimizations are one pull request now, #562 on
perf/shamir-msm, so every Ziren dependency names that branch. The lock
stays at 8a9ab4fe, the GLV commit this guest was built and measured
with: the branch goes on to change the keccak AIR, which the client
must not pick up before the GPU prover does. The guest ELF is
unchanged (766ff6ce).
@eigmax
eigmax merged commit eee74bc into stateless Oct 21, 2026
@eigmax
eigmax deleted the chore/ziren-v2-stateless branch October 21, 2026 03:39
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.

3 participants