From 445e5e6dc37312c12be054c8c7b8b7f3e554f59b Mon Sep 17 00:00:00 2001 From: "Chris T." Date: Thu, 19 Dec 2024 13:02:42 -0800 Subject: [PATCH] refactor: sdk v2 (#1875) Co-authored-by: Tamir Hemo Co-authored-by: Tej Qu Nair Co-authored-by: Kevin Jue Co-authored-by: John Guibas Co-authored-by: erabinov Co-authored-by: Eugene Rabinovich Co-authored-by: Yuwen Zhang Co-authored-by: N --- .gitignore | 7 +- Cargo.lock | 306 +- Cargo.toml | 50 +- book/docs/generating-proofs/proof-types.md | 18 +- .../generating-proofs/prover-network/usage.md | 2 +- .../docs/verification/onchain/solidity-sdk.md | 2 +- book/docs/writing-programs/patched-crates.md | 12 + .../writing-programs/proof-aggregation.md | 2 +- book/sp1.png | Bin 0 -> 66629 bytes book/verification/off-chain-verification.md | 49 + .../onchain/contract-addresses.md | 101 + book/verification/onchain/getting-started.md | 33 + book/verification/onchain/solidity-sdk.md | 122 + crates/cli/src/commands/install_toolchain.rs | 13 +- crates/cli/src/commands/vkey.rs | 2 +- crates/core/executor/src/hook.rs | 94 +- crates/core/executor/src/profiler.rs | 33 +- .../precompiles/edwards/decompress.rs | 3 +- .../src/operations/field/field_sqrt.rs | 6 +- .../precompiles/edwards/ed_decompress.rs | 4 +- crates/cuda/src/lib.rs | 6 +- crates/curves/Cargo.toml | 1 - crates/curves/src/edwards/ed25519.rs | 16 +- crates/curves/src/lib.rs | 34 +- crates/eval/src/main.rs | 4 +- crates/perf/Cargo.toml | 2 +- crates/perf/src/main.rs | 40 +- crates/prover/scripts/build_compress_vks.rs | 4 +- crates/prover/scripts/fibonacci_groth16.rs | 4 +- crates/prover/scripts/fibonacci_sweep.rs | 4 +- crates/prover/scripts/tendermint_sweep.rs | 4 +- crates/prover/src/components.rs | 4 +- crates/prover/src/lib.rs | 92 +- crates/recursion/gnark-ffi/src/proof.rs | 3 - crates/sdk/Cargo.toml | 12 +- crates/sdk/src/action.rs | 232 - crates/sdk/src/artifacts.rs | 47 +- crates/sdk/src/client.rs | 136 + crates/sdk/src/cpu/builder.rs | 31 + crates/sdk/src/cpu/execute.rs | 138 + crates/sdk/src/cpu/mod.rs | 342 ++ crates/sdk/src/cpu/prove.rs | 296 ++ crates/sdk/src/cuda/builder.rs | 31 + crates/sdk/src/cuda/mod.rs | 172 + crates/sdk/src/cuda/prove.rs | 178 + crates/sdk/src/env/mod.rs | 192 + crates/sdk/src/env/prove.rs | 166 + crates/sdk/src/install.rs | 26 +- crates/sdk/src/lib.rs | 504 +- crates/sdk/src/network-v2/client.rs | 280 -- crates/sdk/src/network-v2/mod.rs | 20 - crates/sdk/src/network-v2/proto/mod.rs | 2 - crates/sdk/src/network-v2/proto/network.rs | 3932 --------------- crates/sdk/src/network-v2/prover.rs | 330 -- crates/sdk/src/network/auth.rs | 142 - crates/sdk/src/network/builder.rs | 94 + crates/sdk/src/network/client.rs | 449 +- crates/sdk/src/network/mod.rs | 20 +- .../{network-v2 => network}/proto/artifact.rs | 12 +- crates/sdk/src/network/proto/mod.rs | 1 + crates/sdk/src/network/proto/network.rs | 4335 ++++++++++++++--- crates/sdk/src/network/prove.rs | 301 ++ crates/sdk/src/network/prover.rs | 452 +- .../{network-v2 => network}/sign_message.rs | 5 +- .../{network-v2/json.rs => network/utils.rs} | 25 +- crates/sdk/src/proof.rs | 106 +- crates/sdk/src/prover.rs | 164 + crates/sdk/src/provers/cpu.rs | 131 - crates/sdk/src/provers/cuda.rs | 125 - crates/sdk/src/provers/mock.rs | 170 - crates/sdk/src/provers/mod.rs | 175 - crates/sdk/src/utils.rs | 33 + crates/test-artifacts/programs/Cargo.lock | 67 +- crates/verifier/Cargo.toml | 12 +- crates/verifier/src/error.rs | 2 +- crates/verifier/src/groth16/converter.rs | 2 +- crates/verifier/src/groth16/error.rs | 2 +- crates/verifier/src/groth16/mod.rs | 55 +- crates/verifier/src/groth16/verify.rs | 4 +- crates/verifier/src/lib.rs | 7 +- crates/verifier/src/plonk/converter.rs | 11 +- crates/verifier/src/plonk/error.rs | 2 +- crates/verifier/src/plonk/mod.rs | 46 +- crates/verifier/src/plonk/verify.rs | 4 +- crates/verifier/src/tests.rs | 37 +- crates/zkvm/entrypoint/Cargo.toml | 2 +- crates/zkvm/lib/src/io.rs | 6 + examples/Cargo.lock | 994 ++-- examples/Cargo.toml | 2 +- examples/aggregation/script/src/main.rs | 2 +- examples/bls12381/script/src/main.rs | 2 +- examples/bn254/script/src/main.rs | 2 +- examples/chess/script/src/main.rs | 2 +- examples/cycle-tracking/script/src/main.rs | 7 +- examples/elf/riscv32im-succinct-zkvm-elf | Bin 0 -> 145784 bytes .../program/elf/riscv32im-succinct-zkvm-elf | Bin 0 -> 105052 bytes examples/fibonacci/script/bin/compressed.rs | 2 +- examples/fibonacci/script/bin/execute.rs | 2 +- .../fibonacci/script/bin/groth16_bn254.rs | 2 +- examples/fibonacci/script/bin/plonk_bn254.rs | 2 +- examples/fibonacci/script/src/main.rs | 2 +- examples/groth16/script/src/main.rs | 4 +- examples/io/script/src/main.rs | 2 +- examples/is-prime/script/src/main.rs | 2 +- examples/json/script/src/main.rs | 2 +- examples/patch-testing/program/src/main.rs | 24 +- examples/patch-testing/script/src/main.rs | 2 +- examples/regex/script/src/main.rs | 2 +- examples/rsa/script/src/main.rs | 2 +- examples/rsp/script/src/main.rs | 2 +- examples/ssz-withdrawals/script/src/main.rs | 2 +- examples/tendermint/script/src/main.rs | 2 +- 112 files changed, 8109 insertions(+), 8101 deletions(-) create mode 100644 book/sp1.png create mode 100644 book/verification/off-chain-verification.md create mode 100644 book/verification/onchain/contract-addresses.md create mode 100644 book/verification/onchain/getting-started.md create mode 100644 book/verification/onchain/solidity-sdk.md delete mode 100644 crates/sdk/src/action.rs create mode 100644 crates/sdk/src/client.rs create mode 100644 crates/sdk/src/cpu/builder.rs create mode 100644 crates/sdk/src/cpu/execute.rs create mode 100644 crates/sdk/src/cpu/mod.rs create mode 100644 crates/sdk/src/cpu/prove.rs create mode 100644 crates/sdk/src/cuda/builder.rs create mode 100644 crates/sdk/src/cuda/mod.rs create mode 100644 crates/sdk/src/cuda/prove.rs create mode 100644 crates/sdk/src/env/mod.rs create mode 100644 crates/sdk/src/env/prove.rs delete mode 100644 crates/sdk/src/network-v2/client.rs delete mode 100644 crates/sdk/src/network-v2/mod.rs delete mode 100644 crates/sdk/src/network-v2/proto/mod.rs delete mode 100644 crates/sdk/src/network-v2/proto/network.rs delete mode 100644 crates/sdk/src/network-v2/prover.rs delete mode 100644 crates/sdk/src/network/auth.rs create mode 100644 crates/sdk/src/network/builder.rs rename crates/sdk/src/{network-v2 => network}/proto/artifact.rs (95%) create mode 100644 crates/sdk/src/network/prove.rs rename crates/sdk/src/{network-v2 => network}/sign_message.rs (94%) rename crates/sdk/src/{network-v2/json.rs => network/utils.rs} (70%) create mode 100644 crates/sdk/src/prover.rs delete mode 100644 crates/sdk/src/provers/cpu.rs delete mode 100644 crates/sdk/src/provers/cuda.rs delete mode 100644 crates/sdk/src/provers/mock.rs delete mode 100644 crates/sdk/src/provers/mod.rs create mode 100644 crates/sdk/src/utils.rs create mode 100755 examples/elf/riscv32im-succinct-zkvm-elf create mode 100755 examples/fibonacci/program/elf/riscv32im-succinct-zkvm-elf diff --git a/.gitignore b/.gitignore index e67ec1ef1b..020a50c25a 100644 --- a/.gitignore +++ b/.gitignore @@ -40,11 +40,12 @@ crates/prover/semaphore-gnark-11 crates/prover/trusted-setup crates/prover/vk -<<<<<<< Updated upstream # Example legacy elf examples/elf -======= + # Example fibonacci groth16 / plonk proofs examples/fibonacci/fibonacci-groth16.bin examples/fibonacci/fibonacci-plonk.bin ->>>>>>> Stashed changes + +# C++ +.vscode/c_cpp_properties.json \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 3ec8df2d2d..103eb41a64 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -188,7 +188,7 @@ dependencies = [ "alloy-sol-types", "serde", "serde_json", - "thiserror 1.0.69", + "thiserror", "tracing", ] @@ -210,7 +210,7 @@ dependencies = [ "async-trait", "auto_impl", "futures-utils-wasm", - "thiserror 1.0.69", + "thiserror", ] [[package]] @@ -317,7 +317,7 @@ dependencies = [ "auto_impl", "elliptic-curve", "k256", - "thiserror 1.0.69", + "thiserror", ] [[package]] @@ -333,7 +333,7 @@ dependencies = [ "async-trait", "k256", "rand 0.8.5", - "thiserror 1.0.69", + "thiserror", ] [[package]] @@ -494,54 +494,6 @@ dependencies = [ "backtrace", ] -[[package]] -name = "ark-bn254" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a22f4561524cd949590d78d7d4c5df8f592430d221f7f3c9497bbafd8972120f" -dependencies = [ - "ark-ec", - "ark-ff 0.4.2", - "ark-std 0.4.0", -] - -[[package]] -name = "ark-crypto-primitives" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3a13b34da09176a8baba701233fdffbaa7c1b1192ce031a3da4e55ce1f1a56" -dependencies = [ - "ark-ec", - "ark-ff 0.4.2", - "ark-relations", - "ark-serialize 0.4.2", - "ark-snark", - "ark-std 0.4.0", - "blake2", - "derivative", - "digest 0.10.7", - "rayon", - "sha2 0.10.8", -] - -[[package]] -name = "ark-ec" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "defd9a439d56ac24968cca0571f598a61bc8c55f71d50a89cda591cb750670ba" -dependencies = [ - "ark-ff 0.4.2", - "ark-poly", - "ark-serialize 0.4.2", - "ark-std 0.4.0", - "derivative", - "hashbrown 0.13.2", - "itertools 0.10.5", - "num-traits", - "rayon", - "zeroize", -] - [[package]] name = "ark-ff" version = "0.3.0" @@ -576,7 +528,6 @@ dependencies = [ "num-bigint 0.4.6", "num-traits", "paste", - "rayon", "rustc_version 0.4.1", "zeroize", ] @@ -626,48 +577,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "ark-groth16" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20ceafa83848c3e390f1cbf124bc3193b3e639b3f02009e0e290809a501b95fc" -dependencies = [ - "ark-crypto-primitives", - "ark-ec", - "ark-ff 0.4.2", - "ark-poly", - "ark-relations", - "ark-serialize 0.4.2", - "ark-std 0.4.0", - "rayon", -] - -[[package]] -name = "ark-poly" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d320bfc44ee185d899ccbadfa8bc31aab923ce1558716e1997a1e74057fe86bf" -dependencies = [ - "ark-ff 0.4.2", - "ark-serialize 0.4.2", - "ark-std 0.4.0", - "derivative", - "hashbrown 0.13.2", - "rayon", -] - -[[package]] -name = "ark-relations" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00796b6efc05a3f48225e59cb6a2cda78881e7c390872d5786aaf112f31fb4f0" -dependencies = [ - "ark-ff 0.4.2", - "ark-std 0.4.0", - "tracing", - "tracing-subscriber 0.2.25", -] - [[package]] name = "ark-serialize" version = "0.3.0" @@ -684,35 +593,11 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" dependencies = [ - "ark-serialize-derive", "ark-std 0.4.0", "digest 0.10.7", "num-bigint 0.4.6", ] -[[package]] -name = "ark-serialize-derive" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae3281bc6d0fd7e549af32b52511e1302185bd688fd3359fa36423346ff682ea" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "ark-snark" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84d3cc6833a335bb8a600241889ead68ee89a3cf8448081fb7694c0fe503da63" -dependencies = [ - "ark-ff 0.4.2", - "ark-relations", - "ark-serialize 0.4.2", - "ark-std 0.4.0", -] - [[package]] name = "ark-std" version = "0.3.0" @@ -731,7 +616,6 @@ checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" dependencies = [ "num-traits", "rand 0.8.5", - "rayon", ] [[package]] @@ -1308,7 +1192,7 @@ dependencies = [ "semver 1.0.23", "serde", "serde_json", - "thiserror 1.0.69", + "thiserror", ] [[package]] @@ -1734,32 +1618,6 @@ dependencies = [ "windows-sys 0.52.0", ] -[[package]] -name = "curve25519-dalek" -version = "4.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" -dependencies = [ - "cfg-if", - "cpufeatures", - "curve25519-dalek-derive", - "fiat-crypto", - "rustc_version 0.4.1", - "subtle", - "zeroize", -] - -[[package]] -name = "curve25519-dalek-derive" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.87", -] - [[package]] name = "darling" version = "0.13.4" @@ -2233,12 +2091,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "fiat-crypto" -version = "0.2.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" - [[package]] name = "fixed-hash" version = "0.8.0" @@ -2653,15 +2505,6 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" -[[package]] -name = "hashbrown" -version = "0.13.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" -dependencies = [ - "ahash", -] - [[package]] name = "hashbrown" version = "0.14.5" @@ -4179,7 +4022,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "879952a81a83930934cbf1786752d6dedc3b1f29e8f8fb2ad1d0a36f377cf442" dependencies = [ "memchr", - "thiserror 1.0.69", + "thiserror", "ucd-trie", ] @@ -4525,7 +4368,7 @@ dependencies = [ "rustc-hash 2.0.0", "rustls 0.23.16", "socket2", - "thiserror 1.0.69", + "thiserror", "tokio", "tracing", ] @@ -4542,7 +4385,7 @@ dependencies = [ "rustc-hash 2.0.0", "rustls 0.23.16", "slab", - "thiserror 1.0.69", + "thiserror", "tinyvec", "tracing", ] @@ -4703,7 +4546,7 @@ checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" dependencies = [ "getrandom 0.2.15", "libredox", - "thiserror 1.0.69", + "thiserror", ] [[package]] @@ -4811,7 +4654,7 @@ dependencies = [ "http 1.1.0", "reqwest", "serde", - "thiserror 1.0.69", + "thiserror", "tower-service", ] @@ -5295,7 +5138,7 @@ checksum = "c7715380eec75f029a4ef7de39a9200e0a63823176b759d055b613f5a87df6a6" dependencies = [ "percent-encoding", "serde", - "thiserror 1.0.69", + "thiserror", ] [[package]] @@ -5541,7 +5384,7 @@ dependencies = [ [[package]] name = "sp1-build" -version = "3.0.0" +version = "3.4.0" dependencies = [ "anyhow", "cargo_metadata", @@ -5552,7 +5395,7 @@ dependencies = [ [[package]] name = "sp1-cli" -version = "3.0.0" +version = "3.4.0" dependencies = [ "anstyle", "anyhow", @@ -5581,7 +5424,7 @@ dependencies = [ [[package]] name = "sp1-core-executor" -version = "3.0.0" +version = "3.4.0" dependencies = [ "bincode", "bytemuck", @@ -5611,7 +5454,7 @@ dependencies = [ "strum", "strum_macros", "test-artifacts", - "thiserror 1.0.69", + "thiserror", "tiny-keccak", "tracing", "typenum", @@ -5620,7 +5463,7 @@ dependencies = [ [[package]] name = "sp1-core-machine" -version = "3.0.0" +version = "3.4.0" dependencies = [ "bincode", "cfg-if", @@ -5659,18 +5502,18 @@ dependencies = [ "strum_macros", "tempfile", "test-artifacts", - "thiserror 1.0.69", + "thiserror", "tiny-keccak", "tracing", "tracing-forest", - "tracing-subscriber 0.3.18", + "tracing-subscriber", "typenum", "web-time", ] [[package]] name = "sp1-cuda" -version = "3.0.0" +version = "3.4.0" dependencies = [ "bincode", "ctrlc", @@ -5688,10 +5531,9 @@ dependencies = [ [[package]] name = "sp1-curves" -version = "3.0.0" +version = "3.4.0" dependencies = [ "cfg-if", - "curve25519-dalek", "dashu", "elliptic-curve", "generic-array 1.1.0", @@ -5711,7 +5553,7 @@ dependencies = [ [[package]] name = "sp1-derive" -version = "3.0.0" +version = "3.4.0" dependencies = [ "quote", "syn 1.0.109", @@ -5719,7 +5561,7 @@ dependencies = [ [[package]] name = "sp1-eval" -version = "3.0.0" +version = "3.4.0" dependencies = [ "anyhow", "bincode", @@ -5737,14 +5579,16 @@ dependencies = [ [[package]] name = "sp1-helper" -version = "3.0.0" +version = "3.4.0" dependencies = [ "sp1-build", ] [[package]] name = "sp1-lib" -version = "3.0.0" +version = "3.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c8744af050832df5ca44fcd63979a83b93ca3010b2d5a5ce2a2b91f7438065c" dependencies = [ "bincode", "serde", @@ -5752,9 +5596,7 @@ dependencies = [ [[package]] name = "sp1-lib" -version = "3.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c8744af050832df5ca44fcd63979a83b93ca3010b2d5a5ce2a2b91f7438065c" +version = "3.4.0" dependencies = [ "bincode", "serde", @@ -5762,7 +5604,7 @@ dependencies = [ [[package]] name = "sp1-perf" -version = "3.0.0" +version = "3.4.0" dependencies = [ "bincode", "clap", @@ -5778,7 +5620,7 @@ dependencies = [ [[package]] name = "sp1-primitives" -version = "3.0.0" +version = "3.4.0" dependencies = [ "bincode", "hex", @@ -5794,7 +5636,7 @@ dependencies = [ [[package]] name = "sp1-prover" -version = "3.0.0" +version = "3.4.0" dependencies = [ "anyhow", "bincode", @@ -5823,15 +5665,15 @@ dependencies = [ "sp1-recursion-gnark-ffi", "sp1-stark", "test-artifacts", - "thiserror 1.0.69", + "thiserror", "tracing", "tracing-appender", - "tracing-subscriber 0.3.18", + "tracing-subscriber", ] [[package]] name = "sp1-recursion-circuit" -version = "3.0.0" +version = "3.4.0" dependencies = [ "ff 0.13.0", "hashbrown 0.14.5", @@ -5868,7 +5710,7 @@ dependencies = [ [[package]] name = "sp1-recursion-compiler" -version = "3.0.0" +version = "3.4.0" dependencies = [ "backtrace", "criterion", @@ -5893,7 +5735,7 @@ dependencies = [ [[package]] name = "sp1-recursion-core" -version = "3.0.0" +version = "3.4.0" dependencies = [ "backtrace", "ff 0.13.0", @@ -5920,7 +5762,7 @@ dependencies = [ "sp1-primitives", "sp1-stark", "static_assertions", - "thiserror 1.0.69", + "thiserror", "tracing", "vec_map", "zkhash", @@ -5928,7 +5770,7 @@ dependencies = [ [[package]] name = "sp1-recursion-derive" -version = "3.0.0" +version = "3.4.0" dependencies = [ "quote", "syn 1.0.109", @@ -5936,7 +5778,7 @@ dependencies = [ [[package]] name = "sp1-recursion-gnark-cli" -version = "3.0.0" +version = "3.4.0" dependencies = [ "bincode", "clap", @@ -5945,7 +5787,7 @@ dependencies = [ [[package]] name = "sp1-recursion-gnark-ffi" -version = "3.0.0" +version = "3.4.0" dependencies = [ "anyhow", "bincode", @@ -5969,7 +5811,7 @@ dependencies = [ [[package]] name = "sp1-sdk" -version = "3.0.0" +version = "3.4.0" dependencies = [ "alloy-primitives", "alloy-signer", @@ -6006,7 +5848,7 @@ dependencies = [ "strum_macros", "tempfile", "test-artifacts", - "thiserror 1.0.69", + "thiserror", "tokio", "tonic", "tracing", @@ -6016,7 +5858,7 @@ dependencies = [ [[package]] name = "sp1-stark" -version = "3.0.0" +version = "3.4.0" dependencies = [ "arrayref", "hashbrown 0.14.5", @@ -6049,13 +5891,8 @@ dependencies = [ [[package]] name = "sp1-verifier" -version = "3.0.0" +version = "3.4.0" dependencies = [ - "ark-bn254", - "ark-ec", - "ark-ff 0.4.2", - "ark-groth16", - "ark-serialize 0.4.2", "hex", "lazy_static", "num-bigint 0.4.6", @@ -6063,12 +5900,12 @@ dependencies = [ "sha2 0.10.8", "sp1-sdk", "substrate-bn-succinct", - "thiserror 2.0.3", + "thiserror-no-std", ] [[package]] name = "sp1-zkvm" -version = "3.0.1" +version = "3.4.0" dependencies = [ "cfg-if", "getrandom 0.2.15", @@ -6078,7 +5915,7 @@ dependencies = [ "p3-field", "rand 0.8.5", "sha2 0.10.8", - "sp1-lib 3.0.0", + "sp1-lib 3.4.0", "sp1-primitives", ] @@ -6397,7 +6234,7 @@ dependencies = [ [[package]] name = "test-artifacts" -version = "3.0.0" +version = "3.4.0" dependencies = [ "sp1-build", ] @@ -6419,16 +6256,7 @@ version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ - "thiserror-impl 1.0.69", -] - -[[package]] -name = "thiserror" -version = "2.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c006c85c7651b3cf2ada4584faa36773bd07bac24acfb39f3c431b36d7e667aa" -dependencies = [ - "thiserror-impl 2.0.3", + "thiserror-impl", ] [[package]] @@ -6443,14 +6271,23 @@ dependencies = [ ] [[package]] -name = "thiserror-impl" -version = "2.0.3" +name = "thiserror-impl-no-std" +version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f077553d607adc1caf65430528a576c757a71ed73944b66ebb58ef2bbd243568" +checksum = "58e6318948b519ba6dc2b442a6d0b904ebfb8d411a3ad3e07843615a72249758" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 1.0.109", +] + +[[package]] +name = "thiserror-no-std" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3ad459d94dd517257cc96add8a43190ee620011bb6e6cdc82dafd97dfafafea" +dependencies = [ + "thiserror-impl-no-std", ] [[package]] @@ -6789,9 +6626,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3566e8ce28cc0a3fe42519fc80e6b4c943cc4c8cef275620eb8dac2d3d4e06cf" dependencies = [ "crossbeam-channel", - "thiserror 1.0.69", + "thiserror", "time 0.3.36", - "tracing-subscriber 0.3.18", + "tracing-subscriber", ] [[package]] @@ -6823,9 +6660,9 @@ checksum = "ee40835db14ddd1e3ba414292272eddde9dad04d3d4b65509656414d1c42592f" dependencies = [ "ansi_term", "smallvec", - "thiserror 1.0.69", + "thiserror", "tracing", - "tracing-subscriber 0.3.18", + "tracing-subscriber", ] [[package]] @@ -6849,15 +6686,6 @@ dependencies = [ "tracing-core", ] -[[package]] -name = "tracing-subscriber" -version = "0.2.25" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e0d2eaa99c3c2e41547cfa109e910a68ea03823cccad4a0525dcbc9b01e8c71" -dependencies = [ - "tracing-core", -] - [[package]] name = "tracing-subscriber" version = "0.3.18" @@ -6896,7 +6724,7 @@ dependencies = [ "log", "rand 0.8.5", "sha1 0.10.6", - "thiserror 1.0.69", + "thiserror", "url", "utf-8", ] @@ -6926,7 +6754,7 @@ dependencies = [ "reqwest", "serde", "serde_json", - "thiserror 1.0.69", + "thiserror", "tokio", "tower 0.5.1", "url", diff --git a/Cargo.toml b/Cargo.toml index 58e56265fc..14885539d9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [workspace.package] -version = "3.0.0" +version = "3.4.0" edition = "2021" license = "MIT OR Apache-2.0" rust-version = "1.79" @@ -30,6 +30,7 @@ members = [ "crates/cuda", "crates/verifier", "crates/stark", + "crates/verifier", "crates/zkvm/*", "crates/test-artifacts", ] @@ -49,31 +50,28 @@ debug-assertions = true [workspace.dependencies] # sp1 -sp1-build = { path = "crates/build", version = "3.0.0" } -sp1-cli = { path = "crates/cli", version = "3.0.0", default-features = false } -sp1-core-machine = { path = "crates/core/machine", version = "3.0.0" } -sp1-core-executor = { path = "crates/core/executor", version = "3.0.0" } -sp1-curves = { path = "crates/curves", version = "3.0.0" } -sp1-derive = { path = "crates/derive", version = "3.0.0" } -sp1-eval = { path = "crates/eval", version = "3.0.0" } -sp1-helper = { path = "crates/helper", version = "3.0.0", default-features = false } -sp1-primitives = { path = "crates/primitives", version = "3.0.0" } -sp1-prover = { path = "crates/prover", version = "3.0.0" } -sp1-recursion-compiler = { path = "crates/recursion/compiler", version = "3.0.0" } -sp1-recursion-core = { path = "crates/recursion/core", version = "3.0.0", default-features = false } -sp1-recursion-derive = { path = "crates/recursion/derive", version = "3.0.0", default-features = false } -sp1-recursion-gnark-ffi = { path = "crates/recursion/gnark-ffi", version = "3.0.0", default-features = false } -sp1-recursion-circuit = { path = "crates/recursion/circuit", version = "3.0.0", default-features = false } -sp1-sdk = { path = "crates/sdk", version = "3.0.0" } -sp1-cuda = { path = "crates/cuda", version = "3.0.0" } -sp1-stark = { path = "crates/stark", version = "3.0.0" } -sp1-lib = { path = "crates/zkvm/lib", version = "3.0.0", default-features = false } -# NOTE: The version in this crate is manually set to 3.0.1 right now. When upgrading SP1 versions, -# make sure to update this crate. -sp1-zkvm = { path = "crates/zkvm/entrypoint", version = "3.0.1", default-features = false } - -# For testing. -test-artifacts = { path = "crates/test-artifacts", version = "3.0.0" } +sp1-build = { path = "crates/build", version = "3.4.0" } +sp1-cli = { path = "crates/cli", version = "3.4.0", default-features = false } +sp1-core-machine = { path = "crates/core/machine", version = "3.4.0" } +sp1-core-executor = { path = "crates/core/executor", version = "3.4.0" } +sp1-curves = { path = "crates/curves", version = "3.4.0" } +sp1-derive = { path = "crates/derive", version = "3.4.0" } +sp1-eval = { path = "crates/eval", version = "3.4.0" } +sp1-helper = { path = "crates/helper", version = "3.4.0", default-features = false } +sp1-primitives = { path = "crates/primitives", version = "3.4.0" } +sp1-prover = { path = "crates/prover", version = "3.4.0" } +sp1-recursion-compiler = { path = "crates/recursion/compiler", version = "3.4.0" } +sp1-recursion-core = { path = "crates/recursion/core", version = "3.4.0", default-features = false } +sp1-recursion-derive = { path = "crates/recursion/derive", version = "3.4.0", default-features = false } +sp1-recursion-gnark-ffi = { path = "crates/recursion/gnark-ffi", version = "3.4.0", default-features = false } +sp1-recursion-circuit = { path = "crates/recursion/circuit", version = "3.4.0", default-features = false } +sp1-sdk = { path = "crates/sdk", version = "3.4.0" } +sp1-cuda = { path = "crates/cuda", version = "3.4.0" } +sp1-stark = { path = "crates/stark", version = "3.4.0" } +sp1-lib = { path = "crates/zkvm/lib", version = "3.4.0", default-features = false } +sp1-zkvm = { path = "crates/zkvm/entrypoint", version = "3.4.0", default-features = false } +sp1-verifier = { path = "crates/verifier", version = "3.4.0" } +test-artifacts = { path = "crates/test-artifacts", version = "3.4.0" } # p3 # p3-air = "0.1.4-succinct" diff --git a/book/docs/generating-proofs/proof-types.md b/book/docs/generating-proofs/proof-types.md index 1e0db699b4..581a751d3c 100644 --- a/book/docs/generating-proofs/proof-types.md +++ b/book/docs/generating-proofs/proof-types.md @@ -11,8 +11,8 @@ For a full list of options, see the following [docs](https://docs.rs/sp1-sdk/lat The default prover mode generates a list of STARK proofs that in aggregate have size proportional to the size of the execution. Use this in settings where you don't care about **verification cost / proof size**. -```rust -let client = ProverClient::new(); +```rust,noplayground +let client = ProverClient::from_env(); client.prove(&pk, stdin).run().unwrap(); ``` @@ -21,19 +21,19 @@ client.prove(&pk, stdin).run().unwrap(); The compressed prover mode generates STARK proofs that have constant size. Use this in settings where you care about **verification cost / proof size**, but not onchain verification. Compressed proofs are also useful because they can be cheaply recursively verified within SP1 itself (see the [proof aggregation](../writing-programs/proof-aggregation.md) section). -```rust -let client = ProverClient::new(); +```rust,noplayground +let client = ProverClient::from_env(); client.prove(&pk, stdin).compressed().run().unwrap(); ``` ## Groth16 (Recommended) -The Groth16 prover mode generates a SNARK proof that is ~260 bytes large and can be verified onchain for around ~270k gas. +The Groth16 prover mode generates a SNARK proof that is ~260 bytes large and can be verified onchain for around ~270k gas. The trusted setup for the Groth16 circuit keys uses the [Aztec Ignition ceremony](https://github.com/AztecProtocol/ignition-verification) + entropy contributions from members of the Succinct team. If you are uncomfortable with the security assumptions of the ceremony, you can use the PLONK proof type instead. -```rust -let client = ProverClient::new(); +```rust,noplayground +let client = ProverClient::from_env(); client.prove(&pk, stdin).groth16().run().unwrap(); ``` @@ -43,7 +43,7 @@ The PLONK prover mode generates a SNARK proof that is ~868 bytes large and can a PLONK does not require a trusted setup and reuses contributions from the Aztec Ignition ceremony. -```rust -let client = ProverClient::new(); +```rust,noplayground +let client = ProverClient::from_env(); client.prove(&pk, stdin).plonk().run().unwrap(); ``` diff --git a/book/docs/generating-proofs/prover-network/usage.md b/book/docs/generating-proofs/prover-network/usage.md index 12ef4ac4e6..388c61efdb 100644 --- a/book/docs/generating-proofs/prover-network/usage.md +++ b/book/docs/generating-proofs/prover-network/usage.md @@ -8,7 +8,7 @@ To use the prover network to generate a proof, you can run your script that uses ```rust // Generate the proof for the given program. -let client = ProverClient::new(); +let client = ProverClient::from_env(); let (pk, vk) = client.setup(ELF); let mut proof = client.prove(&pk, stdin).run().unwrap(); ``` diff --git a/book/docs/verification/onchain/solidity-sdk.md b/book/docs/verification/onchain/solidity-sdk.md index 822ab620b9..93a241ed96 100644 --- a/book/docs/verification/onchain/solidity-sdk.md +++ b/book/docs/verification/onchain/solidity-sdk.md @@ -81,7 +81,7 @@ fn main() { sp1_sdk::utils::setup_logger(); // Setup the prover client. - let client = ProverClient::new(); + let client = ProverClient::from_env(); // Setup the program. let (_, vk) = client.setup(FIBONACCI_ELF); diff --git a/book/docs/writing-programs/patched-crates.md b/book/docs/writing-programs/patched-crates.md index 8b250e5c5c..0ebda21693 100644 --- a/book/docs/writing-programs/patched-crates.md +++ b/book/docs/writing-programs/patched-crates.md @@ -44,6 +44,18 @@ secp256k1 = { git = "https://github.com/sp1-patches/rust-secp256k1", tag = "secp substrate-bn = { git = "https://github.com/sp1-patches/bn", tag = "substrate_bn-v0.6.0-patch-v1" } bls12_381 = { git = "https://github.com/sp1-patches/bls12_381", tag = "bls12_381-v0.8.0-patch-v1" } +# For sp1 versions >= 3.4.0 +curve25519-dalek = { git = "https://github.com/sp1-patches/curve25519-dalek", tag = "patch-v4.1.3-v3.4.0" } +# For sp1 versions < 3.4.0 +curve25519-dalek = { git = "https://github.com/sp1-patches/curve25519-dalek", tag = "curve25519_dalek-v4.1.3-patch-v1" } +curve25519-dalek-ng = { git = "https://github.com/sp1-patches/curve25519-dalek-ng", tag = "curve25519_dalek_ng-v4.1.1-patch-v1" } +ed25519-consensus = { git = "https://github.com/sp1-patches/ed25519-consensus", tag = "ed25519_consensus-v2.1.0-patch-v1" } +# For sp1 versions >= 3.3.0 +ecdsa-core = { git = "https://github.com/sp1-patches/signatures", package = "ecdsa", tag = "ecdsa-v0.16.9-patch-v3.3.0" } +secp256k1 = { git = "https://github.com/sp1-patches/rust-secp256k1", tag = "secp256k1-v0.29.0-patch-v3.3.0" } +# For sp1 versions < 3.3.0 +ecdsa-core = { git = "https://github.com/sp1-patches/signatures", package = "ecdsa", tag = "ecdsa-v0.16.9-patch-v1" } +secp256k1 = { git = "https://github.com/sp1-patches/rust-secp256k1", tag = "secp256k1-v0.29.0-patch-v1" } ``` If you are patching a crate from Github instead of from crates.io, you need to specify the diff --git a/book/docs/writing-programs/proof-aggregation.md b/book/docs/writing-programs/proof-aggregation.md index dc13d6e42c..a6780af1f6 100644 --- a/book/docs/writing-programs/proof-aggregation.md +++ b/book/docs/writing-programs/proof-aggregation.md @@ -17,7 +17,7 @@ Note that by itself, SP1 can already prove arbitrarily large programs by chunkin To verify a proof inside the zkVM, you can use the `sp1_zkvm::lib::verify::verify_sp1_proof` function. -```rust +```rust,noplayground sp1_zkvm::lib::verify::verify_sp1_proof(vkey, public_values_digest); ``` diff --git a/book/sp1.png b/book/sp1.png new file mode 100644 index 0000000000000000000000000000000000000000..78576befe311ab327f31e2fd3054f8dddcd081dd GIT binary patch literal 66629 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 Twg!hb@;){(x_Gt->KySO+>0Oy literal 0 HcmV?d00001 diff --git a/book/verification/off-chain-verification.md b/book/verification/off-chain-verification.md new file mode 100644 index 0000000000..9250b6021a --- /dev/null +++ b/book/verification/off-chain-verification.md @@ -0,0 +1,49 @@ +# Offchain Verification + +## Rust `no_std` Verification + +You can verify SP1 Groth16 and Plonk proofs in `no_std` environments with [`sp1-verifier`](https://docs.rs/sp1-verifier/latest/sp1_verifier/). + +`sp1-verifier` is also patched to verify Groth16 and Plonk proofs within the SP1 ZKVM, using +[bn254](https://blog.succinct.xyz/succinctshipsprecompiles/) precompiles. For an example of this, see +the [Groth16 Example](https://github.com/succinctlabs/sp1/tree/main/examples/groth16/). + +### Installation + +Import the following dependency in your `Cargo.toml`: + +```toml +sp1-verifier = {version = "3.0.0", default-features = false} +``` + +### Usage + +`sp1-verifier`'s interface is very similar to the solidity verifier's. It exposes two public functions: +[`Groth16Verifier::verify_proof`](https://docs.rs/sp1-verifier/latest/src/sp1_verifier/groth16.rs.html) +and [`PlonkVerifier::verify_proof`](https://docs.rs/sp1-verifier/latest/src/sp1_verifier/plonk.rs.html). + +`sp1-verifier` also exposes the Groth16 and Plonk verifying keys as constants, `GROTH16_VK_BYTES` and `PLONK_VK_BYTES`. These +keys correspond to the current SP1 version's official Groth16 and Plonk verifying keys, which are used for verifying proofs generated +using docker or the prover network. + +First, generate your groth16/plonk proof with the SP1 SDK. See [here](./onchain/getting-started.md#generating-sp1-proofs-for-onchain-verification) +for more information -- `sp1-verifier` and the solidity verifier expect inputs in the same format. + +Next, verify the proof with `sp1-verifier`. The following snippet is from the [Groth16 example program](https://github.com/succinctlabs/sp1/tree/dev/examples/groth16/), which verifies a Groth16 proof within SP1 using `sp1-verifier`. + +```rust,noplayground +{{#include ../../examples/groth16/program/src/main.rs}} +``` + +Here, the proof, public inputs, and vkey hash are read from stdin. See the following snippet to see how these values are generated. + +```rust,noplayground +{{#include ../../examples/groth16/script/src/main.rs:12:34}} +``` + +> Note that the SP1 SDK itself is *not* `no_std` compatible. + +## Wasm Verification + +The [`example-sp1-wasm-verifier`](https://github.com/succinctlabs/example-sp1-wasm-verifier) demonstrates how to +verify SP1 proofs in wasm. For a more detailed explanation of the process, please see the [README](https://github.com/succinctlabs/example-sp1-wasm-verifier/blob/main/README.md). diff --git a/book/verification/onchain/contract-addresses.md b/book/verification/onchain/contract-addresses.md new file mode 100644 index 0000000000..0a23f6ab2e --- /dev/null +++ b/book/verification/onchain/contract-addresses.md @@ -0,0 +1,101 @@ +# Contract Addresses + +To verify SP1 proofs on-chain, we recommend using our deployed canonical verifier gateways. The +[SP1VerifierGateway](https://github.com/succinctlabs/sp1-contracts/blob/main/contracts/src/ISP1VerifierGateway.sol) +will automatically route your SP1 proof to the correct verifier based on the SP1 version used. + +## Canonical Verifier Gateways + +There are different verifier gateway for each proof system: Groth16 and PLONK. This means that you +must use the correct verifier gateway depending on if you are verifying a Groth16 or PLONK proof. + +### Groth16 + +| Chain ID | Chain | Gateway | +| -------- | ---------------- | --------------------------------------------------------------------------------------------------------------------------------------- | +| 1 | Mainnet | [0x397A5f7f3dBd538f23DE225B51f532c34448dA9B](https://etherscan.io/address/0x397A5f7f3dBd538f23DE225B51f532c34448dA9B) | +| 11155111 | Sepolia | [0x397A5f7f3dBd538f23DE225B51f532c34448dA9B](https://sepolia.etherscan.io/address/0x397A5f7f3dBd538f23DE225B51f532c34448dA9B) | +| 17000 | Holesky | [0x397A5f7f3dBd538f23DE225B51f532c34448dA9B](https://holesky.etherscan.io/address/0x397A5f7f3dBd538f23DE225B51f532c34448dA9B) | +| 42161 | Arbitrum One | [0x397A5f7f3dBd538f23DE225B51f532c34448dA9B](https://arbiscan.io/address/0x397A5f7f3dBd538f23DE225B51f532c34448dA9B) | +| 421614 | Arbitrum Sepolia | [0x397A5f7f3dBd538f23DE225B51f532c34448dA9B](https://sepolia.arbiscan.io/address/0x397A5f7f3dBd538f23DE225B51f532c34448dA9B) | +| 8453 | Base | [0x397A5f7f3dBd538f23DE225B51f532c34448dA9B](https://basescan.org/address/0x397A5f7f3dBd538f23DE225B51f532c34448dA9B) | +| 84532 | Base Sepolia | [0x397A5f7f3dBd538f23DE225B51f532c34448dA9B](https://sepolia.basescan.org/address/0x397A5f7f3dBd538f23DE225B51f532c34448dA9B) | +| 10 | Optimism | [0x397A5f7f3dBd538f23DE225B51f532c34448dA9B](https://optimistic.etherscan.io/address/0x397A5f7f3dBd538f23DE225B51f532c34448dA9B) | +| 11155420 | Optimism Sepolia | [0x397A5f7f3dBd538f23DE225B51f532c34448dA9B](https://sepolia-optimism.etherscan.io/address/0x397A5f7f3dBd538f23DE225B51f532c34448dA9B) | +| 534351 | Scroll Sepolia | [0x397A5f7f3dBd538f23DE225B51f532c34448dA9B](https://sepolia.scrollscan.com/address/0x397A5f7f3dBd538f23DE225B51f532c34448dA9B) | +| 534352 | Scroll | [0x397A5f7f3dBd538f23DE225B51f532c34448dA9B](https://scrollscan.com/address/0x397A5f7f3dBd538f23DE225B51f532c34448dA9B) | + +### PLONK + +| Chain ID | Chain | Gateway | +| -------- | ---------------- | --------------------------------------------------------------------------------------------------------------------------------------- | +| 1 | Mainnet | [0x3B6041173B80E77f038f3F2C0f9744f04837185e](https://etherscan.io/address/0x3B6041173B80E77f038f3F2C0f9744f04837185e) | +| 11155111 | Sepolia | [0x3B6041173B80E77f038f3F2C0f9744f04837185e](https://sepolia.etherscan.io/address/0x3B6041173B80E77f038f3F2C0f9744f04837185e) | +| 17000 | Holesky | [0x3B6041173B80E77f038f3F2C0f9744f04837185e](https://holesky.etherscan.io/address/0x3B6041173B80E77f038f3F2C0f9744f04837185e) | +| 42161 | Arbitrum One | [0x3B6041173B80E77f038f3F2C0f9744f04837185e](https://arbiscan.io/address/0x3B6041173B80E77f038f3F2C0f9744f04837185e) | +| 421614 | Arbitrum Sepolia | [0x3B6041173B80E77f038f3F2C0f9744f04837185e](https://sepolia.arbiscan.io/address/0x3B6041173B80E77f038f3F2C0f9744f04837185e) | +| 8453 | Base | [0x3B6041173B80E77f038f3F2C0f9744f04837185e](https://basescan.org/address/0x3B6041173B80E77f038f3F2C0f9744f04837185e) | +| 84532 | Base Sepolia | [0x3B6041173B80E77f038f3F2C0f9744f04837185e](https://sepolia.basescan.org/address/0x3B6041173B80E77f038f3F2C0f9744f04837185e) | +| 10 | Optimism | [0x3B6041173B80E77f038f3F2C0f9744f04837185e](https://optimistic.etherscan.io/address/0x3b6041173b80e77f038f3f2c0f9744f04837185e) | +| 11155420 | Optimism Sepolia | [0x3B6041173B80E77f038f3F2C0f9744f04837185e](https://sepolia-optimism.etherscan.io/address/0x3B6041173B80E77f038f3F2C0f9744f04837185e) | +| 534351 | Scroll Sepolia | [0x3B6041173B80E77f038f3F2C0f9744f04837185e](https://sepolia.scrollscan.com/address/0x3B6041173B80E77f038f3F2C0f9744f04837185e) | +| 534352 | Scroll | [0x3B6041173B80E77f038f3F2C0f9744f04837185e](https://scrollscan.com/address/0x3B6041173B80E77f038f3F2C0f9744f04837185e) | + +The most up-to-date reference on each chain can be found in the +[deployments](https://github.com/succinctlabs/sp1-contracts/blob/main/contracts/deployments) +directory in the +SP1 contracts repository, where each chain has a dedicated JSON file with each verifier's address. + +## Versioning Policy + +Whenever a verifier for a new SP1 version is deployed, the gateway contract will be updated to +support it with +[addRoute()](https://github.com/succinctlabs/sp1-contracts/blob/main/contracts/src/ISP1VerifierGateway.sol#L65). +If a verifier for an SP1 version has an issue, the route will be frozen with +[freezeRoute()](https://github.com/succinctlabs/sp1-contracts/blob/main/contracts/src/ISP1VerifierGateway.sol#L71). + +On mainnets, only official versioned releases are deployed and added to the gateway. Testnets have +`rc` versions of the verifier deployed supported in addition to the official versions. + +## Deploying to other Chains + +In the case that you need to use a chain that is not listed above, you can deploy your own +verifier contract by following the instructions in the +[SP1 Contracts Repo](https://github.com/succinctlabs/sp1-contracts/blob/main/README.md#deployments). + +Since both the `SP1VerifierGateway` and each `SP1Verifier` implement the [ISP1Verifier +interface](https://github.com/succinctlabs/sp1-contracts/blob/main/contracts/src/ISP1Verifier.sol), you can choose to either: + +* Deploy the `SP1VerifierGateway` and add `SP1Verifier` contracts to it. Then point to the + `SP1VerifierGateway` address in your contracts. +* Deploy just the `SP1Verifier` contract that you want to use. Then point to the `SP1Verifier` + address in + your contracts. + +If you want support for a canonical verifier on your chain, contact us [here](https://t.me/+AzG4ws-kD24yMGYx). We often deploy canonical verifiers on new chains if there's enough demand. + +## ISP1Verifier Interface + +All verifiers implement the [ISP1Verifier](https://github.com/succinctlabs/sp1-contracts/blob/main/contracts/src/ISP1Verifier.sol) interface. + +```c++ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +/// @title SP1 Verifier Interface +/// @author Succinct Labs +/// @notice This contract is the interface for the SP1 Verifier. +interface ISP1Verifier { + /// @notice Verifies a proof with given public values and vkey. + /// @dev It is expected that the first 4 bytes of proofBytes must match the first 4 bytes of + /// target verifier's VERIFIER_HASH. + /// @param programVKey The verification key for the RISC-V program. + /// @param publicValues The public values encoded as bytes. + /// @param proofBytes The proof of the program execution the SP1 zkVM encoded as bytes. + function verifyProof( + bytes32 programVKey, + bytes calldata publicValues, + bytes calldata proofBytes + ) external view; +} +``` diff --git a/book/verification/onchain/getting-started.md b/book/verification/onchain/getting-started.md new file mode 100644 index 0000000000..834a23dc18 --- /dev/null +++ b/book/verification/onchain/getting-started.md @@ -0,0 +1,33 @@ +# Onchain Verification: Setup + +The best way to get started with verifying SP1 proofs on-chain is to refer to the [SP1 Project Template](https://github.com/succinctlabs/sp1-project-template/tree/main). + +- The template [program](https://github.com/succinctlabs/sp1-project-template/blob/main/program/src/main.rs) shows how to write outputs that can be decoded in Solidity. +- The template [script](https://github.com/succinctlabs/sp1-project-template/blob/main/script/src/bin/prove.rs) shows how to generate the proof using the SDK and save it to a file. +- The template [contract](https://github.com/succinctlabs/sp1-project-template/blob/main/contracts/src/Fibonacci.sol) shows how to verify the proof onchain using Solidity. + +Refer to the section on [Contract Addresses](./contract-addresses.md#contract-addresses) for the addresses of the deployed verifiers. + +## Generating SP1 Proofs for Onchain Verification + +By default, the proofs generated by SP1 are not verifiable onchain, as they are non-constant size and STARK verification on Ethereum is very expensive. To generate a proof that can be verified onchain, we use performant STARK recursion to combine SP1 shard proofs into a single STARK proof and then wrap that in a SNARK proof. Our `ProverClient` has a prover option for this called `plonk`. Behind the scenes, this function will first generate a normal SP1 proof, then recursively combine all of them into a single proof using the STARK recursion protocol. Finally, the proof is wrapped in a SNARK proof using PLONK. + +> WARNING: The Groth16 and PLONK provers are only guaranteed to work on official releases of SP1. To +> use Groth16 or PLONK proving & verification locally, ensure that you have Docker installed and have +> at least 128GB of RAM. + +### Example + +```rust,noplayground +{{#include ../../examples/fibonacci/script/bin/groth16_bn254.rs}} +``` + +You can run the above script with `RUST_LOG=info cargo run --bin groth16_bn254 --release` in `examples/fibonacci/script`. + +#### Using Groth16 and PLONK without Docker (Advanced) + +If you would like to run the Groth16 or PLONK prover directly without Docker, you must have Go 1.22 installed and enable the `native-gnark` feature in `sp1-sdk`. This path is not recommended and may require additional native dependencies. + +```toml +sp1-sdk = { version = "2.0.0", features = ["native-gnark"] } +``` diff --git a/book/verification/onchain/solidity-sdk.md b/book/verification/onchain/solidity-sdk.md new file mode 100644 index 0000000000..822ab620b9 --- /dev/null +++ b/book/verification/onchain/solidity-sdk.md @@ -0,0 +1,122 @@ +# Solidity Verifier + +We maintain a suite of [contracts](https://github.com/succinctlabs/sp1-contracts/tree/main) used for verifying SP1 proofs onchain. We highly recommend using [Foundry](https://book.getfoundry.sh/). + +## Installation + +To install the latest release version: + +```bash +forge install succinctlabs/sp1-contracts +``` + +To install a specific version: + +```bash +forge install succinctlabs/sp1-contracts@ +``` + +Finally, add `@sp1-contracts/=lib/sp1-contracts/contracts/src/` in `remappings.txt.` + +### Usage + +Once installed, you can use the contracts in the library by importing them: + +```c++ +// SPDX-License-Identifier: MIT +pragma solidity ^0.8.20; + +import {ISP1Verifier} from "@sp1-contracts/ISP1Verifier.sol"; + +/// @title Fibonacci. +/// @author Succinct Labs +/// @notice This contract implements a simple example of verifying the proof of a computing a +/// fibonacci number. +contract Fibonacci { + /// @notice The address of the SP1 verifier contract. + /// @dev This can either be a specific SP1Verifier for a specific version, or the + /// SP1VerifierGateway which can be used to verify proofs for any version of SP1. + /// For the list of supported verifiers on each chain, see: + /// https://docs.succinct.xyz/onchain-verification/contract-addresses + address public verifier; + + /// @notice The verification key for the fibonacci program. + bytes32 public fibonacciProgramVKey; + + constructor(address _verifier, bytes32 _fibonacciProgramVKey) { + verifier = _verifier; + fibonacciProgramVKey = _fibonacciProgramVKey; + } + + /// @notice The entrypoint for verifying the proof of a fibonacci number. + /// @param _proofBytes The encoded proof. + /// @param _publicValues The encoded public values. + function verifyFibonacciProof(bytes calldata _publicValues, bytes calldata _proofBytes) + public + view + returns (uint32, uint32, uint32) + { + ISP1Verifier(verifier).verifyProof(fibonacciProgramVKey, _publicValues, _proofBytes); + (uint32 n, uint32 a, uint32 b) = abi.decode(_publicValues, (uint32, uint32, uint32)); + return (n, a, b); + } +} + +``` + +### Finding your program vkey + +The program vkey (`fibonacciProgramVKey` in the example above) is passed into the `ISP1Verifier` along with the public values and proof bytes. You +can find your program vkey by going through the following steps: + +1. Find what version of SP1 crates you are using. +2. Use the version from step to run this command: `sp1up --version ` +3. Use the vkey command to get the program vkey: `cargo prove vkey -elf ` + +Alternatively, you can set up a simple script to do this using the `sp1-sdk` crate: + +```rust +fn main() { + // Setup the logger. + sp1_sdk::utils::setup_logger(); + + // Setup the prover client. + let client = ProverClient::new(); + + // Setup the program. + let (_, vk) = client.setup(FIBONACCI_ELF); + + // Print the verification key. + println!("Program Verification Key: {}", vk.bytes32()); +} +``` + +### Testing + +To test the contract, we recommend setting up [Foundry +Tests](https://book.getfoundry.sh/forge/tests). We have an example of such a test in the [SP1 +Project +Template](https://github.com/succinctlabs/sp1-project-template/blob/dev/contracts/test/Fibonacci.t.sol). + +### Solidity Versions + +The officially deployed contracts are built using Solidity 0.8.20 and exist on the +[sp1-contracts main](https://github.com/succinctlabs/sp1-contracts/tree/main) branch. + +If you need to use different versions that are compatible with your contracts, there are also other +branches you can install that contain different versions. For +example for branch [main-0.8.15](https://github.com/succinctlabs/sp1-contracts/tree/main-0.8.15) +contains the contracts with: + +```c++ +pragma solidity ^0.8.15; +``` + +and you can install it with: + +```sh +forge install succinctlabs/sp1-contracts@main-0.8.15 +``` + +If there is different versions that you need but there aren't branches for them yet, please ask in +the [SP1 Telegram](https://t.me/+AzG4ws-kD24yMGYx). diff --git a/crates/cli/src/commands/install_toolchain.rs b/crates/cli/src/commands/install_toolchain.rs index de09773cef..e027729f26 100644 --- a/crates/cli/src/commands/install_toolchain.rs +++ b/crates/cli/src/commands/install_toolchain.rs @@ -1,15 +1,16 @@ -use anyhow::Result; -use clap::Parser; -use dirs::home_dir; -use rand::{distributions::Alphanumeric, Rng}; -use reqwest::Client; -use sp1_sdk::artifacts::download_file; use std::{ fs::{self}, io::Read, process::Command, }; +use anyhow::Result; +use clap::Parser; +use dirs::home_dir; +use rand::{distributions::Alphanumeric, Rng}; +use reqwest::Client; +use sp1_sdk::install::download_file; + #[cfg(target_family = "unix")] use std::os::unix::fs::PermissionsExt; diff --git a/crates/cli/src/commands/vkey.rs b/crates/cli/src/commands/vkey.rs index 734b470970..b69e91c986 100644 --- a/crates/cli/src/commands/vkey.rs +++ b/crates/cli/src/commands/vkey.rs @@ -48,7 +48,7 @@ impl VkeyCmd { file.read_to_end(&mut elf)?; // Get the verification key - let prover = ProverClient::new(); + let prover = ProverClient::from_env(); let (_, vk) = prover.setup(&elf); // Print the verification key hash diff --git a/crates/core/executor/src/hook.rs b/crates/core/executor/src/hook.rs index e5479f623f..a2ce720bf0 100644 --- a/crates/core/executor/src/hook.rs +++ b/crates/core/executor/src/hook.rs @@ -11,11 +11,20 @@ use crate::Executor; /// A runtime hook, wrapped in a smart pointer. pub type BoxedHook<'a> = Arc>; -/// The file descriptor through which to access `hook_k1_ecrecover`. -pub const K1_ECRECOVER_HOOK: u32 = 5; +/// The file descriptor through which to access `hook_ecrecover`. +pub const FD_ECRECOVER_HOOK: u32 = 5; + /// The file descriptor through which to access `hook_r1_ecrecover`. pub const R1_ECRECOVER_HOOK: u32 = 6; +// Note: we skip 6 because we have an eddsa hook in dev. + +/// The file descriptor through which to access `hook_ecrecover_2`. +pub const FD_ECRECOVER_HOOK_2: u32 = 7; + +/// The file descriptor through which to access `hook_ed_decompress`. +pub const FD_EDDECOMPRESS: u32 = 8; + /// A runtime hook. May be called during execution by writing to a specified file descriptor, /// accepting and returning arbitrary data. pub trait Hook { @@ -78,8 +87,10 @@ impl<'a> Default for HookRegistry<'a> { let table = HashMap::from([ // Note: To ensure any `fd` value is synced with `zkvm/precompiles/src/io.rs`, // add an assertion to the test `hook_fds_match` below. - (K1_ECRECOVER_HOOK, hookify(hook_k1_ecrecover)), + (FD_ECRECOVER_HOOK, hookify(hook_ecrecover)), (R1_ECRECOVER_HOOK, hookify(hook_r1_ecrecover)), + (FD_ECRECOVER_HOOK_2, hookify(hook_ecrecover_v2)), + (FD_EDDECOMPRESS, hookify(hook_ed_decompress)), ]); Self { table } @@ -121,7 +132,7 @@ pub struct HookEnv<'a, 'b: 'a> { /// WARNING: This function is used to recover the public key outside of the zkVM context. These /// values must be constrained by the zkVM for correctness. #[must_use] -pub fn hook_k1_ecrecover(_: HookEnv, buf: &[u8]) -> Vec> { +pub fn hook_ecrecover(_: HookEnv, buf: &[u8]) -> Vec> { assert_eq!(buf.len(), 65 + 32, "ecrecover input should have length 65 + 32"); let (sig, msg_hash) = buf.split_at(65); let sig: &[u8; 65] = sig.try_into().unwrap(); @@ -166,14 +177,87 @@ pub fn hook_r1_ecrecover(_: HookEnv, buf: &[u8]) -> Vec> { vec![s_inverse.to_bytes().to_vec()] } +/// Recovers the public key from the signature and message hash using the k256 crate. +/// +/// # Arguments +/// +/// * `env` - The environment in which the hook is invoked. +/// * `buf` - The buffer containing the signature and message hash. +/// - The signature is 65 bytes, the first 64 bytes are the signature and the last byte is the +/// recovery ID. +/// - The message hash is 32 bytes. +/// +/// The result is returned as a status and a pair of bytes, where the first 32 bytes are the X coordinate +/// and the second 32 bytes are the Y coordinate of the decompressed point. +/// +/// A status of 0 indicates that the public key could not be recovered. +/// +/// WARNING: This function is used to recover the public key outside of the zkVM context. These +/// values must be constrained by the zkVM for correctness. +#[must_use] +pub fn hook_ecrecover_v2(_: HookEnv, buf: &[u8]) -> Vec> { + assert_eq!(buf.len(), 65 + 32, "ecrecover input should have length 65 + 32, this is a bug."); + let (sig, msg_hash) = buf.split_at(65); + let sig: &[u8; 65] = sig.try_into().unwrap(); + let msg_hash: &[u8; 32] = msg_hash.try_into().unwrap(); + + let mut recovery_id = sig[64]; + let mut sig = Signature::from_slice(&sig[..64]).unwrap(); + + if let Some(sig_normalized) = sig.normalize_s() { + sig = sig_normalized; + recovery_id ^= 1; + }; + let recid = RecoveryId::from_byte(recovery_id) + .expect("Computed recovery ID is invalid, this is a bug."); + + // Attempting to recvover the public key has failed, write a 0 to indicate to the caller. + let Ok(recovered_key) = VerifyingKey::recover_from_prehash(&msg_hash[..], &sig, recid) else { + return vec![vec![0]]; + }; + + let bytes = recovered_key.to_sec1_bytes(); + + let (_, s) = sig.split_scalars(); + let s_inverse = s.invert(); + + vec![vec![1], bytes.to_vec(), s_inverse.to_bytes().to_vec()] +} + +/// Checks if a compressed Edwards point can be decompressed. +/// +/// # Arguments +/// * `env` - The environment in which the hook is invoked. +/// * `buf` - The buffer containing the compressed Edwards point. +/// - The compressed Edwards point is 32 bytes. +/// - The high bit of the last byte is the sign bit. +/// +/// The result is either `0` if the point cannot be decompressed, or `1` if it can. +/// +/// WARNING: This function merely hints at the validity of the compressed point. These values must +/// be constrained by the zkVM for correctness. +#[must_use] +pub fn hook_ed_decompress(_: HookEnv, buf: &[u8]) -> Vec> { + let Ok(point) = sp1_curves::curve25519_dalek::CompressedEdwardsY::from_slice(buf) else { + return vec![vec![0]]; + }; + + if sp1_curves::edwards::ed25519::decompress(&point).is_some() { + vec![vec![1]] + } else { + vec![vec![0]] + } +} + #[cfg(test)] pub mod tests { + use super::*; #[test] pub fn hook_fds_match() { use sp1_zkvm::lib::io; - assert_eq!(K1_ECRECOVER_HOOK, io::K1_ECRECOVER_HOOK); + assert_eq!(FD_ECRECOVER_HOOK, io::K1_ECRECOVER_HOOK); assert_eq!(R1_ECRECOVER_HOOK, io::R1_ECRECOVER_HOOK); } diff --git a/crates/core/executor/src/profiler.rs b/crates/core/executor/src/profiler.rs index a3066455cb..416993bb3c 100644 --- a/crates/core/executor/src/profiler.rs +++ b/crates/core/executor/src/profiler.rs @@ -197,31 +197,32 @@ impl Profiler { } /// Simple check to makes sure we have valid main function that lasts - /// for most of the exeuction time. + /// for most of the execution time. fn check_samples(&self) { let Some(main_idx) = self.main_idx else { - eprintln!("Warning: The `main` function is not present in the Elf file, this is likely caused by using the wrong Elf file"); + eprintln!( + "Warning: The `main` function is not present in the Elf file, this is likely caused by using the wrong Elf file" + ); return; }; - let main_count = - self.samples - .iter() - .filter(|s| { - s.stack.iter().any(|f| { - if let Frame::Label(idx) = f { - *idx == main_idx - } else { - false - } - }) - }) - .count(); + let main_count = self + .samples + .iter() + .filter(|s| { + s.stack + .iter() + .any(|f| if let Frame::Label(idx) = f { *idx == main_idx } else { false }) + }) + .count(); #[allow(clippy::cast_precision_loss)] let main_ratio = main_count as f64 / self.samples.len() as f64; if main_ratio < 0.9 { - eprintln!("Warning: This trace appears to be invalid. The `main` function is present in only {:.2}% of the samples, this is likely caused by the using the wrong Elf file", main_ratio * 100.0); + eprintln!( + "Warning: This trace appears to be invalid. The `main` function is present in only {:.2}% of the samples, this is likely caused by the using the wrong Elf file", + main_ratio * 100.0 + ); } } } diff --git a/crates/core/executor/src/syscalls/precompiles/edwards/decompress.rs b/crates/core/executor/src/syscalls/precompiles/edwards/decompress.rs index 6e790ab133..12276aa181 100644 --- a/crates/core/executor/src/syscalls/precompiles/edwards/decompress.rs +++ b/crates/core/executor/src/syscalls/precompiles/edwards/decompress.rs @@ -53,7 +53,8 @@ impl Syscall for EdwardsDecompressSyscall { // Compute actual decompressed X let compressed_y = CompressedEdwardsY(compressed_edwards_y); - let decompressed = decompress(&compressed_y); + let decompressed = + decompress(&compressed_y).expect("Decompression failed, syscall invariant violated."); let mut decompressed_x_bytes = decompressed.x.to_bytes_le(); decompressed_x_bytes.resize(32, 0u8); diff --git a/crates/core/machine/src/operations/field/field_sqrt.rs b/crates/core/machine/src/operations/field/field_sqrt.rs index a0f40c6a48..dbe4e4806a 100644 --- a/crates/core/machine/src/operations/field/field_sqrt.rs +++ b/crates/core/machine/src/operations/field/field_sqrt.rs @@ -224,7 +224,11 @@ mod tests { let mut row = [F::zero(); NUM_TEST_COLS]; let cols: &mut TestCols = row.as_mut_slice().borrow_mut(); cols.a = P::to_limbs_field::(a); - cols.sqrt.populate(&mut blu_events, 1, a, ed25519_sqrt); + cols.sqrt.populate(&mut blu_events, 1, a, |p| { + ed25519_sqrt(p).expect( + "By now we should have validated the sqrt exists, this is a bug", + ) + }); output.add_byte_lookup_events(blu_events); row }) diff --git a/crates/core/machine/src/syscall/precompiles/edwards/ed_decompress.rs b/crates/core/machine/src/syscall/precompiles/edwards/ed_decompress.rs index 51b3f32e59..e38d9fcaa7 100644 --- a/crates/core/machine/src/syscall/precompiles/edwards/ed_decompress.rs +++ b/crates/core/machine/src/syscall/precompiles/edwards/ed_decompress.rs @@ -99,7 +99,9 @@ impl EdDecompressCols { let dyy = self.dyy.populate(blu_events, shard, &E::d_biguint(), &yy, FieldOperation::Mul); let v = self.v.populate(blu_events, shard, &one, &dyy, FieldOperation::Add); let u_div_v = self.u_div_v.populate(blu_events, shard, &u, &v, FieldOperation::Div); - let x = self.x.populate(blu_events, shard, &u_div_v, ed25519_sqrt); + let x = self.x.populate(blu_events, shard, &u_div_v, |p| { + ed25519_sqrt(p).expect("ed25519_sqrt failed, syscall invariant violated") + }); self.neg_x.populate(blu_events, shard, &BigUint::zero(), &x, FieldOperation::Sub); } } diff --git a/crates/cuda/src/lib.rs b/crates/cuda/src/lib.rs index 3493f6a58c..63495c6129 100644 --- a/crates/cuda/src/lib.rs +++ b/crates/cuda/src/lib.rs @@ -367,7 +367,7 @@ impl Middleware for LoggingMiddleware { #[cfg(test)] mod tests { use sp1_core_machine::{reduce::SP1ReduceProof, utils::setup_logger}; - use sp1_prover::{components::DefaultProverComponents, InnerSC, SP1CoreProof, SP1Prover}; + use sp1_prover::{components::CpuProverComponents, InnerSC, SP1CoreProof, SP1Prover}; use test_artifacts::FIBONACCI_ELF; use twirp::{url::Url, Client}; @@ -380,7 +380,7 @@ mod tests { fn test_client() { setup_logger(); - let prover = SP1Prover::::new(); + let prover = SP1Prover::::new(); let client = SP1CudaProver::new().expect("Failed to create SP1CudaProver"); let (pk, vk) = prover.setup(FIBONACCI_ELF); @@ -414,7 +414,7 @@ mod tests { let client = Client::from_base_url(Url::parse("http://localhost:3000/twirp/").unwrap()).unwrap(); - let prover = SP1Prover::::new(); + let prover = SP1Prover::::new(); let (pk, vk) = prover.setup(FIBONACCI_ELF); let payload = ProveCoreRequestPayload { pk, stdin: SP1Stdin::new() }; let request = diff --git a/crates/curves/Cargo.toml b/crates/curves/Cargo.toml index c656dbd02b..8242decfaf 100644 --- a/crates/curves/Cargo.toml +++ b/crates/curves/Cargo.toml @@ -13,7 +13,6 @@ categories = { workspace = true } num = "0.4.3" serde = { workspace = true, features = ["derive"] } typenum = "1.17.0" -curve25519-dalek = { version = "4.1.2" } k256 = { version = "0.13.3", features = ["expose-field"] } p256 = { version = "0.13.2", features = ["expose-field"] } generic-array = { version = "1.1.0", features = ["alloc", "serde"] } diff --git a/crates/curves/src/edwards/ed25519.rs b/crates/curves/src/edwards/ed25519.rs index c2a823c603..4d1be91ac0 100644 --- a/crates/curves/src/edwards/ed25519.rs +++ b/crates/curves/src/edwards/ed25519.rs @@ -1,6 +1,6 @@ use std::str::FromStr; -use curve25519_dalek::edwards::CompressedEdwardsY; +use crate::curve25519_dalek::CompressedEdwardsY; use generic_array::GenericArray; use num::{BigUint, Num, One}; use serde::{Deserialize, Serialize}; @@ -72,7 +72,7 @@ impl EdwardsParameters for Ed25519Parameters { /// /// This function always returns the nonnegative square root, in the sense that the least /// significant bit of the result is always 0. -pub fn ed25519_sqrt(a: &BigUint) -> BigUint { +pub fn ed25519_sqrt(a: &BigUint) -> Option { // Here is a description of how to calculate sqrt in the Curve25519 base field: // ssh://git@github.com/succinctlabs/curve25519-dalek/blob/ // e2d1bd10d6d772af07cac5c8161cd7655016af6d/curve25519-dalek/src/field.rs#L256 @@ -108,7 +108,7 @@ pub fn ed25519_sqrt(a: &BigUint) -> BigUint { let flipped_sign_sqrt = beta_squared == neg_a; if !correct_sign_sqrt && !flipped_sign_sqrt { - panic!("a is not a square"); + return None; } let beta_bytes = beta.to_bytes_le(); @@ -116,10 +116,10 @@ pub fn ed25519_sqrt(a: &BigUint) -> BigUint { beta = (&modulus - &beta) % &modulus; } - beta + Some(beta) } -pub fn decompress(compressed_point: &CompressedEdwardsY) -> AffinePoint { +pub fn decompress(compressed_point: &CompressedEdwardsY) -> Option> { let mut point_bytes = *compressed_point.as_bytes(); let sign = point_bytes[31] >> 7 == 1; // mask out the sign bit @@ -134,7 +134,7 @@ pub fn decompress(compressed_point: &CompressedEdwardsY) -> AffinePoint let v_inv = v.modpow(&(modulus - BigUint::from(2u64)), modulus); let u_div_v = (u * &v_inv) % modulus; - let mut x = ed25519_sqrt(&u_div_v); + let mut x = ed25519_sqrt(&u_div_v)?; // sqrt always returns the nonnegative square root, // so we negate according to the supplied sign bit. @@ -142,7 +142,7 @@ pub fn decompress(compressed_point: &CompressedEdwardsY) -> AffinePoint x = modulus - &x; } - AffinePoint::new(x, y.clone()) + Some(AffinePoint::new(x, y.clone())) } #[cfg(test)] @@ -178,7 +178,7 @@ mod tests { CompressedEdwardsY(compressed) }; - assert_eq!(point, decompress(&compressed_point)); + assert_eq!(point, decompress(&compressed_point).unwrap()); // Double the point to create a "random" point for the next iteration. point = point.clone() + point.clone(); diff --git a/crates/curves/src/lib.rs b/crates/curves/src/lib.rs index c3f66d9eac..84a1aad0b8 100644 --- a/crates/curves/src/lib.rs +++ b/crates/curves/src/lib.rs @@ -7,7 +7,39 @@ pub mod utils; pub mod weierstrass; pub mod curve25519_dalek { - pub use curve25519_dalek::edwards::CompressedEdwardsY; + /// In "Edwards y" / "Ed25519" format, the curve point \\((x,y)\\) is + /// determined by the \\(y\\)-coordinate and the sign of \\(x\\). + /// + /// The first 255 bits of a `CompressedEdwardsY` represent the + /// \\(y\\)-coordinate. The high bit of the 32nd byte gives the sign of \\(x\\). + /// + /// Note: This is taken from the `curve25519-dalek` crate. + #[derive(Copy, Clone, Eq, PartialEq, Hash)] + pub struct CompressedEdwardsY(pub [u8; 32]); + + impl CompressedEdwardsY { + /// View this `CompressedEdwardsY` as a byte array. + pub fn as_bytes(&self) -> &[u8; 32] { + &self.0 + } + + /// Consume this `CompressedEdwardsY` and return the underlying byte array. + pub fn to_bytes(&self) -> [u8; 32] { + self.0 + } + + /// Construct a `CompressedEdwardsY` from a slice of bytes. + /// + /// # Errors + /// + /// Returns [`TryFromSliceError`] if the input `bytes` slice does not have + /// a length of 32. + pub fn from_slice( + bytes: &[u8], + ) -> Result { + bytes.try_into().map(CompressedEdwardsY) + } + } } pub mod k256 { diff --git a/crates/eval/src/main.rs b/crates/eval/src/main.rs index ca0e75a37b..8c7ca4e00d 100644 --- a/crates/eval/src/main.rs +++ b/crates/eval/src/main.rs @@ -1,10 +1,10 @@ use anyhow::Result; use sp1_eval::evaluate_performance; -use sp1_prover::components::DefaultProverComponents; +use sp1_prover::components::CpuProverComponents; use sp1_stark::SP1ProverOpts; #[tokio::main] async fn main() -> Result<(), Box> { let opts = SP1ProverOpts::default(); - evaluate_performance::(opts).await + evaluate_performance::(opts).await } diff --git a/crates/perf/Cargo.toml b/crates/perf/Cargo.toml index 38300783fe..c9ffb2970d 100644 --- a/crates/perf/Cargo.toml +++ b/crates/perf/Cargo.toml @@ -24,4 +24,4 @@ time = "0.3.26" [features] native-gnark = ["sp1-sdk/native-gnark"] -network-v2 = ["sp1-sdk/network-v2"] +network = ["sp1-sdk/network"] diff --git a/crates/perf/src/main.rs b/crates/perf/src/main.rs index 31a34c52ed..04ca613173 100644 --- a/crates/perf/src/main.rs +++ b/crates/perf/src/main.rs @@ -1,13 +1,10 @@ -use std::{ - env, - time::{Duration, Instant}, -}; +use std::time::{Duration, Instant}; use clap::{command, Parser}; use sp1_cuda::SP1CudaProver; use sp1_prover::HashableKey; -use sp1_prover::{components::DefaultProverComponents, ProverMode}; -use sp1_sdk::{self, ProverClient, SP1Context, SP1Prover, SP1Stdin}; +use sp1_prover::{components::CpuProverComponents, ProverMode}; +use sp1_sdk::{self, Prover, ProverClient, SP1Context, SP1Prover, SP1Stdin}; use sp1_stark::SP1ProverOpts; use test_artifacts::VERIFY_PROOF_ELF; @@ -52,7 +49,7 @@ fn main() { let stdin = std::fs::read(args.stdin).expect("failed to read stdin"); let stdin: SP1Stdin = bincode::deserialize(&stdin).expect("failed to deserialize stdin"); - let prover = SP1Prover::::new(); + let prover = SP1Prover::::new(); let (pk, vk) = prover.setup(&elf); let cycles = sp1_prover::utils::get_cycles(&elf, &stdin); let opts = SP1ProverOpts::default(); @@ -176,31 +173,18 @@ fn main() { println!("{:?}", result); } ProverMode::Network => { - let private_key = env::var("SP1_PRIVATE_KEY") - .expect("SP1_PRIVATE_KEY must be set for remote proving"); - let rpc_url = env::var("PROVER_NETWORK_RPC").ok(); - let skip_simulation = - env::var("SKIP_SIMULATION").map(|val| val == "true").unwrap_or_default(); + let prover = ProverClient::builder().network().build(); + let (_, _) = time_operation(|| prover.execute(&elf, &stdin)); - let mut prover_builder = ProverClient::builder().mode(ProverMode::Network); - - if let Some(rpc_url) = rpc_url { - prover_builder = prover_builder.rpc_url(rpc_url); - } - - if skip_simulation { - prover_builder = prover_builder.skip_simulation(); - } - - let prover = prover_builder.private_key(private_key).build(); - let (_, _) = time_operation(|| prover.execute(&elf, stdin.clone())); - - let (proof, _) = - time_operation(|| prover.prove(&pk, stdin.clone()).groth16().run().unwrap()); + let (proof, _) = time_operation(|| { + prover.prove(&pk, stdin.clone()).groth16().skip_simulation(true).run().unwrap() + }); let (_, _) = time_operation(|| prover.verify(&proof, &vk)); - let (proof, _) = time_operation(|| prover.prove(&pk, stdin).plonk().run().unwrap()); + let (proof, _) = time_operation(|| { + prover.prove(&pk, stdin).plonk().skip_simulation(true).run().unwrap() + }); let (_, _) = time_operation(|| prover.verify(&proof, &vk)); } diff --git a/crates/prover/scripts/build_compress_vks.rs b/crates/prover/scripts/build_compress_vks.rs index 0f8c5a0d08..2b700369f5 100644 --- a/crates/prover/scripts/build_compress_vks.rs +++ b/crates/prover/scripts/build_compress_vks.rs @@ -3,7 +3,7 @@ use std::path::PathBuf; use clap::Parser; use sp1_core_machine::utils::setup_logger; use sp1_prover::{ - components::DefaultProverComponents, shapes::build_vk_map_to_file, REDUCE_BATCH_SIZE, + components::CpuProverComponents, shapes::build_vk_map_to_file, REDUCE_BATCH_SIZE, }; #[derive(Parser, Debug)] @@ -37,7 +37,7 @@ fn main() { let range_start = args.start; let range_end = args.end; - build_vk_map_to_file::( + build_vk_map_to_file::( build_dir, reduce_batch_size, dummy, diff --git a/crates/prover/scripts/fibonacci_groth16.rs b/crates/prover/scripts/fibonacci_groth16.rs index 4ca51b00af..cbbc068593 100644 --- a/crates/prover/scripts/fibonacci_groth16.rs +++ b/crates/prover/scripts/fibonacci_groth16.rs @@ -5,7 +5,7 @@ use std::time::Instant; use itertools::iproduct; use sp1_core_executor::SP1Context; use sp1_core_machine::io::SP1Stdin; -use sp1_prover::components::DefaultProverComponents; +use sp1_prover::components::CpuProverComponents; use sp1_prover::SP1Prover; use sp1_stark::SP1ProverOpts; use tracing_subscriber::fmt::format::FmtSpan; @@ -38,7 +38,7 @@ fn main() { std::env::set_var("RECONSTRUCT_COMMITMENTS", "false"); // Initialize prover. - let prover = SP1Prover::::new(); + let prover = SP1Prover::::new(); // Setup sweep. let iterations = [480000u32]; diff --git a/crates/prover/scripts/fibonacci_sweep.rs b/crates/prover/scripts/fibonacci_sweep.rs index 5321d4cf71..6d09967a54 100644 --- a/crates/prover/scripts/fibonacci_sweep.rs +++ b/crates/prover/scripts/fibonacci_sweep.rs @@ -5,7 +5,7 @@ use std::{fs::File, io::BufWriter, io::Write, time::Instant}; use itertools::iproduct; use sp1_core_executor::SP1Context; use sp1_core_machine::io::SP1Stdin; -use sp1_prover::components::DefaultProverComponents; +use sp1_prover::components::CpuProverComponents; use sp1_prover::SP1Prover; use sp1_stark::SP1ProverOpts; use tracing_subscriber::EnvFilter; @@ -37,7 +37,7 @@ fn main() { std::env::set_var("RECONSTRUCT_COMMITMENTS", "false"); // Initialize prover. - let prover = SP1Prover::::new(); + let prover = SP1Prover::::new(); // Setup sweep. let iterations = [480000u32]; diff --git a/crates/prover/scripts/tendermint_sweep.rs b/crates/prover/scripts/tendermint_sweep.rs index bb80f848ea..184e188dd5 100644 --- a/crates/prover/scripts/tendermint_sweep.rs +++ b/crates/prover/scripts/tendermint_sweep.rs @@ -5,7 +5,7 @@ use std::{fs::File, io::BufWriter, io::Write, time::Instant}; use itertools::iproduct; use sp1_core_executor::SP1Context; use sp1_core_machine::io::SP1Stdin; -use sp1_prover::components::DefaultProverComponents; +use sp1_prover::components::CpuProverComponents; use sp1_prover::SP1Prover; use sp1_stark::SP1ProverOpts; use tracing_subscriber::EnvFilter; @@ -37,7 +37,7 @@ fn main() { std::env::set_var("RECONSTRUCT_COMMITMENTS", "false"); // Initialize prover. - let prover = SP1Prover::::new(); + let prover = SP1Prover::::new(); // Setup sweep. let iterations = [480000u32]; diff --git a/crates/prover/src/components.rs b/crates/prover/src/components.rs index e88dd87ceb..12bd26e56e 100644 --- a/crates/prover/src/components.rs +++ b/crates/prover/src/components.rs @@ -25,9 +25,9 @@ pub trait SP1ProverComponents: Send + Sync { + Sync; } -pub struct DefaultProverComponents; +pub struct CpuProverComponents; -impl SP1ProverComponents for DefaultProverComponents { +impl SP1ProverComponents for CpuProverComponents { type CoreProver = CpuProver::Val>>; type CompressProver = CpuProver::Val>>; type ShrinkProver = CpuProver::Val>>; diff --git a/crates/prover/src/lib.rs b/crates/prover/src/lib.rs index 844a5feb3c..f1d517ebd0 100644 --- a/crates/prover/src/lib.rs +++ b/crates/prover/src/lib.rs @@ -81,7 +81,7 @@ use tracing::instrument; pub use types::*; use utils::{sp1_committed_values_digest_bn254, sp1_vkey_digest_bn254, words_to_bytes}; -use components::{DefaultProverComponents, SP1ProverComponents}; +use components::{CpuProverComponents, SP1ProverComponents}; pub use sp1_core_machine::SP1_CIRCUIT_VERSION; @@ -114,8 +114,20 @@ pub type CompressAir = RecursionAir; pub type ShrinkAir = RecursionAir; pub type WrapAir = RecursionAir; +#[allow(clippy::type_complexity)] +enum TracesOrInput { + ProgramRecordTraces( + Box<( + Arc>, + ExecutionRecord, + Vec<(String, RowMajorMatrix)>, + )>, + ), + CircuitWitness(Box), +} + /// A end-to-end prover implementation for the SP1 RISC-V zkVM. -pub struct SP1Prover { +pub struct SP1Prover { /// The machine used for proving the core step. pub core_prover: C::CoreProver, @@ -667,7 +679,7 @@ impl SP1Prover { // Spawn a worker that sends the first layer inputs to a bounded channel. let input_sync = Arc::new(TurnBasedSync::new()); - let (input_tx, input_rx) = sync_channel::<(usize, usize, SP1CircuitWitness)>( + let (input_tx, input_rx) = sync_channel::<(usize, usize, SP1CircuitWitness, bool)>( opts.recursion_opts.checkpoints_channel_capacity, ); let input_tx = Arc::new(Mutex::new(input_tx)); @@ -677,7 +689,7 @@ impl SP1Prover { s.spawn(move || { for (index, input) in first_layer_inputs.into_iter().enumerate() { input_sync.wait_for_turn(index); - input_tx.lock().unwrap().send((index, 0, input)).unwrap(); + input_tx.lock().unwrap().send((index, 0, input, false)).unwrap(); input_sync.advance_turn(); } }); @@ -686,13 +698,9 @@ impl SP1Prover { // Spawn workers who generate the records and traces. let record_and_trace_sync = Arc::new(TurnBasedSync::new()); let (record_and_trace_tx, record_and_trace_rx) = - sync_channel::<( - usize, - usize, - Arc>, - ExecutionRecord, - Vec<(String, RowMajorMatrix)>, - )>(opts.recursion_opts.records_and_traces_channel_capacity); + sync_channel::<(usize, usize, TracesOrInput)>( + opts.recursion_opts.records_and_traces_channel_capacity, + ); let record_and_trace_tx = Arc::new(Mutex::new(record_and_trace_tx)); let record_and_trace_rx = Arc::new(Mutex::new(record_and_trace_rx)); let input_rx = Arc::new(Mutex::new(input_rx)); @@ -705,7 +713,7 @@ impl SP1Prover { let _span = span.enter(); loop { let received = { input_rx.lock().unwrap().recv() }; - if let Ok((index, height, input)) = received { + if let Ok((index, height, input, false)) = received { // Get the program and witness stream. let (program, witness_stream) = tracing::debug_span!( "get program and witness stream" @@ -776,7 +784,29 @@ impl SP1Prover { record_and_trace_tx .lock() .unwrap() - .send((index, height, program, record, traces)) + .send(( + index, + height, + TracesOrInput::ProgramRecordTraces(Box::new(( + program, record, traces, + ))), + )) + .unwrap(); + + // Advance the turn. + record_and_trace_sync.advance_turn(); + } else if let Ok((index, height, input, true)) = received { + record_and_trace_sync.wait_for_turn(index); + + // Send the record and traces to the worker. + record_and_trace_tx + .lock() + .unwrap() + .send(( + index, + height, + TracesOrInput::CircuitWitness(Box::new(input)), + )) .unwrap(); // Advance the turn. @@ -806,7 +836,8 @@ impl SP1Prover { let _span = span.enter(); loop { let received = { record_and_trace_rx.lock().unwrap().recv() }; - if let Ok((index, height, program, record, traces)) = received { + if let Ok((index, height, TracesOrInput::ProgramRecordTraces(boxed_prt))) = received { + let (program, record, traces) = *boxed_prt; tracing::debug_span!("batch").in_scope(|| { // Get the keys. let (pk, vk) = tracing::debug_span!("Setup compress program") @@ -874,7 +905,22 @@ impl SP1Prover { // Advance the turn. prover_sync.advance_turn(); }); - } else { + } else if let Ok((index, height, TracesOrInput::CircuitWitness(witness_box))) = received { + let witness = *witness_box; + if let SP1CircuitWitness::Compress(inner_witness) = witness { + let SP1CompressWitnessValues { vks_and_proofs, is_complete: _ } = inner_witness; + assert!(vks_and_proofs.len()==1); + let (vk, proof) = vks_and_proofs.last().unwrap(); + // Wait for our turn to update the state. + prover_sync.wait_for_turn(index); + + // Send the proof. + proofs_tx.lock().unwrap().send((index, height, vk.clone(), proof.clone())).unwrap(); + + // Advance the turn. + prover_sync.advance_turn(); + } + } else { break; } } @@ -934,7 +980,7 @@ impl SP1Prover { input_tx .lock() .unwrap() - .send((count, next_input_height, input)) + .send((count, next_input_height, input, is_last)) .unwrap(); input_sync.advance_turn(); count += 1; @@ -1516,14 +1562,8 @@ pub mod tests { // TODO(mattstam): We should Test::Plonk here, but this uses the existing // docker image which has a different API than the current. So we need to wait until the // next release (v1.2.0+), and then switch it back. - let prover = SP1Prover::::new(); - test_e2e_prover::( - &prover, - elf, - SP1Stdin::default(), - opts, - Test::All, - ) + let prover = SP1Prover::::new(); + test_e2e_prover::(&prover, elf, SP1Stdin::default(), opts, Test::All) } /// Tests an end-to-end workflow of proving a program across the entire proof generation @@ -1532,13 +1572,13 @@ pub mod tests { #[serial] fn test_e2e_with_deferred_proofs() -> Result<()> { setup_logger(); - test_e2e_with_deferred_proofs_prover::(SP1ProverOpts::default()) + test_e2e_with_deferred_proofs_prover::(SP1ProverOpts::default()) } #[test] fn test_deterministic_setup() { setup_logger(); - let prover = SP1Prover::::new(); + let prover = SP1Prover::::new(); let program = test_artifacts::FIBONACCI_ELF; let (pk, _) = prover.setup(program); let pk2 = prover.setup(program).0; diff --git a/crates/recursion/gnark-ffi/src/proof.rs b/crates/recursion/gnark-ffi/src/proof.rs index ab4345241a..fa71022f42 100644 --- a/crates/recursion/gnark-ffi/src/proof.rs +++ b/crates/recursion/gnark-ffi/src/proof.rs @@ -6,7 +6,6 @@ pub enum ProofBn254 { Groth16(Groth16Bn254Proof), } -/// A zero-knowledge proof generated by the PLONK protocol with a Base64 encoded gnark PLONK proof. #[derive(Debug, Clone, Serialize, Deserialize, Default)] pub struct PlonkBn254Proof { pub public_inputs: [String; 2], @@ -15,8 +14,6 @@ pub struct PlonkBn254Proof { pub plonk_vkey_hash: [u8; 32], } -/// A zero-knowledge proof generated by the Groth16 protocol with a Base64 encoded gnark Groth16 -/// proof. #[derive(Debug, Clone, Serialize, Deserialize, Default)] pub struct Groth16Bn254Proof { pub public_inputs: [String; 2], diff --git a/crates/sdk/Cargo.toml b/crates/sdk/Cargo.toml index 64e102189c..36a186db97 100644 --- a/crates/sdk/Cargo.toml +++ b/crates/sdk/Cargo.toml @@ -58,21 +58,11 @@ backoff = { version = "0.4", features = ["tokio"], optional = true } test-artifacts = { workspace = true } [features] -default = ["network"] +default = ["cuda", "network"] native-gnark = ["sp1-prover/native-gnark"] # TODO: Once alloy has a 1.* release, we can likely remove this feature flag, as there will be less # dependency resolution issues. network = [ - "dep:prost", - "dep:alloy-sol-types", - "dep:tokio", - "dep:alloy-signer", - "dep:alloy-signer-local", - "dep:reqwest", - "dep:twirp", - "dep:reqwest-middleware", -] -network-v2 = [ "dep:prost", "dep:alloy-sol-types", "dep:alloy-signer", diff --git a/crates/sdk/src/action.rs b/crates/sdk/src/action.rs deleted file mode 100644 index 58b38da010..0000000000 --- a/crates/sdk/src/action.rs +++ /dev/null @@ -1,232 +0,0 @@ -use sp1_core_executor::{ExecutionReport, HookEnv, SP1ContextBuilder}; -use sp1_core_machine::io::SP1Stdin; -use sp1_primitives::io::SP1PublicValues; -use sp1_prover::{components::DefaultProverComponents, SP1ProvingKey}; - -use anyhow::{Ok, Result}; -use sp1_stark::{SP1CoreOpts, SP1ProverOpts}; -use std::time::Duration; - -use crate::{provers::ProofOpts, Prover, SP1ProofKind, SP1ProofWithPublicValues}; - -/// Builder to prepare and configure execution of a program on an input. -/// May be run with [Self::run]. -pub struct Execute<'a> { - prover: &'a dyn Prover, - context_builder: SP1ContextBuilder<'a>, - elf: &'a [u8], - stdin: SP1Stdin, -} - -impl<'a> Execute<'a> { - /// Prepare to execute the given program on the given input (without generating a proof). - /// - /// Prefer using [ProverClient::execute](super::ProverClient::execute). - /// See there for more documentation. - pub fn new( - prover: &'a dyn Prover, - elf: &'a [u8], - stdin: SP1Stdin, - ) -> Self { - Self { prover, elf, stdin, context_builder: Default::default() } - } - - /// Execute the program on the input, consuming the built action `self`. - pub fn run(self) -> Result<(SP1PublicValues, ExecutionReport)> { - let Self { prover, elf, stdin, mut context_builder } = self; - let context = context_builder.build(); - Ok(prover.sp1_prover().execute(elf, &stdin, context)?) - } - - /// Add a runtime [Hook](super::Hook) into the context. - /// - /// Hooks may be invoked from within SP1 by writing to the specified file descriptor `fd` - /// with [`sp1_zkvm::io::write`], returning a list of arbitrary data that may be read - /// with successive calls to [`sp1_zkvm::io::read`]. - pub fn with_hook( - mut self, - fd: u32, - f: impl FnMut(HookEnv, &[u8]) -> Vec> + Send + Sync + 'a, - ) -> Self { - self.context_builder.hook(fd, f); - self - } - - /// Avoid registering the default hooks in the runtime. - /// - /// It is not necessary to call this to override hooks --- instead, simply - /// register a hook with the same value of `fd` by calling [`Self::with_hook`]. - pub fn without_default_hooks(mut self) -> Self { - self.context_builder.without_default_hooks(); - self - } - - /// Set the maximum number of cpu cycles to use for execution. - /// - /// If the cycle limit is exceeded, execution will return - /// [`sp1_core_executor::ExecutionError::ExceededCycleLimit`]. - pub fn max_cycles(mut self, max_cycles: u64) -> Self { - self.context_builder.max_cycles(max_cycles); - self - } - - /// Skip deferred proof verification. - pub fn set_skip_deferred_proof_verification(mut self, value: bool) -> Self { - self.context_builder.set_skip_deferred_proof_verification(value); - self - } -} - -/// Builder to prepare and configure proving execution of a program on an input. -/// May be run with [Self::run]. -pub struct Prove<'a> { - prover: &'a dyn Prover, - kind: SP1ProofKind, - context_builder: SP1ContextBuilder<'a>, - pk: &'a SP1ProvingKey, - stdin: SP1Stdin, - core_opts: SP1CoreOpts, - recursion_opts: SP1CoreOpts, - timeout: Option, -} - -impl<'a> Prove<'a> { - /// Prepare to prove the execution of the given program with the given input. - /// - /// Prefer using [ProverClient::prove](super::ProverClient::prove). - /// See there for more documentation. - pub fn new( - prover: &'a dyn Prover, - pk: &'a SP1ProvingKey, - stdin: SP1Stdin, - ) -> Self { - Self { - prover, - kind: Default::default(), - pk, - stdin, - context_builder: Default::default(), - core_opts: SP1CoreOpts::default(), - recursion_opts: SP1CoreOpts::recursion(), - timeout: None, - } - } - - /// Prove the execution of the program on the input, consuming the built action `self`. - pub fn run(self) -> Result { - let Self { - prover, - kind, - pk, - stdin, - mut context_builder, - core_opts, - recursion_opts, - timeout, - } = self; - let opts = SP1ProverOpts { core_opts, recursion_opts }; - let proof_opts = ProofOpts { sp1_prover_opts: opts, timeout }; - let context = context_builder.build(); - - // Dump the program and stdin to files for debugging if `SP1_DUMP` is set. - if std::env::var("SP1_DUMP") - .map(|v| v == "1" || v.to_lowercase() == "true") - .unwrap_or(false) - { - let program = pk.elf.clone(); - std::fs::write("program.bin", program).unwrap(); - let stdin = bincode::serialize(&stdin).unwrap(); - std::fs::write("stdin.bin", stdin.clone()).unwrap(); - } - - prover.prove(pk, stdin, proof_opts, context, kind) - } - - /// Set the proof kind to the core mode. This is the default. - pub fn core(mut self) -> Self { - self.kind = SP1ProofKind::Core; - self - } - - /// Set the proof kind to the compressed mode. - pub fn compressed(mut self) -> Self { - self.kind = SP1ProofKind::Compressed; - self - } - - /// Set the proof mode to the plonk bn254 mode. - pub fn plonk(mut self) -> Self { - self.kind = SP1ProofKind::Plonk; - self - } - - /// Set the proof mode to the groth16 bn254 mode. - pub fn groth16(mut self) -> Self { - self.kind = SP1ProofKind::Groth16; - self - } - - /// Add a runtime [Hook](super::Hook) into the context. - /// - /// Hooks may be invoked from within SP1 by writing to the specified file descriptor `fd` - /// with [`sp1_zkvm::io::write`], returning a list of arbitrary data that may be read - /// with successive calls to [`sp1_zkvm::io::read`]. - pub fn with_hook( - mut self, - fd: u32, - f: impl FnMut(HookEnv, &[u8]) -> Vec> + Send + Sync + 'a, - ) -> Self { - self.context_builder.hook(fd, f); - self - } - - /// Avoid registering the default hooks in the runtime. - /// - /// It is not necessary to call this to override hooks --- instead, simply - /// register a hook with the same value of `fd` by calling [`Self::with_hook`]. - pub fn without_default_hooks(mut self) -> Self { - self.context_builder.without_default_hooks(); - self - } - - /// Set the shard size for proving. - pub fn shard_size(mut self, value: usize) -> Self { - self.core_opts.shard_size = value; - self - } - - /// Set the shard batch size for proving. - pub fn shard_batch_size(mut self, value: usize) -> Self { - self.core_opts.shard_batch_size = value; - self - } - - /// Set whether we should reconstruct commitments while proving. - pub fn reconstruct_commitments(mut self, value: bool) -> Self { - self.core_opts.reconstruct_commitments = value; - self - } - - /// Set the maximum number of cpu cycles to use for execution. - /// - /// If the cycle limit is exceeded, execution will return - /// [`sp1_core_executor::ExecutionError::ExceededCycleLimit`]. - pub fn cycle_limit(mut self, cycle_limit: u64) -> Self { - self.context_builder.max_cycles(cycle_limit); - self - } - - /// Set the timeout for the proof's generation. - /// - /// This parameter is only used when the prover is run in network mode. - pub fn timeout(mut self, timeout: Duration) -> Self { - self.timeout = Some(timeout); - self - } - - /// Set the skip deferred proof verification flag. - pub fn set_skip_deferred_proof_verification(mut self, value: bool) -> Self { - self.context_builder.set_skip_deferred_proof_verification(value); - self - } -} diff --git a/crates/sdk/src/artifacts.rs b/crates/sdk/src/artifacts.rs index 2ed25462c0..f287e9a874 100644 --- a/crates/sdk/src/artifacts.rs +++ b/crates/sdk/src/artifacts.rs @@ -1,18 +1,13 @@ +//! # SP1 Artifacts +//! +//! A library for exporting the SP1 artifacts to the specified output directory. + use std::path::PathBuf; use anyhow::{Context, Result}; -#[cfg(any(feature = "network", feature = "network-v2"))] -use { - futures::StreamExt, - indicatif::{ProgressBar, ProgressStyle}, - reqwest::Client, - std::{cmp::min, fs::File, io::Write}, -}; - -pub use sp1_prover::build::build_plonk_bn254_artifacts_with_dummy; - use crate::install::try_install_circuit_artifacts; +pub use sp1_prover::build::build_plonk_bn254_artifacts_with_dummy; /// Exports the solidity verifier for PLONK proofs to the specified output directory. /// @@ -71,35 +66,3 @@ pub fn export_solidity_groth16_bn254_verifier(output_dir: impl Into) -> Ok(()) } - -#[cfg(any(feature = "network", feature = "network-v2"))] -pub async fn download_file( - client: &Client, - url: &str, - file: &mut File, -) -> std::result::Result<(), String> { - let res = client.get(url).send().await.or(Err(format!("Failed to GET from '{}'", &url)))?; - let total_size = - res.content_length().ok_or(format!("Failed to get content length from '{}'", &url))?; - - let pb = ProgressBar::new(total_size); - pb.set_style(ProgressStyle::default_bar() - .template("{msg}\n{spinner:.green} [{elapsed_precise}] [{wide_bar:.cyan/blue}] {bytes}/{total_bytes} ({bytes_per_sec}, {eta})").unwrap() - .progress_chars("#>-")); - println!("Downloading {}", url); - - let mut downloaded: u64 = 0; - let mut stream = res.bytes_stream(); - - while let Some(item) = stream.next().await { - let chunk = item.or(Err("Error while downloading file"))?; - file.write_all(&chunk).or(Err("Error while writing to file"))?; - let new = min(downloaded + (chunk.len() as u64), total_size); - downloaded = new; - pb.set_position(new); - } - - let msg = format!("Downloaded {} to {:?}", url, file); - pb.finish_with_message(msg); - Ok(()) -} diff --git a/crates/sdk/src/client.rs b/crates/sdk/src/client.rs new file mode 100644 index 0000000000..b0d20c6dc9 --- /dev/null +++ b/crates/sdk/src/client.rs @@ -0,0 +1,136 @@ +//! # SP1 Prover Client +//! +//! A client for interacting with the prover for the SP1 RISC-V zkVM. + +use crate::cpu::builder::CpuProverBuilder; +use crate::cuda::builder::CudaProverBuilder; +use crate::env::EnvProver; +use crate::network::builder::NetworkProverBuilder; + +/// An entrypoint for interacting with the prover for the SP1 RISC-V zkVM. +pub struct ProverClient; + +impl ProverClient { + /// Creates a new [`EnvProver`] from the environment. + /// + /// # Example + /// ```no_run + /// use sp1_sdk::ProverClient; + /// + /// std::env::set_var("SP1_PROVER", "network"); + /// std::env::set_var("NETWORK_PRIVATE_KEY", "..."); + /// std::env::set_var("NETWORK_RPC_URL", "..."); + /// let prover = ProverClient::from_env(); + /// ``` + #[deprecated(since = "4.0.0", note = "use `ProverClient::from_env()` instead")] + #[allow(clippy::new_ret_no_self)] + #[must_use] + pub fn new() -> EnvProver { + Self::from_env() + } + + /// Builds an [`EnvProver`], which loads the mode and any settings from the environment. + /// + /// # Usage + /// ```no_run + /// use sp1_sdk::{ProverClient, SP1Stdin, Prover}; + /// + /// std::env::set_var("SP1_PROVER", "network"); + /// std::env::set_var("NETWORK_PRIVATE_KEY", "..."); + /// let prover = ProverClient::from_env(); + /// + /// let elf = &[1, 2, 3]; + /// let stdin = SP1Stdin::new(); + /// + /// let (pk, vk) = prover.setup(elf); + /// let proof = prover.prove(&pk, &stdin).compressed().run().unwrap(); + /// ``` + #[must_use] + pub fn from_env() -> EnvProver { + EnvProver::new() + } + + /// Creates a new [`ProverClientBuilder`] so that you can configure the prover client. + #[must_use] + pub fn builder() -> ProverClientBuilder { + ProverClientBuilder + } +} + +/// A builder to define which proving client to use. +pub struct ProverClientBuilder; + +impl ProverClientBuilder { + /// Builds a [`CpuProver`] specifically for mock proving. + /// + /// # Example + /// ```no_run + /// use sp1_sdk::{ProverClient, SP1Stdin, Prover}; + /// + /// let elf = &[1, 2, 3]; + /// let stdin = SP1Stdin::new(); + /// + /// let prover = ProverClient::builder().mock().build(); + /// let (pk, vk) = prover.setup(elf); + /// let proof = prover.prove(&pk, &stdin).compressed().run().unwrap(); + /// ``` + #[must_use] + pub fn mock(&self) -> CpuProverBuilder { + CpuProverBuilder { mock: true } + } + + /// Builds a [`CpuProver`] specifically for local CPU proving. + /// + /// # Usage + /// ```no_run + /// use sp1_sdk::{ProverClient, SP1Stdin, Prover}; + /// + /// let elf = &[1, 2, 3]; + /// let stdin = SP1Stdin::new(); + /// + /// let prover = ProverClient::builder().cpu().build(); + /// let (pk, vk) = prover.setup(elf); + /// let proof = prover.prove(&pk, &stdin).compressed().run().unwrap(); + /// ``` + #[must_use] + pub fn cpu(&self) -> CpuProverBuilder { + CpuProverBuilder { mock: false } + } + + /// Builds a [`CudaProver`] specifically for local proving on NVIDIA GPUs. + /// + /// # Example + /// ```no_run + /// use sp1_sdk::{ProverClient, SP1Stdin, Prover}; + /// + /// let elf = &[1, 2, 3]; + /// let stdin = SP1Stdin::new(); + /// + /// let prover = ProverClient::builder().cuda().build(); + /// let (pk, vk) = prover.setup(elf); + /// let proof = prover.prove(&pk, &stdin).compressed().run().unwrap(); + /// ``` + #[must_use] + pub fn cuda(&self) -> CudaProverBuilder { + CudaProverBuilder + } + + /// Builds a [`NetworkProver`] specifically for proving on the network. + /// + /// # Example + /// ```no_run + /// use sp1_sdk::{ProverClient, SP1Stdin, Prover}; + /// + /// let elf = &[1, 2, 3]; + /// let stdin = SP1Stdin::new(); + /// + /// let prover = ProverClient::builder().network().build(); + /// let (pk, vk) = prover.setup(elf); + /// let proof = prover.prove(&pk, &stdin).compressed().run().unwrap(); + /// ``` + #[cfg(feature = "network")] + #[must_use] + pub fn network(&self) -> NetworkProverBuilder { + NetworkProverBuilder { private_key: None, rpc_url: None } + } +} diff --git a/crates/sdk/src/cpu/builder.rs b/crates/sdk/src/cpu/builder.rs new file mode 100644 index 0000000000..3bd17ebc2f --- /dev/null +++ b/crates/sdk/src/cpu/builder.rs @@ -0,0 +1,31 @@ +//! # CPU Prover Builder +//! +//! This module provides a builder for the [`CpuProver`]. + +use super::CpuProver; + +/// A builder for the [`CpuProver`]. +/// +/// The builder is used to configure the [`CpuProver`] before it is built. +pub struct CpuProverBuilder { + pub(crate) mock: bool, +} + +impl CpuProverBuilder { + /// Builds a [`CpuProver`]. + /// + /// # Details + /// This method will build a [`CpuProver`] with the given parameters. In particular, it will + /// build a mock prover if the `mock` flag is set. + /// + /// # Example + /// ```rust,no_run + /// use sp1_sdk::ProverClient; + /// + /// let prover = ProverClient::builder().mock().build(); + /// ``` + #[must_use] + pub fn build(self) -> CpuProver { + if self.mock { CpuProver::mock() } else { CpuProver::new() } + } +} diff --git a/crates/sdk/src/cpu/execute.rs b/crates/sdk/src/cpu/execute.rs new file mode 100644 index 0000000000..4a9ab56b8c --- /dev/null +++ b/crates/sdk/src/cpu/execute.rs @@ -0,0 +1,138 @@ +//! # CPU Execution +//! +//! This module provides a builder for simulating the execution of a program on the CPU. + +use anyhow::Result; +use sp1_core_executor::{ExecutionReport, HookEnv, SP1ContextBuilder}; +use sp1_core_machine::io::SP1Stdin; +use sp1_primitives::io::SP1PublicValues; +use sp1_prover::{components::CpuProverComponents, SP1Prover}; + +/// A builder for simulating the execution of a program on the CPU. +/// +/// This builder providers a typed interface for configuring the SP1 RISC-V executor. The builder +/// is used for all the different variants of the [`crate::ProverClient`]. +pub struct CpuExecuteBuilder<'a> { + pub(crate) elf: &'a [u8], + pub(crate) stdin: SP1Stdin, + pub(crate) prover: &'a SP1Prover, + pub(crate) context_builder: SP1ContextBuilder<'a>, +} + +impl<'a> CpuExecuteBuilder<'a> { + /// Add a executor [`sp1_core_executor::Hook`] into the context. + /// + /// # Arguments + /// * `fd` - The file descriptor that triggers this execution hook. + /// * `f` - The function to invoke when the hook is triggered. + /// + /// # Details + /// Hooks may be invoked from within SP1 by writing to the specified file descriptor `fd` + /// with [`sp1_zkvm::io::write`], returning a list of arbitrary data that may be read + /// with successive calls to [`sp1_zkvm::io::read`]. + /// + /// # Example + /// ```rust,no_run + /// use sp1_sdk::{ProverClient, SP1Stdin, include_elf, Prover}; + /// + /// let elf = &[1, 2, 3]; + /// let stdin = SP1Stdin::new(); + /// + /// let client = ProverClient::builder().cpu().build(); + /// let builder = client.execute(elf, &stdin) + /// .with_hook(1, |env, data| { + /// println!("Hook triggered with data: {:?}", data); + /// vec![vec![1, 2, 3]] + /// }) + /// .run(); + /// ``` + #[must_use] + pub fn with_hook( + mut self, + fd: u32, + f: impl FnMut(HookEnv, &[u8]) -> Vec> + Send + Sync + 'a, + ) -> Self { + self.context_builder.hook(fd, f); + self + } + + /// Set the maximum number of cpu cycles to use for execution. + /// + /// # Arguments + /// * `max_cycles` - The maximum number of cycles to use for execution. + /// + /// # Details + /// If the cycle limit is exceeded, execution will fail with the + /// [`sp1_core_executor::ExecutionError::ExceededCycleLimit`]. This is useful for preventing + /// infinite loops in the and limiting the execution time of the program. + /// + /// # Example + /// ```rust,no_run + /// use sp1_sdk::{ProverClient, SP1Stdin, include_elf, Prover}; + /// + /// let elf = &[1, 2, 3]; + /// let stdin = SP1Stdin::new(); + /// + /// let client = ProverClient::builder().cpu().build(); + /// let builder = client.execute(elf, &stdin) + /// .cycle_limit(1000000) + /// .run(); + /// ``` + #[must_use] + pub fn cycle_limit(mut self, max_cycles: u64) -> Self { + self.context_builder.max_cycles(max_cycles); + self + } + + /// Whether to skip deferred proof verification in the executor. + /// + /// # Arguments + /// * `value` - Whether to skip deferred proof verification. + /// + /// # Details + /// If set to `true`, the executor will skip the deferred proof verification step. This is useful + /// for reducing the execution time of the program and optimistically assuming that the + /// deferred proofs are correct. + /// + /// # Example + /// ```rust,no_run + /// use sp1_sdk::{ProverClient, SP1Stdin, include_elf, Prover}; + /// + /// let elf = &[1, 2, 3]; + /// let stdin = SP1Stdin::new(); + /// + /// let client = ProverClient::builder().cpu().build(); + /// let builder = client.execute(elf, &stdin) + /// .deferred_proof_verification(false) + /// .run(); + /// ``` + #[must_use] + pub fn deferred_proof_verification(mut self, value: bool) -> Self { + self.context_builder.set_skip_deferred_proof_verification(!value); + self + } + + /// Executes the program on the input with the built arguments. + /// + /// # Details + /// This method will execute the program on the input with the built arguments. If the program + /// fails to execute, the method will return an error. + /// + /// # Example + /// ```rust,no_run + /// use sp1_sdk::{ProverClient, SP1Stdin, include_elf, Prover}; + /// + /// let elf = &[1, 2, 3]; + /// let stdin = SP1Stdin::new(); + /// + /// let client = ProverClient::builder().cpu().build(); + /// let (public_values, execution_report) = client.execute(elf, &stdin) + /// .run() + /// .unwrap(); + /// ``` + pub fn run(self) -> Result<(SP1PublicValues, ExecutionReport)> { + let Self { prover, elf, stdin, mut context_builder } = self; + let context = context_builder.build(); + Ok(prover.execute(elf, &stdin, context)?) + } +} diff --git a/crates/sdk/src/cpu/mod.rs b/crates/sdk/src/cpu/mod.rs new file mode 100644 index 0000000000..c4038cae4a --- /dev/null +++ b/crates/sdk/src/cpu/mod.rs @@ -0,0 +1,342 @@ +//! # SP1 CPU Prover +//! +//! A prover that uses the CPU to execute and prove programs. + +pub mod builder; +pub mod execute; +pub mod prove; + +use anyhow::Result; +use execute::CpuExecuteBuilder; +use hashbrown::HashMap; +use p3_baby_bear::BabyBear; +use p3_field::{extension::BinomialExtensionField, AbstractField, PrimeField}; +use p3_fri::{FriProof, TwoAdicFriPcsProof}; +use prove::CpuProveBuilder; +use sp1_core_executor::{SP1Context, SP1ContextBuilder, SP1ReduceProof}; +use sp1_core_machine::io::SP1Stdin; +use sp1_prover::{ + components::CpuProverComponents, + verify::{verify_groth16_bn254_public_inputs, verify_plonk_bn254_public_inputs}, + Groth16Bn254Proof, HashableKey, PlonkBn254Proof, SP1CoreProofData, SP1ProofWithMetadata, + SP1Prover, +}; +use sp1_stark::{ + SP1CoreOpts, SP1ProverOpts, ShardCommitment, ShardOpenedValues, ShardProof, StarkVerifyingKey, +}; + +use crate::install::try_install_circuit_artifacts; +use crate::prover::verify_proof; +use crate::SP1VerificationError; +use crate::{ + Prover, SP1Proof, SP1ProofMode, SP1ProofWithPublicValues, SP1ProvingKey, SP1VerifyingKey, +}; + +/// A prover that uses the CPU to execute and prove programs. +pub struct CpuProver { + pub(crate) prover: SP1Prover, + pub(crate) mock: bool, +} + +impl CpuProver { + /// Creates a new [`CpuProver`]. + #[must_use] + pub fn new() -> Self { + Self::default() + } + + /// Creates a new [`CpuProver`] in mock mode. + #[must_use] + pub fn mock() -> Self { + Self { prover: SP1Prover::new(), mock: true } + } + + /// Creates a new [`CpuExecuteBuilder`] for simulating the execution of a program on the CPU. + /// + /// # Details + /// The builder is used for both the [`crate::cpu::CpuProver`] and [`crate::CudaProver`] client + /// types. + /// + /// # Example + /// ```rust,no_run + /// use sp1_sdk::{ProverClient, SP1Stdin, include_elf, Prover}; + /// + /// let elf = &[1, 2, 3]; + /// let stdin = SP1Stdin::new(); + /// + /// let client = ProverClient::builder().cpu().build(); + /// let (public_values, execution_report) = client.execute(elf, &stdin) + /// .run() + /// .unwrap(); + /// ``` + pub fn execute<'a>(&'a self, elf: &'a [u8], stdin: &SP1Stdin) -> CpuExecuteBuilder<'a> { + CpuExecuteBuilder { + prover: &self.prover, + elf, + stdin: stdin.clone(), + context_builder: SP1ContextBuilder::default(), + } + } + + /// Creates a new [`CpuProveBuilder`] for proving a program on the CPU. + /// + /// # Details + /// The builder is used for only the [`crate::cpu::CpuProver`] client type. + /// + /// # Example + /// ```rust,no_run + /// use sp1_sdk::{ProverClient, SP1Stdin, include_elf, Prover}; + /// + /// let elf = &[1, 2, 3]; + /// let stdin = SP1Stdin::new(); + /// + /// let client = ProverClient::builder().cpu().build(); + /// let (pk, vk) = client.setup(elf); + /// let builder = client.prove(&pk, &stdin) + /// .core() + /// .run(); + /// ``` + pub fn prove<'a>(&'a self, pk: &'a SP1ProvingKey, stdin: &SP1Stdin) -> CpuProveBuilder<'a> { + CpuProveBuilder { + prover: self, + mode: SP1ProofMode::Core, + pk, + stdin: stdin.clone(), + context_builder: SP1ContextBuilder::default(), + core_opts: SP1CoreOpts::default(), + recursion_opts: SP1CoreOpts::recursion(), + mock: self.mock, + } + } + + pub(crate) fn prove_impl<'a>( + &'a self, + pk: &SP1ProvingKey, + stdin: &SP1Stdin, + opts: SP1ProverOpts, + context: SP1Context<'a>, + mode: SP1ProofMode, + ) -> Result { + // If we're in mock mode, return a mock proof. + if self.mock { + return self.mock_prove_impl(pk, stdin.clone(), mode); + } + + // Generate the core proof. + let proof: SP1ProofWithMetadata = + self.prover.prove_core(pk, stdin, opts, context)?; + if mode == SP1ProofMode::Core { + return Ok(SP1ProofWithPublicValues { + proof: SP1Proof::Core(proof.proof.0), + public_values: proof.public_values, + sp1_version: self.version().to_string(), + }); + } + + // Generate the compressed proof. + let deferred_proofs = + stdin.proofs.iter().map(|(reduce_proof, _)| reduce_proof.clone()).collect(); + let public_values = proof.public_values.clone(); + let reduce_proof = self.prover.compress(&pk.vk, proof, deferred_proofs, opts)?; + if mode == SP1ProofMode::Compressed { + return Ok(SP1ProofWithPublicValues { + proof: SP1Proof::Compressed(Box::new(reduce_proof)), + public_values, + sp1_version: self.version().to_string(), + }); + } + + // Generate the shrink proof. + let compress_proof = self.prover.shrink(reduce_proof, opts)?; + + // Generate the wrap proof. + let outer_proof = self.prover.wrap_bn254(compress_proof, opts)?; + + // Generate the gnark proof. + match mode { + SP1ProofMode::Groth16 => { + let groth16_bn254_artifacts = if sp1_prover::build::sp1_dev_mode() { + sp1_prover::build::try_build_groth16_bn254_artifacts_dev( + &outer_proof.vk, + &outer_proof.proof, + ) + } else { + try_install_circuit_artifacts("groth16") + }; + + let proof = self.prover.wrap_groth16_bn254(outer_proof, &groth16_bn254_artifacts); + return Ok(SP1ProofWithPublicValues { + proof: SP1Proof::Groth16(proof), + public_values, + sp1_version: self.version().to_string(), + }); + } + SP1ProofMode::Plonk => { + let plonk_bn254_artifacts = if sp1_prover::build::sp1_dev_mode() { + sp1_prover::build::try_build_plonk_bn254_artifacts_dev( + &outer_proof.vk, + &outer_proof.proof, + ) + } else { + try_install_circuit_artifacts("plonk") + }; + let proof = self.prover.wrap_plonk_bn254(outer_proof, &plonk_bn254_artifacts); + return Ok(SP1ProofWithPublicValues { + proof: SP1Proof::Plonk(proof), + public_values, + sp1_version: self.version().to_string(), + }); + } + _ => unreachable!(), + } + } + + #[allow(clippy::needless_pass_by_value)] + pub(crate) fn mock_prove_impl( + &self, + pk: &SP1ProvingKey, + stdin: SP1Stdin, + mode: SP1ProofMode, + ) -> Result { + let context = SP1Context::default(); + match mode { + SP1ProofMode::Core => { + let (public_values, _) = self.prover.execute(&pk.elf, &stdin, context)?; + Ok(SP1ProofWithPublicValues { + proof: SP1Proof::Core(vec![]), + public_values, + sp1_version: self.version().to_string(), + }) + } + SP1ProofMode::Compressed => { + let (public_values, _) = self.prover.execute(&pk.elf, &stdin, context)?; + + let shard_proof = ShardProof { + commitment: ShardCommitment { + global_main_commit: [BabyBear::zero(); 8].into(), + local_main_commit: [BabyBear::zero(); 8].into(), + permutation_commit: [BabyBear::zero(); 8].into(), + quotient_commit: [BabyBear::zero(); 8].into(), + }, + opened_values: ShardOpenedValues { chips: vec![] }, + opening_proof: TwoAdicFriPcsProof { + fri_proof: FriProof { + commit_phase_commits: vec![], + query_proofs: vec![], + final_poly: BinomialExtensionField::default(), + pow_witness: BabyBear::zero(), + }, + query_openings: vec![], + }, + chip_ordering: HashMap::new(), + public_values: vec![], + }; + + let reduce_vk = StarkVerifyingKey { + commit: [BabyBear::zero(); 8].into(), + pc_start: BabyBear::zero(), + chip_information: vec![], + chip_ordering: HashMap::new(), + }; + + let proof = SP1Proof::Compressed(Box::new(SP1ReduceProof { + vk: reduce_vk, + proof: shard_proof, + })); + + Ok(SP1ProofWithPublicValues { + proof, + public_values, + sp1_version: self.version().to_string(), + }) + } + SP1ProofMode::Plonk => { + let (public_values, _) = self.prover.execute(&pk.elf, &stdin, context)?; + Ok(SP1ProofWithPublicValues { + proof: SP1Proof::Plonk(PlonkBn254Proof { + public_inputs: [ + pk.vk.hash_bn254().as_canonical_biguint().to_string(), + public_values.hash_bn254().to_string(), + ], + encoded_proof: String::new(), + raw_proof: String::new(), + plonk_vkey_hash: [0; 32], + }), + public_values, + sp1_version: self.version().to_string(), + }) + } + SP1ProofMode::Groth16 => { + let (public_values, _) = self.prover.execute(&pk.elf, &stdin, context)?; + Ok(SP1ProofWithPublicValues { + proof: SP1Proof::Groth16(Groth16Bn254Proof { + public_inputs: [ + pk.vk.hash_bn254().as_canonical_biguint().to_string(), + public_values.hash_bn254().to_string(), + ], + encoded_proof: String::new(), + raw_proof: String::new(), + groth16_vkey_hash: [0; 32], + }), + public_values, + sp1_version: self.version().to_string(), + }) + } + } + } + + fn mock_verify( + bundle: &SP1ProofWithPublicValues, + vkey: &SP1VerifyingKey, + ) -> Result<(), SP1VerificationError> { + match &bundle.proof { + SP1Proof::Plonk(PlonkBn254Proof { public_inputs, .. }) => { + verify_plonk_bn254_public_inputs(vkey, &bundle.public_values, public_inputs) + .map_err(SP1VerificationError::Plonk) + } + SP1Proof::Groth16(Groth16Bn254Proof { public_inputs, .. }) => { + verify_groth16_bn254_public_inputs(vkey, &bundle.public_values, public_inputs) + .map_err(SP1VerificationError::Groth16) + } + _ => Ok(()), + } + } +} + +impl Prover for CpuProver { + fn setup(&self, elf: &[u8]) -> (SP1ProvingKey, SP1VerifyingKey) { + self.prover.setup(elf) + } + + fn inner(&self) -> &SP1Prover { + &self.prover + } + + fn prove( + &self, + pk: &SP1ProvingKey, + stdin: &SP1Stdin, + mode: SP1ProofMode, + ) -> Result { + self.prove_impl(pk, stdin, SP1ProverOpts::default(), SP1Context::default(), mode) + } + + fn verify( + &self, + bundle: &SP1ProofWithPublicValues, + vkey: &SP1VerifyingKey, + ) -> Result<(), SP1VerificationError> { + if self.mock { + tracing::warn!("using mock verifier"); + return Self::mock_verify(bundle, vkey); + } + verify_proof(self.inner(), self.version(), bundle, vkey) + } +} + +impl Default for CpuProver { + fn default() -> Self { + let prover = SP1Prover::new(); + Self { prover, mock: false } + } +} diff --git a/crates/sdk/src/cpu/prove.rs b/crates/sdk/src/cpu/prove.rs new file mode 100644 index 0000000000..4101a8071b --- /dev/null +++ b/crates/sdk/src/cpu/prove.rs @@ -0,0 +1,296 @@ +//! # CPU Proving +//! +//! This module provides a builder for proving a program on the CPU. + +use anyhow::Result; +use sp1_core_executor::SP1ContextBuilder; +use sp1_core_machine::io::SP1Stdin; +use sp1_prover::SP1ProvingKey; +use sp1_stark::{SP1CoreOpts, SP1ProverOpts}; + +use super::CpuProver; +use crate::{SP1ProofMode, SP1ProofWithPublicValues}; + +/// A builder for proving a program on the CPU. +/// +/// This builder provides a typed interface for configuring the SP1 RISC-V prover. The builder is +/// used for only the [`crate::cpu::CpuProver`] client type. +pub struct CpuProveBuilder<'a> { + pub(crate) prover: &'a CpuProver, + pub(crate) mode: SP1ProofMode, + pub(crate) context_builder: SP1ContextBuilder<'a>, + pub(crate) pk: &'a SP1ProvingKey, + pub(crate) stdin: SP1Stdin, + pub(crate) core_opts: SP1CoreOpts, + pub(crate) recursion_opts: SP1CoreOpts, + pub(crate) mock: bool, +} + +impl<'a> CpuProveBuilder<'a> { + /// Set the proof kind to [`SP1ProofKind::Core`] mode. + /// + /// # Details + /// This is the default mode for the prover. The proofs grow linearly in size with the number + /// of cycles. + /// + /// # Example + /// ```rust,no_run + /// use sp1_sdk::{ProverClient, SP1Stdin, include_elf, Prover}; + /// + /// let elf = &[1, 2, 3]; + /// let stdin = SP1Stdin::new(); + /// + /// let client = ProverClient::builder().cpu().build(); + /// let (pk, vk) = client.setup(elf); + /// let builder = client.prove(&pk, &stdin) + /// .core() + /// .run(); + /// ``` + #[must_use] + pub fn core(mut self) -> Self { + self.mode = SP1ProofMode::Core; + self + } + + /// Set the proof kind to [`SP1ProofKind::Compressed`] mode. + /// + /// # Details + /// This mode produces a proof that is of constant size, regardless of the number of cycles. It + /// takes longer to prove than [`SP1ProofKind::Core`] due to the need to recursively aggregate + /// proofs into a single proof. + /// + /// # Example + /// ```rust,no_run + /// use sp1_sdk::{ProverClient, SP1Stdin, include_elf, Prover}; + /// + /// let elf = &[1, 2, 3]; + /// let stdin = SP1Stdin::new(); + /// + /// let client = ProverClient::builder().cpu().build(); + /// let (pk, vk) = client.setup(elf); + /// let builder = client.prove(&pk, &stdin) + /// .compressed() + /// .run(); + /// ``` + #[must_use] + pub fn compressed(mut self) -> Self { + self.mode = SP1ProofMode::Compressed; + self + } + + /// Set the proof mode to [`SP1ProofKind::Plonk`] mode. + /// + /// # Details + /// This mode produces a const size PLONK proof that can be verified on chain for roughly ~300k + /// gas. This mode is useful for producing a maximally small proof that can be verified on + /// chain. For more efficient SNARK wrapping, you can use the [`SP1ProofKind::Groth16`] mode but + /// this mode is more . + /// + /// # Example + /// ```rust,no_run + /// use sp1_sdk::{ProverClient, SP1Stdin, include_elf, Prover}; + /// + /// let elf = &[1, 2, 3]; + /// let stdin = SP1Stdin::new(); + /// + /// let client = ProverClient::builder().cpu().build(); + /// let (pk, vk) = client.setup(elf); + /// let builder = client.prove(&pk, &stdin) + /// .plonk() + /// .run(); + /// ``` + #[must_use] + pub fn plonk(mut self) -> Self { + self.mode = SP1ProofMode::Plonk; + self + } + + /// Set the proof mode to [`SP1ProofKind::Groth16`] mode. + /// + /// # Details + /// This mode produces a Groth16 proof that can be verified on chain for roughly ~100k gas. This + /// mode is useful for producing a proof that can be verified on chain with minimal gas. + /// + /// # Example + /// ```rust,no_run + /// use sp1_sdk::{ProverClient, SP1Stdin, include_elf, Prover}; + /// + /// let elf = &[1, 2, 3]; + /// let stdin = SP1Stdin::new(); + /// + /// let client = ProverClient::builder().cpu().build(); + /// let (pk, vk) = client.setup(elf); + /// let builder = client.prove(&pk, &stdin) + /// .groth16() + /// .run(); + /// ``` + #[must_use] + pub fn groth16(mut self) -> Self { + self.mode = SP1ProofMode::Groth16; + self + } + + /// Set the proof mode to the given [`SP1ProofKind`]. + /// + /// # Details + /// This method is useful for setting the proof mode to a custom mode. + /// + /// # Example + /// ```rust,no_run + /// use sp1_sdk::{ProverClient, SP1Stdin, include_elf, Prover, SP1ProofMode}; + /// + /// let elf = &[1, 2, 3]; + /// let stdin = SP1Stdin::new(); + /// + /// let client = ProverClient::builder().cpu().build(); + /// let (pk, vk) = client.setup(elf); + /// let builder = client.prove(&pk, &stdin) + /// .mode(SP1ProofMode::Groth16) + /// .run(); + /// ``` + #[must_use] + pub fn mode(mut self, mode: SP1ProofMode) -> Self { + self.mode = mode; + self + } + + /// Set the shard size for proving. + /// + /// # Details + /// The value should be 2^16, 2^17, ..., 2^22. You must be careful to set this value + /// correctly, as it will affect the memory usage of the prover and the recursion/verification + /// complexity. By default, the value is set to some predefined values that are optimized for performance + /// based on the available amount of RAM on the system. + /// + /// # Example + /// ```rust,no_run + /// use sp1_sdk::{ProverClient, SP1Stdin, include_elf, Prover}; + /// + /// let elf = &[1, 2, 3]; + /// let stdin = SP1Stdin::new(); + /// + /// let client = ProverClient::builder().cpu().build(); + /// let (pk, vk) = client.setup(elf); + /// let builder = client.prove(&pk, &stdin) + /// .shard_size(1 << 16) + /// .run(); + /// ``` + #[must_use] + pub fn shard_size(mut self, value: usize) -> Self { + assert!(value.is_power_of_two(), "shard size must be a power of 2"); + self.core_opts.shard_size = value; + self + } + + /// Set the shard batch size for proving. + /// + /// # Details + /// This is the number of shards that are processed in a single batch in the prover. You should + /// probably not change this value unless you know what you are doing. + /// + /// # Example + /// ```rust,no_run + /// use sp1_sdk::{ProverClient, SP1Stdin, include_elf, Prover}; + /// + /// let elf = &[1, 2, 3]; + /// let stdin = SP1Stdin::new(); + /// + /// let client = ProverClient::builder().cpu().build(); + /// let (pk, vk) = client.setup(elf); + /// let builder = client.prove(&pk, &stdin) + /// .shard_batch_size(4) + /// .run(); + /// ``` + #[must_use] + pub fn shard_batch_size(mut self, value: usize) -> Self { + self.core_opts.shard_batch_size = value; + self + } + + /// Set the maximum number of cpu cycles to use for execution. + /// + /// # Details + /// If the cycle limit is exceeded, execution will return + /// [`sp1_core_executor::ExecutionError::ExceededCycleLimit`]. + /// + /// # Example + /// ```rust,no_run + /// use sp1_sdk::{ProverClient, SP1Stdin, include_elf, Prover}; + /// + /// let elf = &[1, 2, 3]; + /// let stdin = SP1Stdin::new(); + /// + /// let client = ProverClient::builder().cpu().build(); + /// let (pk, vk) = client.setup(elf); + /// let builder = client.prove(&pk, &stdin) + /// .cycle_limit(1000000) + /// .run(); + /// ``` + #[must_use] + pub fn cycle_limit(mut self, cycle_limit: u64) -> Self { + self.context_builder.max_cycles(cycle_limit); + self + } + + /// Set the skip deferred proof verification flag. + /// + /// # Details + /// If set to `true`, the prover will skip the deferred proof verification step in the executor. + /// This is useful for reducing the amount of time it takes to execute the program. + /// + /// # Example + /// ```rust,no_run + /// use sp1_sdk::{ProverClient, SP1Stdin, include_elf, Prover}; + /// + /// let elf = &[1, 2, 3]; + /// let stdin = SP1Stdin::new(); + /// + /// let client = ProverClient::builder().cpu().build(); + /// let (pk, vk) = client.setup(elf); + /// let builder = client.prove(&pk, &stdin) + /// .deferred_proof_verification(false) + /// .run(); + /// ``` + #[must_use] + pub fn deferred_proof_verification(mut self, value: bool) -> Self { + self.context_builder.set_skip_deferred_proof_verification(value); + self + } + + /// Run the prover with the built arguments. + /// + /// # Details + /// This method will run the prover with the built arguments. If the prover fails to run, the + /// method will return an error. + /// + /// # Example + /// ```rust,no_run + /// use sp1_sdk::{ProverClient, SP1Stdin, include_elf, Prover}; + /// + /// let elf = &[1, 2, 3]; + /// let stdin = SP1Stdin::new(); + /// + /// let client = ProverClient::builder().cpu().build(); + /// let (pk, vk) = client.setup(elf); + /// let proof = client.prove(&pk, &stdin) + /// .run() + /// .unwrap(); + /// ``` + pub fn run(self) -> Result { + // Get the arguments. + let Self { prover, mode, pk, stdin, mut context_builder, core_opts, recursion_opts, mock } = + self; + let opts = SP1ProverOpts { core_opts, recursion_opts }; + let context = context_builder.build(); + + // Dump the program and stdin to files for debugging if `SP1_DUMP` is set. + crate::utils::sp1_dump(&pk.elf, &stdin); + + // Run the prover. + if mock { + prover.mock_prove_impl(pk, stdin, mode) + } else { + prover.prove_impl(pk, &stdin, opts, context, mode) + } + } +} diff --git a/crates/sdk/src/cuda/builder.rs b/crates/sdk/src/cuda/builder.rs new file mode 100644 index 0000000000..a447d3f78b --- /dev/null +++ b/crates/sdk/src/cuda/builder.rs @@ -0,0 +1,31 @@ +//! # CPU Prover Builder +//! +//! This module provides a builder for the [`CpuProver`]. + +use sp1_prover::SP1Prover; + +use super::CudaProver; + +/// A builder for the [`CudaProver`]. +/// +/// The builder is used to configure the [`CudaProver`] before it is built. +pub struct CudaProverBuilder; + +impl CudaProverBuilder { + /// Builds a [`CudaProver`]. + /// + /// # Details + /// This method will build a [`CudaProver`] with the given parameters. In particular, it will + /// build a mock prover if the `mock` flag is set. + /// + /// # Example + /// ```rust,no_run + /// use sp1_sdk::ProverClient; + /// + /// let prover = ProverClient::builder().cuda().build(); + /// ``` + #[must_use] + pub fn build(self) -> CudaProver { + CudaProver::new(SP1Prover::new()) + } +} diff --git a/crates/sdk/src/cuda/mod.rs b/crates/sdk/src/cuda/mod.rs new file mode 100644 index 0000000000..c20a8e6dfc --- /dev/null +++ b/crates/sdk/src/cuda/mod.rs @@ -0,0 +1,172 @@ +//! # SP1 CUDA Prover +//! +//! A prover that uses the CUDA to execute and prove programs. + +pub mod builder; +pub mod prove; + +use anyhow::Result; +use prove::CudaProveBuilder; +use sp1_core_executor::SP1ContextBuilder; +use sp1_core_machine::io::SP1Stdin; +use sp1_cuda::SP1CudaProver; +use sp1_prover::{components::CpuProverComponents, SP1Prover}; + +use crate::cpu::execute::CpuExecuteBuilder; +use crate::install::try_install_circuit_artifacts; +use crate::{ + Prover, SP1Proof, SP1ProofMode, SP1ProofWithPublicValues, SP1ProvingKey, SP1VerifyingKey, +}; + +/// A prover that uses the CPU for execution and the CUDA for proving. +pub struct CudaProver { + pub(crate) cpu_prover: SP1Prover, + pub(crate) cuda_prover: SP1CudaProver, +} + +impl CudaProver { + /// Creates a new [`CudaProver`]. + pub fn new(prover: SP1Prover) -> Self { + let cuda_prover = SP1CudaProver::new(); + Self { + cpu_prover: prover, + cuda_prover: cuda_prover.expect("Failed to initialize CUDA prover"), + } + } + + /// Creates a new [`CpuExecuteBuilder`] for simulating the execution of a program on the CPU. + /// + /// # Details + /// The builder is used for both the [`crate::cpu::CpuProver`] and [`crate::CudaProver`] client + /// types. + /// + /// # Example + /// ```rust,no_run + /// use sp1_sdk::{ProverClient, SP1Stdin, include_elf, Prover}; + /// + /// let elf = &[1, 2, 3]; + /// let stdin = SP1Stdin::new(); + /// + /// let client = ProverClient::builder().cuda().build(); + /// let (public_values, execution_report) = client.execute(elf, &stdin) + /// .run() + /// .unwrap(); + /// ``` + pub fn execute<'a>(&'a self, elf: &'a [u8], stdin: &SP1Stdin) -> CpuExecuteBuilder<'a> { + CpuExecuteBuilder { + prover: &self.cpu_prover, + elf, + stdin: stdin.clone(), + context_builder: SP1ContextBuilder::default(), + } + } + + /// Creates a new [`CudaProveBuilder`] for proving a program on the CUDA. + /// + /// # Details + /// The builder is used for only the [`crate::CudaProver`] client type. + /// + /// # Example + /// ```rust,no_run + /// use sp1_sdk::{ProverClient, SP1Stdin, include_elf, Prover}; + /// + /// let elf = &[1, 2, 3]; + /// let stdin = SP1Stdin::new(); + /// + /// let client = ProverClient::builder().cuda().build(); + /// let (pk, vk) = client.setup(elf); + /// let proof = client.prove(&pk, &stdin) + /// .run() + /// .unwrap(); + /// ``` + pub fn prove<'a>(&'a self, pk: &'a SP1ProvingKey, stdin: &'a SP1Stdin) -> CudaProveBuilder<'a> { + CudaProveBuilder { prover: self, mode: SP1ProofMode::Core, pk, stdin: stdin.clone() } + } +} + +impl Prover for CudaProver { + fn setup(&self, elf: &[u8]) -> (SP1ProvingKey, SP1VerifyingKey) { + self.cpu_prover.setup(elf) + } + + fn inner(&self) -> &SP1Prover { + &self.cpu_prover + } + + fn prove( + &self, + pk: &SP1ProvingKey, + stdin: &SP1Stdin, + kind: SP1ProofMode, + ) -> Result { + // Generate the core proof. + let proof = self.cuda_prover.prove_core(pk, stdin)?; + if kind == SP1ProofMode::Core { + return Ok(SP1ProofWithPublicValues { + proof: SP1Proof::Core(proof.proof.0), + public_values: proof.public_values, + sp1_version: self.version().to_string(), + }); + } + + // Generate the compressed proof. + let deferred_proofs = + stdin.proofs.iter().map(|(reduce_proof, _)| reduce_proof.clone()).collect(); + let public_values = proof.public_values.clone(); + let reduce_proof = self.cuda_prover.compress(&pk.vk, proof, deferred_proofs)?; + if kind == SP1ProofMode::Compressed { + return Ok(SP1ProofWithPublicValues { + proof: SP1Proof::Compressed(Box::new(reduce_proof)), + public_values, + sp1_version: self.version().to_string(), + }); + } + + // Generate the shrink proof. + let compress_proof = self.cuda_prover.shrink(reduce_proof)?; + + // Genenerate the wrap proof. + let outer_proof = self.cuda_prover.wrap_bn254(compress_proof)?; + + if kind == SP1ProofMode::Plonk { + let plonk_bn254_artifacts = if sp1_prover::build::sp1_dev_mode() { + sp1_prover::build::try_build_plonk_bn254_artifacts_dev( + &outer_proof.vk, + &outer_proof.proof, + ) + } else { + try_install_circuit_artifacts("plonk") + }; + let proof = self.cpu_prover.wrap_plonk_bn254(outer_proof, &plonk_bn254_artifacts); + return Ok(SP1ProofWithPublicValues { + proof: SP1Proof::Plonk(proof), + public_values, + sp1_version: self.version().to_string(), + }); + } else if kind == SP1ProofMode::Groth16 { + let groth16_bn254_artifacts = if sp1_prover::build::sp1_dev_mode() { + sp1_prover::build::try_build_groth16_bn254_artifacts_dev( + &outer_proof.vk, + &outer_proof.proof, + ) + } else { + try_install_circuit_artifacts("groth16") + }; + + let proof = self.cpu_prover.wrap_groth16_bn254(outer_proof, &groth16_bn254_artifacts); + return Ok(SP1ProofWithPublicValues { + proof: SP1Proof::Groth16(proof), + public_values, + sp1_version: self.version().to_string(), + }); + } + + unreachable!() + } +} + +impl Default for CudaProver { + fn default() -> Self { + Self::new(SP1Prover::new()) + } +} diff --git a/crates/sdk/src/cuda/prove.rs b/crates/sdk/src/cuda/prove.rs new file mode 100644 index 0000000000..642dd97535 --- /dev/null +++ b/crates/sdk/src/cuda/prove.rs @@ -0,0 +1,178 @@ +//! # CUDA Proving +//! +//! This module provides a builder for proving a program on the CUDA. + +use anyhow::Result; +use sp1_core_machine::io::SP1Stdin; +use sp1_prover::{components::CpuProverComponents, SP1ProvingKey}; + +use super::CudaProver; +use crate::{Prover, SP1ProofMode, SP1ProofWithPublicValues}; + +/// A builder for proving a program on the CUDA. +/// +/// This builder provides a typed interface for configuring the SP1 RISC-V prover. The builder is +/// used for only the [`crate::cuda::CudaProver`] client type. +pub struct CudaProveBuilder<'a> { + pub(crate) prover: &'a CudaProver, + pub(crate) mode: SP1ProofMode, + pub(crate) pk: &'a SP1ProvingKey, + pub(crate) stdin: SP1Stdin, +} + +impl<'a> CudaProveBuilder<'a> { + /// Set the proof kind to [`SP1ProofMode::Core`] mode. + /// + /// # Details + /// This is the default mode for the prover. The proofs grow linearly in size with the number + /// of cycles. + /// + /// # Example + /// ```rust,no_run + /// use sp1_sdk::{ProverClient, SP1Stdin, include_elf, Prover}; + /// + /// let elf = &[1, 2, 3]; + /// let stdin = SP1Stdin::new(); + /// + /// let client = ProverClient::builder().cuda().build(); + /// let (pk, vk) = client.setup(elf); + /// let builder = client.prove(&pk, &stdin) + /// .core() + /// .run(); + /// ``` + #[must_use] + pub fn core(mut self) -> Self { + self.mode = SP1ProofMode::Core; + self + } + + /// Set the proof kind to [`SP1ProofMode::Compressed`] mode. + /// + /// # Details + /// This mode produces a proof that is of constant size, regardless of the number of cycles. It + /// takes longer to prove than [`SP1ProofMode::Core`] due to the need to recursively aggregate + /// proofs into a single proof. + /// + /// # Example + /// ```rust,no_run + /// use sp1_sdk::{ProverClient, SP1Stdin, include_elf, Prover}; + /// + /// let elf = &[1, 2, 3]; + /// let stdin = SP1Stdin::new(); + /// + /// let client = ProverClient::builder().cuda().build(); + /// let (pk, vk) = client.setup(elf); + /// let builder = client.prove(&pk, &stdin) + /// .compressed() + /// .run(); + /// ``` + #[must_use] + pub fn compressed(mut self) -> Self { + self.mode = SP1ProofMode::Compressed; + self + } + + /// Set the proof mode to [`SP1ProofMode::Plonk`] mode. + /// + /// # Details + /// This mode produces a const size PLONK proof that can be verified on chain for roughly ~300k + /// gas. This mode is useful for producing a maximally small proof that can be verified on + /// chain. For more efficient SNARK wrapping, you can use the [`SP1ProofMode::Groth16`] mode but + /// this mode is more . + /// + /// # Example + /// ```rust,no_run + /// use sp1_sdk::{ProverClient, SP1Stdin, include_elf, Prover}; + /// + /// let elf = &[1, 2, 3]; + /// let stdin = SP1Stdin::new(); + /// + /// let client = ProverClient::builder().cuda().build(); + /// let (pk, vk) = client.setup(elf); + /// let builder = client.prove(&pk, &stdin) + /// .plonk() + /// .run(); + /// ``` + #[must_use] + pub fn plonk(mut self) -> Self { + self.mode = SP1ProofMode::Plonk; + self + } + + /// Set the proof mode to [`SP1ProofMode::Groth16`] mode. + /// + /// # Details + /// This mode produces a Groth16 proof that can be verified on chain for roughly ~100k gas. This + /// mode is useful for producing a proof that can be verified on chain with minimal gas. + /// + /// # Example + /// ```rust,no_run + /// use sp1_sdk::{ProverClient, SP1Stdin, include_elf, Prover}; + /// + /// let elf = &[1, 2, 3]; + /// let stdin = SP1Stdin::new(); + /// + /// let client = ProverClient::builder().cuda().build(); + /// let (pk, vk) = client.setup(elf); + /// let builder = client.prove(&pk, &stdin) + /// .groth16() + /// .run(); + /// ``` + #[must_use] + pub fn groth16(mut self) -> Self { + self.mode = SP1ProofMode::Groth16; + self + } + + /// Set the proof mode to the given [`SP1ProofMode`]. + /// + /// # Details + /// This method is useful for setting the proof mode to a custom mode. + /// + /// # Example + /// ```rust,no_run + /// use sp1_sdk::{ProverClient, SP1Stdin, include_elf, SP1ProofMode, Prover}; + /// + /// let elf = &[1, 2, 3]; + /// let stdin = SP1Stdin::new(); + /// + /// let client = ProverClient::builder().cuda().build(); + /// let (pk, vk) = client.setup(elf); + /// let builder = client.prove(&pk, &stdin) + /// .mode(SP1ProofMode::Groth16) + /// .run(); + /// ``` + #[must_use] + pub fn mode(mut self, mode: SP1ProofMode) -> Self { + self.mode = mode; + self + } + + /// Run the prover with the built arguments. + /// + /// # Details + /// This method will run the prover with the built arguments. If the prover fails to run, the + /// method will return an error. + /// + /// # Example + /// ```rust,no_run + /// use sp1_sdk::{ProverClient, SP1Stdin, include_elf, Prover}; + /// + /// let elf = &[1, 2, 3]; + /// let stdin = SP1Stdin::new(); + /// + /// let client = ProverClient::builder().cuda().build(); + /// let (pk, vk) = client.setup(elf); + /// let proof = client.prove(&pk, &stdin) + /// .run() + /// .unwrap(); + /// ``` + pub fn run(self) -> Result { + let Self { prover, mode: kind, pk, stdin } = self; + + // Dump the program and stdin to files for debugging if `SP1_DUMP` is set. + crate::utils::sp1_dump(&pk.elf, &stdin); + + Prover::::prove(prover, pk, &stdin, kind) + } +} diff --git a/crates/sdk/src/env/mod.rs b/crates/sdk/src/env/mod.rs new file mode 100644 index 0000000000..26bc967cb3 --- /dev/null +++ b/crates/sdk/src/env/mod.rs @@ -0,0 +1,192 @@ +//! # SP1 Environment Prover +//! +//! A prover that can execute programs and generate proofs with a different implementation based on +//! the value of certain environment variables. + +mod prove; + +use std::env; + +use anyhow::Result; +use prove::EnvProveBuilder; +use sp1_core_executor::SP1ContextBuilder; +use sp1_core_machine::io::SP1Stdin; +use sp1_prover::{components::CpuProverComponents, SP1Prover, SP1ProvingKey, SP1VerifyingKey}; + +use super::{Prover, SP1VerificationError}; +use crate::cpu::execute::CpuExecuteBuilder; +use crate::cpu::CpuProver; +use crate::cuda::CudaProver; +use crate::network::builder::NetworkProverBuilder; +use crate::{SP1ProofMode, SP1ProofWithPublicValues}; + +/// A prover that can execute programs and generate proofs with a different implementation based on +/// the value of certain environment variables. +/// +/// The environment variables are described in [`EnvProver::new`]. +pub struct EnvProver { + pub(crate) prover: Box>, +} + +impl EnvProver { + /// Creates a new [`EnvProver`] with the given configuration. + /// + /// The following environment variables are used to configure the prover: + /// - `SP1_PROVER`: The type of prover to use. Must be one of `mock`, `local`, `cuda`, or `network`. + /// - `NETWORK_PRIVATE_KEY`: The private key to use for the network prover. + /// - `NETWORK_RPC_URL`: The RPC URL to use for the network prover. + #[must_use] + pub fn new() -> Self { + let mode = if let Ok(mode) = env::var("SP1_PROVER") { + mode + } else { + log::warn!("SP1_PROVER environment variable not set, defaulting to 'cpu'"); + "cpu".to_string() + }; + + let prover: Box> = match mode.as_str() { + "mock" => Box::new(CpuProver::mock()), + "cpu" => Box::new(CpuProver::new()), + "cuda" => { + #[cfg(not(feature = "cuda"))] + panic!( + "The CUDA prover requires the 'cuda' feature to be enabled. \ + Please enable it in your Cargo.toml with: \ + sp1-sdk = { version = \"...\", features = [\"cuda\"] }" + ); + + #[cfg(feature = "cuda")] + Box::new(CudaProver::new(SP1Prover::new())) + } + "network" => { + #[cfg(not(feature = "network"))] + panic!( + "The network prover requires the 'network' feature to be enabled. \ + Please enable it in your Cargo.toml with: \ + sp1-sdk = { version = \"...\", features = [\"network\"] }" + ); + + #[cfg(feature = "network")] + { + Box::new(NetworkProverBuilder::default().build()) + } + } + _ => panic!( + "Invalid SP1_PROVER value. Expected one of: mock, cpu, cuda, or network. Got: '{mode}'.\n\ + Please set the SP1_PROVER environment variable to one of the supported values." + ), + }; + EnvProver { prover } + } + + /// Creates a new [`CpuExecuteBuilder`] for simulating the execution of a program on the CPU. + /// + /// # Details + /// The builder is used for both the [`crate::cpu::CpuProver`] and [`crate::CudaProver`] client + /// types. + /// + /// # Example + /// ```rust,no_run + /// use sp1_sdk::{ProverClient, SP1Stdin, Prover}; + /// + /// let elf = &[1, 2, 3]; + /// let stdin = SP1Stdin::new(); + /// + /// let client = ProverClient::from_env(); + /// let (public_values, execution_report) = client.execute(elf, &stdin) + /// .run() + /// .unwrap(); + /// ``` + #[must_use] + pub fn execute<'a>(&'a self, elf: &'a [u8], stdin: &SP1Stdin) -> CpuExecuteBuilder<'a> { + CpuExecuteBuilder { + prover: self.prover.inner(), + elf, + stdin: stdin.clone(), + context_builder: SP1ContextBuilder::default(), + } + } + + /// Creates a new [`EnvProve`] for proving a program on the CPU. + /// + /// # Details + /// The builder is used for only the [`crate::cpu::CpuProver`] client type. + /// + /// # Example + /// ```rust,no_run + /// use sp1_sdk::{ProverClient, SP1Stdin, Prover}; + /// + /// let elf = &[1, 2, 3]; + /// let stdin = SP1Stdin::new(); + /// + /// let client = ProverClient::from_env(); + /// let (pk, vk) = client.setup(elf); + /// let builder = client.prove(&pk, &stdin) + /// .core() + /// .run(); + /// ``` + #[must_use] + pub fn prove<'a>(&'a self, pk: &'a SP1ProvingKey, stdin: &'a SP1Stdin) -> EnvProveBuilder<'a> { + EnvProveBuilder { + prover: self.prover.as_ref(), + mode: SP1ProofMode::Core, + pk, + stdin: stdin.clone(), + } + } + + /// Verifies that the given proof is valid and matches the given verification key produced by + /// [`Self::setup`]. + /// + /// ### Examples + /// ```no_run + /// use sp1_sdk::{ProverClient, SP1Stdin}; + /// + /// let elf = test_artifacts::FIBONACCI_ELF; + /// let stdin = SP1Stdin::new(); + /// + /// let client = ProverClient::from_env(); + /// let (pk, vk) = client.setup(elf); + /// let proof = client.prove(&pk, &stdin).run().unwrap(); + /// client.verify(&proof, &vk).unwrap(); + /// ``` + pub fn verify( + &self, + proof: &SP1ProofWithPublicValues, + vk: &SP1VerifyingKey, + ) -> Result<(), SP1VerificationError> { + self.prover.verify(proof, vk) + } + + /// Setup a program to be proven and verified by the SP1 RISC-V zkVM by computing the proving + /// and verifying keys. + #[must_use] + pub fn setup(&self, elf: &[u8]) -> (SP1ProvingKey, SP1VerifyingKey) { + self.prover.setup(elf) + } +} + +impl Default for EnvProver { + fn default() -> Self { + Self::new() + } +} + +impl Prover for EnvProver { + fn inner(&self) -> &SP1Prover { + self.prover.inner() + } + + fn setup(&self, elf: &[u8]) -> (SP1ProvingKey, SP1VerifyingKey) { + self.prover.setup(elf) + } + + fn prove( + &self, + pk: &SP1ProvingKey, + stdin: &SP1Stdin, + mode: SP1ProofMode, + ) -> Result { + self.prover.prove(pk, stdin, mode) + } +} diff --git a/crates/sdk/src/env/prove.rs b/crates/sdk/src/env/prove.rs new file mode 100644 index 0000000000..74cc78eba2 --- /dev/null +++ b/crates/sdk/src/env/prove.rs @@ -0,0 +1,166 @@ +use anyhow::Result; +use sp1_core_machine::io::SP1Stdin; +use sp1_prover::{components::CpuProverComponents, SP1ProvingKey}; + +use crate::{Prover, SP1ProofMode, SP1ProofWithPublicValues}; + +/// Builder to prepare and configure proving execution of a program on an input. +/// May be run with [`Self::run`]. +pub struct EnvProveBuilder<'a> { + pub(crate) prover: &'a dyn Prover, + pub(crate) mode: SP1ProofMode, + pub(crate) pk: &'a SP1ProvingKey, + pub(crate) stdin: SP1Stdin, +} + +impl<'a> EnvProveBuilder<'a> { + /// Set the proof kind to [`SP1ProofMode::Core`] mode. + /// + /// # Details + /// This is the default mode for the prover. The proofs grow linearly in size with the number + /// of cycles. + /// + /// # Example + /// ```rust,no_run + /// use sp1_sdk::{ProverClient, SP1Stdin, Prover}; + /// + /// let elf = &[1, 2, 3]; + /// let stdin = SP1Stdin::new(); + /// + /// let client = ProverClient::from_env(); + /// let (pk, vk) = client.setup(elf); + /// let builder = client.prove(&pk, &stdin) + /// .core() + /// .run(); + /// ``` + pub fn core(mut self) -> Self { + self.mode = SP1ProofMode::Core; + self + } + + /// Set the proof kind to [`SP1ProofMode::Compressed`] mode. + /// + /// # Details + /// This mode produces a proof that is of constant size, regardless of the number of cycles. It + /// takes longer to prove than [`SP1ProofMode::Core`] due to the need to recursively aggregate + /// proofs into a single proof. + /// + /// # Example + /// ```rust,no_run + /// use sp1_sdk::{ProverClient, SP1Stdin, Prover}; + /// + /// let elf = &[1, 2, 3]; + /// let stdin = SP1Stdin::new(); + /// + /// let client = ProverClient::from_env(); + /// let (pk, vk) = client.setup(elf); + /// let builder = client.prove(&pk, &stdin) + /// .compressed() + /// .run(); + /// ``` + pub fn compressed(mut self) -> Self { + self.mode = SP1ProofMode::Compressed; + self + } + + /// Set the proof mode to [`SP1ProofMode::Plonk`] mode. + /// + /// # Details + /// This mode produces a const size PLONK proof that can be verified on chain for roughly ~300k + /// gas. This mode is useful for producing a maximally small proof that can be verified on + /// chain. For more efficient SNARK wrapping, you can use the [`SP1ProofMode::Groth16`] mode but + /// this mode is more . + /// + /// # Example + /// ```rust,no_run + /// use sp1_sdk::{ProverClient, SP1Stdin, Prover}; + /// + /// let elf = &[1, 2, 3]; + /// let stdin = SP1Stdin::new(); + /// + /// let client = ProverClient::from_env(); + /// let (pk, vk) = client.setup(elf); + /// let builder = client.prove(&pk, &stdin) + /// .plonk() + /// .run(); + /// ``` + pub fn plonk(mut self) -> Self { + self.mode = SP1ProofMode::Plonk; + self + } + + /// Set the proof mode to [`SP1ProofMode::Groth16`] mode. + /// + /// # Details + /// This mode produces a Groth16 proof that can be verified on chain for roughly ~100k gas. This + /// mode is useful for producing a proof that can be verified on chain with minimal gas. + /// + /// # Example + /// ```rust,no_run + /// use sp1_sdk::{ProverClient, SP1Stdin, Prover}; + /// + /// let elf = &[1, 2, 3]; + /// let stdin = SP1Stdin::new(); + /// + /// let client = ProverClient::from_env(); + /// let (pk, vk) = client.setup(elf); + /// let builder = client.prove(&pk, &stdin) + /// .groth16() + /// .run(); + /// ``` + pub fn groth16(mut self) -> Self { + self.mode = SP1ProofMode::Groth16; + self + } + + /// Set the proof mode to the given [`SP1ProofMode`]. + /// + /// # Details + /// This method is useful for setting the proof mode to a custom mode. + /// + /// # Example + /// ```rust,no_run + /// use sp1_sdk::{ProverClient, SP1Stdin, Prover, SP1ProofMode}; + /// + /// let elf = &[1, 2, 3]; + /// let stdin = SP1Stdin::new(); + /// + /// let client = ProverClient::from_env(); + /// let (pk, vk) = client.setup(elf); + /// let builder = client.prove(&pk, &stdin) + /// .mode(SP1ProofMode::Groth16) + /// .run(); + /// ``` + pub fn mode(mut self, mode: SP1ProofMode) -> Self { + self.mode = mode; + self + } + + /// Run the prover with the built arguments. + /// + /// # Details + /// This method will run the prover with the built arguments. If the prover fails to run, the + /// method will return an error. + /// + /// # Example + /// ```rust,no_run + /// use sp1_sdk::{ProverClient, SP1Stdin, Prover}; + /// + /// let elf = &[1, 2, 3]; + /// let stdin = SP1Stdin::new(); + /// + /// let client = ProverClient::from_env(); + /// let (pk, vk) = client.setup(elf); + /// let proof = client.prove(&pk, &stdin) + /// .run() + /// .unwrap(); + /// ``` + pub fn run(self) -> Result { + let Self { prover, mode: kind, pk, stdin } = self; + + // Dump the program and stdin to files for debugging if `SP1_DUMP` is set. + crate::utils::sp1_dump(&pk.elf, &stdin); + + prover.prove(pk, &stdin, kind) + } +} diff --git a/crates/sdk/src/install.rs b/crates/sdk/src/install.rs index b3207664ba..51857f32ca 100644 --- a/crates/sdk/src/install.rs +++ b/crates/sdk/src/install.rs @@ -1,13 +1,17 @@ +//! # SP1 Install +//! +//! A library for installing the SP1 circuit artifacts. + use cfg_if::cfg_if; use std::path::PathBuf; -#[cfg(any(feature = "network", feature = "network-v2"))] +#[cfg(any(feature = "network", feature = "network"))] use { - crate::block_on, + crate::utils::block_on, futures::StreamExt, indicatif::{ProgressBar, ProgressStyle}, reqwest::Client, - std::{cmp::min, io::Write, process::Command}, + std::{cmp::min, process::Command}, }; use crate::SP1_CIRCUIT_VERSION; @@ -16,16 +20,19 @@ use crate::SP1_CIRCUIT_VERSION; pub const CIRCUIT_ARTIFACTS_URL_BASE: &str = "https://sp1-circuits.s3-us-east-2.amazonaws.com"; /// The directory where the groth16 circuit artifacts will be stored. +#[must_use] pub fn groth16_circuit_artifacts_dir() -> PathBuf { dirs::home_dir().unwrap().join(".sp1").join("circuits/groth16").join(SP1_CIRCUIT_VERSION) } /// The directory where the plonk circuit artifacts will be stored. +#[must_use] pub fn plonk_circuit_artifacts_dir() -> PathBuf { dirs::home_dir().unwrap().join(".sp1").join("circuits/plonk").join(SP1_CIRCUIT_VERSION) } /// Tries to install the groth16 circuit artifacts if they are not already installed. +#[must_use] pub fn try_install_circuit_artifacts(artifacts_type: &str) -> PathBuf { let build_dir = if artifacts_type == "groth16" { groth16_circuit_artifacts_dir() @@ -43,7 +50,7 @@ pub fn try_install_circuit_artifacts(artifacts_type: &str) -> PathBuf { ); } else { cfg_if! { - if #[cfg(any(feature = "network", feature = "network-v2"))] { + if #[cfg(any(feature = "network", feature = "network"))] { println!( "[sp1] {} circuit artifacts for version {} do not exist at {}. downloading...", artifacts_type, @@ -60,15 +67,16 @@ pub fn try_install_circuit_artifacts(artifacts_type: &str) -> PathBuf { /// Install the latest circuit artifacts. /// /// This function will download the latest circuit artifacts from the S3 bucket and extract them -/// to the directory specified by [groth16_bn254_artifacts_dir()]. -#[cfg(any(feature = "network", feature = "network-v2"))] +/// to the directory specified by [`groth16_bn254_artifacts_dir()`]. +#[cfg(any(feature = "network", feature = "network"))] +#[allow(clippy::needless_pass_by_value)] pub fn install_circuit_artifacts(build_dir: PathBuf, artifacts_type: &str) { // Create the build directory. std::fs::create_dir_all(&build_dir).expect("failed to create build directory"); // Download the artifacts. let download_url = - format!("{}/{}-{}.tar.gz", CIRCUIT_ARTIFACTS_URL_BASE, SP1_CIRCUIT_VERSION, artifacts_type); + format!("{CIRCUIT_ARTIFACTS_URL_BASE}/{SP1_CIRCUIT_VERSION}-{artifacts_type}.tar.gz"); let mut artifacts_tar_gz_file = tempfile::NamedTempFile::new().expect("failed to create tempfile"); let client = Client::builder().build().expect("failed to create reqwest client"); @@ -91,11 +99,11 @@ pub fn install_circuit_artifacts(build_dir: PathBuf, artifacts_type: &str) { } /// Download the file with a progress bar that indicates the progress. -#[cfg(any(feature = "network", feature = "network-v2"))] +#[cfg(any(feature = "network", feature = "network"))] pub async fn download_file( client: &Client, url: &str, - file: &mut tempfile::NamedTempFile, + file: &mut impl std::io::Write, ) -> std::result::Result<(), String> { let res = client.get(url).send().await.or(Err(format!("Failed to GET from '{}'", &url)))?; diff --git a/crates/sdk/src/lib.rs b/crates/sdk/src/lib.rs index 7b7bb96f2b..08d3ccecbd 100644 --- a/crates/sdk/src/lib.rs +++ b/crates/sdk/src/lib.rs @@ -2,45 +2,61 @@ //! //! A library for interacting with the SP1 RISC-V zkVM. //! -//! Visit the [Getting Started](https://succinctlabs.github.io/sp1/getting-started.html) section +//! Visit the [Getting Started](https://docs.succinct.xyz/docs/getting-started/install) section //! in the official SP1 documentation for a quick start guide. -pub mod action; +#![warn(clippy::pedantic)] +#![allow(clippy::similar_names)] +#![allow(clippy::cast_possible_wrap)] +#![allow(clippy::cast_possible_truncation)] +#![allow(clippy::cast_sign_loss)] +#![allow(clippy::module_name_repetitions)] +#![allow(clippy::needless_range_loop)] +#![allow(clippy::cast_lossless)] +#![allow(clippy::bool_to_int_with_if)] +#![allow(clippy::should_panic_without_expect)] +#![allow(clippy::field_reassign_with_default)] +#![allow(clippy::manual_assert)] +#![allow(clippy::unreadable_literal)] +#![allow(clippy::match_wildcard_for_single_variants)] +#![allow(clippy::missing_panics_doc)] +#![allow(clippy::missing_errors_doc)] +#![allow(clippy::explicit_iter_loop)] +#![warn(missing_docs)] + pub mod artifacts; +pub mod client; +pub mod cpu; +pub mod cuda; +pub mod env; pub mod install; #[cfg(feature = "network")] pub mod network; -#[cfg(feature = "network-v2")] -#[path = "network-v2/mod.rs"] -pub mod network_v2; +pub mod proof; +pub mod prover; +pub mod utils; -use std::env; +// Re-export the client. +pub use crate::client::ProverClient; +// Re-export the provers. +pub use crate::cpu::CpuProver; +pub use crate::cuda::CudaProver; +pub use crate::env::EnvProver; #[cfg(feature = "network")] -pub use crate::network::prover::NetworkProver as NetworkProverV1; -#[cfg(feature = "network-v2")] -pub use crate::network_v2::prover::NetworkProver as NetworkProverV2; -#[cfg(feature = "cuda")] -pub use crate::provers::CudaProver; - -pub mod proof; -pub mod provers; -pub mod utils { - pub use sp1_core_machine::utils::setup_logger; -} +pub use crate::network::prover::NetworkProver; -use cfg_if::cfg_if; +// Re-export the proof and prover traits. pub use proof::*; -pub use provers::SP1VerificationError; -use sp1_prover::components::DefaultProverComponents; - -#[cfg(any(feature = "network", feature = "network-v2"))] -use {std::future::Future, tokio::task::block_in_place}; - -pub use provers::{CpuProver, MockProver, Prover}; +#[cfg(feature = "network")] +pub use prover::Prover; +pub use prover::SP1VerificationError; +// Re-export the build utilities and executor primitives. pub use sp1_build::include_elf; -pub use sp1_core_executor::{ExecutionReport, HookEnv, SP1Context, SP1ContextBuilder}; +pub use sp1_core_executor::{ExecutionReport, Executor, HookEnv, SP1Context, SP1ContextBuilder}; + +// Re-export the machine/prover primitives. pub use sp1_core_machine::{io::SP1Stdin, riscv::cost::CostEstimator, SP1_CIRCUIT_VERSION}; pub use sp1_primitives::io::SP1PublicValues; pub use sp1_prover::{ @@ -48,424 +64,24 @@ pub use sp1_prover::{ SP1VerifyingKey, }; -/// A client for interacting with SP1. -pub struct ProverClient { - /// The underlying prover implementation. - pub prover: Box>, -} - -impl ProverClient { - /// Creates a new [ProverClient]. - /// - /// Setting the `SP1_PROVER` environment variable can change the prover used under the hood. - /// - `local` (default): Uses [CpuProver] or [CudaProver] if the `cuda` feature is enabled. - /// Recommended for proving end-to-end locally. - /// - `mock`: Uses [MockProver]. Recommended for testing and development. - /// - `network`: Uses [NetworkProver]. Recommended for outsourcing proof generation to an RPC. - /// - /// ### Examples - /// - /// ```no_run - /// use sp1_sdk::ProverClient; - /// - /// std::env::set_var("SP1_PROVER", "local"); - /// let client = ProverClient::new(); - /// ``` - pub fn new() -> Self { - #[allow(unreachable_code)] - match env::var("SP1_PROVER").unwrap_or("local".to_string()).to_lowercase().as_str() { - "mock" => Self { prover: Box::new(MockProver::new()) }, - "local" => { - #[cfg(debug_assertions)] - eprintln!("Warning: Local prover in dev mode is not recommended. Proof generation may be slow."); - Self { - #[cfg(not(feature = "cuda"))] - prover: Box::new(CpuProver::new()), - #[cfg(feature = "cuda")] - prover: Box::new(CudaProver::new(SP1Prover::new())), - } - } - "network" => { - let private_key = env::var("SP1_PRIVATE_KEY") - .expect("SP1_PRIVATE_KEY must be set for remote proving"); - let rpc_url = env::var("PROVER_NETWORK_RPC").ok(); - let skip_simulation = - env::var("SKIP_SIMULATION").map(|val| val == "true").unwrap_or_default(); - - cfg_if! { - if #[cfg(feature = "network-v2")] { - Self { - prover: Box::new(NetworkProverV2::new(&private_key, rpc_url, skip_simulation)), - } - } else if #[cfg(feature = "network")] { - Self { - prover: Box::new(NetworkProverV1::new(&private_key, rpc_url, skip_simulation)), - } - } else { - panic!("network feature is not enabled") - } - } - } - _ => panic!( - "invalid value for SP1_PROVER environment variable: expected 'local', 'mock', or 'network'" - ), - } - } - - /// Returns a [ProverClientBuilder] to easily create a [ProverClient]. - pub fn builder() -> ProverClientBuilder { - ProverClientBuilder::default() - } - - /// Creates a new [ProverClient] with the mock prover. - /// - /// ### Examples - /// - /// ```no_run - /// use sp1_sdk::ProverClient; - /// - /// let client = ProverClient::mock(); - /// ``` - pub fn mock() -> Self { - Self { prover: Box::new(MockProver::new()) } - } - - /// Creates a new [ProverClient] with the local prover, using the CPU. - /// - /// ### Examples - /// - /// ```no_run - /// use sp1_sdk::ProverClient; - /// - /// let client = ProverClient::local(); - /// ``` - #[deprecated(note = "Please use `cpu` instead")] - pub fn local() -> Self { - Self { prover: Box::new(CpuProver::new()) } - } - - /// Creates a new [ProverClient] with the local prover, using the CPU. - /// - /// ### Examples - /// - /// ```no_run - /// use sp1_sdk::ProverClient; - /// - /// let client = ProverClient::cpu(); - /// ``` - pub fn cpu() -> Self { - Self { prover: Box::new(CpuProver::new()) } - } - - /// Creates a new [ProverClient] with the local prover, using the GPU. - /// - /// ### Examples - /// - /// ```no_run - /// use sp1_sdk::ProverClient; - /// - /// let client = ProverClient::cuda(); - /// ``` - #[cfg(feature = "cuda")] - pub fn cuda() -> Self { - Self { prover: Box::new(CudaProver::new(SP1Prover::new())) } - } - - /// Creates a new [ProverClient] with the network prover. - /// - /// ### Examples - /// - /// ```no_run - /// use sp1_sdk::ProverClient; - /// - /// let private_key = std::env::var("SP1_PRIVATE_KEY").unwrap(); - /// let rpc_url = std::env::var("PROVER_NETWORK_RPC").ok(); - /// let skip_simulation = - /// std::env::var("SKIP_SIMULATION").map(|val| val == "true").unwrap_or_default(); - /// - /// let client = ProverClient::network(private_key, rpc_url, skip_simulation); - /// ``` - #[cfg(any(feature = "network", feature = "network-v2"))] - pub fn network(private_key: String, rpc_url: Option, skip_simulation: bool) -> Self { - cfg_if! { - if #[cfg(feature = "network-v2")] { - Self { - prover: Box::new(NetworkProverV2::new(&private_key, rpc_url, skip_simulation)), - } - } else if #[cfg(feature = "network")] { - Self { - prover: Box::new(NetworkProverV1::new(&private_key, rpc_url, skip_simulation)), - } - } else { - panic!("network feature is not enabled") - } - } - } - - /// Prepare to execute the given program on the given input (without generating a proof). - /// The returned [action::Execute] may be configured via its methods before running. - /// For example, calling [action::Execute::with_hook] registers hooks for execution. - /// - /// To execute, call [action::Execute::run], which returns - /// the public values and execution report of the program after it has been executed. - /// - /// ### Examples - /// ```no_run - /// use sp1_sdk::{ProverClient, SP1Context, SP1Stdin}; - /// - /// // Load the program. - /// let elf = test_artifacts::FIBONACCI_ELF; - /// - /// // Initialize the prover client. - /// let client = ProverClient::new(); - /// - /// // Setup the inputs. - /// let mut stdin = SP1Stdin::new(); - /// stdin.write(&10usize); - /// - /// // Execute the program on the inputs. - /// let (public_values, report) = client.execute(elf, stdin).run().unwrap(); - /// ``` - pub fn execute<'a>(&'a self, elf: &'a [u8], stdin: SP1Stdin) -> action::Execute<'a> { - action::Execute::new(self.prover.as_ref(), elf, stdin) - } - - /// Prepare to prove the execution of the given program with the given input in the default - /// mode. The returned [action::Prove] may be configured via its methods before running. - /// For example, calling [action::Prove::compressed] sets the mode to compressed mode. - /// - /// To prove, call [action::Prove::run], which returns a proof of the program's execution. - /// By default the proof generated will not be compressed to constant size. - /// To create a more succinct proof, use the [action::Prove::compressed], - /// [action::Prove::plonk], or [action::Prove::groth16] methods. - /// - /// ### Examples - /// ```no_run - /// use sp1_sdk::{ProverClient, SP1Context, SP1Stdin}; - /// - /// // Load the program. - /// let elf = test_artifacts::FIBONACCI_ELF; - /// - /// // Initialize the prover client. - /// let client = ProverClient::new(); - /// - /// // Setup the program. - /// let (pk, vk) = client.setup(elf); - /// - /// // Setup the inputs. - /// let mut stdin = SP1Stdin::new(); - /// stdin.write(&10usize); - /// - /// // Generate the proof. - /// let proof = client.prove(&pk, stdin).run().unwrap(); - /// ``` - pub fn prove<'a>(&'a self, pk: &'a SP1ProvingKey, stdin: SP1Stdin) -> action::Prove<'a> { - action::Prove::new(self.prover.as_ref(), pk, stdin) - } - - /// Verifies that the given proof is valid and matches the given verification key produced by - /// [Self::setup]. - /// - /// ### Examples - /// ```no_run - /// use sp1_sdk::{ProverClient, SP1Stdin}; - /// - /// let elf = test_artifacts::FIBONACCI_ELF; - /// let client = ProverClient::new(); - /// let (pk, vk) = client.setup(elf); - /// let mut stdin = SP1Stdin::new(); - /// stdin.write(&10usize); - /// let proof = client.prove(&pk, stdin).run().unwrap(); - /// client.verify(&proof, &vk).unwrap(); - /// ``` - pub fn verify( - &self, - proof: &SP1ProofWithPublicValues, - vk: &SP1VerifyingKey, - ) -> Result<(), SP1VerificationError> { - self.prover.verify(proof, vk) - } - - /// Gets the current version of the SP1 zkVM. - /// - /// Note: This is not the same as the version of the SP1 SDK. - pub fn version(&self) -> String { - SP1_CIRCUIT_VERSION.to_string() - } - - /// Setup a program to be proven and verified by the SP1 RISC-V zkVM by computing the proving - /// and verifying keys. - /// - /// The proving key and verifying key essentially embed the program, as well as other auxiliary - /// data (such as lookup tables) that are used to prove the program's correctness. - /// - /// ### Examples - /// ```no_run - /// use sp1_sdk::{ProverClient, SP1Stdin}; - /// - /// let elf = test_artifacts::FIBONACCI_ELF; - /// let client = ProverClient::new(); - /// let mut stdin = SP1Stdin::new(); - /// stdin.write(&10usize); - /// let (pk, vk) = client.setup(elf); - /// ``` - pub fn setup(&self, elf: &[u8]) -> (SP1ProvingKey, SP1VerifyingKey) { - self.prover.setup(elf) - } -} - -impl Default for ProverClient { - fn default() -> Self { - Self::new() - } -} - -/// Builder type for [`ProverClient`]. -#[derive(Debug, Default)] -pub struct ProverClientBuilder { - mode: Option, - private_key: Option, - rpc_url: Option, - skip_simulation: bool, -} - -impl ProverClientBuilder { - /// Sets the mode of the prover client being created. - pub fn mode(mut self, mode: ProverMode) -> Self { - self.mode = Some(mode); - self - } - - /// Sets the private key. - pub fn private_key(mut self, private_key: String) -> Self { - self.private_key = Some(private_key); - self - } - - /// Sets the RPC URL. - pub fn rpc_url(mut self, rpc_url: String) -> Self { - self.rpc_url = Some(rpc_url); - self - } - - /// Skips simulation. - pub fn skip_simulation(mut self) -> Self { - self.skip_simulation = true; - self - } - - /// Builds a [ProverClient], using the provided private key. - pub fn build(self) -> ProverClient { - match self.mode.expect("The prover mode is required") { - ProverMode::Cpu => ProverClient::cpu(), - ProverMode::Cuda => { - cfg_if! { - if #[cfg(feature = "cuda")] { - ProverClient::cuda() - } else { - panic!("cuda feature is not enabled") - } - } - } - ProverMode::Network => { - let private_key = self.private_key.expect("The private key is required"); - - cfg_if! { - if #[cfg(feature = "network-v2")] { - ProverClient { - prover: Box::new(NetworkProverV2::new(&private_key, self.rpc_url, self.skip_simulation)), - } - } else if #[cfg(feature = "network")] { - ProverClient { - prover: Box::new(NetworkProverV1::new(&private_key, self.rpc_url, self.skip_simulation)), - } - } else { - panic!("network feature is not enabled") - } - } - } - ProverMode::Mock => ProverClient::mock(), - } - } -} - -/// Builder type for network prover. -#[cfg(any(feature = "network", feature = "network-v2"))] -#[derive(Debug, Default)] -pub struct NetworkProverBuilder { - private_key: Option, - rpc_url: Option, - skip_simulation: bool, -} - -#[cfg(any(feature = "network", feature = "network-v2"))] -impl NetworkProverBuilder { - /// Sets the private key. - pub fn private_key(mut self, private_key: String) -> Self { - self.private_key = Some(private_key); - self - } - - /// Sets the RPC URL. - pub fn rpc_url(mut self, rpc_url: String) -> Self { - self.rpc_url = Some(rpc_url); - self - } - - /// Skips simulation. - pub fn skip_simulation(mut self) -> Self { - self.skip_simulation = true; - self - } - - /// Creates a new [NetworkProverV1]. - #[cfg(feature = "network")] - pub fn build(self) -> NetworkProverV1 { - let private_key = self.private_key.expect("The private key is required"); - - NetworkProverV1::new(&private_key, self.rpc_url, self.skip_simulation) - } - - /// Creates a new [NetworkProverV2]. - #[cfg(feature = "network-v2")] - pub fn build_v2(self) -> NetworkProverV2 { - let private_key = self.private_key.expect("The private key is required"); - - NetworkProverV2::new(&private_key, self.rpc_url, self.skip_simulation) - } -} - -/// Utility method for blocking on an async function. -/// -/// If we're already in a tokio runtime, we'll block in place. Otherwise, we'll create a new -/// runtime. -#[cfg(any(feature = "network", feature = "network-v2"))] -pub fn block_on(fut: impl Future) -> T { - // Handle case if we're already in an tokio runtime. - if let Ok(handle) = tokio::runtime::Handle::try_current() { - block_in_place(|| handle.block_on(fut)) - } else { - // Otherwise create a new runtime. - let rt = tokio::runtime::Runtime::new().expect("Failed to create a new runtime"); - rt.block_on(fut) - } -} +// Re-export the utilities. +pub use utils::setup_logger; #[cfg(test)] mod tests { - + use sp1_core_machine::riscv::cost::CostEstimator; use sp1_primitives::io::SP1PublicValues; - use crate::{utils, CostEstimator, ProverClient, SP1Stdin}; + use crate::{utils, Prover, ProverClient, SP1Stdin}; #[test] fn test_execute() { utils::setup_logger(); - let client = ProverClient::cpu(); + let client = ProverClient::builder().cpu().build(); let elf = test_artifacts::FIBONACCI_ELF; let mut stdin = SP1Stdin::new(); stdin.write(&10usize); - let (_, report) = client.execute(elf, stdin).run().unwrap(); + let (_, report) = client.execute(elf, &stdin).run().unwrap(); tracing::info!("gas = {}", report.estimate_gas()); } @@ -473,35 +89,35 @@ mod tests { #[should_panic] fn test_execute_panic() { utils::setup_logger(); - let client = ProverClient::cpu(); + let client = ProverClient::builder().cpu().build(); let elf = test_artifacts::PANIC_ELF; let mut stdin = SP1Stdin::new(); stdin.write(&10usize); - client.execute(elf, stdin).run().unwrap(); + client.execute(elf, &stdin).run().unwrap(); } #[should_panic] #[test] fn test_cycle_limit_fail() { utils::setup_logger(); - let client = ProverClient::cpu(); + let client = ProverClient::builder().cpu().build(); let elf = test_artifacts::PANIC_ELF; let mut stdin = SP1Stdin::new(); stdin.write(&10usize); - client.execute(elf, stdin).max_cycles(1).run().unwrap(); + client.execute(elf, &stdin).cycle_limit(1).run().unwrap(); } #[test] fn test_e2e_core() { utils::setup_logger(); - let client = ProverClient::cpu(); + let client = ProverClient::builder().cpu().build(); let elf = test_artifacts::FIBONACCI_ELF; let (pk, vk) = client.setup(elf); let mut stdin = SP1Stdin::new(); stdin.write(&10usize); // Generate proof & verify. - let mut proof = client.prove(&pk, stdin).run().unwrap(); + let mut proof = client.prove(&pk, &stdin).run().unwrap(); client.verify(&proof, &vk).unwrap(); // Test invalid public values. @@ -514,14 +130,14 @@ mod tests { #[test] fn test_e2e_compressed() { utils::setup_logger(); - let client = ProverClient::cpu(); + let client = ProverClient::builder().cpu().build(); let elf = test_artifacts::FIBONACCI_ELF; let (pk, vk) = client.setup(elf); let mut stdin = SP1Stdin::new(); stdin.write(&10usize); // Generate proof & verify. - let mut proof = client.prove(&pk, stdin).compressed().run().unwrap(); + let mut proof = client.prove(&pk, &stdin).compressed().run().unwrap(); client.verify(&proof, &vk).unwrap(); // Test invalid public values. @@ -534,14 +150,14 @@ mod tests { #[test] fn test_e2e_prove_plonk() { utils::setup_logger(); - let client = ProverClient::cpu(); + let client = ProverClient::builder().cpu().build(); let elf = test_artifacts::FIBONACCI_ELF; let (pk, vk) = client.setup(elf); let mut stdin = SP1Stdin::new(); stdin.write(&10usize); // Generate proof & verify. - let mut proof = client.prove(&pk, stdin).plonk().run().unwrap(); + let mut proof = client.prove(&pk, &stdin).plonk().run().unwrap(); client.verify(&proof, &vk).unwrap(); // Test invalid public values. @@ -554,12 +170,12 @@ mod tests { #[test] fn test_e2e_prove_plonk_mock() { utils::setup_logger(); - let client = ProverClient::mock(); + let client = ProverClient::builder().mock().build(); let elf = test_artifacts::FIBONACCI_ELF; let (pk, vk) = client.setup(elf); let mut stdin = SP1Stdin::new(); stdin.write(&10usize); - let proof = client.prove(&pk, stdin).plonk().run().unwrap(); + let proof = client.prove(&pk, &stdin).plonk().run().unwrap(); client.verify(&proof, &vk).unwrap(); } } diff --git a/crates/sdk/src/network-v2/client.rs b/crates/sdk/src/network-v2/client.rs deleted file mode 100644 index 509aaad444..0000000000 --- a/crates/sdk/src/network-v2/client.rs +++ /dev/null @@ -1,280 +0,0 @@ -use std::result::Result::Ok as StdOk; -use std::str::FromStr; -use std::time::{Duration, SystemTime, UNIX_EPOCH}; - -use alloy_signer::SignerSync; -use alloy_signer_local::PrivateKeySigner; -use anyhow::{Context, Ok, Result}; -use reqwest_middleware::ClientWithMiddleware as HttpClientWithMiddleware; -use serde::{de::DeserializeOwned, Serialize}; -use tonic::{ - transport::{channel::ClientTlsConfig, Channel}, - Code, -}; - -use sp1_core_machine::io::SP1Stdin; -use sp1_prover::{HashableKey, SP1VerifyingKey}; - -use crate::network_v2::proto::artifact::{ - artifact_store_client::ArtifactStoreClient, CreateArtifactRequest, -}; -use crate::network_v2::proto::network::{ - prover_network_client::ProverNetworkClient, CreateProgramRequest, CreateProgramRequestBody, - CreateProgramResponse, FulfillmentStatus, FulfillmentStrategy, GetNonceRequest, - GetProgramRequest, GetProgramResponse, GetProofRequestStatusRequest, - GetProofRequestStatusResponse, MessageFormat, ProofMode, RequestProofRequest, - RequestProofRequestBody, RequestProofResponse, -}; -use crate::network_v2::Signable; - -/// The default RPC endpoint for the Succinct prover network. -pub const DEFAULT_PROVER_NETWORK_RPC: &str = "https://rpc.production.succinct.tools/"; - -pub struct NetworkClient { - signer: PrivateKeySigner, - http: HttpClientWithMiddleware, - rpc_url: String, -} - -impl NetworkClient { - /// Create a new network client with the given private key. - pub fn new(private_key: &str, rpc_url: Option) -> Self { - let signer = PrivateKeySigner::from_str(private_key).unwrap(); - - let http_client = reqwest::Client::builder() - .pool_max_idle_per_host(0) - .pool_idle_timeout(Duration::from_secs(240)) - .build() - .unwrap(); - - Self { - signer, - http: http_client.into(), - rpc_url: rpc_url.unwrap_or_else(|| DEFAULT_PROVER_NETWORK_RPC.to_string()), - } - } - - /// Returns the currently configured RPC endpoint for the Succinct prover network. - pub fn rpc_url(&self) -> String { - self.rpc_url.clone() - } - - /// Get a connected RPC client. - async fn get_rpc(&self) -> Result> { - let rpc_url = self.rpc_url(); - let mut endpoint = Channel::from_shared(rpc_url.clone())?; - - // Check if the URL scheme is HTTPS and configure TLS. - if rpc_url.starts_with("https://") { - let tls_config = ClientTlsConfig::new().with_enabled_roots(); - endpoint = endpoint.tls_config(tls_config)?; - } - - let channel = endpoint.connect().await?; - Ok(ProverNetworkClient::new(channel)) - } - - /// Get a connected artifact store client. - async fn get_store(&self) -> Result> { - let rpc_url = self.rpc_url(); - let mut endpoint = Channel::from_shared(rpc_url.clone())?; - - // Check if the URL scheme is HTTPS and configure TLS. - if rpc_url.starts_with("https://") { - let tls_config = ClientTlsConfig::new().with_enabled_roots(); - endpoint = endpoint.tls_config(tls_config)?; - } - - let channel = endpoint.connect().await?; - Ok(ArtifactStoreClient::new(channel.clone())) - } - - /// Get the latest nonce for this account's address. - pub async fn get_nonce(&self) -> Result { - let mut rpc = self.get_rpc().await?; - let res = - rpc.get_nonce(GetNonceRequest { address: self.signer.address().to_vec() }).await?; - Ok(res.into_inner().nonce) - } - - /// Get the verifying key hash from a verifying key. The verifying key hash is used to identify - /// a program. - pub fn get_vk_hash(vk: &SP1VerifyingKey) -> Result> { - let vk_hash_str = vk.bytes32(); - let vk_hash = hex::decode(vk_hash_str.strip_prefix("0x").unwrap_or(&vk_hash_str))?; - Ok(vk_hash) - } - - /// Registers a program if it is not already registered. - pub async fn register_program(&self, vk: &SP1VerifyingKey, elf: &[u8]) -> Result> { - let vk_hash = Self::get_vk_hash(vk)?; - - // Try to get the existing program. - match self.get_program(&vk_hash).await? { - Some(_) => { - // The program already exists. - Ok(vk_hash) - } - None => { - // The program doesn't exist, create it. - self.create_program(&vk_hash, vk, elf).await?; - log::info!("Registered program 0x{}", hex::encode(vk_hash.clone())); - Ok(vk_hash) - } - } - } - - /// Attempts to get program info, returns None if program doesn't exist. - async fn get_program(&self, vk_hash: &[u8]) -> Result> { - let mut rpc = self.get_rpc().await?; - match rpc.get_program(GetProgramRequest { vk_hash: vk_hash.to_vec() }).await { - StdOk(response) => Ok(Some(response.into_inner())), - Err(status) if status.code() == Code::NotFound => Ok(None), - Err(e) => Err(e.into()), - } - } - - /// Creates a new program. - async fn create_program( - &self, - vk_hash: &[u8], - vk: &SP1VerifyingKey, - elf: &[u8], - ) -> Result { - // Create the program artifact. - let mut store = self.get_store().await?; - let program_uri = self.create_artifact_with_content(&mut store, &elf).await?; - - // Serialize the verifying key. - let vk_encoded = bincode::serialize(&vk)?; - - // Send the request. - let mut rpc = self.get_rpc().await?; - let nonce = self.get_nonce().await?; - let request_body = CreateProgramRequestBody { - nonce, - vk_hash: vk_hash.to_vec(), - vk: vk_encoded, - program_uri, - }; - - Ok(rpc - .create_program(CreateProgramRequest { - format: MessageFormat::Binary.into(), - signature: request_body.sign(&self.signer).into(), - body: Some(request_body), - }) - .await? - .into_inner()) - } - - /// Get the status of a given proof. If the status is Fulfilled, the proof is also returned. - pub async fn get_proof_request_status( - &self, - request_id: &[u8], - ) -> Result<(GetProofRequestStatusResponse, Option

)> { - let mut rpc = self.get_rpc().await?; - let res = rpc - .get_proof_request_status(GetProofRequestStatusRequest { - request_id: request_id.to_vec(), - }) - .await? - .into_inner(); - - let status = FulfillmentStatus::try_from(res.fulfillment_status)?; - let proof = match status { - FulfillmentStatus::Fulfilled => { - let proof_uri = res - .proof_uri - .as_ref() - .ok_or_else(|| anyhow::anyhow!("No proof URI provided"))?; - let proof_bytes = self.download_artifact(proof_uri).await?; - Some(bincode::deserialize(&proof_bytes).context("Failed to deserialize proof")?) - } - _ => None, - }; - - Ok((res, proof)) - } - - /// Creates a proof request with the given verifying key hash and stdin. - #[allow(clippy::too_many_arguments)] - pub async fn request_proof( - &self, - vk_hash: &[u8], - stdin: &SP1Stdin, - mode: ProofMode, - version: &str, - strategy: FulfillmentStrategy, - timeout_secs: u64, - cycle_limit: u64, - ) -> Result { - // Calculate the deadline. - let start = SystemTime::now(); - let since_the_epoch = start.duration_since(UNIX_EPOCH).expect("Invalid start time"); - let deadline = since_the_epoch.as_secs() + timeout_secs; - - // Create the stdin artifact. - let mut store = self.get_store().await?; - let stdin_uri = self.create_artifact_with_content(&mut store, &stdin).await?; - - // Send the request. - let mut rpc = self.get_rpc().await?; - let nonce = self.get_nonce().await?; - let request_body = RequestProofRequestBody { - nonce, - version: format!("sp1-{}", version), - vk_hash: vk_hash.to_vec(), - mode: mode.into(), - strategy: strategy.into(), - stdin_uri, - deadline, - cycle_limit, - }; - let request_response = rpc - .request_proof(RequestProofRequest { - format: MessageFormat::Binary.into(), - signature: request_body.sign(&self.signer).into(), - body: Some(request_body), - }) - .await? - .into_inner(); - - Ok(request_response) - } - - /// Uses the artifact store to to create an artifact, upload the content, and return the URI. - async fn create_artifact_with_content( - &self, - store: &mut ArtifactStoreClient, - item: &T, - ) -> Result { - let signature = self.signer.sign_message_sync("create_artifact".as_bytes())?; - let request = CreateArtifactRequest { signature: signature.as_bytes().to_vec() }; - let response = store.create_artifact(request).await?.into_inner(); - - let presigned_url = response.artifact_presigned_url; - let uri = response.artifact_uri; - - let response = - self.http.put(&presigned_url).body(bincode::serialize::(item)?).send().await?; - - if !response.status().is_success() { - log::debug!("Artifact upload failed with status: {}", response.status()); - } - assert!(response.status().is_success()); - - Ok(uri) - } - - /// Download an artifact from a URI. - async fn download_artifact(&self, uri: &str) -> Result> { - let response = self.http.get(uri).send().await.context("Failed to download from URI")?; - - if !response.status().is_success() { - return Err(anyhow::anyhow!("Failed to download artifact: HTTP {}", response.status())); - } - - Ok(response.bytes().await.context("Failed to read response body")?.to_vec()) - } -} diff --git a/crates/sdk/src/network-v2/mod.rs b/crates/sdk/src/network-v2/mod.rs deleted file mode 100644 index 86f1a82d47..0000000000 --- a/crates/sdk/src/network-v2/mod.rs +++ /dev/null @@ -1,20 +0,0 @@ -pub mod client; -mod json; -pub mod prover; -mod sign_message; -#[rustfmt::skip] -pub mod proto; - -use alloy_signer::{Signature, SignerSync}; -use prost::Message; -pub use serde::{Deserialize, Serialize}; - -pub trait Signable: Message { - fn sign(&self, signer: &S) -> Signature; -} - -impl Signable for T { - fn sign(&self, signer: &S) -> Signature { - signer.sign_message_sync(&self.encode_to_vec()).unwrap() - } -} diff --git a/crates/sdk/src/network-v2/proto/mod.rs b/crates/sdk/src/network-v2/proto/mod.rs deleted file mode 100644 index 48eb63675a..0000000000 --- a/crates/sdk/src/network-v2/proto/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod artifact; -pub mod network; diff --git a/crates/sdk/src/network-v2/proto/network.rs b/crates/sdk/src/network-v2/proto/network.rs deleted file mode 100644 index dd0077db9a..0000000000 --- a/crates/sdk/src/network-v2/proto/network.rs +++ /dev/null @@ -1,3932 +0,0 @@ -// This file is @generated by prost-build. -#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct RequestProofRequest { - /// The message format of the body. - #[prost(enumeration = "MessageFormat", tag = "1")] - pub format: i32, - /// The signature of the sender. - #[prost(bytes = "vec", tag = "2")] - pub signature: ::prost::alloc::vec::Vec, - /// The body of the request. - #[prost(message, optional, tag = "3")] - pub body: ::core::option::Option, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct RequestProofRequestBody { - /// The account nonce of the sender. - #[prost(uint64, tag = "1")] - pub nonce: u64, - /// The verification key hash of the program. - #[prost(bytes = "vec", tag = "2")] - pub vk_hash: ::prost::alloc::vec::Vec, - /// The version of the prover to use. - #[prost(string, tag = "3")] - pub version: ::prost::alloc::string::String, - /// The mode for the request. - #[prost(enumeration = "ProofMode", tag = "4")] - pub mode: i32, - /// The strategy for fulfiller assignment. - #[prost(enumeration = "FulfillmentStrategy", tag = "5")] - pub strategy: i32, - /// The stdin resource identifier. - #[prost(string, tag = "6")] - pub stdin_uri: ::prost::alloc::string::String, - /// The deadline for the request. - #[prost(uint64, tag = "7")] - pub deadline: u64, - /// The cycle limit for the request. - #[prost(uint64, tag = "8")] - pub cycle_limit: u64, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct RequestProofResponse { - /// The transaction hash. - #[prost(bytes = "vec", tag = "1")] - pub tx_hash: ::prost::alloc::vec::Vec, - /// The body of the response. - #[prost(message, optional, tag = "2")] - pub body: ::core::option::Option, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct RequestProofResponseBody { - /// The identifier for the request. - #[prost(bytes = "vec", tag = "1")] - pub request_id: ::prost::alloc::vec::Vec, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct FulfillProofRequest { - /// The message format of the body. - #[prost(enumeration = "MessageFormat", tag = "1")] - pub format: i32, - /// The signature of the sender. - #[prost(bytes = "vec", tag = "2")] - pub signature: ::prost::alloc::vec::Vec, - /// The body of the request. - #[prost(message, optional, tag = "3")] - pub body: ::core::option::Option, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct FulfillProofRequestBody { - /// The account nonce of the sender. - #[prost(uint64, tag = "1")] - pub nonce: u64, - /// The identifier for the request. - #[prost(bytes = "vec", tag = "2")] - pub request_id: ::prost::alloc::vec::Vec, - /// The proof bytes. - #[prost(bytes = "vec", tag = "3")] - pub proof: ::prost::alloc::vec::Vec, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct FulfillProofResponse { - /// The transaction hash. - #[prost(bytes = "vec", tag = "1")] - pub tx_hash: ::prost::alloc::vec::Vec, - /// The body of the response. - #[prost(message, optional, tag = "2")] - pub body: ::core::option::Option, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, Copy, PartialEq, ::prost::Message)] -pub struct FulfillProofResponseBody {} -#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct ExecuteProofRequest { - /// The message format of the body. - #[prost(enumeration = "MessageFormat", tag = "1")] - pub format: i32, - /// The signature of the sender. - #[prost(bytes = "vec", tag = "2")] - pub signature: ::prost::alloc::vec::Vec, - /// The body of the request. - #[prost(message, optional, tag = "3")] - pub body: ::core::option::Option, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct ExecuteProofRequestBody { - /// The account nonce of the sender. - #[prost(uint64, tag = "1")] - pub nonce: u64, - /// The identifier for the request. - #[prost(bytes = "vec", tag = "2")] - pub request_id: ::prost::alloc::vec::Vec, - /// The execution status of the request. - #[prost(enumeration = "ExecutionStatus", tag = "3")] - pub execution_status: i32, - /// The optional public values hash of the request execution, only included if - /// the request is valid. - #[prost(bytes = "vec", optional, tag = "4")] - pub public_values_hash: ::core::option::Option<::prost::alloc::vec::Vec>, - /// The optional cycles used when executing the request, only included if the - /// request is valid. - #[prost(uint64, optional, tag = "5")] - pub cycles: ::core::option::Option, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct ExecuteProofResponse { - /// The transaction hash. - #[prost(bytes = "vec", tag = "1")] - pub tx_hash: ::prost::alloc::vec::Vec, - /// The body of the response. - #[prost(message, optional, tag = "2")] - pub body: ::core::option::Option, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, Copy, PartialEq, ::prost::Message)] -pub struct ExecuteProofResponseBody {} -#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct FailFulfillmentRequest { - /// The message format of the body. - #[prost(enumeration = "MessageFormat", tag = "1")] - pub format: i32, - /// The signature of the sender. - #[prost(bytes = "vec", tag = "2")] - pub signature: ::prost::alloc::vec::Vec, - /// The body of the request. - #[prost(message, optional, tag = "3")] - pub body: ::core::option::Option, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct FailFulfillmentRequestBody { - /// The account nonce of the sender. - #[prost(uint64, tag = "1")] - pub nonce: u64, - /// The identifier for the request. - #[prost(bytes = "vec", tag = "2")] - pub request_id: ::prost::alloc::vec::Vec, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct FailFulfillmentResponse { - /// The transaction hash. - #[prost(bytes = "vec", tag = "1")] - pub tx_hash: ::prost::alloc::vec::Vec, - /// The body of the response. - #[prost(message, optional, tag = "2")] - pub body: ::core::option::Option, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, Copy, PartialEq, ::prost::Message)] -pub struct FailFulfillmentResponseBody {} -#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct FailExecutionRequest { - /// The message format of the body. - #[prost(enumeration = "MessageFormat", tag = "1")] - pub format: i32, - /// The signature of the sender. - #[prost(bytes = "vec", tag = "2")] - pub signature: ::prost::alloc::vec::Vec, - /// The body of the request. - #[prost(message, optional, tag = "3")] - pub body: ::core::option::Option, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct FailExecutionRequestBody { - /// The account nonce of the sender. - #[prost(uint64, tag = "1")] - pub nonce: u64, - /// The identifier for the request. - #[prost(bytes = "vec", tag = "2")] - pub request_id: ::prost::alloc::vec::Vec, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct FailExecutionResponse { - /// The transaction hash. - #[prost(bytes = "vec", tag = "1")] - pub tx_hash: ::prost::alloc::vec::Vec, - /// The body of the response. - #[prost(message, optional, tag = "2")] - pub body: ::core::option::Option, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, Copy, PartialEq, ::prost::Message)] -pub struct FailExecutionResponseBody {} -#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct ProofRequest { - /// The request identifier. - #[prost(bytes = "vec", tag = "1")] - pub request_id: ::prost::alloc::vec::Vec, - /// The verification key hash of the program. - #[prost(bytes = "vec", tag = "2")] - pub vk_hash: ::prost::alloc::vec::Vec, - /// The version of the prover to use. - #[prost(string, tag = "3")] - pub version: ::prost::alloc::string::String, - /// The mode for the proof. - #[prost(enumeration = "ProofMode", tag = "4")] - pub mode: i32, - /// The strategy for fulfiller assignment. - #[prost(enumeration = "FulfillmentStrategy", tag = "5")] - pub strategy: i32, - /// The program resource identifier. - #[prost(string, tag = "6")] - pub program_uri: ::prost::alloc::string::String, - /// The stdin resource identifier. - #[prost(string, tag = "7")] - pub stdin_uri: ::prost::alloc::string::String, - /// The deadline for the request. - #[prost(uint64, tag = "8")] - pub deadline: u64, - /// The cycle limit for the request. - #[prost(uint64, tag = "9")] - pub cycle_limit: u64, - /// The gas price for the request. - #[prost(uint64, optional, tag = "10")] - pub gas_price: ::core::option::Option, - /// The fulfillment status of the request. - #[prost(enumeration = "FulfillmentStatus", tag = "11")] - pub fulfillment_status: i32, - /// The execution status of the request. - #[prost(enumeration = "ExecutionStatus", tag = "12")] - pub execution_status: i32, - /// The requester address that signed the request. - #[prost(bytes = "vec", tag = "13")] - pub requester: ::prost::alloc::vec::Vec, - /// The fulfiller address that fulfilled the request. - #[prost(bytes = "vec", optional, tag = "14")] - pub fulfiller: ::core::option::Option<::prost::alloc::vec::Vec>, - /// The optional name to refer to an alias of the program id. - #[prost(string, optional, tag = "15")] - pub program_name: ::core::option::Option<::prost::alloc::string::String>, - /// The optional name to refer to an alias of the requester address. - #[prost(string, optional, tag = "16")] - pub requester_name: ::core::option::Option<::prost::alloc::string::String>, - /// The optional name to refer to an alias of the fulfiller address. - #[prost(string, optional, tag = "17")] - pub fulfiller_name: ::core::option::Option<::prost::alloc::string::String>, - /// The unix timestamp of when the request was created. - #[prost(uint64, tag = "18")] - pub created_at: u64, - /// The unix timestamp of when the request was updated. - #[prost(uint64, tag = "19")] - pub updated_at: u64, - /// The unix timestamp of when the request was fulfilled. - #[prost(uint64, optional, tag = "20")] - pub fulfilled_at: ::core::option::Option, - /// The transaction hash of the request. - #[prost(bytes = "vec", tag = "21")] - pub tx_hash: ::prost::alloc::vec::Vec, - /// The cycle count for the request. - #[prost(uint64, optional, tag = "22")] - pub cycles: ::core::option::Option, - /// The amount deducted from the fulfiller's balance. - #[prost(string, optional, tag = "23")] - pub deduction_amount: ::core::option::Option<::prost::alloc::string::String>, - /// The amount refunded to the fulfiller's balance. - #[prost(string, optional, tag = "24")] - pub refund_amount: ::core::option::Option<::prost::alloc::string::String>, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct GetProofRequestStatusRequest { - /// The identifier for the request. - #[prost(bytes = "vec", tag = "1")] - pub request_id: ::prost::alloc::vec::Vec, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct GetProofRequestStatusResponse { - /// The fulfillment status of the request. - #[prost(enumeration = "FulfillmentStatus", tag = "1")] - pub fulfillment_status: i32, - /// The execution status of the request. - #[prost(enumeration = "ExecutionStatus", tag = "2")] - pub execution_status: i32, - /// The transaction hash of the request. - #[prost(bytes = "vec", tag = "3")] - pub request_tx_hash: ::prost::alloc::vec::Vec, - /// The optional transaction hash of the proof fulfill. Only included if the - /// request has a fulfillment status of FULFILLED. - #[prost(bytes = "vec", optional, tag = "4")] - pub fulfill_tx_hash: ::core::option::Option<::prost::alloc::vec::Vec>, - /// The optional proof URI, where you can download the result of the request. - /// Only included if the request has a fulfillment status of FULFILLED. - #[prost(string, optional, tag = "5")] - pub proof_uri: ::core::option::Option<::prost::alloc::string::String>, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct GetProofRequestDetailsRequest { - /// The identifier for the request. - #[prost(bytes = "vec", tag = "1")] - pub request_id: ::prost::alloc::vec::Vec, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct GetProofRequestDetailsResponse { - /// The detailed request. - #[prost(message, optional, tag = "1")] - pub request: ::core::option::Option, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct GetFilteredProofRequestsRequest { - /// The optional version of the requests to filter for. - #[prost(string, optional, tag = "1")] - pub version: ::core::option::Option<::prost::alloc::string::String>, - /// The optional fulfillment status of the requests to filter for. - #[prost(enumeration = "FulfillmentStatus", optional, tag = "2")] - pub fulfillment_status: ::core::option::Option, - /// The optional execution status of the requests to filter for. - #[prost(enumeration = "ExecutionStatus", optional, tag = "3")] - pub execution_status: ::core::option::Option, - /// The optional minimum unix timestamp deadline of the requests to filter for. - /// Only returns requests with deadlines after this timestamp. - #[prost(uint64, optional, tag = "4")] - pub minimum_deadline: ::core::option::Option, - /// The optional verification key hash of the program to filter for. - #[prost(bytes = "vec", optional, tag = "5")] - pub vk_hash: ::core::option::Option<::prost::alloc::vec::Vec>, - /// The optional requester address to filter for. - #[prost(bytes = "vec", optional, tag = "6")] - pub requester: ::core::option::Option<::prost::alloc::vec::Vec>, - /// The optional fulfiller address to filter for. - #[prost(bytes = "vec", optional, tag = "7")] - pub fulfiller: ::core::option::Option<::prost::alloc::vec::Vec>, - /// The optional minimum creation unix timestamp of the requests to filter for. - #[prost(uint64, optional, tag = "8")] - pub from: ::core::option::Option, - /// The optional maximum creation unix timestamp of the requests to filter for. - #[prost(uint64, optional, tag = "9")] - pub to: ::core::option::Option, - /// The optional maximum number of requests to return (default is 10, - /// maximum is 100). - #[prost(uint32, optional, tag = "10")] - pub limit: ::core::option::Option, - /// The optional page number to return (default is 1). - #[prost(uint32, optional, tag = "11")] - pub page: ::core::option::Option, - /// The optional mode of the requests to filter for. - #[prost(enumeration = "ProofMode", optional, tag = "12")] - pub mode: ::core::option::Option, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct GetFilteredProofRequestsResponse { - /// The requests that matched the filter criteria. - #[prost(message, repeated, tag = "1")] - pub requests: ::prost::alloc::vec::Vec, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct GetSearchResultsRequest { - /// The search query string. - #[prost(string, tag = "1")] - pub query: ::prost::alloc::string::String, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct SearchResult { - #[prost(bytes = "vec", tag = "1")] - pub id: ::prost::alloc::vec::Vec, - #[prost(string, optional, tag = "2")] - pub name: ::core::option::Option<::prost::alloc::string::String>, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct GetSearchResultsResponse { - /// List of matching request IDs with optional names. - #[prost(message, repeated, tag = "1")] - pub requests: ::prost::alloc::vec::Vec, - /// List of matching program IDs with optional names. - #[prost(message, repeated, tag = "2")] - pub programs: ::prost::alloc::vec::Vec, - /// List of matching requester IDs with optional names. - #[prost(message, repeated, tag = "3")] - pub requesters: ::prost::alloc::vec::Vec, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct GetProofRequestMetricsRequest { - /// The optional address to filter for. - #[prost(bytes = "vec", optional, tag = "1")] - pub address: ::core::option::Option<::prost::alloc::vec::Vec>, - /// The optional interval in days for volume calculation. - #[prost(uint64, optional, tag = "2")] - pub volume_interval_days: ::core::option::Option, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, Copy, PartialEq, ::prost::Message)] -pub struct GetProofRequestMetricsResponse { - /// The total number of proofs. - #[prost(uint64, tag = "1")] - pub total_proofs: u64, - /// The total number of cycles. - #[prost(uint64, tag = "2")] - pub total_cycles: u64, - /// The volume in the specified interval. - #[prost(uint64, tag = "3")] - pub volume: u64, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct GetProofRequestGraphRequest { - /// The optional address to filter for. - #[prost(bytes = "vec", optional, tag = "1")] - pub address: ::core::option::Option<::prost::alloc::vec::Vec>, - /// The optional interval in days for the graph range. - #[prost(uint64, optional, tag = "2")] - pub range_interval_days: ::core::option::Option, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct GraphData { - /// The timestamp of the data point. - #[prost(string, tag = "1")] - pub timestamp: ::prost::alloc::string::String, - /// The value at this timestamp. - #[prost(uint64, tag = "2")] - pub value: u64, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct GetProofRequestGraphResponse { - /// The time series data points. - #[prost(message, repeated, tag = "1")] - pub data: ::prost::alloc::vec::Vec, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct GetAnalyticsGraphsRequest { - /// The optional address to filter for. - #[prost(bytes = "vec", optional, tag = "1")] - pub address: ::core::option::Option<::prost::alloc::vec::Vec>, - /// The optional interval in days for the graph range. - #[prost(uint64, optional, tag = "2")] - pub range_interval_days: ::core::option::Option, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct GetAnalyticsGraphsResponse { - /// The time series data points for proof count. - #[prost(message, repeated, tag = "1")] - pub proofs: ::prost::alloc::vec::Vec, - /// The time series data points for program count. - #[prost(message, repeated, tag = "2")] - pub programs: ::prost::alloc::vec::Vec, - /// The time series data points for cycle count. - #[prost(message, repeated, tag = "3")] - pub cycles: ::prost::alloc::vec::Vec, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct GetNonceRequest { - /// The address of the account. - #[prost(bytes = "vec", tag = "1")] - pub address: ::prost::alloc::vec::Vec, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, Copy, PartialEq, ::prost::Message)] -pub struct GetNonceResponse { - /// The nonce of the account. - #[prost(uint64, tag = "1")] - pub nonce: u64, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct Delegation { - /// The address of the owner. - #[prost(bytes = "vec", tag = "1")] - pub owner: ::prost::alloc::vec::Vec, - /// The address of the delegate (the account with granted permissions). - #[prost(bytes = "vec", tag = "2")] - pub delegate: ::prost::alloc::vec::Vec, - /// Whether the delegation has been accepted. - #[prost(bool, tag = "3")] - pub accepted: bool, - /// The unix timestamp of when the delegation was created. - #[prost(uint64, tag = "4")] - pub created_at: u64, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct GetFilteredDelegationsRequest { - /// The optional owner address to filter for. - #[prost(bytes = "vec", optional, tag = "1")] - pub owner: ::core::option::Option<::prost::alloc::vec::Vec>, - /// The optional maximum number of requests to return (default is 10, - /// maximum is 100). - #[prost(uint32, optional, tag = "2")] - pub limit: ::core::option::Option, - /// The optional page number to return (default is 1). - #[prost(uint32, optional, tag = "3")] - pub page: ::core::option::Option, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct GetFilteredDelegationsResponse { - /// The delegations that matched the filter criteria. - #[prost(message, repeated, tag = "1")] - pub delegations: ::prost::alloc::vec::Vec, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct AddDelegationRequest { - /// The message format of the body. - #[prost(enumeration = "MessageFormat", tag = "1")] - pub format: i32, - /// The signature of the sender. - #[prost(bytes = "vec", tag = "2")] - pub signature: ::prost::alloc::vec::Vec, - /// The body of the request. - #[prost(message, optional, tag = "3")] - pub body: ::core::option::Option, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct AddDelegationRequestBody { - /// The account nonce of the sender. - #[prost(uint64, tag = "1")] - pub nonce: u64, - /// The delegate address to add. - #[prost(bytes = "vec", tag = "2")] - pub delegate: ::prost::alloc::vec::Vec, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct AddDelegationResponse { - /// The transaction hash. - #[prost(bytes = "vec", tag = "1")] - pub tx_hash: ::prost::alloc::vec::Vec, - /// The body of the response. - #[prost(message, optional, tag = "2")] - pub body: ::core::option::Option, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, Copy, PartialEq, ::prost::Message)] -pub struct AddDelegationResponseBody {} -#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct RemoveDelegationRequest { - /// The message format of the body. - #[prost(enumeration = "MessageFormat", tag = "1")] - pub format: i32, - /// The signature of the sender. - #[prost(bytes = "vec", tag = "2")] - pub signature: ::prost::alloc::vec::Vec, - /// The body of the request. - #[prost(message, optional, tag = "3")] - pub body: ::core::option::Option, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct RemoveDelegationRequestBody { - /// The account nonce of the sender. - #[prost(uint64, tag = "1")] - pub nonce: u64, - /// The delegate address to remove. - #[prost(bytes = "vec", tag = "2")] - pub delegate: ::prost::alloc::vec::Vec, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct RemoveDelegationResponse { - /// The transaction hash. - #[prost(bytes = "vec", tag = "1")] - pub tx_hash: ::prost::alloc::vec::Vec, - /// The body of the response. - #[prost(message, optional, tag = "2")] - pub body: ::core::option::Option, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, Copy, PartialEq, ::prost::Message)] -pub struct RemoveDelegationResponseBody {} -#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct AcceptDelegationRequest { - /// The message format of the body. - #[prost(enumeration = "MessageFormat", tag = "1")] - pub format: i32, - /// The signature of the sender. - #[prost(bytes = "vec", tag = "2")] - pub signature: ::prost::alloc::vec::Vec, - /// The body of the request. - #[prost(message, optional, tag = "3")] - pub body: ::core::option::Option, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct AcceptDelegationRequestBody { - /// The account nonce of the sender. - #[prost(uint64, tag = "1")] - pub nonce: u64, - /// The address of the owner who requested the delegation - #[prost(bytes = "vec", tag = "2")] - pub owner: ::prost::alloc::vec::Vec, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct AcceptDelegationResponse { - /// The transaction hash. - #[prost(bytes = "vec", tag = "1")] - pub tx_hash: ::prost::alloc::vec::Vec, - /// The body of the response. - #[prost(message, optional, tag = "2")] - pub body: ::core::option::Option, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, Copy, PartialEq, ::prost::Message)] -pub struct AcceptDelegationResponseBody {} -#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct SetAccountNameRequest { - /// The message format of the body. - #[prost(enumeration = "MessageFormat", tag = "1")] - pub format: i32, - /// The signature of the sender. - #[prost(bytes = "vec", tag = "2")] - pub signature: ::prost::alloc::vec::Vec, - /// The body of the request. - #[prost(message, optional, tag = "3")] - pub body: ::core::option::Option, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct SetAccountNameRequestBody { - /// The account nonce of the sender. - #[prost(uint64, tag = "1")] - pub nonce: u64, - /// The address of the account to update the name of. Only the sender can - /// update the name unless authorized. - #[prost(bytes = "vec", tag = "2")] - pub address: ::prost::alloc::vec::Vec, - /// The name of the account. Must be unique. - #[prost(string, tag = "3")] - pub name: ::prost::alloc::string::String, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct SetAccountNameResponse { - /// The transaction hash. - #[prost(bytes = "vec", tag = "1")] - pub tx_hash: ::prost::alloc::vec::Vec, - /// The body of the response. - #[prost(message, optional, tag = "2")] - pub body: ::core::option::Option, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, Copy, PartialEq, ::prost::Message)] -pub struct SetAccountNameResponseBody {} -#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct GetAccountNameRequest { - /// The address of the account. - #[prost(bytes = "vec", tag = "1")] - pub address: ::prost::alloc::vec::Vec, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct GetAccountNameResponse { - /// The name of the account. - #[prost(string, optional, tag = "1")] - pub name: ::core::option::Option<::prost::alloc::string::String>, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct GetTermsSignatureRequest { - /// The address of the account. - #[prost(bytes = "vec", tag = "1")] - pub address: ::prost::alloc::vec::Vec, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, Copy, PartialEq, ::prost::Message)] -pub struct GetTermsSignatureResponse { - /// Whether the account has signed the terms. - #[prost(bool, tag = "1")] - pub is_signed: bool, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct SetTermsSignatureRequest { - /// The message format of the body. - #[prost(enumeration = "MessageFormat", tag = "1")] - pub format: i32, - /// The signature of the sender. - #[prost(bytes = "vec", tag = "2")] - pub signature: ::prost::alloc::vec::Vec, - /// The body of the request. - #[prost(message, optional, tag = "3")] - pub body: ::core::option::Option, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct SetTermsSignatureRequestBody { - /// The account nonce of the sender. - #[prost(uint64, tag = "1")] - pub nonce: u64, - /// The address of the account. - #[prost(bytes = "vec", tag = "2")] - pub address: ::prost::alloc::vec::Vec, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct SetTermsSignatureResponse { - /// The transaction hash. - #[prost(bytes = "vec", tag = "1")] - pub tx_hash: ::prost::alloc::vec::Vec, - /// The body of the response. - #[prost(message, optional, tag = "2")] - pub body: ::core::option::Option, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, Copy, PartialEq, ::prost::Message)] -pub struct SetTermsSignatureResponseBody {} -#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct Program { - /// The verification key hash. - #[prost(bytes = "vec", tag = "1")] - pub vk_hash: ::prost::alloc::vec::Vec, - /// The verification key. - #[prost(bytes = "vec", tag = "2")] - pub vk: ::prost::alloc::vec::Vec, - /// The program resource identifier. - #[prost(string, tag = "3")] - pub program_uri: ::prost::alloc::string::String, - /// The optional name of the program. - #[prost(string, optional, tag = "4")] - pub name: ::core::option::Option<::prost::alloc::string::String>, - /// The owner of the program. - #[prost(bytes = "vec", tag = "5")] - pub owner: ::prost::alloc::vec::Vec, - /// The unix timestamp of when the program was created. - #[prost(uint64, tag = "6")] - pub created_at: u64, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct GetProgramRequest { - /// The verification key hash of the program. - #[prost(bytes = "vec", tag = "1")] - pub vk_hash: ::prost::alloc::vec::Vec, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct GetProgramResponse { - /// The program details. - #[prost(message, optional, tag = "1")] - pub program: ::core::option::Option, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct CreateProgramRequest { - /// The message format of the body. - #[prost(enumeration = "MessageFormat", tag = "1")] - pub format: i32, - /// The signature of the sender. - #[prost(bytes = "vec", tag = "2")] - pub signature: ::prost::alloc::vec::Vec, - /// The body of the request. - #[prost(message, optional, tag = "3")] - pub body: ::core::option::Option, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct CreateProgramRequestBody { - /// The account nonce of the sender. - #[prost(uint64, tag = "1")] - pub nonce: u64, - /// The verification key hash. - #[prost(bytes = "vec", tag = "2")] - pub vk_hash: ::prost::alloc::vec::Vec, - /// The verification key. - #[prost(bytes = "vec", tag = "3")] - pub vk: ::prost::alloc::vec::Vec, - /// The program resource identifier. - #[prost(string, tag = "4")] - pub program_uri: ::prost::alloc::string::String, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct CreateProgramResponse { - /// The transaction hash. - #[prost(bytes = "vec", tag = "1")] - pub tx_hash: ::prost::alloc::vec::Vec, - /// The body of the response. - #[prost(message, optional, tag = "2")] - pub body: ::core::option::Option, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, Copy, PartialEq, ::prost::Message)] -pub struct CreateProgramResponseBody {} -#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct SetProgramNameRequest { - /// The message format of the body. - #[prost(enumeration = "MessageFormat", tag = "1")] - pub format: i32, - /// The signature of the sender. - #[prost(bytes = "vec", tag = "2")] - pub signature: ::prost::alloc::vec::Vec, - /// The body of the request. - #[prost(message, optional, tag = "3")] - pub body: ::core::option::Option, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct SetProgramNameRequestBody { - /// The account nonce of the sender. - #[prost(uint64, tag = "1")] - pub nonce: u64, - /// The identifier of the program to update the name of. Only the original - /// program creator can update the name unless authorized. - #[prost(bytes = "vec", tag = "2")] - pub vk_hash: ::prost::alloc::vec::Vec, - /// The name of the program. Must be unique. - #[prost(string, tag = "3")] - pub name: ::prost::alloc::string::String, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct SetProgramNameResponse { - /// The transaction hash. - #[prost(bytes = "vec", tag = "1")] - pub tx_hash: ::prost::alloc::vec::Vec, - /// The body of the response. - #[prost(message, optional, tag = "2")] - pub body: ::core::option::Option, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, Copy, PartialEq, ::prost::Message)] -pub struct SetProgramNameResponseBody {} -#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct GetBalanceRequest { - /// The address of the account. - #[prost(bytes = "vec", tag = "1")] - pub address: ::prost::alloc::vec::Vec, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct GetBalanceResponse { - /// The amount of credits owned by the account. - #[prost(string, tag = "1")] - pub amount: ::prost::alloc::string::String, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct BalanceLog { - /// The address of the account. - #[prost(bytes = "vec", tag = "1")] - pub address: ::prost::alloc::vec::Vec, - /// The type of balance change operation. - #[prost(enumeration = "BalanceOperation", tag = "2")] - pub operation: i32, - /// The amount of the change (can be positive or negative). - #[prost(string, tag = "3")] - pub amount: ::prost::alloc::string::String, - /// The transaction hash that caused this change. - #[prost(bytes = "vec", tag = "4")] - pub tx_hash: ::prost::alloc::vec::Vec, - /// The unix timestamp of when this change occurred. - #[prost(uint64, tag = "5")] - pub created_at: u64, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct GetFilteredBalanceLogsRequest { - /// The optional address to filter for. - #[prost(bytes = "vec", optional, tag = "1")] - pub address: ::core::option::Option<::prost::alloc::vec::Vec>, - /// The optional type of operations to filter for. - #[prost(enumeration = "BalanceOperation", optional, tag = "2")] - pub operation: ::core::option::Option, - /// The optional minimum unix timestamp to filter logs from. Only returns - /// logs after this timestamp. - #[prost(uint64, optional, tag = "3")] - pub minimum_timestamp: ::core::option::Option, - /// The optional maximum unix timestamp to filter logs to. Only returns - /// logs before this timestamp. - #[prost(uint64, optional, tag = "4")] - pub maximum_timestamp: ::core::option::Option, - /// The optional maximum number of logs to return (default is 10, maximum is 100). - #[prost(uint32, optional, tag = "5")] - pub limit: ::core::option::Option, - /// The optional page number to return (default is 1). - #[prost(uint32, optional, tag = "6")] - pub page: ::core::option::Option, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct GetFilteredBalanceLogsResponse { - /// The balance logs that matched the filter criteria. - #[prost(message, repeated, tag = "1")] - pub logs: ::prost::alloc::vec::Vec, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct AddCreditRequest { - /// The message format of the body. - #[prost(enumeration = "MessageFormat", tag = "1")] - pub format: i32, - /// The signature of the sender. - #[prost(bytes = "vec", tag = "2")] - pub signature: ::prost::alloc::vec::Vec, - /// The body of the request. - #[prost(message, optional, tag = "3")] - pub body: ::core::option::Option, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct AddCreditRequestBody { - /// The account nonce of the sender. - #[prost(uint64, tag = "1")] - pub nonce: u64, - /// The address of the account to add credits to. - #[prost(bytes = "vec", tag = "2")] - pub address: ::prost::alloc::vec::Vec, - /// The amount of credits to add. - #[prost(string, tag = "3")] - pub amount: ::prost::alloc::string::String, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct AddCreditResponse { - /// The transaction hash. - #[prost(bytes = "vec", tag = "1")] - pub tx_hash: ::prost::alloc::vec::Vec, - /// The body of the response. - #[prost(message, optional, tag = "2")] - pub body: ::core::option::Option, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, Copy, PartialEq, ::prost::Message)] -pub struct AddCreditResponseBody {} -#[derive(serde::Serialize, serde::Deserialize, Clone, Copy, PartialEq, ::prost::Message)] -pub struct GetLatestBridgeBlockRequest { - /// The chain ID of the bridge. - #[prost(uint32, tag = "1")] - pub chain_id: u32, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, Copy, PartialEq, ::prost::Message)] -pub struct GetLatestBridgeBlockResponse { - /// The latest processed block in the bridge. - #[prost(uint64, tag = "1")] - pub block_number: u64, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, Copy, PartialEq, ::prost::Message)] -pub struct GetGasPriceEstimateRequest { - #[prost(enumeration = "FulfillmentStrategy", tag = "1")] - pub strategy: i32, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, Copy, PartialEq, ::prost::Message)] -pub struct GetGasPriceEstimateResponse { - #[prost(uint64, tag = "1")] - pub gas_price: u64, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct GetTransactionDetailsRequest { - /// The transaction hash. - #[prost(bytes = "vec", tag = "1")] - pub tx_hash: ::prost::alloc::vec::Vec, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct TransactionDetails { - #[prost(bytes = "vec", tag = "1")] - pub tx_hash: ::prost::alloc::vec::Vec, - #[prost(bytes = "vec", tag = "2")] - pub sender: ::prost::alloc::vec::Vec, - #[prost(bytes = "vec", tag = "3")] - pub signature: ::prost::alloc::vec::Vec, - #[prost(uint64, tag = "4")] - pub nonce: u64, - #[prost(uint64, tag = "5")] - pub created_at: u64, - #[prost(string, optional, tag = "6")] - pub name: ::core::option::Option<::prost::alloc::string::String>, - #[prost(bytes = "vec", optional, tag = "7")] - pub request_id: ::core::option::Option<::prost::alloc::vec::Vec>, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct GetTransactionDetailsResponse { - #[prost(message, optional, tag = "1")] - pub transaction: ::core::option::Option, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct Reservation { - /// The address of the requester. - #[prost(bytes = "vec", tag = "1")] - pub requester: ::prost::alloc::vec::Vec, - /// The address of the fulfiller. - #[prost(bytes = "vec", tag = "2")] - pub fulfiller: ::prost::alloc::vec::Vec, - /// The optional name to refer to an alias of the requester address. - #[prost(string, optional, tag = "3")] - pub requester_name: ::core::option::Option<::prost::alloc::string::String>, - /// The optional name to refer to an alias of the fulfiller address. - #[prost(string, optional, tag = "4")] - pub fulfiller_name: ::core::option::Option<::prost::alloc::string::String>, - /// The unix timestamp of when the reservation was created. - #[prost(uint64, tag = "5")] - pub created_at: u64, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, Copy, PartialEq, ::prost::Message)] -pub struct GetFilteredReservationsRequest { - /// The optional maximum number of reservations to return (default is 10, - /// maximum is 100). - #[prost(uint32, optional, tag = "1")] - pub limit: ::core::option::Option, - /// The optional page number to return (default is 1). - #[prost(uint32, optional, tag = "2")] - pub page: ::core::option::Option, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct GetFilteredReservationsResponse { - /// The reservations that matched the filter criteria. - #[prost(message, repeated, tag = "1")] - pub reservations: ::prost::alloc::vec::Vec, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct AddReservationRequest { - /// The message format of the body. - #[prost(enumeration = "MessageFormat", tag = "1")] - pub format: i32, - /// The signature of the sender. - #[prost(bytes = "vec", tag = "2")] - pub signature: ::prost::alloc::vec::Vec, - /// The body of the request. - #[prost(message, optional, tag = "3")] - pub body: ::core::option::Option, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct AddReservationRequestBody { - /// The account nonce of the sender. - #[prost(uint64, tag = "1")] - pub nonce: u64, - /// The address of the requester to add reservation for. - #[prost(bytes = "vec", tag = "2")] - pub requester: ::prost::alloc::vec::Vec, - /// The address of the fulfiller to reserve. - #[prost(bytes = "vec", tag = "3")] - pub fulfiller: ::prost::alloc::vec::Vec, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct AddReservationResponse { - /// The transaction hash. - #[prost(bytes = "vec", tag = "1")] - pub tx_hash: ::prost::alloc::vec::Vec, - /// The body of the response. - #[prost(message, optional, tag = "2")] - pub body: ::core::option::Option, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, Copy, PartialEq, ::prost::Message)] -pub struct AddReservationResponseBody {} -#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct RemoveReservationRequest { - /// The message format of the body. - #[prost(enumeration = "MessageFormat", tag = "1")] - pub format: i32, - /// The signature of the sender. - #[prost(bytes = "vec", tag = "2")] - pub signature: ::prost::alloc::vec::Vec, - /// The body of the request. - #[prost(message, optional, tag = "3")] - pub body: ::core::option::Option, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct RemoveReservationRequestBody { - /// The account nonce of the sender. - #[prost(uint64, tag = "1")] - pub nonce: u64, - /// The address of the requester to remove reservation for. - #[prost(bytes = "vec", tag = "2")] - pub requester: ::prost::alloc::vec::Vec, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct RemoveReservationResponse { - /// The transaction hash. - #[prost(bytes = "vec", tag = "1")] - pub tx_hash: ::prost::alloc::vec::Vec, - /// The body of the response. - #[prost(message, optional, tag = "2")] - pub body: ::core::option::Option, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, Copy, PartialEq, ::prost::Message)] -pub struct RemoveReservationResponseBody {} -#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct BidRequest { - /// The message format of the body. - #[prost(enumeration = "MessageFormat", tag = "1")] - pub format: i32, - /// The signature of the sender. - #[prost(bytes = "vec", tag = "2")] - pub signature: ::prost::alloc::vec::Vec, - /// The body of the request. - #[prost(message, optional, tag = "3")] - pub body: ::core::option::Option, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct BidRequestBody { - /// The account nonce of the sender. - #[prost(uint64, tag = "1")] - pub nonce: u64, - /// The request ID to bid on. - #[prost(bytes = "vec", tag = "2")] - pub request_id: ::prost::alloc::vec::Vec, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct BidResponse { - /// The transaction hash. - #[prost(bytes = "vec", tag = "1")] - pub tx_hash: ::prost::alloc::vec::Vec, - /// The body of the response. - #[prost(message, optional, tag = "2")] - pub body: ::core::option::Option, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, Copy, PartialEq, ::prost::Message)] -pub struct BidResponseBody {} -#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct SettleRequest { - /// The message format of the body. - #[prost(enumeration = "MessageFormat", tag = "1")] - pub format: i32, - /// The signature of the sender. - #[prost(bytes = "vec", tag = "2")] - pub signature: ::prost::alloc::vec::Vec, - /// The body of the request. - #[prost(message, optional, tag = "3")] - pub body: ::core::option::Option, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct SettleRequestBody { - /// The account nonce of the sender. - #[prost(uint64, tag = "1")] - pub nonce: u64, - /// The request ID to settle bids for. - #[prost(bytes = "vec", tag = "2")] - pub request_id: ::prost::alloc::vec::Vec, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct SettleResponse { - /// The transaction hash. - #[prost(bytes = "vec", tag = "1")] - pub tx_hash: ::prost::alloc::vec::Vec, - /// The body of the response. - #[prost(message, optional, tag = "2")] - pub body: ::core::option::Option, -} -#[derive(serde::Serialize, serde::Deserialize, Clone, Copy, PartialEq, ::prost::Message)] -pub struct SettleResponseBody {} -/// Format to help decode signature in backend. -#[derive( - serde::Serialize, - serde::Deserialize, - Clone, - Copy, - Debug, - PartialEq, - Eq, - Hash, - PartialOrd, - Ord, - ::prost::Enumeration, -)] -#[repr(i32)] -pub enum MessageFormat { - /// Unspecified message format. - UnspecifiedMessageFormat = 0, - /// The message is in binary format. - Binary = 1, - /// The message is in JSON format. - Json = 2, -} -impl MessageFormat { - /// String value of the enum field names used in the ProtoBuf definition. - /// - /// The values are not transformed in any way and thus are considered stable - /// (if the ProtoBuf definition does not change) and safe for programmatic use. - pub fn as_str_name(&self) -> &'static str { - match self { - Self::UnspecifiedMessageFormat => "UNSPECIFIED_MESSAGE_FORMAT", - Self::Binary => "BINARY", - Self::Json => "JSON", - } - } - /// Creates an enum from field names used in the ProtoBuf definition. - pub fn from_str_name(value: &str) -> ::core::option::Option { - match value { - "UNSPECIFIED_MESSAGE_FORMAT" => Some(Self::UnspecifiedMessageFormat), - "BINARY" => Some(Self::Binary), - "JSON" => Some(Self::Json), - _ => None, - } - } -} -#[derive( - serde::Serialize, - serde::Deserialize, - Clone, - Copy, - Debug, - PartialEq, - Eq, - Hash, - PartialOrd, - Ord, - ::prost::Enumeration, -)] -#[repr(i32)] -pub enum ProofMode { - UnspecifiedProofMode = 0, - /// The core proof mode. - Core = 1, - /// The compressed proof mode. - Compressed = 2, - /// The plonk proof mode. - Plonk = 3, - /// The groth16 proof mode. - Groth16 = 4, -} -impl ProofMode { - /// String value of the enum field names used in the ProtoBuf definition. - /// - /// The values are not transformed in any way and thus are considered stable - /// (if the ProtoBuf definition does not change) and safe for programmatic use. - pub fn as_str_name(&self) -> &'static str { - match self { - Self::UnspecifiedProofMode => "UNSPECIFIED_PROOF_MODE", - Self::Core => "CORE", - Self::Compressed => "COMPRESSED", - Self::Plonk => "PLONK", - Self::Groth16 => "GROTH16", - } - } - /// Creates an enum from field names used in the ProtoBuf definition. - pub fn from_str_name(value: &str) -> ::core::option::Option { - match value { - "UNSPECIFIED_PROOF_MODE" => Some(Self::UnspecifiedProofMode), - "CORE" => Some(Self::Core), - "COMPRESSED" => Some(Self::Compressed), - "PLONK" => Some(Self::Plonk), - "GROTH16" => Some(Self::Groth16), - _ => None, - } - } -} -/// The different strategies that can be used for fulfilling requests. -#[derive( - serde::Serialize, - serde::Deserialize, - Clone, - Copy, - Debug, - PartialEq, - Eq, - Hash, - PartialOrd, - Ord, - ::prost::Enumeration, -)] -#[repr(i32)] -pub enum FulfillmentStrategy { - UnspecifiedFulfillmentStrategy = 0, - /// The hosted fulfillment strategy. Uses Succinct's on-demand prover to fulfill requests. - Hosted = 1, - /// The reserved fulfillment strategy. Uses an already existing agreement with a - /// fulfiller to fulfill requests. - Reserved = 2, - /// The auction fulfillment strategy. Uses a decentralized proof contest to - /// fulfill requests. - Auction = 3, -} -impl FulfillmentStrategy { - /// String value of the enum field names used in the ProtoBuf definition. - /// - /// The values are not transformed in any way and thus are considered stable - /// (if the ProtoBuf definition does not change) and safe for programmatic use. - pub fn as_str_name(&self) -> &'static str { - match self { - Self::UnspecifiedFulfillmentStrategy => "UNSPECIFIED_FULFILLMENT_STRATEGY", - Self::Hosted => "HOSTED", - Self::Reserved => "RESERVED", - Self::Auction => "AUCTION", - } - } - /// Creates an enum from field names used in the ProtoBuf definition. - pub fn from_str_name(value: &str) -> ::core::option::Option { - match value { - "UNSPECIFIED_FULFILLMENT_STRATEGY" => Some(Self::UnspecifiedFulfillmentStrategy), - "HOSTED" => Some(Self::Hosted), - "RESERVED" => Some(Self::Reserved), - "AUCTION" => Some(Self::Auction), - _ => None, - } - } -} -/// The different fulfillment statuses that a request can be in. -#[derive( - serde::Serialize, - serde::Deserialize, - Clone, - Copy, - Debug, - PartialEq, - Eq, - Hash, - PartialOrd, - Ord, - ::prost::Enumeration, -)] -#[repr(i32)] -pub enum FulfillmentStatus { - UnspecifiedFulfillmentStatus = 0, - /// The request has been requested. - Requested = 1, - /// The request has been assigned to a fulfiller. - Assigned = 2, - /// The request has been fulfilled. - Fulfilled = 3, - /// The request cannot be fulfilled. - Unfulfillable = 4, -} -impl FulfillmentStatus { - /// String value of the enum field names used in the ProtoBuf definition. - /// - /// The values are not transformed in any way and thus are considered stable - /// (if the ProtoBuf definition does not change) and safe for programmatic use. - pub fn as_str_name(&self) -> &'static str { - match self { - Self::UnspecifiedFulfillmentStatus => "UNSPECIFIED_FULFILLMENT_STATUS", - Self::Requested => "REQUESTED", - Self::Assigned => "ASSIGNED", - Self::Fulfilled => "FULFILLED", - Self::Unfulfillable => "UNFULFILLABLE", - } - } - /// Creates an enum from field names used in the ProtoBuf definition. - pub fn from_str_name(value: &str) -> ::core::option::Option { - match value { - "UNSPECIFIED_FULFILLMENT_STATUS" => Some(Self::UnspecifiedFulfillmentStatus), - "REQUESTED" => Some(Self::Requested), - "ASSIGNED" => Some(Self::Assigned), - "FULFILLED" => Some(Self::Fulfilled), - "UNFULFILLABLE" => Some(Self::Unfulfillable), - _ => None, - } - } -} -/// The different execution statuses that a request can be in. -#[derive( - serde::Serialize, - serde::Deserialize, - Clone, - Copy, - Debug, - PartialEq, - Eq, - Hash, - PartialOrd, - Ord, - ::prost::Enumeration, -)] -#[repr(i32)] -pub enum ExecutionStatus { - UnspecifiedExecutionStatus = 0, - /// The request has not been executed. - Unexecuted = 1, - /// The request has been executed. - Executed = 2, - /// The request cannot be executed. - Unexecutable = 3, -} -impl ExecutionStatus { - /// String value of the enum field names used in the ProtoBuf definition. - /// - /// The values are not transformed in any way and thus are considered stable - /// (if the ProtoBuf definition does not change) and safe for programmatic use. - pub fn as_str_name(&self) -> &'static str { - match self { - Self::UnspecifiedExecutionStatus => "UNSPECIFIED_EXECUTION_STATUS", - Self::Unexecuted => "UNEXECUTED", - Self::Executed => "EXECUTED", - Self::Unexecutable => "UNEXECUTABLE", - } - } - /// Creates an enum from field names used in the ProtoBuf definition. - pub fn from_str_name(value: &str) -> ::core::option::Option { - match value { - "UNSPECIFIED_EXECUTION_STATUS" => Some(Self::UnspecifiedExecutionStatus), - "UNEXECUTED" => Some(Self::Unexecuted), - "EXECUTED" => Some(Self::Executed), - "UNEXECUTABLE" => Some(Self::Unexecutable), - _ => None, - } - } -} -/// The different types of balance changes that can occur. -#[derive( - serde::Serialize, - serde::Deserialize, - Clone, - Copy, - Debug, - PartialEq, - Eq, - Hash, - PartialOrd, - Ord, - ::prost::Enumeration, -)] -#[repr(i32)] -pub enum BalanceOperation { - UnspecifiedBalanceChangeOperation = 0, - /// A deposit operation (positive). - Deposit = 1, - /// A withdrawal operation (negative). - Withdrawal = 2, - /// A credit operation (positive). - Credit = 3, - /// A deduction operation (negative). - Deduction = 4, - /// A refund operation (positive). - Refund = 5, - /// A bid operation (negative). - Bid = 6, -} -impl BalanceOperation { - /// String value of the enum field names used in the ProtoBuf definition. - /// - /// The values are not transformed in any way and thus are considered stable - /// (if the ProtoBuf definition does not change) and safe for programmatic use. - pub fn as_str_name(&self) -> &'static str { - match self { - Self::UnspecifiedBalanceChangeOperation => "UNSPECIFIED_BALANCE_CHANGE_OPERATION", - Self::Deposit => "DEPOSIT", - Self::Withdrawal => "WITHDRAWAL", - Self::Credit => "CREDIT", - Self::Deduction => "DEDUCTION", - Self::Refund => "REFUND", - Self::Bid => "BID", - } - } - /// Creates an enum from field names used in the ProtoBuf definition. - pub fn from_str_name(value: &str) -> ::core::option::Option { - match value { - "UNSPECIFIED_BALANCE_CHANGE_OPERATION" => Some(Self::UnspecifiedBalanceChangeOperation), - "DEPOSIT" => Some(Self::Deposit), - "WITHDRAWAL" => Some(Self::Withdrawal), - "CREDIT" => Some(Self::Credit), - "DEDUCTION" => Some(Self::Deduction), - "REFUND" => Some(Self::Refund), - "BID" => Some(Self::Bid), - _ => None, - } - } -} -/// Generated client implementations. -pub mod prover_network_client { - #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] - use tonic::codegen::http::Uri; - use tonic::codegen::*; - #[derive(Debug, Clone)] - pub struct ProverNetworkClient { - inner: tonic::client::Grpc, - } - impl ProverNetworkClient { - /// Attempt to create a new client by connecting to a given endpoint. - pub async fn connect(dst: D) -> Result - where - D: TryInto, - D::Error: Into, - { - let conn = tonic::transport::Endpoint::new(dst)?.connect().await?; - Ok(Self::new(conn)) - } - } - impl ProverNetworkClient - where - T: tonic::client::GrpcService, - T::Error: Into, - T::ResponseBody: Body + std::marker::Send + 'static, - ::Error: Into + std::marker::Send, - { - pub fn new(inner: T) -> Self { - let inner = tonic::client::Grpc::new(inner); - Self { inner } - } - pub fn with_origin(inner: T, origin: Uri) -> Self { - let inner = tonic::client::Grpc::with_origin(inner, origin); - Self { inner } - } - pub fn with_interceptor( - inner: T, - interceptor: F, - ) -> ProverNetworkClient> - where - F: tonic::service::Interceptor, - T::ResponseBody: Default, - T: tonic::codegen::Service< - http::Request, - Response = http::Response< - >::ResponseBody, - >, - >, - >>::Error: - Into + std::marker::Send + std::marker::Sync, - { - ProverNetworkClient::new(InterceptedService::new(inner, interceptor)) - } - /// Compress requests with the given encoding. - /// - /// This requires the server to support it otherwise it might respond with an - /// error. - #[must_use] - pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { - self.inner = self.inner.send_compressed(encoding); - self - } - /// Enable decompressing responses. - #[must_use] - pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { - self.inner = self.inner.accept_compressed(encoding); - self - } - /// Limits the maximum size of a decoded message. - /// - /// Default: `4MB` - #[must_use] - pub fn max_decoding_message_size(mut self, limit: usize) -> Self { - self.inner = self.inner.max_decoding_message_size(limit); - self - } - /// Limits the maximum size of an encoded message. - /// - /// Default: `usize::MAX` - #[must_use] - pub fn max_encoding_message_size(mut self, limit: usize) -> Self { - self.inner = self.inner.max_encoding_message_size(limit); - self - } - /// Creates a proof request. - pub async fn request_proof( - &mut self, - request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> - { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/network.ProverNetwork/RequestProof"); - let mut req = request.into_request(); - req.extensions_mut().insert(GrpcMethod::new("network.ProverNetwork", "RequestProof")); - self.inner.unary(req, path, codec).await - } - /// Fulfills a proof request. Only callable by the assigned fulfiller. - pub async fn fulfill_proof( - &mut self, - request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> - { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/network.ProverNetwork/FulfillProof"); - let mut req = request.into_request(); - req.extensions_mut().insert(GrpcMethod::new("network.ProverNetwork", "FulfillProof")); - self.inner.unary(req, path, codec).await - } - /// Executes a proof request. Only callable by the execution oracle. - pub async fn execute_proof( - &mut self, - request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> - { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/network.ProverNetwork/ExecuteProof"); - let mut req = request.into_request(); - req.extensions_mut().insert(GrpcMethod::new("network.ProverNetwork", "ExecuteProof")); - self.inner.unary(req, path, codec).await - } - /// Fails fulfillment. Only callable by the assigned fulfiller. - pub async fn fail_fulfillment( - &mut self, - request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> - { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = - http::uri::PathAndQuery::from_static("/network.ProverNetwork/FailFulfillment"); - let mut req = request.into_request(); - req.extensions_mut() - .insert(GrpcMethod::new("network.ProverNetwork", "FailFulfillment")); - self.inner.unary(req, path, codec).await - } - /// Fails execution. Only callable by the execution oracle. - pub async fn fail_execution( - &mut self, - request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> - { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/network.ProverNetwork/FailExecution"); - let mut req = request.into_request(); - req.extensions_mut().insert(GrpcMethod::new("network.ProverNetwork", "FailExecution")); - self.inner.unary(req, path, codec).await - } - /// Get the status of a proof request. - pub async fn get_proof_request_status( - &mut self, - request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> - { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/network.ProverNetwork/GetProofRequestStatus", - ); - let mut req = request.into_request(); - req.extensions_mut() - .insert(GrpcMethod::new("network.ProverNetwork", "GetProofRequestStatus")); - self.inner.unary(req, path, codec).await - } - /// Get the details of a proof request. - pub async fn get_proof_request_details( - &mut self, - request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - > { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/network.ProverNetwork/GetProofRequestDetails", - ); - let mut req = request.into_request(); - req.extensions_mut() - .insert(GrpcMethod::new("network.ProverNetwork", "GetProofRequestDetails")); - self.inner.unary(req, path, codec).await - } - /// Get the proof requests that meet the filter criteria. - pub async fn get_filtered_proof_requests( - &mut self, - request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - > { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/network.ProverNetwork/GetFilteredProofRequests", - ); - let mut req = request.into_request(); - req.extensions_mut() - .insert(GrpcMethod::new("network.ProverNetwork", "GetFilteredProofRequests")); - self.inner.unary(req, path, codec).await - } - /// Search for proof requests, programs, and requesters. - pub async fn get_search_results( - &mut self, - request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> - { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = - http::uri::PathAndQuery::from_static("/network.ProverNetwork/GetSearchResults"); - let mut req = request.into_request(); - req.extensions_mut() - .insert(GrpcMethod::new("network.ProverNetwork", "GetSearchResults")); - self.inner.unary(req, path, codec).await - } - /// Get metrics for proof requests. - pub async fn get_proof_request_metrics( - &mut self, - request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - > { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/network.ProverNetwork/GetProofRequestMetrics", - ); - let mut req = request.into_request(); - req.extensions_mut() - .insert(GrpcMethod::new("network.ProverNetwork", "GetProofRequestMetrics")); - self.inner.unary(req, path, codec).await - } - /// Get time series data for proof requests. - pub async fn get_proof_request_graph( - &mut self, - request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> - { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = - http::uri::PathAndQuery::from_static("/network.ProverNetwork/GetProofRequestGraph"); - let mut req = request.into_request(); - req.extensions_mut() - .insert(GrpcMethod::new("network.ProverNetwork", "GetProofRequestGraph")); - self.inner.unary(req, path, codec).await - } - /// Get analytics graphs for proof requests. - pub async fn get_analytics_graphs( - &mut self, - request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> - { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = - http::uri::PathAndQuery::from_static("/network.ProverNetwork/GetAnalyticsGraphs"); - let mut req = request.into_request(); - req.extensions_mut() - .insert(GrpcMethod::new("network.ProverNetwork", "GetAnalyticsGraphs")); - self.inner.unary(req, path, codec).await - } - /// Get the nonce of the account. - pub async fn get_nonce( - &mut self, - request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/network.ProverNetwork/GetNonce"); - let mut req = request.into_request(); - req.extensions_mut().insert(GrpcMethod::new("network.ProverNetwork", "GetNonce")); - self.inner.unary(req, path, codec).await - } - /// Get the delegations of the account. - pub async fn get_filtered_delegations( - &mut self, - request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - > { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/network.ProverNetwork/GetFilteredDelegations", - ); - let mut req = request.into_request(); - req.extensions_mut() - .insert(GrpcMethod::new("network.ProverNetwork", "GetFilteredDelegations")); - self.inner.unary(req, path, codec).await - } - /// Add a delegation. Only callable by the owner of an account. - pub async fn add_delegation( - &mut self, - request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> - { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/network.ProverNetwork/AddDelegation"); - let mut req = request.into_request(); - req.extensions_mut().insert(GrpcMethod::new("network.ProverNetwork", "AddDelegation")); - self.inner.unary(req, path, codec).await - } - /// Remove a delegation. Only callable by the owner of an account. - pub async fn remove_delegation( - &mut self, - request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> - { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = - http::uri::PathAndQuery::from_static("/network.ProverNetwork/RemoveDelegation"); - let mut req = request.into_request(); - req.extensions_mut() - .insert(GrpcMethod::new("network.ProverNetwork", "RemoveDelegation")); - self.inner.unary(req, path, codec).await - } - /// Accept a delegation. Only callable by the delegate of a delegation. - pub async fn accept_delegation( - &mut self, - request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> - { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = - http::uri::PathAndQuery::from_static("/network.ProverNetwork/AcceptDelegation"); - let mut req = request.into_request(); - req.extensions_mut() - .insert(GrpcMethod::new("network.ProverNetwork", "AcceptDelegation")); - self.inner.unary(req, path, codec).await - } - /// Set the name of the account. Only callable by the owner of an account. - pub async fn set_account_name( - &mut self, - request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> - { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = - http::uri::PathAndQuery::from_static("/network.ProverNetwork/SetAccountName"); - let mut req = request.into_request(); - req.extensions_mut().insert(GrpcMethod::new("network.ProverNetwork", "SetAccountName")); - self.inner.unary(req, path, codec).await - } - /// Get the name of the account. - pub async fn get_account_name( - &mut self, - request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> - { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = - http::uri::PathAndQuery::from_static("/network.ProverNetwork/GetAccountName"); - let mut req = request.into_request(); - req.extensions_mut().insert(GrpcMethod::new("network.ProverNetwork", "GetAccountName")); - self.inner.unary(req, path, codec).await - } - /// Get whether the account has signed the terms. - pub async fn get_terms_signature( - &mut self, - request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> - { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = - http::uri::PathAndQuery::from_static("/network.ProverNetwork/GetTermsSignature"); - let mut req = request.into_request(); - req.extensions_mut() - .insert(GrpcMethod::new("network.ProverNetwork", "GetTermsSignature")); - self.inner.unary(req, path, codec).await - } - /// Set whether the account has signed the terms. - pub async fn set_terms_signature( - &mut self, - request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> - { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = - http::uri::PathAndQuery::from_static("/network.ProverNetwork/SetTermsSignature"); - let mut req = request.into_request(); - req.extensions_mut() - .insert(GrpcMethod::new("network.ProverNetwork", "SetTermsSignature")); - self.inner.unary(req, path, codec).await - } - /// Get metadata about a program. - pub async fn get_program( - &mut self, - request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> - { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/network.ProverNetwork/GetProgram"); - let mut req = request.into_request(); - req.extensions_mut().insert(GrpcMethod::new("network.ProverNetwork", "GetProgram")); - self.inner.unary(req, path, codec).await - } - /// Create a new program. Must be called before requesting proofs. - pub async fn create_program( - &mut self, - request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> - { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/network.ProverNetwork/CreateProgram"); - let mut req = request.into_request(); - req.extensions_mut().insert(GrpcMethod::new("network.ProverNetwork", "CreateProgram")); - self.inner.unary(req, path, codec).await - } - /// Set the name of the program. Only callable by the owner. - pub async fn set_program_name( - &mut self, - request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> - { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = - http::uri::PathAndQuery::from_static("/network.ProverNetwork/SetProgramName"); - let mut req = request.into_request(); - req.extensions_mut().insert(GrpcMethod::new("network.ProverNetwork", "SetProgramName")); - self.inner.unary(req, path, codec).await - } - /// Get the available balance of an account. - pub async fn get_balance( - &mut self, - request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> - { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/network.ProverNetwork/GetBalance"); - let mut req = request.into_request(); - req.extensions_mut().insert(GrpcMethod::new("network.ProverNetwork", "GetBalance")); - self.inner.unary(req, path, codec).await - } - /// Get the balance logs that meet the filter criteria. - pub async fn get_filtered_balance_logs( - &mut self, - request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - > { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/network.ProverNetwork/GetFilteredBalanceLogs", - ); - let mut req = request.into_request(); - req.extensions_mut() - .insert(GrpcMethod::new("network.ProverNetwork", "GetFilteredBalanceLogs")); - self.inner.unary(req, path, codec).await - } - /// Add credit to an account. - pub async fn add_credit( - &mut self, - request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/network.ProverNetwork/AddCredit"); - let mut req = request.into_request(); - req.extensions_mut().insert(GrpcMethod::new("network.ProverNetwork", "AddCredit")); - self.inner.unary(req, path, codec).await - } - /// Get the latest processed block in the bridge. - pub async fn get_latest_bridge_block( - &mut self, - request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> - { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = - http::uri::PathAndQuery::from_static("/network.ProverNetwork/GetLatestBridgeBlock"); - let mut req = request.into_request(); - req.extensions_mut() - .insert(GrpcMethod::new("network.ProverNetwork", "GetLatestBridgeBlock")); - self.inner.unary(req, path, codec).await - } - /// Get the gas price estimate for a given fulfillment strategy. - pub async fn get_gas_price_estimate( - &mut self, - request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> - { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = - http::uri::PathAndQuery::from_static("/network.ProverNetwork/GetGasPriceEstimate"); - let mut req = request.into_request(); - req.extensions_mut() - .insert(GrpcMethod::new("network.ProverNetwork", "GetGasPriceEstimate")); - self.inner.unary(req, path, codec).await - } - /// Get the details of a transaction. - pub async fn get_transaction_details( - &mut self, - request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> - { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/network.ProverNetwork/GetTransactionDetails", - ); - let mut req = request.into_request(); - req.extensions_mut() - .insert(GrpcMethod::new("network.ProverNetwork", "GetTransactionDetails")); - self.inner.unary(req, path, codec).await - } - /// Get the reservations that meet the filter criteria. - pub async fn get_filtered_reservations( - &mut self, - request: impl tonic::IntoRequest, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - > { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static( - "/network.ProverNetwork/GetFilteredReservations", - ); - let mut req = request.into_request(); - req.extensions_mut() - .insert(GrpcMethod::new("network.ProverNetwork", "GetFilteredReservations")); - self.inner.unary(req, path, codec).await - } - /// Add a reservation for a requester. - pub async fn add_reservation( - &mut self, - request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> - { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = - http::uri::PathAndQuery::from_static("/network.ProverNetwork/AddReservation"); - let mut req = request.into_request(); - req.extensions_mut().insert(GrpcMethod::new("network.ProverNetwork", "AddReservation")); - self.inner.unary(req, path, codec).await - } - /// Remove a reservation for a requester. - pub async fn remove_reservation( - &mut self, - request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> - { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = - http::uri::PathAndQuery::from_static("/network.ProverNetwork/RemoveReservation"); - let mut req = request.into_request(); - req.extensions_mut() - .insert(GrpcMethod::new("network.ProverNetwork", "RemoveReservation")); - self.inner.unary(req, path, codec).await - } - /// Bid for a proof request. Provers that want to be assigned this request must first - /// bid on it. - pub async fn bid( - &mut self, - request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/network.ProverNetwork/Bid"); - let mut req = request.into_request(); - req.extensions_mut().insert(GrpcMethod::new("network.ProverNetwork", "Bid")); - self.inner.unary(req, path, codec).await - } - /// Settle the bids on a proof request to choose the assigned prover. Only callable by - /// the approved settler. - pub async fn settle( - &mut self, - request: impl tonic::IntoRequest, - ) -> std::result::Result, tonic::Status> { - self.inner.ready().await.map_err(|e| { - tonic::Status::new( - tonic::Code::Unknown, - format!("Service was not ready: {}", e.into()), - ) - })?; - let codec = tonic::codec::ProstCodec::default(); - let path = http::uri::PathAndQuery::from_static("/network.ProverNetwork/Settle"); - let mut req = request.into_request(); - req.extensions_mut().insert(GrpcMethod::new("network.ProverNetwork", "Settle")); - self.inner.unary(req, path, codec).await - } - } -} -/// Generated server implementations. -pub mod prover_network_server { - #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] - use tonic::codegen::*; - /// Generated trait containing gRPC methods that should be implemented for use with ProverNetworkServer. - #[async_trait] - pub trait ProverNetwork: std::marker::Send + std::marker::Sync + 'static { - /// Creates a proof request. - async fn request_proof( - &self, - request: tonic::Request, - ) -> std::result::Result, tonic::Status>; - /// Fulfills a proof request. Only callable by the assigned fulfiller. - async fn fulfill_proof( - &self, - request: tonic::Request, - ) -> std::result::Result, tonic::Status>; - /// Executes a proof request. Only callable by the execution oracle. - async fn execute_proof( - &self, - request: tonic::Request, - ) -> std::result::Result, tonic::Status>; - /// Fails fulfillment. Only callable by the assigned fulfiller. - async fn fail_fulfillment( - &self, - request: tonic::Request, - ) -> std::result::Result, tonic::Status>; - /// Fails execution. Only callable by the execution oracle. - async fn fail_execution( - &self, - request: tonic::Request, - ) -> std::result::Result, tonic::Status>; - /// Get the status of a proof request. - async fn get_proof_request_status( - &self, - request: tonic::Request, - ) -> std::result::Result, tonic::Status>; - /// Get the details of a proof request. - async fn get_proof_request_details( - &self, - request: tonic::Request, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - >; - /// Get the proof requests that meet the filter criteria. - async fn get_filtered_proof_requests( - &self, - request: tonic::Request, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - >; - /// Search for proof requests, programs, and requesters. - async fn get_search_results( - &self, - request: tonic::Request, - ) -> std::result::Result, tonic::Status>; - /// Get metrics for proof requests. - async fn get_proof_request_metrics( - &self, - request: tonic::Request, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - >; - /// Get time series data for proof requests. - async fn get_proof_request_graph( - &self, - request: tonic::Request, - ) -> std::result::Result, tonic::Status>; - /// Get analytics graphs for proof requests. - async fn get_analytics_graphs( - &self, - request: tonic::Request, - ) -> std::result::Result, tonic::Status>; - /// Get the nonce of the account. - async fn get_nonce( - &self, - request: tonic::Request, - ) -> std::result::Result, tonic::Status>; - /// Get the delegations of the account. - async fn get_filtered_delegations( - &self, - request: tonic::Request, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - >; - /// Add a delegation. Only callable by the owner of an account. - async fn add_delegation( - &self, - request: tonic::Request, - ) -> std::result::Result, tonic::Status>; - /// Remove a delegation. Only callable by the owner of an account. - async fn remove_delegation( - &self, - request: tonic::Request, - ) -> std::result::Result, tonic::Status>; - /// Accept a delegation. Only callable by the delegate of a delegation. - async fn accept_delegation( - &self, - request: tonic::Request, - ) -> std::result::Result, tonic::Status>; - /// Set the name of the account. Only callable by the owner of an account. - async fn set_account_name( - &self, - request: tonic::Request, - ) -> std::result::Result, tonic::Status>; - /// Get the name of the account. - async fn get_account_name( - &self, - request: tonic::Request, - ) -> std::result::Result, tonic::Status>; - /// Get whether the account has signed the terms. - async fn get_terms_signature( - &self, - request: tonic::Request, - ) -> std::result::Result, tonic::Status>; - /// Set whether the account has signed the terms. - async fn set_terms_signature( - &self, - request: tonic::Request, - ) -> std::result::Result, tonic::Status>; - /// Get metadata about a program. - async fn get_program( - &self, - request: tonic::Request, - ) -> std::result::Result, tonic::Status>; - /// Create a new program. Must be called before requesting proofs. - async fn create_program( - &self, - request: tonic::Request, - ) -> std::result::Result, tonic::Status>; - /// Set the name of the program. Only callable by the owner. - async fn set_program_name( - &self, - request: tonic::Request, - ) -> std::result::Result, tonic::Status>; - /// Get the available balance of an account. - async fn get_balance( - &self, - request: tonic::Request, - ) -> std::result::Result, tonic::Status>; - /// Get the balance logs that meet the filter criteria. - async fn get_filtered_balance_logs( - &self, - request: tonic::Request, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - >; - /// Add credit to an account. - async fn add_credit( - &self, - request: tonic::Request, - ) -> std::result::Result, tonic::Status>; - /// Get the latest processed block in the bridge. - async fn get_latest_bridge_block( - &self, - request: tonic::Request, - ) -> std::result::Result, tonic::Status>; - /// Get the gas price estimate for a given fulfillment strategy. - async fn get_gas_price_estimate( - &self, - request: tonic::Request, - ) -> std::result::Result, tonic::Status>; - /// Get the details of a transaction. - async fn get_transaction_details( - &self, - request: tonic::Request, - ) -> std::result::Result, tonic::Status>; - /// Get the reservations that meet the filter criteria. - async fn get_filtered_reservations( - &self, - request: tonic::Request, - ) -> std::result::Result< - tonic::Response, - tonic::Status, - >; - /// Add a reservation for a requester. - async fn add_reservation( - &self, - request: tonic::Request, - ) -> std::result::Result, tonic::Status>; - /// Remove a reservation for a requester. - async fn remove_reservation( - &self, - request: tonic::Request, - ) -> std::result::Result, tonic::Status>; - /// Bid for a proof request. Provers that want to be assigned this request must first - /// bid on it. - async fn bid( - &self, - request: tonic::Request, - ) -> std::result::Result, tonic::Status>; - /// Settle the bids on a proof request to choose the assigned prover. Only callable by - /// the approved settler. - async fn settle( - &self, - request: tonic::Request, - ) -> std::result::Result, tonic::Status>; - } - #[derive(Debug)] - pub struct ProverNetworkServer { - inner: Arc, - accept_compression_encodings: EnabledCompressionEncodings, - send_compression_encodings: EnabledCompressionEncodings, - max_decoding_message_size: Option, - max_encoding_message_size: Option, - } - impl ProverNetworkServer { - pub fn new(inner: T) -> Self { - Self::from_arc(Arc::new(inner)) - } - pub fn from_arc(inner: Arc) -> Self { - Self { - inner, - accept_compression_encodings: Default::default(), - send_compression_encodings: Default::default(), - max_decoding_message_size: None, - max_encoding_message_size: None, - } - } - pub fn with_interceptor(inner: T, interceptor: F) -> InterceptedService - where - F: tonic::service::Interceptor, - { - InterceptedService::new(Self::new(inner), interceptor) - } - /// Enable decompressing requests with the given encoding. - #[must_use] - pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { - self.accept_compression_encodings.enable(encoding); - self - } - /// Compress responses with the given encoding, if the client supports it. - #[must_use] - pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { - self.send_compression_encodings.enable(encoding); - self - } - /// Limits the maximum size of a decoded message. - /// - /// Default: `4MB` - #[must_use] - pub fn max_decoding_message_size(mut self, limit: usize) -> Self { - self.max_decoding_message_size = Some(limit); - self - } - /// Limits the maximum size of an encoded message. - /// - /// Default: `usize::MAX` - #[must_use] - pub fn max_encoding_message_size(mut self, limit: usize) -> Self { - self.max_encoding_message_size = Some(limit); - self - } - } - impl tonic::codegen::Service> for ProverNetworkServer - where - T: ProverNetwork, - B: Body + std::marker::Send + 'static, - B::Error: Into + std::marker::Send + 'static, - { - type Response = http::Response; - type Error = std::convert::Infallible; - type Future = BoxFuture; - fn poll_ready( - &mut self, - _cx: &mut Context<'_>, - ) -> Poll> { - Poll::Ready(Ok(())) - } - fn call(&mut self, req: http::Request) -> Self::Future { - match req.uri().path() { - "/network.ProverNetwork/RequestProof" => { - #[allow(non_camel_case_types)] - struct RequestProofSvc(pub Arc); - impl tonic::server::UnaryService - for RequestProofSvc - { - type Response = super::RequestProofResponse; - type Future = BoxFuture, tonic::Status>; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { - let inner = Arc::clone(&self.0); - let fut = async move { - ::request_proof(&inner, request).await - }; - Box::pin(fut) - } - } - let accept_compression_encodings = self.accept_compression_encodings; - let send_compression_encodings = self.send_compression_encodings; - let max_decoding_message_size = self.max_decoding_message_size; - let max_encoding_message_size = self.max_encoding_message_size; - let inner = self.inner.clone(); - let fut = async move { - let method = RequestProofSvc(inner); - let codec = tonic::codec::ProstCodec::default(); - let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); - let res = grpc.unary(method, req).await; - Ok(res) - }; - Box::pin(fut) - } - "/network.ProverNetwork/FulfillProof" => { - #[allow(non_camel_case_types)] - struct FulfillProofSvc(pub Arc); - impl tonic::server::UnaryService - for FulfillProofSvc - { - type Response = super::FulfillProofResponse; - type Future = BoxFuture, tonic::Status>; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { - let inner = Arc::clone(&self.0); - let fut = async move { - ::fulfill_proof(&inner, request).await - }; - Box::pin(fut) - } - } - let accept_compression_encodings = self.accept_compression_encodings; - let send_compression_encodings = self.send_compression_encodings; - let max_decoding_message_size = self.max_decoding_message_size; - let max_encoding_message_size = self.max_encoding_message_size; - let inner = self.inner.clone(); - let fut = async move { - let method = FulfillProofSvc(inner); - let codec = tonic::codec::ProstCodec::default(); - let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); - let res = grpc.unary(method, req).await; - Ok(res) - }; - Box::pin(fut) - } - "/network.ProverNetwork/ExecuteProof" => { - #[allow(non_camel_case_types)] - struct ExecuteProofSvc(pub Arc); - impl tonic::server::UnaryService - for ExecuteProofSvc - { - type Response = super::ExecuteProofResponse; - type Future = BoxFuture, tonic::Status>; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { - let inner = Arc::clone(&self.0); - let fut = async move { - ::execute_proof(&inner, request).await - }; - Box::pin(fut) - } - } - let accept_compression_encodings = self.accept_compression_encodings; - let send_compression_encodings = self.send_compression_encodings; - let max_decoding_message_size = self.max_decoding_message_size; - let max_encoding_message_size = self.max_encoding_message_size; - let inner = self.inner.clone(); - let fut = async move { - let method = ExecuteProofSvc(inner); - let codec = tonic::codec::ProstCodec::default(); - let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); - let res = grpc.unary(method, req).await; - Ok(res) - }; - Box::pin(fut) - } - "/network.ProverNetwork/FailFulfillment" => { - #[allow(non_camel_case_types)] - struct FailFulfillmentSvc(pub Arc); - impl - tonic::server::UnaryService - for FailFulfillmentSvc - { - type Response = super::FailFulfillmentResponse; - type Future = BoxFuture, tonic::Status>; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { - let inner = Arc::clone(&self.0); - let fut = async move { - ::fail_fulfillment(&inner, request).await - }; - Box::pin(fut) - } - } - let accept_compression_encodings = self.accept_compression_encodings; - let send_compression_encodings = self.send_compression_encodings; - let max_decoding_message_size = self.max_decoding_message_size; - let max_encoding_message_size = self.max_encoding_message_size; - let inner = self.inner.clone(); - let fut = async move { - let method = FailFulfillmentSvc(inner); - let codec = tonic::codec::ProstCodec::default(); - let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); - let res = grpc.unary(method, req).await; - Ok(res) - }; - Box::pin(fut) - } - "/network.ProverNetwork/FailExecution" => { - #[allow(non_camel_case_types)] - struct FailExecutionSvc(pub Arc); - impl tonic::server::UnaryService - for FailExecutionSvc - { - type Response = super::FailExecutionResponse; - type Future = BoxFuture, tonic::Status>; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { - let inner = Arc::clone(&self.0); - let fut = async move { - ::fail_execution(&inner, request).await - }; - Box::pin(fut) - } - } - let accept_compression_encodings = self.accept_compression_encodings; - let send_compression_encodings = self.send_compression_encodings; - let max_decoding_message_size = self.max_decoding_message_size; - let max_encoding_message_size = self.max_encoding_message_size; - let inner = self.inner.clone(); - let fut = async move { - let method = FailExecutionSvc(inner); - let codec = tonic::codec::ProstCodec::default(); - let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); - let res = grpc.unary(method, req).await; - Ok(res) - }; - Box::pin(fut) - } - "/network.ProverNetwork/GetProofRequestStatus" => { - #[allow(non_camel_case_types)] - struct GetProofRequestStatusSvc(pub Arc); - impl - tonic::server::UnaryService - for GetProofRequestStatusSvc - { - type Response = super::GetProofRequestStatusResponse; - type Future = BoxFuture, tonic::Status>; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { - let inner = Arc::clone(&self.0); - let fut = async move { - ::get_proof_request_status(&inner, request) - .await - }; - Box::pin(fut) - } - } - let accept_compression_encodings = self.accept_compression_encodings; - let send_compression_encodings = self.send_compression_encodings; - let max_decoding_message_size = self.max_decoding_message_size; - let max_encoding_message_size = self.max_encoding_message_size; - let inner = self.inner.clone(); - let fut = async move { - let method = GetProofRequestStatusSvc(inner); - let codec = tonic::codec::ProstCodec::default(); - let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); - let res = grpc.unary(method, req).await; - Ok(res) - }; - Box::pin(fut) - } - "/network.ProverNetwork/GetProofRequestDetails" => { - #[allow(non_camel_case_types)] - struct GetProofRequestDetailsSvc(pub Arc); - impl - tonic::server::UnaryService - for GetProofRequestDetailsSvc - { - type Response = super::GetProofRequestDetailsResponse; - type Future = BoxFuture, tonic::Status>; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { - let inner = Arc::clone(&self.0); - let fut = async move { - ::get_proof_request_details(&inner, request) - .await - }; - Box::pin(fut) - } - } - let accept_compression_encodings = self.accept_compression_encodings; - let send_compression_encodings = self.send_compression_encodings; - let max_decoding_message_size = self.max_decoding_message_size; - let max_encoding_message_size = self.max_encoding_message_size; - let inner = self.inner.clone(); - let fut = async move { - let method = GetProofRequestDetailsSvc(inner); - let codec = tonic::codec::ProstCodec::default(); - let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); - let res = grpc.unary(method, req).await; - Ok(res) - }; - Box::pin(fut) - } - "/network.ProverNetwork/GetFilteredProofRequests" => { - #[allow(non_camel_case_types)] - struct GetFilteredProofRequestsSvc(pub Arc); - impl - tonic::server::UnaryService - for GetFilteredProofRequestsSvc - { - type Response = super::GetFilteredProofRequestsResponse; - type Future = BoxFuture, tonic::Status>; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { - let inner = Arc::clone(&self.0); - let fut = async move { - ::get_filtered_proof_requests(&inner, request) - .await - }; - Box::pin(fut) - } - } - let accept_compression_encodings = self.accept_compression_encodings; - let send_compression_encodings = self.send_compression_encodings; - let max_decoding_message_size = self.max_decoding_message_size; - let max_encoding_message_size = self.max_encoding_message_size; - let inner = self.inner.clone(); - let fut = async move { - let method = GetFilteredProofRequestsSvc(inner); - let codec = tonic::codec::ProstCodec::default(); - let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); - let res = grpc.unary(method, req).await; - Ok(res) - }; - Box::pin(fut) - } - "/network.ProverNetwork/GetSearchResults" => { - #[allow(non_camel_case_types)] - struct GetSearchResultsSvc(pub Arc); - impl - tonic::server::UnaryService - for GetSearchResultsSvc - { - type Response = super::GetSearchResultsResponse; - type Future = BoxFuture, tonic::Status>; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { - let inner = Arc::clone(&self.0); - let fut = async move { - ::get_search_results(&inner, request).await - }; - Box::pin(fut) - } - } - let accept_compression_encodings = self.accept_compression_encodings; - let send_compression_encodings = self.send_compression_encodings; - let max_decoding_message_size = self.max_decoding_message_size; - let max_encoding_message_size = self.max_encoding_message_size; - let inner = self.inner.clone(); - let fut = async move { - let method = GetSearchResultsSvc(inner); - let codec = tonic::codec::ProstCodec::default(); - let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); - let res = grpc.unary(method, req).await; - Ok(res) - }; - Box::pin(fut) - } - "/network.ProverNetwork/GetProofRequestMetrics" => { - #[allow(non_camel_case_types)] - struct GetProofRequestMetricsSvc(pub Arc); - impl - tonic::server::UnaryService - for GetProofRequestMetricsSvc - { - type Response = super::GetProofRequestMetricsResponse; - type Future = BoxFuture, tonic::Status>; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { - let inner = Arc::clone(&self.0); - let fut = async move { - ::get_proof_request_metrics(&inner, request) - .await - }; - Box::pin(fut) - } - } - let accept_compression_encodings = self.accept_compression_encodings; - let send_compression_encodings = self.send_compression_encodings; - let max_decoding_message_size = self.max_decoding_message_size; - let max_encoding_message_size = self.max_encoding_message_size; - let inner = self.inner.clone(); - let fut = async move { - let method = GetProofRequestMetricsSvc(inner); - let codec = tonic::codec::ProstCodec::default(); - let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); - let res = grpc.unary(method, req).await; - Ok(res) - }; - Box::pin(fut) - } - "/network.ProverNetwork/GetProofRequestGraph" => { - #[allow(non_camel_case_types)] - struct GetProofRequestGraphSvc(pub Arc); - impl - tonic::server::UnaryService - for GetProofRequestGraphSvc - { - type Response = super::GetProofRequestGraphResponse; - type Future = BoxFuture, tonic::Status>; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { - let inner = Arc::clone(&self.0); - let fut = async move { - ::get_proof_request_graph(&inner, request).await - }; - Box::pin(fut) - } - } - let accept_compression_encodings = self.accept_compression_encodings; - let send_compression_encodings = self.send_compression_encodings; - let max_decoding_message_size = self.max_decoding_message_size; - let max_encoding_message_size = self.max_encoding_message_size; - let inner = self.inner.clone(); - let fut = async move { - let method = GetProofRequestGraphSvc(inner); - let codec = tonic::codec::ProstCodec::default(); - let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); - let res = grpc.unary(method, req).await; - Ok(res) - }; - Box::pin(fut) - } - "/network.ProverNetwork/GetAnalyticsGraphs" => { - #[allow(non_camel_case_types)] - struct GetAnalyticsGraphsSvc(pub Arc); - impl - tonic::server::UnaryService - for GetAnalyticsGraphsSvc - { - type Response = super::GetAnalyticsGraphsResponse; - type Future = BoxFuture, tonic::Status>; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { - let inner = Arc::clone(&self.0); - let fut = async move { - ::get_analytics_graphs(&inner, request).await - }; - Box::pin(fut) - } - } - let accept_compression_encodings = self.accept_compression_encodings; - let send_compression_encodings = self.send_compression_encodings; - let max_decoding_message_size = self.max_decoding_message_size; - let max_encoding_message_size = self.max_encoding_message_size; - let inner = self.inner.clone(); - let fut = async move { - let method = GetAnalyticsGraphsSvc(inner); - let codec = tonic::codec::ProstCodec::default(); - let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); - let res = grpc.unary(method, req).await; - Ok(res) - }; - Box::pin(fut) - } - "/network.ProverNetwork/GetNonce" => { - #[allow(non_camel_case_types)] - struct GetNonceSvc(pub Arc); - impl tonic::server::UnaryService for GetNonceSvc { - type Response = super::GetNonceResponse; - type Future = BoxFuture, tonic::Status>; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { - let inner = Arc::clone(&self.0); - let fut = async move { - ::get_nonce(&inner, request).await - }; - Box::pin(fut) - } - } - let accept_compression_encodings = self.accept_compression_encodings; - let send_compression_encodings = self.send_compression_encodings; - let max_decoding_message_size = self.max_decoding_message_size; - let max_encoding_message_size = self.max_encoding_message_size; - let inner = self.inner.clone(); - let fut = async move { - let method = GetNonceSvc(inner); - let codec = tonic::codec::ProstCodec::default(); - let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); - let res = grpc.unary(method, req).await; - Ok(res) - }; - Box::pin(fut) - } - "/network.ProverNetwork/GetFilteredDelegations" => { - #[allow(non_camel_case_types)] - struct GetFilteredDelegationsSvc(pub Arc); - impl - tonic::server::UnaryService - for GetFilteredDelegationsSvc - { - type Response = super::GetFilteredDelegationsResponse; - type Future = BoxFuture, tonic::Status>; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { - let inner = Arc::clone(&self.0); - let fut = async move { - ::get_filtered_delegations(&inner, request) - .await - }; - Box::pin(fut) - } - } - let accept_compression_encodings = self.accept_compression_encodings; - let send_compression_encodings = self.send_compression_encodings; - let max_decoding_message_size = self.max_decoding_message_size; - let max_encoding_message_size = self.max_encoding_message_size; - let inner = self.inner.clone(); - let fut = async move { - let method = GetFilteredDelegationsSvc(inner); - let codec = tonic::codec::ProstCodec::default(); - let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); - let res = grpc.unary(method, req).await; - Ok(res) - }; - Box::pin(fut) - } - "/network.ProverNetwork/AddDelegation" => { - #[allow(non_camel_case_types)] - struct AddDelegationSvc(pub Arc); - impl tonic::server::UnaryService - for AddDelegationSvc - { - type Response = super::AddDelegationResponse; - type Future = BoxFuture, tonic::Status>; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { - let inner = Arc::clone(&self.0); - let fut = async move { - ::add_delegation(&inner, request).await - }; - Box::pin(fut) - } - } - let accept_compression_encodings = self.accept_compression_encodings; - let send_compression_encodings = self.send_compression_encodings; - let max_decoding_message_size = self.max_decoding_message_size; - let max_encoding_message_size = self.max_encoding_message_size; - let inner = self.inner.clone(); - let fut = async move { - let method = AddDelegationSvc(inner); - let codec = tonic::codec::ProstCodec::default(); - let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); - let res = grpc.unary(method, req).await; - Ok(res) - }; - Box::pin(fut) - } - "/network.ProverNetwork/RemoveDelegation" => { - #[allow(non_camel_case_types)] - struct RemoveDelegationSvc(pub Arc); - impl - tonic::server::UnaryService - for RemoveDelegationSvc - { - type Response = super::RemoveDelegationResponse; - type Future = BoxFuture, tonic::Status>; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { - let inner = Arc::clone(&self.0); - let fut = async move { - ::remove_delegation(&inner, request).await - }; - Box::pin(fut) - } - } - let accept_compression_encodings = self.accept_compression_encodings; - let send_compression_encodings = self.send_compression_encodings; - let max_decoding_message_size = self.max_decoding_message_size; - let max_encoding_message_size = self.max_encoding_message_size; - let inner = self.inner.clone(); - let fut = async move { - let method = RemoveDelegationSvc(inner); - let codec = tonic::codec::ProstCodec::default(); - let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); - let res = grpc.unary(method, req).await; - Ok(res) - }; - Box::pin(fut) - } - "/network.ProverNetwork/AcceptDelegation" => { - #[allow(non_camel_case_types)] - struct AcceptDelegationSvc(pub Arc); - impl - tonic::server::UnaryService - for AcceptDelegationSvc - { - type Response = super::AcceptDelegationResponse; - type Future = BoxFuture, tonic::Status>; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { - let inner = Arc::clone(&self.0); - let fut = async move { - ::accept_delegation(&inner, request).await - }; - Box::pin(fut) - } - } - let accept_compression_encodings = self.accept_compression_encodings; - let send_compression_encodings = self.send_compression_encodings; - let max_decoding_message_size = self.max_decoding_message_size; - let max_encoding_message_size = self.max_encoding_message_size; - let inner = self.inner.clone(); - let fut = async move { - let method = AcceptDelegationSvc(inner); - let codec = tonic::codec::ProstCodec::default(); - let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); - let res = grpc.unary(method, req).await; - Ok(res) - }; - Box::pin(fut) - } - "/network.ProverNetwork/SetAccountName" => { - #[allow(non_camel_case_types)] - struct SetAccountNameSvc(pub Arc); - impl tonic::server::UnaryService - for SetAccountNameSvc - { - type Response = super::SetAccountNameResponse; - type Future = BoxFuture, tonic::Status>; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { - let inner = Arc::clone(&self.0); - let fut = async move { - ::set_account_name(&inner, request).await - }; - Box::pin(fut) - } - } - let accept_compression_encodings = self.accept_compression_encodings; - let send_compression_encodings = self.send_compression_encodings; - let max_decoding_message_size = self.max_decoding_message_size; - let max_encoding_message_size = self.max_encoding_message_size; - let inner = self.inner.clone(); - let fut = async move { - let method = SetAccountNameSvc(inner); - let codec = tonic::codec::ProstCodec::default(); - let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); - let res = grpc.unary(method, req).await; - Ok(res) - }; - Box::pin(fut) - } - "/network.ProverNetwork/GetAccountName" => { - #[allow(non_camel_case_types)] - struct GetAccountNameSvc(pub Arc); - impl tonic::server::UnaryService - for GetAccountNameSvc - { - type Response = super::GetAccountNameResponse; - type Future = BoxFuture, tonic::Status>; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { - let inner = Arc::clone(&self.0); - let fut = async move { - ::get_account_name(&inner, request).await - }; - Box::pin(fut) - } - } - let accept_compression_encodings = self.accept_compression_encodings; - let send_compression_encodings = self.send_compression_encodings; - let max_decoding_message_size = self.max_decoding_message_size; - let max_encoding_message_size = self.max_encoding_message_size; - let inner = self.inner.clone(); - let fut = async move { - let method = GetAccountNameSvc(inner); - let codec = tonic::codec::ProstCodec::default(); - let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); - let res = grpc.unary(method, req).await; - Ok(res) - }; - Box::pin(fut) - } - "/network.ProverNetwork/GetTermsSignature" => { - #[allow(non_camel_case_types)] - struct GetTermsSignatureSvc(pub Arc); - impl - tonic::server::UnaryService - for GetTermsSignatureSvc - { - type Response = super::GetTermsSignatureResponse; - type Future = BoxFuture, tonic::Status>; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { - let inner = Arc::clone(&self.0); - let fut = async move { - ::get_terms_signature(&inner, request).await - }; - Box::pin(fut) - } - } - let accept_compression_encodings = self.accept_compression_encodings; - let send_compression_encodings = self.send_compression_encodings; - let max_decoding_message_size = self.max_decoding_message_size; - let max_encoding_message_size = self.max_encoding_message_size; - let inner = self.inner.clone(); - let fut = async move { - let method = GetTermsSignatureSvc(inner); - let codec = tonic::codec::ProstCodec::default(); - let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); - let res = grpc.unary(method, req).await; - Ok(res) - }; - Box::pin(fut) - } - "/network.ProverNetwork/SetTermsSignature" => { - #[allow(non_camel_case_types)] - struct SetTermsSignatureSvc(pub Arc); - impl - tonic::server::UnaryService - for SetTermsSignatureSvc - { - type Response = super::SetTermsSignatureResponse; - type Future = BoxFuture, tonic::Status>; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { - let inner = Arc::clone(&self.0); - let fut = async move { - ::set_terms_signature(&inner, request).await - }; - Box::pin(fut) - } - } - let accept_compression_encodings = self.accept_compression_encodings; - let send_compression_encodings = self.send_compression_encodings; - let max_decoding_message_size = self.max_decoding_message_size; - let max_encoding_message_size = self.max_encoding_message_size; - let inner = self.inner.clone(); - let fut = async move { - let method = SetTermsSignatureSvc(inner); - let codec = tonic::codec::ProstCodec::default(); - let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); - let res = grpc.unary(method, req).await; - Ok(res) - }; - Box::pin(fut) - } - "/network.ProverNetwork/GetProgram" => { - #[allow(non_camel_case_types)] - struct GetProgramSvc(pub Arc); - impl tonic::server::UnaryService for GetProgramSvc { - type Response = super::GetProgramResponse; - type Future = BoxFuture, tonic::Status>; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { - let inner = Arc::clone(&self.0); - let fut = async move { - ::get_program(&inner, request).await - }; - Box::pin(fut) - } - } - let accept_compression_encodings = self.accept_compression_encodings; - let send_compression_encodings = self.send_compression_encodings; - let max_decoding_message_size = self.max_decoding_message_size; - let max_encoding_message_size = self.max_encoding_message_size; - let inner = self.inner.clone(); - let fut = async move { - let method = GetProgramSvc(inner); - let codec = tonic::codec::ProstCodec::default(); - let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); - let res = grpc.unary(method, req).await; - Ok(res) - }; - Box::pin(fut) - } - "/network.ProverNetwork/CreateProgram" => { - #[allow(non_camel_case_types)] - struct CreateProgramSvc(pub Arc); - impl tonic::server::UnaryService - for CreateProgramSvc - { - type Response = super::CreateProgramResponse; - type Future = BoxFuture, tonic::Status>; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { - let inner = Arc::clone(&self.0); - let fut = async move { - ::create_program(&inner, request).await - }; - Box::pin(fut) - } - } - let accept_compression_encodings = self.accept_compression_encodings; - let send_compression_encodings = self.send_compression_encodings; - let max_decoding_message_size = self.max_decoding_message_size; - let max_encoding_message_size = self.max_encoding_message_size; - let inner = self.inner.clone(); - let fut = async move { - let method = CreateProgramSvc(inner); - let codec = tonic::codec::ProstCodec::default(); - let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); - let res = grpc.unary(method, req).await; - Ok(res) - }; - Box::pin(fut) - } - "/network.ProverNetwork/SetProgramName" => { - #[allow(non_camel_case_types)] - struct SetProgramNameSvc(pub Arc); - impl tonic::server::UnaryService - for SetProgramNameSvc - { - type Response = super::SetProgramNameResponse; - type Future = BoxFuture, tonic::Status>; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { - let inner = Arc::clone(&self.0); - let fut = async move { - ::set_program_name(&inner, request).await - }; - Box::pin(fut) - } - } - let accept_compression_encodings = self.accept_compression_encodings; - let send_compression_encodings = self.send_compression_encodings; - let max_decoding_message_size = self.max_decoding_message_size; - let max_encoding_message_size = self.max_encoding_message_size; - let inner = self.inner.clone(); - let fut = async move { - let method = SetProgramNameSvc(inner); - let codec = tonic::codec::ProstCodec::default(); - let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); - let res = grpc.unary(method, req).await; - Ok(res) - }; - Box::pin(fut) - } - "/network.ProverNetwork/GetBalance" => { - #[allow(non_camel_case_types)] - struct GetBalanceSvc(pub Arc); - impl tonic::server::UnaryService for GetBalanceSvc { - type Response = super::GetBalanceResponse; - type Future = BoxFuture, tonic::Status>; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { - let inner = Arc::clone(&self.0); - let fut = async move { - ::get_balance(&inner, request).await - }; - Box::pin(fut) - } - } - let accept_compression_encodings = self.accept_compression_encodings; - let send_compression_encodings = self.send_compression_encodings; - let max_decoding_message_size = self.max_decoding_message_size; - let max_encoding_message_size = self.max_encoding_message_size; - let inner = self.inner.clone(); - let fut = async move { - let method = GetBalanceSvc(inner); - let codec = tonic::codec::ProstCodec::default(); - let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); - let res = grpc.unary(method, req).await; - Ok(res) - }; - Box::pin(fut) - } - "/network.ProverNetwork/GetFilteredBalanceLogs" => { - #[allow(non_camel_case_types)] - struct GetFilteredBalanceLogsSvc(pub Arc); - impl - tonic::server::UnaryService - for GetFilteredBalanceLogsSvc - { - type Response = super::GetFilteredBalanceLogsResponse; - type Future = BoxFuture, tonic::Status>; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { - let inner = Arc::clone(&self.0); - let fut = async move { - ::get_filtered_balance_logs(&inner, request) - .await - }; - Box::pin(fut) - } - } - let accept_compression_encodings = self.accept_compression_encodings; - let send_compression_encodings = self.send_compression_encodings; - let max_decoding_message_size = self.max_decoding_message_size; - let max_encoding_message_size = self.max_encoding_message_size; - let inner = self.inner.clone(); - let fut = async move { - let method = GetFilteredBalanceLogsSvc(inner); - let codec = tonic::codec::ProstCodec::default(); - let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); - let res = grpc.unary(method, req).await; - Ok(res) - }; - Box::pin(fut) - } - "/network.ProverNetwork/AddCredit" => { - #[allow(non_camel_case_types)] - struct AddCreditSvc(pub Arc); - impl tonic::server::UnaryService for AddCreditSvc { - type Response = super::AddCreditResponse; - type Future = BoxFuture, tonic::Status>; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { - let inner = Arc::clone(&self.0); - let fut = async move { - ::add_credit(&inner, request).await - }; - Box::pin(fut) - } - } - let accept_compression_encodings = self.accept_compression_encodings; - let send_compression_encodings = self.send_compression_encodings; - let max_decoding_message_size = self.max_decoding_message_size; - let max_encoding_message_size = self.max_encoding_message_size; - let inner = self.inner.clone(); - let fut = async move { - let method = AddCreditSvc(inner); - let codec = tonic::codec::ProstCodec::default(); - let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); - let res = grpc.unary(method, req).await; - Ok(res) - }; - Box::pin(fut) - } - "/network.ProverNetwork/GetLatestBridgeBlock" => { - #[allow(non_camel_case_types)] - struct GetLatestBridgeBlockSvc(pub Arc); - impl - tonic::server::UnaryService - for GetLatestBridgeBlockSvc - { - type Response = super::GetLatestBridgeBlockResponse; - type Future = BoxFuture, tonic::Status>; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { - let inner = Arc::clone(&self.0); - let fut = async move { - ::get_latest_bridge_block(&inner, request).await - }; - Box::pin(fut) - } - } - let accept_compression_encodings = self.accept_compression_encodings; - let send_compression_encodings = self.send_compression_encodings; - let max_decoding_message_size = self.max_decoding_message_size; - let max_encoding_message_size = self.max_encoding_message_size; - let inner = self.inner.clone(); - let fut = async move { - let method = GetLatestBridgeBlockSvc(inner); - let codec = tonic::codec::ProstCodec::default(); - let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); - let res = grpc.unary(method, req).await; - Ok(res) - }; - Box::pin(fut) - } - "/network.ProverNetwork/GetGasPriceEstimate" => { - #[allow(non_camel_case_types)] - struct GetGasPriceEstimateSvc(pub Arc); - impl - tonic::server::UnaryService - for GetGasPriceEstimateSvc - { - type Response = super::GetGasPriceEstimateResponse; - type Future = BoxFuture, tonic::Status>; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { - let inner = Arc::clone(&self.0); - let fut = async move { - ::get_gas_price_estimate(&inner, request).await - }; - Box::pin(fut) - } - } - let accept_compression_encodings = self.accept_compression_encodings; - let send_compression_encodings = self.send_compression_encodings; - let max_decoding_message_size = self.max_decoding_message_size; - let max_encoding_message_size = self.max_encoding_message_size; - let inner = self.inner.clone(); - let fut = async move { - let method = GetGasPriceEstimateSvc(inner); - let codec = tonic::codec::ProstCodec::default(); - let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); - let res = grpc.unary(method, req).await; - Ok(res) - }; - Box::pin(fut) - } - "/network.ProverNetwork/GetTransactionDetails" => { - #[allow(non_camel_case_types)] - struct GetTransactionDetailsSvc(pub Arc); - impl - tonic::server::UnaryService - for GetTransactionDetailsSvc - { - type Response = super::GetTransactionDetailsResponse; - type Future = BoxFuture, tonic::Status>; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { - let inner = Arc::clone(&self.0); - let fut = async move { - ::get_transaction_details(&inner, request).await - }; - Box::pin(fut) - } - } - let accept_compression_encodings = self.accept_compression_encodings; - let send_compression_encodings = self.send_compression_encodings; - let max_decoding_message_size = self.max_decoding_message_size; - let max_encoding_message_size = self.max_encoding_message_size; - let inner = self.inner.clone(); - let fut = async move { - let method = GetTransactionDetailsSvc(inner); - let codec = tonic::codec::ProstCodec::default(); - let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); - let res = grpc.unary(method, req).await; - Ok(res) - }; - Box::pin(fut) - } - "/network.ProverNetwork/GetFilteredReservations" => { - #[allow(non_camel_case_types)] - struct GetFilteredReservationsSvc(pub Arc); - impl - tonic::server::UnaryService - for GetFilteredReservationsSvc - { - type Response = super::GetFilteredReservationsResponse; - type Future = BoxFuture, tonic::Status>; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { - let inner = Arc::clone(&self.0); - let fut = async move { - ::get_filtered_reservations(&inner, request) - .await - }; - Box::pin(fut) - } - } - let accept_compression_encodings = self.accept_compression_encodings; - let send_compression_encodings = self.send_compression_encodings; - let max_decoding_message_size = self.max_decoding_message_size; - let max_encoding_message_size = self.max_encoding_message_size; - let inner = self.inner.clone(); - let fut = async move { - let method = GetFilteredReservationsSvc(inner); - let codec = tonic::codec::ProstCodec::default(); - let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); - let res = grpc.unary(method, req).await; - Ok(res) - }; - Box::pin(fut) - } - "/network.ProverNetwork/AddReservation" => { - #[allow(non_camel_case_types)] - struct AddReservationSvc(pub Arc); - impl tonic::server::UnaryService - for AddReservationSvc - { - type Response = super::AddReservationResponse; - type Future = BoxFuture, tonic::Status>; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { - let inner = Arc::clone(&self.0); - let fut = async move { - ::add_reservation(&inner, request).await - }; - Box::pin(fut) - } - } - let accept_compression_encodings = self.accept_compression_encodings; - let send_compression_encodings = self.send_compression_encodings; - let max_decoding_message_size = self.max_decoding_message_size; - let max_encoding_message_size = self.max_encoding_message_size; - let inner = self.inner.clone(); - let fut = async move { - let method = AddReservationSvc(inner); - let codec = tonic::codec::ProstCodec::default(); - let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); - let res = grpc.unary(method, req).await; - Ok(res) - }; - Box::pin(fut) - } - "/network.ProverNetwork/RemoveReservation" => { - #[allow(non_camel_case_types)] - struct RemoveReservationSvc(pub Arc); - impl - tonic::server::UnaryService - for RemoveReservationSvc - { - type Response = super::RemoveReservationResponse; - type Future = BoxFuture, tonic::Status>; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { - let inner = Arc::clone(&self.0); - let fut = async move { - ::remove_reservation(&inner, request).await - }; - Box::pin(fut) - } - } - let accept_compression_encodings = self.accept_compression_encodings; - let send_compression_encodings = self.send_compression_encodings; - let max_decoding_message_size = self.max_decoding_message_size; - let max_encoding_message_size = self.max_encoding_message_size; - let inner = self.inner.clone(); - let fut = async move { - let method = RemoveReservationSvc(inner); - let codec = tonic::codec::ProstCodec::default(); - let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); - let res = grpc.unary(method, req).await; - Ok(res) - }; - Box::pin(fut) - } - "/network.ProverNetwork/Bid" => { - #[allow(non_camel_case_types)] - struct BidSvc(pub Arc); - impl tonic::server::UnaryService for BidSvc { - type Response = super::BidResponse; - type Future = BoxFuture, tonic::Status>; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { - let inner = Arc::clone(&self.0); - let fut = - async move { ::bid(&inner, request).await }; - Box::pin(fut) - } - } - let accept_compression_encodings = self.accept_compression_encodings; - let send_compression_encodings = self.send_compression_encodings; - let max_decoding_message_size = self.max_decoding_message_size; - let max_encoding_message_size = self.max_encoding_message_size; - let inner = self.inner.clone(); - let fut = async move { - let method = BidSvc(inner); - let codec = tonic::codec::ProstCodec::default(); - let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); - let res = grpc.unary(method, req).await; - Ok(res) - }; - Box::pin(fut) - } - "/network.ProverNetwork/Settle" => { - #[allow(non_camel_case_types)] - struct SettleSvc(pub Arc); - impl tonic::server::UnaryService for SettleSvc { - type Response = super::SettleResponse; - type Future = BoxFuture, tonic::Status>; - fn call( - &mut self, - request: tonic::Request, - ) -> Self::Future { - let inner = Arc::clone(&self.0); - let fut = - async move { ::settle(&inner, request).await }; - Box::pin(fut) - } - } - let accept_compression_encodings = self.accept_compression_encodings; - let send_compression_encodings = self.send_compression_encodings; - let max_decoding_message_size = self.max_decoding_message_size; - let max_encoding_message_size = self.max_encoding_message_size; - let inner = self.inner.clone(); - let fut = async move { - let method = SettleSvc(inner); - let codec = tonic::codec::ProstCodec::default(); - let mut grpc = tonic::server::Grpc::new(codec) - .apply_compression_config( - accept_compression_encodings, - send_compression_encodings, - ) - .apply_max_message_size_config( - max_decoding_message_size, - max_encoding_message_size, - ); - let res = grpc.unary(method, req).await; - Ok(res) - }; - Box::pin(fut) - } - _ => Box::pin(async move { - Ok(http::Response::builder() - .status(200) - .header("grpc-status", tonic::Code::Unimplemented as i32) - .header(http::header::CONTENT_TYPE, tonic::metadata::GRPC_CONTENT_TYPE) - .body(empty_body()) - .unwrap()) - }), - } - } - } - impl Clone for ProverNetworkServer { - fn clone(&self) -> Self { - let inner = self.inner.clone(); - Self { - inner, - accept_compression_encodings: self.accept_compression_encodings, - send_compression_encodings: self.send_compression_encodings, - max_decoding_message_size: self.max_decoding_message_size, - max_encoding_message_size: self.max_encoding_message_size, - } - } - } - /// Generated gRPC service name - pub const SERVICE_NAME: &str = "network.ProverNetwork"; - impl tonic::server::NamedService for ProverNetworkServer { - const NAME: &'static str = SERVICE_NAME; - } -} diff --git a/crates/sdk/src/network-v2/prover.rs b/crates/sdk/src/network-v2/prover.rs deleted file mode 100644 index 91056adde1..0000000000 --- a/crates/sdk/src/network-v2/prover.rs +++ /dev/null @@ -1,330 +0,0 @@ -use std::time::{Duration, Instant}; - -use crate::network_v2::client::DEFAULT_PROVER_NETWORK_RPC; -use crate::{ - network_v2::client::NetworkClient, - network_v2::proto::network::{ - ExecutionStatus, FulfillmentStatus, FulfillmentStrategy, ProofMode, - }, - NetworkProverBuilder, Prover, SP1Context, SP1ProofKind, SP1ProofWithPublicValues, - SP1ProvingKey, SP1VerifyingKey, -}; -use anyhow::Result; -use backoff::{future::retry, Error as BackoffError, ExponentialBackoff}; -use serde::de::DeserializeOwned; -use sp1_core_machine::io::SP1Stdin; -use sp1_prover::{components::DefaultProverComponents, SP1Prover, SP1_CIRCUIT_VERSION}; -use sp1_stark::SP1ProverOpts; -use tonic::Code; - -use {crate::block_on, tokio::time::sleep}; - -use crate::provers::{CpuProver, ProofOpts, ProverType}; - -/// The timeout for a proof request to be fulfilled. -const TIMEOUT_SECS: u64 = 14400; - -/// The default cycle limit for a proof request if simulation is skipped. -const DEFAULT_CYCLE_LIMIT: u64 = 100_000_000; - -/// An implementation of [crate::ProverClient] that can generate proofs on a remote RPC server. -pub struct NetworkProver { - client: NetworkClient, - local_prover: CpuProver, - skip_simulation: bool, - strategy: FulfillmentStrategy, -} - -impl NetworkProver { - /// Creates a new [NetworkProver] with the given private key. - pub fn new(private_key: &str, rpc_url: Option, skip_simulation: bool) -> Self { - let version = SP1_CIRCUIT_VERSION; - log::info!("Client circuit version: {}", version); - let local_prover = CpuProver::new(); - let client = NetworkClient::new(private_key, rpc_url); - Self { client, local_prover, skip_simulation, strategy: FulfillmentStrategy::Hosted } - } - - /// Sets the fulfillment strategy for the client. By default, the strategy is set to `Hosted`. - pub fn with_strategy(&mut self, strategy: FulfillmentStrategy) { - self.strategy = strategy; - } - - /// Creates a new network prover builder. See [`NetworkProverBuilder`] for more details. - pub fn builder() -> NetworkProverBuilder { - NetworkProverBuilder::default() - } - - /// Registers a program if it is not already registered. - pub async fn register_program(&self, vk: &SP1VerifyingKey, elf: &[u8]) -> Result> { - self.client.register_program(vk, elf).await - } - - /// Get the cycle limit, either by simulating or using the default cycle limit. - fn get_cycle_limit(&self, elf: &[u8], stdin: &SP1Stdin) -> Result { - if !self.skip_simulation { - let (_, report) = - self.local_prover.sp1_prover().execute(elf, stdin, Default::default())?; - let cycles = report.total_instruction_count(); - Ok(cycles) - } else { - Ok(DEFAULT_CYCLE_LIMIT) - } - } - - /// Requests a proof from the prover network, returning the request ID. - pub async fn request_proof( - &self, - vk_hash: &[u8], - stdin: &SP1Stdin, - mode: ProofMode, - cycle_limit: u64, - timeout: Option, - ) -> Result> { - // Get the timeout. - let timeout_secs = timeout.map(|dur| dur.as_secs()).unwrap_or(TIMEOUT_SECS); - - log::info!("Requesting proof with cycle limit: {}", cycle_limit); - - // Request the proof with retries. - let response = with_retry( - || async { - self.client - .request_proof( - vk_hash, - stdin, - mode, - SP1_CIRCUIT_VERSION, - self.strategy, - timeout_secs, - cycle_limit, - ) - .await - }, - timeout, - "requesting proof", - ) - .await?; - - // Log the request ID and transaction hash. - let tx_hash_hex = "0x".to_string() + &hex::encode(response.tx_hash); - let request_id = response.body.unwrap().request_id; - let request_id_hex = "0x".to_string() + &hex::encode(request_id.clone()); - log::info!("Created request {} in transaction {}", request_id_hex, tx_hash_hex); - - if self.client.rpc_url() == DEFAULT_PROVER_NETWORK_RPC { - log::info!("View in explorer: https://network.succinct.xyz/request/{}", request_id_hex); - } - - Ok(request_id) - } - - /// Waits for a proof to be generated and returns the proof. If a timeout is supplied, the - /// function will return an error if the proof is not generated within the timeout. - pub async fn wait_proof( - &self, - request_id: &[u8], - timeout: Option, - ) -> Result

{ - let mut is_assigned = false; - let start_time = Instant::now(); - - loop { - // Calculate the remaining timeout. - if let Some(timeout) = timeout { - if start_time.elapsed() > timeout { - return Err(anyhow::anyhow!("Proof request timed out.")); - } - } - let remaining_timeout = timeout.map(|t| { - let elapsed = start_time.elapsed(); - if elapsed < t { - t - elapsed - } else { - Duration::from_secs(0) - } - }); - - // Get status with retries. - let (status, maybe_proof) = with_retry( - || async { self.client.get_proof_request_status::

(request_id).await }, - remaining_timeout, - "getting proof request status", - ) - .await?; - - // Check the execution status. - if status.execution_status == ExecutionStatus::Unexecutable as i32 { - return Err(anyhow::anyhow!("Proof request is unexecutable")); - } - - // Check the fulfillment status. - match FulfillmentStatus::try_from(status.fulfillment_status) { - Ok(FulfillmentStatus::Fulfilled) => { - return Ok(maybe_proof.unwrap()); - } - Ok(FulfillmentStatus::Assigned) => { - if !is_assigned { - log::info!("Proof request assigned, proving..."); - is_assigned = true; - } - } - Ok(FulfillmentStatus::Unfulfillable) => { - return Err(anyhow::anyhow!("Proof request is unfulfillable")); - } - _ => {} - } - - sleep(Duration::from_secs(2)).await; - } - } - - /// Requests a proof from the prover network and waits for it to be generated. - pub async fn prove( - &self, - pk: &SP1ProvingKey, - stdin: SP1Stdin, - mode: ProofMode, - timeout: Option, - ) -> Result { - let vk_hash = self.register_program(&pk.vk, &pk.elf).await?; - let cycle_limit = self.get_cycle_limit(&pk.elf, &stdin)?; - let request_id = self.request_proof(&vk_hash, &stdin, mode, cycle_limit, timeout).await?; - self.wait_proof(&request_id, timeout).await - } -} - -impl Prover for NetworkProver { - fn id(&self) -> ProverType { - ProverType::Network - } - - fn setup(&self, elf: &[u8]) -> (SP1ProvingKey, SP1VerifyingKey) { - self.local_prover.setup(elf) - } - - fn sp1_prover(&self) -> &SP1Prover { - self.local_prover.sp1_prover() - } - - fn prove<'a>( - &'a self, - pk: &SP1ProvingKey, - stdin: SP1Stdin, - opts: ProofOpts, - context: SP1Context<'a>, - kind: SP1ProofKind, - ) -> Result { - warn_if_not_default(&opts.sp1_prover_opts, &context); - block_on(self.prove(pk, stdin, kind.into(), opts.timeout)) - } -} - -/// Warns if `opts` or `context` are not default values, since they are currently unsupported. -fn warn_if_not_default(opts: &SP1ProverOpts, context: &SP1Context) { - let _guard = tracing::warn_span!("network_prover").entered(); - if opts != &SP1ProverOpts::default() { - tracing::warn!("non-default opts will be ignored: {:?}", opts.core_opts); - tracing::warn!("custom SP1ProverOpts are currently unsupported by the network prover"); - } - // Exhaustive match is done to ensure we update the warnings if the types change. - let SP1Context { hook_registry, subproof_verifier, .. } = context; - if hook_registry.is_some() { - tracing::warn!("non-default context.hook_registry will be ignored: {:?}", hook_registry); - tracing::warn!("custom runtime hooks are currently unsupported by the network prover"); - tracing::warn!("proving may fail due to missing hooks"); - } - if subproof_verifier.is_some() { - tracing::warn!("non-default context.subproof_verifier will be ignored"); - tracing::warn!("custom subproof verifiers are currently unsupported by the network prover"); - } -} - -impl From for ProofMode { - fn from(value: SP1ProofKind) -> Self { - match value { - SP1ProofKind::Core => Self::Core, - SP1ProofKind::Compressed => Self::Compressed, - SP1ProofKind::Plonk => Self::Plonk, - SP1ProofKind::Groth16 => Self::Groth16, - } - } -} - -/// Execute an async operation with exponential backoff retries. -pub async fn with_retry( - operation: F, - timeout: Option, - operation_name: &str, -) -> Result -where - F: Fn() -> Fut, - Fut: std::future::Future>, -{ - let backoff = ExponentialBackoff { - initial_interval: Duration::from_secs(1), - max_interval: Duration::from_secs(120), - max_elapsed_time: timeout, - ..Default::default() - }; - - retry(backoff, || async { - match operation().await { - Ok(result) => Ok(result), - Err(e) => { - // Check for tonic status errors. - if let Some(status) = e.downcast_ref::() { - match status.code() { - Code::Unavailable => { - log::warn!( - "Network temporarily unavailable when {} due to {}, retrying...", - operation_name, - status.message(), - ); - Err(BackoffError::transient(e)) - } - Code::NotFound => { - log::error!( - "{} not found due to {}", - operation_name, - status.message(), - ); - Err(BackoffError::permanent(e)) - } - _ => { - log::error!( - "Permanent error encountered when {}: {} ({})", - operation_name, - status.message(), - status.code() - ); - Err(BackoffError::permanent(e)) - } - } - } else { - // Check for common transport errors. - let error_msg = e.to_string().to_lowercase(); - let is_transient = error_msg.contains("tls handshake") || - error_msg.contains("dns error") || - error_msg.contains("connection reset") || - error_msg.contains("broken pipe") || - error_msg.contains("transport error") || - error_msg.contains("failed to lookup"); - - if is_transient { - log::warn!( - "Transient transport error when {}: {}, retrying...", - operation_name, - error_msg - ); - Err(BackoffError::transient(e)) - } else { - log::error!("Permanent error when {}: {}", operation_name, error_msg); - Err(BackoffError::permanent(e)) - } - } - } - } - }) - .await -} diff --git a/crates/sdk/src/network/auth.rs b/crates/sdk/src/network/auth.rs deleted file mode 100644 index 7786cc4d36..0000000000 --- a/crates/sdk/src/network/auth.rs +++ /dev/null @@ -1,142 +0,0 @@ -use std::{borrow::Cow, str::FromStr}; - -use alloy_signer::SignerSync; -use alloy_signer_local::PrivateKeySigner; - -use alloy_sol_types::{sol, Eip712Domain, SolStruct}; -use anyhow::Result; - -use crate::network::proto::network::UnclaimReason; - -sol! { - struct CreateProof { - uint64 nonce; - uint64 deadline; - uint32 mode; - string version; - } - - struct SubmitProof { - uint64 nonce; - string proof_id; - } - - struct ClaimProof { - uint64 nonce; - string proof_id; - } - - struct UnclaimProof { - uint64 nonce; - string proof_id; - uint8 reason; - string description; - } - - struct ModifyCpuCycles { - uint64 nonce; - string proof_id; - uint64 cycles; - } - - struct FulfillProof { - uint64 nonce; - string proof_id; - } -} - -/// Handles authentication for the Succinct prover network. All interactions that could potentially -/// use computational resources must be authenticated by signing a message with a secp256k1 key. -/// -/// The messages themselves follow EIP-712, where the domain is "succinct" and the TypeStruct -/// changes depending on which endpoint is being used. Documentation for EIP-712 can be found at: -/// https://eips.ethereum.org/EIPS/eip-712 -pub struct NetworkAuth { - // Holds a secp256k1 private key. - wallet: PrivateKeySigner, -} - -impl NetworkAuth { - pub fn new(private_key: &str) -> Self { - let wallet = PrivateKeySigner::from_str(private_key).unwrap(); - Self { wallet } - } - - /// Gets the EIP-712 domain separator for the Succinct prover network. - fn get_domain_separator() -> Eip712Domain { - Eip712Domain { - name: Some(Cow::Borrowed("succinct")), - version: Some(Cow::Borrowed("1")), - ..Default::default() - } - } - - /// Gets the address of the auth's account, derived from the secp256k1 private key. - pub fn get_address(&self) -> [u8; 20] { - self.wallet.address().into() - } - - // Generic function to sign a message based on the SolStruct. - async fn sign_message(&self, type_struct: T) -> Result> { - let domain_separator = Self::get_domain_separator(); - let message_hash = type_struct.eip712_signing_hash(&domain_separator); - let signature = self.wallet.sign_hash_sync(&message_hash)?; - Ok(signature.as_bytes().to_vec()) - } - - /// Signs a message to to request to create a proof. - pub async fn sign_create_proof_message( - &self, - nonce: u64, - deadline: u64, - mode: i32, - version: &str, - ) -> Result> { - let type_struct = - CreateProof { nonce, deadline, mode: mode as u32, version: version.to_string() }; - self.sign_message(type_struct).await - } - - /// Signs a message to mark a proof as ready for proof generation. - pub async fn sign_submit_proof_message(&self, nonce: u64, proof_id: &str) -> Result> { - let type_struct = SubmitProof { nonce, proof_id: proof_id.to_string() }; - self.sign_message(type_struct).await - } - - /// Signs a message to claim a proof that was requested. - pub async fn sign_claim_proof_message(&self, nonce: u64, proof_id: &str) -> Result> { - let type_struct = ClaimProof { nonce, proof_id: proof_id.to_string() }; - self.sign_message(type_struct).await - } - - /// Signs a message to unclaim a proof that was previously claimed. - pub async fn sign_unclaim_proof_message( - &self, - nonce: u64, - proof_id: String, - reason: UnclaimReason, - description: String, - ) -> Result> { - let type_struct = UnclaimProof { nonce, proof_id, reason: reason as u8, description }; - self.sign_message(type_struct).await - } - - /// Signs a message to modify the CPU cycles for a proof. The proof must have been previously - /// claimed by the signer first. - pub async fn sign_modify_cpu_cycles_message( - &self, - nonce: u64, - proof_id: &str, - cycles: u64, - ) -> Result> { - let type_struct = ModifyCpuCycles { nonce, proof_id: proof_id.to_string(), cycles }; - self.sign_message(type_struct).await - } - - /// Signs a message to fulfill a proof. The proof must have been previously claimed by the - /// signer first. - pub async fn sign_fulfill_proof_message(&self, nonce: u64, proof_id: &str) -> Result> { - let type_struct = FulfillProof { nonce, proof_id: proof_id.to_string() }; - self.sign_message(type_struct).await - } -} diff --git a/crates/sdk/src/network/builder.rs b/crates/sdk/src/network/builder.rs new file mode 100644 index 0000000000..5a9585a67a --- /dev/null +++ b/crates/sdk/src/network/builder.rs @@ -0,0 +1,94 @@ +//! # Network Prover Builder +//! +//! This module provides a builder for the [`NetworkProver`]. + +use crate::NetworkProver; + +/// A builder for the [`NetworkProver`]. +/// +/// The builder is used to configure the [`NetworkProver`] before it is built. +#[derive(Default)] +pub struct NetworkProverBuilder { + pub(crate) private_key: Option, + pub(crate) rpc_url: Option, +} + +impl NetworkProverBuilder { + /// Sets the Secp256k1 private key (same format as the one used by Ethereum). + /// + /// # Details + /// Sets the private key that will be used sign requests sent to the network. By default, the + /// private key is read from the `NETWORK_PRIVATE_KEY` environment variable. + /// + /// # Example + /// ```rust,no_run + /// use sp1_sdk::{ProverClient}; + /// + /// let prover = ProverClient::builder().network() + /// .private_key("...") + /// .build(); + /// ``` + #[must_use] + pub fn private_key(mut self, private_key: &str) -> Self { + self.private_key = Some(private_key.to_string()); + self + } + + /// Sets the remote procedure call URL. + /// + /// # Details + /// The URL determines the network that the client will connect to. By default, the URL is + /// read from the `NETWORK_RPC_URL` environment variable. + /// + /// # Example + /// ```rust,no_run + /// use sp1_sdk::{ProverClient}; + /// + /// let prover = ProverClient::builder() + /// .network() + /// .rpc_url("...") + /// .build(); + /// ``` + #[must_use] + pub fn rpc_url(mut self, rpc_url: &str) -> Self { + self.rpc_url = Some(rpc_url.to_string()); + self + } + + /// Builds a [`NetworkProver`]. + /// + /// # Details + /// This method will build a [`NetworkProver`] with the given parameters. If the private key is + /// not provided, the method will look for the `NETWORK_PRIVATE_KEY` environment variable. + /// + /// # Example + /// ```rust,no_run + /// use sp1_sdk::{ProverClient}; + /// + /// let prover = ProverClient::builder() + /// .network() + /// .private_key("...") + /// .rpc_url("...") + /// .build(); + /// ``` + #[must_use] + pub fn build(self) -> NetworkProver { + let private_key = match self.private_key { + Some(private_key) => private_key, + None => std::env::var("NETWORK_PRIVATE_KEY").expect( + "NETWORK_PRIVATE_KEY environment variable is not set. \ + Please set it to your private key or use the .private_key() method.", + ), + }; + + let rpc_url = match self.rpc_url { + Some(rpc_url) => rpc_url, + None => std::env::var("NETWORK_RPC_URL").expect( + "NETWORK_RPC_URL environment variable is not set. \ + Please set it to your rpc url or use the .rpc_url() method.", + ), + }; + + NetworkProver::new(&private_key, &rpc_url) + } +} diff --git a/crates/sdk/src/network/client.rs b/crates/sdk/src/network/client.rs index 2e39f9b08b..880352c5c6 100644 --- a/crates/sdk/src/network/client.rs +++ b/crates/sdk/src/network/client.rs @@ -1,122 +1,159 @@ -use std::time::Duration; - -use crate::{ - network::{ - auth::NetworkAuth, - proto::network::{ - ModifyCpuCyclesRequest, ModifyCpuCyclesResponse, UnclaimProofRequest, UnclaimReason, - }, - }, - SP1ProofWithPublicValues, -}; +//! # Network Client +//! +//! This module provides a client for directly interacting with the network prover service. + +use std::result::Result::Ok as StdOk; +use std::str::FromStr; +use std::time::{Duration, SystemTime, UNIX_EPOCH}; + +use alloy_signer::SignerSync; +use alloy_signer_local::PrivateKeySigner; use anyhow::{Context, Ok, Result}; -use futures::{future::join_all, Future}; -use reqwest::{Client as HttpClient, Url}; use reqwest_middleware::ClientWithMiddleware as HttpClientWithMiddleware; +use serde::{de::DeserializeOwned, Serialize}; use sp1_core_machine::io::SP1Stdin; -use std::{ - result::Result::Ok as StdOk, - time::{SystemTime, UNIX_EPOCH}, +use sp1_prover::{HashableKey, SP1VerifyingKey}; +use tonic::{ + transport::{channel::ClientTlsConfig, Channel}, + Code, }; -use twirp::{Client as TwirpClient, ClientError}; +use super::utils::Signable; +use crate::network::proto::artifact::{ + artifact_store_client::ArtifactStoreClient, CreateArtifactRequest, +}; use crate::network::proto::network::{ - ClaimProofRequest, ClaimProofResponse, CreateProofRequest, FulfillProofRequest, - FulfillProofResponse, GetNonceRequest, GetProofRequestsRequest, GetProofRequestsResponse, - GetProofStatusRequest, GetProofStatusResponse, NetworkServiceClient, ProofMode, ProofStatus, - SubmitProofRequest, + prover_network_client::ProverNetworkClient, CreateProgramRequest, CreateProgramRequestBody, + CreateProgramResponse, FulfillmentStatus, FulfillmentStrategy, GetNonceRequest, + GetProgramRequest, GetProgramResponse, GetProofRequestStatusRequest, + GetProofRequestStatusResponse, MessageFormat, ProofMode, RequestProofRequest, + RequestProofRequestBody, RequestProofResponse, }; -/// The default RPC endpoint for the Succinct prover network. -pub const DEFAULT_PROVER_NETWORK_RPC: &str = "https://rpc.succinct.xyz/"; - -/// The timeout for a proof request to be fulfilled. -const PROOF_TIMEOUT: Duration = Duration::from_secs(60 * 60); - -/// The timeout for a single RPC request. -const REQUEST_TIMEOUT: Duration = Duration::from_secs(30); - +/// A client for interacting with the network. pub struct NetworkClient { - pub rpc: TwirpClient, - pub http: HttpClientWithMiddleware, - pub auth: NetworkAuth, - pub is_using_prover_network: bool, + pub(crate) signer: PrivateKeySigner, + pub(crate) http: HttpClientWithMiddleware, + pub(crate) rpc_url: String, } impl NetworkClient { - /// Create a new NetworkClient with the given private key for authentication. - pub fn new(private_key: &str, rpc_url: Option) -> Self { - let auth = NetworkAuth::new(private_key); - - let twirp_http_client = HttpClient::builder() - .timeout(REQUEST_TIMEOUT) + /// Creates a new [`NetworkClient`] with the given private key and rpc url. + pub fn new(private_key: impl Into, rpc_url: impl Into) -> Self { + let signer = PrivateKeySigner::from_str(&private_key.into()).unwrap(); + let client = reqwest::Client::builder() .pool_max_idle_per_host(0) .pool_idle_timeout(Duration::from_secs(240)) .build() .unwrap(); + Self { signer, http: client.into(), rpc_url: rpc_url.into() } + } - let rpc_url = rpc_url.unwrap_or_else(|| DEFAULT_PROVER_NETWORK_RPC.to_string()); - let rpc = - TwirpClient::new(Url::parse(&rpc_url).unwrap(), twirp_http_client, vec![]).unwrap(); + /// Get the latest nonce for this account's address. + pub async fn get_nonce(&self) -> Result { + let mut rpc = self.prover_network_client().await?; + let res = + rpc.get_nonce(GetNonceRequest { address: self.signer.address().to_vec() }).await?; + Ok(res.into_inner().nonce) + } - let http_client = HttpClient::builder() - .timeout(REQUEST_TIMEOUT) - .pool_max_idle_per_host(0) - .pool_idle_timeout(Duration::from_secs(240)) - .build() - .unwrap(); + /// Get the verifying key hash from a verifying key. + /// + /// # Details + /// The verifying key hash is used to identify a program. + pub fn get_vk_hash(vk: &SP1VerifyingKey) -> Result> { + let vk_hash_str = vk.bytes32(); + let vk_hash = hex::decode(vk_hash_str.strip_prefix("0x").unwrap_or(&vk_hash_str))?; + Ok(vk_hash) + } - Self { - auth, - rpc, - http: http_client.into(), - is_using_prover_network: rpc_url == DEFAULT_PROVER_NETWORK_RPC, + /// Registers a program with the network if it is not already registered. + pub async fn register_program(&self, vk: &SP1VerifyingKey, elf: &[u8]) -> Result> { + let vk_hash = Self::get_vk_hash(vk)?; + + // Try to get the existing program. + if (self.get_program(&vk_hash).await?).is_some() { + // The program already exists. + Ok(vk_hash) + } else { + // The program doesn't exist, create it. + self.create_program(&vk_hash, vk, elf).await?; + log::info!("Registered program 0x{}", hex::encode(vk_hash.clone())); + Ok(vk_hash) } } - /// Gets the latest nonce for this auth's account. - pub async fn get_nonce(&self) -> Result { - let res = self - .with_error_handling( - self.rpc.get_nonce(GetNonceRequest { address: self.auth.get_address().to_vec() }), - ) - .await?; - Ok(res.nonce) + /// Attempts to get the program on the network. + /// + /// # Details + /// Returns `None` if the program does not exist. + pub async fn get_program(&self, vk_hash: &[u8]) -> Result> { + let mut rpc = self.prover_network_client().await?; + match rpc.get_program(GetProgramRequest { vk_hash: vk_hash.to_vec() }).await { + StdOk(response) => Ok(Some(response.into_inner())), + Err(status) if status.code() == Code::NotFound => Ok(None), + Err(e) => Err(e.into()), + } } - /// Upload a file to the specified url. - async fn upload_file(&self, url: &str, data: Vec) -> Result<()> { - self.http.put(url).body(data).send().await?; - Ok(()) + /// Creates a new program on the network. + pub async fn create_program( + &self, + vk_hash: &[u8], + vk: &SP1VerifyingKey, + elf: &[u8], + ) -> Result { + // Create the program artifact. + let mut store = self.artifact_store_client().await?; + let program_uri = self.create_artifact_with_content(&mut store, &elf).await?; + + // Serialize the verifying key. + let vk_encoded = bincode::serialize(&vk)?; + + // Send the request. + let mut rpc = self.prover_network_client().await?; + let nonce = self.get_nonce().await?; + let request_body = CreateProgramRequestBody { + nonce, + vk_hash: vk_hash.to_vec(), + vk: vk_encoded, + program_uri, + }; + + Ok(rpc + .create_program(CreateProgramRequest { + format: MessageFormat::Binary.into(), + signature: request_body.sign(&self.signer).into(), + body: Some(request_body), + }) + .await? + .into_inner()) } - /// Get the status and the proof if available of a given proof request. The proof is returned - /// only if the status is Fulfilled. - pub async fn get_proof_status( + /// Get the status of a given proof. + /// + /// # Details + /// If the status is Fulfilled, the proof is also returned. + pub async fn get_proof_request_status( &self, - proof_id: &str, - ) -> Result<(GetProofStatusResponse, Option)> { - let res = self - .with_error_handling( - self.rpc.get_proof_status(GetProofStatusRequest { proof_id: proof_id.to_string() }), - ) - .await - .context("Failed to get proof status")?; - - let proof = match res.status() { - ProofStatus::ProofFulfilled => { - log::info!("Proof request fulfilled"); - let proof_bytes = self - .http - .get(res.proof_url.as_ref().expect("no proof url")) - .timeout(Duration::from_secs(120)) - .send() - .await - .context("Failed to send HTTP request for proof")? - .bytes() - .await - .context("Failed to load proof bytes")?; - + request_id: &[u8], + ) -> Result<(GetProofRequestStatusResponse, Option

)> { + let mut rpc = self.prover_network_client().await?; + let res = rpc + .get_proof_request_status(GetProofRequestStatusRequest { + request_id: request_id.to_vec(), + }) + .await? + .into_inner(); + + let status = FulfillmentStatus::try_from(res.fulfillment_status)?; + let proof = match status { + FulfillmentStatus::Fulfilled => { + let proof_uri = res + .proof_uri + .as_ref() + .ok_or_else(|| anyhow::anyhow!("No proof URI provided"))?; + let proof_bytes = self.download_artifact(proof_uri).await?; Some(bincode::deserialize(&proof_bytes).context("Failed to deserialize proof")?) } _ => None, @@ -125,167 +162,119 @@ impl NetworkClient { Ok((res, proof)) } - /// Get all the proof requests for a given status. Also filter by circuit version if provided. - pub async fn get_proof_requests( + /// Creates a proof request with the given verifying key hash and stdin. + /// + /// # Details + /// * `vk_hash`: The verifying key hash of the program to prove. Used to identify the program. + /// * `stdin`: The standard input to provide to the program. + /// * `mode`: The [`ProofMode`] to use. + /// * `version`: The version of the SP1 circuits to use. + /// * `strategy`: The [`FulfillmentStrategy`] to use. + /// * `timeout_secs`: The timeout for the proof request in seconds. + /// * `cycle_limit`: The cycle limit for the proof request. + #[allow(clippy::too_many_arguments)] + pub async fn request_proof( &self, - status: ProofStatus, - circuit_version: Option<&str>, - ) -> Result { - self.with_error_handling(self.rpc.get_proof_requests(GetProofRequestsRequest { - status: status.into(), - circuit_version: circuit_version.map(|v| v.to_owned()), - })) - .await - } - - /// Creates a proof request for the given ELF and stdin. - pub async fn create_proof( - &self, - elf: &[u8], + vk_hash: &[u8], stdin: &SP1Stdin, mode: ProofMode, - circuit_version: &str, - ) -> Result { + version: &str, + strategy: FulfillmentStrategy, + timeout_secs: u64, + cycle_limit: u64, + ) -> Result { + // Calculate the deadline. let start = SystemTime::now(); let since_the_epoch = start.duration_since(UNIX_EPOCH).expect("Invalid start time"); - let deadline = since_the_epoch.as_secs() + PROOF_TIMEOUT.as_secs(); + let deadline = since_the_epoch.as_secs() + timeout_secs; - let nonce = self.get_nonce().await?; - let create_proof_signature = self - .auth - .sign_create_proof_message(nonce, deadline, mode.into(), circuit_version) - .await?; - - let res = self - .with_error_handling(self.rpc.create_proof(CreateProofRequest { - signature: create_proof_signature.to_vec(), - nonce, - deadline, - mode: mode.into(), - circuit_version: circuit_version.to_string(), - })) - .await?; - - let program_bytes = bincode::serialize(elf)?; - let stdin_bytes = bincode::serialize(&stdin)?; - let program_promise = self.upload_file(&res.program_url, program_bytes); - let stdin_promise = self.upload_file(&res.stdin_url, stdin_bytes); - let v = vec![program_promise, stdin_promise]; - let mut results = join_all(v).await; - results.pop().expect("Failed to upload stdin")?; - results.pop().expect("Failed to upload program")?; + // Create the stdin artifact. + let mut store = self.artifact_store_client().await?; + let stdin_uri = self.create_artifact_with_content(&mut store, &stdin).await?; + // Send the request. + let mut rpc = self.prover_network_client().await?; let nonce = self.get_nonce().await?; - let submit_proof_signature = - self.auth.sign_submit_proof_message(nonce, &res.proof_id).await?; - - self.with_error_handling(self.rpc.submit_proof(SubmitProofRequest { - signature: submit_proof_signature.to_vec(), + let request_body = RequestProofRequestBody { nonce, - proof_id: res.proof_id.clone(), - })) - .await?; - - Ok(res.proof_id) + version: format!("sp1-{version}"), + vk_hash: vk_hash.to_vec(), + mode: mode.into(), + strategy: strategy.into(), + stdin_uri, + deadline, + cycle_limit, + }; + let request_response = rpc + .request_proof(RequestProofRequest { + format: MessageFormat::Binary.into(), + signature: request_body.sign(&self.signer).into(), + body: Some(request_body), + }) + .await? + .into_inner(); + + Ok(request_response) } - /// Claim a proof that was requested. This commits to generating a proof and fulfilling it. - /// Returns an error if the proof is not in a PROOF_REQUESTED state. - pub async fn claim_proof(&self, proof_id: &str) -> Result { - let nonce = self.get_nonce().await?; - let signature = self.auth.sign_claim_proof_message(nonce, proof_id).await?; + pub(crate) async fn prover_network_client(&self) -> Result> { + let rpc_url = self.rpc_url.clone(); + let mut endpoint = Channel::from_shared(rpc_url.clone())?; - self.with_error_handling(self.rpc.claim_proof(ClaimProofRequest { - signature, - nonce, - proof_id: proof_id.to_string(), - })) - .await + // Check if the URL scheme is HTTPS and configure TLS. + if rpc_url.starts_with("https://") { + let tls_config = ClientTlsConfig::new().with_enabled_roots(); + endpoint = endpoint.tls_config(tls_config)?; + } + + let channel = endpoint.connect().await?; + Ok(ProverNetworkClient::new(channel)) } - /// Unclaim a proof that was claimed. This should only be called if the proof has not been - /// fulfilled yet. Returns an error if the proof is not in a PROOF_CLAIMED state or if the - /// caller is not the claimer. - pub async fn unclaim_proof( - &self, - proof_id: String, - reason: UnclaimReason, - description: String, - ) -> Result<()> { - let nonce = self.get_nonce().await?; - let signature = self - .auth - .sign_unclaim_proof_message(nonce, proof_id.clone(), reason, description.clone()) - .await?; + pub(crate) async fn artifact_store_client(&self) -> Result> { + let rpc_url = self.rpc_url.clone(); + let mut endpoint = Channel::from_shared(rpc_url.clone())?; - self.with_error_handling(self.rpc.unclaim_proof(UnclaimProofRequest { - signature, - nonce, - proof_id, - reason: reason.into(), - description, - })) - .await?; + // Check if the URL scheme is HTTPS and configure TLS. + if rpc_url.starts_with("https://") { + let tls_config = ClientTlsConfig::new().with_enabled_roots(); + endpoint = endpoint.tls_config(tls_config)?; + } - Ok(()) + let channel = endpoint.connect().await?; + Ok(ArtifactStoreClient::new(channel.clone())) } - /// Modifies the CPU cycles for a proof. May be called by the claimer after the proof has been - /// claimed. Returns an error if the proof is not in a PROOF_CLAIMED state or if the caller is - /// not the claimer. - pub async fn modify_cpu_cycles( + pub(crate) async fn create_artifact_with_content( &self, - proof_id: &str, - cycles: u64, - ) -> Result { - let nonce = self.get_nonce().await?; - let signature = self.auth.sign_modify_cpu_cycles_message(nonce, proof_id, cycles).await?; - let res = self - .with_error_handling(self.rpc.modify_cpu_cycles(ModifyCpuCyclesRequest { - signature, - nonce, - proof_id: proof_id.to_string(), - cycles, - })) - .await?; - - Ok(res) - } + store: &mut ArtifactStoreClient, + item: &T, + ) -> Result { + let signature = self.signer.sign_message_sync("create_artifact".as_bytes())?; + let request = CreateArtifactRequest { signature: signature.as_bytes().to_vec() }; + let response = store.create_artifact(request).await?.into_inner(); - /// Fulfill a proof. Should only be called after the proof has been uploaded. Returns an error - /// if the proof is not in a PROOF_CLAIMED state or if the caller is not the claimer. - pub async fn fulfill_proof(&self, proof_id: &str) -> Result { - let nonce = self.get_nonce().await?; - let signature = self.auth.sign_fulfill_proof_message(nonce, proof_id).await?; - let res = self - .with_error_handling(self.rpc.fulfill_proof(FulfillProofRequest { - signature, - nonce, - proof_id: proof_id.to_string(), - })) - .await?; - - Ok(res) - } + let presigned_url = response.artifact_presigned_url; + let uri = response.artifact_uri; - /// Awaits the future, then handles Succinct prover network errors. - async fn with_error_handling(&self, future: F) -> Result - where - F: Future>, - { - let result = future.await; - self.handle_twirp_error(result) + let response = + self.http.put(&presigned_url).body(bincode::serialize::(item)?).send().await?; + + if !response.status().is_success() { + log::debug!("Artifact upload failed with status: {}", response.status()); + } + assert!(response.status().is_success()); + + Ok(uri) } - /// Handles Twirp errors by formatting them into more readable error messages. - fn handle_twirp_error(&self, result: std::result::Result) -> Result { - match result { - StdOk(response) => StdOk(response), - Err(ClientError::TwirpError(err)) => { - let display_err = format!("error: \"{:?}\" message: {:?}", err.code, err.msg); - Err(anyhow::anyhow!(display_err)) - } - Err(err) => Err(err.into()), + pub(crate) async fn download_artifact(&self, uri: &str) -> Result> { + let response = self.http.get(uri).send().await.context("Failed to download from URI")?; + + if !response.status().is_success() { + return Err(anyhow::anyhow!("Failed to download artifact: HTTP {}", response.status())); } + + Ok(response.bytes().await.context("Failed to read response body")?.to_vec()) } } diff --git a/crates/sdk/src/network/mod.rs b/crates/sdk/src/network/mod.rs index 12d9b7b352..6cc201f327 100644 --- a/crates/sdk/src/network/mod.rs +++ b/crates/sdk/src/network/mod.rs @@ -1,6 +1,22 @@ -pub mod auth; +//! # SP1 Network +//! +//! A library for interacting with the SP1 prover over the network. + pub mod client; pub mod prover; - +mod sign_message; #[rustfmt::skip] +#[allow(missing_docs)] +#[allow(clippy::default_trait_access)] +#[allow(clippy::too_many_lines)] pub mod proto; +pub mod builder; +pub mod prove; +pub mod utils; + +pub use crate::network::client::NetworkClient; +pub use crate::network::proto::network::FulfillmentStrategy; + +pub(crate) const DEFAULT_PROVER_NETWORK_RPC: &str = "https://rpc.production.succinct.tools/"; +pub(crate) const DEFAULT_TIMEOUT_SECS: u64 = 14400; +pub(crate) const DEFAULT_CYCLE_LIMIT: u64 = 100_000_000; diff --git a/crates/sdk/src/network-v2/proto/artifact.rs b/crates/sdk/src/network/proto/artifact.rs similarity index 95% rename from crates/sdk/src/network-v2/proto/artifact.rs rename to crates/sdk/src/network/proto/artifact.rs index f635654c39..e1ff3ad034 100644 --- a/crates/sdk/src/network-v2/proto/artifact.rs +++ b/crates/sdk/src/network/proto/artifact.rs @@ -18,7 +18,7 @@ pub struct CreateArtifactResponse { pub mod artifact_store_client { #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] use tonic::codegen::http::Uri; - use tonic::codegen::*; + use tonic::codegen::{Body, Bytes, CompressionEncoding, GrpcMethod, InterceptedService, StdError, http}; #[derive(Debug, Clone)] pub struct ArtifactStoreClient { inner: tonic::client::Grpc, @@ -57,11 +57,11 @@ pub mod artifact_store_client { F: tonic::service::Interceptor, T::ResponseBody: Default, T: tonic::codegen::Service< - http::Request, - Response = http::Response< - >::ResponseBody, + http::Request, + Response = http::Response< + >::ResponseBody, + >, >, - >, >>::Error: Into + std::marker::Send + std::marker::Sync, { @@ -123,7 +123,7 @@ pub mod artifact_store_client { /// Generated server implementations. pub mod artifact_store_server { #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] - use tonic::codegen::*; + use tonic::codegen::{Arc, Body, BoxFuture, CompressionEncoding, Context, EnabledCompressionEncodings, InterceptedService, Poll, StdError, async_trait, empty_body, http}; /// Generated trait containing gRPC methods that should be implemented for use with ArtifactStoreServer. #[async_trait] pub trait ArtifactStore: std::marker::Send + std::marker::Sync + 'static { diff --git a/crates/sdk/src/network/proto/mod.rs b/crates/sdk/src/network/proto/mod.rs index a61610bd4d..48eb63675a 100644 --- a/crates/sdk/src/network/proto/mod.rs +++ b/crates/sdk/src/network/proto/mod.rs @@ -1 +1,2 @@ +pub mod artifact; pub mod network; diff --git a/crates/sdk/src/network/proto/network.rs b/crates/sdk/src/network/proto/network.rs index 545c9db255..52691b93ab 100644 --- a/crates/sdk/src/network/proto/network.rs +++ b/crates/sdk/src/network/proto/network.rs @@ -1,271 +1,1146 @@ // This file is @generated by prost-build. -/// The request to create a proof, the first step in requesting a proof. #[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct CreateProofRequest { - /// The signature of the message. - #[prost(bytes = "vec", tag = "1")] +pub struct RequestProofRequest { + /// The message format of the body. + #[prost(enumeration = "MessageFormat", tag = "1")] + pub format: i32, + /// The signature of the sender. + #[prost(bytes = "vec", tag = "2")] pub signature: ::prost::alloc::vec::Vec, - /// The nonce for the account. - #[prost(uint64, tag = "2")] + /// The body of the request. + #[prost(message, optional, tag = "3")] + pub body: ::core::option::Option, +} +#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] +pub struct RequestProofRequestBody { + /// The account nonce of the sender. + #[prost(uint64, tag = "1")] pub nonce: u64, - /// The mode for proof generation. - #[prost(enumeration = "ProofMode", tag = "3")] + /// The verification key hash of the program. + #[prost(bytes = "vec", tag = "2")] + pub vk_hash: ::prost::alloc::vec::Vec, + /// The version of the prover to use. + #[prost(string, tag = "3")] + pub version: ::prost::alloc::string::String, + /// The mode for the request. + #[prost(enumeration = "ProofMode", tag = "4")] pub mode: i32, - /// The deadline for the proof request, signifying the latest time a fulfillment would be valid. - #[prost(uint64, tag = "4")] + /// The strategy for fulfiller assignment. + #[prost(enumeration = "FulfillmentStrategy", tag = "5")] + pub strategy: i32, + /// The stdin resource identifier. + #[prost(string, tag = "6")] + pub stdin_uri: ::prost::alloc::string::String, + /// The deadline for the request. + #[prost(uint64, tag = "7")] pub deadline: u64, - /// The SP1 circuit version to use for the proof. - #[prost(string, tag = "5")] - pub circuit_version: ::prost::alloc::string::String, + /// The cycle limit for the request. + #[prost(uint64, tag = "8")] + pub cycle_limit: u64, } -/// The response for creating a proof. #[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct CreateProofResponse { - /// The proof identifier. - #[prost(string, tag = "1")] - pub proof_id: ::prost::alloc::string::String, - /// The URL to upload the ELF file. - #[prost(string, tag = "2")] - pub program_url: ::prost::alloc::string::String, - /// The URL to upload the standard input (stdin). - #[prost(string, tag = "3")] - pub stdin_url: ::prost::alloc::string::String, +pub struct RequestProofResponse { + /// The transaction hash. + #[prost(bytes = "vec", tag = "1")] + pub tx_hash: ::prost::alloc::vec::Vec, + /// The body of the response. + #[prost(message, optional, tag = "2")] + pub body: ::core::option::Option, } -/// The request to submit a proof, the second step in requesting a proof. MUST be called when the -/// proof is in a PROOF_REQUESTED state and MUST be called after uploading the program and stdin to -/// the URLs provided during create proof. #[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct SubmitProofRequest { - /// The signature of the message. +pub struct RequestProofResponseBody { + /// The identifier for the request. #[prost(bytes = "vec", tag = "1")] + pub request_id: ::prost::alloc::vec::Vec, +} +#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] +pub struct FulfillProofRequest { + /// The message format of the body. + #[prost(enumeration = "MessageFormat", tag = "1")] + pub format: i32, + /// The signature of the sender. + #[prost(bytes = "vec", tag = "2")] pub signature: ::prost::alloc::vec::Vec, - /// The nonce for the account. - #[prost(uint64, tag = "2")] + /// The body of the request. + #[prost(message, optional, tag = "3")] + pub body: ::core::option::Option, +} +#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] +pub struct FulfillProofRequestBody { + /// The account nonce of the sender. + #[prost(uint64, tag = "1")] pub nonce: u64, - /// The proof identifier. - #[prost(string, tag = "3")] - pub proof_id: ::prost::alloc::string::String, + /// The identifier for the request. + #[prost(bytes = "vec", tag = "2")] + pub request_id: ::prost::alloc::vec::Vec, + /// The proof bytes. + #[prost(bytes = "vec", tag = "3")] + pub proof: ::prost::alloc::vec::Vec, +} +#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] +pub struct FulfillProofResponse { + /// The transaction hash. + #[prost(bytes = "vec", tag = "1")] + pub tx_hash: ::prost::alloc::vec::Vec, + /// The body of the response. + #[prost(message, optional, tag = "2")] + pub body: ::core::option::Option, } -/// The response for submitting a proof, empty on success. #[derive(serde::Serialize, serde::Deserialize, Clone, Copy, PartialEq, ::prost::Message)] -pub struct SubmitProofResponse {} -/// The request to claim a proof, which agrees to fulfill the proof by the deadline. MUST be called -/// when the proof is in a PROOF_REQUESTED state. +pub struct FulfillProofResponseBody {} #[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct ClaimProofRequest { - /// The signature of the message. +pub struct ExecuteProofRequest { + /// The message format of the body. + #[prost(enumeration = "MessageFormat", tag = "1")] + pub format: i32, + /// The signature of the sender. + #[prost(bytes = "vec", tag = "2")] + pub signature: ::prost::alloc::vec::Vec, + /// The body of the request. + #[prost(message, optional, tag = "3")] + pub body: ::core::option::Option, +} +#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] +pub struct ExecuteProofRequestBody { + /// The account nonce of the sender. + #[prost(uint64, tag = "1")] + pub nonce: u64, + /// The identifier for the request. + #[prost(bytes = "vec", tag = "2")] + pub request_id: ::prost::alloc::vec::Vec, + /// The execution status of the request. + #[prost(enumeration = "ExecutionStatus", tag = "3")] + pub execution_status: i32, + /// The optional public values hash of the request execution, only included if + /// the request is valid. + #[prost(bytes = "vec", optional, tag = "4")] + pub public_values_hash: ::core::option::Option<::prost::alloc::vec::Vec>, + /// The optional cycles used when executing the request, only included if the + /// request is valid. + #[prost(uint64, optional, tag = "5")] + pub cycles: ::core::option::Option, +} +#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] +pub struct ExecuteProofResponse { + /// The transaction hash. #[prost(bytes = "vec", tag = "1")] + pub tx_hash: ::prost::alloc::vec::Vec, + /// The body of the response. + #[prost(message, optional, tag = "2")] + pub body: ::core::option::Option, +} +#[derive(serde::Serialize, serde::Deserialize, Clone, Copy, PartialEq, ::prost::Message)] +pub struct ExecuteProofResponseBody {} +#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] +pub struct FailFulfillmentRequest { + /// The message format of the body. + #[prost(enumeration = "MessageFormat", tag = "1")] + pub format: i32, + /// The signature of the sender. + #[prost(bytes = "vec", tag = "2")] pub signature: ::prost::alloc::vec::Vec, - /// The nonce for the account. - #[prost(uint64, tag = "2")] + /// The body of the request. + #[prost(message, optional, tag = "3")] + pub body: ::core::option::Option, +} +#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] +pub struct FailFulfillmentRequestBody { + /// The account nonce of the sender. + #[prost(uint64, tag = "1")] pub nonce: u64, - /// The proof identifier. + /// The identifier for the request. + #[prost(bytes = "vec", tag = "2")] + pub request_id: ::prost::alloc::vec::Vec, +} +#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] +pub struct FailFulfillmentResponse { + /// The transaction hash. + #[prost(bytes = "vec", tag = "1")] + pub tx_hash: ::prost::alloc::vec::Vec, + /// The body of the response. + #[prost(message, optional, tag = "2")] + pub body: ::core::option::Option, +} +#[derive(serde::Serialize, serde::Deserialize, Clone, Copy, PartialEq, ::prost::Message)] +pub struct FailFulfillmentResponseBody {} +#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] +pub struct FailExecutionRequest { + /// The message format of the body. + #[prost(enumeration = "MessageFormat", tag = "1")] + pub format: i32, + /// The signature of the sender. + #[prost(bytes = "vec", tag = "2")] + pub signature: ::prost::alloc::vec::Vec, + /// The body of the request. + #[prost(message, optional, tag = "3")] + pub body: ::core::option::Option, +} +#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] +pub struct FailExecutionRequestBody { + /// The account nonce of the sender. + #[prost(uint64, tag = "1")] + pub nonce: u64, + /// The identifier for the request. + #[prost(bytes = "vec", tag = "2")] + pub request_id: ::prost::alloc::vec::Vec, +} +#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] +pub struct FailExecutionResponse { + /// The transaction hash. + #[prost(bytes = "vec", tag = "1")] + pub tx_hash: ::prost::alloc::vec::Vec, + /// The body of the response. + #[prost(message, optional, tag = "2")] + pub body: ::core::option::Option, +} +#[derive(serde::Serialize, serde::Deserialize, Clone, Copy, PartialEq, ::prost::Message)] +pub struct FailExecutionResponseBody {} +#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] +pub struct ProofRequest { + /// The request identifier. + #[prost(bytes = "vec", tag = "1")] + pub request_id: ::prost::alloc::vec::Vec, + /// The verification key hash of the program. + #[prost(bytes = "vec", tag = "2")] + pub vk_hash: ::prost::alloc::vec::Vec, + /// The version of the prover to use. #[prost(string, tag = "3")] - pub proof_id: ::prost::alloc::string::String, + pub version: ::prost::alloc::string::String, + /// The mode for the proof. + #[prost(enumeration = "ProofMode", tag = "4")] + pub mode: i32, + /// The strategy for fulfiller assignment. + #[prost(enumeration = "FulfillmentStrategy", tag = "5")] + pub strategy: i32, + /// The program resource identifier. + #[prost(string, tag = "6")] + pub program_uri: ::prost::alloc::string::String, + /// The stdin resource identifier. + #[prost(string, tag = "7")] + pub stdin_uri: ::prost::alloc::string::String, + /// The deadline for the request. + #[prost(uint64, tag = "8")] + pub deadline: u64, + /// The cycle limit for the request. + #[prost(uint64, tag = "9")] + pub cycle_limit: u64, + /// The gas price for the request. + #[prost(uint64, optional, tag = "10")] + pub gas_price: ::core::option::Option, + /// The fulfillment status of the request. + #[prost(enumeration = "FulfillmentStatus", tag = "11")] + pub fulfillment_status: i32, + /// The execution status of the request. + #[prost(enumeration = "ExecutionStatus", tag = "12")] + pub execution_status: i32, + /// The requester address that signed the request. + #[prost(bytes = "vec", tag = "13")] + pub requester: ::prost::alloc::vec::Vec, + /// The fulfiller address that fulfilled the request. + #[prost(bytes = "vec", optional, tag = "14")] + pub fulfiller: ::core::option::Option<::prost::alloc::vec::Vec>, + /// The optional name to refer to an alias of the program id. + #[prost(string, optional, tag = "15")] + pub program_name: ::core::option::Option<::prost::alloc::string::String>, + /// The optional name to refer to an alias of the requester address. + #[prost(string, optional, tag = "16")] + pub requester_name: ::core::option::Option<::prost::alloc::string::String>, + /// The optional name to refer to an alias of the fulfiller address. + #[prost(string, optional, tag = "17")] + pub fulfiller_name: ::core::option::Option<::prost::alloc::string::String>, + /// The unix timestamp of when the request was created. + #[prost(uint64, tag = "18")] + pub created_at: u64, + /// The unix timestamp of when the request was updated. + #[prost(uint64, tag = "19")] + pub updated_at: u64, + /// The unix timestamp of when the request was fulfilled. + #[prost(uint64, optional, tag = "20")] + pub fulfilled_at: ::core::option::Option, + /// The transaction hash of the request. + #[prost(bytes = "vec", tag = "21")] + pub tx_hash: ::prost::alloc::vec::Vec, + /// The cycle count for the request. + #[prost(uint64, optional, tag = "22")] + pub cycles: ::core::option::Option, + /// The amount deducted from the fulfiller's balance. + #[prost(string, optional, tag = "23")] + pub deduction_amount: ::core::option::Option<::prost::alloc::string::String>, + /// The amount refunded to the fulfiller's balance. + #[prost(string, optional, tag = "24")] + pub refund_amount: ::core::option::Option<::prost::alloc::string::String>, +} +#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] +pub struct GetProofRequestStatusRequest { + /// The identifier for the request. + #[prost(bytes = "vec", tag = "1")] + pub request_id: ::prost::alloc::vec::Vec, +} +#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] +pub struct GetProofRequestStatusResponse { + /// The fulfillment status of the request. + #[prost(enumeration = "FulfillmentStatus", tag = "1")] + pub fulfillment_status: i32, + /// The execution status of the request. + #[prost(enumeration = "ExecutionStatus", tag = "2")] + pub execution_status: i32, + /// The transaction hash of the request. + #[prost(bytes = "vec", tag = "3")] + pub request_tx_hash: ::prost::alloc::vec::Vec, + /// The optional transaction hash of the proof fulfill. Only included if the + /// request has a fulfillment status of FULFILLED. + #[prost(bytes = "vec", optional, tag = "4")] + pub fulfill_tx_hash: ::core::option::Option<::prost::alloc::vec::Vec>, + /// The optional proof URI, where you can download the result of the request. + /// Only included if the request has a fulfillment status of FULFILLED. + #[prost(string, optional, tag = "5")] + pub proof_uri: ::core::option::Option<::prost::alloc::string::String>, +} +#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] +pub struct GetProofRequestDetailsRequest { + /// The identifier for the request. + #[prost(bytes = "vec", tag = "1")] + pub request_id: ::prost::alloc::vec::Vec, +} +#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] +pub struct GetProofRequestDetailsResponse { + /// The detailed request. + #[prost(message, optional, tag = "1")] + pub request: ::core::option::Option, +} +#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] +pub struct GetFilteredProofRequestsRequest { + /// The optional version of the requests to filter for. + #[prost(string, optional, tag = "1")] + pub version: ::core::option::Option<::prost::alloc::string::String>, + /// The optional fulfillment status of the requests to filter for. + #[prost(enumeration = "FulfillmentStatus", optional, tag = "2")] + pub fulfillment_status: ::core::option::Option, + /// The optional execution status of the requests to filter for. + #[prost(enumeration = "ExecutionStatus", optional, tag = "3")] + pub execution_status: ::core::option::Option, + /// The optional minimum unix timestamp deadline of the requests to filter for. + /// Only returns requests with deadlines after this timestamp. + #[prost(uint64, optional, tag = "4")] + pub minimum_deadline: ::core::option::Option, + /// The optional verification key hash of the program to filter for. + #[prost(bytes = "vec", optional, tag = "5")] + pub vk_hash: ::core::option::Option<::prost::alloc::vec::Vec>, + /// The optional requester address to filter for. + #[prost(bytes = "vec", optional, tag = "6")] + pub requester: ::core::option::Option<::prost::alloc::vec::Vec>, + /// The optional fulfiller address to filter for. + #[prost(bytes = "vec", optional, tag = "7")] + pub fulfiller: ::core::option::Option<::prost::alloc::vec::Vec>, + /// The optional minimum creation unix timestamp of the requests to filter for. + #[prost(uint64, optional, tag = "8")] + pub from: ::core::option::Option, + /// The optional maximum creation unix timestamp of the requests to filter for. + #[prost(uint64, optional, tag = "9")] + pub to: ::core::option::Option, + /// The optional maximum number of requests to return (default is 10, + /// maximum is 100). + #[prost(uint32, optional, tag = "10")] + pub limit: ::core::option::Option, + /// The optional page number to return (default is 1). + #[prost(uint32, optional, tag = "11")] + pub page: ::core::option::Option, + /// The optional mode of the requests to filter for. + #[prost(enumeration = "ProofMode", optional, tag = "12")] + pub mode: ::core::option::Option, +} +#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] +pub struct GetFilteredProofRequestsResponse { + /// The requests that matched the filter criteria. + #[prost(message, repeated, tag = "1")] + pub requests: ::prost::alloc::vec::Vec, } -/// The response for claiming a proof, giving identifiers for the locations to retrieve the program -/// and stdin, as well as the location to upload the proof. #[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct ClaimProofResponse { - /// The artifact identifier for the program location. +pub struct GetSearchResultsRequest { + /// The search query string. #[prost(string, tag = "1")] - pub program_artifact_id: ::prost::alloc::string::String, - /// The artifact identifier for the stdin location. - #[prost(string, tag = "2")] - pub stdin_artifact_id: ::prost::alloc::string::String, - /// The artifact identifier for the proof location. - #[prost(string, tag = "3")] - pub proof_artifact_id: ::prost::alloc::string::String, + pub query: ::prost::alloc::string::String, } -/// The request to unclaim a proof, which cancels the claim to fulfill the proof. MUST be called -/// when the proof is in a PROOF_CLAIMED state and MUST be called by the prover who claimed it. #[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct UnclaimProofRequest { - /// The signature of the message. +pub struct SearchResult { #[prost(bytes = "vec", tag = "1")] - pub signature: ::prost::alloc::vec::Vec, - /// The nonce for the account. + pub id: ::prost::alloc::vec::Vec, + #[prost(string, optional, tag = "2")] + pub name: ::core::option::Option<::prost::alloc::string::String>, +} +#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] +pub struct GetSearchResultsResponse { + /// List of matching request IDs with optional names. + #[prost(message, repeated, tag = "1")] + pub requests: ::prost::alloc::vec::Vec, + /// List of matching program IDs with optional names. + #[prost(message, repeated, tag = "2")] + pub programs: ::prost::alloc::vec::Vec, + /// List of matching requester IDs with optional names. + #[prost(message, repeated, tag = "3")] + pub requesters: ::prost::alloc::vec::Vec, +} +#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] +pub struct GetProofRequestMetricsRequest { + /// The optional address to filter for. + #[prost(bytes = "vec", optional, tag = "1")] + pub address: ::core::option::Option<::prost::alloc::vec::Vec>, + /// The optional interval in days for volume calculation. + #[prost(uint64, optional, tag = "2")] + pub volume_interval_days: ::core::option::Option, +} +#[derive(serde::Serialize, serde::Deserialize, Clone, Copy, PartialEq, ::prost::Message)] +pub struct GetProofRequestMetricsResponse { + /// The total number of proofs. + #[prost(uint64, tag = "1")] + pub total_proofs: u64, + /// The total number of cycles. #[prost(uint64, tag = "2")] + pub total_cycles: u64, + /// The volume in the specified interval. + #[prost(uint64, tag = "3")] + pub volume: u64, +} +#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] +pub struct GetProofRequestGraphRequest { + /// The optional address to filter for. + #[prost(bytes = "vec", optional, tag = "1")] + pub address: ::core::option::Option<::prost::alloc::vec::Vec>, + /// The optional interval in days for the graph range. + #[prost(uint64, optional, tag = "2")] + pub range_interval_days: ::core::option::Option, +} +#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] +pub struct GraphData { + /// The timestamp of the data point. + #[prost(string, tag = "1")] + pub timestamp: ::prost::alloc::string::String, + /// The value at this timestamp. + #[prost(uint64, tag = "2")] + pub value: u64, +} +#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] +pub struct GetProofRequestGraphResponse { + /// The time series data points. + #[prost(message, repeated, tag = "1")] + pub data: ::prost::alloc::vec::Vec, +} +#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] +pub struct GetAnalyticsGraphsRequest { + /// The optional address to filter for. + #[prost(bytes = "vec", optional, tag = "1")] + pub address: ::core::option::Option<::prost::alloc::vec::Vec>, + /// The optional interval in days for the graph range. + #[prost(uint64, optional, tag = "2")] + pub range_interval_days: ::core::option::Option, +} +#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] +pub struct GetAnalyticsGraphsResponse { + /// The time series data points for proof count. + #[prost(message, repeated, tag = "1")] + pub proofs: ::prost::alloc::vec::Vec, + /// The time series data points for program count. + #[prost(message, repeated, tag = "2")] + pub programs: ::prost::alloc::vec::Vec, + /// The time series data points for cycle count. + #[prost(message, repeated, tag = "3")] + pub cycles: ::prost::alloc::vec::Vec, +} +#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] +pub struct GetNonceRequest { + /// The address of the account. + #[prost(bytes = "vec", tag = "1")] + pub address: ::prost::alloc::vec::Vec, +} +#[derive(serde::Serialize, serde::Deserialize, Clone, Copy, PartialEq, ::prost::Message)] +pub struct GetNonceResponse { + /// The nonce of the account. + #[prost(uint64, tag = "1")] pub nonce: u64, - /// The proof identifier. - #[prost(string, tag = "3")] - pub proof_id: ::prost::alloc::string::String, - /// The reason for unclaiming the proof. - #[prost(enumeration = "UnclaimReason", tag = "4")] - pub reason: i32, - /// The description for the reason. - #[prost(string, tag = "5")] - pub description: ::prost::alloc::string::String, -} -/// The response for unclaiming a proof, empty on success. +} +#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] +pub struct Delegation { + /// The address of the owner. + #[prost(bytes = "vec", tag = "1")] + pub owner: ::prost::alloc::vec::Vec, + /// The address of the delegate (the account with granted permissions). + #[prost(bytes = "vec", tag = "2")] + pub delegate: ::prost::alloc::vec::Vec, + /// Whether the delegation has been accepted. + #[prost(bool, tag = "3")] + pub accepted: bool, + /// The unix timestamp of when the delegation was created. + #[prost(uint64, tag = "4")] + pub created_at: u64, +} +#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] +pub struct GetFilteredDelegationsRequest { + /// The optional owner address to filter for. + #[prost(bytes = "vec", optional, tag = "1")] + pub owner: ::core::option::Option<::prost::alloc::vec::Vec>, + /// The optional maximum number of requests to return (default is 10, + /// maximum is 100). + #[prost(uint32, optional, tag = "2")] + pub limit: ::core::option::Option, + /// The optional page number to return (default is 1). + #[prost(uint32, optional, tag = "3")] + pub page: ::core::option::Option, +} +#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] +pub struct GetFilteredDelegationsResponse { + /// The delegations that matched the filter criteria. + #[prost(message, repeated, tag = "1")] + pub delegations: ::prost::alloc::vec::Vec, +} +#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] +pub struct AddDelegationRequest { + /// The message format of the body. + #[prost(enumeration = "MessageFormat", tag = "1")] + pub format: i32, + /// The signature of the sender. + #[prost(bytes = "vec", tag = "2")] + pub signature: ::prost::alloc::vec::Vec, + /// The body of the request. + #[prost(message, optional, tag = "3")] + pub body: ::core::option::Option, +} +#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] +pub struct AddDelegationRequestBody { + /// The account nonce of the sender. + #[prost(uint64, tag = "1")] + pub nonce: u64, + /// The delegate address to add. + #[prost(bytes = "vec", tag = "2")] + pub delegate: ::prost::alloc::vec::Vec, +} +#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] +pub struct AddDelegationResponse { + /// The transaction hash. + #[prost(bytes = "vec", tag = "1")] + pub tx_hash: ::prost::alloc::vec::Vec, + /// The body of the response. + #[prost(message, optional, tag = "2")] + pub body: ::core::option::Option, +} #[derive(serde::Serialize, serde::Deserialize, Clone, Copy, PartialEq, ::prost::Message)] -pub struct UnclaimProofResponse {} -/// The request to update a proof's CPU cycle count. +pub struct AddDelegationResponseBody {} #[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct ModifyCpuCyclesRequest { - /// The signature of the message. +pub struct RemoveDelegationRequest { + /// The message format of the body. + #[prost(enumeration = "MessageFormat", tag = "1")] + pub format: i32, + /// The signature of the sender. + #[prost(bytes = "vec", tag = "2")] + pub signature: ::prost::alloc::vec::Vec, + /// The body of the request. + #[prost(message, optional, tag = "3")] + pub body: ::core::option::Option, +} +#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] +pub struct RemoveDelegationRequestBody { + /// The account nonce of the sender. + #[prost(uint64, tag = "1")] + pub nonce: u64, + /// The delegate address to remove. + #[prost(bytes = "vec", tag = "2")] + pub delegate: ::prost::alloc::vec::Vec, +} +#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] +pub struct RemoveDelegationResponse { + /// The transaction hash. #[prost(bytes = "vec", tag = "1")] + pub tx_hash: ::prost::alloc::vec::Vec, + /// The body of the response. + #[prost(message, optional, tag = "2")] + pub body: ::core::option::Option, +} +#[derive(serde::Serialize, serde::Deserialize, Clone, Copy, PartialEq, ::prost::Message)] +pub struct RemoveDelegationResponseBody {} +#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] +pub struct AcceptDelegationRequest { + /// The message format of the body. + #[prost(enumeration = "MessageFormat", tag = "1")] + pub format: i32, + /// The signature of the sender. + #[prost(bytes = "vec", tag = "2")] pub signature: ::prost::alloc::vec::Vec, - /// The nonce for the account. - #[prost(uint64, tag = "2")] + /// The body of the request. + #[prost(message, optional, tag = "3")] + pub body: ::core::option::Option, +} +#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] +pub struct AcceptDelegationRequestBody { + /// The account nonce of the sender. + #[prost(uint64, tag = "1")] + pub nonce: u64, + /// The address of the owner who requested the delegation + #[prost(bytes = "vec", tag = "2")] + pub owner: ::prost::alloc::vec::Vec, +} +#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] +pub struct AcceptDelegationResponse { + /// The transaction hash. + #[prost(bytes = "vec", tag = "1")] + pub tx_hash: ::prost::alloc::vec::Vec, + /// The body of the response. + #[prost(message, optional, tag = "2")] + pub body: ::core::option::Option, +} +#[derive(serde::Serialize, serde::Deserialize, Clone, Copy, PartialEq, ::prost::Message)] +pub struct AcceptDelegationResponseBody {} +#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] +pub struct SetAccountNameRequest { + /// The message format of the body. + #[prost(enumeration = "MessageFormat", tag = "1")] + pub format: i32, + /// The signature of the sender. + #[prost(bytes = "vec", tag = "2")] + pub signature: ::prost::alloc::vec::Vec, + /// The body of the request. + #[prost(message, optional, tag = "3")] + pub body: ::core::option::Option, +} +#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] +pub struct SetAccountNameRequestBody { + /// The account nonce of the sender. + #[prost(uint64, tag = "1")] pub nonce: u64, - /// The proof identifier. + /// The address of the account to update the name of. Only the sender can + /// update the name unless authorized. + #[prost(bytes = "vec", tag = "2")] + pub address: ::prost::alloc::vec::Vec, + /// The name of the account. Must be unique. #[prost(string, tag = "3")] - pub proof_id: ::prost::alloc::string::String, - /// The number of CPU cycles for this proof. - #[prost(uint64, tag = "4")] - pub cycles: u64, + pub name: ::prost::alloc::string::String, +} +#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] +pub struct SetAccountNameResponse { + /// The transaction hash. + #[prost(bytes = "vec", tag = "1")] + pub tx_hash: ::prost::alloc::vec::Vec, + /// The body of the response. + #[prost(message, optional, tag = "2")] + pub body: ::core::option::Option, } -/// The response for updating a proof's CPU cycle count, empty on success. #[derive(serde::Serialize, serde::Deserialize, Clone, Copy, PartialEq, ::prost::Message)] -pub struct ModifyCpuCyclesResponse {} -/// The request to fulfill a proof. MUST be called after the proof has been uploaded and MUST be called -/// when the proof is in a PROOF_CLAIMED state. +pub struct SetAccountNameResponseBody {} #[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct FulfillProofRequest { - /// The signature of the message. +pub struct GetAccountNameRequest { + /// The address of the account. #[prost(bytes = "vec", tag = "1")] + pub address: ::prost::alloc::vec::Vec, +} +#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] +pub struct GetAccountNameResponse { + /// The name of the account. + #[prost(string, optional, tag = "1")] + pub name: ::core::option::Option<::prost::alloc::string::String>, +} +#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] +pub struct GetTermsSignatureRequest { + /// The address of the account. + #[prost(bytes = "vec", tag = "1")] + pub address: ::prost::alloc::vec::Vec, +} +#[derive(serde::Serialize, serde::Deserialize, Clone, Copy, PartialEq, ::prost::Message)] +pub struct GetTermsSignatureResponse { + /// Whether the account has signed the terms. + #[prost(bool, tag = "1")] + pub is_signed: bool, +} +#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] +pub struct SetTermsSignatureRequest { + /// The message format of the body. + #[prost(enumeration = "MessageFormat", tag = "1")] + pub format: i32, + /// The signature of the sender. + #[prost(bytes = "vec", tag = "2")] pub signature: ::prost::alloc::vec::Vec, - /// The nonce for the account. - #[prost(uint64, tag = "2")] + /// The body of the request. + #[prost(message, optional, tag = "3")] + pub body: ::core::option::Option, +} +#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] +pub struct SetTermsSignatureRequestBody { + /// The account nonce of the sender. + #[prost(uint64, tag = "1")] pub nonce: u64, - /// The proof identifier. - #[prost(string, tag = "3")] - pub proof_id: ::prost::alloc::string::String, + /// The address of the account. + #[prost(bytes = "vec", tag = "2")] + pub address: ::prost::alloc::vec::Vec, +} +#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] +pub struct SetTermsSignatureResponse { + /// The transaction hash. + #[prost(bytes = "vec", tag = "1")] + pub tx_hash: ::prost::alloc::vec::Vec, + /// The body of the response. + #[prost(message, optional, tag = "2")] + pub body: ::core::option::Option, } -/// The response for fulfilling a proof, empty on success. #[derive(serde::Serialize, serde::Deserialize, Clone, Copy, PartialEq, ::prost::Message)] -pub struct FulfillProofResponse { - /// The amount of time, in seconds, between proof claim and fulfillment. +pub struct SetTermsSignatureResponseBody {} +#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] +pub struct Program { + /// The verification key hash. + #[prost(bytes = "vec", tag = "1")] + pub vk_hash: ::prost::alloc::vec::Vec, + /// The verification key. + #[prost(bytes = "vec", tag = "2")] + pub vk: ::prost::alloc::vec::Vec, + /// The program resource identifier. + #[prost(string, tag = "3")] + pub program_uri: ::prost::alloc::string::String, + /// The optional name of the program. + #[prost(string, optional, tag = "4")] + pub name: ::core::option::Option<::prost::alloc::string::String>, + /// The owner of the program. + #[prost(bytes = "vec", tag = "5")] + pub owner: ::prost::alloc::vec::Vec, + /// The unix timestamp of when the program was created. + #[prost(uint64, tag = "6")] + pub created_at: u64, +} +#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] +pub struct GetProgramRequest { + /// The verification key hash of the program. + #[prost(bytes = "vec", tag = "1")] + pub vk_hash: ::prost::alloc::vec::Vec, +} +#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] +pub struct GetProgramResponse { + /// The program details. + #[prost(message, optional, tag = "1")] + pub program: ::core::option::Option, +} +#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] +pub struct CreateProgramRequest { + /// The message format of the body. + #[prost(enumeration = "MessageFormat", tag = "1")] + pub format: i32, + /// The signature of the sender. + #[prost(bytes = "vec", tag = "2")] + pub signature: ::prost::alloc::vec::Vec, + /// The body of the request. + #[prost(message, optional, tag = "3")] + pub body: ::core::option::Option, +} +#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] +pub struct CreateProgramRequestBody { + /// The account nonce of the sender. #[prost(uint64, tag = "1")] - pub proving_seconds: u64, + pub nonce: u64, + /// The verification key hash. + #[prost(bytes = "vec", tag = "2")] + pub vk_hash: ::prost::alloc::vec::Vec, + /// The verification key. + #[prost(bytes = "vec", tag = "3")] + pub vk: ::prost::alloc::vec::Vec, + /// The program resource identifier. + #[prost(string, tag = "4")] + pub program_uri: ::prost::alloc::string::String, } -/// The request to relay a proof through the NetworkGateway on a given chain. MUST be called when the -/// proof is in a PROOF_FULFILLED state. #[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct RelayProofRequest { - /// The signature of the message. +pub struct CreateProgramResponse { + /// The transaction hash. #[prost(bytes = "vec", tag = "1")] + pub tx_hash: ::prost::alloc::vec::Vec, + /// The body of the response. + #[prost(message, optional, tag = "2")] + pub body: ::core::option::Option, +} +#[derive(serde::Serialize, serde::Deserialize, Clone, Copy, PartialEq, ::prost::Message)] +pub struct CreateProgramResponseBody {} +#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] +pub struct SetProgramNameRequest { + /// The message format of the body. + #[prost(enumeration = "MessageFormat", tag = "1")] + pub format: i32, + /// The signature of the sender. + #[prost(bytes = "vec", tag = "2")] pub signature: ::prost::alloc::vec::Vec, - /// The nonce for the account. - #[prost(uint64, tag = "2")] + /// The body of the request. + #[prost(message, optional, tag = "3")] + pub body: ::core::option::Option, +} +#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] +pub struct SetProgramNameRequestBody { + /// The account nonce of the sender. + #[prost(uint64, tag = "1")] pub nonce: u64, - /// The proof identifier. + /// The identifier of the program to update the name of. Only the original + /// program creator can update the name unless authorized. + #[prost(bytes = "vec", tag = "2")] + pub vk_hash: ::prost::alloc::vec::Vec, + /// The name of the program. Must be unique. #[prost(string, tag = "3")] - pub proof_id: ::prost::alloc::string::String, - /// The chain ID for the requested chain. - #[prost(uint32, tag = "4")] - pub chain_id: u32, - /// The address of the verifier for this proof. - #[prost(bytes = "vec", tag = "5")] - pub verifier: ::prost::alloc::vec::Vec, - /// The address of the callback to call after the proof has been verified by the verifier. - #[prost(bytes = "vec", tag = "6")] - pub callback: ::prost::alloc::vec::Vec, - /// The data to send to the callback, including the function selector. - #[prost(bytes = "vec", tag = "7")] - pub callback_data: ::prost::alloc::vec::Vec, -} -/// The response for relaying a proof. -#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct RelayProofResponse { - /// The transaction identifier. + pub name: ::prost::alloc::string::String, +} +#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] +pub struct SetProgramNameResponse { + /// The transaction hash. + #[prost(bytes = "vec", tag = "1")] + pub tx_hash: ::prost::alloc::vec::Vec, + /// The body of the response. + #[prost(message, optional, tag = "2")] + pub body: ::core::option::Option, +} +#[derive(serde::Serialize, serde::Deserialize, Clone, Copy, PartialEq, ::prost::Message)] +pub struct SetProgramNameResponseBody {} +#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] +pub struct GetBalanceRequest { + /// The address of the account. + #[prost(bytes = "vec", tag = "1")] + pub address: ::prost::alloc::vec::Vec, +} +#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] +pub struct GetBalanceResponse { + /// The amount of credits owned by the account. #[prost(string, tag = "1")] - pub tx_id: ::prost::alloc::string::String, + pub amount: ::prost::alloc::string::String, } -/// The request for an account nonce. Used to check current nonce for the account, which must match when signing and sending a message. #[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct GetNonceRequest { - /// The account's address for which to get the nonce. +pub struct BalanceLog { + /// The address of the account. #[prost(bytes = "vec", tag = "1")] pub address: ::prost::alloc::vec::Vec, + /// The type of balance change operation. + #[prost(enumeration = "BalanceOperation", tag = "2")] + pub operation: i32, + /// The amount of the change (can be positive or negative). + #[prost(string, tag = "3")] + pub amount: ::prost::alloc::string::String, + /// The transaction hash that caused this change. + #[prost(bytes = "vec", tag = "4")] + pub tx_hash: ::prost::alloc::vec::Vec, + /// The unix timestamp of when this change occurred. + #[prost(uint64, tag = "5")] + pub created_at: u64, +} +#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] +pub struct GetFilteredBalanceLogsRequest { + /// The optional address to filter for. + #[prost(bytes = "vec", optional, tag = "1")] + pub address: ::core::option::Option<::prost::alloc::vec::Vec>, + /// The optional type of operations to filter for. + #[prost(enumeration = "BalanceOperation", optional, tag = "2")] + pub operation: ::core::option::Option, + /// The optional minimum unix timestamp to filter logs from. Only returns + /// logs after this timestamp. + #[prost(uint64, optional, tag = "3")] + pub minimum_timestamp: ::core::option::Option, + /// The optional maximum unix timestamp to filter logs to. Only returns + /// logs before this timestamp. + #[prost(uint64, optional, tag = "4")] + pub maximum_timestamp: ::core::option::Option, + /// The optional maximum number of logs to return (default is 10, maximum is 100). + #[prost(uint32, optional, tag = "5")] + pub limit: ::core::option::Option, + /// The optional page number to return (default is 1). + #[prost(uint32, optional, tag = "6")] + pub page: ::core::option::Option, +} +#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] +pub struct GetFilteredBalanceLogsResponse { + /// The balance logs that matched the filter criteria. + #[prost(message, repeated, tag = "1")] + pub logs: ::prost::alloc::vec::Vec, +} +#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] +pub struct AddCreditRequest { + /// The message format of the body. + #[prost(enumeration = "MessageFormat", tag = "1")] + pub format: i32, + /// The signature of the sender. + #[prost(bytes = "vec", tag = "2")] + pub signature: ::prost::alloc::vec::Vec, + /// The body of the request. + #[prost(message, optional, tag = "3")] + pub body: ::core::option::Option, +} +#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] +pub struct AddCreditRequestBody { + /// The account nonce of the sender. + #[prost(uint64, tag = "1")] + pub nonce: u64, + /// The address of the account to add credits to. + #[prost(bytes = "vec", tag = "2")] + pub address: ::prost::alloc::vec::Vec, + /// The amount of credits to add. + #[prost(string, tag = "3")] + pub amount: ::prost::alloc::string::String, +} +#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] +pub struct AddCreditResponse { + /// The transaction hash. + #[prost(bytes = "vec", tag = "1")] + pub tx_hash: ::prost::alloc::vec::Vec, + /// The body of the response. + #[prost(message, optional, tag = "2")] + pub body: ::core::option::Option, } -/// The response for a nonce request. #[derive(serde::Serialize, serde::Deserialize, Clone, Copy, PartialEq, ::prost::Message)] -pub struct GetNonceResponse { - /// The nonce for the given address. It should be signed along with the rest of the message. +pub struct AddCreditResponseBody {} +#[derive(serde::Serialize, serde::Deserialize, Clone, Copy, PartialEq, ::prost::Message)] +pub struct GetLatestBridgeBlockRequest { + /// The chain ID of the bridge. + #[prost(uint32, tag = "1")] + pub chain_id: u32, +} +#[derive(serde::Serialize, serde::Deserialize, Clone, Copy, PartialEq, ::prost::Message)] +pub struct GetLatestBridgeBlockResponse { + /// The latest processed block in the bridge. + #[prost(uint64, tag = "1")] + pub block_number: u64, +} +#[derive(serde::Serialize, serde::Deserialize, Clone, Copy, PartialEq, ::prost::Message)] +pub struct GetGasPriceEstimateRequest { + #[prost(enumeration = "FulfillmentStrategy", tag = "1")] + pub strategy: i32, +} +#[derive(serde::Serialize, serde::Deserialize, Clone, Copy, PartialEq, ::prost::Message)] +pub struct GetGasPriceEstimateResponse { #[prost(uint64, tag = "1")] + pub gas_price: u64, +} +#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] +pub struct GetTransactionDetailsRequest { + /// The transaction hash. + #[prost(bytes = "vec", tag = "1")] + pub tx_hash: ::prost::alloc::vec::Vec, +} +#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] +pub struct TransactionDetails { + #[prost(bytes = "vec", tag = "1")] + pub tx_hash: ::prost::alloc::vec::Vec, + #[prost(bytes = "vec", tag = "2")] + pub sender: ::prost::alloc::vec::Vec, + #[prost(bytes = "vec", tag = "3")] + pub signature: ::prost::alloc::vec::Vec, + #[prost(uint64, tag = "4")] pub nonce: u64, + #[prost(uint64, tag = "5")] + pub created_at: u64, + #[prost(string, optional, tag = "6")] + pub name: ::core::option::Option<::prost::alloc::string::String>, + #[prost(bytes = "vec", optional, tag = "7")] + pub request_id: ::core::option::Option<::prost::alloc::vec::Vec>, } -/// The request to get a proof status by a given proof ID. #[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct GetProofStatusRequest { - /// The proof identifier. - #[prost(string, tag = "1")] - pub proof_id: ::prost::alloc::string::String, +pub struct GetTransactionDetailsResponse { + #[prost(message, optional, tag = "1")] + pub transaction: ::core::option::Option, } -/// The response for a proof status request. #[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct GetProofStatusResponse { - /// The status of the proof request. - #[prost(enumeration = "ProofStatus", tag = "1")] - pub status: i32, - /// Optional proof URL, where you can download the result of the proof request. Only included if - /// the proof has been fulfilled. - #[prost(string, optional, tag = "2")] - pub proof_url: ::core::option::Option<::prost::alloc::string::String>, - /// If the proof was unclaimed, the reason why. - #[prost(enumeration = "UnclaimReason", optional, tag = "3")] - pub unclaim_reason: ::core::option::Option, - /// If the proof was unclaimed, the description detailing why. +pub struct Reservation { + /// The address of the requester. + #[prost(bytes = "vec", tag = "1")] + pub requester: ::prost::alloc::vec::Vec, + /// The address of the fulfiller. + #[prost(bytes = "vec", tag = "2")] + pub fulfiller: ::prost::alloc::vec::Vec, + /// The optional name to refer to an alias of the requester address. + #[prost(string, optional, tag = "3")] + pub requester_name: ::core::option::Option<::prost::alloc::string::String>, + /// The optional name to refer to an alias of the fulfiller address. #[prost(string, optional, tag = "4")] - pub unclaim_description: ::core::option::Option<::prost::alloc::string::String>, + pub fulfiller_name: ::core::option::Option<::prost::alloc::string::String>, + /// The unix timestamp of when the reservation was created. + #[prost(uint64, tag = "5")] + pub created_at: u64, +} +#[derive(serde::Serialize, serde::Deserialize, Clone, Copy, PartialEq, ::prost::Message)] +pub struct GetFilteredReservationsRequest { + /// The optional maximum number of reservations to return (default is 10, + /// maximum is 100). + #[prost(uint32, optional, tag = "1")] + pub limit: ::core::option::Option, + /// The optional page number to return (default is 1). + #[prost(uint32, optional, tag = "2")] + pub page: ::core::option::Option, } -/// The request to get proof requests by a given status. #[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct GetProofRequestsRequest { - /// The status of the proof requests to filter for. - #[prost(enumeration = "ProofStatus", tag = "1")] - pub status: i32, - /// The SP1 circuit version of the proof requests to filter for. - #[prost(string, optional, tag = "2")] - pub circuit_version: ::core::option::Option<::prost::alloc::string::String>, +pub struct GetFilteredReservationsResponse { + /// The reservations that matched the filter criteria. + #[prost(message, repeated, tag = "1")] + pub reservations: ::prost::alloc::vec::Vec, } -/// A proof request. #[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct RequestedProof { - /// The proof identifier. - #[prost(string, tag = "1")] - pub proof_id: ::prost::alloc::string::String, - /// The mode for proof generation. - #[prost(enumeration = "ProofMode", tag = "2")] - pub mode: i32, - /// Proof requester's address. +pub struct AddReservationRequest { + /// The message format of the body. + #[prost(enumeration = "MessageFormat", tag = "1")] + pub format: i32, + /// The signature of the sender. + #[prost(bytes = "vec", tag = "2")] + pub signature: ::prost::alloc::vec::Vec, + /// The body of the request. + #[prost(message, optional, tag = "3")] + pub body: ::core::option::Option, +} +#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] +pub struct AddReservationRequestBody { + /// The account nonce of the sender. + #[prost(uint64, tag = "1")] + pub nonce: u64, + /// The address of the requester to add reservation for. + #[prost(bytes = "vec", tag = "2")] + pub requester: ::prost::alloc::vec::Vec, + /// The address of the fulfiller to reserve. #[prost(bytes = "vec", tag = "3")] + pub fulfiller: ::prost::alloc::vec::Vec, +} +#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] +pub struct AddReservationResponse { + /// The transaction hash. + #[prost(bytes = "vec", tag = "1")] + pub tx_hash: ::prost::alloc::vec::Vec, + /// The body of the response. + #[prost(message, optional, tag = "2")] + pub body: ::core::option::Option, +} +#[derive(serde::Serialize, serde::Deserialize, Clone, Copy, PartialEq, ::prost::Message)] +pub struct AddReservationResponseBody {} +#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] +pub struct RemoveReservationRequest { + /// The message format of the body. + #[prost(enumeration = "MessageFormat", tag = "1")] + pub format: i32, + /// The signature of the sender. + #[prost(bytes = "vec", tag = "2")] + pub signature: ::prost::alloc::vec::Vec, + /// The body of the request. + #[prost(message, optional, tag = "3")] + pub body: ::core::option::Option, +} +#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] +pub struct RemoveReservationRequestBody { + /// The account nonce of the sender. + #[prost(uint64, tag = "1")] + pub nonce: u64, + /// The address of the requester to remove reservation for. + #[prost(bytes = "vec", tag = "2")] pub requester: ::prost::alloc::vec::Vec, - /// The SP1 circuit version to use for the proof. - #[prost(string, tag = "4")] - pub circuit_version: ::prost::alloc::string::String, } -/// The response for getting proof requests by a given status. #[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct GetProofRequestsResponse { - /// The proof identifiers of the proof requests. Limited to the 10 most recent proof requests with - /// that status. - #[prost(message, repeated, tag = "1")] - pub proofs: ::prost::alloc::vec::Vec, +pub struct RemoveReservationResponse { + /// The transaction hash. + #[prost(bytes = "vec", tag = "1")] + pub tx_hash: ::prost::alloc::vec::Vec, + /// The body of the response. + #[prost(message, optional, tag = "2")] + pub body: ::core::option::Option, } -/// The request to get the status of a relay request. +#[derive(serde::Serialize, serde::Deserialize, Clone, Copy, PartialEq, ::prost::Message)] +pub struct RemoveReservationResponseBody {} #[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct GetRelayStatusRequest { - /// The transaction identifier. - #[prost(string, tag = "1")] - pub tx_id: ::prost::alloc::string::String, +pub struct BidRequest { + /// The message format of the body. + #[prost(enumeration = "MessageFormat", tag = "1")] + pub format: i32, + /// The signature of the sender. + #[prost(bytes = "vec", tag = "2")] + pub signature: ::prost::alloc::vec::Vec, + /// The body of the request. + #[prost(message, optional, tag = "3")] + pub body: ::core::option::Option, +} +#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] +pub struct BidRequestBody { + /// The account nonce of the sender. + #[prost(uint64, tag = "1")] + pub nonce: u64, + /// The request ID to bid on. + #[prost(bytes = "vec", tag = "2")] + pub request_id: ::prost::alloc::vec::Vec, } -/// The response for getting the status of a relay request. #[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] -pub struct GetRelayStatusResponse { - /// The status of the transaction. - #[prost(enumeration = "TransactionStatus", tag = "1")] - pub status: i32, +pub struct BidResponse { /// The transaction hash. + #[prost(bytes = "vec", tag = "1")] + pub tx_hash: ::prost::alloc::vec::Vec, + /// The body of the response. + #[prost(message, optional, tag = "2")] + pub body: ::core::option::Option, +} +#[derive(serde::Serialize, serde::Deserialize, Clone, Copy, PartialEq, ::prost::Message)] +pub struct BidResponseBody {} +#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] +pub struct SettleRequest { + /// The message format of the body. + #[prost(enumeration = "MessageFormat", tag = "1")] + pub format: i32, + /// The signature of the sender. + #[prost(bytes = "vec", tag = "2")] + pub signature: ::prost::alloc::vec::Vec, + /// The body of the request. + #[prost(message, optional, tag = "3")] + pub body: ::core::option::Option, +} +#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] +pub struct SettleRequestBody { + /// The account nonce of the sender. + #[prost(uint64, tag = "1")] + pub nonce: u64, + /// The request ID to settle bids for. #[prost(bytes = "vec", tag = "2")] + pub request_id: ::prost::alloc::vec::Vec, +} +#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] +pub struct SettleResponse { + /// The transaction hash. + #[prost(bytes = "vec", tag = "1")] pub tx_hash: ::prost::alloc::vec::Vec, - /// The transactionsimulation URL, only present if the transaction failed. - #[prost(string, tag = "3")] - pub simulation_url: ::prost::alloc::string::String, + /// The body of the response. + #[prost(message, optional, tag = "2")] + pub body: ::core::option::Option, +} +#[derive(serde::Serialize, serde::Deserialize, Clone, Copy, PartialEq, ::prost::Message)] +pub struct SettleResponseBody {} +/// Format to help decode signature in backend. +#[derive( + serde::Serialize, + serde::Deserialize, + Clone, + Copy, + Debug, + PartialEq, + Eq, + Hash, + PartialOrd, + Ord, + ::prost::Enumeration, +)] +#[repr(i32)] +pub enum MessageFormat { + /// Unspecified message format. + UnspecifiedMessageFormat = 0, + /// The message is in binary format. + Binary = 1, + /// The message is in JSON format. + Json = 2, +} +impl MessageFormat { + /// String value of the enum field names used in the `ProtoBuf` definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the `ProtoBuf` definition does not change) and safe for programmatic use. + #[must_use] pub fn as_str_name(&self) -> &'static str { + match self { + Self::UnspecifiedMessageFormat => "UNSPECIFIED_MESSAGE_FORMAT", + Self::Binary => "BINARY", + Self::Json => "JSON", + } + } + /// Creates an enum from field names used in the `ProtoBuf` definition. + #[must_use] pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "UNSPECIFIED_MESSAGE_FORMAT" => Some(Self::UnspecifiedMessageFormat), + "BINARY" => Some(Self::Binary), + "JSON" => Some(Self::Json), + _ => None, + } + } } -/// The mode used when generating the proof. #[derive( serde::Serialize, serde::Deserialize, @@ -281,44 +1156,43 @@ pub struct GetRelayStatusResponse { )] #[repr(i32)] pub enum ProofMode { - /// Unspecified or invalid proof mode. - Unspecified = 0, - /// The proof mode for an SP1 core proof. + UnspecifiedProofMode = 0, + /// The core proof mode. Core = 1, - /// The proof mode for a compressed proof. + /// The compressed proof mode. Compressed = 2, - /// The proof mode for a PlonK proof. + /// The plonk proof mode. Plonk = 3, - /// The proof mode for a Groth16 proof. + /// The groth16 proof mode. Groth16 = 4, } impl ProofMode { - /// String value of the enum field names used in the ProtoBuf definition. + /// String value of the enum field names used in the `ProtoBuf` definition. /// /// The values are not transformed in any way and thus are considered stable - /// (if the ProtoBuf definition does not change) and safe for programmatic use. - pub fn as_str_name(&self) -> &'static str { + /// (if the `ProtoBuf` definition does not change) and safe for programmatic use. + #[must_use] pub fn as_str_name(&self) -> &'static str { match self { - Self::Unspecified => "PROOF_MODE_UNSPECIFIED", - Self::Core => "PROOF_MODE_CORE", - Self::Compressed => "PROOF_MODE_COMPRESSED", - Self::Plonk => "PROOF_MODE_PLONK", - Self::Groth16 => "PROOF_MODE_GROTH16", + Self::UnspecifiedProofMode => "UNSPECIFIED_PROOF_MODE", + Self::Core => "CORE", + Self::Compressed => "COMPRESSED", + Self::Plonk => "PLONK", + Self::Groth16 => "GROTH16", } } - /// Creates an enum from field names used in the ProtoBuf definition. - pub fn from_str_name(value: &str) -> ::core::option::Option { + /// Creates an enum from field names used in the `ProtoBuf` definition. + #[must_use] pub fn from_str_name(value: &str) -> ::core::option::Option { match value { - "PROOF_MODE_UNSPECIFIED" => Some(Self::Unspecified), - "PROOF_MODE_CORE" => Some(Self::Core), - "PROOF_MODE_COMPRESSED" => Some(Self::Compressed), - "PROOF_MODE_PLONK" => Some(Self::Plonk), - "PROOF_MODE_GROTH16" => Some(Self::Groth16), + "UNSPECIFIED_PROOF_MODE" => Some(Self::UnspecifiedProofMode), + "CORE" => Some(Self::Core), + "COMPRESSED" => Some(Self::Compressed), + "PLONK" => Some(Self::Plonk), + "GROTH16" => Some(Self::Groth16), _ => None, } } } -/// The status of a proof request. +/// The different strategies that can be used for fulfilling requests. #[derive( serde::Serialize, serde::Deserialize, @@ -333,49 +1207,42 @@ impl ProofMode { ::prost::Enumeration, )] #[repr(i32)] -pub enum ProofStatus { - /// Unspecified or invalid status. - ProofUnspecifiedStatus = 0, - /// The proof request has been created but is awaiting the requester to submit it. - ProofPreparing = 1, - /// The proof request has been submitted and is awaiting a prover to claim it. - ProofRequested = 2, - /// The proof request has been claimed and is awaiting a prover to fulfill it. - ProofClaimed = 3, - /// The proof request was previously claimed but has now been unclaimed. - ProofUnclaimed = 4, - /// The proof request has been fulfilled and is available for download. - ProofFulfilled = 5, -} -impl ProofStatus { - /// String value of the enum field names used in the ProtoBuf definition. +pub enum FulfillmentStrategy { + UnspecifiedFulfillmentStrategy = 0, + /// The hosted fulfillment strategy. Uses Succinct's on-demand prover to fulfill requests. + Hosted = 1, + /// The reserved fulfillment strategy. Uses an already existing agreement with a + /// fulfiller to fulfill requests. + Reserved = 2, + /// The auction fulfillment strategy. Uses a decentralized proof contest to + /// fulfill requests. + Auction = 3, +} +impl FulfillmentStrategy { + /// String value of the enum field names used in the `ProtoBuf` definition. /// /// The values are not transformed in any way and thus are considered stable - /// (if the ProtoBuf definition does not change) and safe for programmatic use. - pub fn as_str_name(&self) -> &'static str { + /// (if the `ProtoBuf` definition does not change) and safe for programmatic use. + #[must_use] pub fn as_str_name(&self) -> &'static str { match self { - Self::ProofUnspecifiedStatus => "PROOF_UNSPECIFIED_STATUS", - Self::ProofPreparing => "PROOF_PREPARING", - Self::ProofRequested => "PROOF_REQUESTED", - Self::ProofClaimed => "PROOF_CLAIMED", - Self::ProofUnclaimed => "PROOF_UNCLAIMED", - Self::ProofFulfilled => "PROOF_FULFILLED", + Self::UnspecifiedFulfillmentStrategy => "UNSPECIFIED_FULFILLMENT_STRATEGY", + Self::Hosted => "HOSTED", + Self::Reserved => "RESERVED", + Self::Auction => "AUCTION", } } - /// Creates an enum from field names used in the ProtoBuf definition. - pub fn from_str_name(value: &str) -> ::core::option::Option { + /// Creates an enum from field names used in the `ProtoBuf` definition. + #[must_use] pub fn from_str_name(value: &str) -> ::core::option::Option { match value { - "PROOF_UNSPECIFIED_STATUS" => Some(Self::ProofUnspecifiedStatus), - "PROOF_PREPARING" => Some(Self::ProofPreparing), - "PROOF_REQUESTED" => Some(Self::ProofRequested), - "PROOF_CLAIMED" => Some(Self::ProofClaimed), - "PROOF_UNCLAIMED" => Some(Self::ProofUnclaimed), - "PROOF_FULFILLED" => Some(Self::ProofFulfilled), + "UNSPECIFIED_FULFILLMENT_STRATEGY" => Some(Self::UnspecifiedFulfillmentStrategy), + "HOSTED" => Some(Self::Hosted), + "RESERVED" => Some(Self::Reserved), + "AUCTION" => Some(Self::Auction), _ => None, } } } -/// The status of a relay request transaction. +/// The different fulfillment statuses that a request can be in. #[derive( serde::Serialize, serde::Deserialize, @@ -390,48 +1257,44 @@ impl ProofStatus { ::prost::Enumeration, )] #[repr(i32)] -pub enum TransactionStatus { - /// Unspecified or invalid status. - TransactionUnspecifiedStatus = 0, - /// The transaction has been scheduled for relay. - TransactionScheduled = 1, - /// The transaction has been broadcast to the requested chain. - TransactionBroadcasted = 2, - /// The transaction was never confirmed as mined. - TransactionTimedout = 3, - /// The transaction failed to be broadcast, likely due to a revert in simulation. - TransactionFailed = 4, - /// The transaction was mined successfully. - TransactionFinalized = 5, -} -impl TransactionStatus { - /// String value of the enum field names used in the ProtoBuf definition. +pub enum FulfillmentStatus { + UnspecifiedFulfillmentStatus = 0, + /// The request has been requested. + Requested = 1, + /// The request has been assigned to a fulfiller. + Assigned = 2, + /// The request has been fulfilled. + Fulfilled = 3, + /// The request cannot be fulfilled. + Unfulfillable = 4, +} +impl FulfillmentStatus { + /// String value of the enum field names used in the `ProtoBuf` definition. /// /// The values are not transformed in any way and thus are considered stable - /// (if the ProtoBuf definition does not change) and safe for programmatic use. - pub fn as_str_name(&self) -> &'static str { + /// (if the `ProtoBuf` definition does not change) and safe for programmatic use. + #[must_use] pub fn as_str_name(&self) -> &'static str { match self { - Self::TransactionUnspecifiedStatus => "TRANSACTION_UNSPECIFIED_STATUS", - Self::TransactionScheduled => "TRANSACTION_SCHEDULED", - Self::TransactionBroadcasted => "TRANSACTION_BROADCASTED", - Self::TransactionTimedout => "TRANSACTION_TIMEDOUT", - Self::TransactionFailed => "TRANSACTION_FAILED", - Self::TransactionFinalized => "TRANSACTION_FINALIZED", + Self::UnspecifiedFulfillmentStatus => "UNSPECIFIED_FULFILLMENT_STATUS", + Self::Requested => "REQUESTED", + Self::Assigned => "ASSIGNED", + Self::Fulfilled => "FULFILLED", + Self::Unfulfillable => "UNFULFILLABLE", } } - /// Creates an enum from field names used in the ProtoBuf definition. - pub fn from_str_name(value: &str) -> ::core::option::Option { + /// Creates an enum from field names used in the `ProtoBuf` definition. + #[must_use] pub fn from_str_name(value: &str) -> ::core::option::Option { match value { - "TRANSACTION_UNSPECIFIED_STATUS" => Some(Self::TransactionUnspecifiedStatus), - "TRANSACTION_SCHEDULED" => Some(Self::TransactionScheduled), - "TRANSACTION_BROADCASTED" => Some(Self::TransactionBroadcasted), - "TRANSACTION_TIMEDOUT" => Some(Self::TransactionTimedout), - "TRANSACTION_FAILED" => Some(Self::TransactionFailed), - "TRANSACTION_FINALIZED" => Some(Self::TransactionFinalized), + "UNSPECIFIED_FULFILLMENT_STATUS" => Some(Self::UnspecifiedFulfillmentStatus), + "REQUESTED" => Some(Self::Requested), + "ASSIGNED" => Some(Self::Assigned), + "FULFILLED" => Some(Self::Fulfilled), + "UNFULFILLABLE" => Some(Self::Unfulfillable), _ => None, } } } +/// The different execution statuses that a request can be in. #[derive( serde::Serialize, serde::Deserialize, @@ -446,348 +1309,2624 @@ impl TransactionStatus { ::prost::Enumeration, )] #[repr(i32)] -pub enum UnclaimReason { - /// Unspecified reason. - Unspecified = 0, - /// The prover claims the request is invalid and cannot be fulfilled. - Invalid = 1, - /// The prover is unable to fulfill the proof due to any other reason. - Abandoned = 2, -} -impl UnclaimReason { - /// String value of the enum field names used in the ProtoBuf definition. +pub enum ExecutionStatus { + UnspecifiedExecutionStatus = 0, + /// The request has not been executed. + Unexecuted = 1, + /// The request has been executed. + Executed = 2, + /// The request cannot be executed. + Unexecutable = 3, +} +impl ExecutionStatus { + /// String value of the enum field names used in the `ProtoBuf` definition. /// /// The values are not transformed in any way and thus are considered stable - /// (if the ProtoBuf definition does not change) and safe for programmatic use. - pub fn as_str_name(&self) -> &'static str { + /// (if the `ProtoBuf` definition does not change) and safe for programmatic use. + #[must_use] pub fn as_str_name(&self) -> &'static str { match self { - Self::Unspecified => "UNCLAIM_REASON_UNSPECIFIED", - Self::Invalid => "UNCLAIM_REASON_INVALID", - Self::Abandoned => "UNCLAIM_REASON_ABANDONED", + Self::UnspecifiedExecutionStatus => "UNSPECIFIED_EXECUTION_STATUS", + Self::Unexecuted => "UNEXECUTED", + Self::Executed => "EXECUTED", + Self::Unexecutable => "UNEXECUTABLE", } } - /// Creates an enum from field names used in the ProtoBuf definition. - pub fn from_str_name(value: &str) -> ::core::option::Option { + /// Creates an enum from field names used in the `ProtoBuf` definition. + #[must_use] pub fn from_str_name(value: &str) -> ::core::option::Option { match value { - "UNCLAIM_REASON_UNSPECIFIED" => Some(Self::Unspecified), - "UNCLAIM_REASON_INVALID" => Some(Self::Invalid), - "UNCLAIM_REASON_ABANDONED" => Some(Self::Abandoned), + "UNSPECIFIED_EXECUTION_STATUS" => Some(Self::UnspecifiedExecutionStatus), + "UNEXECUTED" => Some(Self::Unexecuted), + "EXECUTED" => Some(Self::Executed), + "UNEXECUTABLE" => Some(Self::Unexecutable), _ => None, } } } -pub use twirp; -pub const SERVICE_FQN: &str = "/network.NetworkService"; -#[twirp::async_trait::async_trait] -pub trait NetworkService { - async fn create_proof( - &self, - ctx: twirp::Context, - req: CreateProofRequest, - ) -> Result; - async fn submit_proof( - &self, - ctx: twirp::Context, - req: SubmitProofRequest, - ) -> Result; - async fn claim_proof( - &self, - ctx: twirp::Context, - req: ClaimProofRequest, - ) -> Result; - async fn unclaim_proof( - &self, - ctx: twirp::Context, - req: UnclaimProofRequest, - ) -> Result; - async fn modify_cpu_cycles( - &self, - ctx: twirp::Context, - req: ModifyCpuCyclesRequest, - ) -> Result; - async fn fulfill_proof( - &self, - ctx: twirp::Context, - req: FulfillProofRequest, - ) -> Result; - async fn relay_proof( - &self, - ctx: twirp::Context, - req: RelayProofRequest, - ) -> Result; - async fn get_nonce( - &self, - ctx: twirp::Context, - req: GetNonceRequest, - ) -> Result; - async fn get_proof_status( - &self, - ctx: twirp::Context, - req: GetProofStatusRequest, - ) -> Result; - async fn get_proof_requests( - &self, - ctx: twirp::Context, - req: GetProofRequestsRequest, - ) -> Result; - async fn get_relay_status( - &self, - ctx: twirp::Context, - req: GetRelayStatusRequest, - ) -> Result; -} -#[twirp::async_trait::async_trait] -impl NetworkService for std::sync::Arc -where - T: NetworkService + Sync + Send, -{ - async fn create_proof( - &self, - ctx: twirp::Context, - req: CreateProofRequest, - ) -> Result { - T::create_proof(&*self, ctx, req).await - } - async fn submit_proof( - &self, - ctx: twirp::Context, - req: SubmitProofRequest, - ) -> Result { - T::submit_proof(&*self, ctx, req).await - } - async fn claim_proof( - &self, - ctx: twirp::Context, - req: ClaimProofRequest, - ) -> Result { - T::claim_proof(&*self, ctx, req).await - } - async fn unclaim_proof( - &self, - ctx: twirp::Context, - req: UnclaimProofRequest, - ) -> Result { - T::unclaim_proof(&*self, ctx, req).await - } - async fn modify_cpu_cycles( - &self, - ctx: twirp::Context, - req: ModifyCpuCyclesRequest, - ) -> Result { - T::modify_cpu_cycles(&*self, ctx, req).await - } - async fn fulfill_proof( - &self, - ctx: twirp::Context, - req: FulfillProofRequest, - ) -> Result { - T::fulfill_proof(&*self, ctx, req).await - } - async fn relay_proof( - &self, - ctx: twirp::Context, - req: RelayProofRequest, - ) -> Result { - T::relay_proof(&*self, ctx, req).await - } - async fn get_nonce( - &self, - ctx: twirp::Context, - req: GetNonceRequest, - ) -> Result { - T::get_nonce(&*self, ctx, req).await - } - async fn get_proof_status( - &self, - ctx: twirp::Context, - req: GetProofStatusRequest, - ) -> Result { - T::get_proof_status(&*self, ctx, req).await - } - async fn get_proof_requests( - &self, - ctx: twirp::Context, - req: GetProofRequestsRequest, - ) -> Result { - T::get_proof_requests(&*self, ctx, req).await - } - async fn get_relay_status( - &self, - ctx: twirp::Context, - req: GetRelayStatusRequest, - ) -> Result { - T::get_relay_status(&*self, ctx, req).await - } +/// The different types of balance changes that can occur. +#[derive( + serde::Serialize, + serde::Deserialize, + Clone, + Copy, + Debug, + PartialEq, + Eq, + Hash, + PartialOrd, + Ord, + ::prost::Enumeration, +)] +#[repr(i32)] +pub enum BalanceOperation { + UnspecifiedBalanceChangeOperation = 0, + /// A deposit operation (positive). + Deposit = 1, + /// A withdrawal operation (negative). + Withdrawal = 2, + /// A credit operation (positive). + Credit = 3, + /// A deduction operation (negative). + Deduction = 4, + /// A refund operation (positive). + Refund = 5, + /// A bid operation (negative). + Bid = 6, } -pub fn router(api: T) -> twirp::Router -where - T: NetworkService + Clone + Send + Sync + 'static, -{ - twirp::details::TwirpRouterBuilder::new(api) - .route("/CreateProof", |api: T, ctx: twirp::Context, req: CreateProofRequest| async move { - api.create_proof(ctx, req).await - }) - .route("/SubmitProof", |api: T, ctx: twirp::Context, req: SubmitProofRequest| async move { - api.submit_proof(ctx, req).await - }) - .route("/ClaimProof", |api: T, ctx: twirp::Context, req: ClaimProofRequest| async move { - api.claim_proof(ctx, req).await - }) - .route( - "/UnclaimProof", - |api: T, ctx: twirp::Context, req: UnclaimProofRequest| async move { - api.unclaim_proof(ctx, req).await - }, - ) - .route( - "/ModifyCpuCycles", - |api: T, ctx: twirp::Context, req: ModifyCpuCyclesRequest| async move { - api.modify_cpu_cycles(ctx, req).await - }, - ) - .route( - "/FulfillProof", - |api: T, ctx: twirp::Context, req: FulfillProofRequest| async move { - api.fulfill_proof(ctx, req).await - }, - ) - .route("/RelayProof", |api: T, ctx: twirp::Context, req: RelayProofRequest| async move { - api.relay_proof(ctx, req).await - }) - .route("/GetNonce", |api: T, ctx: twirp::Context, req: GetNonceRequest| async move { - api.get_nonce(ctx, req).await - }) - .route( - "/GetProofStatus", - |api: T, ctx: twirp::Context, req: GetProofStatusRequest| async move { - api.get_proof_status(ctx, req).await - }, - ) - .route( - "/GetProofRequests", - |api: T, ctx: twirp::Context, req: GetProofRequestsRequest| async move { - api.get_proof_requests(ctx, req).await - }, - ) - .route( - "/GetRelayStatus", - |api: T, ctx: twirp::Context, req: GetRelayStatusRequest| async move { - api.get_relay_status(ctx, req).await - }, - ) - .build() -} -#[twirp::async_trait::async_trait] -pub trait NetworkServiceClient: Send + Sync + std::fmt::Debug { - async fn create_proof( - &self, - req: CreateProofRequest, - ) -> Result; - async fn submit_proof( - &self, - req: SubmitProofRequest, - ) -> Result; - async fn claim_proof( - &self, - req: ClaimProofRequest, - ) -> Result; - async fn unclaim_proof( - &self, - req: UnclaimProofRequest, - ) -> Result; - async fn modify_cpu_cycles( - &self, - req: ModifyCpuCyclesRequest, - ) -> Result; - async fn fulfill_proof( - &self, - req: FulfillProofRequest, - ) -> Result; - async fn relay_proof( - &self, - req: RelayProofRequest, - ) -> Result; - async fn get_nonce(&self, req: GetNonceRequest) - -> Result; - async fn get_proof_status( - &self, - req: GetProofStatusRequest, - ) -> Result; - async fn get_proof_requests( - &self, - req: GetProofRequestsRequest, - ) -> Result; - async fn get_relay_status( - &self, - req: GetRelayStatusRequest, - ) -> Result; -} -#[twirp::async_trait::async_trait] -impl NetworkServiceClient for twirp::client::Client { - async fn create_proof( - &self, - req: CreateProofRequest, - ) -> Result { - self.request("network.NetworkService/CreateProof", req).await +impl BalanceOperation { + /// String value of the enum field names used in the `ProtoBuf` definition. + /// + /// The values are not transformed in any way and thus are considered stable + /// (if the `ProtoBuf` definition does not change) and safe for programmatic use. + #[must_use] pub fn as_str_name(&self) -> &'static str { + match self { + Self::UnspecifiedBalanceChangeOperation => "UNSPECIFIED_BALANCE_CHANGE_OPERATION", + Self::Deposit => "DEPOSIT", + Self::Withdrawal => "WITHDRAWAL", + Self::Credit => "CREDIT", + Self::Deduction => "DEDUCTION", + Self::Refund => "REFUND", + Self::Bid => "BID", + } } - async fn submit_proof( - &self, - req: SubmitProofRequest, - ) -> Result { - self.request("network.NetworkService/SubmitProof", req).await + /// Creates an enum from field names used in the `ProtoBuf` definition. + #[must_use] pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "UNSPECIFIED_BALANCE_CHANGE_OPERATION" => Some(Self::UnspecifiedBalanceChangeOperation), + "DEPOSIT" => Some(Self::Deposit), + "WITHDRAWAL" => Some(Self::Withdrawal), + "CREDIT" => Some(Self::Credit), + "DEDUCTION" => Some(Self::Deduction), + "REFUND" => Some(Self::Refund), + "BID" => Some(Self::Bid), + _ => None, + } } - async fn claim_proof( - &self, - req: ClaimProofRequest, - ) -> Result { - self.request("network.NetworkService/ClaimProof", req).await +} +/// Generated client implementations. +pub mod prover_network_client { + #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + use tonic::codegen::http::Uri; + use tonic::codegen::{Body, Bytes, CompressionEncoding, GrpcMethod, InterceptedService, StdError, http}; + #[derive(Debug, Clone)] + pub struct ProverNetworkClient { + inner: tonic::client::Grpc, } - async fn unclaim_proof( - &self, - req: UnclaimProofRequest, - ) -> Result { - self.request("network.NetworkService/UnclaimProof", req).await + impl ProverNetworkClient { + /// Attempt to create a new client by connecting to a given endpoint. + pub async fn connect(dst: D) -> Result + where + D: TryInto, + D::Error: Into, + { + let conn = tonic::transport::Endpoint::new(dst)?.connect().await?; + Ok(Self::new(conn)) + } } - async fn modify_cpu_cycles( - &self, - req: ModifyCpuCyclesRequest, - ) -> Result { - self.request("network.NetworkService/ModifyCpuCycles", req).await + impl ProverNetworkClient + where + T: tonic::client::GrpcService, + T::Error: Into, + T::ResponseBody: Body + std::marker::Send + 'static, + ::Error: Into + std::marker::Send, + { + pub fn new(inner: T) -> Self { + let inner = tonic::client::Grpc::new(inner); + Self { inner } + } + pub fn with_origin(inner: T, origin: Uri) -> Self { + let inner = tonic::client::Grpc::with_origin(inner, origin); + Self { inner } + } + pub fn with_interceptor( + inner: T, + interceptor: F, + ) -> ProverNetworkClient> + where + F: tonic::service::Interceptor, + T::ResponseBody: Default, + T: tonic::codegen::Service< + http::Request, + Response = http::Response< + >::ResponseBody, + >, + >, + >>::Error: + Into + std::marker::Send + std::marker::Sync, + { + ProverNetworkClient::new(InterceptedService::new(inner, interceptor)) + } + /// Compress requests with the given encoding. + /// + /// This requires the server to support it otherwise it might respond with an + /// error. + #[must_use] + pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.send_compressed(encoding); + self + } + /// Enable decompressing responses. + #[must_use] + pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.inner = self.inner.accept_compressed(encoding); + self + } + /// Limits the maximum size of a decoded message. + /// + /// Default: `4MB` + #[must_use] + pub fn max_decoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_decoding_message_size(limit); + self + } + /// Limits the maximum size of an encoded message. + /// + /// Default: `usize::MAX` + #[must_use] + pub fn max_encoding_message_size(mut self, limit: usize) -> Self { + self.inner = self.inner.max_encoding_message_size(limit); + self + } + /// Creates a proof request. + pub async fn request_proof( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> + { + self.inner.ready().await.map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static("/network.ProverNetwork/RequestProof"); + let mut req = request.into_request(); + req.extensions_mut().insert(GrpcMethod::new("network.ProverNetwork", "RequestProof")); + self.inner.unary(req, path, codec).await + } + /// Fulfills a proof request. Only callable by the assigned fulfiller. + pub async fn fulfill_proof( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> + { + self.inner.ready().await.map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static("/network.ProverNetwork/FulfillProof"); + let mut req = request.into_request(); + req.extensions_mut().insert(GrpcMethod::new("network.ProverNetwork", "FulfillProof")); + self.inner.unary(req, path, codec).await + } + /// Executes a proof request. Only callable by the execution oracle. + pub async fn execute_proof( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> + { + self.inner.ready().await.map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static("/network.ProverNetwork/ExecuteProof"); + let mut req = request.into_request(); + req.extensions_mut().insert(GrpcMethod::new("network.ProverNetwork", "ExecuteProof")); + self.inner.unary(req, path, codec).await + } + /// Fails fulfillment. Only callable by the assigned fulfiller. + pub async fn fail_fulfillment( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> + { + self.inner.ready().await.map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = + http::uri::PathAndQuery::from_static("/network.ProverNetwork/FailFulfillment"); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("network.ProverNetwork", "FailFulfillment")); + self.inner.unary(req, path, codec).await + } + /// Fails execution. Only callable by the execution oracle. + pub async fn fail_execution( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> + { + self.inner.ready().await.map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static("/network.ProverNetwork/FailExecution"); + let mut req = request.into_request(); + req.extensions_mut().insert(GrpcMethod::new("network.ProverNetwork", "FailExecution")); + self.inner.unary(req, path, codec).await + } + /// Get the status of a proof request. + pub async fn get_proof_request_status( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> + { + self.inner.ready().await.map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/network.ProverNetwork/GetProofRequestStatus", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("network.ProverNetwork", "GetProofRequestStatus")); + self.inner.unary(req, path, codec).await + } + /// Get the details of a proof request. + pub async fn get_proof_request_details( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner.ready().await.map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/network.ProverNetwork/GetProofRequestDetails", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("network.ProverNetwork", "GetProofRequestDetails")); + self.inner.unary(req, path, codec).await + } + /// Get the proof requests that meet the filter criteria. + pub async fn get_filtered_proof_requests( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner.ready().await.map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/network.ProverNetwork/GetFilteredProofRequests", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("network.ProverNetwork", "GetFilteredProofRequests")); + self.inner.unary(req, path, codec).await + } + /// Search for proof requests, programs, and requesters. + pub async fn get_search_results( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> + { + self.inner.ready().await.map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = + http::uri::PathAndQuery::from_static("/network.ProverNetwork/GetSearchResults"); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("network.ProverNetwork", "GetSearchResults")); + self.inner.unary(req, path, codec).await + } + /// Get metrics for proof requests. + pub async fn get_proof_request_metrics( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner.ready().await.map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/network.ProverNetwork/GetProofRequestMetrics", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("network.ProverNetwork", "GetProofRequestMetrics")); + self.inner.unary(req, path, codec).await + } + /// Get time series data for proof requests. + pub async fn get_proof_request_graph( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> + { + self.inner.ready().await.map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = + http::uri::PathAndQuery::from_static("/network.ProverNetwork/GetProofRequestGraph"); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("network.ProverNetwork", "GetProofRequestGraph")); + self.inner.unary(req, path, codec).await + } + /// Get analytics graphs for proof requests. + pub async fn get_analytics_graphs( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> + { + self.inner.ready().await.map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = + http::uri::PathAndQuery::from_static("/network.ProverNetwork/GetAnalyticsGraphs"); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("network.ProverNetwork", "GetAnalyticsGraphs")); + self.inner.unary(req, path, codec).await + } + /// Get the nonce of the account. + pub async fn get_nonce( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> { + self.inner.ready().await.map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static("/network.ProverNetwork/GetNonce"); + let mut req = request.into_request(); + req.extensions_mut().insert(GrpcMethod::new("network.ProverNetwork", "GetNonce")); + self.inner.unary(req, path, codec).await + } + /// Get the delegations of the account. + pub async fn get_filtered_delegations( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner.ready().await.map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/network.ProverNetwork/GetFilteredDelegations", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("network.ProverNetwork", "GetFilteredDelegations")); + self.inner.unary(req, path, codec).await + } + /// Add a delegation. Only callable by the owner of an account. + pub async fn add_delegation( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> + { + self.inner.ready().await.map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static("/network.ProverNetwork/AddDelegation"); + let mut req = request.into_request(); + req.extensions_mut().insert(GrpcMethod::new("network.ProverNetwork", "AddDelegation")); + self.inner.unary(req, path, codec).await + } + /// Remove a delegation. Only callable by the owner of an account. + pub async fn remove_delegation( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> + { + self.inner.ready().await.map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = + http::uri::PathAndQuery::from_static("/network.ProverNetwork/RemoveDelegation"); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("network.ProverNetwork", "RemoveDelegation")); + self.inner.unary(req, path, codec).await + } + /// Accept a delegation. Only callable by the delegate of a delegation. + pub async fn accept_delegation( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> + { + self.inner.ready().await.map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = + http::uri::PathAndQuery::from_static("/network.ProverNetwork/AcceptDelegation"); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("network.ProverNetwork", "AcceptDelegation")); + self.inner.unary(req, path, codec).await + } + /// Set the name of the account. Only callable by the owner of an account. + pub async fn set_account_name( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> + { + self.inner.ready().await.map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = + http::uri::PathAndQuery::from_static("/network.ProverNetwork/SetAccountName"); + let mut req = request.into_request(); + req.extensions_mut().insert(GrpcMethod::new("network.ProverNetwork", "SetAccountName")); + self.inner.unary(req, path, codec).await + } + /// Get the name of the account. + pub async fn get_account_name( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> + { + self.inner.ready().await.map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = + http::uri::PathAndQuery::from_static("/network.ProverNetwork/GetAccountName"); + let mut req = request.into_request(); + req.extensions_mut().insert(GrpcMethod::new("network.ProverNetwork", "GetAccountName")); + self.inner.unary(req, path, codec).await + } + /// Get whether the account has signed the terms. + pub async fn get_terms_signature( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> + { + self.inner.ready().await.map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = + http::uri::PathAndQuery::from_static("/network.ProverNetwork/GetTermsSignature"); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("network.ProverNetwork", "GetTermsSignature")); + self.inner.unary(req, path, codec).await + } + /// Set whether the account has signed the terms. + pub async fn set_terms_signature( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> + { + self.inner.ready().await.map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = + http::uri::PathAndQuery::from_static("/network.ProverNetwork/SetTermsSignature"); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("network.ProverNetwork", "SetTermsSignature")); + self.inner.unary(req, path, codec).await + } + /// Get metadata about a program. + pub async fn get_program( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> + { + self.inner.ready().await.map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static("/network.ProverNetwork/GetProgram"); + let mut req = request.into_request(); + req.extensions_mut().insert(GrpcMethod::new("network.ProverNetwork", "GetProgram")); + self.inner.unary(req, path, codec).await + } + /// Create a new program. Must be called before requesting proofs. + pub async fn create_program( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> + { + self.inner.ready().await.map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static("/network.ProverNetwork/CreateProgram"); + let mut req = request.into_request(); + req.extensions_mut().insert(GrpcMethod::new("network.ProverNetwork", "CreateProgram")); + self.inner.unary(req, path, codec).await + } + /// Set the name of the program. Only callable by the owner. + pub async fn set_program_name( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> + { + self.inner.ready().await.map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = + http::uri::PathAndQuery::from_static("/network.ProverNetwork/SetProgramName"); + let mut req = request.into_request(); + req.extensions_mut().insert(GrpcMethod::new("network.ProverNetwork", "SetProgramName")); + self.inner.unary(req, path, codec).await + } + /// Get the available balance of an account. + pub async fn get_balance( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> + { + self.inner.ready().await.map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static("/network.ProverNetwork/GetBalance"); + let mut req = request.into_request(); + req.extensions_mut().insert(GrpcMethod::new("network.ProverNetwork", "GetBalance")); + self.inner.unary(req, path, codec).await + } + /// Get the balance logs that meet the filter criteria. + pub async fn get_filtered_balance_logs( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner.ready().await.map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/network.ProverNetwork/GetFilteredBalanceLogs", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("network.ProverNetwork", "GetFilteredBalanceLogs")); + self.inner.unary(req, path, codec).await + } + /// Add credit to an account. + pub async fn add_credit( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> { + self.inner.ready().await.map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static("/network.ProverNetwork/AddCredit"); + let mut req = request.into_request(); + req.extensions_mut().insert(GrpcMethod::new("network.ProverNetwork", "AddCredit")); + self.inner.unary(req, path, codec).await + } + /// Get the latest processed block in the bridge. + pub async fn get_latest_bridge_block( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> + { + self.inner.ready().await.map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = + http::uri::PathAndQuery::from_static("/network.ProverNetwork/GetLatestBridgeBlock"); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("network.ProverNetwork", "GetLatestBridgeBlock")); + self.inner.unary(req, path, codec).await + } + /// Get the gas price estimate for a given fulfillment strategy. + pub async fn get_gas_price_estimate( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> + { + self.inner.ready().await.map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = + http::uri::PathAndQuery::from_static("/network.ProverNetwork/GetGasPriceEstimate"); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("network.ProverNetwork", "GetGasPriceEstimate")); + self.inner.unary(req, path, codec).await + } + /// Get the details of a transaction. + pub async fn get_transaction_details( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> + { + self.inner.ready().await.map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/network.ProverNetwork/GetTransactionDetails", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("network.ProverNetwork", "GetTransactionDetails")); + self.inner.unary(req, path, codec).await + } + /// Get the reservations that meet the filter criteria. + pub async fn get_filtered_reservations( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner.ready().await.map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/network.ProverNetwork/GetFilteredReservations", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("network.ProverNetwork", "GetFilteredReservations")); + self.inner.unary(req, path, codec).await + } + /// Add a reservation for a requester. + pub async fn add_reservation( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> + { + self.inner.ready().await.map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = + http::uri::PathAndQuery::from_static("/network.ProverNetwork/AddReservation"); + let mut req = request.into_request(); + req.extensions_mut().insert(GrpcMethod::new("network.ProverNetwork", "AddReservation")); + self.inner.unary(req, path, codec).await + } + /// Remove a reservation for a requester. + pub async fn remove_reservation( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> + { + self.inner.ready().await.map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = + http::uri::PathAndQuery::from_static("/network.ProverNetwork/RemoveReservation"); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("network.ProverNetwork", "RemoveReservation")); + self.inner.unary(req, path, codec).await + } + /// Bid for a proof request. Provers that want to be assigned this request must first + /// bid on it. + pub async fn bid( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> { + self.inner.ready().await.map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static("/network.ProverNetwork/Bid"); + let mut req = request.into_request(); + req.extensions_mut().insert(GrpcMethod::new("network.ProverNetwork", "Bid")); + self.inner.unary(req, path, codec).await + } + /// Settle the bids on a proof request to choose the assigned prover. Only callable by + /// the approved settler. + pub async fn settle( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> { + self.inner.ready().await.map_err(|e| { + tonic::Status::new( + tonic::Code::Unknown, + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic::codec::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static("/network.ProverNetwork/Settle"); + let mut req = request.into_request(); + req.extensions_mut().insert(GrpcMethod::new("network.ProverNetwork", "Settle")); + self.inner.unary(req, path, codec).await + } } - async fn fulfill_proof( - &self, - req: FulfillProofRequest, - ) -> Result { - self.request("network.NetworkService/FulfillProof", req).await +} +/// Generated server implementations. +pub mod prover_network_server { + #![allow(unused_variables, dead_code, missing_docs, clippy::let_unit_value)] + use tonic::codegen::{Arc, Body, BoxFuture, CompressionEncoding, Context, EnabledCompressionEncodings, InterceptedService, Poll, StdError, async_trait, empty_body, http}; + /// Generated trait containing gRPC methods that should be implemented for use with ProverNetworkServer. + #[async_trait] + pub trait ProverNetwork: std::marker::Send + std::marker::Sync + 'static { + /// Creates a proof request. + async fn request_proof( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status>; + /// Fulfills a proof request. Only callable by the assigned fulfiller. + async fn fulfill_proof( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status>; + /// Executes a proof request. Only callable by the execution oracle. + async fn execute_proof( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status>; + /// Fails fulfillment. Only callable by the assigned fulfiller. + async fn fail_fulfillment( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status>; + /// Fails execution. Only callable by the execution oracle. + async fn fail_execution( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status>; + /// Get the status of a proof request. + async fn get_proof_request_status( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status>; + /// Get the details of a proof request. + async fn get_proof_request_details( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; + /// Get the proof requests that meet the filter criteria. + async fn get_filtered_proof_requests( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; + /// Search for proof requests, programs, and requesters. + async fn get_search_results( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status>; + /// Get metrics for proof requests. + async fn get_proof_request_metrics( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; + /// Get time series data for proof requests. + async fn get_proof_request_graph( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status>; + /// Get analytics graphs for proof requests. + async fn get_analytics_graphs( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status>; + /// Get the nonce of the account. + async fn get_nonce( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status>; + /// Get the delegations of the account. + async fn get_filtered_delegations( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; + /// Add a delegation. Only callable by the owner of an account. + async fn add_delegation( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status>; + /// Remove a delegation. Only callable by the owner of an account. + async fn remove_delegation( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status>; + /// Accept a delegation. Only callable by the delegate of a delegation. + async fn accept_delegation( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status>; + /// Set the name of the account. Only callable by the owner of an account. + async fn set_account_name( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status>; + /// Get the name of the account. + async fn get_account_name( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status>; + /// Get whether the account has signed the terms. + async fn get_terms_signature( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status>; + /// Set whether the account has signed the terms. + async fn set_terms_signature( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status>; + /// Get metadata about a program. + async fn get_program( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status>; + /// Create a new program. Must be called before requesting proofs. + async fn create_program( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status>; + /// Set the name of the program. Only callable by the owner. + async fn set_program_name( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status>; + /// Get the available balance of an account. + async fn get_balance( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status>; + /// Get the balance logs that meet the filter criteria. + async fn get_filtered_balance_logs( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; + /// Add credit to an account. + async fn add_credit( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status>; + /// Get the latest processed block in the bridge. + async fn get_latest_bridge_block( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status>; + /// Get the gas price estimate for a given fulfillment strategy. + async fn get_gas_price_estimate( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status>; + /// Get the details of a transaction. + async fn get_transaction_details( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status>; + /// Get the reservations that meet the filter criteria. + async fn get_filtered_reservations( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; + /// Add a reservation for a requester. + async fn add_reservation( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status>; + /// Remove a reservation for a requester. + async fn remove_reservation( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status>; + /// Bid for a proof request. Provers that want to be assigned this request must first + /// bid on it. + async fn bid( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status>; + /// Settle the bids on a proof request to choose the assigned prover. Only callable by + /// the approved settler. + async fn settle( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status>; } - async fn relay_proof( - &self, - req: RelayProofRequest, - ) -> Result { - self.request("network.NetworkService/RelayProof", req).await + #[derive(Debug)] + pub struct ProverNetworkServer { + inner: Arc, + accept_compression_encodings: EnabledCompressionEncodings, + send_compression_encodings: EnabledCompressionEncodings, + max_decoding_message_size: Option, + max_encoding_message_size: Option, } - async fn get_nonce( - &self, - req: GetNonceRequest, - ) -> Result { - self.request("network.NetworkService/GetNonce", req).await + impl ProverNetworkServer { + pub fn new(inner: T) -> Self { + Self::from_arc(Arc::new(inner)) + } + pub fn from_arc(inner: Arc) -> Self { + Self { + inner, + accept_compression_encodings: Default::default(), + send_compression_encodings: Default::default(), + max_decoding_message_size: None, + max_encoding_message_size: None, + } + } + pub fn with_interceptor(inner: T, interceptor: F) -> InterceptedService + where + F: tonic::service::Interceptor, + { + InterceptedService::new(Self::new(inner), interceptor) + } + /// Enable decompressing requests with the given encoding. + #[must_use] + pub fn accept_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.accept_compression_encodings.enable(encoding); + self + } + /// Compress responses with the given encoding, if the client supports it. + #[must_use] + pub fn send_compressed(mut self, encoding: CompressionEncoding) -> Self { + self.send_compression_encodings.enable(encoding); + self + } + /// Limits the maximum size of a decoded message. + /// + /// Default: `4MB` + #[must_use] + pub fn max_decoding_message_size(mut self, limit: usize) -> Self { + self.max_decoding_message_size = Some(limit); + self + } + /// Limits the maximum size of an encoded message. + /// + /// Default: `usize::MAX` + #[must_use] + pub fn max_encoding_message_size(mut self, limit: usize) -> Self { + self.max_encoding_message_size = Some(limit); + self + } } - async fn get_proof_status( - &self, - req: GetProofStatusRequest, - ) -> Result { - self.request("network.NetworkService/GetProofStatus", req).await + impl tonic::codegen::Service> for ProverNetworkServer + where + T: ProverNetwork, + B: Body + std::marker::Send + 'static, + B::Error: Into + std::marker::Send + 'static, + { + type Response = http::Response; + type Error = std::convert::Infallible; + type Future = BoxFuture; + fn poll_ready( + &mut self, + _cx: &mut Context<'_>, + ) -> Poll> { + Poll::Ready(Ok(())) + } + fn call(&mut self, req: http::Request) -> Self::Future { + match req.uri().path() { + "/network.ProverNetwork/RequestProof" => { + #[allow(non_camel_case_types)] + struct RequestProofSvc(pub Arc); + impl tonic::server::UnaryService + for RequestProofSvc + { + type Response = super::RequestProofResponse; + type Future = BoxFuture, tonic::Status>; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::request_proof(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = RequestProofSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/network.ProverNetwork/FulfillProof" => { + #[allow(non_camel_case_types)] + struct FulfillProofSvc(pub Arc); + impl tonic::server::UnaryService + for FulfillProofSvc + { + type Response = super::FulfillProofResponse; + type Future = BoxFuture, tonic::Status>; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::fulfill_proof(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = FulfillProofSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/network.ProverNetwork/ExecuteProof" => { + #[allow(non_camel_case_types)] + struct ExecuteProofSvc(pub Arc); + impl tonic::server::UnaryService + for ExecuteProofSvc + { + type Response = super::ExecuteProofResponse; + type Future = BoxFuture, tonic::Status>; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::execute_proof(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = ExecuteProofSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/network.ProverNetwork/FailFulfillment" => { + #[allow(non_camel_case_types)] + struct FailFulfillmentSvc(pub Arc); + impl + tonic::server::UnaryService + for FailFulfillmentSvc + { + type Response = super::FailFulfillmentResponse; + type Future = BoxFuture, tonic::Status>; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::fail_fulfillment(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = FailFulfillmentSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/network.ProverNetwork/FailExecution" => { + #[allow(non_camel_case_types)] + struct FailExecutionSvc(pub Arc); + impl tonic::server::UnaryService + for FailExecutionSvc + { + type Response = super::FailExecutionResponse; + type Future = BoxFuture, tonic::Status>; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::fail_execution(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = FailExecutionSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/network.ProverNetwork/GetProofRequestStatus" => { + #[allow(non_camel_case_types)] + struct GetProofRequestStatusSvc(pub Arc); + impl + tonic::server::UnaryService + for GetProofRequestStatusSvc + { + type Response = super::GetProofRequestStatusResponse; + type Future = BoxFuture, tonic::Status>; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::get_proof_request_status(&inner, request) + .await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = GetProofRequestStatusSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/network.ProverNetwork/GetProofRequestDetails" => { + #[allow(non_camel_case_types)] + struct GetProofRequestDetailsSvc(pub Arc); + impl + tonic::server::UnaryService + for GetProofRequestDetailsSvc + { + type Response = super::GetProofRequestDetailsResponse; + type Future = BoxFuture, tonic::Status>; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::get_proof_request_details(&inner, request) + .await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = GetProofRequestDetailsSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/network.ProverNetwork/GetFilteredProofRequests" => { + #[allow(non_camel_case_types)] + struct GetFilteredProofRequestsSvc(pub Arc); + impl + tonic::server::UnaryService + for GetFilteredProofRequestsSvc + { + type Response = super::GetFilteredProofRequestsResponse; + type Future = BoxFuture, tonic::Status>; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::get_filtered_proof_requests(&inner, request) + .await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = GetFilteredProofRequestsSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/network.ProverNetwork/GetSearchResults" => { + #[allow(non_camel_case_types)] + struct GetSearchResultsSvc(pub Arc); + impl + tonic::server::UnaryService + for GetSearchResultsSvc + { + type Response = super::GetSearchResultsResponse; + type Future = BoxFuture, tonic::Status>; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::get_search_results(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = GetSearchResultsSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/network.ProverNetwork/GetProofRequestMetrics" => { + #[allow(non_camel_case_types)] + struct GetProofRequestMetricsSvc(pub Arc); + impl + tonic::server::UnaryService + for GetProofRequestMetricsSvc + { + type Response = super::GetProofRequestMetricsResponse; + type Future = BoxFuture, tonic::Status>; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::get_proof_request_metrics(&inner, request) + .await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = GetProofRequestMetricsSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/network.ProverNetwork/GetProofRequestGraph" => { + #[allow(non_camel_case_types)] + struct GetProofRequestGraphSvc(pub Arc); + impl + tonic::server::UnaryService + for GetProofRequestGraphSvc + { + type Response = super::GetProofRequestGraphResponse; + type Future = BoxFuture, tonic::Status>; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::get_proof_request_graph(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = GetProofRequestGraphSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/network.ProverNetwork/GetAnalyticsGraphs" => { + #[allow(non_camel_case_types)] + struct GetAnalyticsGraphsSvc(pub Arc); + impl + tonic::server::UnaryService + for GetAnalyticsGraphsSvc + { + type Response = super::GetAnalyticsGraphsResponse; + type Future = BoxFuture, tonic::Status>; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::get_analytics_graphs(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = GetAnalyticsGraphsSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/network.ProverNetwork/GetNonce" => { + #[allow(non_camel_case_types)] + struct GetNonceSvc(pub Arc); + impl tonic::server::UnaryService for GetNonceSvc { + type Response = super::GetNonceResponse; + type Future = BoxFuture, tonic::Status>; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::get_nonce(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = GetNonceSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/network.ProverNetwork/GetFilteredDelegations" => { + #[allow(non_camel_case_types)] + struct GetFilteredDelegationsSvc(pub Arc); + impl + tonic::server::UnaryService + for GetFilteredDelegationsSvc + { + type Response = super::GetFilteredDelegationsResponse; + type Future = BoxFuture, tonic::Status>; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::get_filtered_delegations(&inner, request) + .await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = GetFilteredDelegationsSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/network.ProverNetwork/AddDelegation" => { + #[allow(non_camel_case_types)] + struct AddDelegationSvc(pub Arc); + impl tonic::server::UnaryService + for AddDelegationSvc + { + type Response = super::AddDelegationResponse; + type Future = BoxFuture, tonic::Status>; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::add_delegation(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = AddDelegationSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/network.ProverNetwork/RemoveDelegation" => { + #[allow(non_camel_case_types)] + struct RemoveDelegationSvc(pub Arc); + impl + tonic::server::UnaryService + for RemoveDelegationSvc + { + type Response = super::RemoveDelegationResponse; + type Future = BoxFuture, tonic::Status>; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::remove_delegation(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = RemoveDelegationSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/network.ProverNetwork/AcceptDelegation" => { + #[allow(non_camel_case_types)] + struct AcceptDelegationSvc(pub Arc); + impl + tonic::server::UnaryService + for AcceptDelegationSvc + { + type Response = super::AcceptDelegationResponse; + type Future = BoxFuture, tonic::Status>; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::accept_delegation(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = AcceptDelegationSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/network.ProverNetwork/SetAccountName" => { + #[allow(non_camel_case_types)] + struct SetAccountNameSvc(pub Arc); + impl tonic::server::UnaryService + for SetAccountNameSvc + { + type Response = super::SetAccountNameResponse; + type Future = BoxFuture, tonic::Status>; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::set_account_name(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = SetAccountNameSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/network.ProverNetwork/GetAccountName" => { + #[allow(non_camel_case_types)] + struct GetAccountNameSvc(pub Arc); + impl tonic::server::UnaryService + for GetAccountNameSvc + { + type Response = super::GetAccountNameResponse; + type Future = BoxFuture, tonic::Status>; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::get_account_name(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = GetAccountNameSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/network.ProverNetwork/GetTermsSignature" => { + #[allow(non_camel_case_types)] + struct GetTermsSignatureSvc(pub Arc); + impl + tonic::server::UnaryService + for GetTermsSignatureSvc + { + type Response = super::GetTermsSignatureResponse; + type Future = BoxFuture, tonic::Status>; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::get_terms_signature(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = GetTermsSignatureSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/network.ProverNetwork/SetTermsSignature" => { + #[allow(non_camel_case_types)] + struct SetTermsSignatureSvc(pub Arc); + impl + tonic::server::UnaryService + for SetTermsSignatureSvc + { + type Response = super::SetTermsSignatureResponse; + type Future = BoxFuture, tonic::Status>; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::set_terms_signature(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = SetTermsSignatureSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/network.ProverNetwork/GetProgram" => { + #[allow(non_camel_case_types)] + struct GetProgramSvc(pub Arc); + impl tonic::server::UnaryService for GetProgramSvc { + type Response = super::GetProgramResponse; + type Future = BoxFuture, tonic::Status>; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::get_program(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = GetProgramSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/network.ProverNetwork/CreateProgram" => { + #[allow(non_camel_case_types)] + struct CreateProgramSvc(pub Arc); + impl tonic::server::UnaryService + for CreateProgramSvc + { + type Response = super::CreateProgramResponse; + type Future = BoxFuture, tonic::Status>; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::create_program(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = CreateProgramSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/network.ProverNetwork/SetProgramName" => { + #[allow(non_camel_case_types)] + struct SetProgramNameSvc(pub Arc); + impl tonic::server::UnaryService + for SetProgramNameSvc + { + type Response = super::SetProgramNameResponse; + type Future = BoxFuture, tonic::Status>; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::set_program_name(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = SetProgramNameSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/network.ProverNetwork/GetBalance" => { + #[allow(non_camel_case_types)] + struct GetBalanceSvc(pub Arc); + impl tonic::server::UnaryService for GetBalanceSvc { + type Response = super::GetBalanceResponse; + type Future = BoxFuture, tonic::Status>; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::get_balance(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = GetBalanceSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/network.ProverNetwork/GetFilteredBalanceLogs" => { + #[allow(non_camel_case_types)] + struct GetFilteredBalanceLogsSvc(pub Arc); + impl + tonic::server::UnaryService + for GetFilteredBalanceLogsSvc + { + type Response = super::GetFilteredBalanceLogsResponse; + type Future = BoxFuture, tonic::Status>; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::get_filtered_balance_logs(&inner, request) + .await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = GetFilteredBalanceLogsSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/network.ProverNetwork/AddCredit" => { + #[allow(non_camel_case_types)] + struct AddCreditSvc(pub Arc); + impl tonic::server::UnaryService for AddCreditSvc { + type Response = super::AddCreditResponse; + type Future = BoxFuture, tonic::Status>; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::add_credit(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = AddCreditSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/network.ProverNetwork/GetLatestBridgeBlock" => { + #[allow(non_camel_case_types)] + struct GetLatestBridgeBlockSvc(pub Arc); + impl + tonic::server::UnaryService + for GetLatestBridgeBlockSvc + { + type Response = super::GetLatestBridgeBlockResponse; + type Future = BoxFuture, tonic::Status>; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::get_latest_bridge_block(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = GetLatestBridgeBlockSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/network.ProverNetwork/GetGasPriceEstimate" => { + #[allow(non_camel_case_types)] + struct GetGasPriceEstimateSvc(pub Arc); + impl + tonic::server::UnaryService + for GetGasPriceEstimateSvc + { + type Response = super::GetGasPriceEstimateResponse; + type Future = BoxFuture, tonic::Status>; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::get_gas_price_estimate(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = GetGasPriceEstimateSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/network.ProverNetwork/GetTransactionDetails" => { + #[allow(non_camel_case_types)] + struct GetTransactionDetailsSvc(pub Arc); + impl + tonic::server::UnaryService + for GetTransactionDetailsSvc + { + type Response = super::GetTransactionDetailsResponse; + type Future = BoxFuture, tonic::Status>; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::get_transaction_details(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = GetTransactionDetailsSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/network.ProverNetwork/GetFilteredReservations" => { + #[allow(non_camel_case_types)] + struct GetFilteredReservationsSvc(pub Arc); + impl + tonic::server::UnaryService + for GetFilteredReservationsSvc + { + type Response = super::GetFilteredReservationsResponse; + type Future = BoxFuture, tonic::Status>; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::get_filtered_reservations(&inner, request) + .await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = GetFilteredReservationsSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/network.ProverNetwork/AddReservation" => { + #[allow(non_camel_case_types)] + struct AddReservationSvc(pub Arc); + impl tonic::server::UnaryService + for AddReservationSvc + { + type Response = super::AddReservationResponse; + type Future = BoxFuture, tonic::Status>; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::add_reservation(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = AddReservationSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/network.ProverNetwork/RemoveReservation" => { + #[allow(non_camel_case_types)] + struct RemoveReservationSvc(pub Arc); + impl + tonic::server::UnaryService + for RemoveReservationSvc + { + type Response = super::RemoveReservationResponse; + type Future = BoxFuture, tonic::Status>; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::remove_reservation(&inner, request).await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = RemoveReservationSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/network.ProverNetwork/Bid" => { + #[allow(non_camel_case_types)] + struct BidSvc(pub Arc); + impl tonic::server::UnaryService for BidSvc { + type Response = super::BidResponse; + type Future = BoxFuture, tonic::Status>; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = + async move { ::bid(&inner, request).await }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = BidSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/network.ProverNetwork/Settle" => { + #[allow(non_camel_case_types)] + struct SettleSvc(pub Arc); + impl tonic::server::UnaryService for SettleSvc { + type Response = super::SettleResponse; + type Future = BoxFuture, tonic::Status>; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = + async move { ::settle(&inner, request).await }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = SettleSvc(inner); + let codec = tonic::codec::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + _ => Box::pin(async move { + Ok(http::Response::builder() + .status(200) + .header("grpc-status", tonic::Code::Unimplemented as i32) + .header(http::header::CONTENT_TYPE, tonic::metadata::GRPC_CONTENT_TYPE) + .body(empty_body()) + .unwrap()) + }), + } + } } - async fn get_proof_requests( - &self, - req: GetProofRequestsRequest, - ) -> Result { - self.request("network.NetworkService/GetProofRequests", req).await + impl Clone for ProverNetworkServer { + fn clone(&self) -> Self { + let inner = self.inner.clone(); + Self { + inner, + accept_compression_encodings: self.accept_compression_encodings, + send_compression_encodings: self.send_compression_encodings, + max_decoding_message_size: self.max_decoding_message_size, + max_encoding_message_size: self.max_encoding_message_size, + } + } } - async fn get_relay_status( - &self, - req: GetRelayStatusRequest, - ) -> Result { - self.request("network.NetworkService/GetRelayStatus", req).await + /// Generated gRPC service name + pub const SERVICE_NAME: &str = "network.ProverNetwork"; + impl tonic::server::NamedService for ProverNetworkServer { + const NAME: &'static str = SERVICE_NAME; } } diff --git a/crates/sdk/src/network/prove.rs b/crates/sdk/src/network/prove.rs new file mode 100644 index 0000000000..2d33ea628a --- /dev/null +++ b/crates/sdk/src/network/prove.rs @@ -0,0 +1,301 @@ +//! # Network Prove +//! +//! This module provides a builder for creating a proof request to the network. + +use std::time::Duration; + +use anyhow::Result; +use sp1_core_machine::io::SP1Stdin; +use sp1_prover::SP1ProvingKey; + +use crate::{ + utils::block_on, utils::sp1_dump, NetworkProver, SP1ProofMode, SP1ProofWithPublicValues, +}; + +use super::proto::network::FulfillmentStrategy; + +/// A builder for creating a proof request to the network. +pub struct NetworkProveBuilder<'a> { + pub(crate) prover: &'a NetworkProver, + pub(crate) mode: SP1ProofMode, + pub(crate) pk: &'a SP1ProvingKey, + pub(crate) stdin: SP1Stdin, + pub(crate) timeout: Option, + pub(crate) strategy: FulfillmentStrategy, + pub(crate) skip_simulation: bool, +} + +impl<'a> NetworkProveBuilder<'a> { + /// Set the proof kind to [`SP1ProofMode::Core`] mode. + /// + /// # Details + /// This is the default mode for the prover. The proofs grow linearly in size with the number + /// of cycles. + /// + /// # Example + /// ```rust,no_run + /// use sp1_sdk::{ProverClient, SP1Stdin, Prover}; + /// + /// let elf = &[1, 2, 3]; + /// let stdin = SP1Stdin::new(); + /// + /// let client = ProverClient::builder().network().build(); + /// let (pk, vk) = client.setup(elf); + /// let builder = client.prove(&pk, &stdin) + /// .core() + /// .run(); + /// ``` + #[must_use] + pub fn core(mut self) -> Self { + self.mode = SP1ProofMode::Core; + self + } + + /// Set the proof kind to [`SP1ProofMode::Compressed`] mode. + /// + /// # Details + /// This mode produces a proof that is of constant size, regardless of the number of cycles. It + /// takes longer to prove than [`SP1ProofMode::Core`] due to the need to recursively aggregate + /// proofs into a single proof. + /// + /// # Example + /// ```rust,no_run + /// use sp1_sdk::{ProverClient, SP1Stdin, Prover}; + /// + /// let elf = &[1, 2, 3]; + /// let stdin = SP1Stdin::new(); + /// + /// let client = ProverClient::builder().network().build(); + /// let (pk, vk) = client.setup(elf); + /// let builder = client.prove(&pk, &stdin) + /// .compressed() + /// .run(); + /// ``` + #[must_use] + pub fn compressed(mut self) -> Self { + self.mode = SP1ProofMode::Compressed; + self + } + + /// Set the proof mode to [`SP1ProofMode::Plonk`] mode. + /// + /// # Details + /// This mode produces a const size PLONK proof that can be verified on chain for roughly ~300k + /// gas. This mode is useful for producing a maximally small proof that can be verified on + /// chain. For more efficient SNARK wrapping, you can use the [`SP1ProofMode::Groth16`] mode but + /// this mode is more . + /// + /// # Example + /// ```rust,no_run + /// use sp1_sdk::{ProverClient, SP1Stdin, Prover}; + /// + /// let elf = &[1, 2, 3]; + /// let stdin = SP1Stdin::new(); + /// + /// let client = ProverClient::builder().network().build(); + /// let (pk, vk) = client.setup(elf); + /// let builder = client.prove(&pk, &stdin) + /// .plonk() + /// .run(); + /// ``` + #[must_use] + pub fn plonk(mut self) -> Self { + self.mode = SP1ProofMode::Plonk; + self + } + + /// Set the proof mode to [`SP1ProofMode::Groth16`] mode. + /// + /// # Details + /// This mode produces a Groth16 proof that can be verified on chain for roughly ~100k gas. This + /// mode is useful for producing a proof that can be verified on chain with minimal gas. + /// + /// # Example + /// ```rust,no_run + /// use sp1_sdk::{ProverClient, SP1Stdin, Prover}; + /// + /// let elf = &[1, 2, 3]; + /// let stdin = SP1Stdin::new(); + /// + /// let client = ProverClient::builder().network().build(); + /// let (pk, vk) = client.setup(elf); + /// let builder = client.prove(&pk, &stdin) + /// .groth16() + /// .run(); + /// ``` + #[must_use] + pub fn groth16(mut self) -> Self { + self.mode = SP1ProofMode::Groth16; + self + } + + /// Set the proof mode to the given [`SP1ProofMode`]. + /// + /// # Details + /// This method is useful for setting the proof mode to a custom mode. + /// + /// # Example + /// ```rust,no_run + /// use sp1_sdk::{ProverClient, SP1Stdin, Prover, SP1ProofMode}; + /// + /// let elf = &[1, 2, 3]; + /// let stdin = SP1Stdin::new(); + /// + /// let client = ProverClient::builder().network().build(); + /// let (pk, vk) = client.setup(elf); + /// let builder = client.prove(&pk, &stdin) + /// .mode(SP1ProofMode::Groth16) + /// .run(); + /// ``` + #[must_use] + pub fn mode(mut self, mode: SP1ProofMode) -> Self { + self.mode = mode; + self + } + + /// Set the timeout for the proof's generation. + /// + /// # Details + /// This method sets the timeout for the proof's generation. If the proof is not generated + /// within the timeout, the [`NetworkProveBuilder::run`] will return an error. + /// + /// # Example + /// ```rust,no_run + /// use sp1_sdk::{ProverClient, SP1Stdin, Prover}; + /// use std::time::Duration; + /// + /// let elf = &[1, 2, 3]; + /// let stdin = SP1Stdin::new(); + /// + /// let client = ProverClient::builder().network().build(); + /// let (pk, vk) = client.setup(elf); + /// let builder = client.prove(&pk, &stdin) + /// .timeout(Duration::from_secs(60)) + /// .run(); + /// ``` + #[must_use] + pub fn timeout(mut self, timeout: Duration) -> Self { + self.timeout = Some(timeout); + self + } + + /// Set whether to skip the local execution simulation step. + /// + /// # Details + /// This method sets whether to skip the local execution simulation step. If the simulation + /// step is skipped, the request will sent to the network without verifying that the execution + /// succeeds locally (without generating a proof). This feature is recommended for users who + /// want to optimize the latency of the proof generation on the network. + /// + /// # Example + /// ```rust,no_run + /// use sp1_sdk::{ProverClient, SP1Stdin, Prover}; + /// + /// let elf = &[1, 2, 3]; + /// let stdin = SP1Stdin::new(); + /// + /// let client = ProverClient::builder().network().build(); + /// let (pk, vk) = client.setup(elf); + /// let builder = client.prove(&pk, &stdin) + /// .skip_simulation(true) + /// .run(); + /// ``` + #[must_use] + pub fn skip_simulation(mut self, skip_simulation: bool) -> Self { + self.skip_simulation = skip_simulation; + self + } + + /// Sets the fulfillment strategy for the client. + /// + /// # Details + /// The strategy determines how the client will fulfill requests. + /// + /// # Example + /// ```rust,no_run + /// use sp1_sdk::{ProverClient, SP1Stdin, Prover, network::FulfillmentStrategy}; + /// + /// let elf = &[1, 2, 3]; + /// let stdin = SP1Stdin::new(); + /// + /// let client = ProverClient::builder().network().build(); + /// let (pk, vk) = client.setup(elf); + /// let proof = client.prove(&pk, &stdin) + /// .strategy(FulfillmentStrategy::Hosted) + /// .run() + /// .unwrap(); + /// ``` + #[must_use] + pub fn strategy(mut self, strategy: FulfillmentStrategy) -> Self { + self.strategy = strategy; + self + } + + /// Run the prover with the built arguments. + /// + /// # Details + /// This method will run the prover with the built arguments. If the prover fails to run, the + /// method will return an error. + /// + /// # Example + /// ```rust,no_run + /// use sp1_sdk::{ProverClient, SP1Stdin, Prover}; + /// + /// let elf = &[1, 2, 3]; + /// let stdin = SP1Stdin::new(); + /// + /// let client = ProverClient::builder().network().build(); + /// let (pk, vk) = client.setup(elf); + /// let proof = client.prove(&pk, &stdin) + /// .run() + /// .unwrap(); + /// ``` + pub fn run(self) -> Result { + let Self { prover, mode, pk, stdin, timeout, strategy, mut skip_simulation } = self; + + // Check for deprecated environment variable + if let Ok(val) = std::env::var("SKIP_SIMULATION") { + eprintln!( + "Warning: SKIP_SIMULATION environment variable is deprecated. Please use .skip_simulation() instead." + ); + skip_simulation = matches!(val.to_lowercase().as_str(), "true" | "1"); + } + + sp1_dump(&pk.elf, &stdin); + + block_on(prover.prove_impl(pk, &stdin, mode, strategy, timeout, skip_simulation)) + } + + /// Run the prover with the built arguments asynchronously. + /// + /// # Details + /// This method will run the prover with the built arguments asynchronously. + /// + /// # Example + /// ```rust,no_run + /// use sp1_sdk::{ProverClient, SP1Stdin, Prover}; + /// + /// let elf = &[1, 2, 3]; + /// let stdin = SP1Stdin::new(); + /// + /// let client = ProverClient::builder().network().build(); + /// let (pk, vk) = client.setup(elf); + /// let proof = client.prove(&pk, &stdin) + /// .run_async(); + /// ``` + pub async fn run_async(self) -> Result { + let Self { prover, mode, pk, stdin, timeout, strategy, mut skip_simulation } = self; + + // Check for deprecated environment variable + if let Ok(val) = std::env::var("SKIP_SIMULATION") { + eprintln!( + "Warning: SKIP_SIMULATION environment variable is deprecated. Please use .skip_simulation() instead." + ); + skip_simulation = matches!(val.to_lowercase().as_str(), "true" | "1"); + } + + sp1_dump(&pk.elf, &stdin); + + prover.prove_impl(pk, &stdin, mode, strategy, timeout, skip_simulation).await + } +} diff --git a/crates/sdk/src/network/prover.rs b/crates/sdk/src/network/prover.rs index 70969adf5b..4927acca35 100644 --- a/crates/sdk/src/network/prover.rs +++ b/crates/sdk/src/network/prover.rs @@ -1,211 +1,385 @@ +//! # Network Prover +//! +//! This module provides an implementation of the [`crate::Prover`] trait that can generate proofs +//! on a remote RPC server. + use std::time::{Duration, Instant}; +use super::prove::NetworkProveBuilder; +use super::DEFAULT_CYCLE_LIMIT; +use crate::cpu::execute::CpuExecuteBuilder; +use crate::cpu::CpuProver; +use crate::network::{DEFAULT_PROVER_NETWORK_RPC, DEFAULT_TIMEOUT_SECS}; use crate::{ - network::{ - client::NetworkClient, - proto::network::{ProofMode, ProofStatus}, - }, - NetworkProverBuilder, Prover, SP1Context, SP1ProofKind, SP1ProofWithPublicValues, - SP1ProvingKey, SP1VerifyingKey, + network::client::NetworkClient, + network::proto::network::{ExecutionStatus, FulfillmentStatus, FulfillmentStrategy, ProofMode}, + Prover, SP1ProofMode, SP1ProofWithPublicValues, SP1ProvingKey, SP1VerifyingKey, }; use anyhow::Result; +use backoff::{future::retry, Error as BackoffError, ExponentialBackoff}; +use serde::de::DeserializeOwned; +use sp1_core_executor::{SP1Context, SP1ContextBuilder}; use sp1_core_machine::io::SP1Stdin; -use sp1_prover::{components::DefaultProverComponents, SP1Prover, SP1_CIRCUIT_VERSION}; -use sp1_stark::SP1ProverOpts; - -use super::proto::network::GetProofStatusResponse; - -use {crate::block_on, tokio::time::sleep}; +use sp1_prover::{components::CpuProverComponents, SP1Prover, SP1_CIRCUIT_VERSION}; +use tonic::Code; -use crate::provers::{CpuProver, ProofOpts, ProverType}; +use {crate::utils::block_on, tokio::time::sleep}; -/// Number of consecutive errors to tolerate before returning an error while polling proof status. -const MAX_CONSECUTIVE_ERRORS: usize = 10; - -/// An implementation of [crate::ProverClient] that can generate proofs on a remote RPC server. +/// An implementation of [`crate::ProverClient`] that can generate proofs on a remote RPC server. pub struct NetworkProver { - client: NetworkClient, - local_prover: CpuProver, - skip_simulation: bool, + pub(crate) client: NetworkClient, + pub(crate) prover: CpuProver, } impl NetworkProver { - /// Creates a new [NetworkProver] with the given private key. - pub fn new(private_key: &str, rpc_url: Option, skip_simulation: bool) -> Self { - let version = SP1_CIRCUIT_VERSION; - log::info!("Client circuit version: {}", version); + /// Creates a new [`NetworkProver`] with the given private key. + /// + /// # Details + /// * `private_key`: The Secp256k1 private key to use for signing requests. + /// * `rpc_url`: The rpc url to use for the prover network. + /// + /// # Example + /// ```rust,no_run + /// use sp1_sdk::NetworkProver; + /// + /// let prover = NetworkProver::new("...", "..."); + /// ``` + #[must_use] + pub fn new(private_key: &str, rpc_url: &str) -> Self { + let prover = CpuProver::new(); + let client = NetworkClient::new(private_key, rpc_url); + Self { client, prover } + } - let local_prover = CpuProver::new(); - Self { client: NetworkClient::new(private_key, rpc_url), local_prover, skip_simulation } + /// Creates a new [`CpuExecuteBuilder`] for simulating the execution of a program on the CPU. + /// + /// # Details + /// Note that this does not use the network in any capacity. The method is provided for + /// convenience. + /// + /// # Example + /// ```rust,no_run + /// use sp1_sdk::{ProverClient, SP1Stdin, Prover}; + /// + /// let elf = &[1, 2, 3]; + /// let stdin = SP1Stdin::new(); + /// + /// let client = ProverClient::builder().cpu().build(); + /// let (public_values, execution_report) = client.execute(elf, &stdin) + /// .run() + /// .unwrap(); + /// ``` + pub fn execute<'a>(&'a self, elf: &'a [u8], stdin: &SP1Stdin) -> CpuExecuteBuilder<'a> { + CpuExecuteBuilder { + prover: self.prover.inner(), + elf, + stdin: stdin.clone(), + context_builder: SP1ContextBuilder::default(), + } } - /// Creates a new network prover builder. See [`NetworkProverBuilder`] for more details. - pub fn builder() -> NetworkProverBuilder { - NetworkProverBuilder::default() + /// A request to generate a proof for a given proving key and input. + /// + /// # Details + /// * `pk`: The proving key to use for the proof. + /// * `stdin`: The input to use for the proof. + /// + /// # Example + /// ```rust,no_run + /// use sp1_sdk::{ProverClient, SP1Stdin, Prover}; + /// + /// let elf = &[1, 2, 3]; + /// let stdin = SP1Stdin::new(); + /// + /// let client = ProverClient::builder().network().build(); + /// let (pk, vk) = client.setup(elf); + /// let proof = client.prove(&pk, &stdin).run(); + /// ``` + pub fn prove<'a>( + &'a self, + pk: &'a SP1ProvingKey, + stdin: &'a SP1Stdin, + ) -> NetworkProveBuilder<'a> { + NetworkProveBuilder { + prover: self, + mode: SP1ProofMode::Core, + pk, + stdin: stdin.clone(), + timeout: None, + strategy: FulfillmentStrategy::Hosted, + skip_simulation: false, + } } - /// Requests a proof from the prover network, returning the proof ID. - pub async fn request_proof( + /// Registers a program if it is not already registered. + /// + /// # Details + /// * `vk`: The verifying key to use for the program. + /// * `elf`: The elf to use for the program. + /// + /// Note that this method requires that the user honestly registers the program (i.e., the elf + /// matches the vk). + /// + /// # Example + /// ```rust,no_run + /// use sp1_sdk::{ProverClient, SP1Stdin, Prover}; + /// + /// let elf = &[1, 2, 3]; + /// let client = ProverClient::builder().network().build(); + /// let (pk, vk) = client.setup(elf); + /// + /// let vk_hash = client.register_program(&vk, elf); + /// ``` + pub async fn register_program(&self, vk: &SP1VerifyingKey, elf: &[u8]) -> Result> { + self.client.register_program(vk, elf).await + } + + /// Requests a proof from the prover network, returning the request ID. + pub(crate) async fn request_proof( &self, - elf: &[u8], - stdin: SP1Stdin, + vk_hash: &[u8], + stdin: &SP1Stdin, mode: ProofMode, - ) -> Result { - let client = &self.client; + strategy: FulfillmentStrategy, + cycle_limit: u64, + timeout: Option, + ) -> Result> { + // Get the timeout. + let timeout_secs = timeout.map_or(DEFAULT_TIMEOUT_SECS, |dur| dur.as_secs()); - if !self.skip_simulation { - let (_, report) = - self.local_prover.sp1_prover().execute(elf, &stdin, Default::default())?; - log::info!("Simulation complete, cycles: {}", report.total_instruction_count()); - } else { - log::info!("Skipping simulation"); - } + // Log the request. + log::info!("Requesting proof:"); + log::info!("├─ Cycle limit: {}", cycle_limit); + log::info!("├─ Proof mode: {:?}", mode); + log::info!("├─ Strategy: {:?}", strategy); + log::info!("├─ Timeout: {} seconds", timeout_secs); + log::info!("└─ Circuit version: {}", SP1_CIRCUIT_VERSION); + + // Request the proof with retries. + let response = with_retry( + || async { + self.client + .request_proof( + vk_hash, + stdin, + mode, + SP1_CIRCUIT_VERSION, + strategy, + timeout_secs, + cycle_limit, + ) + .await + }, + timeout, + "requesting proof", + ) + .await?; - let proof_id = client.create_proof(elf, &stdin, mode, SP1_CIRCUIT_VERSION).await?; - log::info!("Created {}", proof_id); + // Log the request ID and transaction hash. + let tx_hash_hex = "0x".to_string() + &hex::encode(response.tx_hash); + let request_id = response.body.unwrap().request_id; + let request_id_hex = "0x".to_string() + &hex::encode(request_id.clone()); + log::info!("Created request {} in transaction {}", request_id_hex, tx_hash_hex); - if self.client.is_using_prover_network { - log::info!("View in explorer: https://explorer.succinct.xyz/{}", proof_id); + if self.client.rpc_url == DEFAULT_PROVER_NETWORK_RPC { + log::info!( + "View request status at: https://network.succinct.xyz/request/{}", + request_id_hex + ); } - Ok(proof_id) + + Ok(request_id) } /// Waits for a proof to be generated and returns the proof. If a timeout is supplied, the /// function will return an error if the proof is not generated within the timeout. - pub async fn wait_proof( + pub(crate) async fn wait_proof( &self, - proof_id: &str, + request_id: &[u8], timeout: Option, - ) -> Result { - let client = &self.client; - let mut is_claimed = false; + ) -> Result

{ + let mut is_assigned = false; let start_time = Instant::now(); - let mut consecutive_errors = 0; + loop { + // Calculate the remaining timeout. if let Some(timeout) = timeout { if start_time.elapsed() > timeout { - return Err(anyhow::anyhow!("Proof generation timed out.")); + return Err(anyhow::anyhow!("proof request timed out.")); } } + let remaining_timeout = timeout.map(|t| { + let elapsed = start_time.elapsed(); + if elapsed < t { t - elapsed } else { Duration::from_secs(0) } + }); - let result = client.get_proof_status(proof_id).await; - - if let Err(e) = result { - consecutive_errors += 1; - log::warn!( - "Failed to get proof status ({}/{}): {:?}", - consecutive_errors, - MAX_CONSECUTIVE_ERRORS, - e - ); - if consecutive_errors == MAX_CONSECUTIVE_ERRORS { - return Err(anyhow::anyhow!( - "Proof generation failed: {} consecutive errors.", - MAX_CONSECUTIVE_ERRORS - )); - } - continue; - } - consecutive_errors = 0; + // Get status with retries. + let (status, maybe_proof) = with_retry( + || async { self.client.get_proof_request_status::

(request_id).await }, + remaining_timeout, + "getting proof request status", + ) + .await?; - let (status, maybe_proof) = result.unwrap(); + // Check the execution status. + if status.execution_status == ExecutionStatus::Unexecutable as i32 { + return Err(anyhow::anyhow!("proof request is unexecutable")); + } - match status.status() { - ProofStatus::ProofFulfilled => { + // Check the fulfillment status. + match FulfillmentStatus::try_from(status.fulfillment_status) { + Ok(FulfillmentStatus::Fulfilled) => { return Ok(maybe_proof.unwrap()); } - ProofStatus::ProofClaimed => { - if !is_claimed { - log::info!("Proof request claimed, proving..."); - is_claimed = true; + Ok(FulfillmentStatus::Assigned) => { + if !is_assigned { + log::info!("proof request assigned, proving..."); + is_assigned = true; } } - ProofStatus::ProofUnclaimed => { - return Err(anyhow::anyhow!( - "Proof generation failed: {}", - status.unclaim_description() - )); + Ok(FulfillmentStatus::Unfulfillable) => { + return Err(anyhow::anyhow!("proof request is unfulfillable")); } _ => {} } + sleep(Duration::from_secs(2)).await; } } - /// Get the status and the proof if available of a given proof request. The proof is returned - /// only if the status is Fulfilled. - pub async fn get_proof_status( - &self, - proof_id: &str, - ) -> Result<(GetProofStatusResponse, Option)> { - self.client.get_proof_status(proof_id).await - } - /// Requests a proof from the prover network and waits for it to be generated. - pub async fn prove( + pub(crate) async fn prove_impl( &self, - elf: &[u8], - stdin: SP1Stdin, - mode: ProofMode, + pk: &SP1ProvingKey, + stdin: &SP1Stdin, + mode: SP1ProofMode, + strategy: FulfillmentStrategy, timeout: Option, + skip_simulation: bool, ) -> Result { - let proof_id = self.request_proof(elf, stdin, mode).await?; - self.wait_proof(&proof_id, timeout).await + let vk_hash = self.register_program(&pk.vk, &pk.elf).await?; + let cycle_limit = self.get_cycle_limit(&pk.elf, stdin, skip_simulation)?; + let request_id = self + .request_proof(&vk_hash, stdin, mode.into(), strategy, cycle_limit, timeout) + .await?; + self.wait_proof(&request_id, timeout).await } -} -impl Prover for NetworkProver { - fn id(&self) -> ProverType { - ProverType::Network + fn get_cycle_limit(&self, elf: &[u8], stdin: &SP1Stdin, skip_simulation: bool) -> Result { + if skip_simulation { + Ok(DEFAULT_CYCLE_LIMIT) + } else { + let (_, report) = self.prover.inner().execute(elf, stdin, SP1Context::default())?; + let cycles = report.total_instruction_count(); + Ok(cycles) + } } +} +impl Prover for NetworkProver { fn setup(&self, elf: &[u8]) -> (SP1ProvingKey, SP1VerifyingKey) { - self.local_prover.setup(elf) + self.prover.setup(elf) } - fn sp1_prover(&self) -> &SP1Prover { - self.local_prover.sp1_prover() + fn inner(&self) -> &SP1Prover { + self.prover.inner() } - fn prove<'a>( - &'a self, + fn prove( + &self, pk: &SP1ProvingKey, - stdin: SP1Stdin, - opts: ProofOpts, - context: SP1Context<'a>, - kind: SP1ProofKind, + stdin: &SP1Stdin, + mode: SP1ProofMode, ) -> Result { - warn_if_not_default(&opts.sp1_prover_opts, &context); - block_on(self.prove(&pk.elf, stdin, kind.into(), opts.timeout)) + block_on(self.prove_impl(pk, stdin, mode, FulfillmentStrategy::Hosted, None, false)) } } -/// Warns if `opts` or `context` are not default values, since they are currently unsupported. -fn warn_if_not_default(opts: &SP1ProverOpts, context: &SP1Context) { - if opts != &SP1ProverOpts::default() { - tracing::warn!("non-default opts will be ignored: {:?}", opts.core_opts); - tracing::warn!("custom SP1ProverOpts are currently unsupported by the network prover"); - } - // Exhaustive match is done to ensure we update the warnings if the types change. - let SP1Context { hook_registry, subproof_verifier, .. } = context; - if hook_registry.is_some() { - tracing::warn!("non-default context.hook_registry will be ignored: {:?}", hook_registry); - tracing::warn!("custom runtime hooks are currently unsupported by the network prover"); - tracing::warn!("proving may fail due to missing hooks"); - } - if subproof_verifier.is_some() { - tracing::warn!("non-default context.subproof_verifier will be ignored"); - tracing::warn!("custom subproof verifiers are currently unsupported by the network prover"); +impl From for ProofMode { + fn from(value: SP1ProofMode) -> Self { + match value { + SP1ProofMode::Core => Self::Core, + SP1ProofMode::Compressed => Self::Compressed, + SP1ProofMode::Plonk => Self::Plonk, + SP1ProofMode::Groth16 => Self::Groth16, + } } } -impl From for ProofMode { - fn from(value: SP1ProofKind) -> Self { - match value { - SP1ProofKind::Core => Self::Core, - SP1ProofKind::Compressed => Self::Compressed, - SP1ProofKind::Plonk => Self::Plonk, - SP1ProofKind::Groth16 => Self::Groth16, +/// Execute an async operation with exponential backoff retries. +pub async fn with_retry( + operation: F, + timeout: Option, + operation_name: &str, +) -> Result +where + F: Fn() -> Fut, + Fut: std::future::Future>, +{ + let backoff = ExponentialBackoff { + initial_interval: Duration::from_secs(1), + max_interval: Duration::from_secs(120), + max_elapsed_time: timeout, + ..Default::default() + }; + + retry(backoff, || async { + match operation().await { + Ok(result) => Ok(result), + Err(e) => { + // Check for tonic status errors. + if let Some(status) = e.downcast_ref::() { + match status.code() { + Code::Unavailable => { + log::warn!( + "Network temporarily unavailable when {} due to {}, retrying...", + operation_name, + status.message(), + ); + Err(BackoffError::transient(e)) + } + Code::NotFound => { + log::error!( + "{} not found due to {}", + operation_name, + status.message(), + ); + Err(BackoffError::permanent(e)) + } + _ => { + log::error!( + "Permanent error encountered when {}: {} ({})", + operation_name, + status.message(), + status.code() + ); + Err(BackoffError::permanent(e)) + } + } + } else { + // Check for common transport errors. + let error_msg = e.to_string().to_lowercase(); + let is_transient = error_msg.contains("tls handshake") || + error_msg.contains("dns error") || + error_msg.contains("connection reset") || + error_msg.contains("broken pipe") || + error_msg.contains("transport error") || + error_msg.contains("failed to lookup"); + + if is_transient { + log::warn!( + "Transient transport error when {}: {}, retrying...", + operation_name, + error_msg + ); + Err(BackoffError::transient(e)) + } else { + log::error!("Permanent error when {}: {}", operation_name, error_msg); + Err(BackoffError::permanent(e)) + } + } + } } - } + }) + .await } diff --git a/crates/sdk/src/network-v2/sign_message.rs b/crates/sdk/src/network/sign_message.rs similarity index 94% rename from crates/sdk/src/network-v2/sign_message.rs rename to crates/sdk/src/network/sign_message.rs index a71290e315..9d12891525 100644 --- a/crates/sdk/src/network-v2/sign_message.rs +++ b/crates/sdk/src/network/sign_message.rs @@ -2,8 +2,8 @@ use alloy_primitives::{Address, Signature}; use prost::Message; use thiserror::Error; -use crate::network_v2::json::{format_json_message, JsonFormatError}; -use crate::network_v2::proto::network::{FulfillProofRequest, MessageFormat, RequestProofRequest}; +use crate::network::proto::network::{FulfillProofRequest, MessageFormat, RequestProofRequest}; +use crate::network::utils::{format_json_message, JsonFormatError}; #[allow(dead_code)] pub trait SignedMessage { @@ -83,6 +83,7 @@ macro_rules! impl_signed_message { impl_signed_message!(RequestProofRequest); impl_signed_message!(FulfillProofRequest); +#[allow(clippy::needless_pass_by_value)] pub fn recover_sender_raw( signature: Vec, message: Vec, diff --git a/crates/sdk/src/network-v2/json.rs b/crates/sdk/src/network/utils.rs similarity index 70% rename from crates/sdk/src/network-v2/json.rs rename to crates/sdk/src/network/utils.rs index a0808d9be6..e1b7d749b5 100644 --- a/crates/sdk/src/network-v2/json.rs +++ b/crates/sdk/src/network/utils.rs @@ -1,17 +1,29 @@ +//! # Network Utils +//! +//! This module provides utility functions for the network module. + +use alloy_signer::{Signature, SignerSync}; use prost::Message; -#[allow(unused_imports)] -use serde::{Deserialize, Serialize}; +use serde::Serialize; use thiserror::Error; -/// Errors that can occur during JSON formatting. +pub(crate) trait Signable: Message { + fn sign(&self, signer: &S) -> Signature; +} + +impl Signable for T { + fn sign(&self, signer: &S) -> Signature { + signer.sign_message_sync(&self.encode_to_vec()).unwrap() + } +} + #[derive(Error, Debug)] -pub enum JsonFormatError { +pub(crate) enum JsonFormatError { #[error("Serialization error: {0}")] SerializationError(String), } -/// Formats a Protobuf body into a JSON byte representation. -pub fn format_json_message(body: &T) -> Result, JsonFormatError> +pub(crate) fn format_json_message(body: &T) -> Result, JsonFormatError> where T: Message + Serialize, { @@ -33,6 +45,7 @@ where mod tests { use super::*; use prost::Message as ProstMessage; + use serde::{Deserialize, Serialize}; // Test message for JSON formatting. #[derive(Clone, ProstMessage, Serialize, Deserialize)] diff --git a/crates/sdk/src/proof.rs b/crates/sdk/src/proof.rs index 42d5c92865..0eb556d0d5 100644 --- a/crates/sdk/src/proof.rs +++ b/crates/sdk/src/proof.rs @@ -1,33 +1,45 @@ +#![allow(missing_docs)] + use std::{fmt::Debug, fs::File, path::Path}; use anyhow::Result; use serde::{Deserialize, Serialize}; use sp1_core_executor::SP1ReduceProof; -use sp1_core_machine::io::SP1Stdin; use sp1_primitives::io::SP1PublicValues; -use strum_macros::{EnumDiscriminants, EnumTryAs}; - use sp1_prover::{CoreSC, Groth16Bn254Proof, InnerSC, PlonkBn254Proof}; -use sp1_stark::{MachineVerificationError, ShardProof}; +use sp1_stark::ShardProof; +use strum_macros::{EnumDiscriminants, EnumTryAs}; -/// A proof generated with SP1 of a particular proof mode. +/// A proof generated by the SP1 RISC-V zkVM. #[derive(Debug, Clone, Serialize, Deserialize, EnumDiscriminants, EnumTryAs)] #[strum_discriminants(derive(Default, Hash, PartialOrd, Ord))] -#[strum_discriminants(name(SP1ProofKind))] +#[strum_discriminants(name(SP1ProofMode))] pub enum SP1Proof { + /// A proof generated by the core proof mode. + /// + /// The proof size scales linearly with the number of cycles. #[strum_discriminants(default)] Core(Vec>), + /// A proof generated by the compress proof mode. + /// + /// The proof size is constant, regardless of the number of cycles. Compressed(Box>), + /// A proof generated by the Plonk proof mode. Plonk(PlonkBn254Proof), + /// A proof generated by the Groth16 proof mode. Groth16(Groth16Bn254Proof), } -/// A proof generated with SP1, bundled together with stdin, public values, and the SP1 version. +/// A proof generated by the SP1 RISC-V zkVM bundled together with the public values and the +/// version. #[derive(Debug, Clone, Serialize, Deserialize)] pub struct SP1ProofWithPublicValues { + /// The raw proof generated by the SP1 RISC-V zkVM. pub proof: SP1Proof, - pub stdin: SP1Stdin, + /// The public values generated by the SP1 RISC-V zkVM. pub public_values: SP1PublicValues, + /// The version of the SP1 RISC-V zkVM (not necessary but useful for detecting version + /// mismatches). pub sp1_version: String, } @@ -44,24 +56,19 @@ impl SP1ProofWithPublicValues { .map_err(Into::into) } - /// Returns the raw proof as a string. - pub fn raw(&self) -> String { - match &self.proof { - SP1Proof::Plonk(plonk) => plonk.raw_proof.clone(), - SP1Proof::Groth16(groth16) => groth16.raw_proof.clone(), - _ => unimplemented!(), - } - } - - /// For Plonk or Groth16 proofs, returns the proof in a byte encoding the onchain verifier - /// accepts. The bytes consist of the first four bytes of Plonk vkey hash followed by the - /// encoded proof, in a form optimized for onchain verification. + /// The proof in the byte encoding the onchain verifiers accepts for [`SP1ProofMode::Groth16`] and + /// [`SP1ProofMode::Plonk`] proofs. + /// + /// # Details + /// The bytes consist of the first four bytes of Groth16/Plonk vkey hash followed by the encoded + /// proof, in a form optimized for onchain verification. + #[must_use] pub fn bytes(&self) -> Vec { match &self.proof { SP1Proof::Plonk(plonk_proof) => { + // If the proof is empty, then this is a mock proof. The mock SP1 verifier + // expects an empty byte array for verification, so return an empty byte array. if plonk_proof.encoded_proof.is_empty() { - // If the proof is empty, then this is a mock proof. The mock SP1 verifier - // expects an empty byte array for verification, so return an empty byte array. return Vec::new(); } @@ -70,9 +77,9 @@ impl SP1ProofWithPublicValues { [plonk_proof.plonk_vkey_hash[..4].to_vec(), proof_bytes].concat() } SP1Proof::Groth16(groth16_proof) => { + // If the proof is empty, then this is a mock proof. The mock SP1 verifier + // expects an empty byte array for verification, so return an empty byte array. if groth16_proof.encoded_proof.is_empty() { - // If the proof is empty, then this is a mock proof. The mock SP1 verifier - // expects an empty byte array for verification, so return an empty byte array. return Vec::new(); } @@ -80,15 +87,15 @@ impl SP1ProofWithPublicValues { hex::decode(&groth16_proof.encoded_proof).expect("Invalid Groth16 proof"); [groth16_proof.groth16_vkey_hash[..4].to_vec(), proof_bytes].concat() } - _ => unimplemented!("only Plonk and Groth16 proofs are verifiable onchain"), + proof => panic!( + "Proof type {:?} is not supported for onchain verification. \ + Only Plonk and Groth16 proofs are verifiable onchain", + std::mem::discriminant(proof) + ), } } } -pub type SP1CoreProofVerificationError = MachineVerificationError; - -pub type SP1CompressedProofVerificationError = MachineVerificationError; - #[cfg(test)] mod tests { use super::*; @@ -99,12 +106,11 @@ mod tests { proof: SP1Proof::Plonk(PlonkBn254Proof { encoded_proof: "ab".to_string(), plonk_vkey_hash: [0; 32], - public_inputs: ["".to_string(), "".to_string()], - raw_proof: "".to_string(), + public_inputs: [String::new(), String::new()], + raw_proof: String::new(), }), - stdin: SP1Stdin::new(), public_values: SP1PublicValues::new(), - sp1_version: "".to_string(), + sp1_version: String::new(), }; let expected_bytes = [vec![0, 0, 0, 0], hex::decode("ab").unwrap()].concat(); assert_eq!(plonk_proof.bytes(), expected_bytes); @@ -116,12 +122,11 @@ mod tests { proof: SP1Proof::Groth16(Groth16Bn254Proof { encoded_proof: "ab".to_string(), groth16_vkey_hash: [0; 32], - public_inputs: ["".to_string(), "".to_string()], - raw_proof: "".to_string(), + public_inputs: [String::new(), String::new()], + raw_proof: String::new(), }), - stdin: SP1Stdin::new(), public_values: SP1PublicValues::new(), - sp1_version: "".to_string(), + sp1_version: String::new(), }; let expected_bytes = [vec![0, 0, 0, 0], hex::decode("ab").unwrap()].concat(); assert_eq!(groth16_proof.bytes(), expected_bytes); @@ -131,14 +136,13 @@ mod tests { fn test_mock_plonk_proof_bytes() { let mock_plonk_proof = SP1ProofWithPublicValues { proof: SP1Proof::Plonk(PlonkBn254Proof { - encoded_proof: "".to_string(), + encoded_proof: String::new(), plonk_vkey_hash: [0; 32], - public_inputs: ["".to_string(), "".to_string()], - raw_proof: "".to_string(), + public_inputs: [String::new(), String::new()], + raw_proof: String::new(), }), - stdin: SP1Stdin::new(), public_values: SP1PublicValues::new(), - sp1_version: "".to_string(), + sp1_version: String::new(), }; assert_eq!(mock_plonk_proof.bytes(), Vec::::new()); } @@ -147,27 +151,27 @@ mod tests { fn test_mock_groth16_proof_bytes() { let mock_groth16_proof = SP1ProofWithPublicValues { proof: SP1Proof::Groth16(Groth16Bn254Proof { - encoded_proof: "".to_string(), + encoded_proof: String::new(), groth16_vkey_hash: [0; 32], - public_inputs: ["".to_string(), "".to_string()], - raw_proof: "".to_string(), + public_inputs: [String::new(), String::new()], + raw_proof: String::new(), }), - stdin: SP1Stdin::new(), public_values: SP1PublicValues::new(), - sp1_version: "".to_string(), + sp1_version: String::new(), }; assert_eq!(mock_groth16_proof.bytes(), Vec::::new()); } #[test] - #[should_panic(expected = "only Plonk and Groth16 proofs are verifiable onchain")] + #[should_panic( + expected = "Proof type Discriminant(0) is not supported for onchain verification. Only Plonk and Groth16 proofs are verifiable onchain" + )] fn test_core_proof_bytes_unimplemented() { let core_proof = SP1ProofWithPublicValues { proof: SP1Proof::Core(vec![]), - stdin: SP1Stdin::new(), public_values: SP1PublicValues::new(), - sp1_version: "".to_string(), + sp1_version: String::new(), }; - core_proof.bytes(); + println!("{:?}", core_proof.bytes()); } } diff --git a/crates/sdk/src/prover.rs b/crates/sdk/src/prover.rs new file mode 100644 index 0000000000..83f04deb95 --- /dev/null +++ b/crates/sdk/src/prover.rs @@ -0,0 +1,164 @@ +//! # SP1 Prover Trait +//! +//! A trait that each prover variant must implement. + +use std::borrow::Borrow; + +use anyhow::Result; +use itertools::Itertools; +use p3_field::PrimeField32; +use sp1_core_executor::{ExecutionReport, SP1Context}; +use sp1_core_machine::{io::SP1Stdin, SP1_CIRCUIT_VERSION}; +use sp1_primitives::io::SP1PublicValues; +use sp1_prover::{ + components::SP1ProverComponents, CoreSC, InnerSC, SP1CoreProofData, SP1Prover, SP1ProvingKey, + SP1VerifyingKey, +}; +use sp1_stark::{air::PublicValues, MachineVerificationError, Word}; +use thiserror::Error; + +use crate::install::try_install_circuit_artifacts; +use crate::{SP1Proof, SP1ProofMode, SP1ProofWithPublicValues}; + +/// A basic set of primitives that each prover variant must implement. +pub trait Prover: Send + Sync { + /// The inner [`SP1Prover`] struct used by the prover. + fn inner(&self) -> &SP1Prover; + + /// The version of the current SP1 circuit. + fn version(&self) -> &str { + SP1_CIRCUIT_VERSION + } + + /// Generate the proving and verifying keys for the given program. + fn setup(&self, elf: &[u8]) -> (SP1ProvingKey, SP1VerifyingKey); + + /// Executes the program on the given input. + fn execute(&self, elf: &[u8], stdin: &SP1Stdin) -> Result<(SP1PublicValues, ExecutionReport)> { + Ok(self.inner().execute(elf, stdin, SP1Context::default())?) + } + + /// Proves the given program on the given input in the given proof mode. + fn prove( + &self, + pk: &SP1ProvingKey, + stdin: &SP1Stdin, + mode: SP1ProofMode, + ) -> Result; + + /// Verify that an SP1 proof is valid given its vkey and metadata. + /// For Plonk proofs, verifies that the public inputs of the `PlonkBn254` proof match + /// the hash of the VK and the committed public values of the `SP1ProofWithPublicValues`. + fn verify( + &self, + bundle: &SP1ProofWithPublicValues, + vkey: &SP1VerifyingKey, + ) -> Result<(), SP1VerificationError> { + verify_proof(self.inner(), self.version(), bundle, vkey) + } +} + +/// An error that occurs when calling [`Prover::verify`]. +#[derive(Error, Debug)] +pub enum SP1VerificationError { + /// An error that occurs when the public values are invalid. + #[error("Invalid public values")] + InvalidPublicValues, + /// An error that occurs when the SP1 version does not match the version of the circuit. + #[error("Version mismatch")] + VersionMismatch(String), + /// An error that occurs when the core machine verification fails. + #[error("Core machine verification error: {0}")] + Core(MachineVerificationError), + /// An error that occurs when the recursion verification fails. + #[error("Recursion verification error: {0}")] + Recursion(MachineVerificationError), + /// An error that occurs when the Plonk verification fails. + #[error("Plonk verification error: {0}")] + Plonk(anyhow::Error), + /// An error that occurs when the Groth16 verification fails. + #[error("Groth16 verification error: {0}")] + Groth16(anyhow::Error), +} + +pub(crate) fn verify_proof( + prover: &SP1Prover, + version: &str, + bundle: &SP1ProofWithPublicValues, + vkey: &SP1VerifyingKey, +) -> Result<(), SP1VerificationError> { + // Check that the SP1 version matches the version of the currentcircuit. + if bundle.sp1_version != version { + return Err(SP1VerificationError::VersionMismatch(bundle.sp1_version.clone())); + } + + match &bundle.proof { + SP1Proof::Core(proof) => { + let public_values: &PublicValues, _> = + proof.last().unwrap().public_values.as_slice().borrow(); + + // Get the committed value digest bytes. + let committed_value_digest_bytes = public_values + .committed_value_digest + .iter() + .flat_map(|w| w.0.iter().map(|x| x.as_canonical_u32() as u8)) + .collect_vec(); + + // Make sure the committed value digest matches the public values hash. + for (a, b) in committed_value_digest_bytes.iter().zip_eq(bundle.public_values.hash()) { + if *a != b { + return Err(SP1VerificationError::InvalidPublicValues); + } + } + + // Verify the core proof. + prover + .verify(&SP1CoreProofData(proof.clone()), vkey) + .map_err(SP1VerificationError::Core) + } + SP1Proof::Compressed(proof) => { + let public_values: &PublicValues, _> = + proof.proof.public_values.as_slice().borrow(); + + // Get the committed value digest bytes. + let committed_value_digest_bytes = public_values + .committed_value_digest + .iter() + .flat_map(|w| w.0.iter().map(|x| x.as_canonical_u32() as u8)) + .collect_vec(); + + // Make sure the committed value digest matches the public values hash. + for (a, b) in committed_value_digest_bytes.iter().zip_eq(bundle.public_values.hash()) { + if *a != b { + return Err(SP1VerificationError::InvalidPublicValues); + } + } + + prover.verify_compressed(proof, vkey).map_err(SP1VerificationError::Recursion) + } + SP1Proof::Plonk(proof) => prover + .verify_plonk_bn254( + proof, + vkey, + &bundle.public_values, + &if sp1_prover::build::sp1_dev_mode() { + sp1_prover::build::plonk_bn254_artifacts_dev_dir() + } else { + try_install_circuit_artifacts("plonk") + }, + ) + .map_err(SP1VerificationError::Plonk), + SP1Proof::Groth16(proof) => prover + .verify_groth16_bn254( + proof, + vkey, + &bundle.public_values, + &if sp1_prover::build::sp1_dev_mode() { + sp1_prover::build::groth16_bn254_artifacts_dev_dir() + } else { + try_install_circuit_artifacts("groth16") + }, + ) + .map_err(SP1VerificationError::Groth16), + } +} diff --git a/crates/sdk/src/provers/cpu.rs b/crates/sdk/src/provers/cpu.rs deleted file mode 100644 index 234e663909..0000000000 --- a/crates/sdk/src/provers/cpu.rs +++ /dev/null @@ -1,131 +0,0 @@ -use anyhow::Result; -use sp1_core_executor::SP1Context; -use sp1_core_machine::io::SP1Stdin; -use sp1_prover::{components::DefaultProverComponents, SP1Prover}; - -use crate::install::try_install_circuit_artifacts; -use crate::{ - provers::ProofOpts, Prover, SP1Proof, SP1ProofKind, SP1ProofWithPublicValues, SP1ProvingKey, - SP1VerifyingKey, -}; - -use super::ProverType; - -/// An implementation of [crate::ProverClient] that can generate end-to-end proofs locally. -pub struct CpuProver { - prover: SP1Prover, -} - -impl CpuProver { - /// Creates a new [LocalProver]. - pub fn new() -> Self { - let prover = SP1Prover::new(); - Self { prover } - } - - /// Creates a new [LocalProver] from an existing [SP1Prover]. - pub fn from_prover(prover: SP1Prover) -> Self { - Self { prover } - } -} - -impl Prover for CpuProver { - fn id(&self) -> ProverType { - ProverType::Cpu - } - - fn setup(&self, elf: &[u8]) -> (SP1ProvingKey, SP1VerifyingKey) { - self.prover.setup(elf) - } - - fn sp1_prover(&self) -> &SP1Prover { - &self.prover - } - - fn prove<'a>( - &'a self, - pk: &SP1ProvingKey, - stdin: SP1Stdin, - opts: ProofOpts, - context: SP1Context<'a>, - kind: SP1ProofKind, - ) -> Result { - // Generate the core proof. - let proof: sp1_prover::SP1ProofWithMetadata = - self.prover.prove_core(pk, &stdin, opts.sp1_prover_opts, context)?; - if kind == SP1ProofKind::Core { - return Ok(SP1ProofWithPublicValues { - proof: SP1Proof::Core(proof.proof.0), - stdin: proof.stdin, - public_values: proof.public_values, - sp1_version: self.version().to_string(), - }); - } - - let deferred_proofs = - stdin.proofs.iter().map(|(reduce_proof, _)| reduce_proof.clone()).collect(); - let public_values = proof.public_values.clone(); - - // Generate the compressed proof. - let reduce_proof = - self.prover.compress(&pk.vk, proof, deferred_proofs, opts.sp1_prover_opts)?; - if kind == SP1ProofKind::Compressed { - return Ok(SP1ProofWithPublicValues { - proof: SP1Proof::Compressed(Box::new(reduce_proof)), - stdin, - public_values, - sp1_version: self.version().to_string(), - }); - } - - // Generate the shrink proof. - let compress_proof = self.prover.shrink(reduce_proof, opts.sp1_prover_opts)?; - - // Genenerate the wrap proof. - let outer_proof = self.prover.wrap_bn254(compress_proof, opts.sp1_prover_opts)?; - - if kind == SP1ProofKind::Plonk { - let plonk_bn254_artifacts = if sp1_prover::build::sp1_dev_mode() { - sp1_prover::build::try_build_plonk_bn254_artifacts_dev( - &outer_proof.vk, - &outer_proof.proof, - ) - } else { - try_install_circuit_artifacts("plonk") - }; - let proof = self.prover.wrap_plonk_bn254(outer_proof, &plonk_bn254_artifacts); - - return Ok(SP1ProofWithPublicValues { - proof: SP1Proof::Plonk(proof), - stdin, - public_values, - sp1_version: self.version().to_string(), - }); - } else if kind == SP1ProofKind::Groth16 { - let groth16_bn254_artifacts = if sp1_prover::build::sp1_dev_mode() { - sp1_prover::build::try_build_groth16_bn254_artifacts_dev( - &outer_proof.vk, - &outer_proof.proof, - ) - } else { - try_install_circuit_artifacts("groth16") - }; - - let proof = self.prover.wrap_groth16_bn254(outer_proof, &groth16_bn254_artifacts); - return Ok(SP1ProofWithPublicValues { - proof: SP1Proof::Groth16(proof), - stdin, - public_values, - sp1_version: self.version().to_string(), - }); - } - - unreachable!() - } -} - -impl Default for CpuProver { - fn default() -> Self { - Self::new() - } -} diff --git a/crates/sdk/src/provers/cuda.rs b/crates/sdk/src/provers/cuda.rs deleted file mode 100644 index 5f8ab983aa..0000000000 --- a/crates/sdk/src/provers/cuda.rs +++ /dev/null @@ -1,125 +0,0 @@ -use anyhow::Result; -use sp1_core_machine::io::SP1Stdin; -use sp1_cuda::SP1CudaProver; -use sp1_prover::{components::DefaultProverComponents, SP1Prover}; - -use super::ProverType; -use crate::install::try_install_circuit_artifacts; -use crate::{ - provers::ProofOpts, Prover, SP1Context, SP1Proof, SP1ProofKind, SP1ProofWithPublicValues, - SP1ProvingKey, SP1VerifyingKey, -}; - -/// An implementation of [crate::ProverClient] that can generate proofs locally using CUDA. -pub struct CudaProver { - prover: SP1Prover, - cuda_prover: SP1CudaProver, -} - -impl CudaProver { - /// Creates a new [CudaProver]. - pub fn new(prover: SP1Prover) -> Self { - let cuda_prover = SP1CudaProver::new(); - Self { prover, cuda_prover: cuda_prover.expect("Failed to initialize CUDA prover") } - } -} - -impl Prover for CudaProver { - fn id(&self) -> ProverType { - ProverType::Cuda - } - - fn setup(&self, elf: &[u8]) -> (SP1ProvingKey, SP1VerifyingKey) { - self.prover.setup(elf) - } - - fn sp1_prover(&self) -> &SP1Prover { - &self.prover - } - - fn prove<'a>( - &'a self, - pk: &SP1ProvingKey, - stdin: SP1Stdin, - _opts: ProofOpts, - _context: SP1Context<'a>, - kind: SP1ProofKind, - ) -> Result { - tracing::warn!("opts and context are ignored for the cuda prover"); - - // Generate the core proof. - let proof = self.cuda_prover.prove_core(pk, &stdin)?; - if kind == SP1ProofKind::Core { - return Ok(SP1ProofWithPublicValues { - proof: SP1Proof::Core(proof.proof.0), - stdin: proof.stdin, - public_values: proof.public_values, - sp1_version: self.version().to_string(), - }); - } - - let deferred_proofs = - stdin.proofs.iter().map(|(reduce_proof, _)| reduce_proof.clone()).collect(); - let public_values = proof.public_values.clone(); - - // Generate the compressed proof. - let reduce_proof = self.cuda_prover.compress(&pk.vk, proof, deferred_proofs)?; - if kind == SP1ProofKind::Compressed { - return Ok(SP1ProofWithPublicValues { - proof: SP1Proof::Compressed(Box::new(reduce_proof)), - stdin, - public_values, - sp1_version: self.version().to_string(), - }); - } - - // Generate the shrink proof. - let compress_proof = self.cuda_prover.shrink(reduce_proof)?; - - // Genenerate the wrap proof. - let outer_proof = self.cuda_prover.wrap_bn254(compress_proof)?; - - if kind == SP1ProofKind::Plonk { - let plonk_bn254_artifacts = if sp1_prover::build::sp1_dev_mode() { - sp1_prover::build::try_build_plonk_bn254_artifacts_dev( - &outer_proof.vk, - &outer_proof.proof, - ) - } else { - try_install_circuit_artifacts("plonk") - }; - let proof = self.prover.wrap_plonk_bn254(outer_proof, &plonk_bn254_artifacts); - return Ok(SP1ProofWithPublicValues { - proof: SP1Proof::Plonk(proof), - stdin, - public_values, - sp1_version: self.version().to_string(), - }); - } else if kind == SP1ProofKind::Groth16 { - let groth16_bn254_artifacts = if sp1_prover::build::sp1_dev_mode() { - sp1_prover::build::try_build_groth16_bn254_artifacts_dev( - &outer_proof.vk, - &outer_proof.proof, - ) - } else { - try_install_circuit_artifacts("groth16") - }; - - let proof = self.prover.wrap_groth16_bn254(outer_proof, &groth16_bn254_artifacts); - return Ok(SP1ProofWithPublicValues { - proof: SP1Proof::Groth16(proof), - stdin, - public_values, - sp1_version: self.version().to_string(), - }); - } - - unreachable!() - } -} - -impl Default for CudaProver { - fn default() -> Self { - Self::new(SP1Prover::new()) - } -} diff --git a/crates/sdk/src/provers/mock.rs b/crates/sdk/src/provers/mock.rs deleted file mode 100644 index ca317972ac..0000000000 --- a/crates/sdk/src/provers/mock.rs +++ /dev/null @@ -1,170 +0,0 @@ -#![allow(unused_variables)] -use hashbrown::HashMap; -use sp1_core_executor::{SP1Context, SP1ReduceProof}; -use sp1_core_machine::io::SP1Stdin; -use sp1_stark::{ShardCommitment, ShardOpenedValues, ShardProof, StarkVerifyingKey}; - -use crate::{ - Prover, SP1Proof, SP1ProofKind, SP1ProofWithPublicValues, SP1ProvingKey, SP1VerificationError, - SP1VerifyingKey, -}; -use anyhow::Result; -use p3_baby_bear::BabyBear; -use p3_field::{AbstractField, PrimeField}; -use p3_fri::{FriProof, TwoAdicFriPcsProof}; -use sp1_prover::{ - components::DefaultProverComponents, - verify::{verify_groth16_bn254_public_inputs, verify_plonk_bn254_public_inputs}, - Groth16Bn254Proof, HashableKey, PlonkBn254Proof, SP1Prover, -}; - -use super::{ProofOpts, ProverType}; - -/// An implementation of [crate::ProverClient] that can generate mock proofs. -pub struct MockProver { - pub(crate) prover: SP1Prover, -} - -impl MockProver { - /// Creates a new [MockProver]. - pub fn new() -> Self { - let prover = SP1Prover::new(); - Self { prover } - } -} - -impl Prover for MockProver { - fn id(&self) -> ProverType { - ProverType::Mock - } - - fn setup(&self, elf: &[u8]) -> (SP1ProvingKey, SP1VerifyingKey) { - self.prover.setup(elf) - } - - fn sp1_prover(&self) -> &SP1Prover { - &self.prover - } - - fn prove<'a>( - &'a self, - pk: &SP1ProvingKey, - stdin: SP1Stdin, - opts: ProofOpts, - context: SP1Context<'a>, - kind: SP1ProofKind, - ) -> Result { - match kind { - SP1ProofKind::Core => { - let (public_values, _) = self.prover.execute(&pk.elf, &stdin, context)?; - Ok(SP1ProofWithPublicValues { - proof: SP1Proof::Core(vec![]), - stdin, - public_values, - sp1_version: self.version().to_string(), - }) - } - SP1ProofKind::Compressed => { - let (public_values, _) = self.prover.execute(&pk.elf, &stdin, context)?; - - let shard_proof = ShardProof { - commitment: ShardCommitment { - global_main_commit: [BabyBear::zero(); 8].into(), - local_main_commit: [BabyBear::zero(); 8].into(), - permutation_commit: [BabyBear::zero(); 8].into(), - quotient_commit: [BabyBear::zero(); 8].into(), - }, - opened_values: ShardOpenedValues { chips: vec![] }, - opening_proof: TwoAdicFriPcsProof { - fri_proof: FriProof { - commit_phase_commits: vec![], - query_proofs: vec![], - final_poly: Default::default(), - pow_witness: BabyBear::zero(), - }, - query_openings: vec![], - }, - chip_ordering: HashMap::new(), - public_values: vec![], - }; - - let reduce_vk = StarkVerifyingKey { - commit: [BabyBear::zero(); 8].into(), - pc_start: BabyBear::zero(), - chip_information: vec![], - chip_ordering: HashMap::new(), - }; - - let proof = SP1Proof::Compressed(Box::new(SP1ReduceProof { - vk: reduce_vk, - proof: shard_proof, - })); - - Ok(SP1ProofWithPublicValues { - proof, - stdin, - public_values, - sp1_version: self.version().to_string(), - }) - } - SP1ProofKind::Plonk => { - let (public_values, _) = self.prover.execute(&pk.elf, &stdin, context)?; - Ok(SP1ProofWithPublicValues { - proof: SP1Proof::Plonk(PlonkBn254Proof { - public_inputs: [ - pk.vk.hash_bn254().as_canonical_biguint().to_string(), - public_values.hash_bn254().to_string(), - ], - encoded_proof: "".to_string(), - raw_proof: "".to_string(), - plonk_vkey_hash: [0; 32], - }), - stdin, - public_values, - sp1_version: self.version().to_string(), - }) - } - SP1ProofKind::Groth16 => { - let (public_values, _) = self.prover.execute(&pk.elf, &stdin, context)?; - Ok(SP1ProofWithPublicValues { - proof: SP1Proof::Groth16(Groth16Bn254Proof { - public_inputs: [ - pk.vk.hash_bn254().as_canonical_biguint().to_string(), - public_values.hash_bn254().to_string(), - ], - encoded_proof: "".to_string(), - raw_proof: "".to_string(), - groth16_vkey_hash: [0; 32], - }), - stdin, - public_values, - sp1_version: self.version().to_string(), - }) - } - } - } - - fn verify( - &self, - bundle: &SP1ProofWithPublicValues, - vkey: &SP1VerifyingKey, - ) -> Result<(), SP1VerificationError> { - match &bundle.proof { - SP1Proof::Plonk(PlonkBn254Proof { public_inputs, .. }) => { - verify_plonk_bn254_public_inputs(vkey, &bundle.public_values, public_inputs) - .map_err(SP1VerificationError::Plonk) - } - SP1Proof::Groth16(Groth16Bn254Proof { public_inputs, .. }) => { - verify_groth16_bn254_public_inputs(vkey, &bundle.public_values, public_inputs) - .map_err(SP1VerificationError::Groth16) - } - _ => Ok(()), - } - } -} - -impl Default for MockProver { - fn default() -> Self { - Self::new() - } -} diff --git a/crates/sdk/src/provers/mod.rs b/crates/sdk/src/provers/mod.rs deleted file mode 100644 index 1db5309fac..0000000000 --- a/crates/sdk/src/provers/mod.rs +++ /dev/null @@ -1,175 +0,0 @@ -mod cpu; -#[cfg(feature = "cuda")] -mod cuda; -mod mock; - -pub use cpu::CpuProver; -#[cfg(feature = "cuda")] -pub use cuda::CudaProver; -pub use mock::MockProver; - -use itertools::Itertools; -use p3_field::PrimeField32; -use std::borrow::Borrow; -use std::time::Duration; - -use anyhow::Result; -use sp1_core_executor::SP1Context; -use sp1_core_machine::{io::SP1Stdin, SP1_CIRCUIT_VERSION}; -use sp1_prover::{ - components::SP1ProverComponents, CoreSC, InnerSC, SP1CoreProofData, SP1Prover, SP1ProvingKey, - SP1VerifyingKey, -}; -use sp1_stark::{air::PublicValues, MachineVerificationError, SP1ProverOpts, Word}; -use strum_macros::EnumString; -use thiserror::Error; - -use crate::install::try_install_circuit_artifacts; -use crate::{SP1Proof, SP1ProofKind, SP1ProofWithPublicValues}; - -/// The type of prover. -#[derive(Debug, PartialEq, EnumString)] -pub enum ProverType { - Cpu, - Cuda, - Mock, - Network, -} - -/// Options to configure proof generation. -#[derive(Clone, Default)] -pub struct ProofOpts { - /// Options to configure the SP1 prover. - pub sp1_prover_opts: SP1ProverOpts, - /// Optional timeout duration for proof generation. - pub timeout: Option, -} - -#[derive(Error, Debug)] -pub enum SP1VerificationError { - #[error("Invalid public values")] - InvalidPublicValues, - #[error("Version mismatch")] - VersionMismatch(String), - #[error("Core machine verification error: {0}")] - Core(MachineVerificationError), - #[error("Recursion verification error: {0}")] - Recursion(MachineVerificationError), - #[error("Plonk verification error: {0}")] - Plonk(anyhow::Error), - #[error("Groth16 verification error: {0}")] - Groth16(anyhow::Error), -} - -/// An implementation of [crate::ProverClient]. -pub trait Prover: Send + Sync { - fn id(&self) -> ProverType; - - fn sp1_prover(&self) -> &SP1Prover; - - fn version(&self) -> &str { - SP1_CIRCUIT_VERSION - } - - fn setup(&self, elf: &[u8]) -> (SP1ProvingKey, SP1VerifyingKey); - - /// Prove the execution of a RISCV ELF with the given inputs, according to the given proof mode. - fn prove<'a>( - &'a self, - pk: &SP1ProvingKey, - stdin: SP1Stdin, - opts: ProofOpts, - context: SP1Context<'a>, - kind: SP1ProofKind, - ) -> Result; - - /// Verify that an SP1 proof is valid given its vkey and metadata. - /// For Plonk proofs, verifies that the public inputs of the PlonkBn254 proof match - /// the hash of the VK and the committed public values of the SP1ProofWithPublicValues. - fn verify( - &self, - bundle: &SP1ProofWithPublicValues, - vkey: &SP1VerifyingKey, - ) -> Result<(), SP1VerificationError> { - if bundle.sp1_version != self.version() { - return Err(SP1VerificationError::VersionMismatch(bundle.sp1_version.clone())); - } - match &bundle.proof { - SP1Proof::Core(proof) => { - let public_values: &PublicValues, _> = - proof.last().unwrap().public_values.as_slice().borrow(); - - // Get the committed value digest bytes. - let committed_value_digest_bytes = public_values - .committed_value_digest - .iter() - .flat_map(|w| w.0.iter().map(|x| x.as_canonical_u32() as u8)) - .collect_vec(); - - // Make sure the committed value digest matches the public values hash. - for (a, b) in - committed_value_digest_bytes.iter().zip_eq(bundle.public_values.hash()) - { - if *a != b { - return Err(SP1VerificationError::InvalidPublicValues); - } - } - - // Verify the core proof. - self.sp1_prover() - .verify(&SP1CoreProofData(proof.clone()), vkey) - .map_err(SP1VerificationError::Core) - } - SP1Proof::Compressed(proof) => { - let public_values: &PublicValues, _> = - proof.proof.public_values.as_slice().borrow(); - - // Get the committed value digest bytes. - let committed_value_digest_bytes = public_values - .committed_value_digest - .iter() - .flat_map(|w| w.0.iter().map(|x| x.as_canonical_u32() as u8)) - .collect_vec(); - - // Make sure the committed value digest matches the public values hash. - for (a, b) in - committed_value_digest_bytes.iter().zip_eq(bundle.public_values.hash()) - { - if *a != b { - return Err(SP1VerificationError::InvalidPublicValues); - } - } - - self.sp1_prover() - .verify_compressed(proof, vkey) - .map_err(SP1VerificationError::Recursion) - } - SP1Proof::Plonk(proof) => self - .sp1_prover() - .verify_plonk_bn254( - proof, - vkey, - &bundle.public_values, - &if sp1_prover::build::sp1_dev_mode() { - sp1_prover::build::plonk_bn254_artifacts_dev_dir() - } else { - try_install_circuit_artifacts("plonk") - }, - ) - .map_err(SP1VerificationError::Plonk), - SP1Proof::Groth16(proof) => self - .sp1_prover() - .verify_groth16_bn254( - proof, - vkey, - &bundle.public_values, - &if sp1_prover::build::sp1_dev_mode() { - sp1_prover::build::groth16_bn254_artifacts_dev_dir() - } else { - try_install_circuit_artifacts("groth16") - }, - ) - .map_err(SP1VerificationError::Groth16), - } - } -} diff --git a/crates/sdk/src/utils.rs b/crates/sdk/src/utils.rs new file mode 100644 index 0000000000..347c3bb02f --- /dev/null +++ b/crates/sdk/src/utils.rs @@ -0,0 +1,33 @@ +//! # SP1 SDK Utilities +//! +//! A collection of utilities for the SP1 SDK. + +use sp1_core_machine::io::SP1Stdin; +pub use sp1_core_machine::utils::setup_logger; + +/// Dump the program and stdin to files for debugging if `SP1_DUMP` is set. +pub(crate) fn sp1_dump(elf: &[u8], stdin: &SP1Stdin) { + if std::env::var("SP1_DUMP").map(|v| v == "1" || v.to_lowercase() == "true").unwrap_or(false) { + std::fs::write("program.bin", elf).unwrap(); + let stdin = bincode::serialize(&stdin).unwrap(); + std::fs::write("stdin.bin", stdin.clone()).unwrap(); + } +} + +/// Utility method for blocking on an async function. +/// +/// If we're already in a tokio runtime, we'll block in place. Otherwise, we'll create a new +/// runtime. +#[cfg(feature = "network")] +pub(crate) fn block_on(fut: impl std::future::Future) -> T { + use tokio::task::block_in_place; + + // Handle case if we're already in an tokio runtime. + if let Ok(handle) = tokio::runtime::Handle::try_current() { + block_in_place(|| handle.block_on(fut)) + } else { + // Otherwise create a new runtime. + let rt = tokio::runtime::Runtime::new().expect("Failed to create a new runtime"); + rt.block_on(fut) + } +} diff --git a/crates/test-artifacts/programs/Cargo.lock b/crates/test-artifacts/programs/Cargo.lock index b404318c5a..94423f6aef 100644 --- a/crates/test-artifacts/programs/Cargo.lock +++ b/crates/test-artifacts/programs/Cargo.lock @@ -107,7 +107,7 @@ version = "1.1.0" dependencies = [ "common-test-utils", "sp1-curves", - "sp1-lib 3.0.0", + "sp1-lib 3.4.0", "sp1-zkvm", ] @@ -150,7 +150,7 @@ name = "bls12381-mul-test" version = "1.1.0" dependencies = [ "sp1-derive", - "sp1-lib 3.0.0", + "sp1-lib 3.4.0", "sp1-zkvm", ] @@ -160,7 +160,7 @@ version = "1.1.0" dependencies = [ "common-test-utils", "sp1-curves", - "sp1-lib 3.0.0", + "sp1-lib 3.4.0", "sp1-zkvm", ] @@ -203,7 +203,7 @@ name = "bn254-mul-test" version = "1.1.0" dependencies = [ "sp1-derive", - "sp1-lib 3.0.0", + "sp1-lib 3.4.0", "sp1-zkvm", ] @@ -245,7 +245,7 @@ name = "common-test-utils" version = "1.1.0" dependencies = [ "num-bigint", - "sp1-lib 3.0.0", + "sp1-lib 3.4.0", ] [[package]] @@ -341,21 +341,6 @@ dependencies = [ "typenum", ] -[[package]] -name = "curve25519-dalek" -version = "4.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" -dependencies = [ - "cfg-if", - "cpufeatures", - "curve25519-dalek-derive 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "fiat-crypto", - "rustc_version", - "subtle", - "zeroize", -] - [[package]] name = "curve25519-dalek" version = "4.1.3" @@ -364,7 +349,7 @@ dependencies = [ "anyhow", "cfg-if", "cpufeatures", - "curve25519-dalek-derive 0.1.1 (git+https://github.com/sp1-patches/curve25519-dalek?branch=patch-curve25519-v4.1.3)", + "curve25519-dalek-derive", "digest 0.10.7", "fiat-crypto", "rustc_version", @@ -373,17 +358,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "curve25519-dalek-derive" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.87", -] - [[package]] name = "curve25519-dalek-derive" version = "0.1.1" @@ -613,7 +587,7 @@ name = "ed25519-dalek" version = "2.1.1" source = "git+https://github.com/sp1-patches/curve25519-dalek?branch=patch-curve25519-v4.1.3#1d73fd95f1a76bee8f46643cf78bbccc1fb06ede" dependencies = [ - "curve25519-dalek 4.1.3 (git+https://github.com/sp1-patches/curve25519-dalek?branch=patch-curve25519-v4.1.3)", + "curve25519-dalek", "ed25519", "serde", "sha2 0.10.8", @@ -1634,7 +1608,7 @@ version = "1.1.0" dependencies = [ "common-test-utils", "sp1-curves", - "sp1-lib 3.0.0", + "sp1-lib 3.4.0", "sp1-zkvm", ] @@ -1670,7 +1644,7 @@ dependencies = [ "num", "p256", "sp1-curves", - "sp1-lib 3.0.0", + "sp1-lib 3.4.0", "sp1-zkvm", ] @@ -1691,7 +1665,7 @@ dependencies = [ "num", "p256", "sp1-curves", - "sp1-lib 3.0.0", + "sp1-lib 3.4.0", "sp1-zkvm", ] @@ -1832,10 +1806,9 @@ dependencies = [ [[package]] name = "sp1-curves" -version = "3.0.0" +version = "3.4.0" dependencies = [ "cfg-if", - "curve25519-dalek 4.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "dashu", "elliptic-curve 0.13.8", "generic-array 1.1.0", @@ -1853,7 +1826,7 @@ dependencies = [ [[package]] name = "sp1-derive" -version = "3.0.0" +version = "3.4.0" dependencies = [ "quote", "syn 1.0.109", @@ -1875,7 +1848,9 @@ dependencies = [ [[package]] name = "sp1-lib" -version = "3.0.0" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1aa18834c58df127706eb2fb2ea6e2892dbf0361d6b2485bf7b3fbd5f8b8c3c" dependencies = [ "bincode", "serde", @@ -1883,9 +1858,7 @@ dependencies = [ [[package]] name = "sp1-lib" -version = "3.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1aa18834c58df127706eb2fb2ea6e2892dbf0361d6b2485bf7b3fbd5f8b8c3c" +version = "3.4.0" dependencies = [ "bincode", "serde", @@ -1893,7 +1866,7 @@ dependencies = [ [[package]] name = "sp1-primitives" -version = "3.0.0" +version = "3.4.0" dependencies = [ "bincode", "hex", @@ -1909,7 +1882,7 @@ dependencies = [ [[package]] name = "sp1-stark" -version = "3.0.0" +version = "3.4.0" dependencies = [ "arrayref", "hashbrown 0.14.5", @@ -1941,7 +1914,7 @@ dependencies = [ [[package]] name = "sp1-zkvm" -version = "3.0.1" +version = "3.4.0" dependencies = [ "cfg-if", "getrandom", @@ -1951,7 +1924,7 @@ dependencies = [ "p3-field", "rand", "sha2 0.10.8", - "sp1-lib 3.0.0", + "sp1-lib 3.4.0", "sp1-primitives", ] diff --git a/crates/verifier/Cargo.toml b/crates/verifier/Cargo.toml index c2b861b16d..d3f76c92b3 100644 --- a/crates/verifier/Cargo.toml +++ b/crates/verifier/Cargo.toml @@ -12,17 +12,10 @@ categories = { workspace = true } [dependencies] bn = { version = "0.6.0", package = "substrate-bn-succinct" } sha2 = { version = "0.10.8", default-features = false } -thiserror = { version = "2", default-features = false } +thiserror-no-std = "2.0.2" hex = { version = "0.4.3", default-features = false, features = ["alloc"] } lazy_static = { version = "1.5.0", default-features = false } -# arkworks -ark-bn254 = { version = "0.4.0", optional = true } -ark-serialize = { version = "0.4.2", optional = true } -ark-ff = { version = "0.4.2", optional = true } -ark-groth16 = { version = "0.4.0", optional = true } -ark-ec = { version = "0.4.0", optional = true } - [dev-dependencies] sp1-sdk = { workspace = true } num-bigint = "0.4.6" @@ -30,5 +23,4 @@ num-traits = "0.2.19" [features] default = ["std"] -std = ["thiserror/std"] -ark = ["ark-bn254", "ark-serialize", "ark-ff", "ark-groth16", "ark-ec"] +std = ["thiserror-no-std/std"] \ No newline at end of file diff --git a/crates/verifier/src/error.rs b/crates/verifier/src/error.rs index 1f30633fde..2d37bceac9 100644 --- a/crates/verifier/src/error.rs +++ b/crates/verifier/src/error.rs @@ -1,5 +1,5 @@ use bn::{CurveError, FieldError, GroupError}; -use thiserror::Error; +use thiserror_no_std::Error; #[derive(Error, Debug)] pub enum Error { diff --git a/crates/verifier/src/groth16/converter.rs b/crates/verifier/src/groth16/converter.rs index 6648eb95c9..6c7a5e3b97 100644 --- a/crates/verifier/src/groth16/converter.rs +++ b/crates/verifier/src/groth16/converter.rs @@ -13,7 +13,7 @@ use super::error::Groth16Error; /// Load the Groth16 proof from the given byte slice. /// /// The byte slice is represented as 2 uncompressed g1 points, and one uncompressed g2 point, -/// as outputted from Gnark. +/// as outputted from gnark. pub(crate) fn load_groth16_proof_from_bytes(buffer: &[u8]) -> Result { let ar = uncompressed_bytes_to_g1_point(&buffer[..64])?; let bs = uncompressed_bytes_to_g2_point(&buffer[64..192])?; diff --git a/crates/verifier/src/groth16/error.rs b/crates/verifier/src/groth16/error.rs index 18d8e2dcbe..36952cb749 100644 --- a/crates/verifier/src/groth16/error.rs +++ b/crates/verifier/src/groth16/error.rs @@ -1,4 +1,4 @@ -use thiserror::Error; +use thiserror_no_std::Error; #[derive(Debug, Error)] pub enum Groth16Error { diff --git a/crates/verifier/src/groth16/mod.rs b/crates/verifier/src/groth16/mod.rs index 9075d6491b..c6cf98a23a 100644 --- a/crates/verifier/src/groth16/mod.rs +++ b/crates/verifier/src/groth16/mod.rs @@ -2,25 +2,19 @@ mod converter; pub mod error; mod verify; -use bn::Fr; pub(crate) use converter::{load_groth16_proof_from_bytes, load_groth16_verifying_key_from_bytes}; +use sha2::{Digest, Sha256}; pub(crate) use verify::*; use error::Groth16Error; -use crate::{decode_sp1_vkey_hash, error::Error, hash_public_inputs}; - -use alloc::vec::Vec; -use sha2::{Digest, Sha256}; - -#[cfg(feature = "ark")] -pub mod ark_converter; +use crate::{bn254_public_values, decode_sp1_vkey_hash, error::Error}; /// A verifier for Groth16 zero-knowledge proofs. #[derive(Debug)] pub struct Groth16Verifier; impl Groth16Verifier { - /// Verifies an SP1 Groth16 proof, as generated by the SP1 SDK. + /// Verifies a Groth16 proof. /// /// # Arguments /// @@ -63,48 +57,11 @@ impl Groth16Verifier { } let sp1_vkey_hash = decode_sp1_vkey_hash(sp1_vkey_hash)?; + let public_inputs = bn254_public_values(&sp1_vkey_hash, sp1_public_inputs); - Self::verify_gnark_proof( - &proof[4..], - &[sp1_vkey_hash, hash_public_inputs(sp1_public_inputs)], - groth16_vk, - ) - } - - /// Verifies a Gnark Groth16 proof using raw byte inputs. - /// - /// WARNING: if you're verifying an SP1 proof, you should use [`verify`] instead. - /// This is a lower-level verification method that works directly with raw bytes rather than - /// the SP1 SDK's data structures. - /// - /// # Arguments - /// - /// * `proof` - The raw Groth16 proof bytes (without the 4-byte vkey hash prefix) - /// * `public_inputs` - The public inputs to the circuit - /// * `groth16_vk` - The Groth16 verifying key bytes - /// - /// # Returns - /// - /// A [`Result`] containing unit `()` if the proof is valid, - /// or a [`Groth16Error`] if verification fails. - /// - /// # Note - /// - /// This method expects the raw proof bytes without the 4-byte vkey hash prefix that - /// [`verify`] checks. If you have a complete proof with the prefix, use [`verify`] instead. - pub fn verify_gnark_proof( - proof: &[u8], - public_inputs: &[[u8; 32]], - groth16_vk: &[u8], - ) -> Result<(), Groth16Error> { - let proof = load_groth16_proof_from_bytes(proof)?; + let proof = load_groth16_proof_from_bytes(&proof[4..])?; let groth16_vk = load_groth16_verifying_key_from_bytes(groth16_vk)?; - let public_inputs = public_inputs - .iter() - .map(|input| Fr::from_slice(input)) - .collect::, bn::FieldError>>() - .map_err(|_| Groth16Error::GeneralError(Error::InvalidData))?; - verify_groth16_algebraic(&groth16_vk, &proof, &public_inputs) + verify_groth16_raw(&groth16_vk, &proof, &public_inputs) } } diff --git a/crates/verifier/src/groth16/verify.rs b/crates/verifier/src/groth16/verify.rs index 636a7f66d6..686e62ff61 100644 --- a/crates/verifier/src/groth16/verify.rs +++ b/crates/verifier/src/groth16/verify.rs @@ -46,11 +46,11 @@ fn prepare_inputs(vk: Groth16VerifyingKey, public_inputs: &[Fr]) -> Result Result<(), PlonkError> { let plonk_vk = load_plonk_verifying_key_from_bytes(plonk_vk)?; - let proof = load_plonk_proof_from_bytes(proof, plonk_vk.qcp.len())?; + let proof = load_plonk_proof_from_bytes(&proof[4..], plonk_vk.qcp.len())?; - let public_inputs = public_inputs - .iter() - .map(|input| Fr::from_slice(input)) - .collect::, bn::FieldError>>() - .map_err(|_| PlonkError::GeneralError(Error::InvalidData))?; - verify_plonk_algebraic(&plonk_vk, &proof, &public_inputs) + verify_plonk_raw(&plonk_vk, &proof, &public_inputs) } } diff --git a/crates/verifier/src/plonk/verify.rs b/crates/verifier/src/plonk/verify.rs index 6da0872d6e..4cfbcc884f 100644 --- a/crates/verifier/src/plonk/verify.rs +++ b/crates/verifier/src/plonk/verify.rs @@ -33,7 +33,7 @@ pub(crate) struct PlonkVerifyingKey { pub(crate) commitment_constraint_indexes: Vec, } -/// Verifies a PLONK proof using algebraic inputs. +/// Verifies a PLONK proof /// /// # Arguments /// @@ -44,7 +44,7 @@ pub(crate) struct PlonkVerifyingKey { /// # Returns /// /// * `Result` - Returns true if the proof is valid, or an error if verification fails -pub(crate) fn verify_plonk_algebraic( +pub(crate) fn verify_plonk_raw( vk: &PlonkVerifyingKey, proof: &PlonkProof, public_inputs: &[Fr], diff --git a/crates/verifier/src/tests.rs b/crates/verifier/src/tests.rs index c6d9a853c6..3cda26694a 100644 --- a/crates/verifier/src/tests.rs +++ b/crates/verifier/src/tests.rs @@ -1,6 +1,9 @@ use sp1_sdk::{install::try_install_circuit_artifacts, SP1ProofWithPublicValues}; +extern crate std; + #[test] +#[ignore] fn test_verify_groth16() { // Location of the serialized SP1ProofWithPublicValues. See README.md for more information. let proof_file = "test_binaries/fibonacci-groth16.bin"; @@ -19,6 +22,7 @@ fn test_verify_groth16() { } #[test] +#[ignore] fn test_verify_plonk() { // Location of the serialized SP1ProofWithPublicValues. See README.md for more information. let proof_file = "test_binaries/fibonacci-plonk.bin"; @@ -37,6 +41,7 @@ fn test_verify_plonk() { } #[test] +#[ignore] fn test_vkeys() { let groth16_path = try_install_circuit_artifacts("groth16"); let s3_vkey_path = groth16_path.join("groth16_vk.bin"); @@ -48,35 +53,3 @@ fn test_vkeys() { let s3_vkey_bytes = std::fs::read(s3_vkey_path).unwrap(); assert_eq!(s3_vkey_bytes, *crate::PLONK_VK_BYTES); } - -#[test] -#[cfg(feature = "ark")] -fn test_ark_groth16() { - use ark_bn254::Bn254; - use ark_groth16::{r1cs_to_qap::LibsnarkReduction, Groth16}; - - use crate::{decode_sp1_vkey_hash, groth16::ark_converter::*, hash_public_inputs}; - - // Location of the serialized SP1ProofWithPublicValues. See README.md for more information. - let proof_file = "test_binaries/fibonacci-groth16.bin"; - - // Load the saved proof and extract the proof and public inputs. - let sp1_proof_with_public_values = SP1ProofWithPublicValues::load(proof_file).unwrap(); - - let proof = sp1_proof_with_public_values.bytes(); - let public_inputs = sp1_proof_with_public_values.public_values.to_vec(); - - // This vkey hash was derived by calling `vk.bytes32()` on the verifying key. - let vkey_hash = "0x00e60860c07bfc6e4c480286c0ddbb879674eb47f84b4ef041cf858b17aa0ed1"; - - let proof = load_ark_proof_from_bytes(&proof[4..]).unwrap(); - let vkey = load_ark_groth16_verifying_key_from_bytes(&crate::GROTH16_VK_BYTES).unwrap(); - - let public_inputs = load_ark_public_inputs_from_bytes( - &decode_sp1_vkey_hash(vkey_hash).unwrap(), - &hash_public_inputs(&public_inputs), - ); - - Groth16::::verify_proof(&vkey.into(), &proof, &public_inputs) - .unwrap(); -} diff --git a/crates/zkvm/entrypoint/Cargo.toml b/crates/zkvm/entrypoint/Cargo.toml index e38600efd9..180f657881 100644 --- a/crates/zkvm/entrypoint/Cargo.toml +++ b/crates/zkvm/entrypoint/Cargo.toml @@ -2,7 +2,7 @@ name = "sp1-zkvm" description = "SP1 is a performant, 100% open-source, contributor-friendly zkVM." readme = "../../../README.md" -version = "3.0.1" +version = "3.4.0" edition = { workspace = true } license = { workspace = true } repository = { workspace = true } diff --git a/crates/zkvm/lib/src/io.rs b/crates/zkvm/lib/src/io.rs index 94a92a602c..cc59cee8e3 100644 --- a/crates/zkvm/lib/src/io.rs +++ b/crates/zkvm/lib/src/io.rs @@ -16,6 +16,12 @@ pub const FD_HINT: u32 = 4; pub const K1_ECRECOVER_HOOK: u32 = 5; pub const R1_ECRECOVER_HOOK: u32 = 6; +/// The file descriptor through which to access `hook_ecrecover_2`. +pub const FD_ECRECOVER_HOOK_2: u32 = 7; + +/// The file descriptor through which to access `hook_ed_decompress`. +pub const FD_EDDECOMPRESS: u32 = 8; + /// A writer that writes to a file descriptor inside the zkVM. struct SyscallWriter { fd: u32, diff --git a/examples/Cargo.lock b/examples/Cargo.lock index 05d23d23a0..7e8cbf164b 100644 --- a/examples/Cargo.lock +++ b/examples/Cargo.lock @@ -68,9 +68,9 @@ dependencies = [ [[package]] name = "allocator-api2" -version = "0.2.18" +version = "0.2.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c6cb57a04249c6480766f7f7cef5467412af1490f8d1e243141daddada3264f" +checksum = "45862d1c77f2228b9e10bc609d5bc203d86ebc9b87ad8d5d5167a6c9abf739d9" [[package]] name = "alloy-chains" @@ -78,7 +78,7 @@ version = "0.1.47" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "18c5c520273946ecf715c0010b4e3503d7eba9893cd9ce6b7fff5654c4a3c470" dependencies = [ - "alloy-primitives 0.8.11", + "alloy-primitives 0.8.14", "alloy-rlp", "num_enum 0.7.3", "serde", @@ -92,7 +92,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "629b62e38d471cc15fea534eb7283d2f8a4e8bdb1811bcc5d66dda6cfce6fae1" dependencies = [ "alloy-eips 0.3.6", - "alloy-primitives 0.8.11", + "alloy-primitives 0.8.14", "alloy-rlp", "alloy-serde 0.3.6", "c-kzg", @@ -106,7 +106,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41ed961a48297c732a5d97ee321aa8bb5009ecadbcb077d8bec90cb54e651629" dependencies = [ "alloy-eips 0.5.4", - "alloy-primitives 0.8.11", + "alloy-primitives 0.8.14", "alloy-rlp", "alloy-serde 0.5.4", "auto_impl", @@ -121,7 +121,7 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0069cf0642457f87a01a014f6dc29d5d893cd4fd8fddf0c3cdfad1bb3ebafc41" dependencies = [ - "alloy-primitives 0.8.11", + "alloy-primitives 0.8.14", "alloy-rlp", "serde", ] @@ -132,7 +132,7 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ea59dc42102bc9a1905dc57901edc6dd48b9f38115df86c7d252acba70d71d04" dependencies = [ - "alloy-primitives 0.8.11", + "alloy-primitives 0.8.14", "alloy-rlp", "k256", "serde", @@ -144,7 +144,7 @@ version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "64ffc577390ce50234e02d841214b3dc0bea6aaaae8e04bbf3cb82e9a45da9eb" dependencies = [ - "alloy-primitives 0.8.11", + "alloy-primitives 0.8.14", "alloy-rlp", "derive_more 1.0.0", "serde", @@ -158,7 +158,7 @@ checksum = "f923dd5fca5f67a43d81ed3ebad0880bd41f6dd0ada930030353ac356c54cd0f" dependencies = [ "alloy-eip2930", "alloy-eip7702 0.1.1", - "alloy-primitives 0.8.11", + "alloy-primitives 0.8.14", "alloy-rlp", "alloy-serde 0.3.6", "c-kzg", @@ -176,7 +176,7 @@ checksum = "b69e06cf9c37be824b9d26d6d101114fdde6af0c87de2828b414c05c4b3daa71" dependencies = [ "alloy-eip2930", "alloy-eip7702 0.3.2", - "alloy-primitives 0.8.11", + "alloy-primitives 0.8.14", "alloy-rlp", "alloy-serde 0.5.4", "c-kzg", @@ -192,18 +192,18 @@ version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3a7a18afb0b318616b6b2b0e2e7ac5529d32a966c673b48091c9919e284e6aca" dependencies = [ - "alloy-primitives 0.8.11", + "alloy-primitives 0.8.14", "alloy-serde 0.3.6", "serde", ] [[package]] name = "alloy-json-abi" -version = "0.8.11" +version = "0.8.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ded610181f3dad5810f6ff12d1a99994cf9b42d2fcb7709029352398a5da5ae6" +checksum = "ac4b22b3e51cac09fd2adfcc73b55f447b4df669f983c13f7894ec82b607c63f" dependencies = [ - "alloy-primitives 0.8.11", + "alloy-primitives 0.8.14", "alloy-sol-type-parser", "serde", "serde_json", @@ -215,11 +215,11 @@ version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af5979e0d5a7bf9c7eb79749121e8256e59021af611322aee56e77e20776b4b3" dependencies = [ - "alloy-primitives 0.8.11", + "alloy-primitives 0.8.14", "alloy-sol-types", "serde", "serde_json", - "thiserror 1.0.68", + "thiserror 1.0.69", "tracing", ] @@ -233,7 +233,7 @@ dependencies = [ "alloy-eips 0.5.4", "alloy-json-rpc", "alloy-network-primitives 0.5.4", - "alloy-primitives 0.8.11", + "alloy-primitives 0.8.14", "alloy-rpc-types-eth 0.5.4", "alloy-serde 0.5.4", "alloy-signer", @@ -241,7 +241,7 @@ dependencies = [ "async-trait", "auto_impl", "futures-utils-wasm", - "thiserror 1.0.68", + "thiserror 1.0.69", ] [[package]] @@ -251,7 +251,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "94ad40869867ed2d9cd3842b1e800889e5b49e6b92da346e93862b4a741bedf3" dependencies = [ "alloy-eips 0.3.6", - "alloy-primitives 0.8.11", + "alloy-primitives 0.8.14", "alloy-serde 0.3.6", "serde", ] @@ -264,7 +264,7 @@ checksum = "514f70ee2a953db21631cd817b13a1571474ec77ddc03d47616d5e8203489fde" dependencies = [ "alloy-consensus 0.5.4", "alloy-eips 0.5.4", - "alloy-primitives 0.8.11", + "alloy-primitives 0.8.14", "alloy-serde 0.5.4", "serde", ] @@ -293,9 +293,9 @@ dependencies = [ [[package]] name = "alloy-primitives" -version = "0.8.11" +version = "0.8.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd58d377699e6cfeab52c4a9d28bdc4ef37e2bd235ff2db525071fe37a2e9af5" +checksum = "9db948902dfbae96a73c2fbf1f7abec62af034ab883e4c777c3fd29702bd6e2c" dependencies = [ "alloy-rlp", "bytes", @@ -304,7 +304,7 @@ dependencies = [ "derive_more 1.0.0", "foldhash", "getrandom", - "hashbrown 0.15.1", + "hashbrown 0.15.2", "hex-literal", "indexmap 2.6.0", "itoa", @@ -339,7 +339,7 @@ checksum = "2b09cae092c27b6f1bde952653a22708691802e57bfef4a2973b80bea21efd3f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -362,7 +362,7 @@ dependencies = [ "alloy-consensus 0.3.6", "alloy-eips 0.3.6", "alloy-network-primitives 0.3.6", - "alloy-primitives 0.8.11", + "alloy-primitives 0.8.14", "alloy-rlp", "alloy-serde 0.3.6", "alloy-sol-types", @@ -383,7 +383,7 @@ dependencies = [ "alloy-consensus 0.5.4", "alloy-eips 0.5.4", "alloy-network-primitives 0.5.4", - "alloy-primitives 0.8.11", + "alloy-primitives 0.8.14", "alloy-rlp", "alloy-serde 0.5.4", "alloy-sol-types", @@ -399,7 +399,7 @@ version = "0.3.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "731f75ec5d383107fd745d781619bd9cedf145836c51ecb991623d41278e71fa" dependencies = [ - "alloy-primitives 0.8.11", + "alloy-primitives 0.8.14", "serde", "serde_json", ] @@ -410,7 +410,7 @@ version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "028e72eaa9703e4882344983cfe7636ce06d8cce104a78ea62fd19b46659efc4" dependencies = [ - "alloy-primitives 0.8.11", + "alloy-primitives 0.8.14", "serde", "serde_json", ] @@ -421,12 +421,12 @@ version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "592c185d7100258c041afac51877660c7bf6213447999787197db4842f0e938e" dependencies = [ - "alloy-primitives 0.8.11", + "alloy-primitives 0.8.14", "async-trait", "auto_impl", "elliptic-curve", "k256", - "thiserror 1.0.68", + "thiserror 1.0.69", ] [[package]] @@ -437,33 +437,33 @@ checksum = "6614f02fc1d5b079b2a4a5320018317b506fd0a6d67c1fd5542a71201724986c" dependencies = [ "alloy-consensus 0.5.4", "alloy-network", - "alloy-primitives 0.8.11", + "alloy-primitives 0.8.14", "alloy-signer", "async-trait", "k256", "rand 0.8.5", - "thiserror 1.0.68", + "thiserror 1.0.69", ] [[package]] name = "alloy-sol-macro" -version = "0.8.11" +version = "0.8.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a1b42ac8f45e2f49f4bcdd72cbfde0bb148f5481d403774ffa546e48b83efc1" +checksum = "3bfd7853b65a2b4f49629ec975fee274faf6dff15ab8894c620943398ef283c0" dependencies = [ "alloy-sol-macro-expander", "alloy-sol-macro-input", "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] name = "alloy-sol-macro-expander" -version = "0.8.11" +version = "0.8.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06318f1778e57f36333e850aa71bd1bb5e560c10279e236622faae0470c50412" +checksum = "82ec42f342d9a9261699f8078e57a7a4fda8aaa73c1a212ed3987080e6a9cd13" dependencies = [ "alloy-sol-macro-input", "const-hex", @@ -472,31 +472,31 @@ dependencies = [ "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", "syn-solidity", "tiny-keccak", ] [[package]] name = "alloy-sol-macro-input" -version = "0.8.11" +version = "0.8.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eaebb9b0ad61a41345a22c9279975c0cdd231b97947b10d7aad1cf0a7181e4a5" +checksum = "ed2c50e6a62ee2b4f7ab3c6d0366e5770a21cad426e109c2f40335a1b3aff3df" dependencies = [ "const-hex", "dunce", "heck", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", "syn-solidity", ] [[package]] name = "alloy-sol-type-parser" -version = "0.8.11" +version = "0.8.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12c71028bfbfec210e24106a542aad3def7caf1a70e2c05710e92a98481980d3" +checksum = "ac17c6e89a50fb4a758012e4b409d9a0ba575228e69b539fe37d7a1bd507ca4a" dependencies = [ "serde", "winnow 0.6.20", @@ -504,12 +504,12 @@ dependencies = [ [[package]] name = "alloy-sol-types" -version = "0.8.11" +version = "0.8.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "374d7fb042d68ddfe79ccb23359de3007f6d4d53c13f703b64fb0db422132111" +checksum = "c9dc0fffe397aa17628160e16b89f704098bf3c9d74d5d369ebc239575936de5" dependencies = [ "alloy-json-abi", - "alloy-primitives 0.8.11", + "alloy-primitives 0.8.14", "alloy-sol-macro", "const-hex", "serde", @@ -521,7 +521,7 @@ version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0a46c9c4fdccda7982e7928904bd85fe235a0404ee3d7e197fff13d61eac8b4f" dependencies = [ - "alloy-primitives 0.8.11", + "alloy-primitives 0.8.14", "alloy-rlp", "derive_more 1.0.0", "hashbrown 0.14.5", @@ -752,6 +752,28 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" +[[package]] +name = "async-stream" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" +dependencies = [ + "async-stream-impl", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-stream-impl" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + [[package]] name = "async-trait" version = "0.1.83" @@ -760,9 +782,15 @@ checksum = "721cae7de5c34fbb2acd27e21e6d2cf7b886dce0c27388d46c4e6c47ea4318dd" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + [[package]] name = "aurora-engine-modexp" version = "1.1.0" @@ -781,7 +809,7 @@ checksum = "3c87f3f15e7794432337fc718554eaa4dc8f04c9677a950ffe366f20a162ae42" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -792,9 +820,9 @@ checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26" [[package]] name = "axum" -version = "0.7.7" +version = "0.7.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "504e3947307ac8326a5437504c517c4b56716c9d98fac0028c2acc7ca47d70ae" +checksum = "edca88bc138befd0323b20752846e6587272d3b03b0343c8ea28a6f819e6e71f" dependencies = [ "async-trait", "axum-core", @@ -816,9 +844,9 @@ dependencies = [ "serde_json", "serde_path_to_error", "serde_urlencoded", - "sync_wrapper 1.0.1", + "sync_wrapper 1.0.2", "tokio", - "tower", + "tower 0.5.1", "tower-layer", "tower-service", "tracing", @@ -839,12 +867,26 @@ dependencies = [ "mime", "pin-project-lite", "rustversion", - "sync_wrapper 1.0.1", + "sync_wrapper 1.0.2", "tower-layer", "tower-service", "tracing", ] +[[package]] +name = "backoff" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b62ddb9cb1ec0a098ad4bbf9344d0713fa193ae1a80af55febcff2627b6a00c1" +dependencies = [ + "futures-core", + "getrandom", + "instant", + "pin-project-lite", + "rand 0.8.5", + "tokio", +] + [[package]] name = "backtrace" version = "0.3.74" @@ -911,7 +953,7 @@ dependencies = [ "regex", "rustc-hash 1.1.0", "shlex", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -1031,7 +1073,7 @@ dependencies = [ "group 0.13.0", "pairing 0.23.0", "rand_core 0.6.4", - "sp1-lib 3.1.0", + "sp1-lib 3.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "subtle", ] @@ -1078,9 +1120,9 @@ checksum = "c3ac9f8b63eca6fd385229b3675f6cc0dc5c8a5c8a54a59d4f52ffd670d87b0c" [[package]] name = "bytemuck" -version = "1.19.0" +version = "1.20.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8334215b81e418a0a7bdb8ef0849474f40bb10c8b71f1c4ed315cff49f32494d" +checksum = "8b37c88a63ffd85d15b406896cc343916d7cf57838a847b3a6f2ca5d39a5695a" dependencies = [ "bytemuck_derive", ] @@ -1093,7 +1135,7 @@ checksum = "bcfcc3cd946cb52f0bbfdbbcfa2f4e24f75ebb6c0e1002f7c25904fada18b9ec" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -1104,9 +1146,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.8.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ac0150caa2ae65ca5bd83f25c7de183dea78d4d366469f148435e2acfbad0da" +checksum = "325918d6fe32f23b19878fe4b34794ae41fc19ddbe53b10571a4874d44ffd39b" dependencies = [ "serde", ] @@ -1137,9 +1179,9 @@ dependencies = [ [[package]] name = "cargo-platform" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24b1f0365a6c6bb4020cd05806fd0d33c44d38046b8bd7f0e40814b9763cabfc" +checksum = "e35af189006b9c0f00a064685c727031e3ed2d8020f7ba284d78cc2671bd36ea" dependencies = [ "serde", ] @@ -1155,14 +1197,14 @@ dependencies = [ "semver 1.0.23", "serde", "serde_json", - "thiserror 1.0.68", + "thiserror 1.0.69", ] [[package]] name = "cc" -version = "1.1.36" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baee610e9452a8f6f0a1b6194ec09ff9e2d85dea54432acdae41aa0761c95d70" +checksum = "f34d93e62b03caf570cccc334cbc6c2fceca82f39211051345108adcba3eebdc" dependencies = [ "jobserver", "libc", @@ -1244,9 +1286,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.20" +version = "4.5.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97f376d85a664d5837dbae44bf546e6477a679ff6610010f17276f686d867e8" +checksum = "fb3b4b9e5a7c7514dfa52869339ee98b3156b0bfb4e8a77c4ff4babb64b1604f" dependencies = [ "clap_builder", "clap_derive", @@ -1254,9 +1296,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.20" +version = "4.5.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19bc80abd44e4bed93ca373a0704ccbd1b710dc5749406201bb018272808dc54" +checksum = "b17a95aa67cc7b5ebd32aa5370189aa0d79069ef1c64ce893bd30fb24bff20ec" dependencies = [ "anstream", "anstyle", @@ -1273,14 +1315,14 @@ dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] name = "clap_lex" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" +checksum = "afb84c814227b90d6895e01398aee0d8033c00e7466aca416fb6a8e0eb19d8a7" [[package]] name = "colorchoice" @@ -1297,15 +1339,15 @@ dependencies = [ "encode_unicode", "lazy_static", "libc", - "unicode-width", + "unicode-width 0.1.14", "windows-sys 0.52.0", ] [[package]] name = "const-hex" -version = "1.13.1" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0121754e84117e65f9d90648ee6aa4882a6e63110307ab73967a4c5e7e69e586" +checksum = "4b0485bab839b018a8f1723fc5391819fea5f8f0f32288ef8a735fd096b6160c" dependencies = [ "cfg-if", "cpufeatures", @@ -1347,6 +1389,16 @@ dependencies = [ "unicode-segmentation", ] +[[package]] +name = "core-foundation" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b55271e5c8c478ad3f38ad24ef34923091e0548492a266d19b3c0b4d82574c63" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "core-foundation-sys" version = "0.8.7" @@ -1355,9 +1407,9 @@ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "cpufeatures" -version = "0.2.14" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0" +checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3" dependencies = [ "libc", ] @@ -1377,6 +1429,15 @@ version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "19d374276b40fb8bbdee95aef7c7fa6b5316ec764510eb64b8dd0e2ed0d7e7f5" +[[package]] +name = "crossbeam-channel" +version = "0.5.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06ba6d68e24814cb8de6bb986db8222d3a027d15872cabc0d18817bc3c0e4471" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "crossbeam-deque" version = "0.8.5" @@ -1453,7 +1514,7 @@ dependencies = [ [[package]] name = "curve25519-dalek" version = "4.1.3" -source = "git+https://github.com/sp1-patches/curve25519-dalek?tag=curve25519_dalek-v4.1.3-patch-v1#dbdd0ffeea0ff767affc3f6765d1edbdaa9e2cb9" +source = "git+https://github.com/sp1-patches/curve25519-dalek?tag=patch-v4.1.3-v3.4.0#bfe63b8205f0b6baa0c1f4c71da33209f766e3e4" dependencies = [ "anyhow", "cfg-if", @@ -1462,7 +1523,7 @@ dependencies = [ "digest 0.10.7", "fiat-crypto", "rustc_version 0.4.1", - "sp1-lib 3.1.0", + "sp1-lib 3.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "subtle", "zeroize", ] @@ -1470,11 +1531,11 @@ dependencies = [ [[package]] name = "curve25519-dalek-derive" version = "0.1.1" -source = "git+https://github.com/sp1-patches/curve25519-dalek?tag=curve25519_dalek-v4.1.3-patch-v1#dbdd0ffeea0ff767affc3f6765d1edbdaa9e2cb9" +source = "git+https://github.com/sp1-patches/curve25519-dalek?tag=patch-v4.1.3-v3.4.0#bfe63b8205f0b6baa0c1f4c71da33209f766e3e4" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -1487,7 +1548,7 @@ dependencies = [ "cfg-if", "digest 0.9.0", "rand_core 0.6.4", - "sp1-lib 3.1.0", + "sp1-lib 3.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "subtle-ng", "zeroize", ] @@ -1502,7 +1563,7 @@ dependencies = [ "cfg-if", "digest 0.9.0", "rand_core 0.6.4", - "sp1-lib 3.1.0", + "sp1-lib 3.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "subtle-ng", "zeroize", ] @@ -1544,7 +1605,7 @@ dependencies = [ "proc-macro2", "quote", "strsim", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -1555,7 +1616,7 @@ checksum = "d336a2a514f6ccccaa3e09b02d41d35330c07ddf03a62165fcec10bb561c7806" dependencies = [ "darling_core", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -1636,15 +1697,6 @@ dependencies = [ "rustversion", ] -[[package]] -name = "debugid" -version = "0.8.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef552e6f588e446098f6ba40d89ac146c8c7b64aade83c051ee00bb5d2bc18d" -dependencies = [ - "uuid", -] - [[package]] name = "der" version = "0.5.1" @@ -1698,7 +1750,7 @@ dependencies = [ "proc-macro2", "quote", "rustc_version 0.4.1", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -1719,7 +1771,7 @@ dependencies = [ "convert_case 0.6.0", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", "unicode-xid", ] @@ -1773,7 +1825,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -1819,7 +1871,7 @@ dependencies = [ "elliptic-curve", "hex-literal", "signature", - "sp1-lib 3.1.0", + "sp1-lib 3.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "spki 0.7.3", ] @@ -1843,7 +1895,7 @@ dependencies = [ "rand_core 0.6.4", "serde", "sha2 0.9.9", - "thiserror 1.0.68", + "thiserror 1.0.69", "zeroize", ] @@ -1933,7 +1985,7 @@ checksum = "f282cfdfe92516eb26c2af8589c274c7c17681f5ecc03c18255fe741c6aa64eb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -1944,7 +1996,7 @@ checksum = "2f9ed6b3789237c8a0c1c505af1c7eb2c560df6186f01b098c3a1064ea532f38" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -1955,12 +2007,12 @@ checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "errno" -version = "0.3.9" +version = "0.3.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +checksum = "33d852cb9b869c2a9b3df2f71a3074817f01e1844f839a144f5fcef059a4eb5d" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -1997,9 +2049,9 @@ dependencies = [ [[package]] name = "fastrand" -version = "2.1.1" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8c02a5121d4ea3eb16a80748c74f5549a5665e4c21333c6098f283870fbdea6" +checksum = "486f806e73c5707928240ddc295403b1b93c96a02038563881c4a2fd84b81ac4" [[package]] name = "fastrlp" @@ -2178,7 +2230,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -2223,17 +2275,6 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d758ba1b47b00caf47f24925c0074ecb20d6dfcffe7f6d53395c0465674841a" -[[package]] -name = "gecko_profile" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "890852c7e1e02bc6758e325d6b1e0236e4fbf21b492f585ce4d4715be54b4c6a" -dependencies = [ - "debugid", - "serde", - "serde_json", -] - [[package]] name = "generic-array" version = "0.14.7" @@ -2247,9 +2288,9 @@ dependencies = [ [[package]] name = "generic-array" -version = "1.1.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96512db27971c2c3eece70a1e106fbe6c87760234e31e8f7e5634912fe52794a" +checksum = "2cb8bc4c28d15ade99c7e90b219f30da4be5c88e586277e8cbe886beeb868ab2" dependencies = [ "serde", "typenum", @@ -2262,8 +2303,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", + "js-sys", "libc", "wasi", + "wasm-bindgen", ] [[package]] @@ -2291,17 +2334,6 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" -[[package]] -name = "goblin" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b363a30c165f666402fe6a3024d3bec7ebc898f96a4a23bd1c99f8dbf3f4f47" -dependencies = [ - "log", - "plain", - "scroll", -] - [[package]] name = "groth16-verifier-program" version = "1.1.0" @@ -2341,6 +2373,25 @@ dependencies = [ "subtle", ] +[[package]] +name = "h2" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccae279728d634d083c00f6099cb58f01cc99c145b84b8be2f6c74618d79922e" +dependencies = [ + "atomic-waker", + "bytes", + "fnv", + "futures-core", + "futures-sink", + "http", + "indexmap 2.6.0", + "slab", + "tokio", + "tokio-util", + "tracing", +] + [[package]] name = "half" version = "1.8.3" @@ -2389,9 +2440,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.1" +version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a9bfc1af68b1726ea47d3d5109de126281def866b33970e10fbab11b5dafab3" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" dependencies = [ "allocator-api2", "equivalent", @@ -2483,13 +2534,14 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "hyper" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbbff0a806a4728c99295b254c8838933b5b082d75e3cb70c8dab21fdfbcfa9a" +checksum = "97818827ef4f364230e16705d4706e2897df2bb60617d6ca15d598025a3c481f" dependencies = [ "bytes", "futures-channel", "futures-util", + "h2", "http", "http-body", "httparse", @@ -2519,6 +2571,19 @@ dependencies = [ "webpki-roots", ] +[[package]] +name = "hyper-timeout" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b90d566bffbce6a75bd8b09a05aa8c2cb1fabb6cb348f8840c9e4c90a0d83b0" +dependencies = [ + "hyper", + "hyper-util", + "pin-project-lite", + "tokio", + "tower-service", +] + [[package]] name = "hyper-util" version = "0.1.10" @@ -2676,7 +2741,7 @@ checksum = "1ec89e9337638ecdc08744df490b221a7399bf8d164eb52a665454e60e075ad6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -2717,13 +2782,13 @@ dependencies = [ [[package]] name = "impl-trait-for-tuples" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11d7a9f6330b71fea57921c9b61c47ee6e84f72d394754eff6163ae67e7395eb" +checksum = "a0eb5a3343abf848c0984fe4604b2b105da9539376e24fc0a3b0007411ae4fd9" dependencies = [ "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.90", ] [[package]] @@ -2750,21 +2815,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "707907fe3c25f5424cce2cb7e1cbcafee6bdbe735ca90ef77c29e84591e5b9da" dependencies = [ "equivalent", - "hashbrown 0.15.1", + "hashbrown 0.15.2", "serde", ] [[package]] name = "indicatif" -version = "0.17.8" +version = "0.17.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "763a5a8f45087d6bcea4222e7b72c291a054edf80e4ef6efd2a4979878c7bea3" +checksum = "cbf675b85ed934d3c67b5c5469701eec7db22689d0a2139d856e0925fa28b281" dependencies = [ "console", - "instant", "number_prefix", "portable-atomic", - "unicode-width", + "unicode-width 0.2.0", + "web-time", ] [[package]] @@ -2849,9 +2914,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.11" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" +checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" [[package]] name = "jobserver" @@ -2864,9 +2929,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.72" +version = "0.3.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a88f1bda2bd75b0452a14784937d796722fdebfe50df998aeb3f0b7603019a9" +checksum = "fb15147158e79fd8b8afd0252522769c4f48725460b37338544d8379d94fc8f9" dependencies = [ "wasm-bindgen", ] @@ -2968,9 +3033,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.161" +version = "0.2.167" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e9489c2807c139ffd9c1794f4af0ebe86a828db53ecdc7fea2111d0fed085d1" +checksum = "09d6582e104315a817dff97f75133544b2e094ee22447d2acf4a74e189ba06fc" [[package]] name = "libgit2-sys" @@ -2986,9 +3051,9 @@ dependencies = [ [[package]] name = "libloading" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" +checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34" dependencies = [ "cfg-if", "windows-targets 0.52.6", @@ -3030,9 +3095,9 @@ checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" [[package]] name = "litemap" -version = "0.7.3" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "643cb0b8d4fcc284004d5fd0d67ccf61dfffadb7f75e1e71bc420f4688a3a704" +checksum = "4ee93343901ab17bd981295f2cf0026d4ad018c7c31ba84549a4ddbb47a45104" [[package]] name = "lock_api" @@ -3056,7 +3121,7 @@ version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "234cf4f4a04dc1f57e24b96cc0cd600cf2af460d4161ac5ecdd0af8e1f3b2a38" dependencies = [ - "hashbrown 0.15.1", + "hashbrown 0.15.2", ] [[package]] @@ -3109,11 +3174,10 @@ dependencies = [ [[package]] name = "mio" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80e04d1dcff3aae0704555fe5fee3bcfaf3d1fdf8a7e521d5b9d2b42acb52cec" +checksum = "2886843bf800fba2e3377cff24abf6379b4c4d5c6681eaf9ea5b0d15090450bd" dependencies = [ - "hermit-abi", "libc", "wasi", "windows-sys 0.52.0", @@ -3268,7 +3332,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -3375,7 +3439,7 @@ checksum = "af1844ef2428cc3e1cb900be36181049ef3d3193c63e43026cfe202983b27a56" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -3429,7 +3493,7 @@ checksum = "21aad1fbf80d2bcd7406880efc7ba109365f44bbb72896758ddcbfa46bf1592c" dependencies = [ "alloy-consensus 0.3.6", "alloy-eips 0.3.6", - "alloy-primitives 0.8.11", + "alloy-primitives 0.8.14", "alloy-rlp", "alloy-serde 0.3.6", "derive_more 1.0.0", @@ -3445,7 +3509,7 @@ checksum = "e281fbfc2198b7c0c16457d6524f83d192662bc9f3df70f24c3038d4521616df" dependencies = [ "alloy-eips 0.3.6", "alloy-network-primitives 0.3.6", - "alloy-primitives 0.8.11", + "alloy-primitives 0.8.14", "alloy-rpc-types-eth 0.3.6", "alloy-serde 0.3.6", "cfg-if", @@ -3461,6 +3525,12 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + [[package]] name = "option-ext" version = "0.2.0" @@ -3488,7 +3558,7 @@ dependencies = [ [[package]] name = "p3-air" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3?branch=sp1-v4#db3d45d4ec899efaf8f7234a8573f285fbdda5db" +source = "git+https://github.com/Plonky3/Plonky3?branch=sp1-v4#bba88386261c3eaceb7f922b99bea56c1d6c6c58" dependencies = [ "p3-field", "p3-matrix", @@ -3497,7 +3567,7 @@ dependencies = [ [[package]] name = "p3-baby-bear" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3?branch=sp1-v4#db3d45d4ec899efaf8f7234a8573f285fbdda5db" +source = "git+https://github.com/Plonky3/Plonky3?branch=sp1-v4#bba88386261c3eaceb7f922b99bea56c1d6c6c58" dependencies = [ "num-bigint 0.4.6", "p3-field", @@ -3511,7 +3581,7 @@ dependencies = [ [[package]] name = "p3-bn254-fr" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3?branch=sp1-v4#db3d45d4ec899efaf8f7234a8573f285fbdda5db" +source = "git+https://github.com/Plonky3/Plonky3?branch=sp1-v4#bba88386261c3eaceb7f922b99bea56c1d6c6c58" dependencies = [ "ff 0.13.0", "num-bigint 0.4.6", @@ -3525,7 +3595,7 @@ dependencies = [ [[package]] name = "p3-challenger" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3?branch=sp1-v4#db3d45d4ec899efaf8f7234a8573f285fbdda5db" +source = "git+https://github.com/Plonky3/Plonky3?branch=sp1-v4#bba88386261c3eaceb7f922b99bea56c1d6c6c58" dependencies = [ "p3-field", "p3-maybe-rayon", @@ -3538,7 +3608,7 @@ dependencies = [ [[package]] name = "p3-commit" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3?branch=sp1-v4#db3d45d4ec899efaf8f7234a8573f285fbdda5db" +source = "git+https://github.com/Plonky3/Plonky3?branch=sp1-v4#bba88386261c3eaceb7f922b99bea56c1d6c6c58" dependencies = [ "itertools 0.12.1", "p3-challenger", @@ -3551,7 +3621,7 @@ dependencies = [ [[package]] name = "p3-dft" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3?branch=sp1-v4#db3d45d4ec899efaf8f7234a8573f285fbdda5db" +source = "git+https://github.com/Plonky3/Plonky3?branch=sp1-v4#bba88386261c3eaceb7f922b99bea56c1d6c6c58" dependencies = [ "p3-field", "p3-matrix", @@ -3563,7 +3633,7 @@ dependencies = [ [[package]] name = "p3-field" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3?branch=sp1-v4#db3d45d4ec899efaf8f7234a8573f285fbdda5db" +source = "git+https://github.com/Plonky3/Plonky3?branch=sp1-v4#bba88386261c3eaceb7f922b99bea56c1d6c6c58" dependencies = [ "itertools 0.12.1", "num-bigint 0.4.6", @@ -3576,7 +3646,7 @@ dependencies = [ [[package]] name = "p3-fri" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3?branch=sp1-v4#db3d45d4ec899efaf8f7234a8573f285fbdda5db" +source = "git+https://github.com/Plonky3/Plonky3?branch=sp1-v4#bba88386261c3eaceb7f922b99bea56c1d6c6c58" dependencies = [ "itertools 0.12.1", "p3-challenger", @@ -3594,7 +3664,7 @@ dependencies = [ [[package]] name = "p3-interpolation" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3?branch=sp1-v4#db3d45d4ec899efaf8f7234a8573f285fbdda5db" +source = "git+https://github.com/Plonky3/Plonky3?branch=sp1-v4#bba88386261c3eaceb7f922b99bea56c1d6c6c58" dependencies = [ "p3-field", "p3-matrix", @@ -3604,7 +3674,7 @@ dependencies = [ [[package]] name = "p3-keccak-air" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3?branch=sp1-v4#db3d45d4ec899efaf8f7234a8573f285fbdda5db" +source = "git+https://github.com/Plonky3/Plonky3?branch=sp1-v4#bba88386261c3eaceb7f922b99bea56c1d6c6c58" dependencies = [ "p3-air", "p3-field", @@ -3617,7 +3687,7 @@ dependencies = [ [[package]] name = "p3-matrix" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3?branch=sp1-v4#db3d45d4ec899efaf8f7234a8573f285fbdda5db" +source = "git+https://github.com/Plonky3/Plonky3?branch=sp1-v4#bba88386261c3eaceb7f922b99bea56c1d6c6c58" dependencies = [ "itertools 0.12.1", "p3-field", @@ -3631,7 +3701,7 @@ dependencies = [ [[package]] name = "p3-maybe-rayon" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3?branch=sp1-v4#db3d45d4ec899efaf8f7234a8573f285fbdda5db" +source = "git+https://github.com/Plonky3/Plonky3?branch=sp1-v4#bba88386261c3eaceb7f922b99bea56c1d6c6c58" dependencies = [ "rayon", ] @@ -3639,7 +3709,7 @@ dependencies = [ [[package]] name = "p3-mds" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3?branch=sp1-v4#db3d45d4ec899efaf8f7234a8573f285fbdda5db" +source = "git+https://github.com/Plonky3/Plonky3?branch=sp1-v4#bba88386261c3eaceb7f922b99bea56c1d6c6c58" dependencies = [ "itertools 0.12.1", "p3-dft", @@ -3653,7 +3723,7 @@ dependencies = [ [[package]] name = "p3-merkle-tree" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3?branch=sp1-v4#db3d45d4ec899efaf8f7234a8573f285fbdda5db" +source = "git+https://github.com/Plonky3/Plonky3?branch=sp1-v4#bba88386261c3eaceb7f922b99bea56c1d6c6c58" dependencies = [ "itertools 0.12.1", "p3-commit", @@ -3669,7 +3739,7 @@ dependencies = [ [[package]] name = "p3-poseidon2" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3?branch=sp1-v4#db3d45d4ec899efaf8f7234a8573f285fbdda5db" +source = "git+https://github.com/Plonky3/Plonky3?branch=sp1-v4#bba88386261c3eaceb7f922b99bea56c1d6c6c58" dependencies = [ "gcd", "p3-field", @@ -3682,7 +3752,7 @@ dependencies = [ [[package]] name = "p3-symmetric" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3?branch=sp1-v4#db3d45d4ec899efaf8f7234a8573f285fbdda5db" +source = "git+https://github.com/Plonky3/Plonky3?branch=sp1-v4#bba88386261c3eaceb7f922b99bea56c1d6c6c58" dependencies = [ "itertools 0.12.1", "p3-field", @@ -3692,7 +3762,7 @@ dependencies = [ [[package]] name = "p3-uni-stark" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3?branch=sp1-v4#db3d45d4ec899efaf8f7234a8573f285fbdda5db" +source = "git+https://github.com/Plonky3/Plonky3?branch=sp1-v4#bba88386261c3eaceb7f922b99bea56c1d6c6c58" dependencies = [ "itertools 0.12.1", "p3-air", @@ -3710,7 +3780,7 @@ dependencies = [ [[package]] name = "p3-util" version = "0.1.0" -source = "git+https://github.com/Plonky3/Plonky3?branch=sp1-v4#db3d45d4ec899efaf8f7234a8573f285fbdda5db" +source = "git+https://github.com/Plonky3/Plonky3?branch=sp1-v4#bba88386261c3eaceb7f922b99bea56c1d6c6c58" dependencies = [ "serde", ] @@ -3735,28 +3805,29 @@ dependencies = [ [[package]] name = "parity-scale-codec" -version = "3.6.12" +version = "3.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "306800abfa29c7f16596b5970a588435e3d5b3149683d00c12b699cc19f895ee" +checksum = "8be4817d39f3272f69c59fe05d0535ae6456c2dc2fa1ba02910296c7e0a5c590" dependencies = [ "arrayvec 0.7.6", "bitvec", "byte-slice-cast", "impl-trait-for-tuples", "parity-scale-codec-derive", + "rustversion", "serde", ] [[package]] name = "parity-scale-codec-derive" -version = "3.6.12" +version = "3.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d830939c76d294956402033aee57a6da7b438f2294eb94864c37b0569053a42c" +checksum = "8781a75c6205af67215f382092b6e0a4ff3734798523e69073d4bcd294ec767b" dependencies = [ "proc-macro-crate 3.2.0", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.90", ] [[package]] @@ -3822,7 +3893,7 @@ checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" name = "patch-testing-program" version = "1.1.0" dependencies = [ - "alloy-primitives 0.8.11", + "alloy-primitives 0.8.14", "curve25519-dalek", "curve25519-dalek-ng 4.1.1 (git+https://github.com/sp1-patches/curve25519-dalek-ng?tag=curve25519_dalek_ng-v4.1.1-patch-v1)", "ed25519-consensus", @@ -3877,10 +3948,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "879952a81a83930934cbf1786752d6dedc3b1f29e8f8fb2ad1d0a36f377cf442" dependencies = [ "memchr", - "thiserror 1.0.68", + "thiserror 1.0.69", "ucd-trie", ] +[[package]] +name = "pin-project" +version = "1.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be57f64e946e500c8ee36ef6331845d40a93055567ec57e8fae13efd33759b95" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c0f5fad0874fc7abcd4d750e76917eaebbecaa2c20bde22e1dbeeba8beb758c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.90", +] + [[package]] name = "pin-project-lite" version = "0.2.15" @@ -3942,17 +4033,11 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "953ec861398dccce10c670dfeaf3ec4911ca479e9c02154b3a215178c5f566f2" -[[package]] -name = "plain" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" - [[package]] name = "portable-atomic" -version = "1.9.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc9c68a3f6da06753e9335d63e27f6b9754dd1920d941135b7ea8224f141adb2" +checksum = "280dc24453071f1b63954171985a0b0d30058d287960968b9b2aca264c8d4ee6" [[package]] name = "powerfmt" @@ -3976,7 +4061,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "64d1ec885c64d0457d564db4ec299b2dae3f9c02808b8ad9c3a089c591b18033" dependencies = [ "proc-macro2", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -4037,14 +4122,14 @@ dependencies = [ "proc-macro-error-attr2", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] name = "proc-macro2" -version = "1.0.89" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f139b0662de085916d1fb67d2b4169d1addddda1919e696f3252b740b629986e" +checksum = "37d3544b3f2748c54e147655edb5025752e2303145b5aefb3c3ea2c78b973bb0" dependencies = [ "unicode-ident", ] @@ -4099,7 +4184,7 @@ dependencies = [ "itertools 0.12.1", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -4112,7 +4197,7 @@ dependencies = [ "itertools 0.13.0", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -4132,9 +4217,9 @@ checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" [[package]] name = "quinn" -version = "0.11.5" +version = "0.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c7c5fdde3cdae7203427dc4f0a68fe0ed09833edc525a03456b153b79828684" +checksum = "62e96808277ec6f97351a2380e6c25114bc9e67037775464979f3037c92d05ef" dependencies = [ "bytes", "pin-project-lite", @@ -4143,26 +4228,29 @@ dependencies = [ "rustc-hash 2.0.0", "rustls", "socket2", - "thiserror 1.0.68", + "thiserror 2.0.3", "tokio", "tracing", ] [[package]] name = "quinn-proto" -version = "0.11.8" +version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fadfaed2cd7f389d0161bb73eeb07b7b78f8691047a6f3e73caaeae55310a4a6" +checksum = "a2fe5ef3495d7d2e377ff17b1a8ce2ee2ec2a18cde8b6ad6619d65d0701c135d" dependencies = [ "bytes", + "getrandom", "rand 0.8.5", "ring", "rustc-hash 2.0.0", "rustls", + "rustls-pki-types", "slab", - "thiserror 1.0.68", + "thiserror 2.0.3", "tinyvec", "tracing", + "web-time", ] [[package]] @@ -4326,7 +4414,7 @@ checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" dependencies = [ "getrandom", "libredox", - "thiserror 1.0.68", + "thiserror 1.0.69", ] [[package]] @@ -4337,7 +4425,7 @@ checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.8", + "regex-automata 0.4.9", "regex-syntax 0.8.5", ] @@ -4352,9 +4440,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.8" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ "aho-corasick", "memchr", @@ -4419,7 +4507,7 @@ dependencies = [ "serde", "serde_json", "serde_urlencoded", - "sync_wrapper 1.0.1", + "sync_wrapper 1.0.2", "tokio", "tokio-rustls", "tokio-util", @@ -4444,7 +4532,7 @@ dependencies = [ "http", "reqwest", "serde", - "thiserror 1.0.68", + "thiserror 1.0.69", "tower-service", ] @@ -4457,7 +4545,7 @@ dependencies = [ "reth-execution-errors", "reth-primitives", "reth-storage-errors", - "thiserror 1.0.68", + "thiserror 1.0.69", ] [[package]] @@ -4468,7 +4556,7 @@ dependencies = [ "alloy-chains", "alloy-eips 0.3.6", "alloy-genesis", - "alloy-primitives 0.8.11", + "alloy-primitives 0.8.14", "alloy-trie", "auto_impl", "derive_more 1.0.0", @@ -4490,7 +4578,7 @@ dependencies = [ "alloy-consensus 0.3.6", "alloy-eips 0.3.6", "alloy-genesis", - "alloy-primitives 0.8.11", + "alloy-primitives 0.8.14", "alloy-trie", "bytes", "modular-bitfield", @@ -4506,7 +4594,7 @@ dependencies = [ "convert_case 0.6.0", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -4551,7 +4639,7 @@ dependencies = [ "reth-execution-errors", "reth-fs-util", "reth-storage-errors", - "thiserror 1.0.68", + "thiserror 1.0.69", ] [[package]] @@ -4572,7 +4660,7 @@ version = "1.0.6" source = "git+https://github.com/sp1-patches/reth?tag=rsp-20240830#260c7ed2c9374182a43a3602aaa953d37aa9217b" dependencies = [ "alloy-chains", - "alloy-primitives 0.8.11", + "alloy-primitives 0.8.14", "alloy-rlp", "auto_impl", "crc", @@ -4635,7 +4723,7 @@ dependencies = [ "reth-revm", "revm", "revm-primitives", - "thiserror 1.0.68", + "thiserror 1.0.69", "tracing", ] @@ -4645,7 +4733,7 @@ version = "1.0.6" source = "git+https://github.com/sp1-patches/reth?tag=rsp-20240830#260c7ed2c9374182a43a3602aaa953d37aa9217b" dependencies = [ "alloy-eips 0.3.6", - "alloy-primitives 0.8.11", + "alloy-primitives 0.8.14", "alloy-rlp", "derive_more 1.0.0", "nybbles", @@ -4674,7 +4762,7 @@ source = "git+https://github.com/sp1-patches/reth?tag=rsp-20240830#260c7ed2c9374 dependencies = [ "serde", "serde_json", - "thiserror 1.0.68", + "thiserror 1.0.69", ] [[package]] @@ -4682,11 +4770,11 @@ name = "reth-network-peers" version = "1.0.6" source = "git+https://github.com/sp1-patches/reth?tag=rsp-20240830#260c7ed2c9374182a43a3602aaa953d37aa9217b" dependencies = [ - "alloy-primitives 0.8.11", + "alloy-primitives 0.8.14", "alloy-rlp", "enr", "serde_with", - "thiserror 1.0.68", + "thiserror 1.0.69", "url", ] @@ -4696,7 +4784,7 @@ version = "1.0.6" source = "git+https://github.com/sp1-patches/reth?tag=rsp-20240830#260c7ed2c9374182a43a3602aaa953d37aa9217b" dependencies = [ "alloy-chains", - "alloy-primitives 0.8.11", + "alloy-primitives 0.8.14", "derive_more 1.0.0", "once_cell", "reth-chainspec", @@ -4725,7 +4813,7 @@ dependencies = [ "alloy-consensus 0.3.6", "alloy-eips 0.3.6", "alloy-genesis", - "alloy-primitives 0.8.11", + "alloy-primitives 0.8.14", "alloy-rlp", "alloy-rpc-types", "alloy-serde 0.3.6", @@ -4743,7 +4831,7 @@ dependencies = [ "reth-trie-common", "revm-primitives", "serde", - "thiserror 1.0.68", + "thiserror 1.0.69", ] [[package]] @@ -4754,7 +4842,7 @@ dependencies = [ "alloy-consensus 0.3.6", "alloy-eips 0.3.6", "alloy-genesis", - "alloy-primitives 0.8.11", + "alloy-primitives 0.8.14", "alloy-rlp", "alloy-rpc-types-eth 0.3.6", "byteorder", @@ -4772,13 +4860,13 @@ name = "reth-prune-types" version = "1.0.6" source = "git+https://github.com/sp1-patches/reth?tag=rsp-20240830#260c7ed2c9374182a43a3602aaa953d37aa9217b" dependencies = [ - "alloy-primitives 0.8.11", + "alloy-primitives 0.8.14", "bytes", "derive_more 1.0.0", "modular-bitfield", "reth-codecs", "serde", - "thiserror 1.0.68", + "thiserror 1.0.69", ] [[package]] @@ -4801,7 +4889,7 @@ name = "reth-stages-types" version = "1.0.6" source = "git+https://github.com/sp1-patches/reth?tag=rsp-20240830#260c7ed2c9374182a43a3602aaa953d37aa9217b" dependencies = [ - "alloy-primitives 0.8.11", + "alloy-primitives 0.8.14", "bytes", "modular-bitfield", "reth-codecs", @@ -4814,7 +4902,7 @@ name = "reth-static-file-types" version = "1.0.6" source = "git+https://github.com/sp1-patches/reth?tag=rsp-20240830#260c7ed2c9374182a43a3602aaa953d37aa9217b" dependencies = [ - "alloy-primitives 0.8.11", + "alloy-primitives 0.8.14", "derive_more 1.0.0", "serde", "strum", @@ -4873,7 +4961,7 @@ source = "git+https://github.com/sp1-patches/reth?tag=rsp-20240830#260c7ed2c9374 dependencies = [ "alloy-consensus 0.3.6", "alloy-genesis", - "alloy-primitives 0.8.11", + "alloy-primitives 0.8.14", "alloy-rlp", "alloy-trie", "bytes", @@ -4938,7 +5026,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e7a6bff9dbde3370a5ac9555104117f7e6039b3cc76e8d5d9d01899088beca2a" dependencies = [ "alloy-eips 0.3.6", - "alloy-primitives 0.8.11", + "alloy-primitives 0.8.14", "auto_impl", "bitflags", "bitvec", @@ -4998,9 +5086,9 @@ dependencies = [ [[package]] name = "roaring" -version = "0.10.6" +version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f4b84ba6e838ceb47b41de5194a60244fac43d9fe03b71dbe8c5a201081d6d1" +checksum = "f81dc953b2244ddd5e7860cb0bb2a790494b898ef321d4aff8e260efab60cc88" dependencies = [ "bytemuck", "byteorder", @@ -5039,9 +5127,9 @@ dependencies = [ [[package]] name = "rsa" -version = "0.9.6" +version = "0.9.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d0e5124fcb30e76a7e79bfee683a2746db83784b86289f6251b54b7950a0dfc" +checksum = "47c75d7c5c6b673e58bf54d8544a9f432e3a925b0e80f7cd3602ab5c50c55519" dependencies = [ "const-oid 0.9.6", "digest 0.10.7", @@ -5061,7 +5149,7 @@ dependencies = [ name = "rsa-program" version = "1.1.0" dependencies = [ - "rsa 0.9.6", + "rsa 0.9.7", "sha2 0.10.8", "sp1-zkvm", ] @@ -5080,7 +5168,7 @@ name = "rsp-client-executor" version = "0.1.0" source = "git+https://github.com/succinctlabs/rsp/?rev=3647076#3647076da6580e30384dd911a3fc50d4bcdb5bc1" dependencies = [ - "alloy-primitives 0.8.11", + "alloy-primitives 0.8.14", "alloy-rlp", "eyre", "futures", @@ -5113,7 +5201,7 @@ name = "rsp-mpt" version = "0.1.0" source = "git+https://github.com/succinctlabs/rsp/?rev=3647076#3647076da6580e30384dd911a3fc50d4bcdb5bc1" dependencies = [ - "alloy-primitives 0.8.11", + "alloy-primitives 0.8.14", "alloy-rlp", "alloy-rpc-types", "anyhow", @@ -5127,7 +5215,7 @@ dependencies = [ "rlp", "rsp-primitives", "serde", - "thiserror 1.0.68", + "thiserror 1.0.69", ] [[package]] @@ -5163,7 +5251,7 @@ dependencies = [ name = "rsp-script" version = "0.1.0" dependencies = [ - "alloy-primitives 0.8.11", + "alloy-primitives 0.8.14", "bincode", "clap", "rsp-client-executor", @@ -5260,9 +5348,9 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.39" +version = "0.38.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "375116bee2be9ed569afe2154ea6a99dfdffd257f533f187498c2a8f5feaf4ee" +checksum = "d7f649912bc1495e167a6edee79151c84b1bad49748cb4f1f1167f459f6224f6" dependencies = [ "bitflags", "errno", @@ -5273,10 +5361,11 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.16" +version = "0.23.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eee87ff5d9b36712a58574e12e9f0ea80f915a5b0ac518d322b24a465617925e" +checksum = "934b404430bb06b3fae2cba809eb45a1ab1aecd64491213d7c3301b88393f8d1" dependencies = [ + "log", "once_cell", "ring", "rustls-pki-types", @@ -5285,6 +5374,18 @@ dependencies = [ "zeroize", ] +[[package]] +name = "rustls-native-certs" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcff2dd52b58a8d98a70243663a0d234c4e2b79235637849d15913394a247d3" +dependencies = [ + "openssl-probe", + "rustls-pki-types", + "schannel", + "security-framework", +] + [[package]] name = "rustls-pemfile" version = "2.2.0" @@ -5299,6 +5400,9 @@ name = "rustls-pki-types" version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "16f1201b3c9a7ee8039bcadc17b7e605e2945b27eee7631788c1bd2b0643674b" +dependencies = [ + "web-time", +] [[package]] name = "rustls-webpki" @@ -5337,9 +5441,9 @@ checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] name = "scale-info" -version = "2.11.5" +version = "2.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1aa7ffc1c0ef49b0452c6e2986abf2b07743320641ffd5fc63d552458e3b779b" +checksum = "346a3b32eba2640d17a9cb5927056b08f3de90f65b72fe09402c2ad07d684d0b" dependencies = [ "cfg-if", "derive_more 1.0.0", @@ -5349,50 +5453,39 @@ dependencies = [ [[package]] name = "scale-info-derive" -version = "2.11.5" +version = "2.11.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46385cc24172cf615450267463f937c10072516359b3ff1cb24228a4a08bf951" +checksum = "c6630024bf739e2179b91fb424b28898baf819414262c5d376677dbff1fe7ebf" dependencies = [ "proc-macro-crate 3.2.0", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] name = "scc" -version = "2.2.4" +version = "2.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8d25269dd3a12467afe2e510f69fb0b46b698e5afb296b59f2145259deaf8e8" +checksum = "66b202022bb57c049555430e11fc22fea12909276a80a4c3d368da36ac1d88ed" dependencies = [ "sdd", ] [[package]] -name = "scopeguard" -version = "1.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" - -[[package]] -name = "scroll" -version = "0.12.0" +name = "schannel" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ab8598aa408498679922eff7fa985c25d58a90771bd6be794434c5277eab1a6" +checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" dependencies = [ - "scroll_derive", + "windows-sys 0.59.0", ] [[package]] -name = "scroll_derive" -version = "0.12.0" +name = "scopeguard" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f81c2fde025af7e69b1d1420531c8a8811ca898919db177141a85313b1cb932" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.87", -] +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "sdd" @@ -5435,6 +5528,29 @@ dependencies = [ "cc", ] +[[package]] +name = "security-framework" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81d3f8c9bfcc3cbb6b0179eb57042d75b1582bdc65c3cb95f3fa999509c03cbc" +dependencies = [ + "bitflags", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1863fd3768cd83c56a7f60faa4dc0d403f1b6df0a38c3c25f44b7894e45370d5" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "semver" version = "0.11.0" @@ -5455,18 +5571,18 @@ dependencies = [ [[package]] name = "semver-parser" -version = "0.10.2" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7" +checksum = "9900206b54a3527fdc7b8a938bffd94a568bac4f4aa8113b209df75a09c0dec2" dependencies = [ "pest", ] [[package]] name = "serde" -version = "1.0.214" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f55c3193aca71c12ad7890f1785d2b73e1b9f63a0bbc353c08ef26fe03fc56b5" +checksum = "6513c1ad0b11a9376da888e3e0baa0077f1aed55c17f50e7b2397136129fb88f" dependencies = [ "serde_derive", ] @@ -5492,20 +5608,20 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.214" +version = "1.0.215" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de523f781f095e28fa605cdce0f8307e451cc0fd14e2eb4cd2e98a355b147766" +checksum = "ad1e866f866923f252f05c889987993144fb74e722403468a4ebd70c3cd756c0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] name = "serde_json" -version = "1.0.132" +version = "1.0.133" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d726bfaff4b320266d395898905d0eba0345aae23b54aee3a737e260fd46db03" +checksum = "c7fceb2473b9166b2294ef05efcb65a3db80803f0b03ef86a5fc88a2b85ee377" dependencies = [ "indexmap 2.6.0", "itoa", @@ -5532,7 +5648,7 @@ checksum = "6c64451ba24fc7a6a2d60fc75dd9c83c90903b19028d4eff35e88fc1e86564e9" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -5574,14 +5690,14 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] name = "serial_test" -version = "3.1.1" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b4b487fe2acf240a021cf57c6b2b4903b1e78ca0ecd862a71b71d2a51fed77d" +checksum = "1b258109f244e1d6891bf1053a55d63a5cd4f8f4c30cf9a1280989f80e7a1fa9" dependencies = [ "futures", "log", @@ -5593,13 +5709,13 @@ dependencies = [ [[package]] name = "serial_test_derive" -version = "3.1.1" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82fe9db325bcef1fbcde82e078a5cc4efdf787e96b3b9cf45b50b529f2083d67" +checksum = "5d69265a08751de7844521fd15003ae0a888e035773ba05695c5c759a6f89eef" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -5726,9 +5842,9 @@ dependencies = [ [[package]] name = "socket2" -version = "0.5.7" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" +checksum = "c970269d99b64e60ec3bd6ad27270092a5394c4e309314b18ae3fe575695fbe8" dependencies = [ "libc", "windows-sys 0.52.0", @@ -5736,7 +5852,7 @@ dependencies = [ [[package]] name = "sp1-build" -version = "3.0.0" +version = "3.4.0" dependencies = [ "anyhow", "cargo_metadata", @@ -5747,18 +5863,15 @@ dependencies = [ [[package]] name = "sp1-core-executor" -version = "3.0.0" +version = "3.4.0" dependencies = [ "bincode", "bytemuck", "elf", "enum-map", "eyre", - "gecko_profile", - "goblin", "hashbrown 0.14.5", "hex", - "indicatif", "itertools 0.13.0", "log", "nohash-hasher", @@ -5767,15 +5880,13 @@ dependencies = [ "p3-maybe-rayon", "rand 0.8.5", "rrs-succinct", - "rustc-demangle", "serde", - "serde_json", "sp1-curves", "sp1-primitives", "sp1-stark", "strum", "strum_macros", - "thiserror 1.0.68", + "thiserror 1.0.69", "tiny-keccak", "tracing", "typenum", @@ -5784,12 +5895,12 @@ dependencies = [ [[package]] name = "sp1-core-machine" -version = "3.0.0" +version = "3.4.0" dependencies = [ "bincode", "cfg-if", "elliptic-curve", - "generic-array 1.1.0", + "generic-array 1.1.1", "hashbrown 0.14.5", "hex", "itertools 0.13.0", @@ -5820,7 +5931,7 @@ dependencies = [ "strum", "strum_macros", "tempfile", - "thiserror 1.0.68", + "thiserror 1.0.69", "tracing", "tracing-forest", "tracing-subscriber", @@ -5830,7 +5941,7 @@ dependencies = [ [[package]] name = "sp1-cuda" -version = "3.0.0" +version = "3.4.0" dependencies = [ "bincode", "ctrlc", @@ -5845,13 +5956,12 @@ dependencies = [ [[package]] name = "sp1-curves" -version = "3.0.0" +version = "3.4.0" dependencies = [ "cfg-if", - "curve25519-dalek", "dashu", "elliptic-curve", - "generic-array 1.1.0", + "generic-array 1.1.1", "itertools 0.13.0", "k256", "num", @@ -5866,7 +5976,7 @@ dependencies = [ [[package]] name = "sp1-derive" -version = "3.0.0" +version = "3.4.0" dependencies = [ "quote", "syn 1.0.109", @@ -5888,7 +5998,7 @@ dependencies = [ [[package]] name = "sp1-lib" -version = "3.0.0" +version = "3.4.0" dependencies = [ "bincode", "serde", @@ -5896,9 +6006,9 @@ dependencies = [ [[package]] name = "sp1-lib" -version = "3.1.0" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14deb700469a37ec075bcf88dac3815b026dd9c4b9cb175980826f1fbb2e4e80" +checksum = "7a5729da1b05d56c01457e5ecabdc77f1cc941df23f2921163a2f325aec22428" dependencies = [ "bincode", "serde", @@ -5906,7 +6016,7 @@ dependencies = [ [[package]] name = "sp1-primitives" -version = "3.0.0" +version = "3.4.0" dependencies = [ "bincode", "hex", @@ -5922,7 +6032,7 @@ dependencies = [ [[package]] name = "sp1-prover" -version = "3.0.0" +version = "3.4.0" dependencies = [ "anyhow", "bincode", @@ -5950,14 +6060,15 @@ dependencies = [ "sp1-recursion-core", "sp1-recursion-gnark-ffi", "sp1-stark", - "thiserror 1.0.68", + "thiserror 1.0.69", "tracing", + "tracing-appender", "tracing-subscriber", ] [[package]] name = "sp1-recursion-circuit" -version = "3.0.0" +version = "3.4.0" dependencies = [ "hashbrown 0.14.5", "itertools 0.13.0", @@ -5989,7 +6100,7 @@ dependencies = [ [[package]] name = "sp1-recursion-compiler" -version = "3.0.0" +version = "3.4.0" dependencies = [ "backtrace", "itertools 0.13.0", @@ -6009,7 +6120,7 @@ dependencies = [ [[package]] name = "sp1-recursion-core" -version = "3.0.0" +version = "3.4.0" dependencies = [ "backtrace", "ff 0.13.0", @@ -6035,7 +6146,7 @@ dependencies = [ "sp1-primitives", "sp1-stark", "static_assertions", - "thiserror 1.0.68", + "thiserror 1.0.69", "tracing", "vec_map", "zkhash", @@ -6043,7 +6154,7 @@ dependencies = [ [[package]] name = "sp1-recursion-derive" -version = "3.0.0" +version = "3.4.0" dependencies = [ "quote", "syn 1.0.109", @@ -6051,7 +6162,7 @@ dependencies = [ [[package]] name = "sp1-recursion-gnark-ffi" -version = "3.0.0" +version = "3.4.0" dependencies = [ "anyhow", "bincode", @@ -6075,13 +6186,15 @@ dependencies = [ [[package]] name = "sp1-sdk" -version = "3.0.0" +version = "3.4.0" dependencies = [ + "alloy-primitives 0.8.14", "alloy-signer", "alloy-signer-local", "alloy-sol-types", "anyhow", "async-trait", + "backoff", "bincode", "cfg-if", "dirs", @@ -6098,6 +6211,7 @@ dependencies = [ "reqwest", "reqwest-middleware", "serde", + "serde_json", "sp1-build", "sp1-core-executor", "sp1-core-machine", @@ -6108,8 +6222,9 @@ dependencies = [ "strum", "strum_macros", "tempfile", - "thiserror 1.0.68", + "thiserror 1.0.69", "tokio", + "tonic", "tracing", "twirp-rs", "vergen", @@ -6117,7 +6232,7 @@ dependencies = [ [[package]] name = "sp1-stark" -version = "3.0.0" +version = "3.4.0" dependencies = [ "arrayref", "hashbrown 0.14.5", @@ -6149,7 +6264,7 @@ dependencies = [ [[package]] name = "sp1-verifier" -version = "3.0.0" +version = "3.4.0" dependencies = [ "hex", "lazy_static", @@ -6160,7 +6275,7 @@ dependencies = [ [[package]] name = "sp1-zkvm" -version = "3.0.1" +version = "3.4.0" dependencies = [ "cfg-if", "getrandom", @@ -6170,7 +6285,7 @@ dependencies = [ "p3-field", "rand 0.8.5", "sha2 0.10.8", - "sp1-lib 3.0.0", + "sp1-lib 3.4.0", "sp1-primitives", ] @@ -6302,7 +6417,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -6317,7 +6432,7 @@ dependencies = [ "lazy_static", "rand 0.8.5", "rustc-hex", - "sp1-lib 3.1.0", + "sp1-lib 3.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -6334,7 +6449,7 @@ dependencies = [ "num-bigint 0.4.6", "rand 0.8.5", "rustc-hex", - "sp1-lib 3.1.0", + "sp1-lib 3.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -6371,9 +6486,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.87" +version = "2.0.90" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25aa4ce346d03a6dcd68dd8b4010bcb74e54e62c90c573f394c46eae99aba32d" +checksum = "919d3b74a5dd0ccd15aeb8f93e7006bd9e14c295087c9896a110f490752bcf31" dependencies = [ "proc-macro2", "quote", @@ -6382,14 +6497,14 @@ dependencies = [ [[package]] name = "syn-solidity" -version = "0.8.11" +version = "0.8.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edf42e81491fb8871b74df3d222c64ae8cbc1269ea509fa768a3ed3e1b0ac8cb" +checksum = "da0523f59468a2696391f2a772edc089342aacd53c3caa2ac3264e598edf119b" dependencies = [ "paste", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -6400,9 +6515,9 @@ checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" [[package]] name = "sync_wrapper" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7065abeca94b6a8a577f9bd45aa0867a2238b74e8eb67cf10d492bc39351394" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" dependencies = [ "futures-core", ] @@ -6427,7 +6542,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -6453,9 +6568,9 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "tempfile" -version = "3.13.0" +version = "3.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0f2c9fc62d0beef6951ccffd757e241266a2c833136efbe35af6cd2567dca5b" +checksum = "28cce251fcbc87fac86a866eeb0d6c2d536fc16d06f184bb61aeae11aa4cee0c" dependencies = [ "cfg-if", "fastrand", @@ -6546,11 +6661,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.68" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02dd99dc800bbb97186339685293e1cc5d9df1f8fae2d0aecd9ff1c77efea892" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ - "thiserror-impl 1.0.68", + "thiserror-impl 1.0.69", ] [[package]] @@ -6564,13 +6679,13 @@ dependencies = [ [[package]] name = "thiserror-impl" -version = "1.0.68" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7c61ec9a6f64d2793d8a45faba21efbe3ced62a886d44c36a009b2b519b4c7e" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -6581,7 +6696,7 @@ checksum = "f077553d607adc1caf65430528a576c757a71ed73944b66ebb58ef2bbd243568" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -6692,9 +6807,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.41.0" +version = "1.41.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "145f3413504347a2be84393cc8a7d2fb4d863b375909ea59f2158261aa258bbb" +checksum = "22cfb5bee7a6a52939ca9224d6ac897bb669134078daa8735560897f69de4d33" dependencies = [ "backtrace", "bytes", @@ -6716,7 +6831,7 @@ checksum = "693d596312e88961bc67d7f1f97af8a70227d9f90c31bba5806eec004978d752" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -6730,6 +6845,17 @@ dependencies = [ "tokio", ] +[[package]] +name = "tokio-stream" +version = "0.1.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047" +dependencies = [ + "futures-core", + "pin-project-lite", + "tokio", +] + [[package]] name = "tokio-util" version = "0.7.12" @@ -6771,6 +6897,59 @@ dependencies = [ "winnow 0.6.20", ] +[[package]] +name = "tonic" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877c5b330756d856ffcc4553ab34a5684481ade925ecc54bcd1bf02b1d0d4d52" +dependencies = [ + "async-stream", + "async-trait", + "axum", + "base64 0.22.1", + "bytes", + "h2", + "http", + "http-body", + "http-body-util", + "hyper", + "hyper-timeout", + "hyper-util", + "percent-encoding", + "pin-project", + "prost 0.13.3", + "rustls-native-certs", + "rustls-pemfile", + "socket2", + "tokio", + "tokio-rustls", + "tokio-stream", + "tower 0.4.13", + "tower-layer", + "tower-service", + "tracing", +] + +[[package]] +name = "tower" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8fa9be0de6cf49e536ce1851f987bd21a43b771b09473c3549a6c853db37c1c" +dependencies = [ + "futures-core", + "futures-util", + "indexmap 1.9.3", + "pin-project", + "pin-project-lite", + "rand 0.8.5", + "slab", + "tokio", + "tokio-util", + "tower-layer", + "tower-service", + "tracing", +] + [[package]] name = "tower" version = "0.5.1" @@ -6801,9 +6980,9 @@ checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" -version = "0.1.40" +version = "0.1.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" dependencies = [ "log", "pin-project-lite", @@ -6811,22 +6990,34 @@ dependencies = [ "tracing-core", ] +[[package]] +name = "tracing-appender" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3566e8ce28cc0a3fe42519fc80e6b4c943cc4c8cef275620eb8dac2d3d4e06cf" +dependencies = [ + "crossbeam-channel", + "thiserror 1.0.69", + "time", + "tracing-subscriber", +] + [[package]] name = "tracing-attributes" -version = "0.1.27" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +checksum = "395ae124c09f9e6918a2310af6038fba074bcf474ac352496d5910dd59a2226d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] name = "tracing-core" -version = "0.1.32" +version = "0.1.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +checksum = "e672c95779cf947c5311f83787af4fa8fffd12fb27e4993211a84bdfd9610f9c" dependencies = [ "once_cell", "valuable", @@ -6840,7 +7031,7 @@ checksum = "ee40835db14ddd1e3ba414292272eddde9dad04d3d4b65509656414d1c42592f" dependencies = [ "ansi_term", "smallvec", - "thiserror 1.0.68", + "thiserror 1.0.69", "tracing", "tracing-subscriber", ] @@ -6858,9 +7049,9 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.18" +version = "0.3.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" +checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" dependencies = [ "matchers", "nu-ansi-term", @@ -6896,9 +7087,9 @@ dependencies = [ "reqwest", "serde", "serde_json", - "thiserror 1.0.68", + "thiserror 1.0.69", "tokio", - "tower", + "tower 0.5.1", "url", ] @@ -6934,9 +7125,9 @@ checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" [[package]] name = "unicode-ident" -version = "1.0.13" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e91b56cd4cadaeb79bbf1a5645f6b4f8dc5bde8834ad5894a8db35fda9efa1fe" +checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" [[package]] name = "unicode-segmentation" @@ -6950,6 +7141,12 @@ version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" +[[package]] +name = "unicode-width" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd" + [[package]] name = "unicode-xid" version = "0.2.6" @@ -6964,9 +7161,9 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "url" -version = "2.5.3" +version = "2.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d157f1b96d14500ffdc1f10ba712e780825526c03d9a49b4d0324b0d9113ada" +checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" dependencies = [ "form_urlencoded", "idna", @@ -6991,12 +7188,6 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" -[[package]] -name = "uuid" -version = "1.11.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8c5f0a0af699448548ad1a2fbf920fb4bee257eae39953ba95cb84891a0446a" - [[package]] name = "valuable" version = "0.1.0" @@ -7063,9 +7254,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.95" +version = "0.2.96" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "128d1e363af62632b8eb57219c8fd7877144af57558fb2ef0368d0087bddeb2e" +checksum = "21d3b25c3ea1126a2ad5f4f9068483c2af1e64168f847abe863a526b8dbfe00b" dependencies = [ "cfg-if", "once_cell", @@ -7074,36 +7265,37 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.95" +version = "0.2.96" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb6dd4d3ca0ddffd1dd1c9c04f94b868c37ff5fac97c30b97cff2d74fce3a358" +checksum = "52857d4c32e496dc6537646b5b117081e71fd2ff06de792e3577a150627db283" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.45" +version = "0.4.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc7ec4f8827a71586374db3e87abdb5a2bb3a15afed140221307c3ec06b1f63b" +checksum = "951fe82312ed48443ac78b66fa43eded9999f738f6022e67aead7b708659e49a" dependencies = [ "cfg-if", "js-sys", + "once_cell", "wasm-bindgen", "web-sys", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.95" +version = "0.2.96" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e79384be7f8f5a9dd5d7167216f022090cf1f9ec128e6e6a482a2cb5c5422c56" +checksum = "920b0ffe069571ebbfc9ddc0b36ba305ef65577c94b06262ed793716a1afd981" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -7111,22 +7303,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.95" +version = "0.2.96" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26c6ab57572f7a24a4985830b120de1594465e5d500f24afe89e16b4e833ef68" +checksum = "bf59002391099644be3524e23b781fa43d2be0c5aa0719a18c0731b9d195cab6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.95" +version = "0.2.96" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65fc09f10666a9f147042251e0dda9c18f166ff7de300607007e96bdebc1068d" +checksum = "e5047c5392700766601942795a436d7d2599af60dcc3cc1248c9120bfb0827b0" [[package]] name = "wasm-streams" @@ -7143,9 +7335,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.72" +version = "0.3.73" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6488b90108c040df0fe62fa815cbdee25124641df01814dd7282749234c6112" +checksum = "476364ff87d0ae6bfb661053a9104ab312542658c3d8f963b7ace80b6f9b26b9" dependencies = [ "js-sys", "wasm-bindgen", @@ -7163,9 +7355,9 @@ dependencies = [ [[package]] name = "webpki-roots" -version = "0.26.6" +version = "0.26.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "841c67bff177718f1d4dfefde8d8f0e78f9b6589319ba88312f567fc5841a958" +checksum = "5d642ff16b7e79272ae451b7322067cdc17cadf68c23264be9d94a32319efe7e" dependencies = [ "rustls-pki-types", ] @@ -7430,9 +7622,9 @@ dependencies = [ [[package]] name = "yoke" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c5b1314b079b0930c31e3af543d8ee1757b1951ae1e1565ec704403a7240ca5" +checksum = "120e6aef9aa629e3d4f52dc8cc43a015c7724194c97dfaf45180d2daf2b77f40" dependencies = [ "serde", "stable_deref_trait", @@ -7442,13 +7634,13 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28cc31741b18cb6f1d5ff12f5b7523e3d6eb0852bbbad19d73905511d9849b95" +checksum = "2380878cad4ac9aac1e2435f3eb4020e8374b5f13c296cb75b4620ff8e229154" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", "synstructure 0.13.1", ] @@ -7470,27 +7662,27 @@ checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] name = "zerofrom" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91ec111ce797d0e0784a1116d0ddcdbea84322cd79e5d5ad173daeba4f93ab55" +checksum = "cff3ee08c995dee1859d998dea82f7374f2826091dd9cd47def953cae446cd2e" dependencies = [ "zerofrom-derive", ] [[package]] name = "zerofrom-derive" -version = "0.1.4" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ea7b4a3637ea8669cedf0f1fd5c286a17f3de97b8dd5a70a6c167a1730e63a5" +checksum = "595eed982f7d355beb85837f651fa22e90b3c044842dc7f2c2842c086f295808" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", "synstructure 0.13.1", ] @@ -7511,7 +7703,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] @@ -7533,7 +7725,7 @@ checksum = "6eafa6dfb17584ea3e2bd6e76e0cc15ad7af12b09abdd1ca55961bed9b1063c6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.87", + "syn 2.0.90", ] [[package]] diff --git a/examples/Cargo.toml b/examples/Cargo.toml index d10ee9741e..73bcf63be5 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -66,7 +66,7 @@ serde_json = "1.0.132" tracing = "0.1.40" [patch.crates-io] -curve25519-dalek = { git = "https://github.com/sp1-patches/curve25519-dalek", tag = "curve25519_dalek-v4.1.3-patch-v1" } +curve25519-dalek = { git = "https://github.com/sp1-patches/curve25519-dalek", tag = "patch-v4.1.3-v3.4.0" } curve25519-dalek-ng = { git = "https://github.com/sp1-patches/curve25519-dalek-ng", tag = "curve25519_dalek_ng-v4.1.1-patch-v1" } ecdsa-core = { git = "https://github.com/sp1-patches/signatures", package = "ecdsa", branch = "umadayal/secp256r1" } ed25519-consensus = { git = "https://github.com/sp1-patches/ed25519-consensus", tag = "ed25519_consensus-v2.1.0-patch-v1" } diff --git a/examples/aggregation/script/src/main.rs b/examples/aggregation/script/src/main.rs index 9015cafcc2..2b1227d6c4 100644 --- a/examples/aggregation/script/src/main.rs +++ b/examples/aggregation/script/src/main.rs @@ -24,7 +24,7 @@ fn main() { sp1_sdk::utils::setup_logger(); // Initialize the proving client. - let client = ProverClient::new(); + let client = ProverClient::from_env(); // Setup the proving and verifying keys. let (aggregation_pk, _) = client.setup(AGGREGATION_ELF); diff --git a/examples/bls12381/script/src/main.rs b/examples/bls12381/script/src/main.rs index 385b04124a..7e6c02fd40 100644 --- a/examples/bls12381/script/src/main.rs +++ b/examples/bls12381/script/src/main.rs @@ -6,7 +6,7 @@ fn main() { let stdin = SP1Stdin::new(); - let client = ProverClient::new(); + let client = ProverClient::from_env(); let (_public_values, report) = client.execute(ELF, stdin).run().expect("failed to prove"); println!("executed: {}", report); diff --git a/examples/bn254/script/src/main.rs b/examples/bn254/script/src/main.rs index 4decb3a3f7..cd9c6e5057 100644 --- a/examples/bn254/script/src/main.rs +++ b/examples/bn254/script/src/main.rs @@ -6,7 +6,7 @@ fn main() { let stdin = SP1Stdin::new(); - let client = ProverClient::new(); + let client = ProverClient::from_env(); let (_public_values, report) = client.execute(ELF, stdin).run().expect("failed to prove"); println!("executed: {}", report); diff --git a/examples/chess/script/src/main.rs b/examples/chess/script/src/main.rs index 8026ddf454..3a1df33e50 100644 --- a/examples/chess/script/src/main.rs +++ b/examples/chess/script/src/main.rs @@ -13,7 +13,7 @@ fn main() { let san = "d4".to_string(); stdin.write(&san); - let client = ProverClient::new(); + let client = ProverClient::from_env(); let (pk, vk) = client.setup(ELF); let mut proof = client.prove(&pk, stdin).run().unwrap(); diff --git a/examples/cycle-tracking/script/src/main.rs b/examples/cycle-tracking/script/src/main.rs index 58da7f4e8f..03a76a80f2 100644 --- a/examples/cycle-tracking/script/src/main.rs +++ b/examples/cycle-tracking/script/src/main.rs @@ -9,7 +9,7 @@ fn main() { utils::setup_logger(); // Execute the normal program. - let client = ProverClient::new(); + let client = ProverClient::from_env(); let (_, _) = client.execute(NORMAL_ELF, SP1Stdin::new()).run().expect("proving failed"); // Execute the report program. @@ -17,5 +17,8 @@ fn main() { // Get the "setup" cycle count from the report program. let setup_cycles = report.cycle_tracker.get("setup").unwrap(); - println!("Using cycle-tracker-report saves the number of cycles to the cycle-tracker mapping in the report.\nHere's the number of cycles used by the setup: {}", setup_cycles); + println!( + "Using cycle-tracker-report saves the number of cycles to the cycle-tracker mapping in the report.\nHere's the number of cycles used by the setup: {}", + setup_cycles + ); } diff --git a/examples/elf/riscv32im-succinct-zkvm-elf b/examples/elf/riscv32im-succinct-zkvm-elf new file mode 100755 index 0000000000000000000000000000000000000000..dbd4cfab994c920e538d9c66156ee5d554547c41 GIT binary patch literal 145784 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

(y9F9F6tE2r&Hz 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 literal 0 HcmV?d00001 diff --git a/examples/fibonacci/script/bin/compressed.rs b/examples/fibonacci/script/bin/compressed.rs index 9261d092f8..632f9cd15f 100644 --- a/examples/fibonacci/script/bin/compressed.rs +++ b/examples/fibonacci/script/bin/compressed.rs @@ -13,7 +13,7 @@ fn main() { stdin.write(&n); // Generate the constant-sized proof for the given program and input. - let client = ProverClient::new(); + let client = ProverClient::from_env(); let (pk, vk) = client.setup(ELF); let mut proof = client.prove(&pk, stdin).compressed().run().unwrap(); diff --git a/examples/fibonacci/script/bin/execute.rs b/examples/fibonacci/script/bin/execute.rs index 5cf1efe1b2..7b92525a71 100644 --- a/examples/fibonacci/script/bin/execute.rs +++ b/examples/fibonacci/script/bin/execute.rs @@ -14,7 +14,7 @@ fn main() { stdin.write(&n); // Only execute the program and get a `SP1PublicValues` object. - let client = ProverClient::new(); + let client = ProverClient::from_env(); let (mut public_values, execution_report) = client.execute(ELF, stdin).run().unwrap(); // Print the total number of cycles executed and the full execution report with a breakdown of diff --git a/examples/fibonacci/script/bin/groth16_bn254.rs b/examples/fibonacci/script/bin/groth16_bn254.rs index 06d5b0b95f..98e9fa96af 100644 --- a/examples/fibonacci/script/bin/groth16_bn254.rs +++ b/examples/fibonacci/script/bin/groth16_bn254.rs @@ -14,7 +14,7 @@ fn main() { stdin.write(&n); // Set up the pk and vk. - let client = ProverClient::new(); + let client = ProverClient::from_env(); let (pk, vk) = client.setup(ELF); println!("vk: {:?}", vk.bytes32()); diff --git a/examples/fibonacci/script/bin/plonk_bn254.rs b/examples/fibonacci/script/bin/plonk_bn254.rs index 8759293316..48f9c51a37 100644 --- a/examples/fibonacci/script/bin/plonk_bn254.rs +++ b/examples/fibonacci/script/bin/plonk_bn254.rs @@ -14,7 +14,7 @@ fn main() { stdin.write(&n); // Set up the pk and vk. - let client = ProverClient::new(); + let client = ProverClient::from_env(); let (pk, vk) = client.setup(ELF); println!("vk: {:?}", vk.bytes32()); diff --git a/examples/fibonacci/script/src/main.rs b/examples/fibonacci/script/src/main.rs index 4cfb02879c..442fce04c5 100644 --- a/examples/fibonacci/script/src/main.rs +++ b/examples/fibonacci/script/src/main.rs @@ -16,7 +16,7 @@ fn main() { stdin.write(&n); // Create a `ProverClient` method. - let client = ProverClient::new(); + let client = ProverClient::from_env(); // Execute the program using the `ProverClient.execute` method, without generating a proof. let (_, report) = client.execute(ELF, stdin.clone()).run().unwrap(); diff --git a/examples/groth16/script/src/main.rs b/examples/groth16/script/src/main.rs index b35a15f58c..2fecb5493a 100644 --- a/examples/groth16/script/src/main.rs +++ b/examples/groth16/script/src/main.rs @@ -23,7 +23,7 @@ fn generate_fibonacci_proof() -> (Vec, Vec, String) { stdin.write(&n); // Create a `ProverClient`. - let client = ProverClient::new(); + let client = ProverClient::from_env(); // Generate the groth16 proof for the Fibonacci program. let (pk, vk) = client.setup(FIBONACCI_ELF); @@ -46,7 +46,7 @@ fn main() { stdin.write(&vk); // Create a `ProverClient`. - let client = ProverClient::new(); + let client = ProverClient::from_env(); // Execute the program using the `ProverClient.execute` method, without generating a proof. let (_, report) = client.execute(GROTH16_ELF, stdin.clone()).run().unwrap(); diff --git a/examples/io/script/src/main.rs b/examples/io/script/src/main.rs index 21ad14d0fa..008c69e09d 100644 --- a/examples/io/script/src/main.rs +++ b/examples/io/script/src/main.rs @@ -23,7 +23,7 @@ fn main() { stdin.write(&q); // Generate the proof for the given program. - let client = ProverClient::new(); + let client = ProverClient::from_env(); let (pk, vk) = client.setup(ELF); let mut proof = client.prove(&pk, stdin).run().unwrap(); diff --git a/examples/is-prime/script/src/main.rs b/examples/is-prime/script/src/main.rs index 628d1c605b..c965775743 100644 --- a/examples/is-prime/script/src/main.rs +++ b/examples/is-prime/script/src/main.rs @@ -14,7 +14,7 @@ fn main() { stdin.write(&n); // Generate and verify the proof - let client = ProverClient::new(); + let client = ProverClient::from_env(); let (pk, vk) = client.setup(ELF); let mut proof = client.prove(&pk, stdin).run().unwrap(); diff --git a/examples/json/script/src/main.rs b/examples/json/script/src/main.rs index ee093c1629..4c3eaa03a4 100644 --- a/examples/json/script/src/main.rs +++ b/examples/json/script/src/main.rs @@ -34,7 +34,7 @@ fn main() { stdin.write(&initial_account_state); stdin.write(&transactions); - let client = ProverClient::new(); + let client = ProverClient::from_env(); let (pk, vk) = client.setup(JSON_ELF); let mut proof = client.prove(&pk, stdin).run().expect("proving failed"); diff --git a/examples/patch-testing/program/src/main.rs b/examples/patch-testing/program/src/main.rs index fe6e0d36a0..d5c98607c0 100644 --- a/examples/patch-testing/program/src/main.rs +++ b/examples/patch-testing/program/src/main.rs @@ -81,15 +81,31 @@ fn test_curve25519_dalek_ng() { /// Emits ED_DECOMPRESS syscall. fn test_curve25519_dalek() { - let input = [1u8; 32]; - let y = CompressedEdwardsY_dalek(input); + let input_passing = [1u8; 32]; + + // This y-coordinate is not square, and therefore not on the curve + let limbs: [u64; 4] = + [8083970408152925034, 11907700107021980321, 16259949789167878387, 5645861033211660086]; + + // convert to bytes + let input_failing: [u8; 32] = + limbs.iter().flat_map(|l| l.to_be_bytes()).collect::>().try_into().unwrap(); + + let y_passing = CompressedEdwardsY_dalek(input_passing); println!("cycle-tracker-start: curve25519-dalek decompress"); - let decompressed_key = y.decompress().unwrap(); + let decompressed_key = y_passing.decompress().unwrap(); println!("cycle-tracker-end: curve25519-dalek decompress"); let compressed_key = decompressed_key.compress(); - assert_eq!(compressed_key, y); + assert_eq!(compressed_key, y_passing); + + let y_failing = CompressedEdwardsY_dalek(input_failing); + println!("cycle-tracker-start: curve25519-dalek decompress"); + let decompressed_key = y_failing.decompress(); + println!("cycle-tracker-end: curve25519-dalek decompress"); + + assert!(decompressed_key.is_none()); } /// Emits KECCAK_PERMUTE syscalls. diff --git a/examples/patch-testing/script/src/main.rs b/examples/patch-testing/script/src/main.rs index c80446a5b3..5e85f2b825 100644 --- a/examples/patch-testing/script/src/main.rs +++ b/examples/patch-testing/script/src/main.rs @@ -8,7 +8,7 @@ pub fn main() { let stdin = SP1Stdin::new(); - let client = ProverClient::new(); + let client = ProverClient::from_env(); let (_, report) = client.execute(PATCH_TEST_ELF, stdin).run().expect("executing failed"); // Confirm there was at least 1 SHA_COMPUTE syscall. diff --git a/examples/regex/script/src/main.rs b/examples/regex/script/src/main.rs index b198ab43c2..63c8c6fe66 100644 --- a/examples/regex/script/src/main.rs +++ b/examples/regex/script/src/main.rs @@ -18,7 +18,7 @@ fn main() { stdin.write(&target_string); // Generate the proof for the given program and input. - let client = ProverClient::new(); + let client = ProverClient::from_env(); let (pk, vk) = client.setup(REGEX_IO_ELF); let mut proof = client.prove(&pk, stdin).run().expect("proving failed"); diff --git a/examples/rsa/script/src/main.rs b/examples/rsa/script/src/main.rs index 4a6b50d640..991a458d7d 100644 --- a/examples/rsa/script/src/main.rs +++ b/examples/rsa/script/src/main.rs @@ -52,7 +52,7 @@ fn main() { // let verified = stdout.read::(); // Generate the proof for the given program and input. - let client = ProverClient::new(); + let client = ProverClient::from_env(); let (pk, vk) = client.setup(RSA_ELF); let proof = client.prove(&pk, stdin).run().expect("proving failed"); diff --git a/examples/rsp/script/src/main.rs b/examples/rsp/script/src/main.rs index f67325ccc4..08ded491e0 100644 --- a/examples/rsp/script/src/main.rs +++ b/examples/rsp/script/src/main.rs @@ -31,7 +31,7 @@ fn main() { let client_input = load_input_from_cache(CHAIN_ID_ETH_MAINNET, 20526624); // Generate the proof. - let client = ProverClient::new(); + let client = ProverClient::from_env(); // Setup the proving key and verification key. let (pk, vk) = client.setup(include_elf!("rsp-program")); diff --git a/examples/ssz-withdrawals/script/src/main.rs b/examples/ssz-withdrawals/script/src/main.rs index f410d10815..9a6450bc7d 100644 --- a/examples/ssz-withdrawals/script/src/main.rs +++ b/examples/ssz-withdrawals/script/src/main.rs @@ -8,7 +8,7 @@ fn main() { utils::setup_logger(); let stdin = SP1Stdin::new(); - let client = ProverClient::new(); + let client = ProverClient::from_env(); let (pk, vk) = client.setup(ELF); let proof = client.prove(&pk, stdin).run().expect("proving failed"); diff --git a/examples/tendermint/script/src/main.rs b/examples/tendermint/script/src/main.rs index 258aea371d..298b8ee75f 100644 --- a/examples/tendermint/script/src/main.rs +++ b/examples/tendermint/script/src/main.rs @@ -41,7 +41,7 @@ pub fn main() { // let encoded: Vec = bincode::serialize(&light_block_1).unwrap(); // let decoded: LightBlock = bincode::deserialize(&encoded[..]).unwrap(); - let client = ProverClient::new(); + let client = ProverClient::from_env(); let (pk, vk) = client.setup(TENDERMINT_ELF); client.execute(TENDERMINT_ELF, stdin.clone()).run().expect("proving failed");