diff --git a/.gitignore b/.gitignore index 8fd34cc2d5..24c0cf6e2e 100644 --- a/.gitignore +++ b/.gitignore @@ -33,3 +33,5 @@ target zkvm-prover/*.json .work/ rollup/tests.test +local-secrets.md +tmp/ diff --git a/AGENTS.md b/AGENTS.md index 449aecbdc8..94c4f539ad 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -2,118 +2,91 @@ ## Quick Orientation -This repository is a **mixed Rust + Go monorepo** for the Scroll ZK Rollup. The two most important components for proving-related work are: +Mixed **Rust + Go** monorepo for the Scroll ZK Rollup. Key components for proving work: -- **Coordinator** (`coordinator/`) — Go service that schedules proving tasks and verifies proofs. -- **Prover** (`crates/prover-bin/`) — Rust binary that generates ZK proofs using OpenVM. -- **Shared library** (`crates/libzkp/`, `crates/libzkp_c/`) — Rust proof logic consumed by both prover and coordinator (via CGO). +- **Coordinator** (`coordinator/`) — Go service scheduling proving tasks and verifying proofs +- **Prover** (`crates/prover-bin/`) — Rust binary generating ZK proofs via OpenVM +- **Shared library** (`crates/libzkp/`, `crates/libzkp_c/`) — proof logic consumed by both (CGO) -For a detailed architecture overview, see [`docs/prover-coordinator-overview.md`](docs/prover-coordinator-overview.md). +Architecture overview: [`docs/prover-coordinator-overview.md`](docs/prover-coordinator-overview.md). -## When You Are Working On an OpenVM / zkvm-prover Upgrade +## Testing Workflows (pick the right one) -Follow the structured testing guide in [`docs/testing/openvm-upgrade-testing-guide.md`](docs/testing/openvm-upgrade-testing-guide.md). It covers five verification levels: +| Workflow | When | Entry point | +|---|---|---| +| Upgrade testing ladder (build → unit → artifact → E2E → docker) | after OpenVM / zkvm-prover upgrades | [`docs/testing/openvm-upgrade-testing-guide.md`](docs/testing/openvm-upgrade-testing-guide.md) | +| **Shadow follow mode** — fork mainnet, follow live bundle production (default acceptance test) | prover/guest changes | [`tests/shadow-testing/follow/GUIDE.md`](tests/shadow-testing/follow/GUIDE.md) | +| **Shadow canary parallel-upgrade** — old/new stacks finalize side by side, with rollback drill | pre-upgrade gate (cheap, no old-stack build) | follow/GUIDE.md "Canary Parallel-Upgrade Test" | +| **Shadow hard-switch upgrade** — production-cutover rehearsal (in-flight task reset) | mandatory for major upgrades | follow/GUIDE.md "Mid-Run Upgrade Test" | +| **Shadow snapshot replay** — fixed historical bundle range | incident reproduction, single-bundle debug, Sepolia | [`tests/shadow-testing/snapshot/GUIDE.md`](tests/shadow-testing/snapshot/GUIDE.md) | +| Local E2E (no fork) | quick pipeline sanity | [`tests/prover-e2e/README.md`](tests/prover-e2e/README.md) | -1. Compilation & static checks -2. Unit tests -3. Artifact builds -4. End-to-end proving -5. Docker image builds +Mode chooser + commands: [`tests/shadow-testing/README.md`](tests/shadow-testing/README.md). -## Useful Commands - -```bash -# Rust formatting / linting -cargo fmt --all -- --check -cargo clippy --all-features --all-targets -- -D warnings -cargo check --all-features - -# Build shared library for coordinator -cargo build --release -p libzkp-c +## Non-Negotiable Rules (details behind each link) -# Build prover (CPU) -cd zkvm-prover && make prover_cpu +- **Anvil forks Ethereum L1, never Scroll L2** (ScrollChain proxy `0xa13B…E556` is on ETH mainnet; verify `eth_chainId == 1`). — COMMON Trap 2 +- **L2 RPC must support `debug_executionWitness`** (internal proxies only; `rpc.scroll.io` does not work). — COMMON Trap 3 +- **Version-sensitive facts** (S3 prefixes, digest encoding, codec block thresholds, production stack identity) live in ONE place: [`tests/shadow-testing/docs/CURRENT-STACK.md`](tests/shadow-testing/docs/CURRENT-STACK.md). Never hard-code them elsewhere. +- **Verify the production zk stack before upgrade tests** — never assume the current checkout == production (follow/GUIDE "Determining the Production zk Stack"). — Trap 31 +- **Querying the production RDS**: partial-index and `count(*)` rules in [`tests/shadow-testing/docs/rds-query-rules.md`](tests/shadow-testing/docs/rds-query-rules.md) — violations cost real money. +- **Stop test stacks when done** (`make follow-stop`) — an idle stack polls RDS forever. -# Build prover (GPU) -cd zkvm-prover && make prover - -# Build coordinator API -cd coordinator && make coordinator_api - -# Coordinator unit tests (needs libzkp.so) -cd coordinator && make test +## Useful Commands -# E2E test setup -cd tests/prover-e2e -ln -snf conf # e.g., sepolia-galileoV2 -make all -make coordinator_setup +```bash +cargo fmt --all -- --check && cargo clippy --all-features --all-targets -- -D warnings +cargo build --release -p libzkp-c # shared lib for coordinator (CGO) +make -C zkvm-prover prover # GPU prover (prover_cpu / prover_halo2gpu variants) +make -C coordinator coordinator_api coordinator_cron +make -C coordinator test # unit tests (needs libzkp.so) +cd tests/prover-e2e && ln -snf mainnet-galileoV2 conf && make all && make coordinator_setup ``` ## Directory Guide | Directory | Purpose | |-----------|---------| -| `crates/libzkp` | Core Rust proving/verification library | -| `crates/libzkp_c` | C FFI bindings for `libzkp` | +| `crates/libzkp`, `crates/libzkp_c` | Core proving/verification library + C FFI | | `crates/prover-bin` | Prover binary (`prover`) | | `coordinator/` | Go coordinator service | -| `rollup/` | Go rollup services (produces tasks for coordinator) | -| `tests/prover-e2e/` | E2E test harness for coordinator + prover | +| `rollup/` | Go rollup services (task production, relayer) | +| `tests/shadow-testing/` | Shadow fork/follow/canary/snapshot harness (start at its README) | +| `tests/prover-e2e/` | Local E2E harness (coordinator + prover, no fork) | | `tests/integration-test/` | General integration tests | -| `zkvm-prover/` | Build scripts and runtime config for the prover binary | -| `build/dockerfiles/` | Dockerfiles for production images | +| `zkvm-prover/` | Prover build scripts + runtime config | +| `build/dockerfiles/` | Production Dockerfiles | -## Troubleshooting Common E2E Test Issues +## Agent Discipline: Research Before Experimentation -### Port Conflicts (Shared Servers) -- System PostgreSQL often occupies port 5432. If the default `DB_PORT=5432` conflicts with a system instance, edit `.env` to use an alternative (e.g., `5433`) and run `make gen-config` to regenerate all configs. -- Kill stale coordinator processes before restarting: `pkill -f coordinator_api`. +> **Rule**: When encountering a problem that is **non-trivial**, **time-consuming**, or **has failed more than once**, search existing documentation before attempting new fixes. +> +> 1. Read the relevant markdown in the task directory (e.g., `tests/shadow-testing/docs/*.md`). +> 2. Search for similar error messages, selectors, or symptoms in codebase and docs — start from the **trap index**: [`tests/shadow-testing/docs/TROUBLESHOOTING.md`](tests/shadow-testing/docs/TROUBLESHOOTING.md) (56 numbered traps with symptom tables). +> 3. Only after confirming the issue is **not documented** should you design a new experiment. +> +> **Why**: this repo documents its pitfalls extensively. Blind experimentation repeats solved mistakes. When you discover a new trap or workaround, **write it back** (see the documentation conventions in `tests/shadow-testing/README.md`). -### Stale Docker Containers -- After changing `docker-compose.yml`, old containers may persist with stale port mappings. Always use `docker rm -f ` before `docker compose up`. -- The E2E container is named `local_postgres`. Verify the port mapping with `docker port local_postgres`. - -### Solc Version -- The project requires **solc ≥ 0.8.24** (for `--evm-version cancun`). System-installed solc is often older. -- Workaround: download `solc-static-linux` v0.8.24 to `/tmp/solc` and prepend `/tmp` to PATH. - -### goose Migration Tool -- The E2E `setup_db` step requires `goose`. Install with: `go install github.com/pressly/goose/v3/cmd/goose@latest`. -- Ensure `$GOPATH/bin` (typically `~/go/bin`) is in PATH. - -### Config Template Placeholders -- Some config templates contain literal placeholder strings (e.g., `""`). Always verify the `l2geth.endpoint` field points to a reachable RPC before launching the coordinator. -- A bad endpoint causes the coordinator to panic at startup during `InitL2geth`. - -### validium_mode Consistency -- The E2E config (`tests/prover-e2e/*/config.json`) and coordinator config (`coordinator/build/bin/conf/config.json`) must agree on `validium_mode`. Mismatch causes "invalid data length for DABatchV7" errors. -- For mainnet testing: set `validium_mode: false`. -- For cloak / validium testing: set `validium_mode: true` and ensure `sequencer.decryption_key` is provided. - -### Fork & Block Range Selection -- Blocks must be post-fork to match the configured codec version. For GalileoV2 (codec V10) on mainnet, use blocks ≥ 33,750,000. Older blocks (e.g., 26,653,680) are Galileo (codec V9) and will fail with "mismatched post-state root". -- To verify fork compatibility: check `codec_version` in the E2E config and ensure `SCROLL_FORK_NAME` matches the coordinator's verifier fork list. - -### S3 Asset URLs -- The prover config `base_url` must match the actual S3 object path. Verify with `curl -sI` before running. -- The coordinator downloads **verifier** assets from `v0.X.X/verifier/`; the prover downloads **circuit** assets from `///`. -- If you see HTTP 403 from S3, check whether the URL contains a `releases/` segment that shouldn't be there. +## Coordination with Humans -### Multiple Coordinator Instances -- Running `make coordinator_setup` rebuilds the binary but does not stop running instances. If the old instance holds port 8390, the new one fails with `bind: address already in use`. -- Always check with `ss -tlnp | grep 8390` before launching. +- **Code / logic issues**: reason independently and propose fixes. +- **Environment / secrets issues** (DB passwords, RPC endpoints, cloud credentials, sudo): ask the human and wait. Do not time out and make unilateral decisions. -## Coordination with Humans +## Secrets & Credentials -- **Code / logic issues**: agents should reason independently and propose fixes. -- **Environment / secrets issues** (database passwords, RPC endpoints, cloud credentials, sudo access): ask the human and wait for a response. Do not time out and make unilateral decisions. +All local-development secrets are in [`local-secrets.md`](local-secrets.md) (git-ignored). Before any shadow/E2E test, cross-reference it; if a secret is missing, **ask a human** — never invent URLs or credentials. Categories inside: RPC endpoints (ETH L1 / Scroll L2), DB DSNs (shadow / Sepolia / mainnet RDS tunnel), contract addresses per network, sender EOA keys, S3 base URLs. ## Documentation Index -| Document | What It Covers | -|----------|----------------| -| [`docs/prover-coordinator-overview.md`](docs/prover-coordinator-overview.md) | Architecture, data flow, component relationships, common operations | -| [`docs/testing/openvm-upgrade-testing-guide.md`](docs/testing/openvm-upgrade-testing-guide.md) | Step-by-step testing checklist after OpenVM / zkvm-prover upgrades | -| [`docs/testing/docker-compose-e2e-guide.md`](docs/testing/docker-compose-e2e-guide.md) | Production-like E2E testing with Docker Compose + Coordinator Proxy | -| [`docs/testing_reports/openvm-v1.6.0-guest-v0.8.0-May19.md`](docs/testing_reports/openvm-v1.6.0-guest-v0.8.0-May19.md) | Test report for PR #1783 (OpenVM 1.6.0, guest v0.8.0) | +| Document | Covers | +|----------|--------| +| [`docs/prover-coordinator-overview.md`](docs/prover-coordinator-overview.md) | Architecture, data flow, common operations | +| [`docs/testing/openvm-upgrade-testing-guide.md`](docs/testing/openvm-upgrade-testing-guide.md) | Five-level upgrade verification ladder | +| [`tests/shadow-testing/README.md`](tests/shadow-testing/README.md) | Mode chooser + documentation conventions | +| [`tests/shadow-testing/docs/TROUBLESHOOTING.md`](tests/shadow-testing/docs/TROUBLESHOOTING.md) | **Trap index** (all 56 traps → per-file locations) | +| [`tests/shadow-testing/docs/COMMON-TROUBLESHOOTING.md`](tests/shadow-testing/docs/COMMON-TROUBLESHOOTING.md) | Mode-independent traps, pre-flight ritual, checklists, symptom table | +| `tests/shadow-testing/{follow,snapshot}/GUIDE.md` + `TROUBLESHOOTING.md` | Per-mode runbooks and traps | +| [`tests/shadow-testing/docs/CURRENT-STACK.md`](tests/shadow-testing/docs/CURRENT-STACK.md) | Dated version-sensitive facts (S3, digests, thresholds, production identity) | +| [`tests/shadow-testing/docs/rds-query-rules.md`](tests/shadow-testing/docs/rds-query-rules.md) | Production RDS query discipline | +| [`docs/testing/single-chunk-reproving.md`](docs/testing/single-chunk-reproving.md) | Re-proving one mainnet chunk | +| `docs/testing_reports/*.md` | Dated test reports: [canary 2026-09-11](docs/testing_reports/canary-parallel-upgrade-2026-09-11.md) · [canary docker 2026-08-31](docs/testing_reports/canary-parallel-upgrade-docker-2026-08-31.md) · [canary 2026-08-25](docs/testing_reports/canary-parallel-upgrade-2026-08-25.md) · [snapshot early experiments](docs/testing_reports/snapshot-early-dryrun-and-relayer-tests.md) · [OpenVM 1.6.0 / guest v0.8.0](docs/testing_reports/openvm-v1.6.0-guest-v0.8.0-May19.md) | diff --git a/Cargo.lock b/Cargo.lock index a397bc5f7d..e47854b645 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -81,7 +81,7 @@ version = "0.9.0-rc.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7e713c57c2a2b19159e7be83b9194600d7e8eb3b7c2cd67e671adf47ce189a05" dependencies = [ - "cfg-if", + "cfg-if 1.0.4", "cipher", "cpufeatures 0.2.17", ] @@ -106,7 +106,8 @@ version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" dependencies = [ - "cfg-if", + "cfg-if 1.0.4", + "getrandom 0.3.4", "once_cell", "version_check", "zerocopy", @@ -135,7 +136,7 @@ checksum = "9f5bedd6a59a2bd3a2f1cb7ff488549a2004302edca4df4d578bf0a814888615" dependencies = [ "alloy-consensus", "alloy-core", - "alloy-eips 1.8.3", + "alloy-eips", "alloy-json-rpc", "alloy-network", "alloy-provider", @@ -163,10 +164,10 @@ version = "1.0.41" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9b151e38e42f1586a01369ec52a6934702731d07e8509a7307331b09f6c46dc" dependencies = [ - "alloy-eips 1.8.3", + "alloy-eips", "alloy-primitives", "alloy-rlp", - "alloy-serde 1.8.3", + "alloy-serde", "alloy-trie 0.9.5", "alloy-tx-macros", "auto_impl", @@ -190,10 +191,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e2d5e8668ef6215efdb7dcca6f22277b4e483a5650e05f5de22b2350971f4b8" dependencies = [ "alloy-consensus", - "alloy-eips 1.8.3", + "alloy-eips", "alloy-primitives", "alloy-rlp", - "alloy-serde 1.8.3", + "alloy-serde", "serde", ] @@ -260,26 +261,6 @@ dependencies = [ "thiserror 2.0.18", ] -[[package]] -name = "alloy-eips" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "609515c1955b33af3d78d26357540f68c5551a90ef58fd53def04f2aa074ec43" -dependencies = [ - "alloy-eip2124", - "alloy-eip2930", - "alloy-eip7702", - "alloy-primitives", - "alloy-rlp", - "alloy-serde 0.14.0", - "auto_impl", - "c-kzg", - "derive_more 2.1.1", - "either", - "serde", - "sha2 0.10.9", -] - [[package]] name = "alloy-eips" version = "1.8.3" @@ -292,7 +273,7 @@ dependencies = [ "alloy-eip7928", "alloy-primitives", "alloy-rlp", - "alloy-serde 1.8.3", + "alloy-serde", "auto_impl", "borsh", "c-kzg", @@ -312,7 +293,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08e9e656d58027542447c1ca5aa4ca96293f09e6920c4651953b7451a7c35e4e" dependencies = [ "alloy-consensus", - "alloy-eips 1.8.3", + "alloy-eips", "alloy-hardforks", "alloy-primitives", "alloy-rpc-types-engine", @@ -333,9 +314,9 @@ version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbf9480307b09d22876efb67d30cadd9013134c21f3a17ec9f93fd7536d38024" dependencies = [ - "alloy-eips 1.8.3", + "alloy-eips", "alloy-primitives", - "alloy-serde 1.8.3", + "alloy-serde", "alloy-trie 0.9.5", "borsh", "serde", @@ -391,13 +372,13 @@ checksum = "8eaf2ae05219e73e0979cb2cf55612aafbab191d130f203079805eaf881cca58" dependencies = [ "alloy-consensus", "alloy-consensus-any", - "alloy-eips 1.8.3", + "alloy-eips", "alloy-json-rpc", "alloy-network-primitives", "alloy-primitives", "alloy-rpc-types-any", "alloy-rpc-types-eth", - "alloy-serde 1.8.3", + "alloy-serde", "alloy-signer", "alloy-sol-types", "async-trait", @@ -416,9 +397,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e58f4f345cef483eab7374f2b6056973c7419ffe8ad35e994b7a7f5d8e0c7ba4" dependencies = [ "alloy-consensus", - "alloy-eips 1.8.3", + "alloy-eips", "alloy-primitives", - "alloy-serde 1.8.3", + "alloy-serde", "serde", ] @@ -430,7 +411,7 @@ checksum = "de3b431b4e72cd8bd0ec7a50b4be18e73dab74de0dba180eef171055e5d5926e" dependencies = [ "alloy-rlp", "bytes", - "cfg-if", + "cfg-if 1.0.4", "const-hex", "derive_more 2.1.1", "foldhash 0.2.0", @@ -445,7 +426,7 @@ dependencies = [ "rapidhash", "rkyv", "ruint", - "rustc-hash 2.1.2", + "rustc-hash 2.1.3", "serde", "sha3", "tiny-keccak", @@ -459,7 +440,7 @@ checksum = "de2597751539b1cc8fe4204e5325f9a9ed83fcacfb212018dfcfa7877e76de21" dependencies = [ "alloy-chains", "alloy-consensus", - "alloy-eips 1.8.3", + "alloy-eips", "alloy-json-rpc", "alloy-network", "alloy-network-primitives", @@ -492,9 +473,9 @@ dependencies = [ [[package]] name = "alloy-rlp" -version = "0.3.15" +version = "0.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc90b1e703d3c03f4ff7f48e82dd0bc1c8211ab7d079cd836a06fcfeb06651cb" +checksum = "24671b1f62edcf0f9b62994c7bf72cd621a04a4b99f5020ece1a647b40e2f103" dependencies = [ "alloy-rlp-derive", "arrayvec", @@ -503,13 +484,13 @@ dependencies = [ [[package]] name = "alloy-rlp-derive" -version = "0.3.15" +version = "0.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f36834a5c0a2fa56e171bf256c34d70fca07d0c0031583edea1c4946b7889c9e" +checksum = "9d4311c03125e8a18296504560b9de3d75ecbd0dcda7f71e6cf2a196d57e6fba" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -543,7 +524,7 @@ checksum = "fbde0801a32d21c5f111f037bee7e22874836fba7add34ed4a6919932dd7cf23" dependencies = [ "alloy-consensus-any", "alloy-rpc-types-eth", - "alloy-serde 1.8.3", + "alloy-serde", ] [[package]] @@ -565,10 +546,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "605ec375d91073851f566a3082548af69a28dca831b27a8be7c1b4c49f5c6ca2" dependencies = [ "alloy-consensus", - "alloy-eips 1.8.3", + "alloy-eips", "alloy-primitives", "alloy-rlp", - "alloy-serde 1.8.3", + "alloy-serde", "derive_more 2.1.1", "ethereum_ssz", "ethereum_ssz_derive", @@ -584,11 +565,11 @@ checksum = "361cd87ead4ba7659bda8127902eda92d17fa7ceb18aba1676f7be10f7222487" dependencies = [ "alloy-consensus", "alloy-consensus-any", - "alloy-eips 1.8.3", + "alloy-eips", "alloy-network-primitives", "alloy-primitives", "alloy-rlp", - "alloy-serde 1.8.3", + "alloy-serde", "alloy-sol-types", "itertools 0.14.0", "serde", @@ -597,17 +578,6 @@ dependencies = [ "thiserror 2.0.18", ] -[[package]] -name = "alloy-serde" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4dba6ff08916bc0a9cbba121ce21f67c0b554c39cf174bc7b9df6c651bd3c3b" -dependencies = [ - "alloy-primitives", - "serde", - "serde_json", -] - [[package]] name = "alloy-serde" version = "1.8.3" @@ -645,7 +615,7 @@ dependencies = [ "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -662,7 +632,7 @@ dependencies = [ "proc-macro2", "quote", "sha3", - "syn 2.0.117", + "syn 2.0.118", "syn-solidity", ] @@ -678,7 +648,7 @@ dependencies = [ "macro-string", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", "syn-solidity", ] @@ -784,7 +754,7 @@ dependencies = [ "darling 0.21.3", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -857,15 +827,15 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.102" +version = "1.0.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" +checksum = "2a4385e2e34eb35d6b3efe798b9eb88096925d87726c0798709bf56d9ed84af3" [[package]] name = "ar_archive_writer" -version = "0.5.1" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7eb93bbb63b9c227414f6eb3a0adfddca591a8ce1e9b60661bb08969b87e340b" +checksum = "4087686b4b0a3427190bae57a1d9a478dbb2d40c5dc1bd6e2b6d797913bdd348" dependencies = [ "object", ] @@ -973,6 +943,23 @@ dependencies = [ "zeroize", ] +[[package]] +name = "ark-ff" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7a806ac6c8307b929df4645776290a50ee2aac754ad09d8bdf73391309e43af" +dependencies = [ + "ark-ff-asm 0.6.0", + "ark-ff-macros 0.6.0", + "ark-serialize 0.6.0", + "ark-std 0.6.0", + "digest 0.10.7", + "educe", + "num-bigint", + "num-traits", + "zeroize", +] + [[package]] name = "ark-ff-asm" version = "0.3.0" @@ -1000,7 +987,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62945a2f7e6de02a31fe400aa489f0e0f5b2502e69f95f853adb82a96c7a6b60" dependencies = [ "quote", - "syn 2.0.117", + "syn 2.0.118", +] + +[[package]] +name = "ark-ff-asm" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1479009684adc073dff49a1025d3a7065b317a9ead25aaaca38cdc70058ba8a2" +dependencies = [ + "quote", + "syn 2.0.118", ] [[package]] @@ -1038,7 +1035,20 @@ dependencies = [ "num-traits", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", +] + +[[package]] +name = "ark-ff-macros" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a0691ed21ef00ef89c1e9bda832eba493dda3ec2f8d892fb25b705f73f06bb8" +dependencies = [ + "num-bigint", + "num-traits", + "proc-macro2", + "quote", + "syn 2.0.118", ] [[package]] @@ -1112,13 +1122,26 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f4d068aaf107ebcd7dfb52bc748f8030e0fc930ac8e360146ca54c1203088f7" dependencies = [ - "ark-serialize-derive", + "ark-serialize-derive 0.5.0", "ark-std 0.5.0", "arrayvec", "digest 0.10.7", "num-bigint", ] +[[package]] +name = "ark-serialize" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a74dd304fd536fb95d0a328e72be759209cc496a9da094c5bc56e5fea4f9e86b" +dependencies = [ + "ark-serialize-derive 0.6.0", + "ark-std 0.6.0", + "digest 0.10.7", + "num-bigint", + "serde_with", +] + [[package]] name = "ark-serialize-derive" version = "0.5.0" @@ -1127,7 +1150,18 @@ checksum = "213888f660fddcca0d257e88e54ac05bca01885f258ccdf695bafd77031bb69d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", +] + +[[package]] +name = "ark-serialize-derive" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f153690697a2b91e5e1251ff98411ee5371500a111a0fd317a70e588eb300f9" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", ] [[package]] @@ -1161,6 +1195,16 @@ dependencies = [ "rand 0.8.6", ] +[[package]] +name = "ark-std" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "367c9c827ed431bff6868b7aa926e05b16eb46603cc8b6e768e4a5553fa1d155" +dependencies = [ + "num-traits", + "rand 0.8.6", +] + [[package]] name = "arrayref" version = "0.3.9" @@ -1169,9 +1213,9 @@ checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" [[package]] name = "arrayvec" -version = "0.7.6" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" +checksum = "d3fb67a6e08acf24fdeccbac2cb6ac4305825bd1f117462e0e6f2f193345ad56" dependencies = [ "serde", ] @@ -1219,7 +1263,7 @@ checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -1230,7 +1274,7 @@ checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -1239,6 +1283,17 @@ version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi 0.1.19", + "libc", + "winapi", +] + [[package]] name = "aurora-engine-modexp" version = "1.2.0" @@ -1257,14 +1312,14 @@ checksum = "ffdcb70bdbc4d478427380519163274ac86e52916e10f0a8889adf0f96d3fee7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] name = "autocfg" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" +checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53" [[package]] name = "axum" @@ -1325,7 +1380,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6" dependencies = [ "addr2line", - "cfg-if", + "cfg-if 1.0.4", "libc", "miniz_oxide", "object", @@ -1387,16 +1442,16 @@ version = "0.72.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "993776b509cfb49c750f11b8f07a46fa23e0a1386ffc01fb1e7d343efc387895" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", "cexpr", "clang-sys", "itertools 0.13.0", "proc-macro2", "quote", "regex", - "rustc-hash 2.1.2", - "shlex", - "syn 2.0.117", + "rustc-hash 2.1.3", + "shlex 1.3.0", + "syn 2.0.118", ] [[package]] @@ -1420,38 +1475,45 @@ version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0a6ed1b54d8dc333e7be604d00fa9262f4635485ffea923647b6521a5fff045d" dependencies = [ - "arrayvec", - "bitcode_derive", "bytemuck", - "glam", "serde", ] [[package]] -name = "bitcode_derive" -version = "0.6.9" +name = "bitcoin-consensus-encoding" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "238b90427dfad9da4a9abd60f3ec1cdee6b80454bde49ed37f1781dd8e9dc7f9" +checksum = "b2d6094e2a1ba3c93b5a596fe5a10d1a10c3c6e06785cde89f693a044c01aa40" dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", + "bitcoin-internals", +] + +[[package]] +name = "bitcoin-internals" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a30a22d1f112dde8e16be7b45c63645dc165cef254f835b3e1e9553e485cfa64" +dependencies = [ + "hex-conservative 0.3.2", ] [[package]] name = "bitcoin-io" -version = "0.1.4" +version = "0.1.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dee39a0ee5b4095224a0cfc6bf4cc1baf0f9624b96b367e53b66d974e51d953" +checksum = "bb5de036369d1ac59d3c1819ebc4d850f89466f5401c571a285b6ed564a4cb78" +dependencies = [ + "bitcoin-consensus-encoding", +] [[package]] name = "bitcoin_hashes" -version = "0.14.1" +version = "0.14.101" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26ec84b80c482df901772e931a9a681e26a1b9ee2302edeff23cb30328745c8b" +checksum = "bca4c7abb40c8817d77403c880988cfd484f23ab2365726afb2f798363e2c4a2" dependencies = [ "bitcoin-io", - "hex-conservative", + "hex-conservative 0.2.2", ] [[package]] @@ -1462,9 +1524,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.11.1" +version = "2.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3" +checksum = "b4388bee8683e3d04af747c73422af53102d2bd24d9eadb6cbc100baef4b43f8" dependencies = [ "serde_core", ] @@ -1477,9 +1539,9 @@ checksum = "6099cdc01846bc367c4e7dd630dc5966dccf36b652fae7a74e17b640411a91b2" [[package]] name = "bitvec" -version = "1.0.1" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +checksum = "ddcec3d12c579d40898fe0a9a358a803c23e9c52ca3c425707f81c9436211837" dependencies = [ "funty", "radium", @@ -1508,20 +1570,6 @@ dependencies = [ "constant_time_eq", ] -[[package]] -name = "blake3" -version = "1.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0aa83c34e62843d924f905e0f5c866eb1dd6545fc4d719e803d9ba6030371fce" -dependencies = [ - "arrayref", - "arrayvec", - "cc", - "cfg-if", - "constant_time_eq", - "cpufeatures 0.3.0", -] - [[package]] name = "block-buffer" version = "0.9.0" @@ -1592,9 +1640,9 @@ dependencies = [ [[package]] name = "bon" -version = "3.9.1" +version = "3.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f47dbe92550676ee653353c310dfb9cf6ba17ee70396e1f7cf0a2020ad49b2fe" +checksum = "a602c73c7b0148ec6d12af6fd5cc7a46e2eacc8878271a999abac56eed12f561" dependencies = [ "bon-macros", "rustversion", @@ -1602,9 +1650,9 @@ dependencies = [ [[package]] name = "bon-macros" -version = "3.9.1" +version = "3.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "519bd3116aeeb42d5372c29d982d16d0170d3d4a5ed85fc7dd91642ffff3c67c" +checksum = "6dee98b0db6a962de883bf5d20362dee4d7ca0d12fe39a7c6c73c844e1cd7c1f" dependencies = [ "darling 0.23.0", "ident_case", @@ -1612,14 +1660,14 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] name = "borsh" -version = "1.6.1" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfd1e3f8955a5d7de9fab72fc8373fade9fb8a703968cb200ae3dc6cf08e185a" +checksum = "2f3f6da4992df95bbcd9af42a6c7dcb994498fc9048230405f3b36ff7cd3f145" dependencies = [ "borsh-derive", "bytes", @@ -1628,15 +1676,15 @@ dependencies = [ [[package]] name = "borsh-derive" -version = "1.6.1" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfcfdc083699101d5a7965e49925975f2f55060f94f9a05e7187be95d530ca59" +checksum = "3ae8fb4fb5740e4b2c4884ff95f5f32f5e8479db1e8fd8eb49ddbe09eb09bb7c" dependencies = [ "once_cell", "proc-macro-crate 3.5.0", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -1650,9 +1698,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.20.2" +version = "3.20.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" +checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649" [[package]] name = "byte-slice-cast" @@ -1680,14 +1728,14 @@ checksum = "89385e82b5d1821d2219e0b095efa2cc1f246cbf99080f3be46a1a85c0d392d9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] name = "bytemuck" -version = "1.25.0" +version = "1.25.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec" +checksum = "d6aedf8ae72766347502cf3cb4f41cf5e9cc37d28bee90f1fdaaae15f9cf9424" [[package]] name = "byteorder" @@ -1697,18 +1745,18 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.11.1" +version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" +checksum = "fc652a48c352aef3ea3aed32080501cf3ef6ed5da78602a020c991775b0aff04" dependencies = [ "serde", ] [[package]] name = "bytesize" -version = "2.3.1" +version = "2.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bd91ee7b2422bcb158d90ef4d14f75ef67f340943fc4149891dcce8f8b972a3" +checksum = "3d7c8918969267b2932ffd5655509bbbea0833823058c378876953217f5fc50e" [[package]] name = "bzip2-sys" @@ -1722,9 +1770,9 @@ dependencies = [ [[package]] name = "c-kzg" -version = "2.1.7" +version = "2.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6648ed1e4ea8e8a1a4a2c78e1cda29a3fd500bc622899c340d8525ea9a76b24a" +checksum = "38d04308254695569fdb9bfe3bacc1c91837a670d0806605eb82d63748fbd3a6" dependencies = [ "blst", "cc", @@ -1737,9 +1785,9 @@ dependencies = [ [[package]] name = "camino" -version = "1.2.2" +version = "1.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e629a66d692cb9ff1a1c664e41771b3dcaf961985a9774c0eb0bd1b51cf60a48" +checksum = "5f2d30e4173c4026932d51d31d6b0613b1fd3014bf3f9f8943d4ba139c437ba0" dependencies = [ "serde_core", ] @@ -1769,14 +1817,14 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.62" +version = "1.2.67" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1dce859f0832a7d088c4f1119888ab94ef4b5d6795d1ce05afb7fe159d79f98" +checksum = "e17dd265a7d0f31ef544e1b20e03add05d3b45b491b633b10d67145d2acc1a38" dependencies = [ "find-msvc-tools", "jobserver", "libc", - "shlex", + "shlex 2.0.1", ] [[package]] @@ -1788,6 +1836,12 @@ dependencies = [ "nom", ] +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + [[package]] name = "cfg-if" version = "1.0.4" @@ -1800,11 +1854,22 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" +[[package]] +name = "chacha20" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d524456ba66e72eb8b115ff89e01e497f8e6d11d78b70b1aa13c0fbd97540a81" +dependencies = [ + "cfg-if 1.0.4", + "cpufeatures 0.3.0", + "rand_core 0.10.1", +] + [[package]] name = "chrono" -version = "0.4.44" +version = "0.4.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0" +checksum = "1aa79e62e7697b8e29b513a68abacf485adcd1fe8284a4316c5ae868e6633327" dependencies = [ "iana-time-zone", "num-traits", @@ -1865,7 +1930,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -1874,6 +1939,15 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" +[[package]] +name = "cobs" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa961b519f0b462e3a3b4a34b64d119eeaca1d59af726fe450bbba07a9fc0a1" +dependencies = [ + "thiserror 2.0.18", +] + [[package]] name = "color-eyre" version = "0.6.5" @@ -1936,11 +2010,11 @@ checksum = "cc14f565cf027a105f7a44ccf9e5b424348421a1d8952a8fc9d499d313107789" [[package]] name = "const-hex" -version = "1.19.0" +version = "1.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20d9a563d167a9cce0f94153382b33cb6eded6dfabff03c69ad65a28ea1514e0" +checksum = "33e2a781ebdf4467d1428dc4593067825fb646f6871475098d8577421af73558" dependencies = [ - "cfg-if", + "cfg-if 1.0.4", "cpufeatures 0.2.17", "proptest", "serde_core", @@ -2077,7 +2151,7 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" dependencies = [ - "cfg-if", + "cfg-if 1.0.4", ] [[package]] @@ -2101,18 +2175,18 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.15" +version = "0.5.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" +checksum = "d85363c37faeca707aef026efa9f3b34d077bce547e48f770770625c6013679e" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-deque" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +checksum = "5181e0de7b61eb03a81e347d6dd8797bae9da5146707b51077e2d71a54ec0ceb" dependencies = [ "crossbeam-epoch", "crossbeam-utils", @@ -2120,27 +2194,27 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.18" +version = "0.9.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +checksum = "2d6914041f254d6e9176c01941b21115dcfb7089e55135a35411081bd106ef3f" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-queue" -version = "0.3.12" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f58bbc28f91df819d0aa2a2c00cd19754769c2fad90579b3592b1c9ba7a3115" +checksum = "803d13fb3b09d88be9f4dbc29062c66b19bf7170867ceb746d2a8689bf6c7a26" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-utils" -version = "0.8.21" +version = "0.8.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" +checksum = "61803da095bee82a81bb1a452ecc25d3b2f1416d1897eb86430c6159ef717c17" [[package]] name = "crunchy" @@ -2187,7 +2261,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a2785755761f3ddc1492979ce1e48d2c00d09311c39e4466429188f3dd6501" dependencies = [ "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -2225,10 +2299,10 @@ dependencies = [ ] [[package]] -name = "cuda-runtime-sys" -version = "0.3.0-alpha.1" +name = "cuda-driver-sys" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d070b301187fee3c611e75a425cf12247b7c75c09729dbdef95cb9cb64e8c39" +checksum = "1d4c552cc0de854877d80bcd1f11db75d42be32962d72a6799b88dcca88fffbd" dependencies = [ "cuda-config", ] @@ -2280,7 +2354,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -2295,7 +2369,7 @@ dependencies = [ "quote", "serde", "strsim", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -2308,7 +2382,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -2319,7 +2393,7 @@ checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" dependencies = [ "darling_core 0.20.11", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -2330,7 +2404,7 @@ checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" dependencies = [ "darling_core 0.21.3", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -2341,7 +2415,7 @@ checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d" dependencies = [ "darling_core 0.23.0", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -2350,7 +2424,7 @@ version = "6.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6361d5c062261c78a176addb82d4c821ae42bed6089de0e12603cd25de2059c" dependencies = [ - "cfg-if", + "cfg-if 1.0.4", "crossbeam-utils", "hashbrown 0.14.5", "lock_api", @@ -2375,7 +2449,6 @@ version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" dependencies = [ - "powerfmt", "serde_core", ] @@ -2398,7 +2471,7 @@ checksum = "d150dea618e920167e5973d70ae6ece4385b7164e0d799fe7c122dd0a5d912ad" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -2409,7 +2482,7 @@ checksum = "2cdc8d50f426189eef89dac62fabfa0abb27d5cc008f25bf4156a0203325becc" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -2420,7 +2493,7 @@ checksum = "d08b3a0bcc0d079199cd476b2cae8435016ec11d1c0986c6901c5ac223041534" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -2449,7 +2522,7 @@ checksum = "cb7330aeadfbe296029522e6c40f315320aba36fc43a5b3632f3795348f3bd22" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", "unicode-xid", ] @@ -2463,7 +2536,7 @@ dependencies = [ "proc-macro2", "quote", "rustc_version 0.4.1", - "syn 2.0.117", + "syn 2.0.118", "unicode-xid", ] @@ -2490,13 +2563,13 @@ dependencies = [ [[package]] name = "displaydoc" -version = "0.2.5" +version = "0.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +checksum = "1ac70aa55017e108007fbaf5aa0f54b021c98f92ff8af59d42eda9da96e3dd4f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -2575,14 +2648,14 @@ dependencies = [ "enum-ordinalize", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] name = "either" -version = "1.15.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" +checksum = "91622ff5e7162018101f2fea40d6ebf4a78bbe5a49736a2020649edf9693679e" dependencies = [ "serde", ] @@ -2613,6 +2686,18 @@ dependencies = [ "zeroize", ] +[[package]] +name = "embedded-io" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced" + +[[package]] +name = "embedded-io" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d" + [[package]] name = "encoder-standard" version = "0.1.0" @@ -2627,7 +2712,7 @@ version = "0.8.35" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "75030f3c4f45dafd7586dd6780965a8c7e8e285a5ecb86713e63a79c5b2766f3" dependencies = [ - "cfg-if", + "cfg-if 1.0.4", ] [[package]] @@ -2638,45 +2723,46 @@ checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d" [[package]] name = "enum-ordinalize" -version = "4.3.2" +version = "4.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a1091a7bb1f8f2c4b28f1fe2cef4980ca2d410a3d727d67ecc3178c9b0800f0" +checksum = "07f808d588c10e464ea6f7d3eaed500049eff30aaac103460f61828c2d65b3eb" dependencies = [ "enum-ordinalize-derive", ] [[package]] name = "enum-ordinalize-derive" -version = "4.3.2" +version = "4.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ca9601fb2d62598ee17836250842873a413586e5d7ed88b356e38ddbb0ec631" +checksum = "42e528e2d34ba8a67a1a650b86beae8ef69fc5fdb638016f386b973226590432" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] -name = "enum_dispatch" -version = "0.3.13" +name = "enumn" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa18ce2bc66555b3218614519ac839ddb759a7d6720732f979ef8d13be147ecd" +checksum = "2f9ed6b3789237c8a0c1c505af1c7eb2c560df6186f01b098c3a1064ea532f38" dependencies = [ - "once_cell", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] -name = "enumn" -version = "0.1.14" +name = "env_logger" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f9ed6b3789237c8a0c1c505af1c7eb2c560df6186f01b098c3a1064ea532f38" +checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.117", + "atty", + "humantime", + "log", + "regex", + "termcolor", ] [[package]] @@ -2745,9 +2831,9 @@ dependencies = [ [[package]] name = "ethereum_serde_utils" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dc1355dbb41fbbd34ec28d4fb2a57d9a70c67ac3c19f6a5ca4d4a176b9e997a" +checksum = "38df44a7a271ab43835678f9215b53cc2523e4714a215da6643d83dc110245da" dependencies = [ "alloy-primitives", "hex", @@ -2780,7 +2866,7 @@ dependencies = [ "darling 0.20.11", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -2897,6 +2983,15 @@ dependencies = [ "miniz_oxide", ] +[[package]] +name = "flume" +version = "0.10.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1657b4441c3403d9f7b3409e47575237dac27b1b5726df654a6ecbf92f0f7577" +dependencies = [ + "spin 0.9.8", +] + [[package]] name = "fnv" version = "1.0.7" @@ -3011,7 +3106,7 @@ checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -3064,7 +3159,7 @@ version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "877e94aff08e743b651baaea359664321055749b398adff8740a7399af7796e7" dependencies = [ - "cfg-if", + "cfg-if 1.0.4", ] [[package]] @@ -3084,7 +3179,7 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" dependencies = [ - "cfg-if", + "cfg-if 1.0.4", "js-sys", "libc", "wasi", @@ -3097,37 +3192,35 @@ version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" dependencies = [ - "cfg-if", - "js-sys", + "cfg-if 1.0.4", "libc", "r-efi 5.3.0", "wasip2", - "wasm-bindgen", ] [[package]] name = "getrandom" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" +checksum = "300e883d756b2e4ec94e02791f39b04b522276138852cfc41d9fb7e904106099" dependencies = [ - "cfg-if", + "cfg-if 1.0.4", + "js-sys", "libc", "r-efi 6.0.0", - "wasip2", - "wasip3", + "rand_core 0.10.1", + "wasm-bindgen", ] [[package]] name = "getset" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cf0fc11e47561d47397154977bc219f4cf809b2974facc3ccb3b89e2436f912" +checksum = "6cf442baaabe4213ce7d1239afc26c039180b6456da2cededa316ae2c8a77a77" dependencies = [ - "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -3162,15 +3255,9 @@ checksum = "53010ccb100b96a67bc32c0175f0ed1426b31b655d562898e57325f81c023ac0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] -[[package]] -name = "glam" -version = "0.32.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f70749695b063ecbf6b62949ccccde2e733ec3ecbbd71d467dca4e5c6c97cca0" - [[package]] name = "glob" version = "0.3.3" @@ -3214,9 +3301,9 @@ dependencies = [ [[package]] name = "h2" -version = "0.4.14" +version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "171fefbc92fe4a4de27e0698d6a5b392d6a0e333506bc49133760b3bcf948733" +checksum = "6cb093c84e8bd9b188d4c4a8cb6579fc016968d14c99882163cd3ff402a4f155" dependencies = [ "atomic-waker", "bytes", @@ -3242,9 +3329,8 @@ dependencies = [ [[package]] name = "halo2-axiom" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0aee3f8178b78275038e5ea0e2577140056d2c4c87fccaf6777dc0a8eebe455a" +version = "0.5.2" +source = "git+https://github.com/axiom-crypto/halo2.git?tag=v0.5.2#1eed471495b64ec1edf22f0661bbc65d0e4381d5" dependencies = [ "blake2b_simd", "crossbeam", @@ -3262,14 +3348,54 @@ dependencies = [ "tracing", ] +[[package]] +name = "halo2-axiom-gpu" +version = "1.0.0" +source = "git+https://github.com/axiom-crypto/halo2-gpu.git?tag=v1.0.0#97ef2d02aa3348fc04b520c3c2562a9c13b57126" +dependencies = [ + "ahash", + "anyhow", + "ark-std 0.3.0", + "blake2b_simd", + "cfg-if 0.1.10", + "colored", + "crossbeam", + "cuda-driver-sys", + "env_logger", + "ff 0.13.1", + "git-version", + "group 0.13.0", + "halo2-axiom", + "halo2curves-axiom 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "itertools 0.11.0", + "lazy_static", + "libc", + "log", + "num-bigint", + "num-integer", + "once_cell", + "openvm-cuda-builder", + "openvm-cuda-common", + "pairing 0.23.0", + "rand 0.8.6", + "rand_core 0.6.4", + "rayon", + "rustacuda", + "rustc-hash 1.1.0", + "sha3", + "subtle", + "tracing", + "yastl", +] + [[package]] name = "halo2-base" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "678cf3adc0a39d7b4d9b82315a655201aa24a430dd1902b162c508047f56ac69" +version = "0.5.4" +source = "git+https://github.com/axiom-crypto/halo2-lib.git?tag=v0.5.4#a69fdee77f41bdd48ad658b69673dea5a0815db4" dependencies = [ "getset", "halo2-axiom", + "halo2-axiom-gpu", "itertools 0.11.0", "log", "num-bigint", @@ -3285,9 +3411,8 @@ dependencies = [ [[package]] name = "halo2-ecc" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645c00681fdd1febaf552d8814e9f5a6a142d81a1514102190da07039588b366" +version = "0.5.4" +source = "git+https://github.com/axiom-crypto/halo2-lib.git?tag=v0.5.4#a69fdee77f41bdd48ad658b69673dea5a0815db4" dependencies = [ "halo2-base", "itertools 0.11.0", @@ -3427,6 +3552,15 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + [[package]] name = "hermit-abi" version = "0.5.2" @@ -3452,10 +3586,25 @@ dependencies = [ ] [[package]] -name = "hex-literal" -version = "0.4.1" +name = "hex-conservative" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" +checksum = "830e599c2904b08f0834ee6337d8fe8f0ed4a63b5d9e7a7f49c0ffa06d08d360" +dependencies = [ + "arrayvec", +] + +[[package]] +name = "hex-literal" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fe2267d4ed49bc07b63801559be28c718ea06c4738b7a03c94df7386d2cde46" + +[[package]] +name = "hex-literal" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e712f64ec3850b98572bffac52e2c6f282b29fe6c5fa6d42334b30be438d95c1" [[package]] name = "hkdf" @@ -3477,9 +3626,9 @@ dependencies = [ [[package]] name = "http" -version = "1.4.0" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" +checksum = "6970f50e31d6fc17d3fa27329444bfa74e196cf62e95052a3f6fee181dba6425" dependencies = [ "bytes", "itoa", @@ -3520,20 +3669,29 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" +[[package]] +name = "humantime" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" +dependencies = [ + "quick-error", +] + [[package]] name = "hybrid-array" -version = "0.4.12" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9155a582abd142abc056962c29e3ce5ff2ad5469f4246b537ed42c5deba857da" +checksum = "818356c5132c1fede50f837ca96afbe78ff42413047f4abb886217845e1b6c8c" dependencies = [ "typenum", ] [[package]] name = "hyper" -version = "1.9.0" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6299f016b246a94207e63da54dbe807655bf9e00044f73ded42c3ac5305fbcca" +checksum = "55281c53a1894c864990125767da440a4e630446785086f52523b20033b74498" dependencies = [ "atomic-waker", "bytes", @@ -3714,12 +3872,6 @@ dependencies = [ "zerovec", ] -[[package]] -name = "id-arena" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" - [[package]] name = "ident_case" version = "1.0.1" @@ -3782,7 +3934,7 @@ checksum = "a0eb5a3343abf848c0984fe4604b2b105da9539376e24fc0a3b0007411ae4fd9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -3829,7 +3981,7 @@ version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" dependencies = [ - "cfg-if", + "cfg-if 1.0.4", "js-sys", "wasm-bindgen", "web-sys", @@ -3891,23 +4043,22 @@ checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" [[package]] name = "jobserver" -version = "0.1.34" +version = "0.1.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" +checksum = "1c00acbd29eabad4a2392fa0e921c874934dbbf4194312ad20f04a0ed67a3cb3" dependencies = [ - "getrandom 0.3.4", + "getrandom 0.4.3", "libc", ] [[package]] name = "js-sys" -version = "0.3.98" +version = "0.3.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67df7112613f8bfd9150013a0314e196f4800d3201ae742489d999db2f979f08" +checksum = "53b44bfcdb3f8d5837a46dae1ca9660a837176eee74a28b229bc626816589102" dependencies = [ - "cfg-if", + "cfg-if 1.0.4", "futures-util", - "once_cell", "wasm-bindgen", ] @@ -3931,7 +4082,7 @@ version = "0.13.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f6e3919bbaa2945715f0bb6d3934a173d1e9a59ac23767fbaaef277265a7411b" dependencies = [ - "cfg-if", + "cfg-if 1.0.4", "ecdsa", "elliptic-curve", "once_cell", @@ -3943,12 +4094,12 @@ dependencies = [ [[package]] name = "k256" version = "0.13.4" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" dependencies = [ "ecdsa", "elliptic-curve", "ff 0.13.1", - "hex-literal", + "hex-literal 1.1.0", "num-bigint", "once_cell", "openvm", @@ -3970,9 +4121,9 @@ dependencies = [ [[package]] name = "keccak-asm" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1766b89733097006f3a1388a02849865d6bc98c89273cb622e29fdd209922183" +checksum = "dd5dc2c0d691cbf7595cde551ced329cca99c2387c2cbc97754c5d0cd045d3ee" dependencies = [ "digest 0.10.7", "sha3-asm", @@ -4028,12 +4179,6 @@ dependencies = [ "spin 0.9.8", ] -[[package]] -name = "leb128fmt" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" - [[package]] name = "libc" version = "0.2.186" @@ -4046,7 +4191,7 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b67380fd3b2fbe7527a606e18729d21c6f3951633d0500574c4dc22d2d638b9f" dependencies = [ - "cfg-if", + "cfg-if 1.0.4", "winapi", ] @@ -4056,7 +4201,7 @@ version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" dependencies = [ - "cfg-if", + "cfg-if 1.0.4", "windows-link", ] @@ -4129,9 +4274,9 @@ dependencies = [ [[package]] name = "libz-sys" -version = "1.1.28" +version = "1.1.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc3a226e576f50782b3305c5ccf458698f92798987f551c6a02efe8276721e22" +checksum = "85bc9657773828b90eeb625adff10eeac83cc21bbfd8e23a03eaa8a33c9e28d9" dependencies = [ "cc", "pkg-config", @@ -4148,6 +4293,8 @@ dependencies = [ "c-kzg", "eyre", "git-version", + "openvm-sdk", + "openvm-stark-sdk", "regex", "sbv-core", "sbv-primitives", @@ -4199,9 +4346,9 @@ checksum = "9374ef4228402d4b7e403e5838cb880d9ee663314b0a900d5a6aabf0c213552e" [[package]] name = "log" -version = "0.4.29" +version = "0.4.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" +checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad" [[package]] name = "lru" @@ -4245,7 +4392,7 @@ checksum = "59a9dbbfc75d2688ed057456ce8a3ee3f48d12eec09229f560f3643b9f275653" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -4263,27 +4410,37 @@ version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "47e1ffaa40ddd1f3ed91f717a33c8c0ee23fff369e3aa8772b9605cc1d22f4c3" +[[package]] +name = "matrixmultiply" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06de3016e9fae57a36fd14dba131fccf49f74b40b7fbdb472f96e361ec71a08" +dependencies = [ + "autocfg", + "rawpointer", +] + [[package]] name = "maybe-rayon" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ea1f30cedd69f0a2954655f7188c6a834246d2bcf1e315e2ac40c4b24dc9519" dependencies = [ - "cfg-if", + "cfg-if 1.0.4", "rayon", ] [[package]] name = "memchr" -version = "2.8.0" +version = "2.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" +checksum = "cf8baf1c55e62ffcace7a9f06f4bd9cd3f0c4beb022d3b367256b91b87513d98" [[package]] name = "memmap2" -version = "0.9.10" +version = "0.9.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "714098028fe011992e1c3962653c96b2d578c4b4bce9036e15ff220319b1e0e3" +checksum = "d1219ed1b7f229ee7104d281dd01d6802fe28bb6e95d292942c4daacdeb798c0" dependencies = [ "libc", ] @@ -4364,9 +4521,9 @@ dependencies = [ [[package]] name = "mio" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50b7e5b27aa02a74bac8c3f23f448f8d87ff11f92d3aac1a6ed369ee08cc56c1" +checksum = "02bd0af71c67b473010cbbc60715ee815645a4dc942899111f494b4b737d6fda" dependencies = [ "libc", "wasi", @@ -4411,7 +4568,7 @@ checksum = "4568f25ccbd45ab5d5603dc34318c1ec56b117531781260002151b8530a9f931" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -4431,6 +4588,21 @@ dependencies = [ "tempfile", ] +[[package]] +name = "ndarray" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "882ed72dce9365842bf196bdeedf5055305f11fc8c03dee7bb0194a6cad34841" +dependencies = [ + "matrixmultiply", + "num-complex", + "num-integer", + "num-traits", + "portable-atomic", + "portable-atomic-util", + "rawpointer", +] + [[package]] name = "nibble_vec" version = "0.1.0" @@ -4475,9 +4647,9 @@ dependencies = [ [[package]] name = "num-bigint" -version = "0.4.6" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +checksum = "c89e69e7e0f03bea5ef08013795c25018e101932225a656383bd384495ecc367" dependencies = [ "num-integer", "num-traits", @@ -4511,11 +4683,10 @@ dependencies = [ [[package]] name = "num-iter" -version = "0.1.45" +version = "0.1.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +checksum = "c92800bd69a1eac91786bcfe9da64a897eb72911b8dc3095decbd07429e8048b" dependencies = [ - "autocfg", "num-integer", "num-traits", ] @@ -4574,7 +4745,7 @@ version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b" dependencies = [ - "hermit-abi", + "hermit-abi 0.5.2", "libc", ] @@ -4606,7 +4777,7 @@ dependencies = [ "proc-macro-crate 1.3.1", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -4618,7 +4789,16 @@ dependencies = [ "proc-macro-crate 3.5.0", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", +] + +[[package]] +name = "nvtx" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad2e855e8019f99e4b94ac33670eb4e4f570a2e044f3749a0b2c7f83b841e52c" +dependencies = [ + "cc", ] [[package]] @@ -4641,7 +4821,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0d49ff0c0d00d4a502b39df9af3a525e1efeb14b9dabb5bb83335284c1309210" dependencies = [ "alloy-rlp", - "cfg-if", + "cfg-if 1.0.4", "proptest", "ruint", "serde", @@ -4680,10 +4860,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3a501241474c3118833d6195312ae7eb7cc90bbb0d5f524cbb0b06619e49ff67" dependencies = [ "alloy-consensus", - "alloy-eips 1.8.3", + "alloy-eips", "alloy-primitives", "alloy-rlp", - "alloy-serde 1.8.3", + "alloy-serde", "derive_more 2.1.1", "serde", "serde_with", @@ -4697,7 +4877,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "726da827358a547be9f1e37c2a756b9e3729cb0350f43408164794b370cad8ae" dependencies = [ "alloy-consensus", - "alloy-eips 1.8.3", + "alloy-eips", "alloy-primitives", "alloy-rlp", "derive_more 2.1.1", @@ -4711,7 +4891,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d8f24b8cb66e4b33e6c9e508bf46b8ecafc92eadd0b93fedd306c0accb477657" dependencies = [ "alloy-consensus", - "alloy-eips 1.8.3", + "alloy-eips", "alloy-primitives", "alloy-rlp", "alloy-rpc-types-engine", @@ -4767,12 +4947,12 @@ dependencies = [ [[package]] name = "openssl" -version = "0.10.80" +version = "0.10.81" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a45fa2aa886c42762255da344f0a0d313e254066c46aad76f300c3d3da62d967" +checksum = "77823a27f0babb03091cb9ed9ef80af3b39dbc82f97e8fa530374b7dafd87a45" dependencies = [ - "bitflags 2.11.1", - "cfg-if", + "bitflags 2.13.0", + "cfg-if 1.0.4", "foreign-types", "libc", "openssl-macros", @@ -4787,7 +4967,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -4798,9 +4978,9 @@ checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" [[package]] name = "openssl-sys" -version = "0.9.116" +version = "0.9.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f28a22dc7140cda5f096e5e7724a6962ca81a7f8bfd2979f9b18c11af56318c4" +checksum = "b47e7e6bb2c38cd930d25a23b40fa52e068c10e85f3e03a7f5ba5aaca5713695" dependencies = [ "cc", "libc", @@ -4810,8 +4990,8 @@ dependencies = [ [[package]] name = "openvm" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" +version = "2.0.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" dependencies = [ "bytemuck", "getrandom 0.2.17", @@ -4825,24 +5005,25 @@ dependencies = [ [[package]] name = "openvm-algebra-circuit" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" +version = "2.0.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" dependencies = [ "blstrs", - "cfg-if", + "cfg-if 1.0.4", "derive-new 0.6.0", "derive_more 1.0.0", "eyre", "halo2curves-axiom 0.7.2 (git+https://github.com/axiom-crypto/halo2curves.git?tag=v0.7.2)", "num-bigint", "num-traits", + "once_cell", "openvm-algebra-transpiler", "openvm-circuit", "openvm-circuit-derive", "openvm-circuit-primitives", "openvm-circuit-primitives-derive", + "openvm-cpu-backend", "openvm-cuda-backend", - "openvm-cuda-builder", "openvm-cuda-common", "openvm-instructions", "openvm-mod-circuit-builder", @@ -4858,18 +5039,18 @@ dependencies = [ [[package]] name = "openvm-algebra-complex-macros" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" +version = "2.0.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" dependencies = [ "openvm-macros-common", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] name = "openvm-algebra-guest" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" +version = "2.0.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" dependencies = [ "halo2curves-axiom 0.7.2 (git+https://github.com/axiom-crypto/halo2curves.git?tag=v0.7.2)", "num-bigint", @@ -4884,20 +5065,20 @@ dependencies = [ [[package]] name = "openvm-algebra-moduli-macros" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" +version = "2.0.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" dependencies = [ "num-bigint", "num-prime", "openvm-macros-common", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] name = "openvm-algebra-transpiler" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" +version = "2.0.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" dependencies = [ "openvm-algebra-guest", "openvm-instructions", @@ -4910,10 +5091,10 @@ dependencies = [ [[package]] name = "openvm-bigint-circuit" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" +version = "2.0.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" dependencies = [ - "cfg-if", + "cfg-if 1.0.4", "derive-new 0.6.0", "derive_more 1.0.0", "openvm-bigint-transpiler", @@ -4921,6 +5102,7 @@ dependencies = [ "openvm-circuit-derive", "openvm-circuit-primitives", "openvm-circuit-primitives-derive", + "openvm-cpu-backend", "openvm-cuda-backend", "openvm-cuda-builder", "openvm-cuda-common", @@ -4936,8 +5118,8 @@ dependencies = [ [[package]] name = "openvm-bigint-guest" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" +version = "2.0.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" dependencies = [ "openvm-platform", "strum_macros 0.26.4", @@ -4945,8 +5127,8 @@ dependencies = [ [[package]] name = "openvm-bigint-transpiler" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" +version = "2.0.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" dependencies = [ "openvm-bigint-guest", "openvm-instructions", @@ -4960,8 +5142,8 @@ dependencies = [ [[package]] name = "openvm-build" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" +version = "2.0.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" dependencies = [ "cargo_metadata", "eyre", @@ -4972,17 +5154,16 @@ dependencies = [ [[package]] name = "openvm-circuit" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" +version = "2.0.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" dependencies = [ "abi_stable", "backtrace", - "cfg-if", + "bytesize", + "cfg-if 1.0.4", "dashmap", - "derivative", "derive-new 0.6.0", "derive_more 1.0.0", - "enum_dispatch", "eyre", "getset", "itertools 0.14.0", @@ -4991,6 +5172,7 @@ dependencies = [ "openvm-circuit-derive", "openvm-circuit-primitives", "openvm-circuit-primitives-derive", + "openvm-cpu-backend", "openvm-cuda-backend", "openvm-cuda-builder", "openvm-cuda-common", @@ -5001,7 +5183,7 @@ dependencies = [ "p3-baby-bear", "p3-field", "rand 0.9.4", - "rustc-hash 2.1.2", + "rustc-hash 2.1.3", "serde", "serde-big-array", "static_assertions", @@ -5011,95 +5193,144 @@ dependencies = [ [[package]] name = "openvm-circuit-derive" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" +version = "2.0.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" dependencies = [ "itertools 0.14.0", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] name = "openvm-circuit-primitives" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" +version = "2.0.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" dependencies = [ "derive-new 0.6.0", "itertools 0.14.0", "num-bigint", "num-traits", "openvm-circuit-primitives-derive", + "openvm-cpu-backend", "openvm-cuda-backend", "openvm-cuda-builder", "openvm-cuda-common", "openvm-stark-backend", "rand 0.9.4", + "struct-reflection", "tracing", ] [[package]] name = "openvm-circuit-primitives-derive" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" +version = "2.0.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" dependencies = [ "itertools 0.14.0", + "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", +] + +[[package]] +name = "openvm-codec-derive" +version = "2.0.0" +source = "git+https://github.com/openvm-org/stark-backend.git?tag=v2.0.0#16d60de724c21dcadfde7d8315a1db507e5832d7" +dependencies = [ + "proc-macro-crate 1.3.1", + "proc-macro2", + "quote", + "syn 2.0.118", ] [[package]] name = "openvm-continuations" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" +version = "2.0.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" dependencies = [ + "cfg-if 1.0.4", "derivative", + "derive-new 0.6.0", + "eyre", + "hex", + "itertools 0.14.0", + "num-bigint", "openvm-circuit", - "openvm-native-compiler", - "openvm-native-recursion", + "openvm-circuit-primitives", + "openvm-cpu-backend", + "openvm-cuda-backend", + "openvm-cuda-common", + "openvm-poseidon2-air", + "openvm-recursion-circuit", + "openvm-recursion-circuit-derive", "openvm-stark-backend", "openvm-stark-sdk", + "openvm-verify-stark-host", + "p3-air", "p3-bn254", + "p3-field", + "p3-matrix", "serde", - "static_assertions", + "tracing", +] + +[[package]] +name = "openvm-cpu-backend" +version = "2.0.0" +source = "git+https://github.com/openvm-org/stark-backend.git?tag=v2.0.0#16d60de724c21dcadfde7d8315a1db507e5832d7" +dependencies = [ + "cfg-if 1.0.4", + "derive-new 0.7.0", + "getset", + "itertools 0.14.0", + "openvm-stark-backend", + "p3-air", + "p3-baby-bear", + "p3-dft", + "p3-field", + "p3-interpolation", + "p3-matrix", + "p3-maybe-rayon", + "p3-util", + "rayon", + "rustc-hash 2.1.3", + "serde", + "thiserror 1.0.69", + "tracing", ] [[package]] name = "openvm-cuda-backend" -version = "1.4.0" -source = "git+https://github.com/openvm-org/stark-backend.git?tag=v1.4.0#2d4c6da0c84f43b15fcdac84ce13fd2325148c66" +version = "2.0.0" +source = "git+https://github.com/openvm-org/stark-backend.git?tag=v2.0.0#16d60de724c21dcadfde7d8315a1db507e5832d7" dependencies = [ - "bincode 2.0.1", - "bincode_derive", - "derivative", "derive-new 0.7.0", + "getset", + "glob", "itertools 0.14.0", - "lazy_static", - "metrics", "openvm-cuda-builder", "openvm-cuda-common", "openvm-stark-backend", "openvm-stark-sdk", "p3-baby-bear", - "p3-commit", + "p3-bn254", "p3-dft", "p3-field", - "p3-fri", - "p3-matrix", - "p3-merkle-tree", "p3-symmetric", "p3-util", - "rustc-hash 2.1.2", + "rand 0.9.4", + "rustc-hash 2.1.3", "serde", - "serde_json", "thiserror 1.0.69", "tracing", + "zkhash-axiom", ] [[package]] name = "openvm-cuda-builder" -version = "1.4.0" -source = "git+https://github.com/openvm-org/stark-backend.git?tag=v1.4.0#2d4c6da0c84f43b15fcdac84ce13fd2325148c66" +version = "2.0.0" +source = "git+https://github.com/openvm-org/stark-backend.git?tag=v2.0.0#16d60de724c21dcadfde7d8315a1db507e5832d7" dependencies = [ "cc", "glob", @@ -5107,8 +5338,8 @@ dependencies = [ [[package]] name = "openvm-cuda-common" -version = "1.4.0" -source = "git+https://github.com/openvm-org/stark-backend.git?tag=v1.4.0#2d4c6da0c84f43b15fcdac84ce13fd2325148c66" +version = "2.0.0" +source = "git+https://github.com/openvm-org/stark-backend.git?tag=v2.0.0#16d60de724c21dcadfde7d8315a1db507e5832d7" dependencies = [ "bytesize", "ctor 0.5.0", @@ -5122,24 +5353,79 @@ dependencies = [ [[package]] name = "openvm-custom-insn" version = "0.1.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", +] + +[[package]] +name = "openvm-deferral-circuit" +version = "2.0.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" +dependencies = [ + "cfg-if 1.0.4", + "dashmap", + "derive-new 0.6.0", + "derive_more 1.0.0", + "itertools 0.14.0", + "openvm-circuit", + "openvm-circuit-derive", + "openvm-circuit-primitives", + "openvm-circuit-primitives-derive", + "openvm-cpu-backend", + "openvm-cuda-backend", + "openvm-cuda-builder", + "openvm-cuda-common", + "openvm-deferral-transpiler", + "openvm-instructions", + "openvm-poseidon2-air", + "openvm-rv32im-circuit", + "openvm-stark-backend", + "openvm-stark-sdk", + "p3-field", + "rand 0.9.4", + "rustc-hash 2.1.3", + "serde", +] + +[[package]] +name = "openvm-deferral-guest" +version = "2.0.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" +dependencies = [ + "openvm-custom-insn", + "strum_macros 0.26.4", +] + +[[package]] +name = "openvm-deferral-transpiler" +version = "2.0.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" +dependencies = [ + "eyre", + "openvm-deferral-guest", + "openvm-instructions", + "openvm-instructions-derive", + "openvm-transpiler", + "p3-field", + "rrs-lib", + "serde", + "strum 0.26.3", ] [[package]] name = "openvm-ecc-circuit" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" +version = "2.0.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" dependencies = [ "blstrs", - "cfg-if", + "cfg-if 1.0.4", "derive-new 0.6.0", "derive_more 1.0.0", "halo2curves-axiom 0.7.2 (git+https://github.com/axiom-crypto/halo2curves.git?tag=v0.7.2)", - "hex-literal", + "hex-literal 1.1.0", "lazy_static", "num-bigint", "num-traits", @@ -5148,6 +5434,7 @@ dependencies = [ "openvm-circuit", "openvm-circuit-derive", "openvm-circuit-primitives", + "openvm-cpu-backend", "openvm-cuda-backend", "openvm-cuda-common", "openvm-ecc-transpiler", @@ -5164,8 +5451,8 @@ dependencies = [ [[package]] name = "openvm-ecc-guest" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" +version = "2.0.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" dependencies = [ "ecdsa", "elliptic-curve", @@ -5183,18 +5470,18 @@ dependencies = [ [[package]] name = "openvm-ecc-sw-macros" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" +version = "2.0.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" dependencies = [ "openvm-macros-common", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] name = "openvm-ecc-transpiler" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" +version = "2.0.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" dependencies = [ "openvm-ecc-guest", "openvm-instructions", @@ -5207,8 +5494,8 @@ dependencies = [ [[package]] name = "openvm-instructions" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" +version = "2.0.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" dependencies = [ "backtrace", "derive-new 0.6.0", @@ -5224,19 +5511,18 @@ dependencies = [ [[package]] name = "openvm-instructions-derive" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" +version = "2.0.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" dependencies = [ "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] name = "openvm-keccak256-circuit" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" +version = "2.0.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" dependencies = [ - "cfg-if", "derive-new 0.6.0", "derive_more 1.0.0", "itertools 0.14.0", @@ -5244,6 +5530,7 @@ dependencies = [ "openvm-circuit-derive", "openvm-circuit-primitives", "openvm-circuit-primitives-derive", + "openvm-cpu-backend", "openvm-cuda-backend", "openvm-cuda-builder", "openvm-cuda-common", @@ -5261,16 +5548,16 @@ dependencies = [ [[package]] name = "openvm-keccak256-guest" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" +version = "2.0.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" dependencies = [ "openvm-platform", ] [[package]] name = "openvm-keccak256-transpiler" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" +version = "2.0.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" dependencies = [ "openvm-instructions", "openvm-instructions-derive", @@ -5283,143 +5570,38 @@ dependencies = [ [[package]] name = "openvm-macros-common" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" +version = "2.0.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" dependencies = [ - "syn 2.0.117", + "syn 2.0.118", ] [[package]] name = "openvm-mod-circuit-builder" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" +version = "2.0.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" dependencies = [ - "cuda-runtime-sys", "itertools 0.14.0", "num-bigint", "num-traits", "openvm-circuit", "openvm-circuit-primitives", - "openvm-cuda-backend", - "openvm-cuda-builder", - "openvm-cuda-common", - "openvm-instructions", - "openvm-stark-backend", - "openvm-stark-sdk", - "rand 0.8.6", - "rand 0.9.4", - "tracing", -] - -[[package]] -name = "openvm-native-circuit" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" -dependencies = [ - "cfg-if", - "derive-new 0.6.0", - "derive_more 1.0.0", - "eyre", - "itertools 0.14.0", - "openvm-circuit", - "openvm-circuit-derive", - "openvm-circuit-primitives", - "openvm-circuit-primitives-derive", - "openvm-cuda-backend", - "openvm-cuda-builder", - "openvm-cuda-common", "openvm-instructions", - "openvm-native-compiler", - "openvm-poseidon2-air", - "openvm-rv32im-circuit", - "openvm-rv32im-transpiler", "openvm-stark-backend", "openvm-stark-sdk", - "p3-field", - "rand 0.9.4", - "serde", - "static_assertions", - "strum 0.26.3", -] - -[[package]] -name = "openvm-native-compiler" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" -dependencies = [ - "backtrace", - "itertools 0.14.0", - "num-bigint", - "num-integer", - "openvm-circuit", - "openvm-instructions", - "openvm-instructions-derive", - "openvm-native-compiler-derive", - "openvm-rv32im-transpiler", - "openvm-stark-backend", - "openvm-stark-sdk", - "serde", - "snark-verifier-sdk", - "strum 0.26.3", - "strum_macros 0.26.4", - "zkhash", -] - -[[package]] -name = "openvm-native-compiler-derive" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" -dependencies = [ - "quote", - "syn 2.0.117", -] - -[[package]] -name = "openvm-native-recursion" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" -dependencies = [ - "cfg-if", - "itertools 0.14.0", - "lazy_static", - "once_cell", - "openvm-circuit", - "openvm-native-circuit", - "openvm-native-compiler", - "openvm-native-compiler-derive", - "openvm-stark-backend", - "openvm-stark-sdk", - "p3-dft", - "p3-fri", - "p3-merkle-tree", - "p3-symmetric", "rand 0.8.6", "rand 0.9.4", - "serde", - "serde_json", - "serde_with", - "snark-verifier-sdk", "tracing", ] -[[package]] -name = "openvm-native-transpiler" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" -dependencies = [ - "openvm-instructions", - "openvm-transpiler", - "p3-field", -] - [[package]] name = "openvm-pairing" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" +version = "2.0.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" dependencies = [ "group 0.13.0", "halo2curves-axiom 0.7.2 (git+https://github.com/axiom-crypto/halo2curves.git?tag=v0.7.2)", - "hex-literal", + "hex-literal 1.1.0", "itertools 0.14.0", "num-bigint", "num-traits", @@ -5438,10 +5620,10 @@ dependencies = [ [[package]] name = "openvm-pairing-circuit" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" +version = "2.0.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" dependencies = [ - "cfg-if", + "cfg-if 1.0.4", "derive-new 0.6.0", "derive_more 1.0.0", "eyre", @@ -5452,6 +5634,7 @@ dependencies = [ "openvm-circuit", "openvm-circuit-derive", "openvm-circuit-primitives", + "openvm-cpu-backend", "openvm-cuda-backend", "openvm-ecc-circuit", "openvm-ecc-guest", @@ -5469,12 +5652,12 @@ dependencies = [ [[package]] name = "openvm-pairing-guest" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" +version = "2.0.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" dependencies = [ "blstrs", "halo2curves-axiom 0.7.2 (git+https://github.com/axiom-crypto/halo2curves.git?tag=v0.7.2)", - "hex-literal", + "hex-literal 1.1.0", "itertools 0.14.0", "lazy_static", "num-bigint", @@ -5490,8 +5673,8 @@ dependencies = [ [[package]] name = "openvm-pairing-transpiler" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" +version = "2.0.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" dependencies = [ "openvm-instructions", "openvm-pairing-guest", @@ -5503,8 +5686,8 @@ dependencies = [ [[package]] name = "openvm-platform" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" +version = "2.0.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" dependencies = [ "libm", "openvm-custom-insn", @@ -5513,11 +5696,12 @@ dependencies = [ [[package]] name = "openvm-poseidon2-air" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" +version = "2.0.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" dependencies = [ "derivative", "lazy_static", + "openvm-circuit-primitives", "openvm-cuda-builder", "openvm-stark-backend", "openvm-stark-sdk", @@ -5525,13 +5709,50 @@ dependencies = [ "p3-poseidon2-air", "p3-symmetric", "rand 0.9.4", - "zkhash", + "zkhash-axiom", +] + +[[package]] +name = "openvm-recursion-circuit" +version = "2.0.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" +dependencies = [ + "derive-new 0.6.0", + "itertools 0.14.0", + "openvm-circuit", + "openvm-circuit-primitives", + "openvm-cpu-backend", + "openvm-cuda-backend", + "openvm-cuda-builder", + "openvm-cuda-common", + "openvm-poseidon2-air", + "openvm-recursion-circuit-derive", + "openvm-stark-backend", + "openvm-stark-sdk", + "p3-air", + "p3-baby-bear", + "p3-field", + "p3-matrix", + "p3-maybe-rayon", + "p3-symmetric", + "strum 0.26.3", + "strum_macros 0.26.4", + "tracing", +] + +[[package]] +name = "openvm-recursion-circuit-derive" +version = "2.0.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" +dependencies = [ + "quote", + "syn 2.0.118", ] [[package]] name = "openvm-rv32-adapters" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" +version = "2.0.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" dependencies = [ "derive-new 0.6.0", "itertools 0.14.0", @@ -5547,10 +5768,10 @@ dependencies = [ [[package]] name = "openvm-rv32im-circuit" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" +version = "2.0.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" dependencies = [ - "cfg-if", + "cfg-if 1.0.4", "derive-new 0.6.0", "derive_more 1.0.0", "eyre", @@ -5560,6 +5781,7 @@ dependencies = [ "openvm-circuit-derive", "openvm-circuit-primitives", "openvm-circuit-primitives-derive", + "openvm-cpu-backend", "openvm-cuda-backend", "openvm-cuda-builder", "openvm-cuda-common", @@ -5570,22 +5792,22 @@ dependencies = [ "rand 0.9.4", "serde", "strum 0.26.3", + "tracing", ] [[package]] name = "openvm-rv32im-guest" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" +version = "2.0.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" dependencies = [ "openvm-custom-insn", - "p3-field", "strum_macros 0.26.4", ] [[package]] name = "openvm-rv32im-transpiler" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" +version = "2.0.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" dependencies = [ "openvm-instructions", "openvm-instructions-derive", @@ -5600,124 +5822,147 @@ dependencies = [ [[package]] name = "openvm-sdk" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" +version = "2.0.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" dependencies = [ + "alloy-sol-types", "bitcode", - "bon", - "cfg-if", + "cfg-if 1.0.4", "clap", "derivative", + "derive-new 0.6.0", "derive_more 1.0.0", "eyre", "getset", + "halo2-base", "hex", "itertools 0.14.0", - "metrics", - "num-bigint", "openvm", + "openvm-build", + "openvm-circuit", + "openvm-continuations", + "openvm-cuda-backend", + "openvm-deferral-circuit", + "openvm-recursion-circuit", + "openvm-sdk-config", + "openvm-stark-backend", + "openvm-stark-sdk", + "openvm-static-verifier", + "openvm-transpiler", + "openvm-verify-stark-circuit", + "openvm-verify-stark-host", + "serde", + "serde_json", + "serde_with", + "tempfile", + "thiserror 1.0.69", + "tracing", +] + +[[package]] +name = "openvm-sdk-config" +version = "2.0.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" +dependencies = [ + "bon", + "cfg-if 1.0.4", + "derive_more 1.0.0", "openvm-algebra-circuit", "openvm-algebra-transpiler", "openvm-bigint-circuit", "openvm-bigint-transpiler", - "openvm-build", "openvm-circuit", "openvm-continuations", + "openvm-cpu-backend", "openvm-cuda-backend", + "openvm-deferral-circuit", + "openvm-deferral-transpiler", "openvm-ecc-circuit", "openvm-ecc-transpiler", "openvm-keccak256-circuit", "openvm-keccak256-transpiler", - "openvm-native-circuit", - "openvm-native-compiler", - "openvm-native-recursion", - "openvm-native-transpiler", "openvm-pairing-circuit", "openvm-pairing-transpiler", "openvm-rv32im-circuit", "openvm-rv32im-transpiler", - "openvm-sha256-circuit", - "openvm-sha256-transpiler", + "openvm-sha2-circuit", + "openvm-sha2-transpiler", "openvm-stark-backend", "openvm-stark-sdk", - "openvm-transpiler", - "p3-bn254", - "p3-fri", - "rand 0.9.4", - "rrs-lib", + "openvm-transpiler", + "openvm-verify-stark-circuit", "serde", - "serde_json", - "serde_with", - "snark-verifier", - "snark-verifier-sdk", - "tempfile", - "thiserror 1.0.69", "toml", - "tracing", ] [[package]] name = "openvm-sha2" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" +version = "2.0.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" dependencies = [ - "openvm-sha256-guest", + "openvm-sha2-guest", "sha2 0.10.9", ] [[package]] -name = "openvm-sha256-air" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" +name = "openvm-sha2-air" +version = "2.0.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" dependencies = [ + "ndarray", + "num_enum 0.7.6", "openvm-circuit-primitives", + "openvm-circuit-primitives-derive", "openvm-stark-backend", "rand 0.9.4", "sha2 0.10.9", ] [[package]] -name = "openvm-sha256-circuit" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" +name = "openvm-sha2-circuit" +version = "2.0.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" dependencies = [ - "cfg-if", + "cfg-if 1.0.4", "derive-new 0.6.0", "derive_more 1.0.0", + "itertools 0.14.0", + "ndarray", "openvm-circuit", "openvm-circuit-derive", "openvm-circuit-primitives", + "openvm-circuit-primitives-derive", + "openvm-cpu-backend", "openvm-cuda-backend", "openvm-cuda-builder", "openvm-cuda-common", "openvm-instructions", "openvm-rv32im-circuit", - "openvm-sha256-air", - "openvm-sha256-transpiler", + "openvm-sha2-air", + "openvm-sha2-transpiler", "openvm-stark-backend", "openvm-stark-sdk", "rand 0.9.4", "serde", "sha2 0.10.9", - "strum 0.26.3", ] [[package]] -name = "openvm-sha256-guest" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" +name = "openvm-sha2-guest" +version = "2.0.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" dependencies = [ "openvm-platform", ] [[package]] -name = "openvm-sha256-transpiler" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" +name = "openvm-sha2-transpiler" +version = "2.0.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" dependencies = [ "openvm-instructions", "openvm-instructions-derive", - "openvm-sha256-guest", + "openvm-sha2-guest", "openvm-stark-backend", "openvm-transpiler", "rrs-lib", @@ -5726,72 +5971,97 @@ dependencies = [ [[package]] name = "openvm-stark-backend" -version = "1.4.0" -source = "git+https://github.com/openvm-org/stark-backend.git?tag=v1.4.0#2d4c6da0c84f43b15fcdac84ce13fd2325148c66" +version = "2.0.0" +source = "git+https://github.com/openvm-org/stark-backend.git?tag=v2.0.0#16d60de724c21dcadfde7d8315a1db507e5832d7" dependencies = [ - "bitcode", - "cfg-if", + "cfg-if 1.0.4", "derivative", "derive-new 0.7.0", "eyre", + "getset", + "hex-literal 1.1.0", "itertools 0.14.0", + "metrics", + "num-bigint", + "openvm-codec-derive", "p3-air", "p3-challenger", - "p3-commit", + "p3-dft", "p3-field", + "p3-interpolation", "p3-matrix", "p3-maybe-rayon", + "p3-symmetric", "p3-util", + "postcard", "rayon", - "rustc-hash 2.1.2", + "rustc-hash 2.1.3", "serde", "serde_json", "thiserror 1.0.69", + "tikv-jemallocator", "tracing", ] [[package]] name = "openvm-stark-sdk" -version = "1.4.0" -source = "git+https://github.com/openvm-org/stark-backend.git?tag=v1.4.0#2d4c6da0c84f43b15fcdac84ce13fd2325148c66" +version = "2.0.0" +source = "git+https://github.com/openvm-org/stark-backend.git?tag=v2.0.0#16d60de724c21dcadfde7d8315a1db507e5832d7" dependencies = [ "dashmap", - "derivative", - "derive_more 1.0.0", - "ff 0.13.1", + "derive-new 0.7.0", + "eyre", + "hex-literal 1.1.0", "itertools 0.14.0", "metrics", "metrics-tracing-context", "metrics-util", "num-bigint", + "nvtx", + "openvm-cpu-backend", "openvm-stark-backend", "p3-baby-bear", - "p3-blake3", "p3-bn254", - "p3-dft", - "p3-fri", - "p3-goldilocks", - "p3-keccak", - "p3-koala-bear", - "p3-merkle-tree", - "p3-poseidon", + "p3-field", "p3-poseidon2", - "p3-symmetric", "rand 0.9.4", "serde", "serde_json", "static_assertions", - "toml", "tracing", "tracing-forest", "tracing-subscriber 0.3.23", - "zkhash", + "zkhash-axiom", +] + +[[package]] +name = "openvm-static-verifier" +version = "2.0.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" +dependencies = [ + "halo2-base", + "itertools 0.14.0", + "num-bigint", + "num-integer", + "once_cell", + "openvm-continuations", + "openvm-cpu-backend", + "openvm-cuda-backend", + "openvm-recursion-circuit", + "openvm-stark-sdk", + "openvm-verify-stark-host", + "rand_chacha 0.3.1", + "serde", + "serde_json", + "serde_with", + "snark-verifier-sdk", + "tracing", ] [[package]] name = "openvm-transpiler" -version = "1.6.0" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" +version = "2.0.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" dependencies = [ "elf", "eyre", @@ -5802,6 +6072,54 @@ dependencies = [ "thiserror 1.0.69", ] +[[package]] +name = "openvm-verify-stark-circuit" +version = "2.0.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" +dependencies = [ + "bitcode", + "cfg-if 1.0.4", + "derive-new 0.6.0", + "eyre", + "itertools 0.14.0", + "openvm-circuit", + "openvm-circuit-primitives", + "openvm-continuations", + "openvm-cpu-backend", + "openvm-cuda-backend", + "openvm-cuda-common", + "openvm-deferral-circuit", + "openvm-poseidon2-air", + "openvm-recursion-circuit", + "openvm-recursion-circuit-derive", + "openvm-stark-backend", + "openvm-stark-sdk", + "openvm-verify-stark-host", + "p3-air", + "p3-field", + "p3-matrix", + "serde", + "tracing", +] + +[[package]] +name = "openvm-verify-stark-host" +version = "2.0.0" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" +dependencies = [ + "bitcode", + "eyre", + "openvm-circuit", + "openvm-circuit-primitives", + "openvm-recursion-circuit-derive", + "openvm-stark-backend", + "openvm-stark-sdk", + "p3-field", + "serde", + "thiserror 1.0.69", + "zstd", +] + [[package]] name = "ordered-float" version = "4.6.0" @@ -5832,12 +6150,12 @@ dependencies = [ [[package]] name = "p256" version = "0.13.2" -source = "git+https://github.com/openvm-org/openvm.git?tag=v1.6.0#eda5bf031a6bd0960adb1dcf59b9a0a951eacb20" +source = "git+https://github.com/openvm-org/openvm.git?tag=v2.0.0#15a7ab6baed03d75050dbef2bbad4b4e98fb8dba" dependencies = [ "ecdsa", "elliptic-curve", "ff 0.13.1", - "hex-literal", + "hex-literal 1.1.0", "num-bigint", "openvm", "openvm-algebra-guest", @@ -5872,17 +6190,6 @@ dependencies = [ "rand 0.9.4", ] -[[package]] -name = "p3-blake3" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a8f97fd783752532861bf29bac344b7c226a0d1e2151148834c43c651a5d401" -dependencies = [ - "blake3", - "p3-symmetric", - "p3-util", -] - [[package]] name = "p3-bn254" version = "0.4.3" @@ -5913,21 +6220,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "p3-commit" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf6d7dcb58a8f21f0e1325dc7f7699ad749878ccbe7e286e61f9d46bde2bfa88" -dependencies = [ - "itertools 0.14.0", - "p3-challenger", - "p3-dft", - "p3-field", - "p3-matrix", - "p3-util", - "serde", -] - [[package]] name = "p3-dft" version = "0.4.3" @@ -5959,46 +6251,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "p3-fri" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13ca6a795cfc4180425fbf16dfdb4c9c2bfa85971dd55b5930d97b513e0835df" -dependencies = [ - "itertools 0.14.0", - "p3-challenger", - "p3-commit", - "p3-dft", - "p3-field", - "p3-interpolation", - "p3-matrix", - "p3-maybe-rayon", - "p3-util", - "rand 0.9.4", - "serde", - "thiserror 2.0.18", - "tracing", -] - -[[package]] -name = "p3-goldilocks" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13c47d5c650bbeb25941b9a1fa9bfaf59b3cd202a438ea2c20892489af001399" -dependencies = [ - "num-bigint", - "p3-challenger", - "p3-dft", - "p3-field", - "p3-mds", - "p3-poseidon2", - "p3-symmetric", - "p3-util", - "paste", - "rand 0.9.4", - "serde", -] - [[package]] name = "p3-interpolation" version = "0.4.3" @@ -6011,18 +6263,6 @@ dependencies = [ "p3-util", ] -[[package]] -name = "p3-keccak" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a61b090fb42152d1fcb2f82227b8619b1b022f9cd4a123123dccc9c2ab75d5de" -dependencies = [ - "p3-field", - "p3-symmetric", - "p3-util", - "tiny-keccak", -] - [[package]] name = "p3-keccak-air" version = "0.4.3" @@ -6038,20 +6278,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "p3-koala-bear" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfb02789fca0950e246123d652bd78e75a76e3b90a651fd88dbb215cd3e81f5a" -dependencies = [ - "p3-challenger", - "p3-field", - "p3-monty-31", - "p3-poseidon2", - "p3-symmetric", - "rand 0.9.4", -] - [[package]] name = "p3-matrix" version = "0.4.3" @@ -6089,25 +6315,6 @@ dependencies = [ "rand 0.9.4", ] -[[package]] -name = "p3-merkle-tree" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60e20f61ea816e94f83ed7b8134a5e98d0cad7bd6dff226bc1da17a5143c63cb" -dependencies = [ - "itertools 0.14.0", - "p3-commit", - "p3-field", - "p3-matrix", - "p3-maybe-rayon", - "p3-symmetric", - "p3-util", - "rand 0.9.4", - "serde", - "thiserror 2.0.18", - "tracing", -] - [[package]] name = "p3-monty-31" version = "0.4.3" @@ -6131,18 +6338,6 @@ dependencies = [ "tracing", ] -[[package]] -name = "p3-poseidon" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "548af7ff569975882bc411f653aba7d89a6d85813ca58ef922fd0b1ecb6b5866" -dependencies = [ - "p3-field", - "p3-mds", - "p3-symmetric", - "rand 0.9.4", -] - [[package]] name = "p3-poseidon2" version = "0.4.3" @@ -6235,7 +6430,7 @@ dependencies = [ "proc-macro-crate 3.5.0", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -6265,7 +6460,7 @@ version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "60a2cfe6f0ad2bfc16aefa463b497d5c7a5ecd44a23efa72aa342d90177356dc" dependencies = [ - "cfg-if", + "cfg-if 1.0.4", "instant", "libc", "redox_syscall 0.2.16", @@ -6279,7 +6474,7 @@ version = "0.9.12" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" dependencies = [ - "cfg-if", + "cfg-if 1.0.4", "libc", "redox_syscall 0.5.18", "smallvec", @@ -6330,9 +6525,9 @@ checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "pest" -version = "2.8.6" +version = "2.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0848c601009d37dfa3430c4666e147e49cdcf1b92ecd3e63657d8a5f19da662" +checksum = "47627dd7305c6a2d6c8c6bcd24c5a4c17dbbf425f4f9c5313e724b38fc9782e9" dependencies = [ "memchr", "ucd-trie", @@ -6346,6 +6541,7 @@ checksum = "1fd6780a80ae0c52cc120a26a1a42c1ae51b247a253e4e06113d23d2c2edd078" dependencies = [ "phf_macros 0.11.3", "phf_shared 0.11.3", + "serde", ] [[package]] @@ -6389,7 +6585,7 @@ dependencies = [ "phf_shared 0.11.3", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -6402,7 +6598,7 @@ dependencies = [ "phf_shared 0.13.1", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -6440,7 +6636,7 @@ checksum = "c96395f0a926bc13b1c17622aaddda1ecb55d49c8f1bf9777e4d877800a43f8b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -6477,7 +6673,7 @@ version = "0.7.0-rc.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ffd40cc99d0fbb02b4b3771346b811df94194bc103983efa0203c8893755085" dependencies = [ - "cfg-if", + "cfg-if 1.0.4", "cpufeatures 0.2.17", "universal-hash", ] @@ -6488,6 +6684,15 @@ version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" +[[package]] +name = "portable-atomic-util" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a106d1259c23fac8e543272398ae0e3c0b8d33c88ed73d0cc71b0f1d902618" +dependencies = [ + "portable-atomic", +] + [[package]] name = "poseidon-primitives" version = "0.2.0" @@ -6503,6 +6708,18 @@ dependencies = [ "thiserror 1.0.69", ] +[[package]] +name = "postcard" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6764c3b5dd454e283a30e6dfe78e9b31096d9e32036b5d1eaac7a6119ccb9a24" +dependencies = [ + "cobs", + "embedded-io 0.4.0", + "embedded-io 0.6.1", + "serde", +] + [[package]] name = "potential_utf" version = "0.1.5" @@ -6534,7 +6751,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" dependencies = [ "proc-macro2", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -6576,7 +6793,7 @@ version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f" dependencies = [ - "toml_edit 0.25.11+spec-1.1.0", + "toml_edit 0.25.12+spec-1.1.0", ] [[package]] @@ -6598,7 +6815,7 @@ dependencies = [ "proc-macro-error-attr2", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -6618,7 +6835,7 @@ checksum = "4b45fcc2344c680f5025fe57779faef368840d0bd1f42f216291f0dc4ace4744" dependencies = [ "bit-set", "bit-vec", - "bitflags 2.11.1", + "bitflags 2.13.0", "num-traits", "rand 0.9.4", "rand_chacha 0.9.0", @@ -6645,6 +6862,12 @@ dependencies = [ "http", "libzkp", "once_cell", + "openvm-circuit", + "openvm-continuations", + "openvm-sdk", + "openvm-stark-sdk", + "openvm-verify-stark-circuit", + "openvm-verify-stark-host", "rand 0.8.6", "reqwest", "scroll-proving-sdk", @@ -6686,7 +6909,7 @@ checksum = "7347867d0a7e1208d93b46767be83e2b8f978c3dad35f775ac8d8847551d6fe1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -6712,16 +6935,16 @@ checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" [[package]] name = "quinn" -version = "0.11.9" +version = "0.11.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20" +checksum = "0c1a41e437b6bbd489372cd4971de128e85c855f56c57f283d20ff016cf7c0a8" dependencies = [ "bytes", "cfg_aliases", "pin-project-lite", "quinn-proto", "quinn-udp", - "rustc-hash 2.1.2", + "rustc-hash 2.1.3", "rustls", "socket2", "thiserror 2.0.18", @@ -6732,16 +6955,17 @@ dependencies = [ [[package]] name = "quinn-proto" -version = "0.11.14" +version = "0.11.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "434b42fec591c96ef50e21e886936e66d3cc3f737104fdb9b737c40ffb94c098" +checksum = "2f4bfc015262b9df63c8845072ce59068853ff5872180c2ce2f13038b970e560" dependencies = [ "bytes", - "getrandom 0.3.4", + "getrandom 0.4.3", "lru-slab", - "rand 0.9.4", + "rand 0.10.2", + "rand_pcg", "ring", - "rustc-hash 2.1.2", + "rustc-hash 2.1.3", "rustls", "rustls-pki-types", "slab", @@ -6753,23 +6977,23 @@ dependencies = [ [[package]] name = "quinn-udp" -version = "0.5.14" +version = "0.5.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd" +checksum = "35a133f956daabe89a61a685c2649f13d82d5aa4bd5d12d1277e1072a21c0694" dependencies = [ "cfg_aliases", "libc", "once_cell", "socket2", "tracing", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] name = "quote" -version = "1.0.45" +version = "1.0.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" +checksum = "dfbc457d0c7a0759a614551b11a6409e5951f6c7537be1f1b7682b9ae9230368" dependencies = [ "proc-macro2", ] @@ -6804,9 +7028,9 @@ dependencies = [ [[package]] name = "rancor" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a063ea72381527c2a0561da9c80000ef822bdd7c3241b1cc1b12100e3df081ee" +checksum = "daff8b7b3ccf5f7ba270b3e7a0a4d4c701c5797e38dec27c7e2c3dbb830fed1c" dependencies = [ "ptr_meta", ] @@ -6834,6 +7058,17 @@ dependencies = [ "serde", ] +[[package]] +name = "rand" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7f5fa3a058cd35567ef9bfa5e75732bee0f9e4c55fa90477bef2dfcdbc4be80" +dependencies = [ + "chacha20", + "getrandom 0.4.3", + "rand_core 0.10.1", +] + [[package]] name = "rand_chacha" version = "0.3.1" @@ -6873,6 +7108,21 @@ dependencies = [ "serde", ] +[[package]] +name = "rand_core" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" + +[[package]] +name = "rand_pcg" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caa0f4137e1c0a72f4c651489402276c8e8e1cf081f3b0ba156d2cbeef09e86a" +dependencies = [ + "rand_core 0.10.1", +] + [[package]] name = "rand_xorshift" version = "0.3.0" @@ -6893,9 +7143,9 @@ dependencies = [ [[package]] name = "rapidhash" -version = "4.4.1" +version = "4.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e48930979c155e2f33aa36ab3119b5ee81332beb6482199a8ecd6029b80b59" +checksum = "5da7e78a036ce858e8d55b7e7dc8ba3a88b78350fd2155d3591bbd966b58589e" dependencies = [ "rustversion", ] @@ -6906,9 +7156,15 @@ version = "11.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "498cd0dc59d73224351ee52a95fee0f1a617a2eae0e7d9d720cc622c73a54186" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", ] +[[package]] +name = "rawpointer" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60a357793950651c4ed0f3f52338f53b2f809f32d83a07f72909fa13e4c6c1e3" + [[package]] name = "rayon" version = "1.12.0" @@ -6944,7 +7200,7 @@ version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", ] [[package]] @@ -6964,14 +7220,14 @@ checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] name = "regex" -version = "1.12.3" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" +checksum = "2a0e75113e14dc5acb068cd0786884f214f1312650a3d36d269f5c4f3cdee8a2" dependencies = [ "aho-corasick", "memchr", @@ -6981,9 +7237,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.14" +version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" +checksum = "1f388202e4b80542a0921078cc23b6333bcf1409c1e3f86404cae4766a6131db" dependencies = [ "aho-corasick", "memchr", @@ -6992,15 +7248,15 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.10" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" +checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" [[package]] name = "rend" -version = "0.5.3" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cadadef317c2f20755a64d7fdc48f9e7178ee6b0e1f7fce33fa60f1d68a276e6" +checksum = "663ba70707f96e871406fe10d68128412e619b06d1d47cb91c3a4c6501176240" dependencies = [ "bytecheck", ] @@ -7105,7 +7361,7 @@ source = "git+https://github.com/scroll-tech/reth?tag=scroll-v91.2#11d0a3f73186d dependencies = [ "alloy-chains", "alloy-consensus", - "alloy-eips 1.8.3", + "alloy-eips", "alloy-evm", "alloy-genesis", "alloy-primitives", @@ -7124,7 +7380,7 @@ version = "1.8.2" source = "git+https://github.com/scroll-tech/reth?tag=scroll-v91.2#11d0a3f73186dee7a1ba0d51ea5416dc8fef3e46" dependencies = [ "alloy-consensus", - "alloy-eips 1.8.3", + "alloy-eips", "alloy-genesis", "alloy-primitives", "alloy-trie 0.9.5", @@ -7143,7 +7399,7 @@ source = "git+https://github.com/scroll-tech/reth?tag=scroll-v91.2#11d0a3f73186d dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -7165,7 +7421,7 @@ version = "1.8.2" source = "git+https://github.com/scroll-tech/reth?tag=scroll-v91.2#11d0a3f73186dee7a1ba0d51ea5416dc8fef3e46" dependencies = [ "alloy-consensus", - "alloy-eips 1.8.3", + "alloy-eips", "reth-chainspec", "reth-consensus", "reth-primitives-traits", @@ -7176,7 +7432,7 @@ name = "reth-db-models" version = "1.8.2" source = "git+https://github.com/scroll-tech/reth?tag=scroll-v91.2#11d0a3f73186dee7a1ba0d51ea5416dc8fef3e46" dependencies = [ - "alloy-eips 1.8.3", + "alloy-eips", "alloy-primitives", "reth-primitives-traits", ] @@ -7198,7 +7454,7 @@ version = "1.8.2" source = "git+https://github.com/scroll-tech/reth?tag=scroll-v91.2#11d0a3f73186dee7a1ba0d51ea5416dc8fef3e46" dependencies = [ "alloy-consensus", - "alloy-eips 1.8.3", + "alloy-eips", "alloy-primitives", "reth-chainspec", "reth-consensus", @@ -7226,11 +7482,11 @@ version = "1.8.2" source = "git+https://github.com/scroll-tech/reth?tag=scroll-v91.2#11d0a3f73186dee7a1ba0d51ea5416dc8fef3e46" dependencies = [ "alloy-consensus", - "alloy-eips 1.8.3", + "alloy-eips", "alloy-primitives", "alloy-rlp", "alloy-rpc-types-eth", - "alloy-serde 1.8.3", + "alloy-serde", "reth-codecs", "reth-primitives-traits", "serde", @@ -7243,7 +7499,7 @@ version = "1.8.2" source = "git+https://github.com/scroll-tech/reth?tag=scroll-v91.2#11d0a3f73186dee7a1ba0d51ea5416dc8fef3e46" dependencies = [ "alloy-consensus", - "alloy-eips 1.8.3", + "alloy-eips", "alloy-evm", "alloy-primitives", "auto_impl", @@ -7265,7 +7521,7 @@ version = "1.8.2" source = "git+https://github.com/scroll-tech/reth?tag=scroll-v91.2#11d0a3f73186dee7a1ba0d51ea5416dc8fef3e46" dependencies = [ "alloy-consensus", - "alloy-eips 1.8.3", + "alloy-eips", "alloy-evm", "alloy-primitives", "alloy-rpc-types-engine", @@ -7298,7 +7554,7 @@ version = "1.8.2" source = "git+https://github.com/scroll-tech/reth?tag=scroll-v91.2#11d0a3f73186dee7a1ba0d51ea5416dc8fef3e46" dependencies = [ "alloy-consensus", - "alloy-eips 1.8.3", + "alloy-eips", "alloy-evm", "alloy-primitives", "derive_more 2.1.1", @@ -7339,7 +7595,7 @@ version = "1.8.2" source = "git+https://github.com/scroll-tech/reth?tag=scroll-v91.2#11d0a3f73186dee7a1ba0d51ea5416dc8fef3e46" dependencies = [ "alloy-consensus", - "alloy-eips 1.8.3", + "alloy-eips", "alloy-genesis", "alloy-primitives", "alloy-rlp", @@ -7390,10 +7646,10 @@ source = "git+https://github.com/scroll-tech/reth?tag=scroll-v91.2#11d0a3f73186d dependencies = [ "alloy-chains", "alloy-consensus", - "alloy-eips 1.8.3", + "alloy-eips", "alloy-genesis", "alloy-primitives", - "alloy-serde 1.8.3", + "alloy-serde", "auto_impl", "derive_more 2.1.1", "once_cell", @@ -7414,7 +7670,7 @@ version = "1.8.2" source = "git+https://github.com/scroll-tech/reth?tag=scroll-v91.2#11d0a3f73186dee7a1ba0d51ea5416dc8fef3e46" dependencies = [ "alloy-consensus", - "alloy-eips 1.8.3", + "alloy-eips", "alloy-evm", "alloy-primitives", "alloy-rpc-types-engine", @@ -7458,7 +7714,7 @@ version = "1.8.2" source = "git+https://github.com/scroll-tech/reth?tag=scroll-v91.2#11d0a3f73186dee7a1ba0d51ea5416dc8fef3e46" dependencies = [ "alloy-consensus", - "alloy-eips 1.8.3", + "alloy-eips", "alloy-primitives", "alloy-rlp", "bytes", @@ -7521,7 +7777,7 @@ version = "1.8.2" source = "git+https://github.com/scroll-tech/reth?tag=scroll-v91.2#11d0a3f73186dee7a1ba0d51ea5416dc8fef3e46" dependencies = [ "alloy-consensus", - "alloy-eips 1.8.3", + "alloy-eips", "alloy-primitives", "alloy-rpc-types-engine", "auto_impl", @@ -7542,7 +7798,7 @@ name = "reth-storage-errors" version = "1.8.2" source = "git+https://github.com/scroll-tech/reth?tag=scroll-v91.2#11d0a3f73186dee7a1ba0d51ea5416dc8fef3e46" dependencies = [ - "alloy-eips 1.8.3", + "alloy-eips", "alloy-primitives", "alloy-rlp", "derive_more 2.1.1", @@ -7559,7 +7815,7 @@ version = "1.8.2" source = "git+https://github.com/scroll-tech/reth?tag=scroll-v91.2#11d0a3f73186dee7a1ba0d51ea5416dc8fef3e46" dependencies = [ "alloy-consensus", - "alloy-eips 1.8.3", + "alloy-eips", "alloy-primitives", "alloy-rlp", "alloy-trie 0.9.5", @@ -7626,21 +7882,21 @@ dependencies = [ [[package]] name = "revm" -version = "22.0.1" +version = "27.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5378e95ffe5c8377002dafeb6f7d370a55517cef7d6d6c16fc552253af3b123" +checksum = "5e6bf82101a1ad8a2b637363a37aef27f88b4efc8a6e24c72bf5f64923dc5532" dependencies = [ - "revm-bytecode 3.0.0", - "revm-context 3.0.1", - "revm-context-interface 3.0.0", - "revm-database 3.0.0", - "revm-database-interface 3.0.0", - "revm-handler 3.0.1", - "revm-inspector 3.0.1", - "revm-interpreter 18.0.0", - "revm-precompile 19.0.0", - "revm-primitives 18.0.0", - "revm-state 3.0.0", + "revm-bytecode 6.2.2", + "revm-context 8.0.4", + "revm-context-interface 9.0.0", + "revm-database 7.0.5", + "revm-database-interface 7.0.5", + "revm-handler 8.1.0", + "revm-inspector 8.1.0", + "revm-interpreter 24.0.0", + "revm-precompile 25.0.0", + "revm-primitives 20.2.1", + "revm-state 7.0.5", ] [[package]] @@ -7682,13 +7938,13 @@ dependencies = [ [[package]] name = "revm-bytecode" -version = "3.0.0" +version = "6.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e63e138d520c5c5bc25ecc82506e9e4e6e85a811809fc5251c594378dccabfc6" +checksum = "66c52031b73cae95d84cd1b07725808b5fd1500da3e5e24574a3b2dc13d9f16d" dependencies = [ "bitvec", "phf 0.11.3", - "revm-primitives 18.0.0", + "revm-primitives 20.2.1", "serde", ] @@ -7717,17 +7973,17 @@ dependencies = [ [[package]] name = "revm-context" -version = "3.0.1" +version = "8.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9765628dfea4f3686aa8f2a72471c52801e6b38b601939ac16965f49bac66580" +checksum = "9cd508416a35a4d8a9feaf5ccd06ac6d6661cd31ee2dc0252f9f7316455d71f9" dependencies = [ - "cfg-if", + "cfg-if 1.0.4", "derive-where", - "revm-bytecode 3.0.0", - "revm-context-interface 3.0.0", - "revm-database-interface 3.0.0", - "revm-primitives 18.0.0", - "revm-state 3.0.0", + "revm-bytecode 6.2.2", + "revm-context-interface 9.0.0", + "revm-database-interface 7.0.5", + "revm-primitives 20.2.1", + "revm-state 7.0.5", "serde", ] @@ -7737,7 +7993,7 @@ version = "10.1.1" source = "git+https://github.com/scroll-tech/revm?tag=scroll-v91#10e11b985ed28bd383e624539868bcc3f613d77c" dependencies = [ "bitvec", - "cfg-if", + "cfg-if 1.0.4", "derive-where", "revm-bytecode 7.0.1", "revm-context-interface 11.1.1", @@ -7754,7 +8010,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7adcce0c14cf59b7128de34185a0fbf8f63309539b9263b35ead870d73584114" dependencies = [ "bitvec", - "cfg-if", + "cfg-if 1.0.4", "derive-where", "revm-bytecode 7.1.1", "revm-context-interface 11.1.2", @@ -7766,16 +8022,17 @@ dependencies = [ [[package]] name = "revm-context-interface" -version = "3.0.0" +version = "9.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82d74335aa1f14222cc4d3be1f62a029cc7dc03819cc8d080ff17b7e1d76375f" +checksum = "dc90302642d21c8f93e0876e201f3c5f7913c4fcb66fb465b0fd7b707dfe1c79" dependencies = [ "alloy-eip2930", "alloy-eip7702", "auto_impl", - "revm-database-interface 3.0.0", - "revm-primitives 18.0.0", - "revm-state 3.0.0", + "either", + "revm-database-interface 7.0.5", + "revm-primitives 20.2.1", + "revm-state 7.0.5", "serde", ] @@ -7812,15 +8069,15 @@ dependencies = [ [[package]] name = "revm-database" -version = "3.0.0" +version = "7.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e5c80c5a2fd605f2119ee32a63fb3be941fb6a81ced8cdb3397abca28317224" +checksum = "39a276ed142b4718dcf64bc9624f474373ed82ef20611025045c3fb23edbef9c" dependencies = [ - "alloy-eips 0.14.0", - "revm-bytecode 3.0.0", - "revm-database-interface 3.0.0", - "revm-primitives 18.0.0", - "revm-state 3.0.0", + "alloy-eips", + "revm-bytecode 6.2.2", + "revm-database-interface 7.0.5", + "revm-primitives 20.2.1", + "revm-state 7.0.5", "serde", ] @@ -7829,7 +8086,7 @@ name = "revm-database" version = "9.0.1" source = "git+https://github.com/scroll-tech/revm?tag=scroll-v91#10e11b985ed28bd383e624539868bcc3f613d77c" dependencies = [ - "alloy-eips 1.8.3", + "alloy-eips", "revm-bytecode 7.0.1", "revm-database-interface 8.0.2", "revm-primitives 21.0.1", @@ -7843,7 +8100,7 @@ version = "9.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "980d8d6bba78c5dd35b83abbb6585b0b902eb25ea4448ed7bfba6283b0337191" dependencies = [ - "alloy-eips 1.8.3", + "alloy-eips", "revm-bytecode 7.1.1", "revm-database-interface 8.0.5", "revm-primitives 21.0.2", @@ -7853,13 +8110,14 @@ dependencies = [ [[package]] name = "revm-database-interface" -version = "3.0.0" +version = "7.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0e4dfbc734b1ea67b5e8f8b3c7dc4283e2210d978cdaf6c7a45e97be5ea53b3" +checksum = "8c523c77e74eeedbac5d6f7c092e3851dbe9c7fec6f418b85992bd79229db361" dependencies = [ "auto_impl", - "revm-primitives 18.0.0", - "revm-state 3.0.0", + "either", + "revm-primitives 20.2.1", + "revm-state 7.0.5", "serde", ] @@ -7890,19 +8148,20 @@ dependencies = [ [[package]] name = "revm-handler" -version = "3.0.1" +version = "8.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8676379521c7bf179c31b685c5126ce7800eab5844122aef3231b97026d41a10" +checksum = "1529c8050e663be64010e80ec92bf480315d21b1f2dbf65540028653a621b27d" dependencies = [ "auto_impl", - "revm-bytecode 3.0.0", - "revm-context 3.0.1", - "revm-context-interface 3.0.0", - "revm-database-interface 3.0.0", - "revm-interpreter 18.0.0", - "revm-precompile 19.0.0", - "revm-primitives 18.0.0", - "revm-state 3.0.0", + "derive-where", + "revm-bytecode 6.2.2", + "revm-context 8.0.4", + "revm-context-interface 9.0.0", + "revm-database-interface 7.0.5", + "revm-interpreter 24.0.0", + "revm-precompile 25.0.0", + "revm-primitives 20.2.1", + "revm-state 7.0.5", "serde", ] @@ -7945,17 +8204,18 @@ dependencies = [ [[package]] name = "revm-inspector" -version = "3.0.1" +version = "8.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfed4ecf999a3f6ae776ae2d160478c5dca986a8c2d02168e04066b1e34c789e" +checksum = "f78db140e332489094ef314eaeb0bd1849d6d01172c113ab0eb6ea8ab9372926" dependencies = [ "auto_impl", - "revm-context 3.0.1", - "revm-database-interface 3.0.0", - "revm-handler 3.0.1", - "revm-interpreter 18.0.0", - "revm-primitives 18.0.0", - "revm-state 3.0.0", + "either", + "revm-context 8.0.4", + "revm-database-interface 7.0.5", + "revm-handler 8.1.0", + "revm-interpreter 24.0.0", + "revm-primitives 20.2.1", + "revm-state 7.0.5", "serde", "serde_json", ] @@ -7997,13 +8257,13 @@ dependencies = [ [[package]] name = "revm-interpreter" -version = "18.0.0" +version = "24.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "feb20260342003cfb791536e678ef5bbea1bfd1f8178b170e8885ff821985473" +checksum = "ff9d7d9d71e8a33740b277b602165b6e3d25fff091ba3d7b5a8d373bf55f28a7" dependencies = [ - "revm-bytecode 3.0.0", - "revm-context-interface 3.0.0", - "revm-primitives 18.0.0", + "revm-bytecode 6.2.2", + "revm-context-interface 9.0.0", + "revm-primitives 20.2.1", "serde", ] @@ -8034,26 +8294,28 @@ dependencies = [ [[package]] name = "revm-precompile" -version = "19.0.0" +version = "25.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "418e95eba68c9806c74f3e36cd5d2259170b61e90ac608b17ff8c435038ddace" +checksum = "4cee3f336b83621294b4cfe84d817e3eef6f3d0fce00951973364cc7f860424d" dependencies = [ "ark-bls12-381", "ark-bn254", "ark-ec", "ark-ff 0.5.0", "ark-serialize 0.5.0", + "arrayref", "aurora-engine-modexp", "blst", "c-kzg", - "cfg-if", + "cfg-if 1.0.4", "k256 0.13.4 (registry+https://github.com/rust-lang/crates.io-index)", "libsecp256k1", "once_cell", "p256 0.13.2 (registry+https://github.com/rust-lang/crates.io-index)", - "revm-primitives 18.0.0", + "revm-primitives 20.2.1", "ripemd", - "secp256k1 0.30.0", + "rug", + "secp256k1 0.31.1", "sha2 0.10.9", ] @@ -8070,7 +8332,7 @@ dependencies = [ "arrayref", "aurora-engine-modexp", "c-kzg", - "cfg-if", + "cfg-if 1.0.4", "k256 0.13.4 (registry+https://github.com/rust-lang/crates.io-index)", "p256 0.13.2 (registry+https://github.com/rust-lang/crates.io-index)", "revm-primitives 21.0.1", @@ -8082,12 +8344,13 @@ dependencies = [ [[package]] name = "revm-primitives" -version = "18.0.0" +version = "20.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fc2283ff87358ec7501956c5dd8724a6c2be959c619c4861395ae5e0054575f" +checksum = "5aa29d9da06fe03b249b6419b33968ecdf92ad6428e2f012dc57bcd619b5d94e" dependencies = [ "alloy-primitives", - "enumn", + "num_enum 0.7.6", + "once_cell", "serde", ] @@ -8130,13 +8393,13 @@ dependencies = [ [[package]] name = "revm-state" -version = "3.0.0" +version = "7.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09dd121f6e66d75ab111fb51b4712f129511569bc3e41e6067ae760861418bd8" +checksum = "1f64fbacb86008394aaebd3454f9643b7d5a782bd251135e17c5b33da592d84d" dependencies = [ - "bitflags 2.11.1", - "revm-bytecode 3.0.0", - "revm-primitives 18.0.0", + "bitflags 2.13.0", + "revm-bytecode 6.2.2", + "revm-primitives 20.2.1", "serde", ] @@ -8145,7 +8408,7 @@ name = "revm-state" version = "8.0.1" source = "git+https://github.com/scroll-tech/revm?tag=scroll-v91#10e11b985ed28bd383e624539868bcc3f613d77c" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", "revm-bytecode 7.0.1", "revm-primitives 21.0.1", "serde", @@ -8157,7 +8420,7 @@ version = "8.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7d8be953b7e374dbdea0773cf360debed8df394ea8d82a8b240a6b5da37592fc" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", "revm-bytecode 7.1.1", "revm-primitives 21.0.2", "serde", @@ -8180,7 +8443,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" dependencies = [ "cc", - "cfg-if", + "cfg-if 1.0.4", "getrandom 0.2.17", "libc", "untrusted", @@ -8213,9 +8476,9 @@ dependencies = [ [[package]] name = "rkyv" -version = "0.8.16" +version = "0.8.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73389e0c99e664f919275ab5b5b0471391fe9a8de61e1dff9b1eaf56a90f16e3" +checksum = "815cc8a37159a463064825246cadb07961e25cd9885908606f6d08a98d8f8874" dependencies = [ "bytecheck", "bytes", @@ -8232,13 +8495,13 @@ dependencies = [ [[package]] name = "rkyv_derive" -version = "0.8.16" +version = "0.8.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d2ed0b54125315fb36bd021e82d314d1c126548f871634b483f46b31d13cac6" +checksum = "c0ed1a78a1b19d184b0daa629dd9a024573173ec7d485b287cb369fb3607cc1c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -8297,14 +8560,15 @@ dependencies = [ [[package]] name = "ruint" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0298da754d1395046b0afdc2f20ee76d29a8ae310cd30ffa84ed42acba9cb12a" +checksum = "45caf26f647c19115bf9c453c70ffe4a4a3a6390dceebd942610584f99b8ddce" dependencies = [ "alloy-rlp", "ark-ff 0.3.0", "ark-ff 0.4.2", "ark-ff 0.5.0", + "ark-ff 0.6.0", "bytes", "fastrlp 0.3.1", "fastrlp 0.4.0", @@ -8330,11 +8594,40 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "48fd7bd8a6377e15ad9d42a8ec25371b94ddc67abe7c8b9127bec79bebaaae18" +[[package]] +name = "rustacuda" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47208516ab5338b592d63560e90eaef405d0ec880347eaf7742d893b0a31e228" +dependencies = [ + "bitflags 1.3.2", + "cuda-driver-sys", + "rustacuda_core", + "rustacuda_derive", +] + +[[package]] +name = "rustacuda_core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3858b08976dc2f860c5efbbb48cdcb0d4fafca92a6ac0898465af16c0dbe848" + +[[package]] +name = "rustacuda_derive" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43ce8670a1a1d0fc2514a3b846dacdb65646f9bd494b6674cfacbb4ce430bd7e" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "rustc-demangle" -version = "0.1.27" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b50b8869d9fc858ce7266cce0194bd74df58b9d0e3f6df3a9fc8eb470d95c09d" +checksum = "b74b56ffa8bb2830709a538c2cbcae9aa062db0d2a42563bfb09bdaae44020eb" [[package]] name = "rustc-hash" @@ -8344,9 +8637,9 @@ checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] name = "rustc-hash" -version = "2.1.2" +version = "2.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe" +checksum = "6b1e7f9a428571be2dc5bc0505c13fb6bf936822b894ec87abf8a08a4e51742d" [[package]] name = "rustc-hex" @@ -8378,7 +8671,7 @@ version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", "errno", "libc", "linux-raw-sys", @@ -8387,9 +8680,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.40" +version = "0.23.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef86cd5876211988985292b91c96a8f2d298df24e75989a43a3c73f2d4d8168b" +checksum = "6b92b125634d9b795e7beca796cc790df15a7fb38323bf3196fda83292d06b1f" dependencies = [ "once_cell", "ring", @@ -8401,9 +8694,9 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.14.1" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30a7197ae7eb376e574fe940d068c30fe0462554a3ddbe4eca7838e049c937a9" +checksum = "764899a24af3980067ee14bc143654f297b22eaebfe3c7b6b211920a5a59b046" dependencies = [ "web-time", "zeroize", @@ -8422,9 +8715,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.22" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" +checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f" [[package]] name = "rusty-fork" @@ -8474,13 +8767,13 @@ version = "2.0.0" source = "git+https://github.com/scroll-tech/stateless-block-verifier?tag=scroll-v91.2#3a32848c9438432125751eae8837757f6b87562e" dependencies = [ "alloy-consensus", - "alloy-eips 1.8.3", + "alloy-eips", "alloy-evm", "alloy-network", "alloy-primitives", "alloy-rpc-types-debug", "alloy-rpc-types-eth", - "alloy-serde 1.8.3", + "alloy-serde", "reth-chainspec", "reth-ethereum-forks", "reth-evm", @@ -8537,7 +8830,7 @@ version = "2.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "346a3b32eba2640d17a9cb5927056b08f3de90f65b72fe09402c2ad07d684d0b" dependencies = [ - "cfg-if", + "cfg-if 1.0.4", "derive_more 1.0.0", "parity-scale-codec", "scale-info-derive", @@ -8552,7 +8845,7 @@ dependencies = [ "proc-macro-crate 3.5.0", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -8600,10 +8893,10 @@ version = "1.8.2" source = "git+https://github.com/scroll-tech/reth?tag=scroll-v91.2#11d0a3f73186dee7a1ba0d51ea5416dc8fef3e46" dependencies = [ "alloy-consensus", - "alloy-eips 1.8.3", + "alloy-eips", "alloy-primitives", "alloy-rlp", - "alloy-serde 1.8.3", + "alloy-serde", "derive_more 2.1.1", "reth-codecs", "serde", @@ -8616,7 +8909,7 @@ version = "1.8.2" source = "git+https://github.com/scroll-tech/reth?tag=scroll-v91.2#11d0a3f73186dee7a1ba0d51ea5416dc8fef3e46" dependencies = [ "alloy-consensus", - "alloy-eips 1.8.3", + "alloy-eips", "alloy-evm", "alloy-primitives", "auto_impl", @@ -8659,11 +8952,11 @@ version = "1.8.2" source = "git+https://github.com/scroll-tech/reth?tag=scroll-v91.2#11d0a3f73186dee7a1ba0d51ea5416dc8fef3e46" dependencies = [ "alloy-consensus", - "alloy-eips 1.8.3", + "alloy-eips", "alloy-network-primitives", "alloy-primitives", "alloy-rpc-types-eth", - "alloy-serde 1.8.3", + "alloy-serde", "derive_more 2.1.1", "scroll-alloy-consensus", "serde", @@ -8703,8 +8996,8 @@ dependencies = [ [[package]] name = "scroll-zkvm-prover" -version = "0.8.0" -source = "git+https://github.com/scroll-tech/zkvm-prover?rev=ed3b964#ed3b964c8d0e93856b089d880ad2eda7e08fb7b4" +version = "0.9.0" +source = "git+https://github.com/scroll-tech/zkvm-prover?rev=bf887150bb671af9b17dd53e92b7f2bbf01ec745#bf887150bb671af9b17dd53e92b7f2bbf01ec745" dependencies = [ "base64", "bincode 1.3.3", @@ -8713,10 +9006,17 @@ dependencies = [ "git-version", "hex", "openvm-circuit", - "openvm-native-circuit", - "openvm-native-recursion", + "openvm-continuations", + "openvm-cuda-backend", + "openvm-deferral-circuit", + "openvm-recursion-circuit", "openvm-sdk", + "openvm-sdk-config", + "openvm-stark-backend", "openvm-stark-sdk", + "openvm-static-verifier", + "openvm-verify-stark-circuit", + "openvm-verify-stark-host", "scroll-zkvm-types", "scroll-zkvm-verifier", "serde", @@ -8729,8 +9029,8 @@ dependencies = [ [[package]] name = "scroll-zkvm-types" -version = "0.8.0" -source = "git+https://github.com/scroll-tech/zkvm-prover?rev=ed3b964#ed3b964c8d0e93856b089d880ad2eda7e08fb7b4" +version = "0.9.0" +source = "git+https://github.com/scroll-tech/zkvm-prover?rev=bf887150bb671af9b17dd53e92b7f2bbf01ec745#bf887150bb671af9b17dd53e92b7f2bbf01ec745" dependencies = [ "alloy-primitives", "base64", @@ -8738,9 +9038,11 @@ dependencies = [ "eyre", "hex", "once_cell", - "openvm-native-recursion", + "openvm-circuit", "openvm-sdk", "openvm-stark-sdk", + "openvm-static-verifier", + "openvm-verify-stark-host", "sbv-primitives", "scroll-zkvm-types-base", "scroll-zkvm-types-batch", @@ -8753,11 +9055,11 @@ dependencies = [ [[package]] name = "scroll-zkvm-types-base" -version = "0.8.0" -source = "git+https://github.com/scroll-tech/zkvm-prover?rev=ed3b964#ed3b964c8d0e93856b089d880ad2eda7e08fb7b4" +version = "0.9.0" +source = "git+https://github.com/scroll-tech/zkvm-prover?rev=bf887150bb671af9b17dd53e92b7f2bbf01ec745#bf887150bb671af9b17dd53e92b7f2bbf01ec745" dependencies = [ "alloy-primitives", - "alloy-serde 1.8.3", + "alloy-serde", "serde", "sha2 0.10.9", "sha3", @@ -8765,8 +9067,8 @@ dependencies = [ [[package]] name = "scroll-zkvm-types-batch" -version = "0.8.0" -source = "git+https://github.com/scroll-tech/zkvm-prover?rev=ed3b964#ed3b964c8d0e93856b089d880ad2eda7e08fb7b4" +version = "0.9.0" +source = "git+https://github.com/scroll-tech/zkvm-prover?rev=bf887150bb671af9b17dd53e92b7f2bbf01ec745#bf887150bb671af9b17dd53e92b7f2bbf01ec745" dependencies = [ "alloy-primitives", "c-kzg", @@ -8786,8 +9088,8 @@ dependencies = [ [[package]] name = "scroll-zkvm-types-bundle" -version = "0.8.0" -source = "git+https://github.com/scroll-tech/zkvm-prover?rev=ed3b964#ed3b964c8d0e93856b089d880ad2eda7e08fb7b4" +version = "0.9.0" +source = "git+https://github.com/scroll-tech/zkvm-prover?rev=bf887150bb671af9b17dd53e92b7f2bbf01ec745#bf887150bb671af9b17dd53e92b7f2bbf01ec745" dependencies = [ "scroll-zkvm-types-base", "serde", @@ -8795,20 +9097,20 @@ dependencies = [ [[package]] name = "scroll-zkvm-types-chunk" -version = "0.8.0" -source = "git+https://github.com/scroll-tech/zkvm-prover?rev=ed3b964#ed3b964c8d0e93856b089d880ad2eda7e08fb7b4" +version = "0.9.0" +source = "git+https://github.com/scroll-tech/zkvm-prover?rev=bf887150bb671af9b17dd53e92b7f2bbf01ec745#bf887150bb671af9b17dd53e92b7f2bbf01ec745" dependencies = [ "alloy-consensus", "alloy-primitives", "alloy-sol-types", "ecies", - "hex-literal", + "hex-literal 0.4.1", "itertools 0.14.0", - "k256 0.13.4 (git+https://github.com/openvm-org/openvm.git?tag=v1.6.0)", + "k256 0.13.4 (git+https://github.com/openvm-org/openvm.git?tag=v2.0.0)", "openvm-ecc-guest", "openvm-pairing", "openvm-sha2", - "p256 0.13.2 (git+https://github.com/openvm-org/openvm.git?tag=v1.6.0)", + "p256 0.13.2 (git+https://github.com/openvm-org/openvm.git?tag=v2.0.0)", "sbv-core", "sbv-helpers", "sbv-primitives", @@ -8820,15 +9122,18 @@ dependencies = [ [[package]] name = "scroll-zkvm-verifier" -version = "0.8.0" -source = "git+https://github.com/scroll-tech/zkvm-prover?rev=ed3b964#ed3b964c8d0e93856b089d880ad2eda7e08fb7b4" +version = "0.9.0" +source = "git+https://github.com/scroll-tech/zkvm-prover?rev=bf887150bb671af9b17dd53e92b7f2bbf01ec745#bf887150bb671af9b17dd53e92b7f2bbf01ec745" dependencies = [ "bincode 1.3.3", "eyre", "once_cell", + "openvm-circuit", "openvm-continuations", - "openvm-native-recursion", "openvm-sdk", + "openvm-stark-sdk", + "openvm-static-verifier", + "openvm-verify-stark-host", "scroll-zkvm-types", "serde", "serde_json", @@ -8899,7 +9204,7 @@ version = "3.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", "core-foundation 0.10.1", "core-foundation-sys", "libc", @@ -8999,14 +9304,14 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] name = "serde_json" -version = "1.0.149" +version = "1.0.150" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9" dependencies = [ "indexmap 2.14.0", "itoa", @@ -9024,7 +9329,7 @@ checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -9061,9 +9366,9 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.20.0" +version = "3.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e72c1c2cb7b223fafb600a619537a871c2818583d619401b785e7c0b746ccde2" +checksum = "76a5c54c7310e7b8b9577c286d7e399ddd876c3e12b3ed917a8aabc4b96e9e8c" dependencies = [ "base64", "bs58", @@ -9081,14 +9386,14 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.20.0" +version = "3.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b90c488738ecb4fb0262f41f43bc40efc5868d9fb744319ddf5f5317f417bfac" +checksum = "84d57bc0c8b9a17920c178daa6bb924850d54a9c97ab45194bb8c17ad66bb660" dependencies = [ "darling 0.23.0", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -9108,7 +9413,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" dependencies = [ "block-buffer 0.9.0", - "cfg-if", + "cfg-if 1.0.4", "cpufeatures 0.2.17", "digest 0.9.0", "opaque-debug", @@ -9120,7 +9425,7 @@ version = "0.10.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ - "cfg-if", + "cfg-if 1.0.4", "cpufeatures 0.2.17", "digest 0.10.7", ] @@ -9150,12 +9455,12 @@ dependencies = [ [[package]] name = "sha3-asm" -version = "0.1.7" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f3f15d4e239ebe08413eed880e0f9b5af4b40ee0472543320efa91d488e96a7" +checksum = "a6287fd675f713484342a89cbf0a386abef5f15919cfad607e5e1f19e1e15331" dependencies = [ "cc", - "cfg-if", + "cfg-if 1.0.4", ] [[package]] @@ -9173,6 +9478,12 @@ version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" +[[package]] +name = "shlex" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" + [[package]] name = "signature" version = "2.2.0" @@ -9231,9 +9542,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.15.1" +version = "1.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" +checksum = "8ed6a63f02c8539c91a8685a86f4099661ba3da017932f6ebbea6de3f0fa7c90" dependencies = [ "serde", ] @@ -9246,9 +9557,8 @@ checksum = "1b6b67fb9a61334225b5b790716f609cd58395f895b3fe8b328786812a40bc3b" [[package]] name = "snark-verifier" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d798d8ce8e29b8820ecc1028ac44cc4fc0f0296728af6fe6a0c4db05782c0a4" +version = "0.2.6" +source = "git+https://github.com/axiom-crypto/snark-verifier.git?tag=v0.2.6#364e82654c746b063aff528d8cb660890908278a" dependencies = [ "halo2-base", "halo2-ecc", @@ -9260,7 +9570,7 @@ dependencies = [ "num-traits", "pairing 0.23.0", "rand 0.8.6", - "revm 22.0.1", + "revm 27.1.0", "ruint", "serde", "sha3", @@ -9268,9 +9578,8 @@ dependencies = [ [[package]] name = "snark-verifier-sdk" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a338d065044702bf751e87cf353daac63e2fc4c53a3e323cbcd98c603ee6e66c" +version = "0.2.6" +source = "git+https://github.com/axiom-crypto/snark-verifier.git?tag=v0.2.6#364e82654c746b063aff528d8cb660890908278a" dependencies = [ "ark-std 0.3.0", "bincode 1.3.3", @@ -9292,9 +9601,9 @@ dependencies = [ [[package]] name = "socket2" -version = "0.6.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e" +checksum = "52d1cfed4120b4d927bf7c0f86d2087a4a7d6027c906d9f9d525a80573b9be51" dependencies = [ "libc", "windows-sys 0.61.2", @@ -9305,6 +9614,9 @@ name = "spin" version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +dependencies = [ + "lock_api", +] [[package]] name = "spin" @@ -9338,7 +9650,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "640c8cdd92b6b12f5bcb1803ca3bbf5ab96e5e6b6b96b9ab77dabe9e880b3190" dependencies = [ "cc", - "cfg-if", + "cfg-if 1.0.4", "libc", "psm", "windows-sys 0.61.2", @@ -9362,6 +9674,26 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" +[[package]] +name = "struct-reflection" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "701b671d1ad68e250e05718f95dae3014a17f4e69cbe51842531c30495ff3301" +dependencies = [ + "struct-reflection-derive", +] + +[[package]] +name = "struct-reflection-derive" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ab74230a0592602e361bd63c645413fa8cbe4500d10274e849179e5c72548f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + [[package]] name = "strum" version = "0.24.1" @@ -9418,7 +9750,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -9431,7 +9763,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -9443,7 +9775,7 @@ dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -9465,9 +9797,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.117" +version = "2.0.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +checksum = "1b9ae57f904213ebb649ce6895b8a66c66f0203b9319718f69a5612a065b1422" dependencies = [ "proc-macro2", "quote", @@ -9483,7 +9815,7 @@ dependencies = [ "paste", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -9503,7 +9835,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -9512,7 +9844,7 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a13f3d0daba03132c0aa9767f98351b3488edc2c100cda2d2ec2b04f3d8d3c8b" dependencies = [ - "bitflags 2.11.1", + "bitflags 2.13.0", "core-foundation 0.9.4", "system-configuration-sys", ] @@ -9540,12 +9872,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" dependencies = [ "fastrand", - "getrandom 0.4.2", + "getrandom 0.4.3", "once_cell", "rustix", "windows-sys 0.61.2", ] +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + [[package]] name = "test-case" version = "3.3.1" @@ -9561,10 +9902,10 @@ version = "3.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adcb7fd841cd518e279be3d5a3eb0636409487998a4aff22f3de87b81e88384f" dependencies = [ - "cfg-if", + "cfg-if 1.0.4", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -9575,7 +9916,7 @@ checksum = "5c89e72a01ed4c579669add59014b9a524d609c0c88c6a585ce37485879f6ffb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", "test-case-core", ] @@ -9605,7 +9946,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -9616,16 +9957,16 @@ checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] name = "thread_local" -version = "1.1.9" +version = "1.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" +checksum = "1ad99c4c6d32803332c548b1af0540b357b3f5fc0be8f6c6bfe8b2e6ae784070" dependencies = [ - "cfg-if", + "cfg-if 1.0.4", ] [[package]] @@ -9637,14 +9978,33 @@ dependencies = [ "num_cpus", ] +[[package]] +name = "tikv-jemalloc-sys" +version = "0.6.1+5.3.0-1-ge13ca993e8ccb9ba9847cc330696e02839f328f7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd8aa5b2ab86a2cefa406d889139c162cbb230092f7d1d7cbc1716405d852a3b" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "tikv-jemallocator" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0359b4327f954e0567e69fb191cf1436617748813819c94b8cd4a431422d053a" +dependencies = [ + "libc", + "tikv-jemalloc-sys", +] + [[package]] name = "time" -version = "0.3.47" +version = "0.3.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" +checksum = "18dfaaeddcb932337b5e7866ee7d0ce9b76d2fd092997146f187ec09b4558a50" dependencies = [ "deranged", - "itoa", "num-conv", "powerfmt", "serde_core", @@ -9654,15 +10014,15 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" +checksum = "9e1c906769ad99c88eaa54e728060edef082f8e358ff32030cb7c7d315e81109" [[package]] name = "time-macros" -version = "0.2.27" +version = "0.2.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215" +checksum = "c431b87111666e491a90baa837f914fb45cd5dc3c268591b0220ff5057f2085f" dependencies = [ "num-conv", "time-core", @@ -9689,9 +10049,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3" +checksum = "bb4ebadaa0af04fab11ae01eb5f9fdb5f9c5b875506e210e71c07873528baa7f" dependencies = [ "tinyvec_macros", ] @@ -9725,7 +10085,7 @@ checksum = "385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -9830,9 +10190,9 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.25.11+spec-1.1.0" +version = "0.25.12+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b59c4d22ed448339746c59b905d24568fcbb3ab65a500494f7b8c3e97739f2b" +checksum = "d2153edc6955a6c354fad8f5efd38b6a8769bdccf9fe50f8e1329f81b0baa5d7" dependencies = [ "indexmap 2.14.0", "toml_datetime 1.1.1+spec-1.1.0", @@ -9877,7 +10237,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4cfcf7e2740e6fc6d4d688b4ef00650406bb94adf4731e43c096c3a19fe40840" dependencies = [ "async-compression", - "bitflags 2.11.1", + "bitflags 2.13.0", "bytes", "futures-core", "futures-util", @@ -9924,7 +10284,7 @@ checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -10037,9 +10397,9 @@ checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a" [[package]] name = "typenum" -version = "1.20.0" +version = "1.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40ce102ab67701b8526c123c1bab5cbe42d7040ccfd0f64af1a385808d2f43de" +checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" [[package]] name = "typewit" @@ -10079,9 +10439,9 @@ checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" [[package]] name = "unicode-segmentation" -version = "1.13.2" +version = "1.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9629274872b2bfaf8d66f5f15725007f635594914870f65218920345aa11aa8c" +checksum = "c6f5d3c3b1bf09027a88a6bc961fc00497d651009560b5463668dc81b0fa87a8" [[package]] name = "unicode-xid" @@ -10148,9 +10508,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.23.1" +version = "1.23.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddd74a9687298c6858e9b88ec8935ec45d22e8fd5e6394fa1bd4e99a87789c76" +checksum = "bf80a72845275afea99e7f2b434723d3bc7e38470fcd1c7ed39a599c73319a53" dependencies = [ "js-sys", "wasm-bindgen", @@ -10219,29 +10579,20 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasip2" -version = "1.0.3+wasi-0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20064672db26d7cdc89c7798c48a0fdfac8213434a1186e5ef29fd560ae223d6" -dependencies = [ - "wit-bindgen 0.57.1", -] - -[[package]] -name = "wasip3" -version = "0.4.0+wasi-0.3.0-rc-2026-01-06" +version = "1.0.4+wasi-0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" +checksum = "b67efb37e106e55ce722a510d6b5f9c17f083e5fc79afc2badeb12cc313d9487" dependencies = [ - "wit-bindgen 0.51.0", + "wit-bindgen", ] [[package]] name = "wasm-bindgen" -version = "0.2.121" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49ace1d07c165b0864824eee619580c4689389afa9dc9ed3a4c75040d82e6790" +checksum = "4b067c0c11094aef6b7a801c1e34a26affafdf3d051dba08456b868789aaf9a4" dependencies = [ - "cfg-if", + "cfg-if 1.0.4", "once_cell", "rustversion", "wasm-bindgen-macro", @@ -10250,9 +10601,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.71" +version = "0.4.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96492d0d3ffba25305a7dc88720d250b1401d7edca02cc3bcd50633b424673b8" +checksum = "c62df1340f32221cb9c54d6a27b030e3dba64361d4a95bed55f9aacb44da291d" dependencies = [ "js-sys", "wasm-bindgen", @@ -10260,9 +10611,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.121" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e68e6f4afd367a562002c05637acb8578ff2dea1943df76afb9e83d177c8578" +checksum = "167ce5e579f6bcf889c4f7175a8a5a585de84e8ff93976ce393efa5f2837aab1" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -10270,48 +10621,26 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.121" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d95a9ec35c64b2a7cb35d3fead40c4238d0940c86d107136999567a4703259f2" +checksum = "f3997c7839262f4ef12cf90b818d6340c18e80f263f1a94bf157d0ec4420380e" dependencies = [ "bumpalo", "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.121" +version = "0.2.126" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4e0100b01e9f0d03189a92b96772a1fb998639d981193d7dbab487302513441" +checksum = "dc1b4cb0cc549fcf58d7dfc081778139b3d283a081644e833e84682ad71cea24" dependencies = [ "unicode-ident", ] -[[package]] -name = "wasm-encoder" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" -dependencies = [ - "leb128fmt", - "wasmparser", -] - -[[package]] -name = "wasm-metadata" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" -dependencies = [ - "anyhow", - "indexmap 2.14.0", - "wasm-encoder", - "wasmparser", -] - [[package]] name = "wasm-streams" version = "0.4.2" @@ -10340,18 +10669,6 @@ dependencies = [ "web-sys", ] -[[package]] -name = "wasmparser" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" -dependencies = [ - "bitflags 2.11.1", - "hashbrown 0.15.5", - "indexmap 2.14.0", - "semver 1.0.28", -] - [[package]] name = "wasmtimer" version = "0.4.3" @@ -10368,9 +10685,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.98" +version = "0.3.103" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b572dff8bcf38bad0fa19729c89bb5748b2b9b1d8be70cf90df697e3a8f32aa" +checksum = "8622dcb61c0bcc9fffa6938bed81210af2da9a7e4a1a834b2e37a59b6dfb6141" dependencies = [ "js-sys", "wasm-bindgen", @@ -10388,9 +10705,9 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "1.0.7" +version = "1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52f5ee44c96cf55f1b349600768e3ece3a8f26010c05265ab73f945bb1a2eb9d" +checksum = "bf85cb06032201fa7c6f829d7db5a7e5aa45bcc0655327713065f6f0576731bf" dependencies = [ "rustls-pki-types", ] @@ -10411,6 +10728,15 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +[[package]] +name = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys 0.61.2", +] + [[package]] name = "winapi-x86_64-pc-windows-gnu" version = "0.4.0" @@ -10438,7 +10764,7 @@ checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -10449,7 +10775,7 @@ checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -10493,7 +10819,7 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.6", + "windows-targets", ] [[package]] @@ -10502,16 +10828,7 @@ version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ - "windows-targets 0.52.6", -] - -[[package]] -name = "windows-sys" -version = "0.60.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" -dependencies = [ - "windows-targets 0.53.5", + "windows-targets", ] [[package]] @@ -10529,31 +10846,14 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm 0.52.6", - "windows_aarch64_msvc 0.52.6", - "windows_i686_gnu 0.52.6", - "windows_i686_gnullvm 0.52.6", - "windows_i686_msvc 0.52.6", - "windows_x86_64_gnu 0.52.6", - "windows_x86_64_gnullvm 0.52.6", - "windows_x86_64_msvc 0.52.6", -] - -[[package]] -name = "windows-targets" -version = "0.53.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" -dependencies = [ - "windows-link", - "windows_aarch64_gnullvm 0.53.1", - "windows_aarch64_msvc 0.53.1", - "windows_i686_gnu 0.53.1", - "windows_i686_gnullvm 0.53.1", - "windows_i686_msvc 0.53.1", - "windows_x86_64_gnu 0.53.1", - "windows_x86_64_gnullvm 0.53.1", - "windows_x86_64_msvc 0.53.1", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", ] [[package]] @@ -10562,96 +10862,48 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" - [[package]] name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" -[[package]] -name = "windows_aarch64_msvc" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" - [[package]] name = "windows_i686_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" -[[package]] -name = "windows_i686_gnu" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" - [[package]] name = "windows_i686_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" -[[package]] -name = "windows_i686_gnullvm" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" - [[package]] name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" -[[package]] -name = "windows_i686_msvc" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" - [[package]] name = "windows_x86_64_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" -[[package]] -name = "windows_x86_64_gnu" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" - [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" - [[package]] name = "windows_x86_64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" -[[package]] -name = "windows_x86_64_msvc" -version = "0.53.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" - [[package]] name = "winnow" version = "0.5.40" @@ -10679,100 +10931,12 @@ dependencies = [ "memchr", ] -[[package]] -name = "wit-bindgen" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" -dependencies = [ - "wit-bindgen-rust-macro", -] - [[package]] name = "wit-bindgen" version = "0.57.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e" -[[package]] -name = "wit-bindgen-core" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" -dependencies = [ - "anyhow", - "heck 0.5.0", - "wit-parser", -] - -[[package]] -name = "wit-bindgen-rust" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" -dependencies = [ - "anyhow", - "heck 0.5.0", - "indexmap 2.14.0", - "prettyplease", - "syn 2.0.117", - "wasm-metadata", - "wit-bindgen-core", - "wit-component", -] - -[[package]] -name = "wit-bindgen-rust-macro" -version = "0.51.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" -dependencies = [ - "anyhow", - "prettyplease", - "proc-macro2", - "quote", - "syn 2.0.117", - "wit-bindgen-core", - "wit-bindgen-rust", -] - -[[package]] -name = "wit-component" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" -dependencies = [ - "anyhow", - "bitflags 2.11.1", - "indexmap 2.14.0", - "log", - "serde", - "serde_derive", - "serde_json", - "wasm-encoder", - "wasm-metadata", - "wasmparser", - "wit-parser", -] - -[[package]] -name = "wit-parser" -version = "0.244.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" -dependencies = [ - "anyhow", - "id-arena", - "indexmap 2.14.0", - "log", - "semver 1.0.28", - "serde", - "serde_derive", - "serde_json", - "unicode-xid", - "wasmparser", -] - [[package]] name = "writeable" version = "0.6.3" @@ -10788,11 +10952,21 @@ dependencies = [ "tap", ] +[[package]] +name = "yastl" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ca6c5a4d66c1a9ea261811cf4773c27343de7e5033e1b75ea3f297dc7db3c1a" +dependencies = [ + "flume", + "scopeguard", +] + [[package]] name = "yoke" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abe8c5fda708d9ca3df187cae8bfb9ceda00dd96231bed36e445a1a48e66f9ca" +checksum = "709fe23a0424b6a435d82152b1bd3fdfb0833487d5fa90d05d42762a9891fef5" dependencies = [ "stable_deref_trait", "yoke-derive", @@ -10807,28 +10981,28 @@ checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", "synstructure", ] [[package]] name = "zerocopy" -version = "0.8.48" +version = "0.8.54" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9" +checksum = "b7cbbc0a705a0fd05cc3676525980d2bf5a9bc4adac6d6475209a7887cf59d19" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.48" +version = "0.8.54" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4" +checksum = "e2e817b7b52d0c7358d3246da9d69935ebb18116b2b102b4230dac079b4862f5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -10848,28 +11022,28 @@ checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", "synstructure", ] [[package]] name = "zeroize" -version = "1.8.2" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" +checksum = "e13c156562582aa81c60cb29407084cdb54c4164760106ab78e6c5b0858cf64e" dependencies = [ "zeroize_derive", ] [[package]] name = "zeroize_derive" -version = "1.4.3" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85a5b4158499876c763cb03bc4e49185d3cccbabb15b33c627f7884f43db852e" +checksum = "3c50655cbb0fe3fc43170059e702f1ce5e19b84cec58dc87b037a09935c2f328" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] @@ -10902,13 +11076,14 @@ checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" dependencies = [ "proc-macro2", "quote", - "syn 2.0.117", + "syn 2.0.118", ] [[package]] -name = "zkhash" +name = "zkhash-axiom" version = "0.2.0" -source = "git+https://github.com/HorizenLabs/poseidon2.git?rev=bb476b9#bb476b9ca38198cf5092487283c8b8c5d4317c4e" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d038a7895d0e3ab0a352f53e7eb4f1f829f88fce2fb3cff93d665a8a0e01af6" dependencies = [ "ark-ff 0.4.2", "ark-std 0.4.0", @@ -10916,7 +11091,7 @@ dependencies = [ "blake2", "bls12_381", "byteorder", - "cfg-if", + "cfg-if 1.0.4", "group 0.12.1", "group 0.13.0", "halo2", diff --git a/Cargo.toml b/Cargo.toml index 3bd50a362a..7b0b151dd6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,9 +17,9 @@ repository = "https://github.com/scroll-tech/scroll" version = "4.7.12" [workspace.dependencies] -scroll-zkvm-prover = { git = "https://github.com/scroll-tech/zkvm-prover", rev = "ed3b964" } -scroll-zkvm-verifier = { git = "https://github.com/scroll-tech/zkvm-prover", rev = "ed3b964" } -scroll-zkvm-types = { git = "https://github.com/scroll-tech/zkvm-prover", rev = "ed3b964" } +scroll-zkvm-prover = { git = "https://github.com/scroll-tech/zkvm-prover", rev = "bf887150bb671af9b17dd53e92b7f2bbf01ec745" } +scroll-zkvm-verifier = { git = "https://github.com/scroll-tech/zkvm-prover", rev = "bf887150bb671af9b17dd53e92b7f2bbf01ec745" } +scroll-zkvm-types = { git = "https://github.com/scroll-tech/zkvm-prover", rev = "bf887150bb671af9b17dd53e92b7f2bbf01ec745" } sbv-primitives = { git = "https://github.com/scroll-tech/stateless-block-verifier", tag = "scroll-v91.2", features = ["scroll", "rkyv"] } sbv-utils = { git = "https://github.com/scroll-tech/stateless-block-verifier", tag = "scroll-v91.2" } diff --git a/common/types/message/message.go b/common/types/message/message.go index 7b35d362d8..a9b52f2809 100644 --- a/common/types/message/message.go +++ b/common/types/message/message.go @@ -165,9 +165,18 @@ type OpenVMProofStat struct { // Proof for flatten VM proof type OpenVMProof struct { - Proof []byte `json:"proofs"` - PublicValues []byte `json:"public_values"` - Stat *OpenVMProofStat `json:"stat,omitempty"` + Proof []byte `json:"proofs"` + PublicValues []byte `json:"public_values"` +} + +// Proof for flatten VM stark proof (v0.9.0+). +// Mirrors scroll_zkvm_types::proof::StarkProof used by the OpenVM v2 prover. +type OpenVMStarkProof struct { + Proof []byte `json:"proof"` + UserPvsProof []byte `json:"user_pvs_proof"` + Baseline []byte `json:"baseline,omitempty"` + DeferralMerkleProofs []byte `json:"deferral_merkle_proofs,omitempty"` + Stat *OpenVMProofStat `json:"stat,omitempty"` } // Proof for flatten EVM proof @@ -183,13 +192,13 @@ type OpenVMChunkProof struct { TotalGasUsed uint64 `json:"chunk_total_gas"` } `json:"metadata"` - VmProof *OpenVMProof `json:"proof"` - Vk []byte `json:"vk,omitempty"` - GitVersion string `json:"git_version,omitempty"` + StarkProof *OpenVMStarkProof `json:"proof"` + Vk []byte `json:"vk,omitempty"` + GitVersion string `json:"git_version,omitempty"` } func (p *OpenVMChunkProof) Proof() []byte { - proofJson, err := json.Marshal(p.VmProof) + proofJson, err := json.Marshal(p.StarkProof) if err != nil { panic(fmt.Sprint("marshaling error", err)) } @@ -217,13 +226,13 @@ type OpenVMBatchProof struct { BatchHash common.Hash `json:"batch_hash"` } `json:"metadata"` - VmProof *OpenVMProof `json:"proof"` - Vk []byte `json:"vk,omitempty"` - GitVersion string `json:"git_version,omitempty"` + StarkProof *OpenVMStarkProof `json:"proof"` + Vk []byte `json:"vk,omitempty"` + GitVersion string `json:"git_version,omitempty"` } func (p *OpenVMBatchProof) Proof() []byte { - proofJson, err := json.Marshal(p.VmProof) + proofJson, err := json.Marshal(p.StarkProof) if err != nil { panic(fmt.Sprint("marshaling error", err)) } @@ -240,17 +249,17 @@ func (ap *OpenVMBatchProof) SanityCheck() error { return errors.New("batch info not ready") } - if ap.VmProof == nil { + if ap.StarkProof == nil { return errors.New("proof not ready") } else { if len(ap.Vk) == 0 { return errors.New("vk not ready") } - pf := ap.VmProof - if pf.Proof == nil { + pf := ap.StarkProof + if len(pf.Proof) == 0 { return errors.New("proof data not ready") } - if len(pf.PublicValues) == 0 { + if len(pf.UserPvsProof) == 0 { return errors.New("proof public value not ready") } } diff --git a/coordinator/internal/controller/api/get_task.go b/coordinator/internal/controller/api/get_task.go index c430f45ee3..b8eb0a07a8 100644 --- a/coordinator/internal/controller/api/get_task.go +++ b/coordinator/internal/controller/api/get_task.go @@ -3,7 +3,7 @@ package api import ( "errors" "fmt" - "math/rand" + "sort" "github.com/gin-gonic/gin" "github.com/prometheus/client_golang/prometheus" @@ -79,7 +79,9 @@ func (ptc *GetTaskController) incGetTaskAccessCounter(ctx *gin.Context) error { return nil } -// GetTasks get assigned chunk/batch task +// GetTasks get assigned chunk/batch/bundle task, trying proof types in priority +// order: Bundle > Batch > Chunk. This lets the pipeline finalize the earliest +// ready bundle before proving unrelated chunks/batches further ahead. func (ptc *GetTaskController) GetTasks(ctx *gin.Context) { var getTaskParameter coordinatorType.GetTaskParameter if err := ctx.ShouldBind(&getTaskParameter); err != nil { @@ -99,35 +101,36 @@ func (ptc *GetTaskController) GetTasks(ctx *gin.Context) { } } - proofType := ptc.proofType(&getTaskParameter) - proverTask, isExist := ptc.proverTasks[proofType] - if !isExist { - nerr := fmt.Errorf("parameter wrong proof type:%v", proofType) - types.RenderFailure(ctx, types.ErrCoordinatorParameterInvalidNo, nerr) - return - } + proofTypes := ptc.prioritizedProofTypes(&getTaskParameter) if err := ptc.incGetTaskAccessCounter(ctx); err != nil { log.Warn("get_task access counter inc failed", "error", err.Error()) } - result, err := proverTask.Assign(ctx, &getTaskParameter) - if err != nil { - nerr := fmt.Errorf("return prover task err:%w", err) - types.RenderFailure(ctx, types.ErrCoordinatorGetTaskFailure, nerr) - return - } + for _, proofType := range proofTypes { + proverTask, isExist := ptc.proverTasks[proofType] + if !isExist { + continue + } - if result == nil { - nerr := errors.New("get empty prover task") - types.RenderFailure(ctx, types.ErrCoordinatorEmptyProofData, nerr) - return + result, err := proverTask.Assign(ctx, &getTaskParameter) + if err != nil { + nerr := fmt.Errorf("return prover task err:%w", err) + types.RenderFailure(ctx, types.ErrCoordinatorGetTaskFailure, nerr) + return + } + + if result != nil { + types.RenderSuccess(ctx, result) + return + } } - types.RenderSuccess(ctx, result) + nerr := errors.New("get empty prover task") + types.RenderFailure(ctx, types.ErrCoordinatorEmptyProofData, nerr) } -func (ptc *GetTaskController) proofType(para *coordinatorType.GetTaskParameter) message.ProofType { +func (ptc *GetTaskController) prioritizedProofTypes(para *coordinatorType.GetTaskParameter) []message.ProofType { var proofTypes []message.ProofType for _, proofType := range para.TaskTypes { proofTypes = append(proofTypes, message.ProofType(proofType)) @@ -141,8 +144,9 @@ func (ptc *GetTaskController) proofType(para *coordinatorType.GetTaskParameter) } } - rand.Shuffle(len(proofTypes), func(i, j int) { - proofTypes[i], proofTypes[j] = proofTypes[j], proofTypes[i] + // Bundle (3) > Batch (2) > Chunk (1) + sort.Slice(proofTypes, func(i, j int) bool { + return proofTypes[i] > proofTypes[j] }) - return proofTypes[0] + return proofTypes } diff --git a/coordinator/internal/logic/provertask/batch_prover_task.go b/coordinator/internal/logic/provertask/batch_prover_task.go index 964dba2618..90608cedff 100644 --- a/coordinator/internal/logic/provertask/batch_prover_task.go +++ b/coordinator/internal/logic/provertask/batch_prover_task.go @@ -199,7 +199,7 @@ func (bp *BatchProverTask) Assign(ctx *gin.Context, getTaskParameter *coordinato taskMsg, err := bp.formatProverTask(ctx.Copy(), proverTask, batchTask, hardForkName) if err != nil { - bp.recoverActiveAttempts(ctx, batchTask) + bp.recoverAttempts(ctx, taskCtx, batchTask) log.Error("format prover task failure", "task_id", batchTask.Hash, "err", err) return nil, ErrCoordinatorInternalFailure } @@ -208,7 +208,7 @@ func (bp *BatchProverTask) Assign(ctx *gin.Context, getTaskParameter *coordinato taskMsg, metadata, err = bp.applyUniversal(taskMsg) if err != nil { - bp.recoverActiveAttempts(ctx, batchTask) + bp.recoverAttempts(ctx, taskCtx, batchTask) log.Error("Generate universal prover task failure", "task_id", batchTask.Hash, "type", "batch", "err", err) return nil, ErrCoordinatorInternalFailure } @@ -217,7 +217,8 @@ func (bp *BatchProverTask) Assign(ctx *gin.Context, getTaskParameter *coordinato if isCompatibilityFixingVersion(taskCtx.ProverVersion) { log.Info("Apply compatibility fixing for prover", "version", taskCtx.ProverVersion) if err := fixCompatibility(taskMsg); err != nil { - log.Error("apply compatibility failure", "err", err) + bp.recoverAttempts(ctx, taskCtx, batchTask) + log.Error("apply compatibility failure", "task_id", batchTask.Hash, "err", err) return nil, ErrCoordinatorInternalFailure } } @@ -226,7 +227,7 @@ func (bp *BatchProverTask) Assign(ctx *gin.Context, getTaskParameter *coordinato // Store session info. if taskCtx.hasAssignedTask == nil { if err = bp.proverTaskOrm.InsertProverTask(ctx.Copy(), proverTask); err != nil { - bp.recoverActiveAttempts(ctx, batchTask) + bp.recoverAttempts(ctx, taskCtx, batchTask) log.Error("insert batch prover task info fail", "task_id", batchTask.Hash, "publicKey", taskCtx.PublicKey, "err", err) return nil, ErrCoordinatorInternalFailure } @@ -288,7 +289,17 @@ func (bp *BatchProverTask) formatProverTask(ctx context.Context, task *orm.Prove return taskMsg, nil } -func (bp *BatchProverTask) recoverActiveAttempts(ctx *gin.Context, batchTask *orm.Batch) { +// recoverAttempts rolls back the attempt charged by UpdateBatchAttempts when the coordinator +// fails to dispatch a freshly assigned task (hasAssignedTask == nil): both counters are refunded +// and proving_status is reset to unassigned. For a re-poll of an already assigned task nothing +// was charged in this call, so only active_attempts is decremented as before. +func (bp *BatchProverTask) recoverAttempts(ctx *gin.Context, taskCtx *proverTaskContext, batchTask *orm.Batch) { + if taskCtx.hasAssignedTask == nil { + if err := bp.batchOrm.RefundAttemptsByHash(ctx.Copy(), batchTask.Hash); err != nil { + log.Error("failed to refund batch attempts", "hash", batchTask.Hash, "error", err) + } + return + } if err := bp.batchOrm.DecreaseActiveAttemptsByHash(ctx.Copy(), batchTask.Hash); err != nil { log.Error("failed to recover batch active attempts", "hash", batchTask.Hash, "error", err) } diff --git a/coordinator/internal/logic/provertask/bundle_prover_task.go b/coordinator/internal/logic/provertask/bundle_prover_task.go index 81fddfd702..37ed669d5e 100644 --- a/coordinator/internal/logic/provertask/bundle_prover_task.go +++ b/coordinator/internal/logic/provertask/bundle_prover_task.go @@ -196,7 +196,7 @@ func (bp *BundleProverTask) Assign(ctx *gin.Context, getTaskParameter *coordinat taskMsg, err := bp.formatProverTask(ctx.Copy(), proverTask, hardForkName) if err != nil { - bp.recoverActiveAttempts(ctx, bundleTask) + bp.recoverAttempts(ctx, taskCtx, bundleTask) log.Error("format bundle prover task failure", "task_id", bundleTask.Hash, "err", err) return nil, ErrCoordinatorInternalFailure } @@ -204,7 +204,7 @@ func (bp *BundleProverTask) Assign(ctx *gin.Context, getTaskParameter *coordinat var metadata []byte taskMsg, metadata, err = bp.applyUniversal(taskMsg) if err != nil { - bp.recoverActiveAttempts(ctx, bundleTask) + bp.recoverAttempts(ctx, taskCtx, bundleTask) log.Error("Generate universal prover task failure", "task_id", bundleTask.Hash, "type", "bundle", "err", err) return nil, ErrCoordinatorInternalFailure } @@ -215,7 +215,8 @@ func (bp *BundleProverTask) Assign(ctx *gin.Context, getTaskParameter *coordinat if isCompatibilityFixingVersion(taskCtx.ProverVersion) { log.Info("Apply compatibility fixing for prover", "version", taskCtx.ProverVersion) if err := fixCompatibility(taskMsg); err != nil { - log.Error("apply compatibility failure", "err", err) + bp.recoverAttempts(ctx, taskCtx, bundleTask) + log.Error("apply compatibility failure", "task_id", bundleTask.Hash, "err", err) return nil, ErrCoordinatorInternalFailure } } @@ -224,7 +225,7 @@ func (bp *BundleProverTask) Assign(ctx *gin.Context, getTaskParameter *coordinat // Store session info. if taskCtx.hasAssignedTask == nil { if err = bp.proverTaskOrm.InsertProverTask(ctx.Copy(), proverTask); err != nil { - bp.recoverActiveAttempts(ctx, bundleTask) + bp.recoverAttempts(ctx, taskCtx, bundleTask) log.Error("insert bundle prover task info fail", "task_id", bundleTask.Hash, "publicKey", taskCtx.PublicKey, "err", err) return nil, ErrCoordinatorInternalFailure } @@ -313,7 +314,17 @@ func (bp *BundleProverTask) formatProverTask(ctx context.Context, task *orm.Prov return taskMsg, nil } -func (bp *BundleProverTask) recoverActiveAttempts(ctx *gin.Context, bundleTask *orm.Bundle) { +// recoverAttempts rolls back the attempt charged by UpdateBundleAttempts when the coordinator +// fails to dispatch a freshly assigned task (hasAssignedTask == nil): both counters are refunded +// and proving_status is reset to unassigned. For a re-poll of an already assigned task nothing +// was charged in this call, so only active_attempts is decremented as before. +func (bp *BundleProverTask) recoverAttempts(ctx *gin.Context, taskCtx *proverTaskContext, bundleTask *orm.Bundle) { + if taskCtx.hasAssignedTask == nil { + if err := bp.bundleOrm.RefundAttemptsByHash(ctx.Copy(), bundleTask.Hash); err != nil { + log.Error("failed to refund bundle attempts", "hash", bundleTask.Hash, "error", err) + } + return + } if err := bp.bundleOrm.DecreaseActiveAttemptsByHash(ctx.Copy(), bundleTask.Hash); err != nil { log.Error("failed to recover bundle active attempts", "hash", bundleTask.Hash, "error", err) } diff --git a/coordinator/internal/logic/provertask/chunk_prover_task.go b/coordinator/internal/logic/provertask/chunk_prover_task.go index 6492c10a10..0987c0517b 100644 --- a/coordinator/internal/logic/provertask/chunk_prover_task.go +++ b/coordinator/internal/logic/provertask/chunk_prover_task.go @@ -194,7 +194,7 @@ func (cp *ChunkProverTask) Assign(ctx *gin.Context, getTaskParameter *coordinato taskMsg, err := cp.formatProverTask(ctx.Copy(), proverTask, chunkTask, hardForkName) if err != nil { - cp.recoverActiveAttempts(ctx, chunkTask) + cp.recoverAttempts(ctx, taskCtx, chunkTask) log.Error("format prover task failure", "task_id", chunkTask.Hash, "err", err) return nil, ErrCoordinatorInternalFailure } @@ -203,7 +203,7 @@ func (cp *ChunkProverTask) Assign(ctx *gin.Context, getTaskParameter *coordinato var metadata []byte taskMsg, metadata, err = cp.applyUniversal(taskMsg) if err != nil { - cp.recoverActiveAttempts(ctx, chunkTask) + cp.recoverAttempts(ctx, taskCtx, chunkTask) log.Error("Generate universal prover task failure", "task_id", chunkTask.Hash, "type", "chunk", "err", err) return nil, ErrCoordinatorInternalFailure } @@ -212,7 +212,7 @@ func (cp *ChunkProverTask) Assign(ctx *gin.Context, getTaskParameter *coordinato if taskCtx.hasAssignedTask == nil { if err = cp.proverTaskOrm.InsertProverTask(ctx.Copy(), proverTask); err != nil { - cp.recoverActiveAttempts(ctx, chunkTask) + cp.recoverAttempts(ctx, taskCtx, chunkTask) log.Error("insert chunk prover task fail", "task_id", chunkTask.Hash, "publicKey", taskCtx.PublicKey, "err", err) return nil, ErrCoordinatorInternalFailure } @@ -269,7 +269,17 @@ func (cp *ChunkProverTask) formatProverTask(ctx context.Context, task *orm.Prove return proverTaskSchema, nil } -func (cp *ChunkProverTask) recoverActiveAttempts(ctx *gin.Context, chunkTask *orm.Chunk) { +// recoverAttempts rolls back the attempt charged by UpdateChunkAttempts when the coordinator +// fails to dispatch a freshly assigned task (hasAssignedTask == nil): both counters are refunded +// and proving_status is reset to unassigned. For a re-poll of an already assigned task nothing +// was charged in this call, so only active_attempts is decremented as before. +func (cp *ChunkProverTask) recoverAttempts(ctx *gin.Context, taskCtx *proverTaskContext, chunkTask *orm.Chunk) { + if taskCtx.hasAssignedTask == nil { + if err := cp.chunkOrm.RefundAttemptsByHash(ctx, chunkTask.Hash); err != nil { + log.Error("failed to refund chunk attempts", "hash", chunkTask.Hash, "error", err) + } + return + } if err := cp.chunkOrm.DecreaseActiveAttemptsByHash(ctx, chunkTask.Hash); err != nil { log.Error("failed to recover chunk active attempts", "hash", chunkTask.Hash, "error", err) } diff --git a/coordinator/internal/logic/submitproof/proof_receiver.go b/coordinator/internal/logic/submitproof/proof_receiver.go index e9d4c5abe5..5c4b51d03f 100644 --- a/coordinator/internal/logic/submitproof/proof_receiver.go +++ b/coordinator/internal/logic/submitproof/proof_receiver.go @@ -232,7 +232,7 @@ func (m *ProofReceiverLogic) HandleZkProof(ctx *gin.Context, proofParameter coor return unmarshalErr } success, verifyErr = m.verifier.VerifyChunkProof(chunkProof, hardForkName) - if stat := chunkProof.VmProof.Stat; stat != nil { + if stat := chunkProof.StarkProof.Stat; stat != nil { if g, _ := m.proverSpeed.GetMetricWithLabelValues("chunk", "exec"); g != nil && stat.ExecutionTimeMills > 0 { g.Set(float64(stat.TotalCycle) / float64(stat.ExecutionTimeMills*1000)) } @@ -252,7 +252,7 @@ func (m *ProofReceiverLogic) HandleZkProof(ctx *gin.Context, proofParameter coor return unmarshalErr } success, verifyErr = m.verifier.VerifyBatchProof(batchProof, hardForkName) - if stat := batchProof.VmProof.Stat; stat != nil { + if stat := batchProof.StarkProof.Stat; stat != nil { if g, _ := m.proverSpeed.GetMetricWithLabelValues("batch", "exec"); g != nil && stat.ExecutionTimeMills > 0 { g.Set(float64(stat.TotalCycle) / float64(stat.ExecutionTimeMills*1000)) } diff --git a/coordinator/internal/logic/verifier/mock.go b/coordinator/internal/logic/verifier/mock.go index a79ed8d8fc..9e602aa44f 100644 --- a/coordinator/internal/logic/verifier/mock.go +++ b/coordinator/internal/logic/verifier/mock.go @@ -21,7 +21,7 @@ func NewVerifier(cfg *config.VerifierConfig, _ bool) (*Verifier, error) { // VerifyChunkProof return a mock verification result for a ChunkProof. func (v *Verifier) VerifyChunkProof(proof *message.OpenVMChunkProof, forkName string) (bool, error) { - if proof.VmProof != nil && string(proof.VmProof.Proof) == InvalidTestProof { + if proof.StarkProof != nil && string(proof.StarkProof.Proof) == InvalidTestProof { return false, nil } return true, nil @@ -29,7 +29,7 @@ func (v *Verifier) VerifyChunkProof(proof *message.OpenVMChunkProof, forkName st // VerifyBatchProof return a mock verification result for a BatchProof. func (v *Verifier) VerifyBatchProof(proof *message.OpenVMBatchProof, forkName string) (bool, error) { - if proof.VmProof != nil && string(proof.VmProof.Proof) == InvalidTestProof { + if proof.StarkProof != nil && string(proof.StarkProof.Proof) == InvalidTestProof { return false, nil } return true, nil diff --git a/coordinator/internal/orm/batch.go b/coordinator/internal/orm/batch.go index 51e904a016..72bdae6d2c 100644 --- a/coordinator/internal/orm/batch.go +++ b/coordinator/internal/orm/batch.go @@ -211,13 +211,25 @@ func (o *Batch) GetAttemptsByHash(ctx context.Context, hash string) (int16, int1 func (o *Batch) CheckIfBundleBatchProofsAreReady(ctx context.Context, bundleHash string) (bool, error) { db := o.db.WithContext(ctx) db = db.Model(&Batch{}) + db = db.Where("bundle_hash = ?", bundleHash) + + var totalCount int64 + if err := db.Count(&totalCount).Error; err != nil { + return false, fmt.Errorf("Batch.CheckIfBundleBatchProofsAreReady error: %w, bundle hash: %v", err, bundleHash) + } + if totalCount == 0 { + return false, nil + } + + db = o.db.WithContext(ctx) + db = db.Model(&Batch{}) db = db.Where("bundle_hash = ? AND proving_status != ?", bundleHash, types.ProvingTaskVerified) - var count int64 - if err := db.Count(&count).Error; err != nil { - return false, fmt.Errorf("Chunk.CheckIfBundleBatchProofsAreReady error: %w, bundle hash: %v", err, bundleHash) + var unreadyCount int64 + if err := db.Count(&unreadyCount).Error; err != nil { + return false, fmt.Errorf("Batch.CheckIfBundleBatchProofsAreReady error: %w, bundle hash: %v", err, bundleHash) } - return count == 0, nil + return unreadyCount == 0, nil } // GetBatchByHash retrieves the given batch. @@ -459,3 +471,32 @@ func (o *Batch) DecreaseActiveAttemptsByHash(ctx context.Context, batchHash stri } return nil } + +// RefundAttemptsByHash refunds a full assignment attempt of a batch given its hash: +// it decrements both total_attempts and active_attempts and resets proving_status to unassigned. +// It is used to roll back UpdateBatchAttempts when the coordinator fails to dispatch the task +// (e.g. task formatting or prover task insertion failure), so the attempt is not burned permanently. +func (o *Batch) RefundAttemptsByHash(ctx context.Context, batchHash string, dbTX ...*gorm.DB) error { + db := o.db + if len(dbTX) > 0 && dbTX[0] != nil { + db = dbTX[0] + } + db = db.WithContext(ctx) + db = db.Model(&Batch{}) + db = db.Where("hash = ?", batchHash) + db = db.Where("total_attempts > ?", 0) + db = db.Where("active_attempts > ?", 0) + db = db.Where("proving_status != ?", int(types.ProvingTaskVerified)) + result := db.Updates(map[string]interface{}{ + "total_attempts": gorm.Expr("total_attempts - 1"), + "active_attempts": gorm.Expr("active_attempts - 1"), + "proving_status": int(types.ProvingTaskUnassigned), + }) + if result.Error != nil { + return fmt.Errorf("Batch.RefundAttemptsByHash error: %w, batch hash: %v", result.Error, batchHash) + } + if result.RowsAffected == 0 { + log.Warn("No rows were affected in RefundAttemptsByHash", "batch hash", batchHash) + } + return nil +} diff --git a/coordinator/internal/orm/bundle.go b/coordinator/internal/orm/bundle.go index 4e4e22ea17..acd6793ec3 100644 --- a/coordinator/internal/orm/bundle.go +++ b/coordinator/internal/orm/bundle.go @@ -243,3 +243,32 @@ func (o *Bundle) DecreaseActiveAttemptsByHash(ctx context.Context, bundleHash st } return nil } + +// RefundAttemptsByHash refunds a full assignment attempt of a bundle given its hash: +// it decrements both total_attempts and active_attempts and resets proving_status to unassigned. +// It is used to roll back UpdateBundleAttempts when the coordinator fails to dispatch the task +// (e.g. task formatting or prover task insertion failure), so the attempt is not burned permanently. +func (o *Bundle) RefundAttemptsByHash(ctx context.Context, bundleHash string, dbTX ...*gorm.DB) error { + db := o.db + if len(dbTX) > 0 && dbTX[0] != nil { + db = dbTX[0] + } + db = db.WithContext(ctx) + db = db.Model(&Bundle{}) + db = db.Where("hash = ?", bundleHash) + db = db.Where("total_attempts > ?", 0) + db = db.Where("active_attempts > ?", 0) + db = db.Where("proving_status != ?", int(types.ProvingTaskVerified)) + result := db.Updates(map[string]interface{}{ + "total_attempts": gorm.Expr("total_attempts - 1"), + "active_attempts": gorm.Expr("active_attempts - 1"), + "proving_status": int(types.ProvingTaskUnassigned), + }) + if result.Error != nil { + return fmt.Errorf("Bundle.RefundAttemptsByHash error: %w, bundle hash: %v", result.Error, bundleHash) + } + if result.RowsAffected == 0 { + log.Warn("No rows were affected in RefundAttemptsByHash", "bundle hash", bundleHash) + } + return nil +} diff --git a/coordinator/internal/orm/chunk.go b/coordinator/internal/orm/chunk.go index cfefa2ea6c..6faa552887 100644 --- a/coordinator/internal/orm/chunk.go +++ b/coordinator/internal/orm/chunk.go @@ -171,13 +171,25 @@ func (o *Chunk) GetProvingStatusByHash(ctx context.Context, hash string) (types. func (o *Chunk) CheckIfBatchChunkProofsAreReady(ctx context.Context, batchHash string) (bool, error) { db := o.db.WithContext(ctx) db = db.Model(&Chunk{}) + db = db.Where("batch_hash = ?", batchHash) + + var totalCount int64 + if err := db.Count(&totalCount).Error; err != nil { + return false, fmt.Errorf("Chunk.CheckIfBatchChunkProofsAreReady error: %w, batch hash: %v", err, batchHash) + } + if totalCount == 0 { + return false, nil + } + + db = o.db.WithContext(ctx) + db = db.Model(&Chunk{}) db = db.Where("batch_hash = ? AND proving_status != ?", batchHash, types.ProvingTaskVerified) - var count int64 - if err := db.Count(&count).Error; err != nil { + var unreadyCount int64 + if err := db.Count(&unreadyCount).Error; err != nil { return false, fmt.Errorf("Chunk.CheckIfBatchChunkProofsAreReady error: %w, batch hash: %v", err, batchHash) } - return count == 0, nil + return unreadyCount == 0, nil } // GetChunkByHash retrieves the given chunk. @@ -410,3 +422,32 @@ func (o *Chunk) DecreaseActiveAttemptsByHash(ctx context.Context, chunkHash stri } return nil } + +// RefundAttemptsByHash refunds a full assignment attempt of a chunk given its hash: +// it decrements both total_attempts and active_attempts and resets proving_status to unassigned. +// It is used to roll back UpdateChunkAttempts when the coordinator fails to dispatch the task +// (e.g. task formatting or prover task insertion failure), so the attempt is not burned permanently. +func (o *Chunk) RefundAttemptsByHash(ctx context.Context, chunkHash string, dbTX ...*gorm.DB) error { + db := o.db + if len(dbTX) > 0 && dbTX[0] != nil { + db = dbTX[0] + } + db = db.WithContext(ctx) + db = db.Model(&Chunk{}) + db = db.Where("hash = ?", chunkHash) + db = db.Where("total_attempts > ?", 0) + db = db.Where("active_attempts > ?", 0) + db = db.Where("proving_status != ?", int(types.ProvingTaskVerified)) + result := db.Updates(map[string]interface{}{ + "total_attempts": gorm.Expr("total_attempts - 1"), + "active_attempts": gorm.Expr("active_attempts - 1"), + "proving_status": int(types.ProvingTaskUnassigned), + }) + if result.Error != nil { + return fmt.Errorf("Chunk.RefundAttemptsByHash error: %w, chunk hash: %v", result.Error, chunkHash) + } + if result.RowsAffected == 0 { + log.Warn("No rows were affected in RefundAttemptsByHash", "chunk hash", chunkHash) + } + return nil +} diff --git a/coordinator/internal/orm/orm_test.go b/coordinator/internal/orm/orm_test.go index a653237edf..b63668f03b 100644 --- a/coordinator/internal/orm/orm_test.go +++ b/coordinator/internal/orm/orm_test.go @@ -121,3 +121,183 @@ func TestProverTaskOrmUint256(t *testing.T) { assert.Equal(t, resultRewardUint256, rewardUint256) assert.Equal(t, resultRewardUint256.String(), "115792089237316195423570985008687907853269984665640564039457584007913129639935") } + +func TestChunkRefundAttemptsByHash(t *testing.T) { + sqlDB, err := db.DB() + assert.NoError(t, err) + assert.NoError(t, migrate.ResetDB(sqlDB)) + + chunkOrm := NewChunk(db) + insertChunk := func(index uint64, hash string, provingStatus, totalAttempts, activeAttempts int16) { + execErr := db.Exec(`INSERT INTO chunk (index, hash, start_block_number, start_block_hash, end_block_number, end_block_hash, + total_l1_messages_popped_before, total_l1_messages_popped_in_chunk, start_block_time, parent_chunk_hash, state_root, + parent_chunk_state_root, withdraw_root, total_l2_tx_gas, total_l2_tx_num, total_l1_commit_calldata_size, total_l1_commit_gas, + proving_status, total_attempts, active_attempts) + VALUES (?, ?, 1, '0x1', 2, '0x2', 0, 0, 0, '0x0', '0x3', '0x0', '0x4', 0, 0, 0, 0, ?, ?, ?)`, + index, hash, provingStatus, totalAttempts, activeAttempts).Error + assert.NoError(t, execErr) + } + + // (a) charge via UpdateChunkAttempts then refund -> both counters back to 0, status back to unassigned + insertChunk(1, "0xchunk-a", int16(types.ProvingTaskUnassigned), 0, 0) + rowsAffected, err := chunkOrm.UpdateChunkAttempts(context.Background(), 1, 0, 0) + assert.NoError(t, err) + assert.Equal(t, int64(1), rowsAffected) + active, total, err := chunkOrm.GetAttemptsByHash(context.Background(), "0xchunk-a") + assert.NoError(t, err) + assert.Equal(t, int16(1), active) + assert.Equal(t, int16(1), total) + status, err := chunkOrm.GetProvingStatusByHash(context.Background(), "0xchunk-a") + assert.NoError(t, err) + assert.Equal(t, types.ProvingTaskAssigned, status) + + assert.NoError(t, chunkOrm.RefundAttemptsByHash(context.Background(), "0xchunk-a")) + active, total, err = chunkOrm.GetAttemptsByHash(context.Background(), "0xchunk-a") + assert.NoError(t, err) + assert.Equal(t, int16(0), active) + assert.Equal(t, int16(0), total) + status, err = chunkOrm.GetProvingStatusByHash(context.Background(), "0xchunk-a") + assert.NoError(t, err) + assert.Equal(t, types.ProvingTaskUnassigned, status) + + // (b) refund on a verified row -> no-op + insertChunk(2, "0xchunk-b", int16(types.ProvingTaskVerified), 1, 1) + assert.NoError(t, chunkOrm.RefundAttemptsByHash(context.Background(), "0xchunk-b")) + active, total, err = chunkOrm.GetAttemptsByHash(context.Background(), "0xchunk-b") + assert.NoError(t, err) + assert.Equal(t, int16(1), active) + assert.Equal(t, int16(1), total) + status, err = chunkOrm.GetProvingStatusByHash(context.Background(), "0xchunk-b") + assert.NoError(t, err) + assert.Equal(t, types.ProvingTaskVerified, status) + + // (c) refund when attempts are already 0 -> no underflow, row unchanged + insertChunk(3, "0xchunk-c", int16(types.ProvingTaskAssigned), 0, 0) + assert.NoError(t, chunkOrm.RefundAttemptsByHash(context.Background(), "0xchunk-c")) + active, total, err = chunkOrm.GetAttemptsByHash(context.Background(), "0xchunk-c") + assert.NoError(t, err) + assert.Equal(t, int16(0), active) + assert.Equal(t, int16(0), total) + status, err = chunkOrm.GetProvingStatusByHash(context.Background(), "0xchunk-c") + assert.NoError(t, err) + assert.Equal(t, types.ProvingTaskAssigned, status) +} + +func TestBatchRefundAttemptsByHash(t *testing.T) { + sqlDB, err := db.DB() + assert.NoError(t, err) + assert.NoError(t, migrate.ResetDB(sqlDB)) + + batchOrm := NewBatch(db) + insertBatch := func(index uint64, hash string, provingStatus, totalAttempts, activeAttempts int16) { + execErr := db.Exec(`INSERT INTO batch (index, hash, start_chunk_index, start_chunk_hash, end_chunk_index, end_chunk_hash, + state_root, withdraw_root, parent_batch_hash, batch_header, proving_status, total_attempts, active_attempts) + VALUES (?, ?, 1, '0x1', 2, '0x2', '0x3', '0x4', '0x0', ?, ?, ?, ?)`, + index, hash, []byte{0}, provingStatus, totalAttempts, activeAttempts).Error + assert.NoError(t, execErr) + } + + // (a) charge via UpdateBatchAttempts then refund -> both counters back to 0, status back to unassigned + insertBatch(1, "0xbatch-a", int16(types.ProvingTaskUnassigned), 0, 0) + rowsAffected, err := batchOrm.UpdateBatchAttempts(context.Background(), 1, 0, 0) + assert.NoError(t, err) + assert.Equal(t, int64(1), rowsAffected) + active, total, err := batchOrm.GetAttemptsByHash(context.Background(), "0xbatch-a") + assert.NoError(t, err) + assert.Equal(t, int16(1), active) + assert.Equal(t, int16(1), total) + status, err := batchOrm.GetProvingStatusByHash(context.Background(), "0xbatch-a") + assert.NoError(t, err) + assert.Equal(t, types.ProvingTaskAssigned, status) + + assert.NoError(t, batchOrm.RefundAttemptsByHash(context.Background(), "0xbatch-a")) + active, total, err = batchOrm.GetAttemptsByHash(context.Background(), "0xbatch-a") + assert.NoError(t, err) + assert.Equal(t, int16(0), active) + assert.Equal(t, int16(0), total) + status, err = batchOrm.GetProvingStatusByHash(context.Background(), "0xbatch-a") + assert.NoError(t, err) + assert.Equal(t, types.ProvingTaskUnassigned, status) + + // (b) refund on a verified row -> no-op + insertBatch(2, "0xbatch-b", int16(types.ProvingTaskVerified), 1, 1) + assert.NoError(t, batchOrm.RefundAttemptsByHash(context.Background(), "0xbatch-b")) + active, total, err = batchOrm.GetAttemptsByHash(context.Background(), "0xbatch-b") + assert.NoError(t, err) + assert.Equal(t, int16(1), active) + assert.Equal(t, int16(1), total) + status, err = batchOrm.GetProvingStatusByHash(context.Background(), "0xbatch-b") + assert.NoError(t, err) + assert.Equal(t, types.ProvingTaskVerified, status) + + // (c) refund when attempts are already 0 -> no underflow, row unchanged + insertBatch(3, "0xbatch-c", int16(types.ProvingTaskAssigned), 0, 0) + assert.NoError(t, batchOrm.RefundAttemptsByHash(context.Background(), "0xbatch-c")) + active, total, err = batchOrm.GetAttemptsByHash(context.Background(), "0xbatch-c") + assert.NoError(t, err) + assert.Equal(t, int16(0), active) + assert.Equal(t, int16(0), total) + status, err = batchOrm.GetProvingStatusByHash(context.Background(), "0xbatch-c") + assert.NoError(t, err) + assert.Equal(t, types.ProvingTaskAssigned, status) +} + +func TestBundleRefundAttemptsByHash(t *testing.T) { + sqlDB, err := db.DB() + assert.NoError(t, err) + assert.NoError(t, migrate.ResetDB(sqlDB)) + + bundleOrm := NewBundle(db) + insertBundle := func(hash string, provingStatus, totalAttempts, activeAttempts int16) { + execErr := db.Exec(`INSERT INTO bundle (hash, start_batch_index, end_batch_index, start_batch_hash, end_batch_hash, + codec_version, proving_status, total_attempts, active_attempts) + VALUES (?, 1, 2, '0x1', '0x2', 10, ?, ?, ?)`, + hash, provingStatus, totalAttempts, activeAttempts).Error + assert.NoError(t, execErr) + } + getAttempts := func(hash string) (int16, int16) { + bundle, getErr := bundleOrm.GetBundleByHash(context.Background(), hash) + assert.NoError(t, getErr) + return bundle.ActiveAttempts, bundle.TotalAttempts + } + + // (a) charge via UpdateBundleAttempts then refund -> both counters back to 0, status back to unassigned + insertBundle("0xbundle-a", int16(types.ProvingTaskUnassigned), 0, 0) + rowsAffected, err := bundleOrm.UpdateBundleAttempts(context.Background(), "0xbundle-a", 0, 0) + assert.NoError(t, err) + assert.Equal(t, int64(1), rowsAffected) + active, total := getAttempts("0xbundle-a") + assert.Equal(t, int16(1), active) + assert.Equal(t, int16(1), total) + status, err := bundleOrm.GetProvingStatusByHash(context.Background(), "0xbundle-a") + assert.NoError(t, err) + assert.Equal(t, types.ProvingTaskAssigned, status) + + assert.NoError(t, bundleOrm.RefundAttemptsByHash(context.Background(), "0xbundle-a")) + active, total = getAttempts("0xbundle-a") + assert.Equal(t, int16(0), active) + assert.Equal(t, int16(0), total) + status, err = bundleOrm.GetProvingStatusByHash(context.Background(), "0xbundle-a") + assert.NoError(t, err) + assert.Equal(t, types.ProvingTaskUnassigned, status) + + // (b) refund on a verified row -> no-op + insertBundle("0xbundle-b", int16(types.ProvingTaskVerified), 1, 1) + assert.NoError(t, bundleOrm.RefundAttemptsByHash(context.Background(), "0xbundle-b")) + active, total = getAttempts("0xbundle-b") + assert.Equal(t, int16(1), active) + assert.Equal(t, int16(1), total) + status, err = bundleOrm.GetProvingStatusByHash(context.Background(), "0xbundle-b") + assert.NoError(t, err) + assert.Equal(t, types.ProvingTaskVerified, status) + + // (c) refund when attempts are already 0 -> no underflow, row unchanged + insertBundle("0xbundle-c", int16(types.ProvingTaskAssigned), 0, 0) + assert.NoError(t, bundleOrm.RefundAttemptsByHash(context.Background(), "0xbundle-c")) + active, total = getAttempts("0xbundle-c") + assert.Equal(t, int16(0), active) + assert.Equal(t, int16(0), total) + status, err = bundleOrm.GetProvingStatusByHash(context.Background(), "0xbundle-c") + assert.NoError(t, err) + assert.Equal(t, types.ProvingTaskAssigned, status) +} diff --git a/coordinator/test/api_test.go b/coordinator/test/api_test.go index 9fc303d760..68ad38f392 100644 --- a/coordinator/test/api_test.go +++ b/coordinator/test/api_test.go @@ -687,7 +687,7 @@ func testTimeoutProof(t *testing.T) { assert.NoError(t, err) err = chunkOrm.UpdateBatchHashInRange(context.Background(), 0, 100, batch.Hash) assert.NoError(t, err) - encodeData, err := json.Marshal(message.OpenVMChunkProof{VmProof: &message.OpenVMProof{}, MetaData: struct { + encodeData, err := json.Marshal(message.OpenVMChunkProof{StarkProof: &message.OpenVMStarkProof{}, MetaData: struct { ChunkInfo *message.ChunkInfo `json:"chunk_info"` TotalGasUsed uint64 `json:"chunk_total_gas"` }{ChunkInfo: &message.ChunkInfo{}}}) diff --git a/coordinator/test/mock_prover.go b/coordinator/test/mock_prover.go index 913344e856..d2c29946ec 100644 --- a/coordinator/test/mock_prover.go +++ b/coordinator/test/mock_prover.go @@ -229,7 +229,7 @@ func (r *mockProver) submitProof(t *testing.T, proverTaskSchema *types.GetTaskSc case message.ProofTypeChunk: fallthrough case message.ProofTypeBatch: - encodeData, err := json.Marshal(&message.OpenVMProof{}) + encodeData, err := json.Marshal(&message.OpenVMStarkProof{}) assert.NoError(t, err) assert.NotEmpty(t, encodeData) proof = encodeData @@ -245,7 +245,7 @@ func (r *mockProver) submitProof(t *testing.T, proverTaskSchema *types.GetTaskSc case message.ProofTypeChunk: fallthrough case message.ProofTypeBatch: - encodeData, err := json.Marshal(&message.OpenVMProof{Proof: []byte(verifier.InvalidTestProof)}) + encodeData, err := json.Marshal(&message.OpenVMStarkProof{Proof: []byte(verifier.InvalidTestProof), UserPvsProof: []byte{0x01}}) assert.NoError(t, err) assert.NotEmpty(t, encodeData) proof = encodeData diff --git a/crates/libzkp/Cargo.toml b/crates/libzkp/Cargo.toml index d673efc9f0..abafd17a2b 100644 --- a/crates/libzkp/Cargo.toml +++ b/crates/libzkp/Cargo.toml @@ -7,6 +7,8 @@ edition.workspace = true [dependencies] scroll-zkvm-types = { workspace = true, features = ["scroll"] } scroll-zkvm-verifier.workspace = true +openvm-sdk = { git = "https://github.com/openvm-org/openvm.git", tag = "v2.0.0" } +openvm-stark-sdk = { git = "https://github.com/openvm-org/stark-backend.git", tag = "v2.0.0" } alloy-primitives.workspace = true #depress the effect of "native-keccak" sbv-primitives = {workspace = true, features = ["scroll-compress-info", "scroll"]} diff --git a/crates/libzkp/src/lib.rs b/crates/libzkp/src/lib.rs index f808cf7cad..8351b8723a 100644 --- a/crates/libzkp/src/lib.rs +++ b/crates/libzkp/src/lib.rs @@ -55,43 +55,8 @@ pub fn checkout_chunk_task( /// Convert the universal task json into compatible form for old prover pub fn univ_task_compatibility_fix(task_json: &str) -> eyre::Result { - use scroll_zkvm_types::proof::VmInternalStarkProof; - - let task: tasks::ProvingTask = serde_json::from_str(task_json)?; - let aggregated_proofs: Vec = task - .aggregated_proofs - .into_iter() - .map(|proof| VmInternalStarkProof { - proofs: proof.proofs, - public_values: proof.public_values, - }) - .collect(); - - #[derive(Serialize)] - struct CompatibleProvingTask { - /// seralized witness which should be written into stdin first - pub serialized_witness: Vec>, - /// aggregated proof carried by babybear fields, should be written into stdin - /// followed `serialized_witness` - pub aggregated_proofs: Vec, - /// Fork name specify - pub fork_name: String, - /// The vk of app which is expcted to prove this task - pub vk: Vec, - /// An identifier assigned by coordinator, it should be kept identify for the - /// same task (for example, using chunk, batch and bundle hashes) - pub identifier: String, - } - - let compatible_u_task = CompatibleProvingTask { - serialized_witness: task.serialized_witness, - aggregated_proofs, - fork_name: task.fork_name, - vk: task.vk, - identifier: task.identifier, - }; - - Ok(serde_json::to_string(&compatible_u_task)?) + // v0.9.0+ provers consume the new ProvingTask format directly; no translation needed. + Ok(task_json.to_string()) } /// Generate required staff for proving tasks diff --git a/crates/libzkp/src/tasks/batch.rs b/crates/libzkp/src/tasks/batch.rs index 9d36d1f01f..46ba7cd516 100644 --- a/crates/libzkp/src/tasks/batch.rs +++ b/crates/libzkp/src/tasks/batch.rs @@ -131,6 +131,7 @@ impl BatchProvingTask { .collect(), serialized_witness: vec![serialized_witness], vk: Vec::new(), + input_commits: Vec::new(), }; Ok((proving_task, metadata, batch_pi_hash)) diff --git a/crates/libzkp/src/tasks/bundle.rs b/crates/libzkp/src/tasks/bundle.rs index e1b9aca6a0..abd75aef11 100644 --- a/crates/libzkp/src/tasks/bundle.rs +++ b/crates/libzkp/src/tasks/bundle.rs @@ -38,6 +38,7 @@ impl BundleProvingTask { .collect(), serialized_witness: vec![serialized_witness], vk: Vec::new(), + input_commits: Vec::new(), }; Ok((proving_task, bundle_info, bundle_pi_hash)) diff --git a/crates/libzkp/src/tasks/chunk.rs b/crates/libzkp/src/tasks/chunk.rs index 863f080bef..5cf8059403 100644 --- a/crates/libzkp/src/tasks/chunk.rs +++ b/crates/libzkp/src/tasks/chunk.rs @@ -124,6 +124,7 @@ impl ChunkProvingTask { aggregated_proofs: Vec::new(), serialized_witness: vec![serialized_witness], vk: Vec::new(), + input_commits: Vec::new(), }; Ok((proving_task, chunk_info, chunk_pi_hash)) diff --git a/crates/libzkp/src/verifier/universal.rs b/crates/libzkp/src/verifier/universal.rs index e50fe16f40..f5285ebf06 100644 --- a/crates/libzkp/src/verifier/universal.rs +++ b/crates/libzkp/src/verifier/universal.rs @@ -6,12 +6,17 @@ use crate::{ proofs::{AsRootProof, BatchProof, BundleProof, ChunkProof, IntoEvmProof}, utils::panic_catch, }; +use openvm_sdk::SC; use scroll_zkvm_types::version::Version; use scroll_zkvm_verifier::verifier::UniversalVerifier; use std::path::Path; pub struct Verifier { verifier: UniversalVerifier, + /// Deferral-enabled root verifier VK for batch proofs (v0.9.0+). + /// Loaded from `agg_vk.bin` (the batch circuit's aggregation VK, written by + /// build-guest) if present in the assets directory. + batch_mvk: Option>, version: Version, } @@ -19,8 +24,22 @@ impl Verifier { pub fn new(assets_dir: &str, ver_n: u8) -> Self { let verifier_bin = Path::new(assets_dir); + let verifier = + UniversalVerifier::setup(verifier_bin).expect("Setting up universal verifier"); + + let batch_mvk_path = verifier_bin.join("agg_vk.bin"); + let batch_mvk = if batch_mvk_path.exists() { + Some( + openvm_sdk::fs::read_object_from_file(&batch_mvk_path) + .expect("Reading batch root verifier vk"), + ) + } else { + None + }; + Self { - verifier: UniversalVerifier::setup(verifier_bin).expect("Setting up chunk verifier"), + verifier, + batch_mvk, version: Version::from(ver_n), } } @@ -39,16 +58,23 @@ impl ProofVerifier for Verifier { TaskType::Batch => { let proof = serde_json::from_slice::(proof).unwrap(); assert!(proof.pi_hash_check(self.version)); - self.verifier - .verify_stark_proof(proof.as_root_proof(), &proof.vk) - .unwrap() + let mvk = self + .batch_mvk + .as_ref() + .expect("agg_vk.bin missing from assets"); + UniversalVerifier::verify_stark_proof_with_vk( + mvk, + proof.as_root_proof(), + &proof.vk, + ) + .unwrap() } TaskType::Bundle => { let proof = serde_json::from_slice::(proof).unwrap(); assert!(proof.pi_hash_check(self.version)); let vk = proof.vk.clone(); let evm_proof = proof.into_evm_proof(); - self.verifier.verify_evm_proof(&evm_proof, &vk).unwrap() + self.verifier.verify_evm_proof(&evm_proof, &vk).unwrap(); } }) .map(|_| true) diff --git a/crates/prover-bin/Cargo.toml b/crates/prover-bin/Cargo.toml index 6fd6d94a65..ec5df9af91 100644 --- a/crates/prover-bin/Cargo.toml +++ b/crates/prover-bin/Cargo.toml @@ -23,6 +23,14 @@ futures-util = "0.3" reqwest = { version = "0.12", features = ["gzip", "stream"] } hex = "0.4.3" +# OpenVM v2+ deferred STARK verification helpers for batch/bundle proving. +openvm-circuit = { git = "https://github.com/openvm-org/openvm.git", tag = "v2.0.0" } +openvm-continuations = { git = "https://github.com/openvm-org/openvm.git", tag = "v2.0.0" } +openvm-sdk = { git = "https://github.com/openvm-org/openvm.git", tag = "v2.0.0" } +openvm-stark-sdk = { git = "https://github.com/openvm-org/stark-backend.git", tag = "v2.0.0" } +openvm-verify-stark-circuit = { git = "https://github.com/openvm-org/openvm.git", tag = "v2.0.0" } +openvm-verify-stark-host = { git = "https://github.com/openvm-org/openvm.git", tag = "v2.0.0" } + rand = "0.8.5" tokio = "1.37.0" async-trait = "0.1" @@ -36,4 +44,6 @@ bincode = { version = "2.0", features = ["serde",] } [features] default = [] -cuda = ["scroll-zkvm-prover/cuda"] \ No newline at end of file +cuda = ["scroll-zkvm-prover/cuda"] +# GPU acceleration for the halo2 (SNARK) bundle prover; needs 24 GB-class VRAM. +halo2-gpu = ["cuda", "scroll-zkvm-prover/halo2-gpu"] \ No newline at end of file diff --git a/crates/prover-bin/src/deferral.rs b/crates/prover-bin/src/deferral.rs new file mode 100644 index 0000000000..a0aa1fc4ef --- /dev/null +++ b/crates/prover-bin/src/deferral.rs @@ -0,0 +1,110 @@ +use eyre::Result; +use openvm_circuit::system::memory::merkle::public_values::UserPublicValuesProof; +use openvm_sdk::SC; +use openvm_stark_sdk::openvm_stark_backend::{codec::Decode, proof::Proof}; +use openvm_verify_stark_host::{ + deferral::DeferralMerkleProofs, + vk::{VerificationBaseline, VmStarkVerifyingKey}, + VmStarkProof, +}; +use openvm_sdk::DeferralInput; +use scroll_zkvm_types::proof::StarkProof; +use std::io::Cursor; + +/// Compute deferred STARK verification data required by OpenVM v2+ aggregation circuits. +/// +/// For batch/bundle proving the guest reads `input_commits` from stdin and the host must +/// additionally supply `DeferralInput`s and `DeferralState`s to the SDK prover. This function +/// derives all three from the child STARK proofs, the child aggregation VK and the parent's +/// deferral cached commit. +pub fn compute_deferral_data( + child_agg_vk: &openvm_stark_sdk::openvm_stark_backend::keygen::types::MultiStarkVerifyingKey, + parent_deferral_cached_commit: openvm_continuations::CommitBytes, + proofs: &[&StarkProof], +) -> Result<(Vec<[u8; 32]>, Vec, Vec)> { + let mvk = (*child_agg_vk).clone(); + + let (vm_proofs, baselines): (Vec, Vec) = proofs + .iter() + .map(|p| decode_stark_proof(p)) + .collect::>>()? + .into_iter() + .unzip(); + + let baseline = baselines + .first() + .cloned() + .ok_or_else(|| eyre::eyre!("no child proofs to compute deferral data"))?; + for (i, b) in baselines.iter().enumerate().skip(1) { + if b.app_exe_commit != baseline.app_exe_commit || b.app_vk_commit != baseline.app_vk_commit + { + eyre::bail!( + "child proof {i} has a different verification baseline; all child proofs must use the same app exe/vk commitment" + ); + } + } + + let vk = VmStarkVerifyingKey { mvk, baseline }; + + let cached_commit: openvm_stark_sdk::config::baby_bear_poseidon2::Digest = + parent_deferral_cached_commit.into(); + + let raw_results = openvm_verify_stark_circuit::extension::get_raw_deferral_results( + &vk, + &vm_proofs, + cached_commit, + ) + .map_err(|e| eyre::eyre!("get_raw_deferral_results failed: {e}"))?; + + let input_commits: Vec<[u8; 32]> = raw_results + .iter() + .map(|r| { + r.input + .as_slice() + .try_into() + .expect("input commit must be 32 bytes") + }) + .collect(); + + let deferral_inputs = vec![DeferralInput::from_inputs(&vm_proofs)]; + + let deferral_state = openvm_verify_stark_circuit::extension::get_deferral_state( + &vk, + &vm_proofs, + cached_commit, + 0, + ) + .map_err(|e| eyre::eyre!("get_deferral_state failed: {e}"))?; + + Ok((input_commits, deferral_inputs, vec![deferral_state])) +} + +fn decode_stark_proof(proof: &StarkProof) -> Result<(VmStarkProof, VerificationBaseline)> { + let inner = Proof::::decode_from_bytes(&proof.proof) + .map_err(|e| eyre::eyre!("decode proof failed: {e}"))?; + let user_pvs_proof = + UserPublicValuesProof::decode::(&mut Cursor::new(&proof.user_pvs_proof)) + .map_err(|e| eyre::eyre!("decode user_pvs_proof failed: {e}"))?; + let deferral_merkle_proofs = if proof.deferral_merkle_proofs.is_empty() { + None + } else { + Some( + DeferralMerkleProofs::decode(&mut Cursor::new(&proof.deferral_merkle_proofs)) + .map_err(|e| eyre::eyre!("decode deferral_merkle_proofs failed: {e}"))?, + ) + }; + let baseline = if proof.baseline.is_empty() { + eyre::bail!("stark proof missing verification baseline"); + } else { + serde_json::from_slice(&proof.baseline) + .map_err(|e| eyre::eyre!("decode baseline failed: {e}"))? + }; + Ok(( + VmStarkProof { + inner, + user_pvs_proof, + deferral_merkle_proofs, + }, + baseline, + )) +} diff --git a/crates/prover-bin/src/dumper.rs b/crates/prover-bin/src/dumper.rs index c8360384c0..0bc0c6e796 100644 --- a/crates/prover-bin/src/dumper.rs +++ b/crates/prover-bin/src/dumper.rs @@ -39,7 +39,7 @@ impl Dumper { let mut agg_writer = std::io::BufWriter::new(agg_file); for proof in &task.aggregated_proofs { let sz = bincode::serde::encode_into_std_write( - &proof.proofs, + &proof.proof, &mut agg_writer, bincode::config::standard(), )?; diff --git a/crates/prover-bin/src/main.rs b/crates/prover-bin/src/main.rs index 05fac1ec1a..88e99d1542 100644 --- a/crates/prover-bin/src/main.rs +++ b/crates/prover-bin/src/main.rs @@ -1,4 +1,5 @@ mod dumper; +mod deferral; mod prover; mod types; mod zk_circuits_handler; diff --git a/crates/prover-bin/src/prover.rs b/crates/prover-bin/src/prover.rs index 7fac8419f6..e50cb72bcb 100644 --- a/crates/prover-bin/src/prover.rs +++ b/crates/prover-bin/src/prover.rs @@ -1,4 +1,4 @@ -use crate::zk_circuits_handler::{universal::UniversalHandler, CircuitsHandler}; +use crate::zk_circuits_handler::universal::UniversalHandler; use async_trait::async_trait; use eyre::Result; use scroll_proving_sdk::{ @@ -12,7 +12,7 @@ use scroll_proving_sdk::{ ProvingService, }, }; -use scroll_zkvm_types::ProvingTask; +use scroll_zkvm_types::{proof::StarkProof, ProvingTask}; use serde::{Deserialize, Serialize}; use std::{ collections::HashMap, @@ -93,7 +93,10 @@ impl AssetsLocationData { url_base: &url::Url, base_path: impl AsRef, ) -> Result { - let download_files = ["app.vmexe", "openvm.toml"]; + // agg_vk.bin is the pre-built aggregation verifying key (zkvm-prover + // v0.9.0+); without it the prover derives the VK from the SDK, which is + // slow and allocates GPU memory that is never reclaimed. + let download_files = ["app.vmexe", "openvm.toml", "agg_vk.bin"]; // Step 1: Create a local path for storage let storage_path = base_path.as_ref().join(vk); @@ -191,6 +194,10 @@ pub struct CircuitConfig { /// cached vk value to save some initial cost, for debugging only #[serde(default)] pub vks: HashMap, + /// Child circuit VKs used to enable OpenVM deferral for aggregation tasks. + /// Required for batch (child=chunk) and bundle (child=batch) proving in v0.9.0+. + #[serde(default)] + pub child_circuit_vks: HashMap, } pub struct LocalProver { @@ -198,7 +205,7 @@ pub struct LocalProver { next_task_id: u64, current_task: Option>>, - handlers: HashMap>, + handlers: HashMap>>, } #[async_trait] @@ -323,41 +330,118 @@ impl LocalProver { if prover_task.use_openvm_13 { eyre::bail!("prover do not support snark params base on openvm 13"); } - let prover_task: ProvingTask = prover_task.into(); + let mut prover_task: ProvingTask = prover_task.into(); let vk = hex::encode(&prover_task.vk); - let handler = if let Some(handler) = self.handlers.get(&vk) { - handler.clone() - } else { - let base_config = self - .config - .circuits - .get(&req.hard_fork_name) - .ok_or_else(|| { - eyre::eyre!( - "coordinator sent unexpected forkname {}", - req.hard_fork_name - ) - })?; - let url_base = if let Some(url) = base_config.location_data.asset_detours.get(&vk) { - url.clone() - } else { - base_config - .location_data - .gen_asset_url(&vk, req.proof_type)? - }; - let asset_path = base_config - .location_data - .get_asset(&vk, &url_base, &base_config.workspace_path) - .await?; - let circuits_handler = Arc::new(Mutex::new(UniversalHandler::new(&asset_path)?)); - self.handlers.insert(vk, circuits_handler.clone()); - circuits_handler + + let parent_handler = self + .get_or_load_handler(&req.hard_fork_name, req.proof_type, &vk) + .await?; + + // OpenVM v2+ aggregation circuits (batch/bundle) need deferral enabled + // using their immediate child circuit's prover, plus input commits/defersal + // inputs derived from the child proofs. + let deferral = match req.proof_type { + ProofType::Batch | ProofType::Bundle => { + let child_type = match req.proof_type { + ProofType::Batch => ProofType::Chunk, + ProofType::Bundle => ProofType::Batch, + _ => unreachable!(), + }; + let child_vk = self + .config + .circuits + .get(&req.hard_fork_name) + .and_then(|c| c.child_circuit_vks.get(&child_type)) + .ok_or_else(|| { + eyre::eyre!( + "missing child circuit vk for {:?} in fork {}", + child_type, + req.hard_fork_name + ) + })? + .clone(); + let child_handler = self + .get_or_load_handler(&req.hard_fork_name, child_type, &child_vk) + .await?; + + // A bundle's child (batch) must itself have deferral-over-chunk + // initialized: the bundle verify circuit needs the batch prover's + // def_hook_commit, which only exists after the batch prover's own + // enable_deferral ran (OpenVM v2+). Without it the bundle prover + // panics with "def_hook_commit must be defined to verify child + // proof with deferrals". + if req.proof_type == ProofType::Bundle { + let grandchild_vk = self + .config + .circuits + .get(&req.hard_fork_name) + .and_then(|c| c.child_circuit_vks.get(&ProofType::Chunk)) + .ok_or_else(|| { + eyre::eyre!( + "missing chunk circuit vk for fork {}", + req.hard_fork_name + ) + })? + .clone(); + let grandchild_handler = self + .get_or_load_handler(&req.hard_fork_name, ProofType::Chunk, &grandchild_vk) + .await?; + let mut child_guard = child_handler.lock().await; + let mut grandchild_guard = grandchild_handler.lock().await; + child_guard.enable_deferral(&*grandchild_guard)?; + // The grandchild (chunk) SDK was only needed to initialize the + // batch prover's deferral hook; release its GPU proving keys + // before the bundle STARK/SNARK phase (see UniversalHandler::reset). + grandchild_guard.reset(); + } + + let mut parent_guard = parent_handler.lock().await; + let mut child_guard = child_handler.lock().await; + parent_guard.enable_deferral(&*child_guard)?; + + let child_agg_vk = child_guard + .agg_vk() + .map_err(|e| eyre::eyre!("failed to get child agg vk: {e}"))?; + // The child SDK is no longer needed once deferral is configured on + // the parent and the (file-based) child agg vk is extracted; release + // its GPU proving keys before proving (see UniversalHandler::reset). + child_guard.reset(); + let cached_commit = parent_guard + .deferral_cached_commit() + .map_err(|e| eyre::eyre!("failed to get parent deferral cached commit: {e}"))?; + + let child_proofs: Vec<&StarkProof> = prover_task.aggregated_proofs.iter().collect(); + let (input_commits, def_inputs, def_states) = + crate::deferral::compute_deferral_data( + &child_agg_vk, + cached_commit, + &child_proofs, + )?; + prover_task.input_commits = input_commits; + + // locks are released here + Some((def_inputs, def_states)) + } + _ => None, }; let handle = Handle::current(); let is_evm = req.proof_type == ProofType::Bundle; let task_handle = tokio::task::spawn_blocking(move || { - handle.block_on(handler.get_proof_data(&prover_task, is_evm)) + handle.block_on(async { + let mut guard = parent_handler.lock().await; + match deferral { + Some((def_inputs, def_states)) => { + guard.get_proof_data_with_deferral( + &prover_task, + is_evm, + &def_inputs, + &def_states, + ) + } + None => guard.get_proof_data(&prover_task, is_evm), + } + }) }); self.current_task = Some(task_handle); @@ -372,4 +456,34 @@ impl LocalProver { ..Default::default() }) } + + /// Load a handler for the given fork/proof-type/vk, reusing a cached one if available. + async fn get_or_load_handler( + &mut self, + fork_name: &str, + proof_type: ProofType, + vk: &str, + ) -> Result>> { + if let Some(handler) = self.handlers.get(vk) { + return Ok(handler.clone()); + } + + let base_config = self + .config + .circuits + .get(fork_name) + .ok_or_else(|| eyre::eyre!("coordinator sent unexpected forkname {}", fork_name))?; + let url_base = if let Some(url) = base_config.location_data.asset_detours.get(vk) { + url.clone() + } else { + base_config.location_data.gen_asset_url(vk, proof_type)? + }; + let asset_path = base_config + .location_data + .get_asset(vk, &url_base, &base_config.workspace_path) + .await?; + let handler = Arc::new(Mutex::new(UniversalHandler::new(&asset_path)?)); + self.handlers.insert(vk.to_string(), handler.clone()); + Ok(handler) + } } diff --git a/crates/prover-bin/src/zk_circuits_handler.rs b/crates/prover-bin/src/zk_circuits_handler.rs index f6b9f0086c..a64d745c67 100644 --- a/crates/prover-bin/src/zk_circuits_handler.rs +++ b/crates/prover-bin/src/zk_circuits_handler.rs @@ -2,12 +2,3 @@ #[allow(non_snake_case)] pub mod universal; - -use async_trait::async_trait; -use eyre::Result; -use scroll_zkvm_types::ProvingTask; - -#[async_trait] -pub trait CircuitsHandler: Sync + Send { - async fn get_proof_data(&self, u_task: &ProvingTask, need_snark: bool) -> Result; -} diff --git a/crates/prover-bin/src/zk_circuits_handler/universal.rs b/crates/prover-bin/src/zk_circuits_handler/universal.rs index e332092a8f..60a08bcbb8 100644 --- a/crates/prover-bin/src/zk_circuits_handler/universal.rs +++ b/crates/prover-bin/src/zk_circuits_handler/universal.rs @@ -1,12 +1,11 @@ use std::path::Path; -use super::CircuitsHandler; -use async_trait::async_trait; use eyre::Result; use libzkp::ProvingTaskExt; -use scroll_zkvm_prover::{Prover, ProverConfig}; +use openvm_circuit::arch::deferral::DeferralState; +use openvm_sdk::DeferralInput; +use scroll_zkvm_prover::{task::ProvingTask as ProvingTaskTrait, Prover, ProverConfig}; use scroll_zkvm_types::ProvingTask; -use tokio::sync::Mutex; pub struct UniversalHandler { prover: Prover, } @@ -19,36 +18,96 @@ impl UniversalHandler { pub fn new(workspace_path: impl AsRef) -> Result { let path_app_exe = workspace_path.as_ref().join("app.vmexe"); let path_app_config = workspace_path.as_ref().join("openvm.toml"); - let segment_len = Some((1 << 22) - 100); let config = ProverConfig { path_app_config, path_app_exe, - segment_len, }; let prover = Prover::setup(config, None)?; Ok(Self { prover }) } - /// get_prover get the inner prover, later we would replace chunk/batch/bundle_prover with - /// universal prover, before that, use bundle_prover as the represent one - pub fn get_prover(&mut self) -> &mut Prover { - &mut self.prover + /// Enable OpenVM deferral using `child_prover` as the child circuit prover. + /// Required for batch (child=chunk) and bundle (child=batch) aggregation proofs. + pub fn enable_deferral(&mut self, child: &UniversalHandler) -> Result<()> { + self.prover + .enable_deferral(&child.prover) + .map_err(|e| eyre::eyre!("failed to enable deferral: {}", e))?; + Ok(()) + } + + /// Release the lazily-built SDK (GPU proving keys) of this circuit. + /// + /// The openvm VPMM pool never returns physical pages to the OS, but freed + /// allocations become reusable pool regions; dropping a child circuit's SDK + /// once deferral is configured lowers the live GPU set (and thus the pool + /// high-water mark) before the parent's STARK/SNARK phase. Mirrors the + /// zkvm integration tester, which calls `Prover::reset()` on child provers + /// after `enable_deferral` for the same reason. The SDK is rebuilt lazily + /// on the next task that needs this circuit. + pub fn reset(&mut self) { + self.prover.reset(); + } + + /// Return the child aggregation VK needed to build deferral data. + /// Reads the pre-built agg_vk.bin asset instead of sdk.agg_vk(): building + /// the (GPU) aggregation prover just to obtain the VK uploads ~5.7 GiB of + /// proving keys into the VPMM pool, which is never reclaimed and starves + /// the halo2-gpu SNARK phase of VRAM (quotient.cu cudaErrorInvalidConfiguration). + pub fn agg_vk(&self) -> Result> { + self.prover + .load_agg_vk() + .map(|mvk| mvk.as_ref().clone()) + .map_err(|e| eyre::eyre!("failed to load agg vk: {e}")) + } + + /// Return the cached commit of the verify-stark deferral circuit (def_idx 0). + pub fn deferral_cached_commit(&self) -> Result { + let sdk = self.prover.sdk().map_err(|e| eyre::eyre!("failed to get sdk: {e}"))?; + let mut commits = sdk + .deferral_circuit_cached_commits(0) + .map_err(|e| eyre::eyre!("failed to get deferral cached commits: {e}"))?; + eyre::ensure!( + commits.len() == 1, + "expected one deferral circuit, got {}", + commits.len() + ); + Ok(commits.pop().unwrap()) } pub fn get_task_from_input(input: &str) -> Result { Ok(serde_json::from_str(input)?) } -} -#[async_trait] -impl CircuitsHandler for Mutex { - async fn get_proof_data(&self, u_task: &ProvingTask, need_snark: bool) -> Result { - let mut handler_self = self.lock().await; + /// Generate a proof for `u_task`. + pub fn get_proof_data(&mut self, u_task: &ProvingTask, need_snark: bool) -> Result { + let proof = self.prover.gen_proof_universal(u_task, need_snark)?; + Ok(serde_json::to_string(&proof)?) + } - let proof = handler_self - .get_prover() - .gen_proof_universal(u_task, need_snark)?; + /// Generate a proof for `u_task` using deferred STARK verification data. + /// + /// For batch/bundle tasks this writes `input_commits` into stdin, attaches the deferral + /// states and passes the deferral inputs to the SDK prover. + pub fn get_proof_data_with_deferral( + &mut self, + u_task: &ProvingTask, + need_snark: bool, + def_inputs: &[DeferralInput], + def_states: &[DeferralState], + ) -> Result { + let mut stdin = u_task.build_guest_input(); + stdin.deferrals = def_states.to_vec(); + + let proof = if need_snark { + scroll_zkvm_types::proof::ProofEnum::from(scroll_zkvm_types::proof::EvmProof::from( + self.prover.gen_proof_snark(stdin, def_inputs)?, + )) + } else { + scroll_zkvm_types::proof::ProofEnum::from(self.prover.gen_proof_stark( + stdin, def_inputs, + )?) + }; Ok(serde_json::to_string(&proof)?) } diff --git a/docs/testing/single-chunk-reproving.md b/docs/testing/single-chunk-reproving.md new file mode 100644 index 0000000000..317f6b0e61 --- /dev/null +++ b/docs/testing/single-chunk-reproving.md @@ -0,0 +1,260 @@ +# Re-proving a Single Mainnet Chunk + +This guide describes how to re-prove one specific chunk that already exists in the mainnet production database, without running a full shadow fork or replaying an entire chain segment. + +Typical use cases: + +- A chunk was proven with an old guest / circuit version and the existing proof no longer validates against current verifier assets. +- You want to reproduce a mainnet chunk proof locally for debugging or verification. + +## High-level idea + +The mainnet DB user available to agents is **read-only**, so a local coordinator cannot update `proving_status` or insert `prover_task` records against mainnet RDS directly. The workaround is: + +1. Export the target `chunk` row and its `l2_block` rows from mainnet RDS. +2. Import them into the local **shadow DB** (`localhost:5433/shadow_rollup`), which is writable. +3. Run a temporary coordinator against the shadow DB but with **mainnet L2 RPC** and the production verifier assets. +4. Run the prover in `handle` mode pointing at that coordinator and request exactly the chunk hash. +5. Extract the new proof from the shadow DB, verify it independently, and save it. + +## Prerequisites + +- `psql` and access to both: + - Mainnet RDS via the local tunnel (`localhost:15432/mainnet_rollup`) + - Shadow Postgres (`localhost:5433/shadow_rollup`, writable) +- Built coordinator binary: `coordinator/build/bin/coordinator_api` +- Built prover binary: `target/release/prover` +- Verifier assets matching the current circuit version, e.g. `coordinator/build/bin/assets_v2` +- Cached circuit assets for the prover (the S3 `circuit-release` bucket may return 403 from this environment). Look for an existing `.work/galileo//` directory and copy it into the prover workspace. +- Mainnet genesis file, e.g. `tests/prover-e2e/mainnet-galileoV2/genesis.json` + +## Step-by-step + +### 1. Export the chunk and its blocks from mainnet + +Use `enable_seqscan = off` when querying `l2_block`; the table is huge and a plain `BETWEEN` scan can time out even with a partial index. + +```bash +EXPORT_DIR=/tmp/chunk-6641451-export +mkdir -p $EXPORT_DIR + +# chunk row +PGPASSWORD='' psql -h localhost -p 15432 \ + -U mainnet_infra_team_read_only -d mainnet_rollup -Atq \ + -c "COPY (SELECT * FROM chunk WHERE index = 6641451) TO STDOUT WITH CSV HEADER;" \ + > $EXPORT_DIR/chunk.csv + +# l2_block rows for the chunk's block range +PGPASSWORD='' psql -h localhost -p 15432 \ + -U mainnet_infra_team_read_only -d mainnet_rollup -Atq \ + -c " + SET enable_seqscan = off; + COPY ( + SELECT * FROM l2_block + WHERE number BETWEEN 34180693 AND 34180761 + AND deleted_at IS NULL + ) TO STDOUT WITH CSV HEADER; + " > $EXPORT_DIR/l2_blocks.csv +``` + +### 2. Import into the shadow DB + +```bash +PGPASSWORD='shadow_pass' psql -h localhost -p 5433 \ + -U postgres -d shadow_rollup \ + -f /dev/stdin < $EXPORT_DIR/handle-set.json <<'EOF' +{ + "chunks": [ + "0x90861ddc4e0effb030f59644b03c8bd80e0b2ca8632c8c3500a25029fe4f4081" + ], + "batches": [], + "bundles": [] +} +EOF +``` + +### 6. Configure the prover + +Key settings: + +- `coordinator.base_url`: `http://localhost:8390` +- `circuits.galileoV2.workspace_path`: directory containing the cached circuit assets +- `circuits.galileoV2.debug_mode`: `true` to skip S3 preflight / download (S3 may 403) +- `sdk_config.db_path`: separate from other prover runs + +Example: + +```json +{ + "sdk_config": { + "prover_name_prefix": "mainnet-reprove-chunk-6641451", + "keys_dir": "/tmp/chunk-6641451-export/prover-keys", + "coordinator": { + "base_url": "http://localhost:8390", + "retry_count": 10, + "retry_wait_time_sec": 10, + "connection_timeout_sec": 1800 + }, + "prover": { + "supported_proof_types": [1], + "circuit_version": "v0.13.1" + }, + "health_listener_addr": "127.0.0.1:10080", + "db_path": "/tmp/chunk-6641451-export/prover-db" + }, + "circuits": { + "galileoV2": { + "base_url": "https://circuit-release.s3.us-west-2.amazonaws.com/scroll-zkvm/releases/v0.9.0/", + "workspace_path": "/tmp/prover-multi-gpu/gpu0/.work/galileo", + "debug_mode": true + } + } +} +``` + +If circuit assets are not already in the workspace, copy them from an existing cache: + +```bash +mkdir -p /tmp/prover-multi-gpu/gpu0/.work/galileo +cp -r /home/scroll/zzhang/scroll/.work/galileo/64cf16439a284e4449666c479a3ae42b568fea5e88610777ff6b5f2cda19d91182a47957139d0d1c1c3fbb28b9579c23f2823c0c6ff05669fe71ad4a0c92620e \ + /tmp/prover-multi-gpu/gpu0/.work/galileo/ +``` + +### 7. Run the prover + +OpenVM proving can overflow the default Rust thread stack, so set `RUST_MIN_STACK`. Run with no timeout: + +```bash +cd /home/scroll/zzhang/scroll +RUST_MIN_STACK=33554432 ./target/release/prover \ + --config /tmp/chunk-6641451-export/prover-config.json \ + handle /tmp/chunk-6641451-export/handle-set.json +``` + +For a chunk of ~70 blocks, expect roughly 10–15 minutes on GPU. + +### 8. Extract, verify, and save the proof + +After the coordinator logs `proof verified and valid`, extract the proof from the shadow DB: + +```bash +PGPASSWORD='shadow_pass' psql -h localhost -p 5433 \ + -U postgres -d shadow_rollup -Atq \ + -c "SELECT encode(proof, 'hex') FROM chunk WHERE index = 6641451;" \ + > /tmp/chunk-6641451-export/new-proof.hex + +xxd -r -p /tmp/chunk-6641451-export/new-proof.hex > /tmp/chunk-6641451-export/new-proof.json + +# independent verification +cd coordinator/build/bin +LD_LIBRARY_PATH=../internal/logic/libzkp/lib:$LD_LIBRARY_PATH \ + ./coordinator_tool verify chunk /tmp/chunk-6641451-export/new-proof.json +``` + +Save the final proof to a clear location: + +```bash +cp /tmp/chunk-6641451-export/new-proof.json \ + /tmp/chunk-6641451/chunk_6641451_proof.json +``` + +## Common pitfalls + +| Symptom | Cause | Fix | +|---------|-------|-----| +| `cannot execute UPDATE in a read-only transaction` | Coordinator connected to mainnet RDS with read-only user | Use shadow DB for coordinator writes | +| `server closed the connection unexpectedly` on `localhost:15432` | Mainnet RDS tunnel (stunnel) is down or broken | Retry later or ask ops to restart the tunnel | +| `record not found, uuid:...` during proof submission | Coordinator was restarted/killed after assigning the task; `prover_task` record was lost or not committed | Keep coordinator alive for the entire proving session; use `disable_timeout=true` | +| Prover aborts with stack overflow | Default Rust thread stack too small for OpenVM | `RUST_MIN_STACK=33554432` | +| S3 403 on circuit asset URLs | Directory listings are blocked or bucket is not public | Copy cached circuit assets into the prover workspace and set `debug_mode: true` | +| Query on `l2_block` times out | Table is huge; planner may seq-scan | `SET enable_seqscan = off;` and include `deleted_at IS NULL` | + +## Cleanup + +Stop the temporary coordinator when done. The shadow DB still contains the imported mainnet chunk; delete it if you no longer need it: + +```bash +PGPASSWORD='shadow_pass' psql -h localhost -p 5433 \ + -U postgres -d shadow_rollup -Atq -c " + DELETE FROM l2_block WHERE number BETWEEN 34180693 AND 34180761; + DELETE FROM chunk WHERE index = 6641451; + " +``` diff --git a/docs/testing_reports/canary-parallel-upgrade-2026-08-25.md b/docs/testing_reports/canary-parallel-upgrade-2026-08-25.md new file mode 100644 index 0000000000..bd24ef0890 --- /dev/null +++ b/docs/testing_reports/canary-parallel-upgrade-2026-08-25.md @@ -0,0 +1,62 @@ +# Canary Parallel-Upgrade Test Report — 2026-08-25 + +**Mode**: follow-mode canary parallel upgrade (new; extends, does not replace, the `20-upgrade.sh` hard-switch mode). +**Host**: fresh machine (this repo checkout `c500b7d6`), 2×RTX 4090, shadow DB in local docker postgres:15 (`localhost:5433/shadow_rollup`). +**Remote source DB**: `192.168.1.108:15432/mainnet_rollup` (read-only; no local tunnel this time). + +## Stacks under test + +| | Old (production) | New (this checkout) | +|---|---|---| +| Guest | `79c1f8c` | zkvm-prover `bf887150` (v0.9.0) | +| bundle digest1 | `0x00398b78…9269` | `0x006770fb…5655` | +| Wrapper | `0x808297224e86b1a6055B5F790a2cE07Ed611f955` (mainnet `latestVerifier[10]`, startBatch 0) | deployed fresh on fork per run | +| Proof source | imported from remote DB (`remote_bundle_proof` quarantine) | local provers (GPU) | + +Production digests were verified by decoding `bundle.proof` `instances` bytes 384–448 from the remote DB against the on-chain wrapper immutables (exact match). Note production is NOT on the S3 `releases/v0.9.0` guest — AGENTS.md's `0x0dE1…` wrapper note is stale. + +## Timeline (UTC) + +| Time | Event | +|---|---| +| 06:06 | Phase A up: `10-follow-up.sh --import-proofs --reset` (fork 5h back, block 25828765; lastFinalized@fork 519409). No coordinator/provers. | +| 06:10 | Proof import live: 18,577 production bundle proofs quarantined; 3 applied to the backlog. | +| ~06:12–06:20 | **Phase A acceptance**: bundles 18692/18693/18694 (ends 519410/519412/519415) finalized on the fork purely from imported production proofs, zero local proving. `lastFinalizedBatchIndex` 519409 → 519415. | +| 06:21 | Relayer stopped to stage a backlog for the parallel window. | +| 08:59–09:19 | Import-cursor bug found & fixed (see Findings); backlog bundles 18695/18696 (ends 519417/519418) quarantined + applied. | +| 09:22 | **t1**: `30-canary-upgrade.sh` — boundary N=519419, new wrapper `0x3a25…5577` deployed from S3 v0.9.0 assets and registered via genuine `updateVerifier(10, 519419, …)`; old wrapper moved to `legacyVerifiers[10][0]`. Routing asserted both sides of N; on-chain digest-differ check passed (`00398b78…` vs `006770fb…`). New coordinator+provers started. | +| 09:25–09:35 | **Interleaved finalization (key acceptance)**: relayer restarted; backlog bundles 18695/18696 finalized AFTER the upgrade through the OLD wrapper via `legacyVerifiers` routing (finalize access list includes MVRV + old wrapper; tx `0x73f7dbdb…` status true). Fork `lastFinalizedBatchIndex` → 519418. | +| 09:33 | **Rollback drill**: `31-canary-rollback.sh` — new stack stopped, `updateVerifier(10, 519419, OLD_WRAPPER)` swap-back, boundary cleared. | +| 09:59 | **Post-rollback acceptance**: next mainnet bundle 18697 (end 519420 ≥ N) finalized via imported production proof through the restored old wrapper — "as if the upgrade never happened". Fork `lastFinalizedBatchIndex` → 519420. | +| ~10:02 | **Re-upgrade**: `30-canary-upgrade.sh` again — new boundary N=519421, new wrapper `0xA7898f4BE5Af8A9BCA430E65c9bcbfD34d6b7c3a` registered (plonk verifier `0x0b74Ec1f…1797`), routing + digest checks pass. Rollback → re-upgrade cycle confirmed idempotent. | +| 10:18–12:17 | Mainnet batch-production pause (low activity); batch tip flat at 519421. During the pause both provers died on their first **bundle** task: missing `~/.openvm/params/kzg_bn254_23.srs` (Trap 12 — SRS files were in `~/.openvm/` root, not `params/`). Fixed 14:11, provers restarted 14:12 (see Findings 8). | +| 14:48 | **t2 ✅**: bundles 18698 (end 519421) and 18699 (end 519422) proven by the local NEW stack (`proved_at` 14:48:14 / 14:48:35) and finalized through the NEW wrapper — finalize txs `0x5a2537c7…b0bd9` / `0x60be9f62…4cf39` both status true, access lists include new wrapper `0xA7898f4B…` + plonk verifier `0x0b74Ec1f…`. Fork `lastFinalizedBatchIndex` → 519422. Proof-origin verified cryptographically: bundle 18698's `instances` digest1 = `0x006770fb…5655` (new guest), not production `0x00398b78…9269`. | + +## Findings / bugs fixed during the run + +1. **Import cursor high-watermark skipped late proofs** (real bug, fixed): mainnet creates the `bundle` row first and attaches the proof minutes later; the importer advanced its cursor to remote `MAX(index)` over ALL bundles, permanently skipping bundles still unproven at scan time. Fixed in `sync-mainnet-db.py`: cursor advances over `proving_status=4` rows only + 200-row lookback re-scan. Self-heals on restart. +2. **Boundary N must exceed the proven backlog** (fixed in `30-canary-upgrade.sh` step b): with a proven-but-unfinalized backlog, `N = lastFinalized+1` would route old-proof bundles to the new wrapper → guaranteed `VerificationFailed`. N is now `max(U, P+1)` with P = max end_batch of unfinalized bundles holding a quarantined proof. +3. **`coordinator_api` needs `conf/genesis.json` relative to CWD** (fresh-machine trap): it CRITs seconds after the startup pid check, provers then exhaust login retries and die. Fixed by copying `tests/prover-e2e/mainnet-galileoV2/genesis.json` into `coordinator/build/bin/conf/`; sanity check added to 30. +4. **`setsid nohup … & echo $!` pidfiles can point at a zombie**: `setsid` forks when the job is a pg leader, so the recorded pid is a dead intermediate; `kill -0` on the zombie succeeds and the real process survives "stops". Hit during the rollback drill (the old api kept port 8390 → next api start failed `bind: address already in use`). `stop_component` in 30/31 now always falls through to the pattern sweep. +5. **Coordinator wasted GPU on already-finalized history**: at t1 the new coordinator began proving chunks of bundles finalized in Phase A (their rows had `proving_status=1` since Phase A never needed local proofs). Mitigated manually with `UPDATE chunk/batch SET proving_status=4 … WHERE bundle finalized` (the same NULL-proof-is-safe pattern as 10-follow-up step b). Candidate improvement: have 30-canary-upgrade.sh run this marking itself. +6. Two stale `prover_task` status-3 rows appeared after the rollback/restart (chunk tasks of an already-finalized batch failed verification post-restart — consistent with the Trap-38 "wipe prover db on restart" lesson). Deleted manually; no impact. +7. Remote `l2_block` range copies are slow on this network (server-side `DataFileRead`, minutes per cycle) — proof import latency ≈ one poll cycle (10–15 min). Back-pressure only, no data loss. Manual one-shot `import_remote_proofs()` works around it when staging a boundary. +8. **halo2 SRS not in `~/.openvm/params/` on the fresh machine** (Trap 12, environment miss during setup): the SRS files had been downloaded to `~/.openvm/` root, not the `params/` subdir the prover reads. Chunk/batch STARK proving is unaffected, so the failure only surfaced when the first **bundle** task reached halo2 keygen — both provers panicked (`Failed to open params file …/params/kzg_bn254_23.srs`) and exited, prover-0 at 11:00, prover-1 at 12:25. Fixed by moving `kzg_bn254_{22,23,24}.srs` into `~/.openvm/params/` and restarting the provers; the sweeper had already reset the interrupted bundle task. Setup checklists should verify `ls ~/.openvm/params/` before starting provers. + +## Environment notes (fresh machine) + +- NVML driver/library mismatch (kernel 580.159 vs userland 580.173) fixed by `modprobe -r nvidia_uvm nvidia_drm nvidia_modeset nvidia && modprobe nvidia` — no reboot needed (no processes held the devices). +- OpenVM CUDA build ICEs with nvcc 12.4 (`cp_gen_be.c` assertion on `load_sign_extend.cu`); **CUDA 12.8 works**. Also needs `libclang-dev` (bindgen), `python3-pycryptodome`/`requests` (sync scripts). +- Repo convention is shadow DB password `shadow_pass` (docker-compose.yml and all script defaults); recreating the container with that password avoided touching any script. +- `local-secrets.md` corrections: Alchemy mainnet must use the key previously listed under sepolia (`/v2/demo` is dead); mainnet DB is at `192.168.1.108:15432` directly (no stunnel on this host). File updated in place. + +## Acceptance summary + +| Criterion | Status | +|---|---| +| Phase A: ≥3 backlog bundles finalized purely from imported production proofs | ✅ (18692–18694) | +| t1: genuine `updateVerifier`, old wrapper in `legacyVerifiers`, routing asserted | ✅ (N=519419) | +| Parallel finalization: old-proof bundles finalize post-upgrade via legacy routing | ✅ (18695/18696) | +| Rollback: old wrapper restored, next bundle finalized via imported proof; "no upgrade happened" | ✅ (18697) | +| Re-upgrade after rollback | ✅ (N=519421) | +| t2: first NEW-guest proof finalized on-chain through the new wrapper | ✅ (18698 + 18699, digest-verified) | diff --git a/docs/testing_reports/canary-parallel-upgrade-2026-09-11.md b/docs/testing_reports/canary-parallel-upgrade-2026-09-11.md new file mode 100644 index 0000000000..3ecf8b2302 --- /dev/null +++ b/docs/testing_reports/canary-parallel-upgrade-2026-09-11.md @@ -0,0 +1,85 @@ +# Canary Parallel-Upgrade Test Report — 2026-09-11 + +**Mode**: follow-mode canary parallel upgrade, third run (first: 2026-08-25 bare-metal, second: 2026-08-31 docker). Full cycle this time: Phase A → staging → t1 → parallel window → rollback drill → post-rollback acceptance → re-upgrade → t2 → soak (2 new-stack bundles). +**Host**: same machine, 2×RTX 4090 — but **GPU0 was occupied by an unrelated process (ComfyUI, 22.4 GiB)**, so the entire run used **GPUS=1 (GPU1 only)**. Shadow DB local docker postgres:15 (`localhost:5433/shadow_rollup`), remote read-only `192.168.1.108:15432/mainnet_rollup`. +**Checkout**: `403a1e9e` (branch `shadow-test-ai`; prover binary from 8-31 `prover_halo2gpu` build — the commits since are scripts/docs only). + +## Stacks under test + +| | Old (production) | New (this checkout) | +|---|---|---| +| Guest | unchanged since 8-31 (wrapper digest1 `0x00398b78…9269`) | zkvm-prover `bf887150` (S3 `releases/v0.9.0`, digest1 `0x006770fb…5655`) | +| Wrapper | `0x808297224e86b1a6055B5F790a2cE07Ed611f955` (forked MVRV) | `0x3a251c0c…5577` (t1, N=519738) then `0xA7898f4B…c3a` (re-upgrade, N=519739) | +| Proof source | imported from remote DB (`remote_bundle_proof`) | local prover, GPU1, halo2-gpu | + +Pre-flight verified the production stack had NOT changed since 8-31 (on-chain `latestVerifier[10]` digest vs newest remote proof instances — exact match), so no fork-point version skew. + +## Timeline (UTC) + +| Time | Event | +|---|---| +| 06:06 | Phase A up: `10-follow-up.sh --import-proofs --reset` (fork block 25950750; baseline batch 519730). No coordinator/provers by design. | +| 06:08–06:11 | **Phase A acceptance**: bundles 18961–18964 (ends 519732–519735) finalized purely from imported production proofs; `lastFinalizedBatchIndex` → 519735. | +| 06:15 | Relayer stopped to stage a backlog for the parallel window. | +| 07:26 | **t1**: `30-canary-upgrade.sh` — N=519738 (staged bundle 18965 = only old-path specimen), new wrapper `0x3a25…5577` via genuine `updateVerifier`; routing + digest-differ asserted; coordinator + 1 prover started (GPU1). | +| 07:28 | Relayer restarted → **parallel window**: 18965 (end 519737 < N) finalized through the OLD wrapper via `legacyVerifiers` — `cast run` trace: `MVRV.verifyBundleProof(10,519737)` → `0x8082…::verify`, proof instances carry the old digest1. | +| 07:33 | **Rollback drill**: `31-canary-rollback.sh` — routing restored at 519738, boundary cleared to +∞, new stack stopped; relayer/poll-sync untouched. | +| ~08:28 | **Anvil incident #1**: anvil process died silently (state last persisted 08:27; stdout was discarded by the default launch, so no crash reason). | +| 08:36 | Restored by re-launching anvil with the SAME `--state` file: chainId/`lastFinalized=519737`/rolled-back routing all intact. (Note: this state-file relaunch path is NOT what `re-fork.sh` does — re-fork starts a fresh fork; the state relaunch is lighter and preserved legacy routing + finalize history.) | +| 08:37 | **Post-rollback acceptance**: 18966 (end 519738, first batch ≥ N) finalized via the restored OLD wrapper from an imported proof — "as if the upgrade never happened". | +| 08:45 | **Commit-tx incident**: during anvil warm-up after the restore, the relayer's commit tx for batch 519739 hit a client timeout — but the tx HAD landed (next retry: "transaction already imported"). `commit_tx_hash` never written → infinite `ErrorIncorrectBatchHash` commit retries (5,518 log lines). | +| 10:24 | Repaired: on-chain tx found by scanning blocks (`0x9d97a19a…`, nonce 6, blob tx, status 1), `batch.commit_tx_hash` backfilled, relayer restarted (nonce re-init from chain). Spam stopped. | +| 08:40 | **Re-upgrade**: `30-canary-upgrade.sh` again — N=519739, wrapper `0xA7898f4B…c3a` (plonk `0x0b74Ec1f…1797`), all assertions pass. Idempotency incl. the in-place legacy entry confirmed. | +| 08:44–09:27 | 5 chunks of batch 519739 proved locally on the single GPU (incl. 10–15 min first-task witness fetch). | +| ~10:18 | **t2**: 18967 (end 519739, first ≥ N) proven locally and finalized via the NEW wrapper. Digest-verified: local proof instances digest1 = `0x006770fb…` (new guest); trace: `MVRV` → `0xA7898f4B…::verify`. halo2-gpu SNARK `Create EVM proof` **5.98 s**, GPU peak **8.8 GiB**. | +| ~11:00 | **Anvil incident #2**: anvil STALLED (silent — log ends mid-RPC, no panic; `kill -0` and port checks failed, then it self-recovered). During the stall 18968's finalize tx landed (`0x5170aa92…`, nonce 7, status 1) but the receipt was lost → bundle row stuck `rollup_status=1` while on-chain `lastFinalized` had already advanced to 519740. | +| 11:08 | Repaired (same pattern as 08:45): on-chain finalize found, bundle/batch rows backfilled, relayer restarted. Single healthy anvil confirmed (the "restart" attempt exited on port-in-use — the original had self-recovered). | +| 11:1x | **Soak**: 18968 (end 519740) finalize verified via the NEW wrapper; local proof digest1 = `0x006770fb…` (new guest). 0 unfinalized; quarantine holds remote proofs for both ≥N bundles (rollback-safe). | + +## Findings / new issues this run + +1. **Anvil 1.7.1 instability under shadow-fork load** — one silent death (08:2x) + one silent stall with self-recovery (11:0x), both around state-persistence/heavy-activity moments, no panic in logs (once logging was enabled). The `--state` relaunch recovery path worked perfectly but is **undocumented** (`re-fork.sh` only covers fresh re-forking, which would lose legacyVerifiers routing mid-canary). Recommended: (a) a small anvil watchdog that relaunches from the state file on health-check failure (analogous to the autossh tunnel watchdog), (b) `01-setup-anvil.sh` should log anvil output to a file by default instead of `/dev/null`. +2. **Relayer lacks on-chain reconciliation for send-timeout transactions (hit twice)** — a tx that lands during an RPC stall is retried forever (commit: `ErrorIncorrectBatchHash` spam; finalize: bundle stuck `rs1` while `lastFinalized` on-chain has advanced). Both repaired by backfilling from on-chain evidence. Production-hardening item: before retrying, reconcile against chain state (`committedBatches`, `lastFinalizedBatchIndex`, receipt-by-nonce). +3. **Single-GPU sizing confirmed**: with GPU0 unavailable, 1×4090 (halo2-gpu build) kept pace with mainnet end-to-end (chunks+batch+bundle ≈ 15–40 min per bundle incl. witness fetch vs ~1.5–2 h mainnet cadence). +4. **Staging dependency**: mainnet's low-production morning allowed only ONE staged old-wrapper specimen; the rollback drill supplied the second. Without staging (8-31 run) there may be zero — supports adding `--stage-backlog K` to the runbook. +5. `30-canary-upgrade.sh` WARN "old assets not found … skipping VK-diff sanity check" is expected in canary mode (Phase A has no local assets); the step-f digest-differ check still covers the "is this a real upgrade" question. +6. Confirmed (not fixed this run): `make follow-report` does NOT split at `CANARY_AT_BATCH` (script reads only `UPGRADE_AT_*`) despite `30-canary-upgrade.sh`'s closing hint. + +## Acceptance summary + +| Criterion | Status | +|---|---| +| Phase A: ≥3 backlog bundles finalized purely from imported production proofs | ✅ (18961–18964, 06:08–06:11) | +| t1: genuine `updateVerifier`, routing asserted both sides of N, digest differ | ✅ (N=519738, wrapper `0x3a25…`) | +| Parallel window: old-proof bundle finalizes post-t1 via legacy routing | ✅ (18965, trace-verified) | +| Rollback drill: old wrapper restored at N; next ≥N bundle finalizes from imported proof | ✅ (18966 via restored old wrapper) | +| Re-upgrade after rollback (idempotent) | ✅ (N=519739, wrapper `0xA7898f4B…`) | +| t2: first ≥N bundle proven locally, finalized via NEW wrapper, digest-verified | ✅ (18967, `0x006770fb…`) | +| Soak: second new-stack bundle through the new wrapper | ✅ (18968, digest-verified) | +| `finalized_lag` back to 0 and quarantine rollback-safe | ✅ (0 unfinalized; 2 proofs ≥ N quarantined) | +| Crash-recovery under fire (unplanned) | ✅ 2× anvil incidents + 2× unrecorded-tx repairs, no test invalidation | + +--- + +## Re-validation run (post-doc-restructure, 2026-09-11 12:49–16:50 UTC) + +Full teardown → setup → canary sequence re-run after the trap-corpus restructure, strictly following the new docs — the "does the documentation actually walk?" acceptance. + +| Phase | Time (UTC) | Result | +|---|---|---| +| Teardown | 12:49 | stack + `.work` + `remote_bundle_proof` (18 851 rows) + containers | +| Phase A | 12:56–13:10 | 4 bundles (18966–18969) finalized on imported proofs, zero local proving | +| t1 | 13:35 | caught 18970 unproven → **N=519743**; wrapper `0x3a251c0c…5577` via genuine `updateVerifier` | +| Rollback drill | 13:44 | old wrapper restored at N (tx `0x1d38…8c68`); 18970 finalized from quarantined remote proof via OLD wrapper | +| Re-upgrade | 13:48 | N′=519744, wrapper `0xA7898f4B…c3a` (deterministic, same address as the morning run) | +| t2 | 16:45 | 18971 locally proven → finalized via NEW wrapper; `lastFinalizedBatchIndex`=519746, lag=1 | + +Zero stack failures, zero unplanned interventions; anvil stable throughout (Trap 44 did not recur). One transient `ErrorIncorrectBatchHash` (Trap 4 selector) during Phase A relayer warm-up, self-healed on the next tx. + +Findings: + +1. **Fixed — `monitor-catchup.py` wrote metrics to a foreign hardcoded path** (`/home/scroll/zzhang/…` for both `LOG_FILE` and `WORK_DIR`), so `make follow-status` always printed "(no metrics yet)" and the verifier-drift check read a stale `verifier.env`. Now derived from `__file__` (env-overridable via `SHADOW_WORK_DIR`/`SHADOW_METRICS_LOG`); verified end-to-end. +2. GUIDE prereq said "RDS tunnel + autossh" but this box reaches RDS **directly over LAN** (`192.168.1.108:15432`, `local-secrets.md`) — prereq text now covers both routes. +3. Anvil's listen port (`:18545`) and the single-GPU bundle-pipeline latency (~1–1.5 h at rs1/p1 before the bundle row flips) were undocumented; both added to follow/GUIDE.md. + +Benign observations: `assets_v2` absent is fine for canary (`30-` warns + skips the VK diff); dropping `remote_bundle_proof` is unnecessary for freshness — poll-sync re-upserts the full remote-prove history (~18 k rows) within minutes. diff --git a/docs/testing_reports/canary-parallel-upgrade-docker-2026-08-31.md b/docs/testing_reports/canary-parallel-upgrade-docker-2026-08-31.md new file mode 100644 index 0000000000..fd6527cd73 --- /dev/null +++ b/docs/testing_reports/canary-parallel-upgrade-docker-2026-08-31.md @@ -0,0 +1,66 @@ +# Canary Parallel-Upgrade Test Report (Docker Provers) — 2026-08-31 + +**Mode**: follow-mode canary parallel upgrade, second run — this time with **provers running as GPU docker containers** (bare metal was used only for coordinator/relayer/scripts). Extends the 2026-08-25 bare-metal run (`canary-parallel-upgrade-2026-08-25.md`). +**Host**: same machine, 2×RTX 4090, shadow DB local docker postgres:15 (`localhost:5433/shadow_rollup`), remote read-only `192.168.1.108:15432/mainnet_rollup`. +**Checkout**: `7d683b14` (branch `shadow-test-ai`, includes the Trap 38 halo2-gpu fixes and the Trap 41 `deleted_at IS NULL` sync fix — the latter measurably sped up baseline l2_block copies vs the previous run). + +## Stacks under test + +| | Old (production) | New (this checkout) | +|---|---|---| +| Guest | `79c1f8c` | zkvm-prover `bf887150` (v0.9.0) | +| bundle digest1 | `0x00398b78…9269` | `0x006770fb…5655` | +| Wrapper | `0x808297224e86b1a6055B5F790a2cE07Ed611f955` (forked MVRV) | deployed fresh per upgrade (see timeline) | +| Proof source | imported from remote DB (quarantine `remote_bundle_proof`) | **docker-proven locally** | + +## Prover dockerization (new this run) + +- Image: `scrolltech/prover:v4.7.14-c500b7d6-bf88715` (later `…-halo2gpu`), built locally with `build/dockerfiles/prover.Dockerfile` — the same production-style packaging as the devops `prover-image-build.yml` workflow (binary built externally, copied into a CUDA runtime image + solc). +- Launch: `04-prover-up.sh --docker` (driven by `30-canary-upgrade.sh --docker-provers` / `make canary-upgrade DOCKER_PROVERS=1 PROVER_IMAGE=…`). Each GPU gets a `shadow-prover-` container: same-path work-dir mounts, `--network host`, `--gpus device=`, `--user $(id -u):$(id -g)` with `HOME=/home/prover` and the SRS mounted at `/home/prover/.openvm/params` (Trap 12-proof). The container's **host PID** is written to the standard pidfile, so `11-follow-stop.sh` / `31-canary-rollback.sh` work unchanged; both also got a `docker rm -f shadow-prover-*` backstop. +- The devops workflow itself (`devops/core/prover_rust`, `init-repos.sh` pins `SCROLL_COMMIT`) was used as reference only; no CI trigger was needed. + +## Timeline (UTC) + +| Time | Event | +|---|---| +| 05:52 | First Phase A attempt failed fast: script default `MAINNET_DSN` is `localhost:15432` (RDS-tunnel convention) but this host reaches the DB at `192.168.1.108:15432` directly. Fixed via env override (`local-secrets.md` already had the right value). | +| 05:55 | Phase A up: `10-follow-up.sh --import-proofs --reset`. Fork + baseline + 18,673 production proofs quarantined. No coordinator/provers by design. | +| 05:56–05:58 | **Phase A acceptance ✅**: bundles 18786–18790 (ends 519531–519538) finalized purely from imported production proofs, zero local proving. | +| 06:00 | **t1**: `make canary-upgrade DOCKER_PROVERS=1` — boundary N=519539, new wrapper `0x3a251c0c…5577` deployed + registered via genuine `updateVerifier(10, 519539, …)`, routing asserted both sides, digest-differ check passed. **Docker prover start failed** (Finding 1); verifier/boundary/coordinator steps had already succeeded. | +| 06:01 | Finding 1 fixed (`04-prover-up.sh` canonicalizes `work_dir`); CANARY_* keys recorded manually (step j had been skipped on failure); docker provers started directly — both healthy, GPU-active in-container within a minute. | +| 06:04 | **Rollback drill ✅**: `31-canary-rollback.sh` — docker provers stopped cleanly via pidfile host-PID, `docker rm -f` backstop removed containers, `updateVerifier(10, 519539, OLD_WRAPPER)` restored, boundary cleared to +∞. | +| 06:12 | **Re-upgrade ✅**: N unchanged (519539), new wrapper `0xA7898f4B…c3a` registered; docker provers restarted by the script itself — idempotent docker path confirmed. | +| 06:56 | Mainnet produced bundle 18791 (end 519539 — first ≥ N). | +| 07:29–07:30 | **t2 ✅**: bundle 18791 proven by a docker prover and finalized through the new wrapper (tx `0x59a75b24…ee4f1` status true; fork `lastFinalizedBatchIndex` → 519539; proof digest1 `0x006770fb…5655` = new guest, not imported). | +| 07:41 | Switched image to the **halo2-gpu** build (`make prover_halo2gpu`, tag `…-halo2gpu`) after noticing 18791's bundle SNARK ran on CPU (Finding 4); provers restarted, one stale coordinator-side task assignment cleared. | +| 07:49–08:00 | **GPU-SNARK bundle ✅**: bundle 18792 (end 519540) proven by `shadow-prover-1` — halo2 wrapper `Create EVM proof` **6.05 s**, GPU mem peak **8.8 GiB** (Trap 38 fixes hold in a dockerized mixed-type process); finalized 08:00:02 via the new wrapper (tx `0x57e4bfe7…318c`, digest verified). Fork `lastFinalizedBatchIndex` → 519540. | + +## Bundle proving time: CPU vs GPU SNARK + +| Bundle | Image | Bundle task span | halo2 wrapper `Create EVM proof` | +|---|---|---|---| +| 18791 | `cuda`-only (`make prover`) | 06:56 → 07:29 ≈ **33 min** | dominates (CPU) | +| 18792 | `halo2-gpu` (`make prover_halo2gpu`) | ~07:49 → 07:59 ≈ **10 min** (STARK agg layers now dominate) | **6.05 s** | + +Rule of thumb confirmed: if a bundle task takes tens of minutes, check whether the binary was built with `make prover_halo2gpu`. + +## Findings / fixes this run + +1. **Docker mode broke on the `lib/..` path component** (fixed): `04-prover-up.sh` built `work_dir` as `${SCRIPT_DIR}/../.work/prover-N`. dockerd path-cleans bind-mount targets, but the prover opens its config by the literal path — inside the container `/…​/lib/..` does not resolve (`lib` doesn't exist there) → `File::open` ENOENT at `prover.rs:182`. Fixed by canonicalizing `work_dir` (`cd … && pwd`) before generating configs/mounts. Harmless on bare metal, fatal in docker. +2. **`MAINNET_DSN` script default is `localhost:15432`**; on this host the DB is at `192.168.1.108:15432` (no local tunnel). Export `MAINNET_DSN` explicitly (the scripts honor the env var). +3. **Restarting a prover leaves its coordinator-side assignment** ("already assigned a task" on the new process): cleared via `DELETE FROM prover_task WHERE proving_status IN (1,3)` (the sweeper would also reset it within ~10 min). +4. **Image built from a `make prover` binary runs the bundle SNARK on CPU** — 33 min vs 6 s. For 24 GB-class GPUs always build the image from a `make prover_halo2gpu` binary. GPU contention check before the swap: only the two `shadow-prover-*` containers were on the cards. +5. The Trap 41 `deleted_at IS NULL` predicates (previous commit) visibly sped up the baseline: l2_block range copies that took minutes per cycle on 2026-08-27 completed promptly during this run's baseline. + +## Acceptance summary + +| Criterion | Status | +|---|---| +| Phase A: ≥3 backlog bundles finalized purely from imported production proofs | ✅ (18786–18790, five bundles) | +| t1: genuine `updateVerifier`, routing asserted, digest differ | ✅ (N=519539) | +| Provers run in docker (no bare-metal prover) | ✅ (`shadow-prover-0/1`, GPU-active in-container) | +| Docker prover stop/start through 31/30 paths | ✅ rollback drill + re-upgrade | +| t2: first ≥N bundle proven by docker prover, finalized via new wrapper | ✅ (18791, digest-verified) | +| halo2-gpu bundle in docker (Trap 38 fixes validated in containers) | ✅ (18792: 6.05 s SNARK, peak 8.8 GiB) | + +Note: unlike the 2026-08-25 run, no < N bundle remained unfinalized at t1 (mainnet bundle boundary aligned exactly), so the interleaved-old-after-upgrade step had no specimen this time; it remains covered by the previous run and by the rollback drill. diff --git a/docs/testing_reports/snapshot-early-dryrun-and-relayer-tests.md b/docs/testing_reports/snapshot-early-dryrun-and-relayer-tests.md new file mode 100644 index 0000000000..6e9b5c8043 --- /dev/null +++ b/docs/testing_reports/snapshot-early-dryrun-and-relayer-tests.md @@ -0,0 +1,54 @@ +# Snapshot Mode — Early Dry-Run & Relayer Experiments (postmortem, 2026-05…07 era) + +> Moved out of `snapshot/GUIDE.md` and `docs/COMMON-TROUBLESHOOTING.md` on 2026-09-11 so the GUIDE stays a runbook. Content is a historical record — addresses, batch numbers and digests below were per-experiment; do not reuse them. Current facts live in [`../tests/shadow-testing/docs/CURRENT-STACK.md`](../tests/shadow-testing/docs/CURRENT-STACK.md). +> +> Era: Anvil fork blocks ~25.20–25.21M, bundles 17297–17301 / 17330, batches ~517.7–517.8k. Guest under test: v0.9.0 pre-release. + +## 1. Dry-run against a Mock ScrollChain (mock contract) + +| Transaction | Status | Notes | +|-------------|--------|-------| +| `commitBatches` | ✅ `eth_call` succeeded | Selector `0x9bbaa2ba` via mock `commitBatches(uint8,bytes32,bytes32)` | +| `finalizeBundlePostEuclidV2NoProof` | ✅ `eth_call` succeeded | Selector `0xbd6f916b` via mock no-op | +| `finalizeBundlePostEuclidV2` (with proof) | ✅ `eth_call` succeeded | Bundle 17301 with valid `OpenVMBundleProof` | + +## 2. Dry-run against the real ScrollChain proxy (fork block 25206000) + +| Transaction | Status | Notes | +|-------------|--------|-------| +| `commitBatches` | ⚠️ reached contract, reverted `ErrorIncorrectBatchHash` | Shadow DB batches (518565+) were ahead of the fork block's committed state (~517816) — expected, confirms calldata path | +| `finalizeBundlePostEuclidV2` | ✅ succeeded | Bundle 17330 (batch 517809), real mainnet proof — see §3 | + +Per-run deployed contracts (fork-only, now stale): + +| Contract | Address | Notes | +|----------|---------|-------| +| ZkEvmVerifierPostFeynman (v10) | `0x0dE180164Dc571522457101F5c47B2eaB36d0A82` | copied from mainnet via `anvil_setCode` — only valid for mainnet-digest proofs | +| Plonk verifier (v10) | `0x749fc77a1a131632a8b88e8703e489557660c75e` | copied from mainnet | +| ZkEvmVerifierPostFeynman (wrong) | `0xc3230A4C89a5Ce0455414215e533de4D8849b3f8` | deployed with wrong (Montgomery) digests — do not use | + +## 3. End-to-end `finalizeBundlePostEuclidV2` dry-run success (bundle 17330) + +- Batch 517809, codec V10, single-batch; proof replayed from the real mainnet finalize tx `0x753f8f9ca01d4e67f710c6dab8ce0b17a17a7ad46a9d7480d92657803a36ca24`. +- Public-input hash recomputed (`protocolVersion ‖ 204-byte publicInput`, 236 bytes total keccak) matched `bundle_pi_hash` exactly: `0xcd4421bad526bd108d9ae8c2af3d46ea1a986207f0b8c1af781b601c1ae50e5a`. +- Fork state resets applied pre-execution: `miscData` slot 0xa1 (`lastFinalized=517808`), `nextUnfinalizedQueueIndex` slot 0x68 → 0, `addProver` with a fresh EOA (Anvil default account carries 7702 code → `ErrorAccountIsNotEOA`, now Trap 55). +- Result: tx success, 425,719 gas, `lastFinalizedBatchIndex` → 517809, `finalizedStateRoots[517809]` set, queue index advanced to 998288. +- `anvil_setStorageAt` mapping-slot discovery (now Trap 54): direct-variable slots patch fine; mapping entries are ignored by the EVM. + +## 4. Multi-bundle relayer finalize test (5 consecutive bundles, first success) + +Bundles 17297–17301 (batches 517761–517765), shadow proofs, wrapper `0xb1F2C5c1ea2885278a1070350d12d3D8824265B0` (a per-run deploy): + +| Bundle | Batch | Tx | Status | Gas | +|--------|-------|----|--------|-----| +| 17297 | 517761 | `0x6d6264…cdaa725` | ✅ | 439,987 | +| 17298 | 517762 | `0x071268…1136516` | ✅ | 407,455 | +| 17299 | 517763 | `0x8f8894…6cabd5c` | ✅ | 407,479 | +| 17300 | 517764 | `0xa87721…302cd3e` | ✅ | 407,419 | +| 17301 | 517765 | `0x41ee42…c9cf891` | ✅ | 401,404 | + +All five finalized consecutively with no manual intervention; `lastFinalizedBatchIndex` 517760 → 517765. Pre-conditions that mattered (now traps): reset `bundle`/`batch.rollup_status = 1` (relayer only picks `RollupPending`), commit/finalize senders must be distinct addresses, and the finalizer loop runs independently of the (failing) batch committer. + +## 5. Source-hygiene lesson (from the v0.9.0 multi-bundle test) + +Do not `git checkout --` uncommitted source changes blindly: the v0.9.0 adaptations (`libzkp`, `prover-bin`, Go message types, `rust-toolchain`, `Cargo.lock`) were once wiped this way and had to be reconstructed from compiler errors. Check `git diff --stat` before bulk reverts; stage or stash anything you intend to keep. diff --git a/rollup/cmd/rollup_relayer/app/app.go b/rollup/cmd/rollup_relayer/app/app.go index dc36f91c2a..e2c4da1cc6 100644 --- a/rollup/cmd/rollup_relayer/app/app.go +++ b/rollup/cmd/rollup_relayer/app/app.go @@ -148,15 +148,19 @@ func action(ctx *cli.Context) error { } // Watcher loop to fetch missing blocks - go utils.LoopWithContext(subCtx, 2*time.Second, func(ctx context.Context) { - number, loopErr := rutils.GetLatestConfirmedBlockNumber(ctx, l2ethClient, cfg.L2Config.Confirmations) - if loopErr != nil { - log.Error("failed to get block number", "err", loopErr) - return - } - // errors are logged in the try method as well - _ = l2watcher.TryFetchRunningMissingBlocks(number) - }) + if cfg.L2Config.DisableL2Watcher { + log.Info("L2 watcher is disabled (disable_l2_watcher=true), skipping missing-blocks fetch loop") + } else { + go utils.LoopWithContext(subCtx, 2*time.Second, func(ctx context.Context) { + number, loopErr := rutils.GetLatestConfirmedBlockNumber(ctx, l2ethClient, cfg.L2Config.Confirmations) + if loopErr != nil { + log.Error("failed to get block number", "err", loopErr) + return + } + // errors are logged in the try method as well + _ = l2watcher.TryFetchRunningMissingBlocks(number) + }) + } go utils.Loop(subCtx, time.Duration(cfg.L2Config.ChunkProposerConfig.ProposeIntervalMilliseconds)*time.Millisecond, chunkProposer.TryProposeChunk) diff --git a/rollup/internal/config/l2.go b/rollup/internal/config/l2.go index 91ea322cd0..5616aa6106 100644 --- a/rollup/internal/config/l2.go +++ b/rollup/internal/config/l2.go @@ -16,6 +16,10 @@ type L2Config struct { L2MessageQueueAddress common.Address `json:"l2_message_queue_address"` // The WithdrawTrieRootSlot in L2MessageQueue contract. WithdrawTrieRootSlot common.Hash `json:"withdraw_trie_root_slot,omitempty"` + // DisableL2Watcher disables the L2 watcher loop that fetches missing blocks. + // Useful for shadow-fork testing where the l2_block table is imported/empty and a + // genesis crawl is undesirable. Defaults to false (watcher enabled). + DisableL2Watcher bool `json:"disable_l2_watcher"` // The relayer config RelayerConfig *RelayerConfig `json:"relayer_config"` // The chunk_proposer config @@ -34,6 +38,7 @@ type ChunkProposerConfig struct { MaxL2GasPerChunk uint64 `json:"max_l2_gas_per_chunk"` ChunkTimeoutSec uint64 `json:"chunk_timeout_sec"` MaxUncompressedBatchBytesSize uint64 `json:"max_uncompressed_batch_bytes_size"` + Disable bool `json:"disable"` } // BatchProposerConfig loads batch_proposer configuration items. @@ -42,12 +47,15 @@ type BatchProposerConfig struct { BatchTimeoutSec uint64 `json:"batch_timeout_sec"` MaxChunksPerBatch int `json:"max_chunks_per_batch"` MaxUncompressedBatchBytesSize uint64 `json:"max_uncompressed_batch_bytes_size"` + Disable bool `json:"disable"` } // BundleProposerConfig loads bundle_proposer configuration items. type BundleProposerConfig struct { - MaxBatchNumPerBundle uint64 `json:"max_batch_num_per_bundle"` - BundleTimeoutSec uint64 `json:"bundle_timeout_sec"` + MaxBatchNumPerBundle uint64 `json:"max_batch_num_per_bundle"` + BundleTimeoutSec uint64 `json:"bundle_timeout_sec"` + BundleProposeCooldownSec uint64 `json:"bundle_propose_cooldown_sec"` + Disable bool `json:"disable"` } // BlobUploaderConfig loads blob_uploader configuration items. diff --git a/rollup/internal/config/relayer.go b/rollup/internal/config/relayer.go index 2e50969ada..cb9a228d24 100644 --- a/rollup/internal/config/relayer.go +++ b/rollup/internal/config/relayer.go @@ -37,6 +37,11 @@ type SenderConfig struct { MaxPendingBlobTxs int64 `json:"max_pending_blob_txs"` // The timestamp of the Ethereum Fusaka upgrade in seconds since epoch. FusakaTimestamp uint64 `json:"fusaka_timestamp"` + // ChainNonceOnly initializes the sender nonce from the chain pending nonce only, + // ignoring stale pending_transaction rows in the database. + // Useful for shadow-fork testing against a DB imported from production. + // Defaults to false (nonce = max(db nonce + 1, chain pending nonce)). + ChainNonceOnly bool `json:"chain_nonce_only"` } type BatchSubmission struct { diff --git a/rollup/internal/controller/relayer/l2_relayer.go b/rollup/internal/controller/relayer/l2_relayer.go index e57b6ca73f..4c3a60ef00 100644 --- a/rollup/internal/controller/relayer/l2_relayer.go +++ b/rollup/internal/controller/relayer/l2_relayer.go @@ -536,6 +536,11 @@ func (r *Layer2Relayer) ProcessPendingBatches() { "end hash", lastBatch.Hash, "RollupContractAddress", r.cfg.RollupContractAddress, "err", err, + ) + log.Debug( + "Failed to send commitBatch tx to layer1, calldata dump", + "start index", firstBatch.Index, + "end index", lastBatch.Index, "calldata", common.Bytes2Hex(calldata), ) return @@ -768,7 +773,8 @@ func (r *Layer2Relayer) finalizeBundle(bundle *orm.Bundle, withProof bool) error if err != nil { log.Error("finalizeBundle in layer1 failed", "with proof", withProof, "index", bundle.Index, "start batch index", bundle.StartBatchIndex, "end batch index", bundle.EndBatchIndex, - "RollupContractAddress", r.cfg.RollupContractAddress, "err", err, "calldata", common.Bytes2Hex(calldata)) + "RollupContractAddress", r.cfg.RollupContractAddress, "err", err) + log.Debug("finalizeBundle in layer1 failed, calldata dump", "index", bundle.Index, "calldata", common.Bytes2Hex(calldata)) return err } @@ -906,6 +912,16 @@ func (r *Layer2Relayer) handleConfirmation(cfm *sender.Confirmation) { status = types.RollupFinalizeFailed r.metrics.rollupL2BundlesFinalizedConfirmedFailedTotal.Inc() log.Warn("FinalizeBundleTxType transaction confirmed but failed in layer1", "confirmation", cfm) + // Status RollupFinalizeFailed (7) is NOT picked up again by ProcessPendingBundles + // (GetFirstPendingBundle only queries rollup_status = RollupPending); the bundle is + // stranded until rollup_status is manually reset to 1. + bundleIndex := uint64(0) + bundles, queryErr := r.bundleOrm.GetBundles(r.ctx, map[string]interface{}{"hash": bundleHash}, nil, 1) + if queryErr == nil && len(bundles) > 0 { + bundleIndex = bundles[0].Index + } + log.Error("Bundle is now STRANDED with rollup_status=RollupFinalizeFailed(7): it will NOT be retried by ProcessPendingBundles, manual intervention required (reset rollup_status to 1)", + "bundle index", bundleIndex, "bundle hash", bundleHash, "tx hash", cfm.TxHash.String(), "query err", queryErr) } err := r.db.Transaction(func(dbTX *gorm.DB) error { diff --git a/rollup/internal/controller/sender/estimategas.go b/rollup/internal/controller/sender/estimategas.go index 20d66beefa..f0711f1b01 100644 --- a/rollup/internal/controller/sender/estimategas.go +++ b/rollup/internal/controller/sender/estimategas.go @@ -101,10 +101,19 @@ func (s *Sender) estimateBlobGas(to *common.Address, data []byte, sidecar *types return feeData, nil } +const ( + // estimateGasCap is an explicit non-zero gas limit for the eth_estimateGas CallMsg. + // Some nodes (e.g. Anvil) reject estimation requests that carry fee caps but leave + // Gas at the go-ethereum default of 0. go-ethereum's EstimateGas only uses this as + // the upper bound of its binary search, so a generous cap does not affect the result. + estimateGasCap = 30_000_000 +) + func (s *Sender) estimateGasLimit(to *common.Address, data []byte, sidecar *types.BlobTxSidecar, gasPrice, gasTipCap, gasFeeCap, blobGasFeeCap *big.Int) (uint64, *types.AccessList, error) { msg := ethereum.CallMsg{ From: s.transactionSigner.GetAddr(), To: to, + Gas: estimateGasCap, GasPrice: gasPrice, GasTipCap: gasTipCap, GasFeeCap: gasFeeCap, diff --git a/rollup/internal/controller/sender/sender.go b/rollup/internal/controller/sender/sender.go index 5b37473596..d355a19e83 100644 --- a/rollup/internal/controller/sender/sender.go +++ b/rollup/internal/controller/sender/sender.go @@ -450,19 +450,26 @@ func (s *Sender) createTx(feeData *FeeData, target *common.Address, data []byte, } // initializeNonce initializes the nonce by taking the maximum of database nonce and pending nonce. +// When ChainNonceOnly is enabled, the database is ignored and the chain pending nonce is used +// directly (useful for shadow-fork testing with stale pending_transaction rows). func (s *Sender) initializeNonce() (uint64, error) { - // Get maximum nonce from database - dbNonce, err := s.pendingTransactionOrm.GetMaxNonceBySenderAddress(s.ctx, s.transactionSigner.GetAddr().Hex()) - if err != nil { - return 0, fmt.Errorf("failed to get max nonce from database for address %s, err: %w", s.transactionSigner.GetAddr().Hex(), err) - } - // Get pending nonce from the client pendingNonce, err := s.client.PendingNonceAt(s.ctx, s.transactionSigner.GetAddr()) if err != nil { return 0, fmt.Errorf("failed to get pending nonce for address %s, err: %w", s.transactionSigner.GetAddr().Hex(), err) } + if s.config.ChainNonceOnly { + log.Info("nonce initialization (chain_nonce_only mode, ignoring database pending transactions)", "address", s.transactionSigner.GetAddr().Hex(), "pendingNonce", pendingNonce, "finalNonce", pendingNonce) + return pendingNonce, nil + } + + // Get maximum nonce from database + dbNonce, err := s.pendingTransactionOrm.GetMaxNonceBySenderAddress(s.ctx, s.transactionSigner.GetAddr().Hex()) + if err != nil { + return 0, fmt.Errorf("failed to get max nonce from database for address %s, err: %w", s.transactionSigner.GetAddr().Hex(), err) + } + // Take the maximum of pending nonce and (db nonce + 1) // Database stores the used nonce, so the next available nonce should be dbNonce + 1 // When dbNonce is -1 (no records), dbNonce + 1 = 0, which is correct diff --git a/rollup/internal/controller/watcher/batch_proposer.go b/rollup/internal/controller/watcher/batch_proposer.go index 522ce07cb7..eccbb1a2fc 100644 --- a/rollup/internal/controller/watcher/batch_proposer.go +++ b/rollup/internal/controller/watcher/batch_proposer.go @@ -133,6 +133,9 @@ func (p *BatchProposer) SetReplayDB(replayDB *gorm.DB) { // TryProposeBatch tries to propose a new batches. func (p *BatchProposer) TryProposeBatch() { p.batchProposerCircleTotal.Inc() + if p.cfg.Disable { + return + } if err := p.proposeBatch(); err != nil { p.proposeBatchFailureTotal.Inc() log.Error("proposeBatchChunks failed", "err", err) diff --git a/rollup/internal/controller/watcher/bundle_proposer.go b/rollup/internal/controller/watcher/bundle_proposer.go index 388355e6b8..572d3bc5fa 100644 --- a/rollup/internal/controller/watcher/bundle_proposer.go +++ b/rollup/internal/controller/watcher/bundle_proposer.go @@ -29,6 +29,12 @@ type BundleProposer struct { cfg *config.BundleProposerConfig + // lastBundleCreatedAt is used to enforce a wall-clock cooldown between + // consecutive bundle proposals. This is useful in shadow-fork scenarios + // where L2 block timestamps are historical, so the normal bundle timeout + // would otherwise fire immediately. + lastBundleCreatedAt time.Time + minCodecVersion encoding.CodecVersion chainCfg *params.ChainConfig @@ -52,6 +58,7 @@ func NewBundleProposer(ctx context.Context, cfg *config.BundleProposerConfig, mi batchOrm: orm.NewBatch(db), bundleOrm: orm.NewBundle(db), cfg: cfg, + lastBundleCreatedAt: time.Now(), minCodecVersion: minCodecVersion, chainCfg: chainCfg, @@ -91,6 +98,18 @@ func NewBundleProposer(ctx context.Context, cfg *config.BundleProposerConfig, mi // TryProposeBundle tries to propose a new bundle. func (p *BundleProposer) TryProposeBundle() { p.bundleProposerCircleTotal.Inc() + + if p.cfg.Disable { + return + } + + if p.cfg.BundleProposeCooldownSec > 0 { + if elapsed := time.Since(p.lastBundleCreatedAt).Seconds(); elapsed < float64(p.cfg.BundleProposeCooldownSec) { + log.Debug("bundle proposal cooldown has not elapsed", "elapsed", elapsed, "cooldown", p.cfg.BundleProposeCooldownSec) + return + } + } + if err := p.proposeBundle(); err != nil { p.proposeBundleFailureTotal.Inc() log.Error("propose new bundle failed", "err", err) @@ -121,6 +140,8 @@ func (p *BundleProposer) UpdateDBBundleInfo(batches []*orm.Batch, codecVersion e log.Error("update chunk info in orm failed", "err", err) return err } + + p.lastBundleCreatedAt = time.Now() return nil } diff --git a/rollup/internal/controller/watcher/chunk_proposer.go b/rollup/internal/controller/watcher/chunk_proposer.go index 843abaf542..bba9df1eb0 100644 --- a/rollup/internal/controller/watcher/chunk_proposer.go +++ b/rollup/internal/controller/watcher/chunk_proposer.go @@ -141,6 +141,9 @@ func (p *ChunkProposer) SetReplayDB(replayDB *gorm.DB) { // TryProposeChunk tries to propose a new chunk. func (p *ChunkProposer) TryProposeChunk() { p.chunkProposerCircleTotal.Inc() + if p.cfg.Disable { + return + } if err := p.ProposeChunk(); err != nil { p.proposeChunkFailureTotal.Inc() log.Error("propose new chunk failed", "err", err) diff --git a/rust-toolchain b/rust-toolchain index c17a78fd9e..fd7eda1132 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,4 +1,4 @@ [toolchain] -channel = "nightly-2025-08-18" +channel = "nightly-2025-11-20" targets = ["riscv32im-unknown-none-elf", "x86_64-unknown-linux-gnu"] -components = ["llvm-tools", "rustc-dev"] \ No newline at end of file +components = ["llvm-tools", "rust-src"] \ No newline at end of file diff --git a/tests/prover-e2e/README.md b/tests/prover-e2e/README.md index cdfa62a3a4..d0eefdcf02 100644 --- a/tests/prover-e2e/README.md +++ b/tests/prover-e2e/README.md @@ -109,9 +109,12 @@ docker rm -f local_postgres # kill stale container make setup_db # recreate ``` +> After changing `docker-compose.yml`, old containers can persist with stale port mappings — always `docker rm -f` before `docker compose up`. The E2E container is named `local_postgres`. + ### Prover 403 downloading app.vmexe from S3 - Verify `base_url` in prover `config.json` doesn't contain an extra `releases/` segment. - Test with: `curl -sI "chunk//app.vmexe"` +- S3 prefixes/digest encodings differ per release (v0.8.0 has no `/releases/`; v0.9.0+ requires `agg_vk.bin` per circuit) — see [`../shadow-testing/docs/CURRENT-STACK.md`](../shadow-testing/docs/CURRENT-STACK.md) and shadow-testing follow-mode Trap 33. ### mismatched post-state root (during coordinator task generation) Blocks are from before the configured fork. Use a higher block range (≥ 33,750,000 for galileoV2). diff --git a/tests/prover-e2e/cloak-galileoV2/.make.env b/tests/prover-e2e/cloak-galileoV2/.make.env index 75ffd1e544..adb4711f97 100644 --- a/tests/prover-e2e/cloak-galileoV2/.make.env +++ b/tests/prover-e2e/cloak-galileoV2/.make.env @@ -1,4 +1,4 @@ BEGIN_BLOCK?=33750000 END_BLOCK?=33750005 SCROLL_FORK_NAME=galileoV2 -SCROLL_ZKVM_VERSION?=v0.8.0 \ No newline at end of file +SCROLL_ZKVM_VERSION?=releases/v0.9.0 \ No newline at end of file diff --git a/tests/prover-e2e/docker-e2e/conf/prover.json b/tests/prover-e2e/docker-e2e/conf/prover.json index 241b61adc1..2f9be1ef95 100644 --- a/tests/prover-e2e/docker-e2e/conf/prover.json +++ b/tests/prover-e2e/docker-e2e/conf/prover.json @@ -17,7 +17,7 @@ }, "circuits": { "galileoV2": { - "base_url": "https://circuit-release.s3.us-west-2.amazonaws.com/scroll-zkvm/galileov2/", + "base_url": "https://circuit-release.s3.us-west-2.amazonaws.com/scroll-zkvm/releases/v0.9.0/", "workspace_path": ".work/galileo" } } diff --git a/tests/prover-e2e/mainnet-galileoV2/.make.env b/tests/prover-e2e/mainnet-galileoV2/.make.env index c7f03a5a33..525b337cb5 100644 --- a/tests/prover-e2e/mainnet-galileoV2/.make.env +++ b/tests/prover-e2e/mainnet-galileoV2/.make.env @@ -5,4 +5,4 @@ BEGIN_BLOCK?=33750000 END_BLOCK?=33750005 SCROLL_FORK_NAME=galileoV2 -SCROLL_ZKVM_VERSION?=v0.8.0 +SCROLL_ZKVM_VERSION?=releases/v0.9.0 diff --git a/tests/shadow-testing/.env.example b/tests/shadow-testing/.env.example new file mode 100644 index 0000000000..3a44df2cc2 --- /dev/null +++ b/tests/shadow-testing/.env.example @@ -0,0 +1,57 @@ +# Shadow Coordinator + Prover Environment Variables +# Copy this file to .env and fill in real values + +# ============================================================================ +# PRODUCTION RDS (read-only, via IDC port-forward) +# ============================================================================ +PROD_DB_HOST=localhost +PROD_DB_PORT=15432 +PROD_DB_NAME=rollup +PROD_DB_USER=YOUR_PROD_USER_HERE +PROD_DB_PASSWORD=YOUR_PROD_PASSWORD_HERE + +# Full DSN (constructed from above, or override directly) +# PROD_DB=postgresql://YOUR_PROD_USER_HERE:YOUR_PROD_PASSWORD_HERE@localhost:15432/rollup + +# ============================================================================ +# SHADOW DATABASE (local PostgreSQL in Docker) +# ============================================================================ +SHADOW_DB_HOST=localhost +SHADOW_DB_PORT=5433 +SHADOW_DB_NAME=shadow_rollup +SHADOW_DB_USER=postgres +SHADOW_DB_PASSWORD=YOUR_SHADOW_PASSWORD_HERE + +# Full DSN (constructed from above, or override directly) +# SHADOW_DB=postgresql://postgres:YOUR_SHADOW_PASSWORD_HERE@localhost:5433/shadow_rollup + +# ============================================================================ +# COORDINATOR AUTH +# ============================================================================ +# JWT secret for prover login challenge-response. +# MUST match between coordinator config and prover expectations. +COORDINATOR_AUTH_SECRET=YOUR_RANDOM_SECRET_HERE + +# ============================================================================ +# DOCKER IMAGE TAG +# ============================================================================ +IMAGE_TAG=v4.7.13-openvm16 + +# ============================================================================ +# L2 RPC ENDPOINT +# Must support debug_executionWitness and debug_dbGet. +# https://mainnet-rpc.scroll.io works; https://rpc.scroll.io does NOT. +# ============================================================================ +L2_RPC=https://mainnet-rpc.scroll.io + +# ============================================================================ +# VERIFIER ASSETS PATH +# Directory containing subdirectories: openvm-0.5.6, openvm-v0.7.1, openvm-v0.8.0 +# ============================================================================ +VERIFIER_DIR=/tmp/shadow-verifier-assets + +# ============================================================================ +# DATA IMPORT LIMITS +# ============================================================================ +BATCH_LIMIT=50 +BUNDLE_LIMIT=20000 diff --git a/tests/shadow-testing/.gitignore b/tests/shadow-testing/.gitignore new file mode 100644 index 0000000000..badc900a42 --- /dev/null +++ b/tests/shadow-testing/.gitignore @@ -0,0 +1,23 @@ +# Work directory (logs, pid files, generated configs) +.work/ + +# Anvil state files (large, environment-specific) +states/*.json + +# Generated configs (from templates) +.work/*.json + +# Prover work directories +.work/prover-*/ + +# Relayer logs +.work/relayer-*.log + +# Coordinator logs +.work/coordinator-*.log + +# Actual config files with secrets (use .template files instead) +configs/*.json +follow/configs/*.json +snapshot/configs/*.json +__pycache__/ diff --git a/tests/shadow-testing/Makefile b/tests/shadow-testing/Makefile new file mode 100644 index 0000000000..c8bbcf4a98 --- /dev/null +++ b/tests/shadow-testing/Makefile @@ -0,0 +1,128 @@ +# Shadow Testing Makefile — thin dispatcher. +# +# The two test modes live in their own directories, each with its own +# Makefile, scripts, configs and GUIDE: +# +# follow/ Follow mode (primary): fork the current mainnet tip and follow +# mainnet bundle production in real time. Default acceptance test +# for prover/guest upgrades. +# snapshot/ Snapshot replay mode: fork a historical block and prove/finalize +# a fixed bundle range. Incident reproduction, single-bundle +# debugging, Sepolia testing, codec-migration checks. +# +# Shared scripts and the relayer config template live in lib/. +# .work/ (logs, pidfiles, anvil state) is shared by both modes and stays here. + +CONFIG ?= mainnet +BUNDLE_RANGE ?= 17297:17301 + +# --- Follow mode ------------------------------------------------------------- +.PHONY: follow-up follow-stop follow-status follow-report re-fork + +follow-up: + $(MAKE) -C follow follow + +follow-stop: + $(MAKE) -C follow follow-stop + +follow-status: + $(MAKE) -C follow follow-status + +follow-report: + $(MAKE) -C follow follow-report + +re-fork: + $(MAKE) -C follow re-fork + +# --- Snapshot replay mode ---------------------------------------------------- +.PHONY: snapshot-all snapshot-env snapshot-prove snapshot-finalize \ + snapshot-sepolia-all snapshot-status snapshot-verify \ + snapshot-docker-all snapshot-docker-env snapshot-docker-prove \ + snapshot-docker-finalize snapshot-docker-stop snapshot-stop snapshot-clean + +snapshot-all: + $(MAKE) -C snapshot all CONFIG=$(CONFIG) BUNDLE_RANGE=$(BUNDLE_RANGE) + +snapshot-env: + $(MAKE) -C snapshot env CONFIG=$(CONFIG) BUNDLE_RANGE=$(BUNDLE_RANGE) + +snapshot-prove: + $(MAKE) -C snapshot prove CONFIG=$(CONFIG) BUNDLE_RANGE=$(BUNDLE_RANGE) + +snapshot-finalize: + $(MAKE) -C snapshot finalize CONFIG=$(CONFIG) BUNDLE_RANGE=$(BUNDLE_RANGE) + +snapshot-sepolia-all: + $(MAKE) -C snapshot sepolia-all CONFIG=$(CONFIG) BUNDLE_RANGE=$(BUNDLE_RANGE) + +snapshot-status: + $(MAKE) -C snapshot status CONFIG=$(CONFIG) BUNDLE_RANGE=$(BUNDLE_RANGE) + +snapshot-verify: + $(MAKE) -C snapshot verify CONFIG=$(CONFIG) BUNDLE_RANGE=$(BUNDLE_RANGE) + +snapshot-docker-all: + $(MAKE) -C snapshot docker-all CONFIG=$(CONFIG) BUNDLE_RANGE=$(BUNDLE_RANGE) + +snapshot-docker-env: + $(MAKE) -C snapshot docker-env CONFIG=$(CONFIG) BUNDLE_RANGE=$(BUNDLE_RANGE) + +snapshot-docker-prove: + $(MAKE) -C snapshot docker-prove CONFIG=$(CONFIG) BUNDLE_RANGE=$(BUNDLE_RANGE) + +snapshot-docker-finalize: + $(MAKE) -C snapshot docker-finalize CONFIG=$(CONFIG) BUNDLE_RANGE=$(BUNDLE_RANGE) + +snapshot-docker-stop: + $(MAKE) -C snapshot docker-stop CONFIG=$(CONFIG) + +snapshot-stop: + $(MAKE) -C snapshot stop CONFIG=$(CONFIG) + +snapshot-clean: + $(MAKE) -C snapshot clean CONFIG=$(CONFIG) + +# --- Documentation hygiene ---------------------------------------------------- +# doc-check: validate the trap registry — no duplicate trap numbers across the +# three troubleshooting files, and every "Trap N" reference in any *.md under +# tests/shadow-testing (plus root AGENTS.md) resolves to exactly one definition. +.PHONY: doc-check + +doc-check: + @bash -c 'set -euo pipefail; \ + files="docs/COMMON-TROUBLESHOOTING.md follow/TROUBLESHOOTING.md snapshot/TROUBLESHOOTING.md docs/TRAP-ARCHIVE.md"; \ + dups=$$(grep -h "^### Trap " $$files | grep -oE "^### Trap [0-9]+" | awk "{print \$$3}" | sort -n | uniq -d); \ + if [ -n "$$dups" ]; then echo "doc-check: DUPLICATE trap numbers: $$dups" >&2; exit 1; fi; \ + refs_ok=0; refs_bad=0; \ + for f in $$(grep -rlE "Trap [0-9]+" --include="*.md" . ../../../AGENTS.md 2>/dev/null); do \ + for n in $$(grep -oE "Trap [0-9]+" "$$f" | sort -u | grep -oE "[0-9]+"); do \ + cnt=$$(grep -h "^### Trap $$n[: ]" $$files | wc -l); \ + if [ "$$cnt" -ne 1 ]; then echo "doc-check: BAD ref Trap $$n in $$f (definitions: $$cnt)" >&2; refs_bad=$$((refs_bad+1)); else refs_ok=$$((refs_ok+1)); fi; \ + done; \ + done; \ + total=$$(grep -h "^### Trap " $$files | wc -l); \ + echo "doc-check: OK — $$total traps defined, $$refs_ok unique refs validated, 0 duplicates"' +.PHONY: help + +help: + @echo "Shadow Testing — two modes, each with its own directory:" + @echo "" + @echo "Follow Mode (primary — fork current mainnet tip, follow indefinitely):" + @echo " make follow-up Bring up the full follow-mode stack" + @echo " make follow-status Latest monitor snapshot + finalize lag" + @echo " make follow-report Throughput report for the current run" + @echo " make re-fork Re-fork Anvil at latest block (recovery)" + @echo " make follow-stop Stop the follow-mode stack" + @echo " (or: make -C follow ; guide: follow/GUIDE.md)" + @echo "" + @echo "Snapshot Replay Mode (historical fork, fixed bundle range):" + @echo " make snapshot-all CONFIG= BUNDLE_RANGE= Full pipeline" + @echo " make snapshot-env CONFIG= BUNDLE_RANGE= Setup Anvil + DB" + @echo " make snapshot-prove CONFIG= BUNDLE_RANGE= Prove bundles" + @echo " make snapshot-finalize CONFIG= BUNDLE_RANGE= Finalize bundles" + @echo " make snapshot-status CONFIG= BUNDLE_RANGE= Check status" + @echo " make snapshot-verify CONFIG= BUNDLE_RANGE= Verify on-chain" + @echo " make snapshot-sepolia-all CONFIG=sepolia BUNDLE_RANGE= Sepolia pipeline" + @echo " make snapshot-docker-{all,env,prove,finalize,stop} Docker pipeline" + @echo " make snapshot-stop / snapshot-clean Stop / cleanup" + @echo " (or: make -C snapshot ; guide: snapshot/GUIDE.md)" diff --git a/tests/shadow-testing/README.md b/tests/shadow-testing/README.md new file mode 100644 index 0000000000..945b658bbf --- /dev/null +++ b/tests/shadow-testing/README.md @@ -0,0 +1,117 @@ +# Shadow Testing Toolkit + +Toolkit for running Scroll shadow fork tests against Anvil: a local coordinator + local prover fed by production task data, without interfering with the live system. There are two test modes, each in its own directory with its own Makefile, scripts, configs and guide. + +## Choose a Mode + +| Mode | What It Does | When To Use | +|------|--------------|-------------| +| **[Follow mode](follow/)** (primary) | Fork the **current** ETH mainnet state, baseline-sync the shadow DB, then follow mainnet indefinitely — poll-syncing new chunk/batch/bundle rows, proving them locally, finalizing on the fork — until a preset duration (default 48h) or a failure | **Default acceptance test** for prover/guest upgrades | +| **[Snapshot replay mode](snapshot/)** | Fork a historical block, import a fixed bundle range, prove & finalize ~N bundles | Reproducing a specific incident, debugging one bundle, Sepolia testing, targeted codec-migration checks | + +## Quick Start + +```bash +# Follow mode (primary acceptance test) +cd tests/shadow-testing/follow +make follow # one-shot bring-up of the full follow-mode stack +make follow-status # latest monitor snapshot + lag summary +make follow-report # final report, windowed to this run (SHADOW_REPORT_START) +make follow-stop # tear down (script supports --keep-anvil) + +# Mid-run upgrade test (continuous finalization across a zk-stack upgrade): +# Phase 1 on the production release, then cut over to the new release on the +# SAME fork/DB. See follow/GUIDE.md "Mid-Run Upgrade Test". +make follow-old # Phase 1: old stack = production release + production verifier +make follow-upgrade # Phase 2: deploy/register new verifier, swap coordinator + # assets, restart provers — finalization never stops + +# Snapshot replay mode (fixed bundle range) +cd tests/shadow-testing/snapshot +make docker-all CONFIG=mainnet BUNDLE_RANGE=17302:17305 # Docker (recommended) +make all CONFIG=mainnet BUNDLE_RANGE=17297:17301 # bare-metal +``` + +The root `Makefile` is a thin dispatcher (`make follow-up`, `make snapshot-all ...`, `make help`). `lib/` holds scripts shared by both modes (`01-setup-anvil.sh`, `03-deploy-verifier.sh`, `04-prover-up.sh`, `06-run-relayer.sh`, `anvil-utils.sh`, `sync-queue-hashes.py`, `configs/relayer.json.template`). Runtime state (`.work/` — logs, pidfiles, Anvil state, `follow-run.env`) is shared by both modes at `tests/shadow-testing/.work`. + +## Documentation + +| Document | What It Covers | +|----------|----------------| +| [`follow/GUIDE.md`](follow/GUIDE.md) | Follow mode — bring-up, daemons, steady state, recovery, mid-run hard-switch upgrade, canary parallel-upgrade | +| [`snapshot/GUIDE.md`](snapshot/GUIDE.md) | Snapshot replay mode — step-by-step manual setup, verifier deployment, relayer dry-run | +| [`docs/TROUBLESHOOTING.md`](docs/TROUBLESHOOTING.md) | **Trap index** — all numbered traps → per-file locations | +| [`docs/COMMON-TROUBLESHOOTING.md`](docs/COMMON-TROUBLESHOOTING.md) | Mode-independent traps, pre-flight ritual, checklists, symptom table | +| [`docs/CURRENT-STACK.md`](docs/CURRENT-STACK.md) | Dated version-sensitive facts (production stack, S3 prefixes, digest encoding, codec thresholds) | +| [`docs/rds-query-rules.md`](docs/rds-query-rules.md) | Production RDS query discipline (partial indexes, `count(*)` bans) | +| [`docs/bundle-digest-encoding.md`](docs/bundle-digest-encoding.md) | Bundle verifier digest encodings per release (Montgomery vs canonical) | +| [`follow/TROUBLESHOOTING.md`](follow/TROUBLESHOOTING.md) | Follow-mode traps (poll sync, starvation, live finalization, canary) | +| [`snapshot/TROUBLESHOOTING.md`](snapshot/TROUBLESHOOTING.md) | Snapshot-replay traps (historical fork, fixed bundle range, Sepolia) | +| [`docs/contract-addresses.md`](docs/contract-addresses.md) | L1 contract addresses per network | +| `../../docs/testing_reports/` | Dated test reports (one file per run; indexed from root `AGENTS.md`) | + +## Prerequisites + +- [Foundry](https://book.getfoundry.sh/) (`cast`, `forge`) +- `jq` +- `docker compose` (for Docker mode) +- PostgreSQL client (`psql`) +- Access to production RDS (via IDC port-forward) + +## Configurations + +Each mode has its own `configs/`; copy templates and fill in secrets: + +```bash +cp follow/configs/mainnet.json.template follow/configs/mainnet.json +cp follow/configs/coordinator.json.template follow/configs/coordinator.json +# Only for the mid-run upgrade test: the NEW release's config +cp follow/configs/mainnet-next.json.template follow/configs/mainnet-next.json +cp snapshot/configs/sepolia.json.template snapshot/configs/sepolia.json +# Edit the files and replace placeholders: +# - YOUR_ALCHEMY_API_KEY (in mainnet.json / sepolia.json fork.url) +# - YOUR_SHADOW_DB_PASSWORD (in mainnet.json / sepolia.json db.dsn) +# - prover.s3_base_url + prover.circuit_version + assets.assets_v2 +# (in mainnet-next.json — the NEW release under test) +``` + +## Contributing & Documentation Conventions + +When you discover a new trap or workaround, **write it back** — this toolkit's value is its accumulated failure knowledge. Follow the layering below so the corpus stays navigable as it grows. + +### Knowledge layering — where new knowledge goes + +| Layer | File(s) | What belongs there | What does NOT | +|---|---|---|---| +| **Runbook** | `follow/GUIDE.md`, `snapshot/GUIDE.md` | How to run a mode: procedures, commands, acceptance criteria, recovery paths | One-off incidents, version-baked addresses/digests | +| **Trap** | `docs/COMMON-TROUBLESHOOTING.md` (mode-independent), `follow/TROUBLESHOOTING.md`, `snapshot/TROUBLESHOOTING.md` (active); `docs/TRAP-ARCHIVE.md` (retired) | A failure mode with symptom → cause → fix, learned from real debugging | Procedures that never failed, plain explanations | +| **Report** | `../../docs/testing_reports/--YYYY-MM-DD.md` | What happened in one test run: timeline, findings, acceptance table, evidence (tx hashes, digests) | Durable procedure (promote that part to runbook/trap instead) | +| **Facts** | `docs/CURRENT-STACK.md` | Version-sensitive values: production stack identity, S3 prefixes, digest encodings, codec block thresholds, sizing | Anything timeless | +| **Index** | `docs/TROUBLESHOOTING.md` | The trap registry table only | Trap content | + +Rules of thumb: + +- **Link, don't duplicate.** If the same fact is needed in two places, one becomes canonical and the other links to it. Duplicated prose drifts (this has already happened once — a whole Sepolia table and verifier section lived in root `AGENTS.md` beside the canonical copies). +- **Reports are immutable.** Post-run, extract anything durable into traps/runbooks and leave the report as a dated record. Reference reports from traps ("observed 2026-09-11, report …"), not the other way around. +- **Facts age; procedures don't.** If you catch yourself writing an address, digest, S3 path, or block threshold into a runbook or trap, put the value in `CURRENT-STACK.md` with a `last verified` date and link to it. + +### Trap conventions + +1. **Numbering is globally unique across all trap files, including the archive.** The next free number = `max(existing) + 1` (see the "next free number" line in the registry; `make doc-check` detects collisions). Numbers are never reused — a retired number stays retired. +2. **Lifecycle — every trap has a status** tracked in the registry: **Active** (body in its home file) / **Fixed** (patched upstream or in the harness) / **Checklist** (one-time setup issue absorbed into a COMMON checklist). When a fix lands: update the registry row, move the body to `docs/TRAP-ARCHIVE.md` with a `> **Status: …**` line naming the fix, and leave the number retired. References to retired traps keep resolving (doc-check includes the archive). +3. **New-trap bar**: a trap must be a **recurring failure mode or a non-obvious diagnosis**. One-time-per-machine environment issues go into the Phase 0 checklist instead; pure explanations belong in a GUIDE. When in doubt, ask whether someone will grep for this symptom again — if not, it is not a trap. +4. **Trap→hardening review**: after each significant test run (or at least quarterly), walk the Active list and ask of each trap: *"can the harness prevent this automatically?"* If yes, patch the script (a watchdog, a sanity check, a canonicalized path), verify, then retire the trap per rule 2. The Active count should trend flat or down — a forever-growing Active set means we are accumulating "traps a human must remember" instead of "failures the system prevents". +5. **Style**: `### Trap N: Short Title [both | follow mode | snapshot mode | build | tooling]` followed by **Symptom** / **Cause** / **Fix** / **Rule** (or **Diagnosis** / **Prevention** where they fit). Keep the symptom grep-able — exact error strings and selectors (`0x439cc0cd`) beat paraphrases, and the registry's symptom column is the primary search surface. +6. **Status markers**: `> **Fixed upstream / harness**: …` at the top when the root cause is patched but the trap is still live in some setups. +7. **Cross-references**: `Trap N` (unique, so no file qualifier needed), or `follow/GUIDE.md "Section Name"`. Every reference is validated by `make doc-check`. +8. **Renumbering is a last resort** and requires fixing every reference plus a note on the trap (`> Renumbered YYYY-MM-DD from "Trap N", which collided with …`). + +### Report conventions + +- One file per run: `--YYYY-MM-DD.md` (e.g. `canary-parallel-upgrade-2026-09-11.md`). +- Include: mode + host + checkout, stacks-under-test table (old vs new with digests/wrappers), UTC timeline, findings (each with the fix that was applied), acceptance table with evidence (tx hashes, trace excerpts, digests). +- Update the reports index in root `AGENTS.md` when adding one. + +### Hygiene check + +Run `make doc-check` from `tests/shadow-testing/` before committing documentation changes — it fails on duplicate trap numbers and on `Trap N` references that resolve to zero or multiple definitions. Keep the registry's status column and totals accurate by hand (doc-check covers numbers and references, not statuses). diff --git a/tests/shadow-testing/contracts/IZkEvmVerifier.sol b/tests/shadow-testing/contracts/IZkEvmVerifier.sol new file mode 100644 index 0000000000..244b0deebe --- /dev/null +++ b/tests/shadow-testing/contracts/IZkEvmVerifier.sol @@ -0,0 +1,17 @@ +// SPDX-License-Identifier: MIT + +pragma solidity ^0.8.24; + +interface IZkEvmVerifierV1 { + /// @notice Verify aggregate zk proof. + /// @param aggrProof The aggregated proof. + /// @param publicInputHash The public input hash. + function verify(bytes calldata aggrProof, bytes32 publicInputHash) external view; +} + +interface IZkEvmVerifierV2 { + /// @notice Verify bundle zk proof. + /// @param bundleProof The bundle recursion proof. + /// @param publicInput The public input. + function verify(bytes calldata bundleProof, bytes calldata publicInput) external view; +} diff --git a/tests/shadow-testing/contracts/ZkEvmVerifierPostFeynman.sol b/tests/shadow-testing/contracts/ZkEvmVerifierPostFeynman.sol new file mode 100644 index 0000000000..d2e8dd2e2c --- /dev/null +++ b/tests/shadow-testing/contracts/ZkEvmVerifierPostFeynman.sol @@ -0,0 +1,111 @@ +// SPDX-License-Identifier: MIT + +pragma solidity =0.8.24; + +import {IZkEvmVerifierV2} from "./IZkEvmVerifier.sol"; + +// solhint-disable no-inline-assembly + +/// @notice Wrapper around the OpenVM Halo2 plonk verifier for GalileoV2 (post-Feynman) proofs. +/// +/// @dev Identical to ZkEvmVerifierPostEuclid, except the public input hash is computed as +/// keccak256(abi.encodePacked(protocolVersion, publicInput)). The protocol version is +/// stored as an immutable and corresponds to the batch version (10 for GalileoV2). +contract ZkEvmVerifierPostFeynman is IZkEvmVerifierV2 { + /********** + * Errors * + **********/ + + /// @dev Thrown when bundle recursion zk proof verification is failed. + error VerificationFailed(); + + /************* + * Constants * + *************/ + + /// @notice The address of highly optimized plonk verifier contract. + address public immutable plonkVerifier; + + /// @notice A predetermined digest for the `plonkVerifier`. + bytes32 public immutable verifierDigest1; + + /// @notice A predetermined digest for the `plonkVerifier`. + bytes32 public immutable verifierDigest2; + + /// @notice The protocol version prepended to the public input before hashing. + uint256 public immutable protocolVersion; + + /*************** + * Constructor * + ***************/ + + constructor( + address _verifier, + bytes32 _verifierDigest1, + bytes32 _verifierDigest2, + uint256 _protocolVersion + ) { + plonkVerifier = _verifier; + verifierDigest1 = _verifierDigest1; + verifierDigest2 = _verifierDigest2; + protocolVersion = _protocolVersion; + } + + /************************* + * Public View Functions * + *************************/ + + /// @inheritdoc IZkEvmVerifierV2 + /// + /// @dev Encoding for `publicInput` (v0.9.0 / GalileoV2 bundle proofs): + /// ```text + /// | layer2ChainId | messageQueueHash | numBatches | prevStateRoot | prevBatchHash | postStateRoot | batchHash | withdrawRoot | + /// | 8 bytes | 32 bytes | 4 bytes | 32 bytes | 32 bytes | 32 bytes | 32 bytes | 32 bytes | + /// ``` + /// The hash passed to the plonk verifier is `keccak256(abi.encodePacked(protocolVersion, publicInput))`. + function verify(bytes calldata bundleProof, bytes calldata publicInput) external view override { + address _verifier = plonkVerifier; + bytes32 _verifierDigest1 = verifierDigest1; + bytes32 _verifierDigest2 = verifierDigest2; + bytes32 publicInputHash = keccak256(abi.encodePacked(protocolVersion, publicInput)); + bool success; + + // 1. the first 12 * 32 (0x180) bytes of `bundleProof` is `accumulator` + // 2. the rest bytes of `bundleProof` is the actual `bundle_proof` + // 3. Inserted between `accumulator` and `bundle_proof` are + // 32 * 34 (0x440) bytes, such that: + // | start | end | field | + // |---------------|---------------|-------------------------| + // | 0x00 | 0x180 | bundleProof[0x00:0x180] | + // | 0x180 | 0x180 + 0x20 | verifierDigest1 | + // | 0x180 + 0x20 | 0x180 + 0x40 | verifierDigest2 | + // | 0x180 + 0x40 | 0x180 + 0x60 | publicInputHash[0] | + // | 0x180 + 0x60 | 0x180 + 0x80 | publicInputHash[1] | + // ... + // | 0x180 + 0x420 | 0x180 + 0x440 | publicInputHash[31] | + // | 0x180 + 0x440 | dynamic | bundleProof[0x180:] | + assembly { + let p := mload(0x40) + // 1. copy the accumulator's 0x180 bytes + calldatacopy(p, bundleProof.offset, 0x180) + // 2. insert the public input's 0x440 bytes + mstore(add(p, 0x180), _verifierDigest1) // verifierDigest1 + mstore(add(p, 0x1a0), _verifierDigest2) // verifierDigest2 + for { + let i := 0 + } lt(i, 0x400) { + i := add(i, 0x20) + } { + mstore(add(p, sub(0x5a0, i)), and(publicInputHash, 0xff)) + publicInputHash := shr(8, publicInputHash) + } + // 3. copy all remaining bytes from bundleProof + calldatacopy(add(p, 0x5c0), add(bundleProof.offset, 0x180), sub(bundleProof.length, 0x180)) + // 4. call plonk verifier + success := staticcall(gas(), _verifier, p, add(bundleProof.length, 0x440), 0x00, 0x00) + } + if (!success) { + revert VerificationFailed(); + } + } +} diff --git a/tests/shadow-testing/docker-compose.yml b/tests/shadow-testing/docker-compose.yml new file mode 100644 index 0000000000..e39f5afd05 --- /dev/null +++ b/tests/shadow-testing/docker-compose.yml @@ -0,0 +1,213 @@ +version: "3.8" + +services: + # ─── PostgreSQL (Shadow DB) ──────────────────────────────────────────────── + postgres: + image: postgres:15-alpine + container_name: shadow-postgres + environment: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: shadow_pass + POSTGRES_DB: shadow_rollup + ports: + - "5433:5432" + volumes: + - postgres-data:/var/lib/postgresql/data + healthcheck: + test: ["CMD-SHELL", "pg_isready -U postgres"] + interval: 5s + timeout: 5s + retries: 5 + networks: + - shadow-net + + # ─── Coordinator API ─────────────────────────────────────────────────────── + coordinator: + image: scrolltech/coordinator-api:e2e-test + container_name: shadow-coordinator + profiles: ["coordinator"] + command: + - "--config" + - "/app/conf/config.json" + - "--http" + - "--http.addr" + - "0.0.0.0" + - "--http.port" + - "8390" + ports: + - "8390:8390" + volumes: + - ./follow/configs/coordinator.json:/app/conf/config.json:ro + - ../../coordinator/build/bin/assets_v2:/app/assets:ro + - ../../tests/prover-e2e/mainnet-galileoV2/genesis.json:/app/conf/genesis.json:ro + depends_on: + postgres: + condition: service_healthy + networks: + - shadow-net + restart: unless-stopped + + # ─── Relayer ─────────────────────────────────────────────────────────────── + relayer: + image: ubuntu:22.04 + container_name: shadow-relayer + profiles: ["relayer"] + entrypoint: ["/app/rollup_relayer"] + command: + - "--config" + - "/app/config.json" + - "--genesis" + - "/app/conf/genesis.json" + - "--min-codec-version" + - "7" + - "--verbosity" + - "3" + volumes: + - ./.work/relayer-${CONFIG:-mainnet}.json:/app/config.json:ro + - ../../tests/prover-e2e/mainnet-galileoV2/genesis.json:/app/conf/genesis.json:ro + - ../../rollup/build/bin/rollup_relayer:/app/rollup_relayer:ro + depends_on: + - postgres + networks: + - shadow-net + restart: unless-stopped + + # ─── Anvil (optional — usually started by script for fork flexibility) ───── + anvil: + image: ghcr.io/foundry-rs/foundry:latest + container_name: shadow-anvil + profiles: ["anvil"] + entrypoint: ["anvil"] + command: + - "--fork-url" + - "${FORK_URL:-https://eth-mainnet.g.alchemy.com/v2/demo}" + - "--fork-block-number" + - "${FORK_BLOCK:-25202217}" + - "--block-time" + - "12" + - "--port" + - "8545" + - "--state" + - "/data/anvil.state.json" + ports: + - "18545:8545" + volumes: + - ./states:/data + networks: + - shadow-net + restart: unless-stopped + + # ─── Prover GPU-0 ────────────────────────────────────────────────────────── + prover-gpu-0: + image: scrolltech/prover:${PROVER_VERSION:-e2e-test} + container_name: shadow-prover-gpu-0 + profiles: ["prover"] + ports: + - "10080:10080" + environment: + - RUST_MIN_STACK=16777216 + - CUDA_VISIBLE_DEVICES=0 + volumes: + - ./.work/prover-0.json:/prover/conf/config.json:ro + - ./.work/prover-0:/prover/.work + - ~/.openvm/params:/root/.openvm/params:ro + deploy: + resources: + reservations: + devices: + - driver: nvidia + device_ids: ['0'] + capabilities: [gpu] + depends_on: + - coordinator + networks: + - shadow-net + restart: unless-stopped + + # ─── Prover GPU-1 ────────────────────────────────────────────────────────── + prover-gpu-1: + image: scrolltech/prover:${PROVER_VERSION:-e2e-test} + container_name: shadow-prover-gpu-1 + profiles: ["prover"] + ports: + - "10081:10080" + environment: + - RUST_MIN_STACK=16777216 + - CUDA_VISIBLE_DEVICES=0 + volumes: + - ./.work/prover-1.json:/prover/conf/config.json:ro + - ./.work/prover-1:/prover/.work + - ~/.openvm/params:/root/.openvm/params:ro + deploy: + resources: + reservations: + devices: + - driver: nvidia + device_ids: ['1'] + capabilities: [gpu] + depends_on: + - coordinator + networks: + - shadow-net + restart: unless-stopped + + # ─── Prover GPU-2 ────────────────────────────────────────────────────────── + prover-gpu-2: + image: scrolltech/prover:${PROVER_VERSION:-e2e-test} + container_name: shadow-prover-gpu-2 + profiles: ["prover"] + ports: + - "10082:10080" + environment: + - RUST_MIN_STACK=16777216 + - CUDA_VISIBLE_DEVICES=0 + volumes: + - ./.work/prover-2.json:/prover/conf/config.json:ro + - ./.work/prover-2:/prover/.work + - ~/.openvm/params:/root/.openvm/params:ro + deploy: + resources: + reservations: + devices: + - driver: nvidia + device_ids: ['2'] + capabilities: [gpu] + depends_on: + - coordinator + networks: + - shadow-net + restart: unless-stopped + + # ─── Prover GPU-3 ────────────────────────────────────────────────────────── + prover-gpu-3: + image: scrolltech/prover:${PROVER_VERSION:-e2e-test} + container_name: shadow-prover-gpu-3 + profiles: ["prover"] + ports: + - "10083:10080" + environment: + - RUST_MIN_STACK=16777216 + - CUDA_VISIBLE_DEVICES=0 + volumes: + - ./.work/prover-3.json:/prover/conf/config.json:ro + - ./.work/prover-3:/prover/.work + - ~/.openvm/params:/root/.openvm/params:ro + deploy: + resources: + reservations: + devices: + - driver: nvidia + device_ids: ['3'] + capabilities: [gpu] + depends_on: + - coordinator + networks: + - shadow-net + restart: unless-stopped + +volumes: + postgres-data: + +networks: + shadow-net: + driver: bridge diff --git a/tests/shadow-testing/docs/COMMON-TROUBLESHOOTING.md b/tests/shadow-testing/docs/COMMON-TROUBLESHOOTING.md new file mode 100644 index 0000000000..5945c83d7c --- /dev/null +++ b/tests/shadow-testing/docs/COMMON-TROUBLESHOOTING.md @@ -0,0 +1,337 @@ +# Common Troubleshooting & Pitfalls (Mode-Independent) + +> **Read this file first** before starting any shadow fork or shadow coordinator test. +> This file covers pitfalls that apply regardless of mode. Mode-specific traps live in +> [`../follow/TROUBLESHOOTING.md`](../follow/TROUBLESHOOTING.md) (follow mode) and +> [`../snapshot/TROUBLESHOOTING.md`](../snapshot/TROUBLESHOOTING.md) (snapshot replay mode). +> +> - **Registry & statuses**: [`TROUBLESHOOTING.md`](TROUBLESHOOTING.md) — every trap's number, key symptom, file, and lifecycle status (Active / Fixed / Checklist). +> - **Archive**: [`TRAP-ARCHIVE.md`](TRAP-ARCHIVE.md) — retired traps (fixed upstream/harness or absorbed into the checklists below). Numbers are retired, never reused. +> - This directory contains hard-won knowledge from multiple debugging sessions. Blind experimentation repeats documented mistakes. + +## Pre-Flight Ritual (Mandatory) + +Before executing a single command: + +1. [ ] **Read root `AGENTS.md`** — refresh the trap list. +2. [ ] **Read this file plus the per-mode `TROUBLESHOOTING.md`** (`follow/TROUBLESHOOTING.md` or `snapshot/TROUBLESHOOTING.md`) — check if your planned task matches any documented failure mode. The [trap registry](TROUBLESHOOTING.md) maps symptoms to traps. +3. [ ] **Read the per-mode `GUIDE.md`** (`follow/GUIDE.md` or `snapshot/GUIDE.md`) — verify the specific section matching your task (e.g. "Real Verifier Deployment", "Relayer Finalize on the Fork"). +4. [ ] **Verify network** — confirm you are testing **Mainnet** or **Sepolia**, and all configs/ports/RPCs match that network. +5. [ ] **Verify target bundle range** — query the DB to confirm: + - Bundles exist and have `proving_status = 4` (or will be regenerated) + - Parent batch of the first target batch exists in the DB + - All bundle end batches have `committedBatches` entries on Anvil (or will be seeded) + +## Mainnet vs Sepolia — Decision Table + +| Check | Mainnet | Sepolia | Verification Command | +|-------|---------|---------|---------------------| +| DB port | `5433` or `15432` | `25432` | `psql -h localhost -p -c "SELECT version();"` | +| L2 RPC | `l2geth-rpc-proxy.mainnet.aws.scroll.io` | `l2geth-rpc-proxy.sepolia.aws.scroll.io` | `curl -X POST -d '{"method":"debug_executionWitness","params":["latest"],"id":1}'` | +| Anvil fork URL | `eth-mainnet.g.alchemy.com` | `eth-sepolia.g.alchemy.com` | `cast block-number --rpc-url ` | +| ScrollChain proxy | `0xa13BAF47339d63B743e7Da8741db5456DAc1E556` | `0x2D567EcE699Eabe5afCd141eDB7A4f2D0D6ce8a0` | `cast call "lastFinalizedBatchIndex()(uint256)"` | +| MVRV | `0x4CEA3E866e7c57fD75CB0CA3E9F5f1151D4Ead3F` | `0x8A360c7F6fca548507017DdeD732bFe7E078F963` | `cast call "latestVerifier(uint256)" 10` | +| L1MessageQueueV2 | `0x56971da63A3C0205184FEF096E9ddFc7A8C2D18a` | `0xA0673eC0A48aa924f067F1274EcD281A10c5f19F` | `cast call "nextUnfinalizedQueueIndex()(uint256)"` | +| Verifier | Copy from mainnet (`anvil_setCode`) | Check MVRV first; may already match | `cast call "getVerifier(uint256,uint256)" 10 ` | + +### Sepolia Operational Differences (beyond addresses/ports) + +| Dimension | Mainnet | Sepolia | Failure mode if ignored | +|-----------|---------|---------|------| +| **DB scope** | Imported limited range | Full production snapshot (batches 128080+) | Relayer batch committer floods logs with commit retries | +| **`committedBatches`** | Sparse, but fork block usually covers target batches | Sparse; **every bundle end batch must exist** | Missing entry → `ErrorIncorrectBatchHash(0x2a1c1442)` (Trap 4) | +| **`L1MessageQueueV2` reset** | `nextUnfinalizedQueueIndex = 0` usually sufficient | Set to `MIN(total_l1_messages_popped_before)` of the first target batch; **slot 104** (verify with `forge inspect`) | Wrong slot/value → `ErrorFinalizedIndexTooLarge(0x16465978)` (Trap 5, Trap 20) | +| **Anvil gas estimation** | Same as mainnet | `eth_estimateGas` may fail with fee caps present (`Gas=0`) | Trap 9 (archived — fixed upstream; use a recent relayer build) | +| **Sender balance** | Persisted across restarts | **Resets to 0** after Anvil restart | Re-fund EOAs before each relayer start (Trap 10) | +| **Relayer flags** | Standard | Requires `--config ` AND `--min-codec-version 10` | Wrong config or immediate exit (Trap 11) | +| **Blob version** | Usually V0 | Anvil 1.0.0 cannot decode BlobSidecar V1 | Set `fusaka_timestamp: 2000000000` in relayer config | +| **Proofs in DB** | May already be current | Old proofs may be several guest versions behind | Must reset `proving_status = 1` to regenerate (Trap 8, Trap 16) | + +## Critical Traps (Do Not Skip) + +Traps are grouped by theme; numbers are globally unique and stable. Retired traps (7, 9, 12, 13, 25, 26, 28, 29, 30, 36, 43, 46, 47, 48, 51) live in [`TRAP-ARCHIVE.md`](TRAP-ARCHIVE.md). + +### Verifier, Digests & Release Assets + +### Trap 1: Wrong Verifier Contract or Wrong Digest Form +- **Symptom**: `VerificationFailed(0x439cc0cd)` even with correct digests. +- **Cause A**: Deployed `ZkEvmVerifierPostEuclid` instead of `ZkEvmVerifierPostFeynman`. +- **Cause B**: Used digests in the wrong form. For v0.9.0 the S3 `digest_1.hex` / `digest_2.hex` files are published in **canonical form**, but if you are re-using an old v0.8.0 workflow that converted from Montgomery form, double-check you are not applying the conversion twice. +- **Cause C**: **MVRV routes the batch to the wrong verifier**. The deployed verifier's digests are correct, but `MultipleVersionRollupVerifier.getVerifier(10, batchIndex)` returns an old verifier with different digests. This happens when re-proving bundles with a new prover (new digests) whose batch indices fall in a range still mapped to a legacy verifier. +- **Cause D**: **The wrapper was copied from mainnet via `anvil_setCode`**. `anvil_setCode` copies runtime bytecode but **preserves the original immutables** (`plonkVerifier`, `verifierDigest1/2`, `protocolVersion`). The copied wrapper assembles its `instances` array from the *mainnet* immutables + `keccak256(protocolVersion || publicInput)`, so locally-generated proofs with different digests are rejected even when the plonk verifier binary, public input hash, and proof are all individually correct. Copying is only valid when your proofs intentionally share mainnet's digests (e.g. re-using imported production proofs). +- **Rule**: For guest v0.9.0 proofs, **always use `PostFeynman`** with digests from `.../releases/v0.9.0/bundle/digest_*.hex`, and **verify MVRV routing** before finalizing. +- **Verification — Digests**: Fetch canonical digests from S3 and deploy with `protocolVersion = 10`: + ```bash + BASE_URL="https://circuit-release.s3.us-west-2.amazonaws.com/scroll-zkvm/releases/v0.9.0" + DIGEST1=$(curl -fsSL "${BASE_URL}/bundle/digest_1.hex" | tr -d '[:space:]') + DIGEST2=$(curl -fsSL "${BASE_URL}/bundle/digest_2.hex" | tr -d '[:space:]') + ``` + The S3 files are already in canonical form; no conversion or proof extraction is required. +- **Verification — MVRV Routing**: Before finalizing, confirm the verifier returned by MVRV for each target batch matches the verifier whose digests match the proofs: + ```bash + for idx in 128069 128070 128071; do + cast call $MVRV "getVerifier(uint256,uint256)(address)" 10 $idx --rpc-url $ANVIL_RPC + done + ``` + If any batch returns the old verifier while proofs use new digests, update MVRV: + ```bash + cast rpc anvil_impersonateAccount $OWNER --rpc-url $ANVIL_RPC + cast send $MVRV \ + "updateVerifier(uint256,uint64,address)" \ + 10 $START_BATCH $NEW_VERIFIER \ + --from $OWNER --rpc-url $ANVIL_RPC --unlocked + ``` +- **Diagnosis order when `VerificationFailed` appears** (do NOT jump to blaming the Solidity): + 1. Verify the plonk verifier binary matches the deployed contract's runtime code. + 2. Verify `keccak256(abi.encodePacked(protocolVersion, publicInput))` equals the proof metadata `bundle_pi_hash`. + 3. Verify the wrapper's immutables match the proof's digest words (instances bytes 384–416 / 416–448). + 4. Verify MVRV routing for the exact batch index (Cause C). + 5. Only after 1–4 pass, look at contract logic — and even then, **production code is almost certainly correct**: the wrapper's `sub(0x5a0, i)` loop has finalized thousands of bundles on mainnet; "fixing" its direction inverts the hash-word layout and produces a different, equally failing instances set. +- **Access control**: `finalizeBundlePostEuclidV2` has an `OnlyProver` modifier — on a shadow fork, authorize the finalize sender via `addProver` (or `cast rpc anvil_impersonateAccount `) before sending. + +### Trap 14: Coordinator Verifier Assets vs Prover Circuit S3 Paths (v0.9.0) +- **Symptom**: coordinator asset download 403s or prover cannot find circuit apps. +- **Cause**: Starting with v0.9.0, both verifier assets and circuit apps are released under a unified `scroll-zkvm/releases/v0.9.0/` prefix. Earlier versions split them across `v0.8.0/verifier/` and `scroll-zkvm/galileov2/`. +- **Rule**: For v0.9.0, point both coordinator verifier assets and prover `circuits.galileoV2.base_url` at `…/scroll-zkvm/releases/v0.9.0/`. The expected layout is `{chunk,batch,bundle}//` for circuits and `verifier/` for coordinator assets. Prefixes per release: [`CURRENT-STACK.md`](CURRENT-STACK.md). + +### Chain, RPC & Fork State + +### Trap 2: Anvil Forks Wrong Chain +- **Symptom**: `ScrollChain` proxy has no code, or `eth_chainId` returns `534352`. +- **Cause**: Anvil pointed at Scroll L2 RPC instead of Ethereum L1 RPC. +- **Rule**: Anvil must fork **Ethereum L1** (`chainId=1`). The ScrollChain proxy lives on L1. + +### Trap 3: L2 RPC Missing `debug_executionWitness` +- **Symptom**: Coordinator panics at startup or chunks never get assigned. +- **Cause**: Public RPC (`mainnet-rpc.scroll.io`, `sepolia-rpc.scroll.io`) blocks debug methods. Chunks containing L1 messages additionally need `scroll_getL1MessagesInBlock` (most chunks at current mainnet height contain none). +- **Rule**: Use **internal** L2 RPC proxies only. + +### Trap 19: `miscData.lastCommittedBatchIndex` Desync → `ErrorBatchNotCommitted` (0x227a699e) + +- **Symptom**: `finalizeBundlePostEuclidV2` reverts with custom error `0x227a699e` during `eth_estimateGas`, even though `committedBatches[batchIndex]` on the fork matches the DB hash exactly. +- **Cause**: The deployed (Post-Feynman) ScrollChain rejects finalization when `batchIndex > miscData.lastCommittedBatchIndex`. `committedBatches[i]` being set is **not sufficient** — the bound check uses `miscData.lastCommittedBatchIndex` (slot `0xa1`, lowest 8 bytes). On mainnet `lastCommittedBatchIndex` is usually far ahead of `lastFinalizedBatchIndex`; if setup scripts (or manual patches) set it equal to the rewound `lastFinalizedBatchIndex`, every batch between the two becomes un-finalizable. +- **Diagnosis**: + ```bash + cast call $SCROLL_CHAIN "miscData()(uint64,uint64,uint32,bool)" --rpc-url $ANVIL_RPC + # field 1 = lastCommittedBatchIndex, field 2 = lastFinalizedBatchIndex + cast call $SCROLL_CHAIN "miscData()(uint64,uint64,uint32,bool)" --rpc-url $FORK_URL --block $FORK_BLOCK + ``` +- **Fix**: Patch slot `0xa1`, keeping the high bytes (reserved + flags + timestamp) intact and only replacing the two index fields: + ```bash + # lastCommitted=518665 (0x7ea09, real fork value), lastFinalized=518505 (0x7e969) + cast rpc anvil_setStorageAt $SCROLL_CHAIN 0xa1 \ + 0x0000000000000000000000016a537382000000000007e969000000000007ea09 \ + --rpc-url $ANVIL_RPC + ``` +- **Rule**: `01-setup-anvil.sh` now reads the real `lastCommittedBatchIndex` from fork state by default and preserves timestamp/flags. Only pass `--last-committed` when you deliberately want a different value. Do not set it too high either: `commitBatches` requires `parentBatchHash == committedBatches[lastCommittedBatchIndex]`, so an inflated value breaks future commits on the fork. + +### Trap 20: `nextCrossDomainMessageIndex` Too Low → `ErrorFinalizedIndexTooLarge` (0x16465978) + +- **Symptom**: After fixing Trap 19, finalization reverts with `execution reverted: \x16FYx` (selector `0x16465978`). +- **Cause**: `_afterFinalizeBatch` calls `L1MessageQueueV2.finalizePoppedCrossDomainMessage(totalL1MessagesPoppedOverall)`, which reverts if the new index exceeds `nextCrossDomainMessageIndex` (slot `0x67`). This happens when a manual patch or stale `--state` file left `nextCrossDomainMessageIndex` below the queue indices your batches pop. +- **Diagnosis**: + ```bash + cast call $MQV2 "nextCrossDomainMessageIndex()(uint256)" --rpc-url $ANVIL_RPC + cast call $MQV2 "nextCrossDomainMessageIndex()(uint256)" --rpc-url $FORK_URL --block $FORK_BLOCK + # also confirm the rolling hash the proof expects exists: + cast call $MQV2 "getMessageRollingHash(uint256)(bytes32)" $((TOTAL_L1 - 1)) --rpc-url $ANVIL_RPC + ``` +- **Fix**: Bump slot `0x67` to the real fork value (e.g. 998603 = `0xf3ccb`): + ```bash + cast rpc anvil_setStorageAt $MQV2 0x67 0x00000000000000000000000000000000000000000000000000000000000f3ccb --rpc-url $ANVIL_RPC + ``` + Never lower `nextUnfinalizedQueueIndex` (slot `0x68`) below a bundle's `totalL1MessagesPoppedOverall` — that yields `ErrorFinalizedIndexTooSmall` instead. +- **Rule**: `01-setup-anvil.sh` now defensively bumps slot `0x67` to the fork value when it is lower. Decode the revert selector first — `0x227a699e` and `0x16465978` look similar in relayer logs but have different roots. + +### Relayer & Senders + +### Trap 10: Sender Balance Lost After Anvil Restart +- **Symptom**: `failed to send transaction, err: Insufficient funds for gas * price + value` even after successful gas estimation. +- **Cause**: `anvil_setBalance` funds do not persist across Anvil restarts (they DO survive a `--state` relaunch — Trap 44 — but not a fresh re-fork). +- **Rule**: After every Anvil restart, verify and re-fund sender EOAs before starting the relayer: + ```bash + cast balance 0x410E7FD80a3Fc1E62A4D3450d11b71b812006eB9 --rpc-url http://localhost:18546 + ``` + +### Trap 11: Relayer Started Without Required Flags +- **Symptom**: Relayer prints help and exits with `Required flag "min-codec-version" not set`, or connects to wrong DB. +- **Cause**: `ROLLUP_RELAYER_CONFIG` env var is NOT supported. The relayer uses `--config` CLI flag. +- **Rule**: Always start relayer with BOTH flags: + ```bash + ./rollup_relayer --config /path/to/config.json --min-codec-version 10 + ``` + +### Prover Environment & Proving Pipeline + +### Trap 16: Stale Proofs After Source-Code Revert / Restore + +- **Symptom**: Batch proof fails with `VM error: execution error: program exit code 1`, or bundle proof fails with `mismatch batch-proof exe commitment: expected=..., got=...`. +- **Cause**: The shadow DB contains chunk/batch proofs generated by a different code version (e.g. before a `git revert` and subsequent restore of v0.9.0 source adaptations). The stored proofs verify individually because the coordinator loads the same verifier, but the next-level prover rejects their execution commitment. +- **Rule**: After any non-trivial source change (Rust guest code, OpenVM version, `Cargo.lock`, or `rust-toolchain`), **treat existing shadow proofs as suspect**. Reset all relevant chunks, batches, and bundles to `proving_status = 1, proof = NULL` and re-prove from the lowest level. Do not rely on `proving_status = 4` alone. + +### Trap 17: `coordinator_cron` Re-Marks Corrupt Bundles as Ready + +- **Symptom**: Log is flooded with `format bundle prover task failure: unexpected end of JSON input` for high-index bundles, wasting prover cycles. +- **Cause**: `coordinator_cron` periodically scans batches and sets `bundle.batch_proofs_status = 2` when all member batches have `proving_status = 4`. If those batch proofs are `NULL`/corrupt (Trap 16), the bundle becomes "ready" and is assigned repeatedly. +- **Rule**: While cleaning up stale proofs, either: + 1. Stop `coordinator_cron` until all corrupt proofs are regenerated, or + 2. Reset **all** corrupt bundles/batches/chunks (`proving_status = 4 AND proof IS NULL`) to `proving_status = 1` so the cron never sees them as ready. + +### Trap 21: Stale Cached Proof in Prover Local DB → VData Shape Mismatch + +- **Symptom**: Coordinator logs `proof generated by prover failed ... Proof shape verification failed: Invalid VData: Proof trace_vdata length (44) does not match number of AIRs (42)` with `proofTime=2` (i.e. instant submission from cache, not a real proof run). +- **Cause**: The prover's local LevelDB (`/db`) caches proofs keyed by task. A proof generated under a different circuit/asset version (e.g. before an S3 asset refresh or code revert/restore) is replayed and rejected by the coordinator's shape check. +- **Rule**: Fresh proofs (proofTime ~300s for bundles) from other provers succeed for the same task, so this is self-healing as long as one prover has a clean cache. To stop a prover from repeatedly burning attempts on a poisoned cache, stop it, delete `/db`, and restart. When switching circuit versions, wipe all prover local DBs as part of the reset ritual (same spirit as Trap 16). + +### Trap 24: `coordinator_cron` Collection Timeouts Shorter Than Real Proof Times → False Timeouts, Duplicate Dispatch, Attempt Exhaustation [both] + +- **Symptom**: Repeated `proof task have reach the timeout` warnings in coordinator logs for the **same task id**; the same bundle gets proved twice by different provers; submissions race and the loser gets a benign `validator failure chunk/batch have proved and verified success` reject from `proof_receiver.go`. +- **Cause**: The timeout checker (`coordinator/internal/controller/cron/collect_proof.go`) scans the `prover_task` table every cycle and marks tasks timed out after `{chunk,batch,bundle}_collection_time_sec`. On timeout it invalidates the `prover_task`, decrements `active_attempts`, and **permanently fails the task once `total_attempts >= session_attempts` (5)**. Observed incident: `configs/coordinator.json` had `bundle_collection_time_sec = 180` while real bundle proofs take ~335 s (up to ~90 min for 30-batch bundles). Every bundle task falsely timed out at 180 s, got duplicate-dispatched to a second prover (2× GPU waste), and the two submissions raced. +- **Fix**: Set the collection timeouts well above real proof times in `configs/coordinator.json` (and `configs/coordinator.json.template`): + - `bundle_collection_time_sec ≥ 7200` + - `chunk_collection_time_sec = 3600` and `batch_collection_time_sec = 180` are fine vs ~117 s / ~25 s actuals. + - **Remember**: the timeout checker runs in `coordinator_cron`, so the **cron's** config is the one that matters, not `coordinator_api`'s. +- **Structural gap**: **Note (fixed upstream)**: the coordinator now refunds the charged attempt (both `total_attempts` and `active_attempts`, status back to unassigned) when dispatch fails after `Update*Attempts` — see `recoverAttempts` in `internal/logic/provertask/*_prover_task.go` and `orm.RefundAttemptsByHash` — so format-failure paths no longer leave invisible half-charged tasks; the sweeper reset below is belt-and-braces. Historical description: if task formatting fails *after* attempts are incremented but *before* the `prover_task` row is inserted (e.g. the Trap 22 block-hash failure), no `prover_task` row exists and the timeout checker can never see it. The `sweep-stale-proving.sh` daemon is the safety net — this is why the sweeper also resets `total_attempts`, not just `proving_status`. + +### Anvil & On-Chain Reconciliation + +### Trap 44: Anvil Silent Death / Stall Mid-Run — `--state` Relaunch Recovery [both] + +- **Symptom 1**: all RPC to the Anvil port suddenly refused; the anvil process is gone; the `--state` file's mtime is minutes old (incident 2026-09-11 ~08:28, report `testing_reports/canary-parallel-upgrade-2026-09-11.md`). +- **Symptom 2**: Anvil stops responding (RPC hangs, port/pid checks fail) and then **self-recovers** minutes later; during the stall window the relayer logs `context deadline exceeded` / `connection refused` bursts (incident 2026-09-11 ~11:00). +- **Cause**: Anvil 1.7.1 instability under long-running fork load (periodic mining + blob txs + periodic `--state` persistence + lazy fork-backend fetches). Both incidents were silent — the default launch in `01-setup-anvil.sh` discards stdout/stderr to `/dev/null`, so no crash reason is capturable afterwards. +- **Recovery (validated 2026-09-11)**: relaunch Anvil with the **same command line including `--state `** — it loads the persisted state and resumes exactly where it left off (MVRV legacy routing, `lastFinalizedBatchIndex`, EOA balances/nonces all preserved; block number continues). This is much lighter than `make re-fork` (fresh fork + wrapper redeploy) and is the **only** correct recovery mid-canary/mid-upgrade, where a fresh re-fork would lose `legacyVerifiers` routing and on-chain finalize history. After relaunch, verify `eth_chainId == 1`, `lastFinalizedBatchIndex`, and `getVerifier` routing on both sides of any boundary before restarting the relayer. +- **Watch out**: (a) during warm-up after relaunch Anvil RPC is slow — a relayer send can time out client-side while the tx still lands (→ Trap 45); (b) when relaunching manually, redirect output to a log file (`.work/anvil-restart.log`) instead of `/dev/null`; (c) if the original process only stalled (Symptom 2), a relaunch attempt will exit on port-in-use — check `pgrep -ax anvil` first and reuse the recovered instance. +- **Prevention (candidate)**: an Anvil watchdog (health-check + relaunch from state file), analogous to the `autossh` RDS-tunnel watchdog; plus state-file mtime freshness in the hourly monitor. + +### Trap 45: Tx Landed On-Chain but Relayer Never Recorded It → Infinite Retries / Stuck Rows [both] + +- **Symptom 1**: commit spam — `Failed to send commitBatch tx ... err="failed to get fee data ... execution reverted: *\x1c\x14B"` (selector `0x2a1c1442`, `ErrorIncorrectBatchHash`) repeating every ~2 s forever; the `batch` row shows `rollup_status = 5` but `commit_tx_hash IS NULL`. Observed 2026-09-11: 5,518 retry lines. +- **Symptom 2**: a `bundle` row stuck at `rollup_status = 1` while on-chain `lastFinalizedBatchIndex` has already advanced past its end batch (the finalize tx landed during an Anvil stall, receipt lost). +- **Cause**: the relayer's tx send hit a **client-side timeout** (slow Anvil — e.g. Trap 44 warm-up) *after* the tx was accepted by the node ("transaction already imported" on the next attempt proves it). The confirmation path never runs, so the DB columns (`commit_tx_hash` / `finalize_tx_hash` + rollup status) are never written; retries then fire against chain state that has already moved on. The relayer performs **no on-chain reconciliation before retrying**. +- **Fix (validated twice, 2026-09-11)** — reconstruct from on-chain evidence, backfill the DB, restart the relayer so senders re-initialize nonces from the chain: + 1. Find the tx: scan recent fork blocks for the sender (`cast rpc eth_getBlockByNumber 0x.. true | jq '.transactions[] | select(.from==…)'`) or read the nonce from the relayer error line. + 2. Verify the receipt (`status 1`) and that the call is the expected one (`commitBatches` blob tx / `finalizeBundlePostEuclidV2`). + 3. Backfill: `UPDATE batch|bundle SET _tx_hash = '0x…', rollup_status = 5, finalized_at = now() WHERE … AND IS NULL;` then restart the relayer (`06-run-relayer.sh`) — `initializeNonce = max(db_max+1, chain_pending_nonce)` then picks the correct next nonce. +- **Rule**: whenever the relayer error-logs a revert storm **and** the DB disagrees with on-chain `miscData()` / `lastFinalizedBatchIndex`, trust the chain and reconcile the DB first — restarting into a dirty state keeps the spam going. **Upstream improvement candidate**: reconcile against `committedBatches` / `lastFinalizedBatchIndex` / receipt-by-nonce before retrying a send. + +## Step-by-Step Checklist + +> Phases below are snapshot-replay-shaped (manual setup); follow mode automates them via `10-follow-up.sh` — use them as a mental model there. + +### Phase 0: Environment Validation +- [ ] DB reachable on correct port +- [ ] L2 RPC supports `debug_executionWitness` +- [ ] Anvil not already running on target port +- [ ] Coordinator port 8390 free +- [ ] Prover GPU available (`nvidia-smi`) — including **not occupied by unrelated processes** (high `memory.used` with no prover running; 2026-09-11 run used `GPUS=1` for its entirety because GPU0 held a foreign 22.4 GiB process — 1×4090 suffices for follow/canary pace) +- [ ] halo2 SRS files present: `ls ~/.openvm/params/kzg_bn254_2{2,3,4}.srs` — only bites at the first **bundle** proof, hours in (Trap 12, archived) +- [ ] Toolchain present: `cast`/`forge`/`anvil` (foundry), `psql`, `jq`, `curl`, `go` (coordinator/relayer builds), `cargo` + `nvcc` (GPU prover build) +- [ ] `libclang` installed — `librocksdb-sys` (via scroll-proving-sdk) runs bindgen during the prover build and panics with "Unable to find libclang" without it (`sudo apt install libclang-dev`) +- [ ] Python deps: `psycopg2` AND `pycryptodome` (import name `Crypto`). Note Ubuntu's `python3-pycryptodome` ships the **`Cryptodome`** namespace, which does NOT satisfy `from Crypto.Hash import keccak` in `lib/sync-queue-hashes.py` — install the pycryptodome wheel into the user site (`~/.local/lib/python3.x/site-packages`) instead +- [ ] Fresh shadow DB migrated before first baseline (`db_cli migrate` — Trap 30, archived) + +### Phase 1: DB Setup +- [ ] Import bundle range from production RDS +- [ ] **Exclude `proof` columns** from import +- [ ] Reset `proving_status = 1` for chunks, batches, bundles +- [ ] Insert missing parent batch skeleton +- [ ] Populate `l2_block` table and link via `chunk_hash` + +### Phase 2: Anvil Fork Setup +- [ ] Start Anvil forked from **Ethereum L1** (not Scroll L2) +- [ ] Verify `eth_chainId == 1` +- [ ] Fund owner and sender accounts (verify balances after any Anvil restart) +- [ ] Add prover EOA to `ScrollChain` +- [ ] Set `lastFinalizedBatchIndex` to `(first_target_batch - 1)` +- [ ] Set `lastCommittedBatchIndex` to mainnet value (do NOT reset to lastFinalized) +- [ ] (Sepolia) Verify end-batch `committedBatches` hashes are non-zero on Anvil +- [ ] (Sepolia) Set `L1MessageQueueV2.nextUnfinalizedQueueIndex` to pre-finalization value: + ```sql + SELECT MIN(total_l1_messages_popped_before) + FROM chunk + WHERE batch_hash = (SELECT hash FROM batch WHERE index = ); + ``` +- [ ] (Sepolia) **Verify slot number with `forge inspect L1MessageQueueV2 storage-layout`** before `anvil_setStorageAt` + +### Phase 3: Verifier Setup + +**Determine which scenario you are in:** + +**Scenario A — Re-using production proofs** +- [ ] Extract digests from proof instances +- [ ] Query Sepolia MVRV: `cast call "getVerifier(uint256,uint256)" 10 ` +- [ ] Query verifier digests: `cast call "verifierDigest1()"` / `"verifierDigest2()"` +- [ ] If digests match → **skip deployment**, use existing verifier +- [ ] If digests DON'T match → you are actually in Scenario B + +**Scenario B — Testing new guest / circuit version** +- [ ] Generate new proofs with the new prover (coordinator + prover pipeline) +- [ ] Extract digests from **newly-generated** proof instances, or fetch them from the S3 release (`digest_*.hex`, canonical for v0.9.0+) +- [ ] Deploy plonk verifier from `coordinator/build/bin/assets_v2/verifier.bin` +- [ ] Deploy `ZkEvmVerifierPostFeynman` with new digests + `protocolVersion = 10` +- [ ] Register on `MultipleVersionRollupVerifier` via `updateVerifier(10, startBatch, verifier)` +- [ ] Verify with `getVerifier(10, batchIndex)` + +### Phase 4: Coordinator + Prover +- [ ] Coordinator config points to correct `assets_v2/` directory +- [ ] Coordinator L2 RPC is internal/debug-enabled +- [ ] Prover config `base_url` uses correct S3 path (check [`CURRENT-STACK.md`](CURRENT-STACK.md)) +- [ ] Start coordinator, wait for `Start coordinator api successfully` +- [ ] Start prover(s), verify `Got task from coordinator` + +### Phase 5: Relayer Finalize +- [ ] Build relayer with latest code (rebuild if `estimategas.go` was patched for Anvil) +- [ ] Relayer config has `dry_run: false`, correct contract addresses +- [ ] Clear stale `pending_transaction` entries +- [ ] Reset target bundles/batches to `rollup_status = 1` +- [ ] **Sync `batch.withdraw_root` from batch proof metadata** (shadow fork only; see snapshot-mode Trap 56) +- [ ] **Start relayer with `--config ` AND `--min-codec-version 10`** +- [ ] Monitor logs for `finalizeBundle in layer1` success +- [ ] Verify `lastFinalizedBatchIndex` advanced on Anvil + +## When Things Go Wrong (most frequent) + +The full symptom→trap mapping lives in the [trap registry](TROUBLESHOOTING.md) (symptom column). The most frequent entries: + +| Error / Symptom | Most Likely Cause | See | +|-----------------|-------------------|-----| +| `VerificationFailed(0x439cc0cd)` | Wrong verifier type, digest mismatch, or wrong bundle withdrawRoot (Trap 56); in follow mode: post-fork L1 queue hashes missing (Trap 23); copied mainnet wrapper via `anvil_setCode` (Trap 1 Cause D) | Trap 1, Trap 23, Trap 56 | +| `ErrorIncorrectBatchHash(0x2a1c1442)` | Sparse `committedBatches` (Trap 4), or a commit that already landed unrecorded (Trap 45) | Trap 4, Trap 45 | +| `ErrorFinalizedIndexTooLarge(0x16465978)` | `nextUnfinalizedQueueIndex`/`nextCrossDomainMessageIndex` too low | Trap 5, Trap 20, Trap 23 | +| Follow mode stalls: `failed to fetch block hashes of a chunk` | Poll-synced chunks lack `l2_block` linkage | Trap 22 | +| Chunks verified but batch/bundle sessions never start | NULL `batch_hash`/`bundle_hash` parent links, or stale `prover_task` failure rows | Trap 22, Trap 34 | +| Relayer cannot send on the fork (balance / `ErrorCallerIsNotSequencer` / nonce stuck) | EOA funding, sequencer auth, `pending_transaction` desync | Trap 27 | +| RPC to Anvil refused, or Anvil hung then self-recovered mid-run | Anvil death/stall — relaunch with the same `--state` file (NOT `make re-fork` mid-upgrade) | Trap 44 | +| `Failed to send commitBatch … ErrorIncorrectBatchHash` spam every ~2s, or bundle stuck `rs1` while on-chain `lastFinalized` already advanced | Tx landed on-chain but relayer never recorded it (send timeout) — reconcile DB from chain, restart relayer | Trap 45 | +| RDS bill spikes while a stack runs | Sync/ad-hoc queries missing `deleted_at IS NULL` | Trap 41, [`rds-query-rules.md`](rds-query-rules.md) | +| `mismatched post-state root` | Fork block predates the codec's hardfork | Trap 50 | +| `ErrorCallerIsNotProver (0x7b263b17)` on finalize | Finalize sender not an authorized prover on the fork | Trap 29 (archived) | +| `CoordinatorEmptyProofData` every ~20 s | **Normal idle-poll** when no task is available; only a problem when ALL provers spin AND coordinator logs task-format failures | Trap 22, Trap 21 | + +## Historical incidents (moved) + +The former "Lessons from the v0.9.0 Multi-Bundle Shadow Test" section (bundles 17297–17301 / 20000–20004, 2026-05–2026-07) has been redistributed: + +- **Full postmortem** → [`../../docs/testing_reports/snapshot-early-dryrun-and-relayer-tests.md`](../../docs/testing_reports/snapshot-early-dryrun-and-relayer-tests.md) +- **withdrawRoot from proof metadata** → snapshot-mode Trap 56 +- **`anvil_setCode` preserves immutables** → Trap 1 Cause D +- **Stale proofs after code reverts / proof-chain resets** → Trap 16 / Trap 17 +- **S3 digest encoding (canonical vs Montgomery)** → [`bundle-digest-encoding.md`](bundle-digest-encoding.md) and [`CURRENT-STACK.md`](CURRENT-STACK.md) +- **Cargo.lock discipline on zkvm pin bumps** → follow-mode Trap 32 + +Still-unique procedural knowledge from that era, kept here in condensed form: + +- **`finalizeBundlePostEuclidV2` is the only finalize selector** (`0xc1aa4e19`); the verifier it calls is chosen by MVRV routing and must be a PostFeynman-style wrapper (`keccak256(protocolVersion || publicInput)`, `protocolVersion = 10` for GalileoV2). Public input layout (204 bytes): `chainId(8) | msgQueueHash(32) | numBatches(4) | prevStateRoot(32) | prevBatchHash(32) | postStateRoot(32) | batchHash(32) | withdrawRoot(32)`. +- **Prover aggregation needs deferral enabled** (OpenVM v2+): batch proving requires the chunk child prover, bundle proving the batch child prover — the prover config must carry `child_circuit_vks` so the right child assets load. +- **Sizing**: single-batch bundle proofs ~10–20 min; 30-batch bundles ~30–90 min per bundle on one GPU. + +## Documentation Priority + +When debugging, read docs in this order: + +1. [Trap registry](TROUBLESHOOTING.md) (symptom → trap) + this file + the per-mode `TROUBLESHOOTING.md` (`follow/` or `snapshot/`) — fastest path to known traps +2. The per-mode `GUIDE.md` (`follow/GUIDE.md` or `snapshot/GUIDE.md`) — detailed setup and procedures +3. `README.md` — quick reference for common commands + documentation conventions +4. [`CURRENT-STACK.md`](CURRENT-STACK.md) — dated version-sensitive facts +5. `../../AGENTS.md` (repo root) — cross-network rules and secrets reference diff --git a/tests/shadow-testing/docs/CURRENT-STACK.md b/tests/shadow-testing/docs/CURRENT-STACK.md new file mode 100644 index 0000000000..fa7d92f3ef --- /dev/null +++ b/tests/shadow-testing/docs/CURRENT-STACK.md @@ -0,0 +1,60 @@ +# Current zk Stack — Dated Facts + +> **Purpose**: single home for version-sensitive facts (S3 prefixes, digests, codec thresholds, production stack identity). Other documents should **link here** instead of embedding these values. Every fact carries a **last-verified** date — when an upgrade lands, update this file and only this file. +> +> Last full review: **2026-09-11** (during the canary parallel-upgrade run, report: `testing_reports/canary-parallel-upgrade-2026-09-11.md`). + +## Production (Scroll mainnet) + +| Fact | Value | Last verified | +|---|---|---| +| Production guest | pre-v0.9.0 era guest (`79c1f8c` per `git_version` in production proofs) | 2026-09-11 | +| `latestVerifier[10]` wrapper | `0x808297224e86b1a6055B5F790a2cE07Ed611f955`, startBatch 0 | 2026-09-11 | +| Wrapper `verifierDigest1` | `0x00398b786b500ca759ca2de2aee9c73bd8e28f1c80b49e1c53bc060a9a649269` | 2026-09-11 | +| Bundle cadence | ~1 bundle / 1–2 h (slower on weekends/low activity; multi-hour pauses observed) | 2026-09-11 | +| Contract addresses | see [`contract-addresses.md`](contract-addresses.md) | 2026-05-31 | + +How to re-verify the production stack before any shadow test: follow/GUIDE.md "Determining the Production zk Stack" (on-chain wrapper digests vs newest remote-proof `instances` bytes 384–448 vs `git_version`). + +## Release under test (this branch) + +| Fact | Value | Last verified | +|---|---|---| +| Guest | zkvm-prover `bf887150` (labelled v0.9.0 / circuit_version v0.14.0 in configs) | 2026-09-11 | +| S3 base | `https://circuit-release.s3.us-west-2.amazonaws.com/scroll-zkvm/releases/v0.9.0/` | 2026-09-11 | +| Bundle digest1 (canonical) | `0x006770fb0f71f20718b614c8c5d3fb39482f0527806e67b0ea00ab5508245655` | 2026-09-11 | + +## S3 layout per release + +| Release | Prefix | Digest encoding | Notes | +|---|---|---|---| +| v0.7.1 and earlier | `scroll-zkvm/releases/v0.7.1/` | — | | +| v0.8.0 | `scroll-zkvm/v0.8.0/` (no `/releases/`!) | **Montgomery** — convert to canonical before deploying | verifier + circuits split across prefixes | +| v0.9.0+ | `scroll-zkvm/releases/v0.9.0/` | **canonical** — use as-is | unified prefix; flat circuit layout `//app.vmexe` + `agg_vk.bin` | + +Details: [`bundle-digest-encoding.md`](bundle-digest-encoding.md). + +## Codec / fork thresholds (mainnet) + +| Fork | Codec | Mainnet blocks | Notes | +|---|---|---|---| +| galileo | V9 | any (e.g. ≥ 26,653,680) | pre-V10 | +| galileoV2 | V10 | **≥ 33,750,000** | current; older blocks fail "mismatched post-state root" (Trap 50) | + +## Sizing reference (single-GPU, RTX 4090, halo2-gpu build) + +| Metric | Value | Last verified | +|---|---|---| +| Chunk proof | ~2 min (first task +10–15 min witness fetch) | 2026-09-11 | +| Bundle proof end-to-end | ~10–15 min (STARK agg layers dominate; halo2 SNARK `Create EVM proof` ≈ 6 s) | 2026-09-11 | +| SNARK-phase GPU peak | ~8.8 GiB | 2026-09-11 | +| 1×4090 vs mainnet cadence | keeps pace with ~1.5×–2 h/bundle production incl. backlog | 2026-09-11 | +| 30-batch bundles | ~30–90 min per bundle | 2026-07 | + +## Tooling versions that matter + +| Tool | Version note | Last verified | +|---|---|---| +| anvil | 1.7.1 — silent death/stall observed twice under long fork load (Trap 44); state-file relaunch recovery works | 2026-09-11 | +| solc | ≥ 0.8.24 required (`--evm-version cancun`) | 2026-08 | +| CUDA | 12.8 works; nvcc 12.4 ICEs on OpenVM (`cp_gen_be.c` assertion) | 2026-08-25 | diff --git a/tests/shadow-testing/docs/TRAP-ARCHIVE.md b/tests/shadow-testing/docs/TRAP-ARCHIVE.md new file mode 100644 index 0000000000..986fd661a7 --- /dev/null +++ b/tests/shadow-testing/docs/TRAP-ARCHIVE.md @@ -0,0 +1,133 @@ +# Trap Archive + +Retired traps: failure modes **fixed upstream or in the harness**, or **absorbed into the setup checklists**. Bodies are kept verbatim for archaeology and for anyone running older builds — knowledge of an old failure is still knowledge. + +- Statuses are tracked in the [trap registry](TROUBLESHOOTING.md); a trap lands here only when its number is **retired (never reused)**. +- These traps still `doc-check` as definitions, so `Trap N` references from other documents keep resolving. + +## Fixed upstream or in the harness + +### Trap 7: Relayer Nonce Desync + +> **Status: Fixed** — upstream `chain_nonce_only` sender option + `10-follow-up.sh --reset` TRUNCATEs `pending_transaction`. + +- **Symptom**: Tx sent but never mined; `eth_getTransactionReceipt` returns null forever. +- **Cause**: `pending_transaction` table retains nonces from previous runs that were never confirmed. Relayer initializes nonce from `maxDbNonce + 1`, which is ahead of the on-chain nonce. +- **Rule (older builds)**: After any relayer crash or Anvil restart: + ```sql + DELETE FROM pending_transaction WHERE sender_address = ''; + ``` + Then restart the relayer. + +### Trap 9: Anvil `eth_estimateGas` Rejects Fee Caps + +> **Status: Fixed** — upstream `rollup/internal/controller/sender/estimategas.go` sends an explicit non-zero gas cap in the estimation `CallMsg`. + +- **Symptom**: `failed to get fee data, err: Out of gas: gas required exceeds allowance: 0`. +- **Cause**: Anvil's `eth_estimateGas` fails when `CallMsg` has `GasFeeCap`/`GasTipCap` set but `Gas` is 0 (Go Ethereum client's default). +- **Rule (older builds)**: the correct fix belongs in upstream `estimategas.go` — do not maintain a local patch. + +### Trap 13: Prover Docker `--gpus device=N` + Wrong `CUDA_VISIBLE_DEVICES` + +> **Status: Fixed** — `04-prover-up.sh --docker` pins `--gpus "device=N"` and deliberately sets **no** `CUDA_VISIBLE_DEVICES` inside the container (a pinned device is visible as index 0, which is already the right GPU). + +- **Symptom**: prover container exits (code 139) with `cudaErrorNoDevice: no CUDA-capable device is detected`; only the GPU-0 prover works. +- **Cause**: `--gpus "device=N"` exposes only that GPU and **renumbers it to index 0** inside the container, so setting `CUDA_VISIBLE_DEVICES=N` inside points at a nonexistent device. +- **Rule (manual launches)**: use `--gpus "device=$i"` with `CUDA_VISIBLE_DEVICES=0` (or `--gpus all` with `CUDA_VISIBLE_DEVICES=$i`). + +### Trap 25: Orphaned Poll-Sync + Empty Watermark → Full Mainnet History Backfill + +> **Status: Fixed** — all three defenses below are in place in the harness; **do not remove any of them**. + +- **Symptom**: Shadow DB suddenly fills with millions of mainnet rows (`sync-poll.log` shows `chunk: inserted 25000/6642569` and counting). +- **Cause**: an orphaned sync daemon (pidfile-invisible) surviving a reset, combined with watermark = 0 on the truncated tables, makes the poll treat all of mainnet history as new rows. +- **Defenses**: (1) `11-follow-stop.sh` kills the whole process group; (2) `MAX_POLL_DELTA = 5000` guard in poll mode; (3) baseline runs before any daemon starts. +- **Recovery**: kill the sync process, then `DELETE` contaminated rows below the baseline window. + +### Trap 26: Relayer L2 Watcher Genesis-Crawls an Empty `l2_block` + +> **Status: Fixed** — relayer supports `l2_config.disable_l2_watcher` (set by the shadow relayer template); `--reset` also stops all writers before truncating. + +- **Symptom**: `l2_block` fills with rows numbered 1, 2, 3, … at ~30–60 blocks/s with NULL `chunk_hash` — a days-long full-history crawl. +- **Cause**: the relayer's L2 watcher loop read `MAX(l2_block.number)` once as 0 (empty table) and started fetching from block 1. +- **Rule**: never let `l2_block` go empty while a relayer is running. + +### Trap 28: Post-Fusaka Fork + Anvil 1.0.0 → Blob Base Fee Explosion + +> **Status: Fixed** — `01-setup-anvil.sh` mines empty blocks after `wait_for_anvil` until `cast blob-base-fee` < 1 gwei. + +- **Symptom**: every `commitBatches` right after a fresh fork fails `estimateGasLimit failure ... Insufficient funds` despite a funded EOA (`cast blob-base-fee` ≈ 1e18 wei). +- **Cause**: pre-Fusaka Anvil prices the inherited `excessBlobGas` with the Dencun update fraction → astronomical blob base fee. +- **Manual equivalent (older harness)**: `cast rpc anvil_mine 400`. + +### Trap 29: Same-Block Ordering — Manual `addProver` Mined After the Failing Finalize + +> **Status: Fixed** — `10-follow-up.sh` step h re-ensures `isProver(finalize_sender)` idempotently on every run. Recovery knowledge kept for older setups. + +- **Symptom**: a finalize tx reverts `ErrorCallerIsNotProver` (0x7b263b17) although `addProver` was sent first; bundle ends at `rollup_status = 7`, which `ProcessPendingBundles` **never retries**. +- **Cause**: Anvil mined both txs in one block, ordering the finalize (txIndex 0) before the `addProver` (txIndex 1). +- **Recovery**: impersonate the owner, `addProver()`, verify `isProver` = true, then `UPDATE bundle SET rollup_status = 1 WHERE index = `. **Rule of thumb**: a bundle at `rollup_status = 7` is stranded by design and always needs the manual reset after fixing the cause. + +### Trap 36: `cast receipt status` Output Format Changed in Foundry ≥ 1.6 + +> **Status: Fixed** — the deploy/upgrade scripts accept `0x1`, `1`, `1 (success)`, and `true`. + +- **Symptom**: scripts abort with "updateVerifier reverted (… status 'true')" even though the tx succeeded. +- **Cause**: cast output drift across versions (`0x1` → `1 (success)` → `true`); literal string comparison misreads success as failure. +- **Rule**: when in doubt, verify on-chain state instead of trusting the script's verdict. + +### Trap 43: `11-follow-stop.sh` Aborts Midway — sourced lib re-enables `set -e` + +> **Status: Fixed** (2026-09-04) — `set +e` immediately after the `source`; prover loop matches on `prover.json`; trailing `exit 0`. + +- **Symptom**: `make follow-stop` stops some components then exits non-zero, leaving docker provers/coordinators/Anvil running. +- **Cause**: `lib/anvil-utils.sh`'s `set -euo pipefail` silently re-enabled `-e` inside the deliberately `-e`-less stop script. + +### Trap 46: `cast code` Returns `0x` for Codeless Accounts — Non-Empty Checks Are Not Enough + +> **Status: Fixed** — `01-setup-anvil.sh` explicitly rejects `"0x"` before copying and, in `--skip-verifier` mode, leaves the MVRV untouched; `10-follow-up.sh` asserts the routed wrapper has code and the expected `protocolVersion`. +> Renumbered 2026-09-11 from "Trap 32", which collided with follow-mode's Trap 32 (revm drift). + +- **Symptom** (historical): a "copied" verifier address with **no code** on the fork; every finalization would have failed `VerificationFailed`. +- **Cause**: `cast code` prints `0x` for an EOA / nonexistent contract, so `[[ -n "$code" ]]` passes and `anvil_setCode` writes an empty blob. +- **Rule**: after any `cast code`, check non-empty AND non-`0x`; after any registration, verify `cast code ` is non-trivial. + +### Trap 47: `set -euo pipefail` + Failing `cast`/`psql` Inside `$( )` → Silent Script Death + +> **Status: Fixed** — every `$( )` around `cast`/`psql` in `lib/` and `follow/scripts/` now appends `|| true` and validates explicitly. Renumbered 2026-09-11 from "Trap 33", which collided with follow-mode's Trap 33 (`agg_vk.bin`). + +- **Symptom**: an orchestration script stops mid-step with NO error line — `make` reports `Error 1` after the last step header. +- **Cause**: a failing command substitution under `pipefail` + `set -e` exits before the validation/`log_error` below it. +- **Rule**: follow the same pattern when adding new probes — and when a script dies silently, suspect this first. + +### Trap 48: `coordinator_api` Reads `conf/genesis.json` Relative to Its CWD + +> **Status: Fixed** — `30-canary-upgrade.sh` sanity-checks the file up front; also documented as follow-mode Trap 40 Cause 2. Renumbered 2026-09-11 from "Trap 34", which collided with follow-mode's Trap 34 (stale `prover_task` rows). + +- **Symptom**: `coordinator_api` CRITs seconds after start: `failed to read genesis ... open conf/genesis.json`; provers then exhaust login retries and die. +- **Fix**: `cp tests/prover-e2e/mainnet-galileoV2/genesis.json coordinator/build/bin/conf/genesis.json`. + +### Trap 51: Multiple Provers Sharing One Circuit-Cache Directory + +> **Status: Fixed** — `04-prover-up.sh` gives each GPU its own work dir (`.work/prover-N/`). Kept for manual multi-prover launches. + +- **Symptom**: prover dies with `File exists (os error 17)` when two instances write the same temp file under a shared `.work/galileo` cache. +- **Rule (manual)**: one work directory per prover; optionally symlink a shared **read-only** circuit cache into each and keep distinct write dirs. + +## Absorbed into setup checklists + +### Trap 12: halo2 SRS Not in `~/.openvm/params/` + +> **Status: Checklist** — a Phase 0 pre-flight item (COMMON-TROUBLESHOOTING.md); the failure only bites once per fresh machine, hours into a run. + +- **Symptom**: chunk/batch proofs succeed; the **first bundle proof** crashes the prover with `Params file ".../.openvm/params/kzg_bn254_23.srs" does not exist`. +- **Cause**: openvm reads the KZG SRS from `$HOME/.openvm/params/kzg_bn254_{22,23,24}.srs` only at the bundle proof's halo2 stage. +- **Check**: `ls ~/.openvm/params/` before starting provers; in docker mode the params dir is mounted read-only at the same path. + +### Trap 30: Fresh Shadow DB — Baseline Sync Fails, Schema Never Migrated + +> **Status: Checklist** — a Phase 0 pre-flight item ("Fresh shadow DB migrated before first baseline"). + +- **Symptom**: first-ever `10-follow-up.sh` dies in baseline: `psql staging prep failed ... relation "public." does not exist`. +- **Cause**: `copy_table_pipe()` needs the real tables to exist; nothing migrates the schema before the coordinator starts. +- **Check**: `cd database && go build -o /tmp/db_cli ./cmd && /tmp/db_cli migrate --config ` once per fresh DB. diff --git a/tests/shadow-testing/docs/TROUBLESHOOTING.md b/tests/shadow-testing/docs/TROUBLESHOOTING.md new file mode 100644 index 0000000000..b4cab73be2 --- /dev/null +++ b/tests/shadow-testing/docs/TROUBLESHOOTING.md @@ -0,0 +1,81 @@ +# Troubleshooting & Pitfalls — Trap Registry + +This is the **single interface** to the trap corpus: every trap's number, its most grep-able symptom, where it lives, and its lifecycle status. Search this table first; only then read the trap body. + +**Statuses** + +- **Active** — live failure mode; body in its home file below. +- **Fixed** — root cause patched upstream or in the harness; body in [`TRAP-ARCHIVE.md`](TRAP-ARCHIVE.md) (kept for older builds + archaeology). Number retired, never reused. +- **Checklist** — one-time-per-machine issue absorbed into a COMMON checklist item; body in the archive. + +Content files: + +- [`COMMON-TROUBLESHOOTING.md`](COMMON-TROUBLESHOOTING.md) — mode-independent traps (themed groups), pre-flight ritual, checklists, top-frequency symptom table +- [`../follow/TROUBLESHOOTING.md`](../follow/TROUBLESHOOTING.md) — follow-mode traps (poll sync, relayer-on-fork, upgrades/canary, infra cost) +- [`../snapshot/TROUBLESHOOTING.md`](../snapshot/TROUBLESHOOTING.md) — snapshot-replay traps (fork state, import hygiene, pipeline) +- [`TRAP-ARCHIVE.md`](TRAP-ARCHIVE.md) — retired traps + +To add a trap: take `max(existing number) + 1` across **all** files including the archive, and follow the conventions in [`../README.md`](../README.md) "Documentation Conventions" (including the new-trap bar and the trap→hardening review). `make doc-check` (from `tests/shadow-testing/`) validates numbers and references; statuses and totals in this table are maintained by hand. + +## Registry (1–56) + +| # | Trap | Key symptom (grep-able) | Where | Status | +|---|------|--------------------------|-------|--------| +| 1 | Wrong verifier / digest form / MVRV mis-routing / `anvil_setCode` immutables | `VerificationFailed` `0x439cc0cd` | COMMON | Active | +| 2 | Anvil forks the wrong chain (Scroll L2) | `eth_chainId 534352`; no code at ScrollChain | COMMON | Active | +| 3 | L2 RPC missing `debug_executionWitness` | chunks never assigned; debug methods blocked | COMMON | Active | +| 4 | `committedBatches` sparse (EuclidV2) | `ErrorIncorrectBatchHash 0x2a1c1442` | snapshot | Active | +| 5 | `L1MessageQueueV2` index mismatch (Sepolia) | `ErrorFinalizedIndexTooLarge/Small` | snapshot | Active | +| 6 | Parent batch missing from import | `record not found, index: ` | snapshot | Active | +| 7 | Relayer nonce desync | tx sent but never mined; receipt null | ARCHIVE | Fixed | +| 8 | Production proof overwrite on import | `VerificationFailed` after import | snapshot | Active | +| 9 | Anvil `eth_estimateGas` rejects fee caps | `failed to get fee data … allowance: 0` | ARCHIVE | Fixed | +| 10 | Sender balance lost after Anvil restart | `Insufficient funds for gas * price + value` | COMMON | Active | +| 11 | Relayer started without required flags | `Required flag "min-codec-version" not set` | COMMON | Active | +| 12 | halo2 SRS not in `~/.openvm/params/` | `Params file …kzg_bn254_23.srs does not exist` | ARCHIVE | Checklist | +| 13 | Docker `--gpus device=N` + wrong `CUDA_VISIBLE_DEVICES` | `cudaErrorNoDevice`, exit 139 | ARCHIVE | Fixed | +| 14 | Verifier assets vs circuit S3 paths per release | S3 `403` downloading assets | COMMON | Active | +| 15 | Slow `l2_block` export by `chunk_hash` JOIN | export hangs, 0-byte CSV | snapshot | Active | +| 16 | Stale proofs after source revert/restore | `mismatch batch-proof exe commitment` | COMMON | Active | +| 17 | `coordinator_cron` re-marks corrupt bundles ready | `unexpected end of JSON input` flood | COMMON | Active | +| 18 | Relayer creates competing batches | provers busy, target bundles stall | snapshot | Active | +| 19 | `lastCommittedBatchIndex` desync | `ErrorBatchNotCommitted 0x227a699e` | COMMON | Active | +| 20 | `nextCrossDomainMessageIndex` too low | `0x16465978` (`\x16FYx`) | COMMON | Active | +| 21 | Stale cached proof in prover local DB | `Invalid VData … does not match number of AIRs` | COMMON | Active | +| 22 | Poll-sync `l2_block` linkage / starvation / NULL parent links | `failed to fetch block hashes of a chunk` | follow | Active | +| 23 | Bundles popping post-fork L1 messages | `VerificationFailed` then `0x16465978` (L1-msg bundles) | follow | Active | +| 24 | Collection timeouts < real proof times | `proof task have reach the timeout` | COMMON | Active | +| 25 | Orphaned poll-sync backfills full history | `inserted 25000/6642569` | ARCHIVE | Fixed | +| 26 | Relayer L2 watcher genesis-crawls empty `l2_block` | `l2_block` fills from block 1 | ARCHIVE | Fixed | +| 27 | Relayer cannot commit/finalize — balance/sequencer/nonce | `allowance: 0` / `ErrorCallerIsNotSequencer` / tx queued forever | follow | Active | +| 28 | Post-Fusaka blob base-fee explosion | `Insufficient funds`; blob-base-fee ≈ 1e18 | ARCHIVE | Fixed | +| 29 | Same-block `addProver` ordering | `ErrorCallerIsNotProver 0x7b263b17`; `rollup_status=7` | ARCHIVE | Fixed | +| 30 | Fresh shadow DB schema never migrated | `relation "public.
" does not exist` | ARCHIVE | Checklist | +| 31 | Upgrade Phase 1 built from branch, not production | Phase-1 finalizes all `VerificationFailed` | follow | Active | +| 32 | `cargo update` drifts revm / `[patch]` resolution | `E0308 … multiple versions of revm_primitives` | follow | Active | +| 33 | v0.9.0+ requires `agg_vk.bin` on S3 + in assets | `agg_vk.bin 403` / `missing from assets` | follow | Active | +| 34 | Stale `prover_task` failure rows starve assignment | `chunk_proofs_status=2` forever, no ERROR | follow | Active | +| 35 | Post-upgrade old-format proofs poison dispatch | `untagged enum ProofEnum` loop | follow | Active | +| 36 | `cast receipt status` output drift | `updateVerifier reverted (status 'true')` | ARCHIVE | Fixed | +| 37 | `make coordinator_api` doesn't refresh `libzkp.so` | `Batch verify failed … missing from assets` (stale .so) | follow | Active | +| 38 | halo2-gpu VRAM starvation / `def_hook_commit` | `cudaErrorInvalidConfiguration quotient.cu` | follow | Active | +| 39 | Canary proof-import pitfalls | `bundle.proof` stays NULL; quarantine grows | follow | Active | +| 40 | Canary boundary N vs proven backlog | old-proof backlog finalize-fails post-t1 | follow | Active | +| 41 | Remote queries missing `deleted_at IS NULL` | RDS bill spike; `DataFileRead` minutes/cycle | follow | Active | +| 42 | Docker prover: CPU-SNARK images / assignment rows | bundle 30+ min; `already assigned a task` | follow | Active | +| 43 | `11-follow-stop.sh` aborts midway | `make follow-stop` Error 2, half stack up | ARCHIVE | Fixed | +| 44 | Anvil silent death / stall — `--state` relaunch | RPC refused / anvil hang mid-run | COMMON | Active | +| 45 | Tx landed on-chain but never recorded | `commitBatch` revert spam / bundle stuck `rs1` vs chain advanced | COMMON | Active | +| 46 | `cast code` returns `0x` for codeless accounts | "copied" verifier has no code | ARCHIVE | Fixed | +| 47 | `set -euo pipefail` + failing `$( )` | script dies after step header, no error | ARCHIVE | Fixed | +| 48 | `coordinator_api` genesis.json relative to CWD | `failed to read genesis` seconds after start | ARCHIVE | Fixed | +| 49 | Chunk data prerequisites for task assignment | prover polls empty; coordinator healthy | snapshot | Active | +| 50 | Fork block / codec version mismatch | `mismatched post-state root` | snapshot | Active | +| 51 | Multiple provers sharing one circuit cache | `File exists (os error 17)` | ARCHIVE | Fixed | +| 52 | Orphan bundles deadlock assignment | no bundle task ever assigned | snapshot | Active | +| 53 | Imported `status=2` + NULL proof rows | `chunk_proofs_status=2` then format fails | snapshot | Active | +| 54 | `anvil_setStorageAt` ignored on mapping slots | patched storage visible but `eth_call` uses old | snapshot | Active | +| 55 | Anvil default account not an EOA in fork mode | `ErrorAccountIsNotEOA` on `addProver` | snapshot | Active | +| 56 | Stale `batch.withdraw_root` in finalize | `VerificationFailed` w/ correct digests+routing | snapshot | Active | + +**Totals**: 41 Active · 13 Fixed · 2 Checklist. Next free number: **57**. diff --git a/tests/shadow-testing/docs/bundle-digest-encoding.md b/tests/shadow-testing/docs/bundle-digest-encoding.md new file mode 100644 index 0000000000..a74e2e96ce --- /dev/null +++ b/tests/shadow-testing/docs/bundle-digest-encoding.md @@ -0,0 +1,87 @@ +# Bundle Verifier Digests: Montgomery (v0.8.0) vs Canonical (v0.9.0+) + +The `ZkEvmVerifierPostFeynman` wrapper has two immutables — `verifierDigest1` / +`verifierDigest2` — that commit to the bundle circuit's verifying key. At +`finalizeBundlePostEuclidV2` time the wrapper inserts these two `bytes32` +words into the `instances` array it passes to the Plonk verifier. The Plonk +verifier only accepts the proof if those words equal the digest words embedded +in the proof itself (`instances` offsets **384–416 = digest1, 416–448 = +digest2**). + +The catch: the digest files published on S3 are **not in the same field +encoding for every guest release**. Using them in the wrong encoding deploys a +wrapper whose immutables never match any real proof — every finalization +reverts with `VerificationFailed(0x439cc0cd)`. + +## The Rule + +| Guest release | S3 `bundle/digest_*.hex` encoding | Usable directly for deployment? | +|---------------|-----------------------------------|---------------------------------| +| **v0.8.0** (OpenVM 1.6.0) | **Montgomery form** (BN254) | ❌ — must convert to canonical first | +| **v0.9.0+** (OpenVM 2.0.0) | **Canonical form** | ✅ — use as-is | + +The encoding problem was fixed in v0.9.0: from that release on, the published +digest files are already in the canonical form the Plonk verifier expects. + +## Montgomery → Canonical Conversion + +For v0.8.0 digests (and only those), convert before deploying: + +```python +BN254_MOD = 21888242871839275222246405745257275088548364400416034343698204186575808495617 +R = pow(2, 256, BN254_MOD) # Montgomery radix +R_INV = pow(R, -1, BN254_MOD) + +def montgomery_to_canonical(hex_str): + return f"{(int(hex_str, 16) * R_INV) % BN254_MOD:064x}" +``` + +## Verified Example (Mainnet Production, v0.8.0) + +Cross-checked three independent ways (S3 → conversion → on-chain wrapper → a +real production bundle proof), all consistent: + +| Source | digest1 | digest2 | +|--------|---------|---------| +| S3 `scroll-zkvm/v0.8.0/bundle/digest_*.hex` (Montgomery) | `2bacecb92b61b7cf7cff726f230ee16a42b85eacac2fafa32d48d62f820023eb` | `2190d3ad4438e96758074b6e80d4999f75816dc2317a126b2acc7a02bc96f1e0` | +| → canonical (after conversion) | `0x00398b786b500ca759ca2de2aee9c73bd8e28f1c80b49e1c53bc060a9a649269` | `0x0021785a05e931b447c8d6463f4547f92081a92ee357af26e1c6f6ecfe373d67` | +| Mainnet production wrapper `0x808297224e86b1a6055B5F790a2cE07Ed611f955` immutables | `0x00398b78…` ✅ | `0x0021785a…` ✅ | +| Mainnet bundle #18246 proof `instances[384:448]` | `0x00398b78…` ✅ | `0x0021785a…` ✅ | + +For comparison, v0.9.0 S3 digests (already canonical, no conversion): +`digest1 = 0x006770fb0f71f20718b614c8c5d3fb39482f0527806e67b0ea00ab5508245655`, +`digest2 = 0x00488b196ca5b2ea1fda4c960fe2e1b0b9715c0428a8ec6fb01a64684f8533f7`. + +## How To Check Which Form You Have + +1. **Against a deployed wrapper**: + ```bash + cast call "$WRAPPER" "verifierDigest1()(bytes32)" --rpc-url "$RPC" + cast call "$WRAPPER" "verifierDigest2()(bytes32)" --rpc-url "$RPC" + ``` + Compare with the S3 file. Equal → S3 file is canonical (v0.9.0 behavior). + Equal only after Montgomery→canonical conversion → v0.8.0 behavior. + +2. **Against a real proof** (ground truth): the digest words are always + canonical inside the proof. From a coordinator/production DB: + ```sql + SELECT convert_from(proof, 'UTF8') FROM bundle WHERE index = ; + ``` + decode `proof.instances` (base64) and read bytes `384:416` / `416:448`. + +3. **Rule of thumb**: if `finalizeBundlePostEuclidV2` reverts with + `VerificationFailed(0x439cc0cd)` but the Plonk verifier binary, public + input hash, and proof are all individually correct — suspect digest + encoding first. + +## Notes + +- `lib/03-deploy-verifier.sh` fetches `digest_*.hex` from S3 and deploys them + **as-is**. That is correct for v0.9.0+ but would be wrong for a v0.8.0 + deployment (convert first, or extract from a proof's `instances`). +- The wrapper's `protocolVersion` (10 for GalileoV2 / codec V10) is orthogonal + to the digest encoding issue. +- History: the discrepancy was root-caused during the early shadow-fork tests + (wrapper `0xc323…` deployed with raw S3 digests failed with + `VerificationFailed`); documented in commit `3bb5092c` which removed the old + LESSONS_LEARNED chronicle — this file preserves the digest part. diff --git a/tests/shadow-testing/docs/contract-addresses.md b/tests/shadow-testing/docs/contract-addresses.md new file mode 100644 index 0000000000..c9fdec1c8e --- /dev/null +++ b/tests/shadow-testing/docs/contract-addresses.md @@ -0,0 +1,81 @@ +# Scroll L1 Contract Addresses + +> Auto-generated from genesis configs and on-chain queries. +> Last updated: 2026-05-31 + +## Mainnet (Ethereum L1) + +| Contract | Address | Verified Source | +|----------|---------|-----------------| +| **ScrollChain Proxy** | `0xa13BAF47339d63B743e7Da8741db5456DAc1E556` | [Etherscan](https://etherscan.io/address/0xa13BAF47339d63B743e7Da8741db5456DAc1E556) | +| ScrollChain Implementation | `0x0a20703878e68E587c59204cc0EA86098B8c3bA7` | (from proxy slot) | +| **MultipleVersionRollupVerifier** | `0x4CEA3E866e7c57fD75CB0CA3E9F5f1151D4Ead3F` | [Etherscan](https://etherscan.io/address/0x4CEA3E866e7c57fD75CB0CA3E9F5f1151D4Ead3F) | +| L1MessageQueueV1 | `0x0d7E906BD9cAFa154b048cFa766Cc1E54E39AF9B` | genesis.json | +| L1MessageQueueV2 | `0x56971da63A3C0205184FEF096E9ddFc7A8C2D18a` | genesis.json | +| L2SystemConfig | `0x331A873a2a85219863d80d248F9e2978fE88D0Ea` | genesis.json | +| Scroll Owner | `0x798576400F7D662961BA15C6b3F3d813447a26a6` | `owner()` on-chain | + +### Mainnet Verifier History (from on-chain) + +| Version | Start Batch | Verifier Address | Type | +|---------|-------------|------------------|------| +| 7 | 364,588 | `0xc084a6De8b0F2742396572d6f110eC87ca9329bA` | legacy | +| 8 | 0 | `0xa8d4702Aa5c09AF5dD1323E1842a43789021F485` | pre-v0.8.0 | +| 8 | 0 | `0xc3230A4C89a5Ce0455414215e533de4D8849b3f8` | Anvil-deployed (wrong digests) | +| **10** | 0 | `0x0dE180164Dc571522457101F5c47B2eaB36d0A82` | **GalileoV2 (mainnet)** | + +### Mainnet Batch Status (as of block ~25,213,000) + +- `lastCommittedBatchIndex`: ~517,843 +- `lastFinalizedBatchIndex`: 517,843 +- `committedBatches(517809)`: `0xeadeee9af865c6d13df6b66a45b3f3f161e6211aeb7d86e075a645f0e6a58f9e` +- `committedBatches(517843)`: `0x40545c71ed8fdcaabc06ad64599e9fdd4a62c1e2fd599a6642f64d229f7762a6` + +--- + +## Sepolia (Ethereum Testnet) + +| Contract | Address | Source | +|----------|---------|--------| +| **ScrollChain Proxy** | `0x2D567EcE699Eabe5afCd141eDB7A4f2D0D6ce8a0` | genesis.json | +| **MultipleVersionRollupVerifier** | `0x8A360c7F6fca548507017DdeD732bFe7E078F963` | `verifier()` on Sepolia | +| L1MessageQueueV1 | `0xF0B2293F5D834eAe920c6974D50957A1732de763` | genesis.json | +| L1MessageQueueV2 | `0xA0673eC0A48aa924f067F1274EcD281A10c5f19F` | genesis.json | +| L2SystemConfig | `0xF444cF06A3E3724e20B35c2989d3942ea8b59124` | genesis.json | +| Scroll Owner | `0xbE57544Eaf3515E888614a464EC9e0ad38f73e37` | `owner()` on Sepolia | + +### Sepolia Batch Status + +- `lastFinalizedBatchIndex`: 127,878 (0x1f386) + +--- + +## Cloak (Validium Testnet) + +| Contract | Address | Source | +|----------|---------|--------| +| **ScrollChain Proxy** | `0x9110B582327f6de87d8f833Ef7FAcD38CB093f64` | genesis.json | + +--- + +## How These Addresses Were Found + +### ScrollChain Proxy +The address `0xa13BAF47339d63B743e7Da8741db5456DAc1E556` appears in multiple places: +- `tests/prover-e2e/mainnet-galileoV2/genesis.json`: `"scrollChainAddress"` +- `coordinator/build/bin/conf/genesis.json` +- `bridge-history-api/conf/config.json` +- `scroll-devnets/charts/shadow-fork/e2e-test/values.yaml` + +**Critical verification step**: Initially, Anvil was mistakenly forking Scroll L2 (chainId=534352) instead of Ethereum L1. On Scroll L2, `0xa13B...` had no ScrollChain code. After correcting Anvil to fork Ethereum mainnet (chainId=1), the address correctly resolved to the ScrollChain proxy with: +- Implementation slot: `0x0a20703878e68E587c59204cc0EA86098B8c3bA7` +- `lastFinalizedBatchIndex()`: 517,828 +- `owner()`: `0x798576400F7D662961BA15C6b3F3d813447a26a6` + +### MultipleVersionRollupVerifier +- **Mainnet**: Queried via `cast call 0xa13BAF... "verifier()(address)"` on Ethereum mainnet RPC → `0x4CEA3E866e7c57fD75CB0CA3E9F5f1151D4Ead3F` +- **Sepolia**: Queried via `cast call 0x2D567... "verifier()(address)"` on Sepolia RPC → `0x8A360c7F6fca548507017DdeD732bFe7E078F963` +- Also referenced in `scroll-devnets/charts/shadow-fork/jobs/upgrade-contract.yaml` + +### Other Addresses +All other L1 contract addresses are extracted from the corresponding `genesis.json` files in `tests/prover-e2e//genesis.json`. diff --git a/tests/shadow-testing/docs/rds-query-rules.md b/tests/shadow-testing/docs/rds-query-rules.md new file mode 100644 index 0000000000..3206514231 --- /dev/null +++ b/tests/shadow-testing/docs/rds-query-rules.md @@ -0,0 +1,26 @@ +# Querying the Remote Mainnet DB (RDS via tunnel) — Rules + +> Moved here from root `AGENTS.md` 2026-09-11 (single home for DB-access discipline). +> Production read-only DB: `192.168.1.108:15432/mainnet_rollup` (RDS tunnel; DSN in `local-secrets.md`). Table sizes as of 2026-08. + +## Partial indexes — always predicate with `deleted_at IS NULL` + +- **Every `l2_block` index is partial: `WHERE deleted_at IS NULL`.** Any query on `l2_block` (and `chunk`) without that predicate **cannot use any index** and seq-scans the whole heap (62 GB for `l2_block`) — even innocent-looking ones like `SELECT MAX(number) FROM l2_block`. Always write `... WHERE deleted_at IS NULL AND ...`. (Same pattern on `chunk`; its indexes are partial too.) + +## Never run unbounded `count(*)` on `l2_block` + +- Plain `count(*)` = parallel seq scan ≈ **2 minutes** (33.5M rows / 62 GB heap, 183 GB incl. TOAST). Even `count(*) WHERE deleted_at IS NULL` (parallel index-only scan) ran **>5 minutes** — the index itself is multi-GB. Just don't count this table. +- For row-count estimates use the planner stats instead — instant: + + ```sql + SELECT reltuples::bigint FROM pg_class WHERE relname = 'l2_block'; + ``` + +- Bounded counts are fine when they carry the partial-index predicate plus a range on the indexed column: `SELECT count(*) FROM l2_block WHERE deleted_at IS NULL AND number > X AND number <= Y;` (an 8.4k-block range ≈ 8 s). `MAX(number) ... WHERE deleted_at IS NULL` is instant. +- `chunk` / `batch` / `bundle` are small enough (heaps ≤ 5 GB) that `count(*) WHERE deleted_at IS NULL` returns in seconds — but still always include the predicate, or you seq-scan. + +## Session cost + +- Each `psql` invocation pays ~0.7 s TLS+SCRAM setup and ~80 ms RTT per query (the tunnel forwards to a remote RDS; the LAN hop itself is <1 ms). Batch multiple statements into one session (one `psql` with several `-c`, or interactive) instead of one invocation per query. +- The follow-mode poll-sync daemon only issues indexed queries (`MAX(index)`, range-bound `COPY`, small proof windows), so it is unaffected — this page is for ad-hoc/manual queries. +- Related: follow-mode Trap 41 (`deleted_at IS NULL` discipline inside `sync-mainnet-db.py`). diff --git a/tests/shadow-testing/follow/GUIDE.md b/tests/shadow-testing/follow/GUIDE.md new file mode 100644 index 0000000000..f8bd9de5b1 --- /dev/null +++ b/tests/shadow-testing/follow/GUIDE.md @@ -0,0 +1,326 @@ +# Follow Mode Guide — Shadow Coordinator + Prover Testing + +This guide documents the **follow mode** of the shadow coordinator + local prover environment: fork the ETH mainnet state from `FOLLOW_FORK_HOURS_BACK` hours in the past (default 5h), catch up the resulting backlog, then follow mainnet bundle production in real time. This is the **default acceptance test for prover/guest upgrades**. + +For a fixed historical bundle range (incident reproduction, single-bundle debugging, Sepolia testing, targeted codec-migration checks), see the [Snapshot Replay Mode Guide](../snapshot/GUIDE.md). Shared scripts live in [`../lib/`](../lib/), pitfalls in [`./TROUBLESHOOTING.md`](./TROUBLESHOOTING.md) (follow mode) and [`../docs/COMMON-TROUBLESHOOTING.md`](../docs/COMMON-TROUBLESHOOTING.md) (mode-independent). Runtime state (`.work/`) is shared by both modes at `tests/shadow-testing/.work` (i.e. `../.work` from here). + +## Architecture + +``` +┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐ +│ Production RDS │ │ Shadow DB │ │ Shadow │ +│ (read-only via │────▶│ (local :5433) │────▶│ Coordinator │ +│ port-forward) │ │ │ │ (localhost:8390)│ +└──────────────────┘ └──────────────────┘ └────────┬─────────┘ + │ + │ assigns tasks + ▼ +┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐ +│ L2 RPC │ │ Local Prover │ │ Verifier Assets │ +│ (mainnet-rpc. │◀────│ (GPU/CPU) │ │ (/tmp/shadow- │ +│ scroll.io) │ │ │ │ verifier-assets)│ +└──────────────────┘ └──────────────────┘ └──────────────────┘ +``` + +## Prerequisites + +### Hardware +- GPU with CUDA support (tested on RTX 3090) +- ~50GB disk space for Docker images + verifier assets + circuit downloads +- 16GB+ RAM + +### Software +- Docker + docker-compose +- PostgreSQL client (`psql`) +- Rust toolchain (for local prover binary) +- `kubectl` or SSH access to IDC for port-forwarding to production RDS + +### Network +- Access to IDC machine with port-forward to mainnet RDS (e.g., `idc-us-1-19`) +- Internet access for L2 RPC and S3 circuit downloads + +# Follow Mode (Primary) + +Follow mode forks the ETH mainnet state from **`FOLLOW_FORK_HOURS_BACK` hours in the past** (default 5; `0` = fork at the current tip) with Anvil, baseline-syncs the shadow DB from the mainnet read replica, then **catches up the backlog** (every bundle committed-but-not-finalized at the fork block, plus everything mainnet produced since) before **following** mainnet indefinitely — poll-syncing new chunk/batch/bundle rows, proving them with local GPU provers, and finalizing bundles on the fork — until a preset duration (`FOLLOW_RUN_HOURS`, default 48) or a failure. It answers the question a snapshot cannot: *can this prover fleet catch up a backlog and then keep pace with real mainnet bundle production?* The fork block is `tip - FOLLOW_FORK_HOURS_BACK*300` (12s L1 blocks); `lastFinalizedBatchIndex` and `lastCommittedBatchIndex` are read **at the fork block**, so the baseline window (fork-finalized → mainnet tip) is exactly the backlog. `make follow-report` splits metrics into catch-up and steady-state phases using `MAINNET_BUNDLE_TIP_AT_START` recorded in `.work/follow-run.env`. + +For a fixed historical bundle range (incident reproduction, single-bundle debugging, Sepolia, codec-migration checks), use the [Snapshot Replay Mode Guide](../snapshot/GUIDE.md). + +## Follow Mode Prerequisites + +All general prerequisites above apply, plus: + +- **Mainnet RDS read-replica access** — how this machine reaches the RDS depends on the environment: either an SSH port-forward (`localhost:15432`) or a **direct LAN route** (this box: `192.168.1.108:15432`; see `local-secrets.md` — there is NO local tunnel here). The effective DSN is exported as `MAINNET_DSN` in `~/.bashrc` and consumed by every script (`10-follow-up.sh`'s built-in default assumes a tunnel). Verify: + ```bash + psql "$MAINNET_DSN" -c "SELECT COUNT(*) FROM batch;" + # → 517,830+ batches + ``` +- **RDS route watchdog (tunnel setups only)** — if you reach RDS through an IDC port-forward, it must stay up for the entire run; a dead tunnel silently starves poll-sync. Run it under `autossh` (e.g. `autossh -M 0 -N -L 15432:...`) so it self-heals. On direct-LAN boxes there is nothing to keep alive. +- Enough shadow-DB disk headroom for continuous row growth. + +For automated one-off baseline copies, `scroll-devnets/charts/shadow-fork/rollup-relayer/scripts/copy-db.sh` streams data from mainnet RDS to the local shadow DB via `postgres-tunnel` (`COPY ... TO STDOUT | COPY ... FROM STDIN`). + +## Bring-Up: `make follow` + +One command brings up the entire follow-mode stack (`scripts/10-follow-up.sh`): + +1. **Baseline sync** — `sync-mainnet-db.py` baseline mode copies ONLY the finalization-lag window: batches from the fork's `lastFinalizedBatchIndex - 1` to the mainnet tip, plus their chunks/`l2_block`/`l1_message` and overlapping bundles (typically ~100 batches / a few thousand blocks — NOT deep history). This window is not optional: L1 finalization is sequential (`prevBatchHash` chaining), so the shadow must prove and finalize every committed-but-not-finalized bundle in order before it can follow new ones. Rows at/below the finalized boundary are marked done (`rollup_status=5`, `proving_status=4`) and rows above are aligned to the fork's committed boundary, so a reused DB never carries stale state across forks. `10-follow-up.sh --reset` truncates the task tables first (use it whenever the DB may hold leftovers from older runs/imports — otherwise the coordinator treats ancient pending batches as work). Proof columns are never copied; everything is re-proven locally. +2. **Anvil fork** — fork ETH **L1** at the current block (never Scroll L2 — Trap 2), with `fusaka_timestamp: 2000000000` in the relayer config so Anvil accepts blob sidecars. Anvil listens on **`http://localhost:18545`** (host `0.0.0.0`, `--block-time 12`); its state lives in `.work/anvil-mainnet.state.json` — the relaunch-and-recover handle after a crash (see Failure Recovery). +3. **Verifier wrapper** — deploy/register the `ZkEvmVerifierPostFeynman` wrapper matching the guest under test (manual procedure: "Real Verifier Deployment" in the [Snapshot Replay Mode Guide](../snapshot/GUIDE.md#real-verifier-deployment)). +4. **Coordinator** — start `coordinator_api` + `coordinator_cron` against the shadow DB. +5. **Provers** — start one prover per GPU. +6. **Relayer** — start the rollup relayer with local proposers **disabled** (`l2_config.{chunk,batch,bundle}_proposer_config.disable = true`): the relayer then only commits/finalizes what the DB contains, instead of synthesizing bundles at an unrealistic rate. The shadow relayer config template (`lib/configs/relayer.json.template`) additionally sets `l2_config.disable_l2_watcher = true` (the poll sync, not the relayer's L2 watcher, keeps `l2_block` populated — Trap 26) and `sender_config.chain_nonce_only = true` (sender nonces initialize from the fork, never from stale `pending_transaction` rows — Trap 7/27). +7. **Background daemons** — poll-sync, sweeper, hourly monitor (plain background processes with pidfiles in `.work/`; no agent/session cron is required). + +The run window is recorded in `.work/follow-run.env` (`SHADOW_REPORT_START`, `FOLLOW_RUN_HOURS=48`). Tear down with `make follow-stop` (`scripts/11-follow-stop.sh`, supports `--keep-anvil`). + +### Critical Behavior of the Poll-Sync (Do Not Bypass) + +- Newly inserted rows carry **mainnet's** `rollup_status`/commit/finalize columns, which are meaningless on the fork. The sync resets them per row range: + - `batch.index <= fork miscData.lastCommittedBatchIndex` → `rollup_status = 3` (already committed on the fork). + - `batch.index > boundary` → `rollup_status = 1` so the shadow relayer commits them on Anvil (requires `parentBatchHash == committedBatches[lastCommittedBatchIndex]`; keep Trap 19's boundary accurate). + - `bundle` → always `rollup_status = 1`. +- The boundary is queried from Anvil each poll cycle (`ANVIL_RPC` / `SCROLL_CHAIN` env vars to override), so it advances automatically as the shadow relayer commits new batches. +- `ON CONFLICT DO NOTHING` everywhere: rows already advanced by the shadow relayer are never overwritten. **Consequence**: columns populated lazily on mainnet after the row is first copied stay stale in the shadow DB. The sync re-derives them every cycle instead: + - `sync_l2_blocks()` — links `l2_block.chunk_hash` for recent chunks (the blocks usually exist from baseline import but with NULL `chunk_hash`; an UPDATE, not an INSERT, is what fixes it). Missing this starves chunk task formatting (Trap 22). + - `sync_parent_links()` — re-derives `chunk.batch_hash` and `batch.bundle_hash` from parent index ranges (mainnet sets them at proposal time; rows copied before that keep NULL forever and are invisible to the coordinator's proof-status promotion, Trap 22). +- **L1 message queue follow-along (mandatory)**: bundles that pop L1 messages enqueued after the fork block fail finalization (`VerificationFailed` / `ErrorFinalizedIndexTooLarge`, Trap 23). The poll loop runs `../lib/sync-queue-hashes.py` every cycle — it copies `getMessageRollingHash(i)` from a mainnet RPC into the fork's `messageRollingHashes` mapping (slot 101) and aligns `nextCrossDomainMessageIndex` (slot 103) with mainnet. +- **Watch item**: the first bundle whose batches were committed on mainnet **after** the fork block exercises the relayer's commit path on Anvil (blob-carrying `commitBatches` tx). Keep `fusaka_timestamp: 2000000000` in the relayer config so Anvil accepts the blob sidecar. + +## Day-to-Day Operations + +| Command | What It Does | +|---------|--------------| +| `make follow-status` | Latest monitor snapshot + lag summary | +| `make follow-report` | Report via `generate-catchup-report.py`, windowed to this run by `SHADOW_REPORT_START` (the metrics log accumulates across runs) | +| `make follow-stop` | Tear down the stack (`--keep-anvil` keeps the fork) | +| `make re-fork` | Recover from a fork desync (see Failure Recovery below) | + +### Background Daemons + +| Daemon | Script | Cadence | Purpose | +|--------|--------|---------|---------| +| Poll-sync | `sync-mainnet-db.py --poll-interval 60` | 60s loop | DB row sync + `l2_block`/parent-link repair; runs `../lib/sync-queue-hashes.py` every cycle (L1 queue rolling hashes + cursor follow mainnet, Trap 23) | +| Sweeper | `scripts/sweep-stale-proving.sh` | 10 min | Reset stale proving rows **and `total_attempts`** (attempt exhaustion silently starves tasks, Trap 22; also the safety net for the Trap 24 structural gap) | +| Monitor | `scripts/monitor-catchup.py >> .work/catchup-metrics.log` | 1 h | Hourly metrics snapshot: `finalized_lag`, alerts when lag > 3, verifier `protocolVersion` drift detection | + +All daemons are plain background processes with pidfiles in `.work/`, started by `10-follow-up.sh` — no agent/session cron is required. + +## Expected Steady State + +Mainnet produces ~1 bundle/hour; the pipeline proves + finalizes a bundle in ~10 minutes, so once the initial backlog is cleared the system idles most of the time — provers polling with `CoordinatorEmptyProofData` every ~20s is the **normal** idle state, not an error. + +Validation evidence from the first 48-hour follow run (4× GPU box): + +| Metric | Value | +|--------|-------| +| Duration | ~22 h of operation | +| Bundles proved **and finalized** | 90 (zero backlog at end, lag ≤ 1) | +| Chunks / batches proved | 333 / 92 | +| Avg proof time | chunk 117 s, batch 25 s, bundle 335 s | +| Mainnet cadence vs prove+finalize | ~1 bundle/hour vs ~10 min → large headroom | + +Sizing conclusion: **1 GPU suffices** (~26% duty cycle), **2 recommended** for burst/backlog absorption, **4 is comfortable headroom**. The current 4-GPU box can follow Scroll mainnet in real time. + +## Failure Recovery + +- **Anvil relaunch from `--state` (try FIRST)** — if Anvil died or stalled mid-run (Trap 44), relaunching it with the **same command line including `--state .work/anvil-mainnet.state.json`** restores the exact fork: MVRV routing (incl. `legacyVerifiers` from a canary/mid-run upgrade), `lastFinalizedBatchIndex`, EOA balances and nonces. This is the only correct recovery mid-upgrade — a fresh `re-fork` would lose the registered wrapper routing and on-chain finalize history. Verify `eth_chainId`, `lastFinalizedBatchIndex`, and `getVerifier` on both sides of any boundary before restarting the relayer, and watch for Trap 45 (a send that timed out during warm-up may have landed on-chain unrecorded). +- **`make re-fork`** (`scripts/re-fork.sh`) — when the fork state itself is unusable (state file corrupt/missing, or you intentionally want a fresh fork): re-fork Anvil at the latest block, redeploy the verifier wrapper, re-fund EOAs (Trap 10 — `anvil_setBalance` does not survive restarts), re-mirror L1 queue hashes (`sync-queue-hashes.py`, Trap 23), restart the relayer. +- **RDS route** — tunnel setups: keep the port-forward under `autossh` (poll-sync stalls silently if it dies). Direct-LAN boxes: nothing to do. +- **Verifier-drift alerting** — the hourly monitor snapshot detects verifier `protocolVersion` drift. If it fires, re-check the deployed wrapper and MVRV routing (Snapshot guide, "[Verify MVRV Routing](../snapshot/GUIDE.md#verify-mvrv-routing)") before trusting any finalize result. + +## Mid-Run Upgrade Test (Continuous Finalization Across a zk Upgrade) + +This scenario answers a question a plain follow run cannot: *can the system keep finalizing bundles continuously while the zk stack (guest circuits / prover / on-chain verifier) is upgraded underneath it?* It mirrors a production upgrade: Phase 1 runs the **current production release**, then a single cutover switches to the **new release** — same Anvil fork, same DB, daemons and relayer untouched, `lastFinalizedBatchIndex` advancing the whole time. + +Why it adds coverage over a fresh follow run: + +- **MVRV legacy routing is genuinely exercised** — the new wrapper is registered via the real `updateVerifier(10, N, wrapper)` contract call, so batches below the boundary `N` still route to the old wrapper through `legacyVerifiers`. (A normal follow run force-overwrites the `latestVerifier` storage slot and never tests routing.) +- **Mixed finalization** — bundles already proven with the old circuits finalize *after* the upgrade event, through the old wrapper, interleaved with new-stack bundles. +- **The operational runbook itself** — coordinator assets swap + restart (with its keygen window), prover fleet rollover, in-flight task reset. + +### Procedure + +> ⚠️ **Phase 1 must run the ACTUAL production zk stack, not the current +> checkout.** Do not trust `mainnet.json.template`'s `s3_base_url` or your +> branch's zkvm version to tell you what production runs — verify it (see +> "Determining the Production zk Stack" below). On 2026-07 we learned this +> the hard way: the branch under test was already v0.9.0 while mainnet still +> ran guest v0.8.0, so a Phase-1 run built from the branch produced proofs +> the production wrapper could never verify (`VerificationFailed`). + +**Step 0 — determine the production stack and build it.** Production is +usually `develop`; the new stack is your feature branch. Build each in its +own checkout so both binary sets coexist — a git worktree is ideal: + +```bash +cd ~/scroll # the repo with your feature branch checked out +git worktree add ../scroll-develop develop +cd ../scroll-develop +cargo build --release -p libzkp-c +make -C coordinator coordinator_api coordinator_cron +make -C zkvm-prover prover # GPU build, ~30-60 min + +# Production verifier assets (mind the S3 prefix: v0.8.0 has NO /releases/) +mkdir -p coordinator/build/bin/assets_v0.8.0 +for f in verifier.bin root_verifier_vk openVmVk.json; do + curl -fsSL "https://circuit-release.s3.us-west-2.amazonaws.com/scroll-zkvm/v0.8.0/verifier/$f" \ + -o "coordinator/build/bin/assets_v0.8.0/$f" +done +# Runtime conf: copy build/bin/conf/config.json from your main checkout but +# point verifiers[].assets_path at assets_v0.8.0, and copy conf/genesis.json. +``` + +Point `follow/configs/mainnet.json` at the production release: +`prover.s3_base_url = .../scroll-zkvm/v0.8.0/` (no `/releases/`), +`assets.assets_v2 = /coordinator/build/bin/assets_v0.8.0`. + +**Step 1 — Phase 1 bring-up (old stack).** The forked production MVRV +already routes to a verifier matching production circuits, so NO wrapper is +deployed (`--skip-verifier` asserts routing instead). The env overrides aim +the stack at the production worktree: + +```bash +cd tests/shadow-testing/follow +COORD_DIR=/coordinator/build/bin \ +PROVER_BIN=/target/release/prover \ +ASSETS_DIR=/coordinator/build/bin/assets_v0.8.0 \ + ./scripts/10-follow-up.sh --skip-verifier --reset +# ... let it follow mainnet until a few bundles have finalized (lag <= 1) ... +``` + +**Step 2 — prepare the new stack (feature branch, usually your main +checkout):** + +```bash +cd ~/scroll && make -C zkvm-prover prover # new prover binary +# or, on 24 GB-class GPUs, with GPU-accelerated SNARK (bundle) proving: +# make -C zkvm-prover prover_halo2gpu +make -C coordinator coordinator_api coordinator_cron # if coordinator changed +# Download the NEW verifier assets into the dir named by +# mainnet-next.json's assets.assets_v2, and fill in mainnet-next.json +# (prover.s3_base_url of the new release, e.g. .../releases/v0.9.0/). +``` + +New-stack checklist (learned on the v0.9.0/halo2-gpu upgrade, 2026-07): + +- **Bumping the zkvm pin** (e.g. `tag = "v0.9.0"` → `rev = `): after + `cargo update -p scroll-zkvm-*`, ALWAYS `git diff Cargo.lock` and revert any + revm-family drift before building — `cargo update` silently breaks the + `[patch]` fork resolution (TROUBLESHOOTING.md Trap 32). +- **`halo2-gpu` cargo feature** (zkvm master ≥ bf887150): runs the SNARK + bundle prover on GPU too. Scroll-side it is + `prover --features halo2-gpu` (superset of `cuda`), packaged as the + `prover_halo2gpu` Makefile target. Needs a 24 GB-class GPU. +- **New mandatory assets**: the prover downloads `agg_vk.bin` next to each + circuit's `app.vmexe` (flat S3 layout), and the coordinator reads the batch + circuit's `agg_vk.bin` from its own assets dir. Both are produced by + `make build-guest` in the zkvm-prover repo and must be uploaded to S3 / + copied into `assets_v2` before the cutover (TROUBLESHOOTING.md Trap 33). +- **Re-run `make build-guest`** in the zkvm-prover checkout after switching + commits, and compare `digest_*.hex` against the canonical values — a stale + build once produced a wrong `digest_1` (Trap 33). + +**Step 3 — the cutover (one command).** Aim COORD_DIR at the NEW binaries; +`PROVER_BIN` defaults to `/target/release/prover`: + +```bash +cd tests/shadow-testing/follow +COORD_DIR=/coordinator/build/bin \ + ./scripts/20-upgrade.sh --next-config configs/mainnet-next.json +# or simply: make follow-upgrade (uses COORD_DIR from the environment) +``` + +### Determining the Production zk Stack + +Ground truth, in increasing order of effort: + +1. **On-chain wrapper vs S3 digests** — `cast call $MVRV "latestVerifier(uint256)(uint64,address)" 10 --rpc-url ` gives the production wrapper; compare its `verifierDigest1/2()` against the candidate release's S3 `digest_*.hex`. For v0.8.0 remember the S3 files are Montgomery-encoded — see [`../docs/bundle-digest-encoding.md`](../docs/bundle-digest-encoding.md). +2. **A real production proof** — pull the newest `bundle.proof` JSON from the production DB, base64-decode `proof.instances`, read digest words at bytes 384–416/416–448 (always canonical). The `git_version` field names the guest build commit. +3. **Repo pins** — `git show develop:Cargo.lock | grep zkvm-prover` vs your branch's, plus `zkvm-prover/print_high_zkvm_version.sh` (run it from inside `zkvm-prover/`). + +`20-upgrade.sh` computes the boundary batch `N` from the DB: bundles already proven (old circuit) but not yet finalized keep their proofs and stay on the old verifier; everything at/after `N` is reset (`proving_status=1`, attempts cleared) and re-proven with the new stack. If proven and unproven bundles interleave so no clean cut exists, it falls back to a hard cutover at `lastFinalized+1` (re-proving all pending bundles) and logs a warning. It then stops provers + coordinators, swaps the coordinator's `galileoV2` assets to the new release, restarts the coordinators, deploys + registers the new wrapper via the genuine `updateVerifier` path, restarts the provers with the new circuit version, and records `UPGRADE_AT_BATCH`/`UPGRADE_AT_TIME` in `.work/follow-run.env`. + +### Acceptance criteria + +- Every bundle with `end_batch < N` finalizes via the **old** wrapper (check `getVerifier(10, end_batch)` against `UPGRADE_OLD_WRAPPER` in `follow-run.env`). +- The first bundle with `end_batch >= N` finalizes via the **new** wrapper — the key moment. +- `finalized_lag` returns to ≤ 1 after the re-proving burst (coordinator keygen + re-proving pending tasks causes a temporary lag spike; that is expected, mirroring production deploy downtime). +- `make follow-report` splits metrics into pre/post upgrade phases. + +### Notes & traps + +- **In-flight old proofs always fail after the cutover.** The coordinator re-wraps submitted universal proofs with the VK it has *at submission time* (same fork name = single VK slot, `coordinator/internal/logic/submitproof/proof_receiver.go`), so proofs from old-circuit tasks are rejected once the new assets are live. This is why step (e) resets all task rows ≥ N — do not skip it. +- **Prover-local proof caches** (`.work/prover-*/db`) are wiped for the same reason (Trap 21: stale proofs replay as VData mismatches). +- **The reset in step (e) is deliberately aggressive** (Trap 35): it resets ready flags and clears proof blobs for ALL unfinalized rows at/after N — including rows that were never assigned — and deletes in-flight `prover_task` assignment rows. Anything less leaves old-format proofs reachable by the new coordinator, which then errors on every poll and (via the priority dispatcher) starves all task types. +- **First task generation after an assets swap is slow.** The coordinator fetches `debug_executionWitness` block-by-block (~550 blocks ≈ 10-15 min for two chunks) at 0% CPU — it is not hung, and the prover-side `connection_timeout_sec = 1800` covers it. Subsequent tasks reuse no cache but generate in seconds-to-minutes. +- **The prover binary is whatever is at `target/release/prover`.** The script logs its build time and git rev but does not rebuild it — a stale binary silently re-runs the old stack. +- The monitor's verifier-drift check follows MVRV routing (`getVerifier(10, lastFinalized+1)`), so it tracks whichever wrapper currently serves the next batch — no false alarm after the cutover. +- Sepolia variant: same flow with the Sepolia configs, but mind the Sepolia table in the root AGENTS.md (EOA re-funding, `--min-codec-version`, etc.). + +## Canary Parallel-Upgrade Test (Old and New Stacks Finalizing Side by Side) + +The canary mode answers a stronger question than the hard-switch upgrade test: *can the old and new zk stacks finalize bundles in parallel on the same chain, split purely by MVRV batch-index routing — with a clean rollback path?* It is an **extension** of follow mode; the hard-switch `20-upgrade.sh` flow above is untouched. + +How it differs from the hard-switch upgrade test: + +| Dimension | Hard switch (`follow-old` → `follow-upgrade`) | Canary (`follow-canary` → `canary-upgrade`) | +|-----------|-----------------------------------------------|----------------------------------------------| +| Old proofs | Produced locally by a Phase-1 production build | Imported from the mainnet DB into `remote_bundle_proof` | +| Phase 1/Phase A build | Must build the production worktree (Trap 31) | **No old-stack build needed** | +| At the boundary N | Rows ≥ N are reset and re-proven; in-flight old proofs are discarded | **Nothing is reset** — < N finalizes on imported proofs, ≥ N is proven for the first time by the new stack | +| Rollback | Not supported | `canary-rollback` restores the old wrapper at N and applies quarantined proofs — "as if the upgrade never happened" | + +Semantics: poll-sync (with `SYNC_PROOFS=1`) upserts every remotely-proved bundle (`proving_status=4`) into the shadow-private quarantine table `remote_bundle_proof`, then applies proofs to local `bundle` rows with `proof IS NULL AND rollup_status <> 5 AND end_batch_index < boundary`. The boundary starts at +∞ (Phase A) and is flipped to N by `30-canary-upgrade.sh` via `.work/canary.env` (`PROOF_IMPORT_MAX_END_BATCH`) — no daemon restart needed. After t1, remote proofs ≥ N keep accumulating in the quarantine table, which is what makes rollback safe. The relayer is completely unaware of any of this (MVRV routing happens on-chain). + +### Runbook + +```bash +cd tests/shadow-testing/follow + +# Phase A — old system only, zero local proving: +make follow-canary # = 10-follow-up.sh --import-proofs +# ... watch the backlog finalize purely on imported production proofs ... + +# t1 — the upgrade point (new stack must already be built; see Step 2 of the +# hard-switch section for the new-stack checklist): +make canary-upgrade # = 30-canary-upgrade.sh --next-config configs/mainnet-next.json + +# t1 with DOCKER provers instead of bare metal (production-style packaging): +# build the image from THIS checkout first, then pass it in: +docker build -f build/dockerfiles/prover.Dockerfile \ + -t scrolltech/prover:$(target/release/prover --version | awk '{print $NF}') . +make canary-upgrade DOCKER_PROVERS=1 PROVER_IMAGE=scrolltech/prover: + +# Parallel period — old (< N) and new (>= N) bundles interleave on-chain. +# Rollback drill (recommended BEFORE the first >= N bundle finalizes): +make canary-rollback # = 31-canary-rollback.sh +make canary-upgrade # upgrade again afterwards — 30 is re-runnable +``` + +`30-canary-upgrade.sh` computes `N = MIN(end_batch_index)` over unfinalized bundles with **no** quarantined remote proof (fallback `lastFinalized+1`; override with `--start-batch`), so no local GPU time is wasted re-proving what mainnet already proved. It records `CANARY_AT_BATCH` / `CANARY_OLD_WRAPPER` / `CANARY_NEW_WRAPPER` in `.work/follow-run.env`. + +### Acceptance criteria + +- Phase A: ≥ 3 backlog bundles finalize (`rollup_status=5`, `lastFinalizedBatchIndex` advancing) with **zero local proving** — coordinator/prover pidfiles absent. +- After t1: routing assertions pass (`getVerifier(10, N-1)` → old wrapper, `getVerifier(10, N)` → new wrapper). +- Parallel period: bundles with `end_batch < N` finalize via the old wrapper from imported proofs while bundles with `end_batch >= N` finalize via the new wrapper from local proofs, both reaching `rollup_status=5` in the same window. The first ≥ N finalize is t2, the de-facto cutover. +- Rollback drill: after `canary-rollback`, `getVerifier(10, N)` routes to the old wrapper again and ≥ N bundles finalize from quarantined proofs; a subsequent `canary-upgrade` re-establishes the parallel state. +- `finalized_lag` (make follow-status) returns to ≤ 1 and stays there. + +### Notes & traps + +- **The imported proofs must match the forked production wrapper's digests.** They do by construction (same production system) — unless the fork point is so old that the wrapper/proofs straddle a production upgrade. Verify the production guest version first (see "Determining the Production zk Stack" above and `../docs/bundle-digest-encoding.md`). +- **Proof import never clobbers local state**: the apply rule only touches `proof IS NULL AND rollup_status <> 5` rows, and after t1 the boundary partitions the work — the new coordinator only sees unproven ≥ N bundles, the importer only applies < N. +- The quarantine table `remote_bundle_proof` is shadow-private (created by the sync script, not goose) and survives `--reset` truncations; `make follow-stop` does not remove it either. Drop it manually if you switch the shadow DB to a different purpose. +- New trap entry: TROUBLESHOOTING.md Trap 39 (proof-import mode pitfalls). +- **Pipeline latency vs "stuck"**: after a new bundle appears it sits at `rollup_status=1, proving_status=1` for **~1–1.5 h on a single GPU** — chunk proofs first (first task after an assets swap adds 10–15 min witness fetch), then batch proofs, then the bundle STARK; the bundle row only flips late (`p2` when bundle-proving starts, `p4` + proof when it lands). That is normal progress, not a stall — watch the coordinator log (`start chunk generation session`) / `docker logs shadow-prover-` for signs of actual life before intervening. +- **Docker provers**: `04-prover-up.sh --docker` (driven via `30-canary-upgrade.sh --docker-provers` / `make canary-upgrade DOCKER_PROVERS=1`) runs each prover as a `shadow-prover-` container of `PROVER_IMAGE` with same-path work-dir mounts, host networking, `--user $(id -u)` and the SRS mounted at `$HOME/.openvm/params` inside the container (HOME is overridden so the path matches). The container's host PID is written to the usual pidfile, so `11-follow-stop.sh` / `31-canary-rollback.sh` work unchanged (plus a `docker rm -f shadow-prover-*` sweep as backstop). Prover logs: `docker logs shadow-prover-` (the per-GPU `prover.log` file stays empty in this mode). Build the image from the checkout under test with `build/dockerfiles/prover.Dockerfile` — the same "production-style packaging" the devops `prover-image-build.yml` workflow produces in CI. + +## Run Completion & Acceptance Criteria + +A follow run ends after `FOLLOW_RUN_HOURS` (default 48) or on failure. The run **passes** when: + +- **Lag ≤ 1** bundle sustained over the run window (monitor `finalized_lag`). +- **Zero manual intervention** over the run window (no manual SQL fixes, no daemon restarts). +- The report (`make follow-report`) answers: **kept pace?** (bundles created vs finalized), avg proof times per level (chunk/batch/bundle), and identifies bottlenecks (if any). + diff --git a/tests/shadow-testing/follow/Makefile b/tests/shadow-testing/follow/Makefile new file mode 100644 index 0000000000..4ccd9effb8 --- /dev/null +++ b/tests/shadow-testing/follow/Makefile @@ -0,0 +1,96 @@ +# Follow Mode Makefile +# Fork at the CURRENT mainnet tip and follow mainnet indefinitely: +# baseline sync -> anvil -> verifier -> coordinator -> provers -> relayer +# + poll-sync/sweeper/monitor daemons. See scripts/10-follow-up.sh. +# +# Usage: +# make follow Bring up the full follow-mode stack +# make follow-old Bring up Phase 1 of the mid-run upgrade test +# (old stack = production release, production verifier) +# make follow-upgrade Mid-run upgrade: cut over to the NEW zk stack +# (configs/mainnet-next.json) WITHOUT resetting the +# fork/DB — finalization stays continuous +# make follow-canary Bring up Phase A of the CANARY parallel-upgrade test +# (no local proving; production proofs imported and +# finalized through the forked production wrapper) +# make canary-upgrade Canary t1: register the NEW wrapper at boundary N and +# start the new coordinator+provers alongside the old +# (configs/mainnet-next.json; nothing is reset) +# make canary-rollback Roll back the canary upgrade: restore the old wrapper +# at N and apply quarantined production proofs >= N +# make follow-status Latest monitor snapshot + finalize lag +# make follow-report Throughput report for the current run +# make re-fork Re-fork Anvil at latest block (recovery) +# make follow-stop Stop the follow-mode stack + +SCRIPT_DIR := $(shell cd "$(dir $(lastword $(MAKEFILE_LIST)))" && pwd) +CONFIG_FILE := $(SCRIPT_DIR)/configs/mainnet.json +NEXT_CONFIG := $(SCRIPT_DIR)/configs/mainnet-next.json +# Docker provers: make canary-upgrade DOCKER_PROVERS=1 PROVER_IMAGE=scrolltech/prover: +DOCKER_PROVERS ?= +PROVER_IMAGE ?= +# .work is shared by both modes and stays at tests/shadow-testing/.work. +WORK_DIR := $(SCRIPT_DIR)/../.work + +DB_DSN := $(shell jq -r '.db.dsn' $(CONFIG_FILE) 2>/dev/null) + +.PHONY: follow follow-old follow-upgrade follow-canary canary-upgrade canary-rollback follow-stop follow-status follow-report re-fork help + +follow: + $(SCRIPT_DIR)/scripts/10-follow-up.sh + +follow-old: + $(SCRIPT_DIR)/scripts/10-follow-up.sh --skip-verifier + +follow-upgrade: + $(SCRIPT_DIR)/scripts/20-upgrade.sh --next-config $(NEXT_CONFIG) + +follow-canary: + $(SCRIPT_DIR)/scripts/10-follow-up.sh --import-proofs + +canary-upgrade: + $(if $(PROVER_IMAGE),PROVER_IMAGE=$(PROVER_IMAGE) ,)$(SCRIPT_DIR)/scripts/30-canary-upgrade.sh --next-config $(NEXT_CONFIG) \ + $(if $(DOCKER_PROVERS),--docker-provers,) + +canary-rollback: + $(SCRIPT_DIR)/scripts/31-canary-rollback.sh + +follow-stop: + $(SCRIPT_DIR)/scripts/11-follow-stop.sh + +follow-status: + @echo "📊 Last monitor snapshot:" + @last=$$(grep '^{' $(WORK_DIR)/catchup-metrics.log 2>/dev/null | tail -1); \ + if [ -z "$$last" ]; then echo " (no metrics yet)"; \ + else printf '%s\n' "$$last" | (jq . 2>/dev/null || python3 -m json.tool); fi + @echo "" + @echo "Finalize lag (shadow DB):" + @psql "$(DB_DSN)" -Atq -c "SELECT 'max_bundle=' || COALESCE(MAX(index),0) || ' max_finalized=' || COALESCE(MAX(index) FILTER (WHERE rollup_status=5),0) || ' lag=' || (COALESCE(MAX(index),0) - COALESCE(MAX(index) FILTER (WHERE rollup_status=5),0)) FROM bundle;" 2>/dev/null || echo " (DB not accessible)" + +follow-report: + SHADOW_REPORT_START=$$(grep '^SHADOW_REPORT_START=' $(WORK_DIR)/follow-run.env 2>/dev/null | cut -d= -f2-) python3 $(SCRIPT_DIR)/scripts/generate-catchup-report.py + +re-fork: + $(SCRIPT_DIR)/scripts/re-fork.sh + +help: + @echo "Follow Mode Makefile (fork current mainnet tip, follow indefinitely)" + @echo "" + @echo " make follow Bring up the full follow-mode stack" + @echo " make follow-old Phase 1 of the upgrade test (old stack =" + @echo " production release + production verifier)" + @echo " make follow-upgrade Cut over to the NEW zk stack mid-run" + @echo " (configs/mainnet-next.json; fork/DB untouched)" + @echo " make follow-canary Phase A of the canary parallel-upgrade test" + @echo " (imported production proofs, no local proving)" + @echo " make canary-upgrade Canary t1: new wrapper + new stack alongside" + @echo " the old (configs/mainnet-next.json)" + @echo " make canary-rollback Roll back the canary upgrade (old wrapper" + @echo " restored at N, quarantined proofs applied)" + @echo " make follow-status Latest monitor snapshot + finalize lag" + @echo " make follow-report Throughput report for the current run" + @echo " make re-fork Re-fork Anvil at latest block (recovery)" + @echo " make follow-stop Stop the follow-mode stack" + @echo "" + @echo "For snapshot replay mode (historical fork, fixed bundle range), use:" + @echo " make -C ../snapshot help" diff --git a/tests/shadow-testing/follow/README.md b/tests/shadow-testing/follow/README.md new file mode 100644 index 0000000000..7886016b33 --- /dev/null +++ b/tests/shadow-testing/follow/README.md @@ -0,0 +1,16 @@ +# Follow Mode (Primary) + +Follow mode forks the ETH mainnet state from **FOLLOW_FORK_HOURS_BACK hours in the past** (default 5h), baseline-syncs the shadow DB from the mainnet read replica, then first **catches up** the resulting backlog (all bundles committed-but-not-finalized at the fork block plus everything mainnet produced since) and then **follows** mainnet indefinitely — poll-syncing new chunk/batch/bundle rows, proving them with local GPU provers, and finalizing on the fork — for a preset window (default 48h). It is the **default acceptance test for prover/guest upgrades**: it answers whether the prover fleet can catch up a backlog *and* keep pace with real mainnet bundle production. `FOLLOW_FORK_HOURS_BACK=0` forks at the current tip (no backlog). The final report splits metrics into catch-up and steady-state phases. + +## Quick Start + +```bash +cd tests/shadow-testing/follow +make follow # one-shot bring-up: baseline sync → Anvil fork → verifier → coordinator → provers → relayer → daemons +make follow-status # latest monitor snapshot + finalize lag +make follow-report # throughput report for this run (SHADOW_REPORT_START) +make re-fork # recover from a fork desync (re-fork at latest block) +make follow-stop # tear down (script supports --keep-anvil) +``` + +Full guide: [`GUIDE.md`](GUIDE.md). Pitfalls/traps: [`./TROUBLESHOOTING.md`](./TROUBLESHOOTING.md) (follow mode) and [`../docs/COMMON-TROUBLESHOOTING.md`](../docs/COMMON-TROUBLESHOOTING.md) (mode-independent). Runtime state lives in the shared `../.work/`. diff --git a/tests/shadow-testing/follow/TROUBLESHOOTING.md b/tests/shadow-testing/follow/TROUBLESHOOTING.md new file mode 100644 index 0000000000..c0eb4ab5db --- /dev/null +++ b/tests/shadow-testing/follow/TROUBLESHOOTING.md @@ -0,0 +1,200 @@ +# Follow Mode — Troubleshooting & Pitfalls + +Follow-mode-specific traps (poll sync, starvation, live-mainnet finalization, upgrades/canary). +Mode-independent traps (environment, verifier deployment, relayer flags, prover setup) and the +step-by-step checklist live in [`../docs/COMMON-TROUBLESHOOTING.md`](../docs/COMMON-TROUBLESHOOTING.md); +see also the [Follow Mode Guide](./GUIDE.md). + +- **Registry & statuses**: [`../docs/TROUBLESHOOTING.md`](../docs/TROUBLESHOOTING.md) — every trap's status (Active/Fixed/Checklist) and key symptom. +- **Retired traps** (fixed in harness/upstream or absorbed into checklists — e.g. 25, 26, 28, 29, 30, 36, 43): [`../docs/TRAP-ARCHIVE.md`](../docs/TRAP-ARCHIVE.md). Numbers are retired, never reused. + +## Critical Traps (Follow Mode) + +### Poll-Sync & Task Visibility + +### Trap 22: Poll-Synced Chunks Missing `l2_block` Linkage → "failed to fetch block hashes of a chunk" [follow mode] + +- **Symptom**: In follow mode, after the initial backlog is proved, finalization stalls. Coordinator logs `format prover task failure ... failed to fetch block hashes of a chunk, chunk hash:0x... err:` on every dispatch attempt; provers spin on `CoordinatorEmptyProofData: get empty prover task` every ~20s; chunks pile up in `proving_status = 1` (with sweeps resetting stale `proving_status = 2` rows every 30 min). +- **Cause**: `sync-mainnet-db.py` poll mode copies new chunk/batch/bundle rows but historically skipped `l2_block` (watermarking the 181 GB mainnet table by `MAX(number)` times out). New chunks therefore had no block rows linked via `chunk_hash`, and the coordinator cannot format chunk tasks without them. Subtlety: the block rows usually **already exist** in the shadow DB (imported by block number during baseline) but with `chunk_hash = NULL`, so a plain `INSERT ... ON CONFLICT (number) DO NOTHING` copy is a no-op — the linkage must be established with an UPDATE. +- **Fix**: `sync_l2_blocks()` in `sync-mainnet-db.py` now runs every poll cycle: (1) `UPDATE l2_block SET chunk_hash = chunk.hash` for recent chunks (last 2000) whose blocks lack the link, then (2) copy any genuinely missing block rows from mainnet. One-off manual backfill if needed: + ```sql + UPDATE l2_block b SET chunk_hash = c.hash FROM chunk c + WHERE b.number BETWEEN c.start_block_number AND c.end_block_number + AND c.index > (SELECT COALESCE(MAX(index),0) - 2000 FROM chunk) + AND (b.chunk_hash IS NULL OR b.chunk_hash <> c.hash); + ``` +- **Diagnosis query**: chunks lacking block linkage — + ```sql + SELECT count(*) FROM chunk c + WHERE NOT EXISTS (SELECT 1 FROM l2_block b WHERE b.chunk_hash = c.hash); + ``` +- **Note**: `CoordinatorEmptyProofData` every 20s from an idle prover is the **normal** "no task available" poll response, not an error — chunk dispatch is serialized by parent-chunk proof dependency, so only 2-3 chunks prove concurrently even with 4 provers. It only indicates this trap when ALL provers spin AND the coordinator logs block-hash failures. +- **Secondary damage — attempt exhaustion starvation**: **Note (fixed upstream)**: this is now fixed in the coordinator itself — coordinator-side dispatch failures (task formatting, universal-task generation, prover-task insertion) refund the charged attempt via `orm.RefundAttemptsByHash` (`recoverAttempts` in `internal/logic/provertask/*_prover_task.go`), so `total_attempts` is no longer permanently burned by such failures. The sweeper's `total_attempts` reset described below is now belt-and-braces only. Historical description: the coordinator picks chunk tasks oldest-first but **skips tasks with `total_attempts >= 5`** (`chunk.go GetUnassignedChunk`: `total_attempts < maxAttempts`). Every failed dispatch during the outage burns one attempt, and `sweep-stale-proving.sh` historically reset only `proving_status`/`active_attempts`, not `total_attempts`. Result: the 44 backlog chunks hit 5/5 attempts and became permanently invisible — the coordinator silently leapfrogged to freshly-synced tip chunks while the backlog starved (symptom: only tip chunks prove, old pending chunks never get sessions, no ERROR logged). Fix: reset attempts after the root cause is repaired — + ```sql + UPDATE chunk SET total_attempts=0, active_attempts=0 + WHERE proving_status=1 AND total_attempts>0; + ``` + (same shape for `batch`/`bundle`). `sweep-stale-proving.sh` now resets `total_attempts = 0` on every swept row so future outages self-heal. +- **Diagnosis query for starvation**: oldest pending chunk with maxed attempts — + ```sql + SELECT index, total_attempts, active_attempts FROM chunk + WHERE proving_status = 1 ORDER BY index LIMIT 5; + ``` +- **Tertiary damage — NULL parent links block proof-status promotion**: poll sync copies chunk/batch rows with `ON CONFLICT DO NOTHING`, so rows copied *before* mainnet's proposer assigned them keep `batch_hash` / `bundle_hash` NULL forever. The coordinator_cron promotes `batch.chunk_proofs_status = Ready` only when all chunks joined via `chunk.batch_hash` are verified (`collect_proof.go checkBatchAllChunkReady`), and likewise `bundle.batch_proofs_status` via `batch.bundle_hash`. NULL links → promotion never happens → the batch/bundle is silently invisible to task selection (oldest-first query filters on the status flag; no ERROR is ever logged). Symptom: chunks all verified but batch sessions never start; one stray batch/bundle proves while its older siblings starve. Fix: re-derive links from the parent rows' index ranges — + ```sql + UPDATE chunk c SET batch_hash = b.hash FROM batch b + WHERE c.index BETWEEN b.start_chunk_index AND b.end_chunk_index + AND (c.batch_hash IS NULL OR c.batch_hash = '' OR c.batch_hash <> b.hash); + UPDATE batch b SET bundle_hash = u.hash FROM bundle u + WHERE b.index BETWEEN u.start_batch_index AND u.end_batch_index + AND (b.bundle_hash IS NULL OR b.bundle_hash = '' OR b.bundle_hash <> u.hash); + ``` + `sync-mainnet-db.py` runs both every poll cycle (`sync_parent_links()`, bounded to the recent 500 parents). + +### Trap 23: Bundles Popping Post-Fork L1 Messages → VerificationFailed (0x439cc0cd), then ErrorFinalizedIndexTooLarge (0x16465978) [follow mode] + +- **Symptom**: Most bundles finalize fine, but a bundle whose batches pop L1 messages enqueued **after the Anvil fork block** reverts on-chain with `VerificationFailed` (`0x439cc0cd`). After patching the queue hashes, it then reverts with `ErrorFinalizedIndexTooLarge` (`0x16465978`, appears as raw bytes `\x16FYx` in relayer logs). +- **Diagnosis flow (all verified during the 2026-07-13 incident, bundle 18070)**: + 1. Decode the bundle proof's `metadata.bundle_info` from the DB (`bundle.proof` is a JSON blob) and confirm every field matches mainnet DB values. + 2. Recompute `keccak256(abi.encodePacked(protocolVersion, publicInput))` with the wrapper's packed layout (`chainId 8B | msgQueueHash 32B | numBatches 4B | prevStateRoot | prevBatchHash | postStateRoot | batchHash | withdrawRoot`) and confirm it equals `metadata.bundle_pi_hash`. + 3. Call the wrapper's `verify(bundleProof, publicInput)` directly with the metadata-derived publicInput. **If it succeeds**, proof/digests are fine and the mismatch is contract-side — ScrollChain computes `messageQueueHash` itself via `L1MessageQueueV2.getMessageRollingHash()`. + 4. Compare `getMessageRollingHash(i)` on fork vs mainnet (public RPC e.g. `https://ethereum-rpc.publicnode.com` works; Alchemy demo key is 429-rate-limited). +- **Root cause**: `L1MessageQueueV2` keeps `mapping(uint256=>bytes32) messageRollingHashes` at **storage slot 101** (value = rolling hash with low 32 bits overwritten by enqueue timestamp; the getter clears those bits). Entries for messages enqueued after the fork block are zero on the fork, so the contract builds a publicInput whose `messageQueueHash` differs from the prover's → plonk rejects. Note the **off-by-one**: rh[i] is the hash *after* message i, so a bundle popping to index N needs rh[N-1]; DB `prev/post_l1_message_queue_hash` at popped_before=N equals `getMessageRollingHash(N-1)`. +- **Fix**: `scripts/sync-queue-hashes.py` copies `getMessageRollingHash(i)` from a mainnet RPC into the fork via `anvil_setStorageAt(queue, keccak256(pad32(i)‖pad32(101)), hash)` and also bumps `nextCrossDomainMessageIndex` (slot 103 = 0x67) to mainnet's value (this is what clears the follow-up `ErrorFinalizedIndexTooLarge`). It is idempotent and runs inside the `sync-mainnet-db.py` poll loop during follow mode (failures there only log a warning, never kill the DB sync). Run it manually after any Anvil restart/re-fork, and whenever a finalize reverts with either selector. +- **Rule of thumb**: if finalization fails only for bundles whose `post_l1_message_queue_hash != prev_l1_message_queue_hash` (i.e. the batch pops messages), suspect this trap before touching proofs or the verifier wrapper. + +### Relayer on the Fork + +### Trap 27: Relayer Cannot Commit/Finalize on the Fork — Balance, Sequencer, Nonce Checklist [follow mode] + +Three independent things must hold for the relayer to send its first on-fork commit; each fails with a distinct signature: + +1. **Zero EOA balance** → `Out of gas: gas required exceeds allowance: 0`. `10-follow-up.sh`'s idempotent restart skips `01-setup-anvil.sh` when Anvil is already running, so EOA funding never re-runs. Fix: `cast rpc anvil_setBalance 0x56bc75e2d63100000` for both the commit sender and the finalize sender. +2. **`ErrorCallerIsNotSequencer` (0x3cddbade)** on `commitBatches` → the commit sender is not authorized on the fork. `configs/mainnet.json` `accounts.commit_eoa` **must equal** the address derived from the `COMMIT_KEY` hardcoded in `06-run-relayer.sh` — they had drifted apart (`0xf39F…` vs `0xBC73…`), so `01-setup-anvil.sh` authorized an account the relayer never uses. Authorize manually: impersonate the ScrollChain owner and `cast send … "addSequencer(address)" --unlocked`. +3. **Tx stuck in txpool `queued` forever** → `pending_transaction` nonce desync (Trap 7 variant). The relayer's sender initializes its nonce as `max(db_max_nonce + 1, chain_pending_nonce)` (`rollup/internal/controller/sender/sender.go` `initializeNonce`). `pending_transaction` rows survive Anvil state-file restores, but the on-fork account nonce does not (a restored state can reset it to 0). The relayer then signs with a high nonce, Anvil queues the tx behind a gap that never fills, and *nothing ever mines* — commits silently stall with no error after the initial send. Diagnose with `cast nonce ` vs `cast rpc txpool_content`; fix: stop relayer, `DELETE FROM pending_transaction WHERE sender_address = ''` (or all rows), restart relayer so it re-initializes from the chain nonce. + +Also note that the relayer writes `rollup_status` **only** through its commit/finalize confirmation path (GORM `UPDATE … SET finalize_tx_hash, rollup_status`). If a batch/bundle shows `rollup_status = 5` with NULL `finalize_tx_hash` while `lastFinalizedBatchIndex` on the fork hasn't moved, do not trust the DB row — cross-check on-chain. `log_statement = 'mod'` on the shadow postgres is a cheap way to attribute every status write; it is asserted automatically by `02-prepare-db.sh` and `10-follow-up.sh` (re-applied on every setup, since `ALTER SYSTEM` lives in the container's data volume and is lost when the volume is recreated). Read the writes with `docker logs shadow-postgres` (or the postgres server log on a non-docker setup). + +### Upgrades, Canary & Builds + +### Trap 31: Upgrade-Test Phase 1 Built From the Branch Under Test, Not From Production [follow mode] + +- **Symptom**: Phase-1 chunks/batches prove fine, but every bundle finalize reverts with `VerificationFailed (0x439cc0cd)` even though `--skip-verifier` routing checks pass. +- **Cause**: Assuming the current checkout == the production zk stack. The branch under test and the config templates describe the NEW version (e.g. zkvm v0.9.0 / OpenVM 2.0.0), while mainnet may still run the previous guest (e.g. v0.8.0 / OpenVM 1.6.0 from `develop`). New-guest proofs can never verify against the production wrapper's digests — the mismatch only shows up at finalization, after hours of proving. +- **Fix**: determine the production stack FIRST (follow/GUIDE.md "Determining the Production zk Stack": on-chain wrapper `verifierDigest1/2()` vs S3 `digest_*.hex` — Montgomery conversion needed for v0.8.0, see docs/bundle-digest-encoding.md — plus `git_version` inside a production `bundle.proof` JSON, and `Cargo.lock` zkvm pins per branch). Build production in a separate `git worktree` and aim `COORD_DIR` / `PROVER_BIN` / `ASSETS_DIR` at it for Phase 1. Also remember the v0.8.0 S3 prefix has **no** `/releases/` segment. + +### Trap 32: `cargo update -p scroll-zkvm-*` Drifts `revm`, Breaking the `[patch]` Fork Resolution [build] + +- **Symptom**: After bumping the `scroll-zkvm-*` workspace pin (e.g. `tag = "v0.9.0"` → `rev = `) and running `cargo update -p scroll-zkvm-prover ...`, the build fails deep in the dependency graph with `E0308 mismatched types ... expected revm_primitives::hardfork::SpecId, found SpecId` and the note "there are multiple different versions of crate `revm_primitives`" (crates.io vs the scroll `scroll-v91` fork). +- **Cause**: `cargo update -p` re-resolves more than the named crates. It flipped `alloy-evm 0.22.6`'s edge from `revm 30.1.1` to `revm 30.2.0` (and several `revm-primitives` edges from the patched fork `21.0.1` to crates.io `21.0.2`). The workspace `[patch.crates-io]` only redirects a revm crate to the scroll fork when the fork's version satisfies the requirement; the bumped crates.io `revm` family mixes fork and non-fork `revm-primitives` in one crate and cannot compile. +- **Fix**: restore the exact HEAD edges instead of letting the resolver choose. Inspect with `git diff Cargo.lock`; the two hand-edits that fixed it (2026-07, zkvm master bf887150): (1) in `alloy-evm 0.22.6`'s dependency list change `"revm 30.2.0"` back to `"revm 30.1.1"`; (2) in the six crates.io revm-family packages that flipped (`revm-context 10.1.2`, `revm-context-interface 11.1.2`, `revm-handler 11.2.0`, `revm-inspector 11.2.0`, `revm-interpreter 28.0.0`, `revm 30.2.0`) change `"revm-primitives 21.0.2"` back to `"revm-primitives 21.0.1"` (the fork). Verify with `cargo metadata --locked` before rebuilding. You cannot fix this with `cargo update -p revm --precise ...` — `op-revm` legitimately requires `revm ^30.2.0`, so both versions must coexist. +- **Prevention**: after any `cargo update -p scroll-zkvm-*`, always `git diff Cargo.lock` and revert every revm-family drift before building. + +### Trap 33: v0.9.0+ Master Requires `agg_vk.bin` on S3 (Prover) and in Coordinator Assets [follow mode / upgrade] + +- **Symptom**: New-stack prover exits at startup with `Failed to download agg_vk.bin: HTTP status 403` (or silently falls back to "deriving agg VK from SDK (slow, may allocate GPU memory)" and later OOMs the 24 GB card during SNARK proving). Coordinator panics with `agg_vk.bin missing from assets` when its first batch proof arrives. +- **Cause**: zkvm-prover master (bf887150, halo2-gpu) writes a per-circuit `agg_vk.bin` next to `app.vmexe` at `build-guest` time, and `Prover::load_agg_vk()` reads it to avoid constructing the GPU aggregation prover just to obtain the VK. The scroll prover downloads circuits from the **flat** S3 layout `//app.vmexe` (no VK subdir) and expects `agg_vk.bin` in the same dir; the v0.9.0 S3 assets predate this file. The coordinator's batch-proof verification (deferral) reads the same key as `agg_vk.bin` from its own assets dir (`crates/libzkp/src/verifier/universal.rs`). +- **Fix**: after every guest rebuild that bumps the zkvm pin, upload the new artifacts (bucket layout is flat per circuit): + ```bash + Z=/releases/dev + B=s3://circuit-release/scroll-zkvm/releases/v0.9.0 + for c in chunk batch bundle; do aws s3 cp $Z/$c/agg_vk.bin $B/$c/agg_vk.bin; done + # verify: anonymous GET must succeed (403 = wrong key or missing object) + curl -s -o /dev/null -w '%{http_code}\n' https://circuit-release.s3.us-west-2.amazonaws.com/scroll-zkvm/releases/v0.9.0/chunk/agg_vk.bin + ``` + For the local coordinator, copy the batch circuit's `agg_vk.bin` into `coordinator/build/bin/assets_v2/agg_vk.bin` (no separate S3 object needed — it is the same file the prover downloads from `batch/agg_vk.bin`). +- **Note**: `agg_vk.bin` contents are identical for batch and bundle (same agg config) and equal to `root_verifier_vk` for chunk — matching md5s are expected, not a copy/paste bug. And always re-run `make build-guest` after switching zkvm commits: a stale `releases/dev/` once produced a wrong `digest_1.hex` that only a fresh build corrected (digests must match the canonical values in docs/bundle-digest-encoding.md). + +### Trap 34: Stale `prover_task` Failure Rows Starve Batch Assignment Silently [follow mode] + +- **Symptom**: Chunks all prove, batches sit at `proving_status = 1` with `chunk_proofs_status = 2` (ready) forever, provers idle-poll `CoordinatorEmptyProofData: get empty prover task`, and the coordinator never logs `start batch proof generation session`. No ERROR anywhere. +- **Cause**: The coordinator's batch assignment returns the lowest-index unassigned batch (`ORDER BY index LIMIT 1`) and then applies the "don't dispatch the same failing job to the same prover" rule: if `prover_task` contains a `proving_status = 3` (ProverProofInvalid) row for that batch hash *and* the polling prover, the assignment silently returns empty — and because the query always picks the *same* lowest batch first, later batches are never considered. If every prover has a failure row for that one batch, all batch proving starves permanently. The sweeper (`sweep-stale-proving.sh`) resets `batch.proving_status`/`total_attempts` but does NOT clear `prover_task` failure rows, so the poison survives sweeps and coordinator restarts. +- **How it happens here**: a previous coordinator instance (e.g. a sanity run whose assets lacked `agg_vk.bin`, Trap 33) rejects a valid proof as `ProverProofInvalid`. The failure is the coordinator's fault, but the row pins the *prover* as having failed the task. +- **Fix**: delete the bogus failure rows (verify they are bogus first — `created_at` predating the current coordinator instance is a strong hint): + ```sql + SELECT task_type, task_id, prover_name, failure_type, created_at FROM prover_task WHERE proving_status = 3; + DELETE FROM prover_task WHERE proving_status = 3 AND task_type = 2 AND task_id = ''; + ``` +- **Note**: task type is chosen at RANDOM per poll (`proofType()` in `get_task.go` shuffles chunk/batch/bundle), and a busy prover does not poll — so even a healthy system picks up batch tasks only on lucky idle polls; a few minutes of delay after unblocking is normal, hours is not. + +### Trap 35: Post-Upgrade — Coordinator Loops "Generate universal prover task failure" on Old-Format Proofs [upgrade] + +- **Symptom**: Right after the 20-upgrade.sh cutover, the new coordinator repeatedly logs `Generate universal prover task failure ... data did not match any variant of untagged enum ProofEnum` for the same one or two task ids, provers error on every poll (`CoordinatorGetTaskFailure`), and NO new tasks of any type get assigned (chunks included) — the whole fleet starves. +- **Cause**: three leftover-state problems stack up: + 1. **Stale assigned `prover_task` rows** — tasks that were in-flight at the cutover keep `proving_status = 1` (ProverAssigned) rows; the new coordinator's `hasAssignedTask` path rebuilds them from old-circuit child proofs, which the new libzkp cannot parse. + 2. **Stale ready flags on never-assigned rows** — a naive reset (`WHERE proving_status <> 1`) misses rows that were *already* unproved: bundles whose `batch_proofs_status = Ready` and batches whose `chunk_proofs_status = Ready` from old-circuit proving stay assignable, and their DB proof blobs are old-format. + 3. **Priority dispatch amplifies the poison** — the branch's GetTasks tries Bundle > Batch > Chunk and ABORTS the whole request when a higher-priority `Assign` errors (unlike develop's random pick), so one poisoned bundle blocks chunk/batch assignment too. +- **Fix (codified)**: 20-upgrade.sh step (e) now resets `batch_proofs_status`/`chunk_proofs_status` and clears `proof` blobs for ALL unfinalized rows at/after N (not just `proving_status <> 1`), and `DELETE FROM prover_task WHERE proving_status = 1` while the provers are stopped. Manual recovery is the same SQL; after cleanup the pipeline recovers within one poll cycle. +- **Related**: first chunk task generation after an assets swap is SLOW (the coordinator fetches `debug_executionWitness` block-by-block — ~550 blocks ≈ 10-15 min for two chunks — at 0% CPU). This is normal; the prover-side `connection_timeout_sec = 1800` covers it. Do not restart the coordinator just because it looks idle. + +### Trap 37: `make coordinator_api` Does NOT Refresh the Embedded `libzkp.so` [build / upgrade] + +- **Symptom**: After rebuilding `target/release/libzkp.so` (e.g. for the `agg_vk.bin` verifier change) and restarting the coordinator, batch proof verification still runs the OLD code — valid proofs are rejected (`Batch verify failed, error: missing from assets`) and the rejections poison `prover_task` exactly like Trap 34. +- **Cause**: the coordinator Go binary CGO-links `coordinator/internal/logic/libzkp/lib/libzkp.so` — a **separate copy** that `make coordinator_api` does not rebuild or re-copy. Only `make -C coordinator libzkp` (or a manual `cp target/release/libzkp.so coordinator/internal/logic/libzkp/lib/`) refreshes it. +- **Fix**: after every libzkp-c rebuild that changes verifier/prover logic, sync the copy and restart the coordinators: + ```bash + cargo build --release -p libzkp-c + cp target/release/libzkp.so coordinator/internal/logic/libzkp/lib/libzkp.so + strings coordinator/internal/logic/libzkp/lib/libzkp.so | grep -c "" # sanity check + ``` + Then clear any `ProverProofInvalid` rows created while the stale .so was live (Trap 34 recovery SQL). + +### Trap 38: halo2-gpu Bundle Prover Crashes — VRAM Starvation and `def_hook_commit` [upgrade / halo2-gpu] + +- **Symptom 1**: Both provers die mid-bundle: `panicked ... called Result::unwrap() on an Err value: HaloGpu(Cuda(CudaError { code: 9, name: "cudaErrorInvalidConfiguration", ... quotient.cu }))` right after the halo2 `create_proof` phase, with the log showing `GPU mem ... peak=22.9 GiB`. +- **Cause 1**: scroll's prover-bin obtained the child aggregation VK via `sdk.agg_vk()`, which **builds the child's full GPU aggregation prover (~5.7 GiB per circuit)** just to read the VK. The openvm VPMM pool never returns those pages to the OS, so by SNARK time `cudaMemGetInfo` free ≈ 0 and the quotient chunking computes `batch_size = 0` → `cudaErrorInvalidConfiguration` (not a clean OOM). zkvm-prover master (bf887150) documents exactly this failure mode in its AGENTS.md "VRAM budgeting" section. +- **Fix 1**: `UniversalHandler::agg_vk()` now uses `Prover::load_agg_vk()`, which reads the pre-built `agg_vk.bin` asset (downloaded alongside `app.vmexe`) instead of materializing the GPU prover. Post-fix SNARK-phase peak dropped enough for 24 GB cards (observed halo2_outer ~8 s + wrapper ~2.3 s per bundle). +- **Symptom 2**: After fixing #1, the prover panics with `def_hook_commit must be defined to verify child proof with deferrals` as soon as a **bundle** task arrives before any batch task in a fresh process. +- **Cause 2**: The bundle verify circuit's `def_hook_commit` comes from the *batch child* SDK's deferral prover, which only exists after the batch prover's own `enable_deferral(chunk)` ran. Previously `sdk.agg_vk()` accidentally initialized it as a side effect; with the file-based `load_agg_vk()` that side effect is gone. (Batch tasks are unaffected: chunk children carry no deferral merkle proofs, so the assert passes with a `None` hook commit.) +- **Fix 2**: `do_prove` now initializes the batch child's deferral (`batch.enable_deferral(chunk_handler)`) before `bundle.enable_deferral(batch)` for bundle tasks — mirroring the zkvm integration tester's flow. +- **Symptom 3** (2026-08-03, post-Fix-1 binary): the *same* `quotient.cu ... invalid configuration` panic returns, peak ~22.8 GiB — but only when the prover process proved **chunk/batch tasks earlier in its lifetime** and then picks up a bundle task. A process that goes straight to bundle tasks (the post-Fix-1 verification scenario) survives. +- **Cause 3**: Fix 1 removed the 5.7 GiB/circuit agg-VK derivation, but the GPU circuit provers of every task type the process has served stay resident (VPMM pool never returns pages). Chunk+batch+bundle+halo2_outer together still exceed what the SNARK quotient chunking needs on a 24 GB card → `batch_size = 0` again. Mixed task types re-create the starvation Fix 1 only narrowed. +- **Workaround 3 (ops)**: pin task types per GPU so bundle proofs always run in a clean process — edit `.work/prover-/prover.json` `sdk_config.prover.supported_proof_types` to `[1,2]` on one GPU and `[3]` on the other, then restart both provers. +- **Fix 3 (code, verified 2026-08-03)**: `crates/prover-bin` now calls `Prover::reset()` on the child/grandchild handlers right after `enable_deferral` (+ file-based `agg_vk()`) in `do_prove` — the child SDK exists only to configure the parent's deferral (agg_vk / cached commit / hook commit are captured by value), so its GPU proving keys are released before the parent's STARK/SNARK phase, mirroring the zkvm integration tester (`crates/integration/src/testers/bundle.rs`). Verified live on this shadow fork: bundle 18394 was proven by a **mixed-type process** (same process had proved chunk tasks minutes earlier, `supported_proof_types=[1,2,3]`) and finalized via the new wrapper — halo2_outer `create_proof` live peak was **8.6 GiB** (vs 22.8 GiB in the crash), and the quotient phase ran with `current` 6.4–8.6 GiB instead of 14.7–22.7 GiB. Note the VPMM `in pool=` number still shows the historical high-water mark (~22.4 GiB from earlier chunk proving) — the pool never shrinks, but its free regions are reusable; what matters for the quotient chunking heuristic is that *physical* free stays > ~256 MiB, which on 24 GB cards remains a thin margin. +- **Root-cause note for upstream**: halo2-axiom-gpu's `query_device_free_bytes_for_chunking()` budgets from raw `cudaMemGetInfo` (physical free) while its own allocations go through the VPMM pool — pool-internal free regions are usable but not counted. A minimal upstream fix: add `MemoryManager::pool_free_bytes()` (sum of `free_regions`) to openvm-cuda-common and budget `physical_free + pool_free_bytes() - RESERVED` in `cuda/utils.rs`. +- **Operational note**: after a prover crash, also `DELETE FROM prover_task WHERE proving_status = 1` and reset the affected `bundle`/`batch` rows — a task proved from a *deleted* assignment row is rejected with `validator failure get none prover task for the proof`, and the SDK will happily re-prove its locally-cached stale task instead of picking up the fresh assignment. Three corollaries learned on 2026-08-03: + 1. **Also reset `active_attempts = 0`** on the reset `bundle`/`batch` rows. `GetUnassignedBundle` requires `active_attempts < max`, and once the `prover_task` rows are deleted, coordinator-cron's `DecreaseActiveAttemptsByHash` matches nothing ("No rows were affected") — the row sits at `active_attempts = 1` forever and is never re-dispatched, with no ERROR logged. + 2. **Wipe the crashed prover's local SDK db** (`.work/prover-/db`) *before* restarting it, or it loops forever on the cached task: build fails (`unsupported task type` if you also narrowed `supported_proof_types`) and every submit is rejected (`get none prover task`). + 3. Restart order: SQL cleanup first, then db wipe, then prover restart — restarting against a dirty SDK db just re-poisons the loop. + +### Trap 39: Canary Proof-Import Mode — Stale Cursor, Missing Boundary, and Fork-Point Version Skew [follow mode / canary] + +- **Symptom 1**: After `make follow-canary`, backlog bundles never finalize even though `remote_bundle_proof` keeps growing — `bundle.proof` stays NULL. +- **Cause 1a**: The apply rule only touches rows with `proof IS NULL AND rollup_status <> 5 AND end_batch_index < boundary`. If `.work/canary.env` contains a stale `PROOF_IMPORT_MAX_END_BATCH` from a PREVIOUS canary run (the file is never deleted by `follow-stop`/`--reset`), the boundary silently caps which proofs get applied. Check `grep PROOF_IMPORT_MAX_END_BATCH tests/shadow-testing/.work/canary.env` against the current `lastFinalizedBatchIndex`; delete the file (or the key) to return to +∞ before re-running Phase A. +- **Cause 1b**: The import cursor (`.work/proof-import.cursor`) survived a `--reset` while the shadow DB was truncated, so bundles already scanned are never re-upserted. The quarantine table also survives `--reset`, so normally the apply rule still finds them — but if you dropped `remote_bundle_proof` manually without deleting the cursor file, no proofs will ever re-import. Fix: delete both `remote_bundle_proof` and `.work/proof-import.cursor` together and let one poll cycle re-scan. (Since 2026-08-25, `10-follow-up.sh --reset` deletes both automatically.) +- **Cause 1c (cursor high-watermark vs. late proofs)**: mainnet creates the `bundle` row first and attaches the proof minutes later. An earlier version of the importer advanced its cursor to remote `MAX(index)` over ALL bundles, so any bundle still unproven at scan time was skipped forever — `remote_bundle_proof` stopped growing while mainnet kept proving. Fixed: the cursor only advances over rows with `proving_status=4`, and the scan re-reads a 200-row lookback window (`ON CONFLICT DO NOTHING` makes re-upserts free). If you run an older checkout and see this, hand-import once: run `import_remote_proofs()` from `sync-mainnet-db.py` with `SYNC_PROOFS=1` in a one-off python snippet, then restart the poll-sync python process (the bash wrapper re-launches it within 60s). +- **Symptom 2**: Imported proofs fail on-chain with `VerificationFailed (0x439cc0cd)` during Phase A. +- **Cause 2**: Fork-point version skew (Trap 31 variant): the forked production MVRV wrapper's digests belong to a NEWER/OLDER production guest than the proofs being imported. Production proofs and the production wrapper only match if the fork block post-dates the last production verifier upgrade AND the imported proofs were generated after it. Verify the production guest version before forking (follow/GUIDE.md "Determining the Production zk Stack"; digest encoding in `tests/shadow-testing/docs/bundle-digest-encoding.md`). +- **Symptom 3**: After `31-canary-rollback.sh`, some bundles ≥ N finalize-fail (`rollup_status=7`) even though routing points back at the old wrapper. +- **Cause 3**: Those bundles were proven locally by the NEW stack and the remote had not proved them yet when the rollback applied the quarantine table — the rollback resets such rows to unproven, but a relayer finalize already in flight can still carry the new proof. Wait for the remote proof to land in `remote_bundle_proof` (one poll cycle after mainnet proves it), then reset the failed row: `UPDATE bundle SET rollup_status=1, finalize_tx_hash=NULL WHERE rollup_status=7 AND end_batch_index >= ;` — the next poll cycle applies the quarantined proof and the relayer retries. +- **Note**: the proof-import UPDATE is race-free with the Phase-B coordinator by construction: the importer only writes `< boundary` rows with `proof IS NULL`, the coordinator only dispatches unproven `>= boundary` bundles. If you ever hand-edit `.work/canary.env` mid-run, keep that partition intact. + +### Trap 40: Canary Mode — Boundary N vs. Proven Backlog, and coordinator_api genesis [follow mode / canary] + +- **Symptom 1**: After `30-canary-upgrade.sh`, an OLD-proof backlog bundle (end_batch < N) finalize-fails `VerificationFailed (0x439cc0cd)` even though it verified fine before the upgrade. +- **Cause 1**: N was computed as `lastFinalized+1` while unfinalized bundles WITH imported proofs still sat above it — they then route to the NEW wrapper, which can never verify an old-guest proof. N must be `> MAX(end_batch_index)` over all unfinalized bundles holding a quarantined remote proof. `30-canary-upgrade.sh` step b enforces this (P term) since 2026-08-25; if you hand-pick `--start-batch`, keep the same invariant. +- **Symptom 2**: After `30-canary-upgrade.sh` (or `10-follow-up.sh` on a fresh machine), the provers burn all their coordinator login retries and die; `coordinator-api.pid` points at a corpse. +- **Cause 2**: `coordinator_api` reads `conf/genesis.json` relative to its CWD (`$COORD_DIR`) and CRITs `failed to read genesis` seconds after the startup pid check passes. Fix: `cp tests/prover-e2e/mainnet-galileoV2/genesis.json coordinator/build/bin/conf/genesis.json`, then restart the api and the provers (`lib/04-prover-up.sh`). 30-canary-upgrade.sh now sanity-checks this file up front. (Same failure as COMMON Trap 48, archived.) +- **Symptom 3**: Poll cycles take 10-15 min each, so imported proofs (and new bundles) arrive in the shadow DB in big delayed chunks. +- **Cause 3**: The per-cycle `l2_block` range copy runs a server-side cursor against the remote DB; on a cold/slow remote disk (`DataFileRead` waits in `pg_stat_activity`) each FETCH takes minutes, and `import_remote_proofs()` runs AFTER it in the same cycle. It is back-pressure only, not data loss — but expect proof-import latency ≈ one full cycle. If you need a proof applied NOW (e.g. to stage a boundary), run `import_remote_proofs()` manually as in Trap 39 Cause 1c. + +### Trap 42: Docker Prover Mode — `..` in Mount Paths, and CPU-SNARK Images [follow mode / docker] + +> Path issue fixed 2026-08-31 (work-dir canonicalization); the image-build rule below still bites — kept Active for that. + +- **Symptom 1** (historical, fixed): `04-prover-up.sh --docker` reports "prover container shadow-prover-N failed to start"; `docker logs` shows `Error: No such file or directory (os error 2)` at `prover.rs` `File::open`. +- **Cause 1**: the per-GPU `work_dir` was built as `${SCRIPT_DIR}/../.work/prover-N`. dockerd path-cleans bind-mount targets, but the prover opens its config by the **literal** path — inside the container the `lib/..` component cannot resolve. Bare metal never noticed. +- **Symptom 2**: bundle tasks take ~30+ min under docker while chunk/batch fly. +- **Cause 2**: the image was built from a `make prover` binary (`--features cuda`) — bundle halo2 SNARK then runs on CPU. Build with `make prover_halo2gpu` and rebuild the image; GPU SNARK phase is seconds (`Create EVM proof` ~6 s, peak ~8.8 GiB on a 4090). Same rule applies to bare metal. +- **Symptom 3**: after a prover restart, the new container logs `already assigned a task` forever. +- **Cause 3**: the coordinator still holds the previous process's assignment row. `DELETE FROM prover_task WHERE proving_status IN (1,3);` (or wait for the sweeper, ~10 min). +- **Env note**: scripts default `MAINNET_DSN` to `localhost:15432` (RDS-tunnel convention). On hosts where the DB lives at a direct address, export `MAINNET_DSN` explicitly — every follow-mode script honors the env var. + +### Infra Cost + +### Trap 41: Remote Sync Queries Missing `deleted_at IS NULL` — Seq Scans = RDS Money [follow mode / infra cost] + +- **Symptom**: AWS RDS bill spikes while a follow/snapshot stack is running; remote-side `pg_stat_activity` shows sync queries in `DataFileRead` for minutes per cycle (see also Trap 40 Cause 3, whose real root cause is this one). +- **Cause**: ALL mainnet indexes on `l2_block`/`chunk` (and most on `l1_message`) are **partial** (`WHERE deleted_at IS NULL`). A query without that predicate cannot use them: `SELECT MAX(index) FROM chunk` scanned an entire 6.6M-row index every 60 s poll cycle, and the per-cycle `l2_block` range copy (`count(*)` + `SELECT ... WHERE number BETWEEN ...`) ran **two parallel seq scans of the 62 GB heap** whenever new chunks arrived — TB-scale reads per day on RDS. +- **Fix**: since 2026-08-27 `sync-mainnet-db.py` appends `deleted_at IS NULL` (constant `NOT_DELETED`) to every src-side query (`get_watermarks`, `copy_range`, baseline `copy_table_pipe` clauses, proof import). Verified by EXPLAIN: watermark MAX = 1-page index-only backward scan; range copies = plain index scans. If you add a new src-side query to that script, keep the invariant. Ad-hoc query rules live in [`../docs/rds-query-rules.md`](../docs/rds-query-rules.md). +- **Related discipline**: stop the stack when a test ends (`make follow-stop`) — an idle follow stack polls the remote DB every 60 s forever; that alone was most of the observed cost. diff --git a/tests/shadow-testing/follow/configs/coordinator.json.template b/tests/shadow-testing/follow/configs/coordinator.json.template new file mode 100644 index 0000000000..5b63bd4b69 --- /dev/null +++ b/tests/shadow-testing/follow/configs/coordinator.json.template @@ -0,0 +1,40 @@ +{ + "prover_manager": { + "provers_per_session": 1, + "session_attempts": 5, + "external_prover_threshold": 32, + "bundle_collection_time_sec": 7200, + "batch_collection_time_sec": 180, + "chunk_collection_time_sec": 3600, + "verifier": { + "min_prover_version": "v4.4.45", + "verifiers": [ + { + "assets_path": "assets", + "fork_name": "galileoV2" + } + ] + } + }, + "db": { + "driver_name": "postgres", + "dsn": "postgres://postgres:YOUR_SHADOW_DB_PASSWORD@shadow-postgres:5432/shadow_rollup?sslmode=disable", + "maxOpenNum": 200, + "maxIdleNum": 20 + }, + "l2": { + "validium_mode": false, + "chain_id": 534352, + "l2geth": { + "endpoint": "https://l2geth-rpc-proxy.mainnet.aws.scroll.io" + } + }, + "auth": { + "secret": "YOUR_COORDINATOR_AUTH_SECRET", + "challenge_expire_duration_sec": 3600, + "login_expire_duration_sec": 3600 + }, + "sequencer": { + "decryption_key": "" + } +} diff --git a/tests/shadow-testing/follow/configs/mainnet-next.json.template b/tests/shadow-testing/follow/configs/mainnet-next.json.template new file mode 100644 index 0000000000..7c55810e66 --- /dev/null +++ b/tests/shadow-testing/follow/configs/mainnet-next.json.template @@ -0,0 +1,45 @@ +{ + "name": "mainnet-shadow-fork-next", + "fork": { + "url": "https://eth-mainnet.g.alchemy.com/v2/YOUR_ALCHEMY_API_KEY", + "block_number": 25202217, + "anvil_rpc": "http://localhost:18545" + }, + "contracts": { + "scroll_chain": "0xa13BAF47339d63B743e7Da8741db5456DAc1E556", + "l1_message_queue_v2": "0x56971da63A3C0205184FEF096E9ddFc7A8C2D18a", + "rollup_verifier": "0x4CEA3E866e7c57fD75CB0CA3E9F5f1151D4Ead3F", + "deployed_verifier": "", + "owner": "0x798576400F7D662961BA15C6b3F3d813447a26a6" + }, + "accounts": { + "prover_eoa": "0x410E7FD80a3Fc1E62A4D3450d11b71b812006eB9", + "commit_eoa": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" + }, + "reset": { + "last_finalized_batch_index": 517765, + "next_unfinalized_queue_index": 0, + "codec_version": 10, + "last_committed_batch_index": 517819 + }, + "db": { + "dsn": "postgresql://postgres:YOUR_SHADOW_DB_PASSWORD@localhost:5433/shadow_rollup" + }, + "genesis": "tests/prover-e2e/mainnet-galileoV2/genesis.json", + "assets": { + "assets_v2": "coordinator/build/bin/assets_v2_next" + }, + "prover": { + "name_prefix": "galileo6-shadowfork-prover", + "circuit_version": "v0.14.0", + "s3_base_url": "https://circuit-release.s3.us-west-2.amazonaws.com/scroll-zkvm/releases/vX.Y.Z/" + }, + "relayer": { + "validium_mode": false, + "min_codec_version": 7, + "chain_monitor_enabled": false + }, + "e2e": { + "l2_rpc": "https://l2geth-rpc-proxy.mainnet.aws.scroll.io" + } +} diff --git a/tests/shadow-testing/follow/configs/mainnet.json.template b/tests/shadow-testing/follow/configs/mainnet.json.template new file mode 100644 index 0000000000..ff02fdc90d --- /dev/null +++ b/tests/shadow-testing/follow/configs/mainnet.json.template @@ -0,0 +1,45 @@ +{ + "name": "mainnet-shadow-fork", + "fork": { + "url": "https://eth-mainnet.g.alchemy.com/v2/YOUR_ALCHEMY_API_KEY", + "block_number": 25202217, + "anvil_rpc": "http://localhost:18545" + }, + "contracts": { + "scroll_chain": "0xa13BAF47339d63B743e7Da8741db5456DAc1E556", + "l1_message_queue_v2": "0x56971da63A3C0205184FEF096E9ddFc7A8C2D18a", + "rollup_verifier": "0x4CEA3E866e7c57fD75CB0CA3E9F5f1151D4Ead3F", + "deployed_verifier": "0xb1F2C5c1ea2885278a1070350d12d3D8824265B0", + "owner": "0x798576400F7D662961BA15C6b3F3d813447a26a6" + }, + "accounts": { + "prover_eoa": "0x410E7FD80a3Fc1E62A4D3450d11b71b812006eB9", + "commit_eoa": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266" + }, + "reset": { + "last_finalized_batch_index": 517765, + "next_unfinalized_queue_index": 0, + "codec_version": 10, + "last_committed_batch_index": 517819 + }, + "db": { + "dsn": "postgresql://postgres:YOUR_SHADOW_DB_PASSWORD@localhost:5433/shadow_rollup" + }, + "genesis": "tests/prover-e2e/mainnet-galileoV2/genesis.json", + "assets": { + "assets_v2": "coordinator/build/bin/assets_v2" + }, + "prover": { + "name_prefix": "galileo6-shadowfork-prover", + "circuit_version": "v0.13.1", + "s3_base_url": "https://circuit-release.s3.us-west-2.amazonaws.com/scroll-zkvm/releases/v0.9.0/" + }, + "relayer": { + "validium_mode": false, + "min_codec_version": 7, + "chain_monitor_enabled": false + }, + "e2e": { + "l2_rpc": "https://l2geth-rpc-proxy.mainnet.aws.scroll.io" + } +} diff --git a/tests/shadow-testing/follow/scripts/10-follow-up.sh b/tests/shadow-testing/follow/scripts/10-follow-up.sh new file mode 100755 index 0000000000..8b177f896a --- /dev/null +++ b/tests/shadow-testing/follow/scripts/10-follow-up.sh @@ -0,0 +1,584 @@ +#!/usr/bin/env bash +# 10-follow-up.sh — one-shot orchestrator for "follow mode" shadow testing. +# +# Brings up the full follow-mode stack against a RECENT mainnet state: +# a. sanity checks (postgres 5433, mainnet DSN, alchemy key, stale ports) +# b. baseline DB sync from the mainnet read replica +# c. Anvil fork at tip - FOLLOW_FORK_HOURS_BACK*300 blocks (default 5h back, +# via 01-setup-anvil.sh) so the run opens with a real backlog to catch up +# d. verifier wrapper deploy + registration (via 03-deploy-verifier.sh) +# e. initial L1 queue rolling-hash sync (Trap 23) +# f. coordinator_api + coordinator_cron +# g. GPU provers (via 04-prover-up.sh) +# h. rollup relayer (via 06-run-relayer.sh) +# i. background daemon loops: poll sync / stale-proving sweeper / monitor +# j. records run metadata in .work/follow-run.env +# +# Idempotent-ish: a component whose pidfile exists and is alive is skipped. +# Usage: ./10-follow-up.sh [--config configs/mainnet.json] [--dry-run] [--reset] [--skip-verifier] [--import-proofs] +# Env: FOLLOW_FORK_HOURS_BACK=0 forks at the current tip (no backlog). +# --skip-verifier: do NOT deploy a verifier wrapper in step d; use the +# production verifier already registered on the forked MVRV. This is the +# Phase-1 ("old stack") bring-up for the mid-run upgrade test — see +# scripts/20-upgrade.sh. +# --import-proofs: canary parallel-upgrade Phase A. Implies --skip-verifier; +# additionally skips the local coordinator_api/coordinator_cron/provers +# entirely (Phase A needs no local proving) and passes SYNC_PROOFS=1 to the +# baseline sync and the poll-sync daemon, so proved mainnet bundle proofs are +# imported and applied to the shadow DB (see scripts/30-canary-upgrade.sh). + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)" +REPO_ROOT="$(cd "${SCRIPT_DIR}/../../../.." && pwd)" +LIB_DIR="$(cd "${SCRIPT_DIR}/../../lib" && pwd)" +source "${LIB_DIR}/anvil-utils.sh" + +# ─── Defaults (env-overridable) ────────────────────────────────────────────── +CONFIG_FILE="${CONFIG_FILE:-${PROJECT_ROOT}/configs/mainnet.json}" +# .work is shared by both modes and stays at tests/shadow-testing/.work. +WORK_DIR="${WORK_DIR:-${PROJECT_ROOT}/../.work}" +# Default mirrors sync-mainnet-db.py; override via env if the tunnel differs. +MAINNET_DSN="${MAINNET_DSN:-postgresql://mainnet_infra_team_read_only:AuexDUuaarskbG6tr9CH9gXsJqp4at67mddAbMrt@localhost:15432/mainnet_rollup}" +FOLLOW_RUN_HOURS="${FOLLOW_RUN_HOURS:-48}" +# Fork the L1 state this many hours in the PAST, so the run starts with a +# real backlog (all bundles committed-but-not-finalized at the fork block, +# plus everything mainnet produced since) to catch up before steady-state +# following. 0 = fork at the current tip (old behavior, near-idle start). +FOLLOW_FORK_HOURS_BACK="${FOLLOW_FORK_HOURS_BACK:-5}" +SYNC_POLL_INTERVAL="${SYNC_POLL_INTERVAL:-60}" +SWEEP_INTERVAL="${SWEEP_INTERVAL:-600}" +MONITOR_INTERVAL="${MONITOR_INTERVAL:-3600}" +EXPECTED_PROTOCOL_VERSION="${EXPECTED_PROTOCOL_VERSION:-10}" +# Follow mode runs on GalileoV2 (codec V10) blocks; the relayer must reject +# anything older, so force --min-codec-version 10 regardless of the config +# file's snapshot-mode value (see 06-run-relayer.sh MIN_CODEC override). +MIN_CODEC="${MIN_CODEC:-10}" +GPUS="${GPUS:-0,1}" +# Mainnet rule (AGENTS.md): resetting nextUnfinalizedQueueIndex to 0 is +# sufficient; sync-queue-hashes.py keeps nextCrossDomainMessageIndex current. +NEXT_QUEUE="${NEXT_QUEUE:-0}" +COORD_DIR="${COORD_DIR:-${REPO_ROOT}/coordinator/build/bin}" +DRY_RUN=false +RESET_DB=false +SKIP_VERIFIER=false +IMPORT_PROOFS=false + +while [[ $# -gt 0 ]]; do + case "$1" in + --config) CONFIG_FILE="$2"; shift 2 ;; + --dry-run) DRY_RUN=true; shift ;; + --reset) RESET_DB=true; shift ;; + --skip-verifier) SKIP_VERIFIER=true; shift ;; + --import-proofs) IMPORT_PROOFS=true; SKIP_VERIFIER=true; shift ;; + -h|--help) sed -n '2,28p' "$0"; exit 0 ;; + *) log_error "Unknown option: $1"; exit 1 ;; + esac +done + +mkdir -p "$WORK_DIR" + +# ─── Helpers ───────────────────────────────────────────────────────────────── +pid_alive() { # pidfile -> true if file exists and process alive + local pidfile="$1" pid + [[ -f "$pidfile" ]] || return 1 + pid=$(cat "$pidfile" 2>/dev/null || true) + [[ -n "$pid" ]] && kill -0 "$pid" 2>/dev/null +} + +any_of_our_pids() { # pid -> true if one of our pidfiles references it + local pid="$1" pf + for pf in "$WORK_DIR"/*.pid "$WORK_DIR"/prover-*/prover.pid; do + [[ -f "$pf" ]] || continue + [[ "$(cat "$pf" 2>/dev/null)" == "$pid" ]] && return 0 + done + return 1 +} + +check_port_free() { # port name -> error if occupied by a process we don't track + local port="$1" name="$2" pid + pid=$(lsof -ti :"$port" 2>/dev/null | head -1 || true) + if [[ -n "$pid" ]]; then + if any_of_our_pids "$pid"; then + log_info " port $port ($name): held by tracked pid $pid (will skip restart)" + elif $DRY_RUN; then + log_warn " port $port ($name): held by untracked pid $pid (would abort a real run)" + else + log_error " port $port ($name): held by untracked pid $pid ($(tr '\0' ' ' < /proc/$pid/cmdline 2>/dev/null | cut -c1-80))" + log_error " Stop it first (scripts/11-follow-stop.sh, or kill manually)." + exit 1 + fi + else + log_ok " port $port ($name): free" + fi +} + +run_step() { # in dry-run, print instead of executing + if $DRY_RUN; then + log_info "[dry-run] $*" + else + "$@" + fi +} + +# ─── Load config ───────────────────────────────────────────────────────────── +[[ -f "$CONFIG_FILE" ]] || { log_error "Config not found: $CONFIG_FILE"; exit 1; } +CONFIG_FILE="$(cd "$(dirname "$CONFIG_FILE")" && pwd)/$(basename "$CONFIG_FILE")" + +FORK_URL=$(jq -r '.fork.url' "$CONFIG_FILE") +ANVIL_RPC=$(jq -r '.fork.anvil_rpc' "$CONFIG_FILE") +SHADOW_DSN=$(jq -r '.db.dsn' "$CONFIG_FILE") +SCROLL_CHAIN=$(jq -r '.contracts.scroll_chain' "$CONFIG_FILE") +L1_MSG_QUEUE=$(jq -r '.contracts.l1_message_queue_v2' "$CONFIG_FILE") +ROLLUP_VERIFIER=$(jq -r '.contracts.rollup_verifier' "$CONFIG_FILE") +OWNER=$(jq -r '.contracts.owner' "$CONFIG_FILE") +PROVER_EOA=$(jq -r '.accounts.prover_eoa' "$CONFIG_FILE") +COMMIT_EOA=$(jq -r '.accounts.commit_eoa' "$CONFIG_FILE") +GENESIS=$(jq -r '.genesis' "$CONFIG_FILE") +[[ "$GENESIS" = /* ]] || GENESIS="${REPO_ROOT}/${GENESIS}" +CONFIG_NAME=$(basename "$CONFIG_FILE" .json) + +# ─── a. Sanity checks ──────────────────────────────────────────────────────── +log_info "=== a. Sanity checks ===" +require_cmd jq; require_cmd cast; require_cmd psql; require_cmd python3 +require_cmd forge; require_cmd anvil; require_cmd lsof + +# Alchemy key must be real, not a placeholder/demo +if [[ "$FORK_URL" == *demo* || "$FORK_URL" == *"<"* || "$FORK_URL" == *YOUR* ]]; then + log_error "fork.url in $CONFIG_FILE has no real API key: $FORK_URL" + exit 1 +fi +log_ok " fork.url key present" + +log_info " Checking shadow DB ($SHADOW_DSN) ..." +psql "$SHADOW_DSN" -Atq -c "SELECT 1" >/dev/null +log_ok " shadow DB reachable" + +# Attribute every write in the postgres server log (aids debugging "ghost" +# status writes — see TROUBLESHOOTING Trap 27 tail). ALTER SYSTEM persists in +# postgresql.auto.conf inside the data volume, so re-assert it on every +# bring-up: it is silently lost whenever the postgres container/volume is +# recreated. +if ! $DRY_RUN; then + psql "$SHADOW_DSN" -Atq -c "ALTER SYSTEM SET log_statement = 'mod';" >/dev/null \ + && psql "$SHADOW_DSN" -Atq -c "SELECT pg_reload_conf();" >/dev/null \ + && log_ok " postgres log_statement='mod' asserted (writes visible in the postgres server log)" \ + || log_warn " failed to set log_statement='mod' (non-fatal)" +fi + +log_info " Checking mainnet read replica ..." +timeout 15 psql "$MAINNET_DSN" -Atq -c "SELECT 1" >/dev/null \ + || { log_error "mainnet DSN unreachable: $MAINNET_DSN (is the RDS tunnel up?)"; exit 1; } +log_ok " mainnet DSN reachable" + +check_port_free 8390 coordinator-api +check_port_free 8391 coordinator-cron +check_port_free 18545 anvil + +# ─── b. Baseline DB sync ───────────────────────────────────────────────────── +# Window = everything NOT finalized at the fork block, up to the mainnet tip: +# L1 finalization is sequential (each finalize tx chains prevBatchHash), so the +# shadow must prove and finalize every committed-but-not-finalized bundle +# starting from the fork's lastFinalizedBatchIndex. With FOLLOW_FORK_HOURS_BACK +# > 0 this window covers the fork-back backlog PLUS everything mainnet produced +# between the fork block and now — that backlog is the run's catch-up phase. +# Anything older is already finalized on the fork and is copied only as a +# parent reference (marked done post-baseline). +# +# Resolve the fork block FIRST (rather than passing "latest") so that (a) the +# point is logged and reproducible, and (b) lastFinalized/lastCommitted below +# are read AT the fork block, not at the tip — with a fork-back hours this +# difference is exactly the backlog size. 300 blocks/hour = 12s L1 block time. +log_info "=== b. Baseline DB sync ===" +LATEST_BLOCK=$(cast block-number --rpc-url "$FORK_URL") +if [[ "$FOLLOW_FORK_HOURS_BACK" -gt 0 ]]; then + FORK_BLOCK_NUMBER=$((LATEST_BLOCK - FOLLOW_FORK_HOURS_BACK * 300)) +else + FORK_BLOCK_NUMBER=$LATEST_BLOCK +fi +log_info " fork block: $FORK_BLOCK_NUMBER (latest $LATEST_BLOCK, ${FOLLOW_FORK_HOURS_BACK}h back)" +LAST_FINALIZED=$(cast call "$SCROLL_CHAIN" "lastFinalizedBatchIndex()(uint256)" --rpc-url "$FORK_URL" --block "$FORK_BLOCK_NUMBER" | awk '{print $1}') +MAINNET_TIP=$(psql "$MAINNET_DSN" -Atq -c "SELECT MAX(index) FROM batch" | tr -d ' ') +MAINNET_BUNDLE_TIP=$(psql "$MAINNET_DSN" -Atq -c "SELECT MAX(index) FROM bundle" | tr -d ' ') +BASELINE_START=$((LAST_FINALIZED - 1)) +log_info " lastFinalizedBatchIndex@fork: $LAST_FINALIZED; mainnet batch tip: $MAINNET_TIP" +log_info " baseline window: ${BASELINE_START}..${MAINNET_TIP} ($((MAINNET_TIP - BASELINE_START)) batches = backlog + finalization lag)" +if $RESET_DB; then + # --reset: wipe task tables so the DB contains ONLY the finalization-lag + # window. Without this, stale rows from earlier runs/imports (thousands of + # pending historical batches) are seen by the coordinator as work. + # + # CRITICAL (Trap 26): any component that writes task tables MUST be stopped + # before the TRUNCATE. A relayer left running sees l2_block empty and its + # l2 watcher starts a full L2 genesis crawl (block 1 → tip, days of RPC + # calls, tens of GB of junk rows); an orphaned poll sync bulk-copies all + # mainnet history (Trap 25). A full stop also resets this script's + # idempotent pidfile checks, so every component is restarted fresh below. + log_warn " --reset: stopping all components before truncate" + if ! $DRY_RUN; then + bash "${SCRIPT_DIR}/11-follow-stop.sh" || log_warn " 11-follow-stop returned non-zero (continuing)" + fi + log_warn " --reset: truncating chunk/batch/bundle/l2_block/l1_message/pending_transaction" + if ! $DRY_RUN; then + psql "$SHADOW_DSN" -Atq --set ON_ERROR_STOP=1 -c "TRUNCATE chunk, batch, bundle, l2_block, l1_message" >/dev/null \ + || { log_error "TRUNCATE failed — aborting before baseline"; exit 1; } + # Trap 7/27: pending_transaction rows are not chain/fork-scoped. Stale + # rows from a previous run poison the relayer sender's nonce + # (initializeNonce = max(db_max+1, chain_nonce)) and can replay old + # calldata onto the fresh fork. Wipe them on every reset. + psql "$SHADOW_DSN" -Atq --set ON_ERROR_STOP=1 -c "TRUNCATE pending_transaction" >/dev/null \ + || { log_error "TRUNCATE pending_transaction failed — aborting"; exit 1; } + # Trap 21: wipe prover-local proof caches; they hold proofs from the + # previous run/circuit version and get replayed as VData mismatches. + rm -rf "${WORK_DIR}"/prover-*/db + # Remove stale state from the previous fork too: 01/03 will re-create it. + # follow-run.env carries the PREVIOUS run's report window (step j + # preserves SHADOW_REPORT_START on re-entry) — drop it on --reset so + # the new run gets a fresh report start time. + rm -f "${WORK_DIR}/anvil-${CONFIG_NAME}.state.json" "${WORK_DIR}/verifier.env" "${WORK_DIR}/follow-run.env" + # Trap 39: canary proof-import state must not survive a reset either — + # a stale canary.env boundary silently caps which proofs get applied, + # and a stale import cursor strands the quarantine table out of sync + # with the truncated bundle table. + rm -f "${WORK_DIR}/canary.env" "${WORK_DIR}/proof-import.cursor" + psql "$SHADOW_DSN" -Atq -c "DROP TABLE IF EXISTS remote_bundle_proof" >/dev/null || true + fi +fi +export MAINNET_DSN +if $IMPORT_PROOFS; then + # Canary Phase A: also import proved mainnet bundle proofs into the + # quarantine table and apply them (boundary = +inf until 30-canary-upgrade). + run_step env SYNC_PROOFS=1 python3 "${SCRIPT_DIR}/sync-mainnet-db.py" --init-from-batch "$BASELINE_START" +else + run_step python3 "${SCRIPT_DIR}/sync-mainnet-db.py" --init-from-batch "$BASELINE_START" +fi +# Boundary rows (<= lastFinalized) are already finalized on the fork: mark +# them done so the coordinator never wastes work proving them. Their proof +# columns stay NULL — safe, they are only referenced via row fields +# (parent state root / hash), never by proof bytes. +# Rows ABOVE the boundary may carry stale rollup_status from a previous run +# on an older fork (finalized there, but not on this fresh fork): reset them +# so the relayer re-commits/re-finalizes them in chain order. Proofs already +# generated stay valid (proof content depends on L2 data, not L1 state). +if ! $DRY_RUN; then + MISC_RAW=$(cast call "$SCROLL_CHAIN" 0x06582acb --rpc-url "$FORK_URL" --block "$FORK_BLOCK_NUMBER") + FORK_COMMITTED=$((16#${MISC_RAW:2:64})) + log_info " fork lastCommittedBatchIndex: $FORK_COMMITTED" + psql "$SHADOW_DSN" -Atq -c " + UPDATE batch SET rollup_status = 5, proving_status = 4 + WHERE index <= ${LAST_FINALIZED} AND (rollup_status <> 5 OR proving_status <> 4); + UPDATE bundle SET rollup_status = 5, proving_status = 4 + WHERE end_batch_index <= ${LAST_FINALIZED} AND (rollup_status <> 5 OR proving_status <> 4); + UPDATE chunk SET proving_status = 4 FROM batch b + WHERE chunk.batch_hash = b.hash AND b.index <= ${LAST_FINALIZED} AND chunk.proving_status <> 4; + UPDATE batch SET rollup_status = 3, finalize_tx_hash = NULL, finalized_at = NULL + WHERE index > ${LAST_FINALIZED} AND index <= ${FORK_COMMITTED} AND rollup_status <> 3; + UPDATE batch SET rollup_status = 1, commit_tx_hash = NULL, committed_at = NULL, finalize_tx_hash = NULL, finalized_at = NULL + WHERE index > ${FORK_COMMITTED} AND rollup_status <> 1; + UPDATE bundle SET rollup_status = 1, finalize_tx_hash = NULL, finalized_at = NULL + WHERE end_batch_index > ${LAST_FINALIZED} AND rollup_status <> 1; + " >/dev/null + log_ok " rollup_status aligned to fork boundaries (finalized<=${LAST_FINALIZED}, committed<=${FORK_COMMITTED})" +fi + +# ─── c. Anvil fork at the chosen block ─────────────────────────────────────── +log_info "=== c. Anvil fork setup ===" +# FORK_BLOCK_NUMBER was resolved in step b (tip, or tip - FOLLOW_FORK_HOURS_BACK +# * 300). lastFinalized was read at that same block there. +log_info " fork block: $FORK_BLOCK_NUMBER" +log_info " lastFinalized: $LAST_FINALIZED (read from mainnet at fork block)" +log_info " nextQueueIndex: $NEXT_QUEUE" + +STATE_FILE="${WORK_DIR}/anvil-${CONFIG_NAME}.state.json" +if [[ -f "$STATE_FILE" ]]; then + # Anvil --state LOADS an existing file; a stale state file would silently + # resurrect the previous fork. Back it up so this fork starts fresh. + STATE_BAK="${STATE_FILE}.bak.$(date +%Y%m%d%H%M%S)" + log_warn " backing up existing state file -> $STATE_BAK" + run_step mv "$STATE_FILE" "$STATE_BAK" +fi + +ANVIL_FRESH=false +if pid_alive "${WORK_DIR}/anvil.pid"; then + log_info " Anvil already running (pid $(cat "${WORK_DIR}/anvil.pid")), skipping" +else + ANVIL_FRESH=true + # --deployed-verifier "" : 03-deploy-verifier.sh deploys a fresh wrapper + # below; the copy-from-old-fork fallback in 01 cannot work on a new fork. + run_step "${LIB_DIR}/01-setup-anvil.sh" \ + --fork-url "$FORK_URL" \ + --fork-block "$FORK_BLOCK_NUMBER" \ + --anvil-rpc "$ANVIL_RPC" \ + --state-file "$STATE_FILE" \ + --last-finalized "$LAST_FINALIZED" \ + --next-queue "$NEXT_QUEUE" \ + --deployed-verifier "" \ + ${SKIP_VERIFIER:+--skip-verifier} \ + --prover-eoa "$PROVER_EOA" \ + --commit-eoa "$COMMIT_EOA" \ + --owner "$OWNER" \ + --scroll-chain "$SCROLL_CHAIN" \ + --l1-msg-queue "$L1_MSG_QUEUE" \ + --rollup-verifier "$ROLLUP_VERIFIER" \ + --db-dsn "$SHADOW_DSN" +fi + +# ─── d. Deploy verifier wrapper ────────────────────────────────────────────── +# Full forge redeploy (not anvil_setCode) because anvil_setCode preserves the +# old wrapper's immutables (digest1/digest2/protocolVersion) — see AGENTS.md +# "anvil_setCode Does NOT Reset Immutables". +# EOA funding (owner/prover/commit) is already handled by 01-setup-anvil.sh +# step 7, so nothing extra is needed here. +log_info "=== d. Deploy verifier wrapper ===" +if $SKIP_VERIFIER; then + # Phase-1 ("old stack" = current production release) of the mid-run upgrade + # test: the forked MVRV already routes GalileoV2 batches to the production + # verifier, whose digests match production circuits — nothing to deploy. + # Assert routing is sane, then record it in verifier.env so the monitor and + # re-fork.sh have a wrapper address to reference. 20-upgrade.sh later + # registers the NEW wrapper via the genuine updateVerifier path. + if ! $DRY_RUN; then + # NOTE: every cast here needs `|| true` — a failing cast inside $( ) + # would otherwise kill the script silently under set -e/pipefail. + PROD_WRAPPER=$(cast call "$ROLLUP_VERIFIER" \ + "getVerifier(uint256,uint256)(address)" 10 "$((LAST_FINALIZED + 1))" \ + --rpc-url "$ANVIL_RPC" 2>/dev/null | tr -d ' ' || true) + if [[ -z "$PROD_WRAPPER" || "$PROD_WRAPPER" == "0x0000000000000000000000000000000000000000" ]]; then + log_error "--skip-verifier: MVRV routes batch $((LAST_FINALIZED + 1)) to no verifier —" + log_error "the forked production MVRV state cannot verify phase-1 proofs. Deploy a" + log_error "wrapper instead (drop --skip-verifier)." + exit 1 + fi + PROD_CODE=$(cast code "$PROD_WRAPPER" --rpc-url "$ANVIL_RPC" 2>/dev/null || echo "0x") + if [[ -z "$PROD_CODE" || "$PROD_CODE" == "0x" ]]; then + log_error "--skip-verifier: routed wrapper $PROD_WRAPPER has NO CODE on the fork —" + log_error "it cannot verify anything. (A previous 01-setup-anvil fallback may have" + log_error "registered a codeless address; re-fork.)" + exit 1 + fi + PROD_PV=$(cast call "$PROD_WRAPPER" "protocolVersion()(uint256)" --rpc-url "$ANVIL_RPC" 2>/dev/null | awk '{print $1}' || true) + if [[ "$PROD_PV" != "$EXPECTED_PROTOCOL_VERSION" ]]; then + log_error "--skip-verifier: production wrapper $PROD_WRAPPER has protocolVersion=${PROD_PV:-unknown}," + log_error "expected $EXPECTED_PROTOCOL_VERSION — it cannot verify phase-1 proofs." + exit 1 + fi + log_ok " using production verifier $PROD_WRAPPER (protocolVersion=$PROD_PV) from the forked MVRV" + cat > "${WORK_DIR}/verifier.env" </dev/null + cast rpc anvil_setBalance "$FINALIZE_SENDER" 0x56bc75e2d63100000 --rpc-url "$ANVIL_RPC" >/dev/null + if [[ "$(cast call "$SCROLL_CHAIN" "isSequencer(address)(bool)" "$COMMIT_SENDER" --rpc-url "$ANVIL_RPC" 2>/dev/null)" != "true" ]]; then + log_warn " authorizing $COMMIT_SENDER as sequencer on the fork" + cast rpc anvil_impersonateAccount "$OWNER" --rpc-url "$ANVIL_RPC" >/dev/null + cast send --gas-limit 5000000 "$SCROLL_CHAIN" "addSequencer(address)" "$COMMIT_SENDER" \ + --from "$OWNER" --rpc-url "$ANVIL_RPC" --unlocked >/dev/null \ + || { cast rpc anvil_stopImpersonatingAccount "$OWNER" --rpc-url "$ANVIL_RPC" >/dev/null; log_error "addSequencer failed"; exit 1; } + cast rpc anvil_stopImpersonatingAccount "$OWNER" --rpc-url "$ANVIL_RPC" >/dev/null + fi + # isProver gates finalizeBundlePostEuclidV2 (ErrorCallerIsNotProver + # 0x7b263b17). An Anvil state restore from a pre-addProver backup silently + # drops it, and a failed finalize then strands the bundle at + # rollup_status=7 (not retried). Re-ensure it here, idempotently. + if [[ "$(cast call "$SCROLL_CHAIN" "isProver(address)(bool)" "$FINALIZE_SENDER" --rpc-url "$ANVIL_RPC" 2>/dev/null)" != "true" ]]; then + log_warn " authorizing $FINALIZE_SENDER as prover on the fork" + cast rpc anvil_impersonateAccount "$OWNER" --rpc-url "$ANVIL_RPC" >/dev/null + cast send --gas-limit 5000000 "$SCROLL_CHAIN" "addProver(address)" "$FINALIZE_SENDER" \ + --from "$OWNER" --rpc-url "$ANVIL_RPC" --unlocked >/dev/null \ + || { cast rpc anvil_stopImpersonatingAccount "$OWNER" --rpc-url "$ANVIL_RPC" >/dev/null; log_error "addProver failed"; exit 1; } + cast rpc anvil_stopImpersonatingAccount "$OWNER" --rpc-url "$ANVIL_RPC" >/dev/null + fi + log_ok " relayer EOAs funded (100 ETH), commit sender is sequencer, finalize sender is prover" +fi +if pid_alive "${WORK_DIR}/relayer-${CONFIG_NAME}.pid"; then + log_info " relayer already running (pid $(cat "${WORK_DIR}/relayer-${CONFIG_NAME}.pid")), skipping" +else + run_step env MIN_CODEC="$MIN_CODEC" "${LIB_DIR}/06-run-relayer.sh" --config "$CONFIG_NAME" +fi + +# ─── i. Background daemon loops ────────────────────────────────────────────── +log_info "=== i. Daemon loops ===" +start_loop() { # name interval logfile command... + local name="$1" interval="$2" logfile="$3"; shift 3 + local pidfile="${WORK_DIR}/${name}.pid" + if pid_alive "$pidfile"; then + log_info " ${name} loop already running (pid $(cat "$pidfile")), skipping" + return 0 + fi + log_info " starting ${name} loop (every ${interval}s, log: ${logfile})" + if ! $DRY_RUN; then + # Shell-escape each arg into a single command string. (Naive \"$@\" + # inside double quotes collapses all args into ONE quoted word.) + local cmd + cmd=$(printf '%q ' "$@") + # Detached self-restarting loop; pidfile tracks the loop shell. + setsid nohup bash -c "while true; do ${cmd} >>'${logfile}' 2>&1 || true; sleep ${interval}; done" \ + >/dev/null 2>&1 & + echo $! > "$pidfile" + fi +} + +if $IMPORT_PROOFS; then + # Canary Phase A: poll sync also imports proved mainnet bundle proofs. + start_loop sync-mainnet-db "$SYNC_POLL_INTERVAL" "${WORK_DIR}/sync-mainnet-db.log" \ + env SYNC_PROOFS=1 python3 "${SCRIPT_DIR}/sync-mainnet-db.py" --poll-interval "$SYNC_POLL_INTERVAL" +else + start_loop sync-mainnet-db "$SYNC_POLL_INTERVAL" "${WORK_DIR}/sync-mainnet-db.log" \ + python3 "${SCRIPT_DIR}/sync-mainnet-db.py" --poll-interval "$SYNC_POLL_INTERVAL" +fi +# Sweeper resets proving_status AND total_attempts (Trap 22/23 starvation traps). +start_loop sweeper "$SWEEP_INTERVAL" "${WORK_DIR}/sweeper.log" \ + bash "${SCRIPT_DIR}/sweep-stale-proving.sh" +# monitor-catchup.py appends to .work/catchup-metrics.log itself. +start_loop monitor "$MONITOR_INTERVAL" "${WORK_DIR}/monitor.log" \ + python3 "${SCRIPT_DIR}/monitor-catchup.py" + +# ─── j. Run metadata + summary ─────────────────────────────────────────────── +log_info "=== j. Run metadata ===" +FOLLOW_ENV="${WORK_DIR}/follow-run.env" +if ! $DRY_RUN; then + # Preserve an existing SHADOW_REPORT_START when components were skipped + # (i.e. this is a re-entry into an already-running run, not a fresh run). + EXISTING_START="" + [[ -f "$FOLLOW_ENV" ]] && EXISTING_START=$(grep '^SHADOW_REPORT_START=' "$FOLLOW_ENV" | cut -d= -f2- || true) + REPORT_START="${EXISTING_START:-$(date -u +%Y-%m-%dT%H:%M:%S%z)}" + cat > "$FOLLOW_ENV" <> "$FOLLOW_ENV" + fi + log_ok " wrote $FOLLOW_ENV (SHADOW_REPORT_START=$REPORT_START, FOLLOW_RUN_HOURS=$FOLLOW_RUN_HOURS)" +fi + +echo "" +log_ok "Follow-mode stack is up. Running components:" +for comp in anvil coordinator-api coordinator-cron relayer-${CONFIG_NAME} sync-mainnet-db sweeper monitor; do + pf="${WORK_DIR}/${comp}.pid" + if pid_alive "$pf"; then echo " - $comp (pid $(cat "$pf"))"; fi +done +for gpu in "${GPU_ARRAY[@]}"; do + pf="${WORK_DIR}/prover-${gpu}/prover.pid" + if pid_alive "$pf"; then echo " - prover-gpu${gpu} (pid $(cat "$pf"))"; fi +done +echo "" +echo "Useful commands:" +echo " make follow-status # latest monitor snapshot + finalize lag" +echo " make follow-report # throughput report for this run" +echo " make re-fork # re-fork Anvil at latest block (recovery)" +echo " make follow-stop # stop everything (keeps postgres)" +echo " scripts/11-follow-stop.sh --keep-anvil # stop all but Anvil+DB (run from follow/)" diff --git a/tests/shadow-testing/follow/scripts/11-follow-stop.sh b/tests/shadow-testing/follow/scripts/11-follow-stop.sh new file mode 100755 index 0000000000..270bce27f1 --- /dev/null +++ b/tests/shadow-testing/follow/scripts/11-follow-stop.sh @@ -0,0 +1,154 @@ +#!/usr/bin/env bash +# 11-follow-stop.sh — stop everything started by 10-follow-up.sh. +# +# Stops: daemon loops (sync/sweeper/monitor), relayer, provers, +# coordinator_cron, coordinator_api, and Anvil (unless --keep-anvil). +# Postgres (shadow DB) is never touched. Cleans up pidfiles afterwards. +# +# Usage: ./11-follow-stop.sh [--keep-anvil] [--config configs/mainnet.json] + +set -uo pipefail # no -e: a single dead pidfile must not abort the cleanup + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)" +source "${SCRIPT_DIR}/../../lib/anvil-utils.sh" +# anvil-utils.sh re-enables -e (set -euo pipefail at its top) — undo that: +# this script's contract is best-effort cleanup that never aborts midway. +set +e + +CONFIG_FILE="${CONFIG_FILE:-${PROJECT_ROOT}/configs/mainnet.json}" +# .work is shared by both modes and stays at tests/shadow-testing/.work. +WORK_DIR="${WORK_DIR:-${PROJECT_ROOT}/../.work}" +KEEP_ANVIL=false + +while [[ $# -gt 0 ]]; do + case "$1" in + --keep-anvil) KEEP_ANVIL=true; shift ;; + --config) CONFIG_FILE="$2"; shift 2 ;; + -h|--help) sed -n '2,9p' "$0"; exit 0 ;; + *) log_error "Unknown option: $1"; exit 1 ;; + esac +done + +[[ -f "$CONFIG_FILE" ]] && CONFIG_NAME=$(basename "$CONFIG_FILE" .json) || CONFIG_NAME="mainnet" + +STOPPED=() + +# stop_pid