From a1e362340be2856caa138b48e4527522a8192621 Mon Sep 17 00:00:00 2001 From: Matt Stam Date: Fri, 20 Dec 2024 14:03:28 -0800 Subject: [PATCH] feat(sdk): latest network proto + error handling + fix examples (#1884) --- book/docs/generating-proofs/proof-types.md | 6 +- .../generating-proofs/prover-network/usage.md | 2 +- book/docs/writing-programs/cycle-tracking.mdx | 20 +- ...les_fibonacci_script_bin_compressed.rs.mdx | 2 +- ...amples_fibonacci_script_bin_execute.rs.mdx | 2 +- ..._fibonacci_script_bin_groth16_bn254.rs.mdx | 2 +- .../examples_fibonacci_script_src_main.rs.mdx | 4 +- .../examples_groth16_script_src_main.rs.mdx | 4 +- .../generating-proofs/proof-types.md | 8 +- .../generating-proofs/prover-network/usage.md | 2 +- crates/perf/src/main.rs | 4 +- crates/sdk/src/network/client.rs | 60 +++++- crates/sdk/src/network/error.rs | 39 ++++ crates/sdk/src/network/mod.rs | 13 +- crates/sdk/src/network/proto/artifact.rs | 62 +++++- crates/sdk/src/network/proto/mod.rs | 2 + crates/sdk/src/network/proto/network.rs | 204 ++++++++++++++---- crates/sdk/src/network/prove.rs | 25 ++- crates/sdk/src/network/prover.rs | 43 ++-- crates/sdk/src/network/sign_message.rs | 97 --------- crates/sdk/src/network/utils.rs | 56 +---- examples/aggregation/script/src/main.rs | 8 +- 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 | 5 +- examples/fibonacci/script/Cargo.toml | 4 + 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/network.rs | 77 +++++++ examples/fibonacci/script/bin/plonk_bn254.rs | 2 +- examples/fibonacci/script/src/main.rs | 4 +- 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/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 | 5 +- examples/ssz-withdrawals/script/src/main.rs | 2 +- examples/tendermint/script/src/main.rs | 4 +- 43 files changed, 510 insertions(+), 286 deletions(-) create mode 100644 crates/sdk/src/network/error.rs delete mode 100644 crates/sdk/src/network/sign_message.rs create mode 100644 examples/fibonacci/script/bin/network.rs diff --git a/book/docs/generating-proofs/proof-types.md b/book/docs/generating-proofs/proof-types.md index 581a751d3c..dfdae364d5 100644 --- a/book/docs/generating-proofs/proof-types.md +++ b/book/docs/generating-proofs/proof-types.md @@ -13,7 +13,7 @@ the size of the execution. Use this in settings where you don't care about **ver ```rust,noplayground let client = ProverClient::from_env(); -client.prove(&pk, stdin).run().unwrap(); +client.prove(&pk, &stdin).run().unwrap(); ``` ## Compressed @@ -23,7 +23,7 @@ care about **verification cost / proof size**, but not onchain verification. Com ```rust,noplayground let client = ProverClient::from_env(); -client.prove(&pk, stdin).compressed().run().unwrap(); +client.prove(&pk, &stdin).compressed().run().unwrap(); ``` ## Groth16 (Recommended) @@ -45,5 +45,5 @@ PLONK does not require a trusted setup and reuses contributions from the Aztec I ```rust,noplayground let client = ProverClient::from_env(); -client.prove(&pk, stdin).plonk().run().unwrap(); +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 388c61efdb..77eef1f082 100644 --- a/book/docs/generating-proofs/prover-network/usage.md +++ b/book/docs/generating-proofs/prover-network/usage.md @@ -10,7 +10,7 @@ To use the prover network to generate a proof, you can run your script that uses // Generate the proof for the given program. let client = ProverClient::from_env(); let (pk, vk) = client.setup(ELF); -let mut proof = client.prove(&pk, stdin).run().unwrap(); +let mut proof = client.prove(&pk, &stdin).run().unwrap(); ``` ```sh diff --git a/book/docs/writing-programs/cycle-tracking.mdx b/book/docs/writing-programs/cycle-tracking.mdx index d46da0709f..f38f50d74d 100644 --- a/book/docs/writing-programs/cycle-tracking.mdx +++ b/book/docs/writing-programs/cycle-tracking.mdx @@ -8,7 +8,7 @@ When writing a program, it is useful to know how many RISC-V cycles a portion of To track the number of cycles spent in a portion of the program, you can either put `println!("cycle-tracker-start: block name")` + `println!("cycle-tracker-end: block name")` statements (block name must be same between start and end) around the portion of your program you want to profile or use the `#[sp1_derive::cycle_tracker]` macro on a function. An example is shown below: - + Note that to use the macro, you must add the `sp1-derive` crate to your dependencies for your program. @@ -56,11 +56,12 @@ fn main() { This will log the cycle count for `block name` and include it in the `ExecutionReport` in the `cycle_tracker` map. -### Profiling a ZKVM program +### Profiling a ZKVM program Profiling a zkVM program produces a useful visualization ([example profile](https://share.firefox.dev/3Om1pzz)) which makes it easy to examine program performance and see exactly where VM cycles are being spent without needing to modify the program at all. To profile a program, you need to: + 1. Enable the profiling feature for `sp1-sdk` in `script/Cargo.toml` 2. Set the env variable `TRACE_FILE=trace.json` and then call `ProverClient::execute()` in your script. @@ -68,13 +69,15 @@ If you're executing a larger program (>100M cycles), you should set `TRACE_SAMPL Many examples can be found in the repo, such as this ['fibonacci'](https://github.com/succinctlabs/sp1/blob/dev/examples/fibonacci/script/src/main.rs#L22) script. -Once you have your script it should look like the following: -```rs +Once you have your script it should look like the following: + +```rs // Execute the program using the `ProverClient.execute` method, without generating a proof. - let (_, report) = client.execute(ELF, stdin.clone()).run().unwrap(); + let (_, report) = client.execute(ELF, &stdin).run().unwrap(); ``` As well you must enable the profiling feature on the SDK: + ```toml sp1-sdk = { version = "3.0.0", features = ["profiling"] } ``` @@ -83,11 +86,13 @@ The `TRACE_FILE` env var tells the executor where to save the profile, and the ` A larger sample rate will give you a smaller profile, it is the number of instructions in between each sample. The full command to profile should look something like this + ```sh TRACE_FILE=output.json TRACE_SAMPLE_RATE=100 cargo run ... ``` To view these profiles, we recommend [Samply](https://github.com/mstange/samply). + ```sh cargo install --locked samply samply load output.json @@ -97,7 +102,8 @@ Samply uses the Firefox profiler to create a nice visualization of your programs ![An example screenshot of the Firefox Profiler](@site/static/profiling.png) #### Interpreting the Profile -- The "time" measurement in the profiler is actually the number of cycles spent, -in general the less cycles for a given callframe the better. + +- The "time" measurement in the profiler is actually the number of cycles spent, + in general the less cycles for a given callframe the better. - The CPU usage of the program will always be constant, as its running in the VM which is single threaded. diff --git a/book/static/examples_fibonacci_script_bin_compressed.rs.mdx b/book/static/examples_fibonacci_script_bin_compressed.rs.mdx index 5c9409f8da..1b17c75f3b 100644 --- a/book/static/examples_fibonacci_script_bin_compressed.rs.mdx +++ b/book/static/examples_fibonacci_script_bin_compressed.rs.mdx @@ -16,7 +16,7 @@ fn main() { // Generate the constant-sized proof for the given program and input. let client = ProverClient::new(); let (pk, vk) = client.setup(ELF); - let mut proof = client.prove(&pk, stdin).compressed().run().unwrap(); + let mut proof = client.prove(&pk, &stdin).compressed().run().unwrap(); println!("generated proof"); // Read and verify the output. diff --git a/book/static/examples_fibonacci_script_bin_execute.rs.mdx b/book/static/examples_fibonacci_script_bin_execute.rs.mdx index 46d2bb8757..84175f3017 100644 --- a/book/static/examples_fibonacci_script_bin_execute.rs.mdx +++ b/book/static/examples_fibonacci_script_bin_execute.rs.mdx @@ -16,7 +16,7 @@ fn main() { // Only execute the program and get a `SP1PublicValues` object. let client = ProverClient::new(); - let (mut public_values, execution_report) = client.execute(ELF, stdin).run().unwrap(); + 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 // the RISC-V opcode and syscall counts. diff --git a/book/static/examples_fibonacci_script_bin_groth16_bn254.rs.mdx b/book/static/examples_fibonacci_script_bin_groth16_bn254.rs.mdx index 6b2d6a7f06..a2ef52fc74 100644 --- a/book/static/examples_fibonacci_script_bin_groth16_bn254.rs.mdx +++ b/book/static/examples_fibonacci_script_bin_groth16_bn254.rs.mdx @@ -20,7 +20,7 @@ fn main() { println!("vk: {:?}", vk.bytes32()); // Generate the Groth16 proof. - let proof = client.prove(&pk, stdin).groth16().run().unwrap(); + let proof = client.prove(&pk, &stdin).groth16().run().unwrap(); println!("generated proof"); // Get the public values as bytes. diff --git a/book/static/examples_fibonacci_script_src_main.rs.mdx b/book/static/examples_fibonacci_script_src_main.rs.mdx index 0aa64a9583..c779c5f945 100644 --- a/book/static/examples_fibonacci_script_src_main.rs.mdx +++ b/book/static/examples_fibonacci_script_src_main.rs.mdx @@ -20,12 +20,12 @@ fn main() { let client = ProverClient::new(); // Execute the program using the `ProverClient.execute` method, without generating a proof. - let (_, report) = client.execute(ELF, stdin.clone()).run().unwrap(); + let (_, report) = client.execute(ELF, &stdin).run().unwrap(); println!("executed program with {} cycles", report.total_instruction_count()); // Generate the proof for the given program and input. let (pk, vk) = client.setup(ELF); - let mut proof = client.prove(&pk, stdin).run().unwrap(); + let mut proof = client.prove(&pk, &stdin).run().unwrap(); println!("generated proof"); diff --git a/book/static/examples_groth16_script_src_main.rs.mdx b/book/static/examples_groth16_script_src_main.rs.mdx index 7be12e7e3d..771a908611 100644 --- a/book/static/examples_groth16_script_src_main.rs.mdx +++ b/book/static/examples_groth16_script_src_main.rs.mdx @@ -29,7 +29,7 @@ fn generate_fibonacci_proof() -> (Vec, Vec, String) { // Generate the groth16 proof for the Fibonacci program. let (pk, vk) = client.setup(FIBONACCI_ELF); println!("vk: {:?}", vk.bytes32()); - let proof = client.prove(&pk, stdin).groth16().run().unwrap(); + let proof = client.prove(&pk, &stdin).groth16().run().unwrap(); (proof.bytes(), proof.public_values.to_vec(), vk.bytes32()) } @@ -50,7 +50,7 @@ fn main() { let client = ProverClient::new(); // Execute the program using the `ProverClient.execute` method, without generating a proof. - let (_, report) = client.execute(GROTH16_ELF, stdin.clone()).run().unwrap(); + let (_, report) = client.execute(GROTH16_ELF, &stdin).run().unwrap(); println!("executed groth16 program with {} cycles", report.total_instruction_count()); println!("{}", report); } diff --git a/book/versioned_docs/version-3.4.0/generating-proofs/proof-types.md b/book/versioned_docs/version-3.4.0/generating-proofs/proof-types.md index c6d713e754..ece6318edc 100644 --- a/book/versioned_docs/version-3.4.0/generating-proofs/proof-types.md +++ b/book/versioned_docs/version-3.4.0/generating-proofs/proof-types.md @@ -13,7 +13,7 @@ the size of the execution. Use this in settings where you don't care about **ver ```rust let client = ProverClient::new(); -client.prove(&pk, stdin).run().unwrap(); +client.prove(&pk, &stdin).run().unwrap(); ``` ## Compressed @@ -23,7 +23,7 @@ care about **verification cost / proof size**, but not onchain verification. Com ```rust let client = ProverClient::new(); -client.prove(&pk, stdin).compressed().run().unwrap(); +client.prove(&pk, &stdin).compressed().run().unwrap(); ``` ## Groth16 (Recommended) @@ -34,7 +34,7 @@ The trusted setup for the Groth16 circuit keys uses the [Aztec Ignition ceremony ```rust let client = ProverClient::new(); -client.prove(&pk, stdin).groth16().run().unwrap(); +client.prove(&pk, &stdin).groth16().run().unwrap(); ``` ## PLONK @@ -45,5 +45,5 @@ PLONK does not require a trusted setup. ```rust let client = ProverClient::new(); -client.prove(&pk, stdin).plonk().run().unwrap(); +client.prove(&pk, &stdin).plonk().run().unwrap(); ``` diff --git a/book/versioned_docs/version-3.4.0/generating-proofs/prover-network/usage.md b/book/versioned_docs/version-3.4.0/generating-proofs/prover-network/usage.md index 12ef4ac4e6..f17324113e 100644 --- a/book/versioned_docs/version-3.4.0/generating-proofs/prover-network/usage.md +++ b/book/versioned_docs/version-3.4.0/generating-proofs/prover-network/usage.md @@ -10,7 +10,7 @@ To use the prover network to generate a proof, you can run your script that uses // Generate the proof for the given program. let client = ProverClient::new(); let (pk, vk) = client.setup(ELF); -let mut proof = client.prove(&pk, stdin).run().unwrap(); +let mut proof = client.prove(&pk, &stdin).run().unwrap(); ``` ```sh diff --git a/crates/perf/src/main.rs b/crates/perf/src/main.rs index 04ca613173..7449d67c75 100644 --- a/crates/perf/src/main.rs +++ b/crates/perf/src/main.rs @@ -177,13 +177,13 @@ fn main() { let (_, _) = time_operation(|| prover.execute(&elf, &stdin)); let (proof, _) = time_operation(|| { - prover.prove(&pk, stdin.clone()).groth16().skip_simulation(true).run().unwrap() + prover.prove(&pk, &stdin).groth16().skip_simulation(true).run().unwrap() }); let (_, _) = time_operation(|| prover.verify(&proof, &vk)); let (proof, _) = time_operation(|| { - prover.prove(&pk, stdin).plonk().skip_simulation(true).run().unwrap() + prover.prove(&pk, &stdin).plonk().skip_simulation(true).run().unwrap() }); let (_, _) = time_operation(|| prover.verify(&proof, &vk)); diff --git a/crates/sdk/src/network/client.rs b/crates/sdk/src/network/client.rs index 880352c5c6..6758ffa3d2 100644 --- a/crates/sdk/src/network/client.rs +++ b/crates/sdk/src/network/client.rs @@ -20,14 +20,14 @@ use tonic::{ use super::utils::Signable; use crate::network::proto::artifact::{ - artifact_store_client::ArtifactStoreClient, CreateArtifactRequest, + artifact_store_client::ArtifactStoreClient, ArtifactType, CreateArtifactRequest, }; use crate::network::proto::network::{ prover_network_client::ProverNetworkClient, CreateProgramRequest, CreateProgramRequestBody, - CreateProgramResponse, FulfillmentStatus, FulfillmentStrategy, GetNonceRequest, - GetProgramRequest, GetProgramResponse, GetProofRequestStatusRequest, - GetProofRequestStatusResponse, MessageFormat, ProofMode, RequestProofRequest, - RequestProofRequestBody, RequestProofResponse, + CreateProgramResponse, FulfillmentStatus, FulfillmentStrategy, GetFilteredProofRequestsRequest, + GetFilteredProofRequestsResponse, GetNonceRequest, GetProgramRequest, GetProgramResponse, + GetProofRequestStatusRequest, GetProofRequestStatusResponse, MessageFormat, ProofMode, + RequestProofRequest, RequestProofRequestBody, RequestProofResponse, }; /// A client for interacting with the network. @@ -105,7 +105,8 @@ impl NetworkClient { ) -> 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?; + let program_uri = + self.create_artifact_with_content(&mut store, ArtifactType::Program, &elf).await?; // Serialize the verifying key. let vk_encoded = bincode::serialize(&vk)?; @@ -130,6 +131,44 @@ impl NetworkClient { .into_inner()) } + /// Get all the proof requests that meet the filter criteria. + #[allow(clippy::too_many_arguments)] + pub async fn get_filtered_proof_requests( + &self, + version: Option, + fulfillment_status: Option, + execution_status: Option, + minimum_deadline: Option, + vk_hash: Option>, + requester: Option>, + fulfiller: Option>, + from: Option, + to: Option, + limit: Option, + page: Option, + mode: Option, + ) -> Result { + let mut rpc = self.prover_network_client().await?; + let res = rpc + .get_filtered_proof_requests(GetFilteredProofRequestsRequest { + version, + fulfillment_status, + execution_status, + minimum_deadline, + vk_hash, + requester, + fulfiller, + from, + to, + limit, + page, + mode, + }) + .await? + .into_inner(); + Ok(res) + } + /// Get the status of a given proof. /// /// # Details @@ -190,7 +229,8 @@ impl NetworkClient { // Create the stdin artifact. let mut store = self.artifact_store_client().await?; - let stdin_uri = self.create_artifact_with_content(&mut store, &stdin).await?; + let stdin_uri = + self.create_artifact_with_content(&mut store, ArtifactType::Stdin, &stdin).await?; // Send the request. let mut rpc = self.prover_network_client().await?; @@ -248,10 +288,14 @@ impl NetworkClient { pub(crate) async fn create_artifact_with_content( &self, store: &mut ArtifactStoreClient, + artifact_type: ArtifactType, item: &T, ) -> Result { let signature = self.signer.sign_message_sync("create_artifact".as_bytes())?; - let request = CreateArtifactRequest { signature: signature.as_bytes().to_vec() }; + let request = CreateArtifactRequest { + artifact_type: artifact_type.into(), + signature: signature.as_bytes().to_vec(), + }; let response = store.create_artifact(request).await?.into_inner(); let presigned_url = response.artifact_presigned_url; diff --git a/crates/sdk/src/network/error.rs b/crates/sdk/src/network/error.rs new file mode 100644 index 0000000000..3cde6d6047 --- /dev/null +++ b/crates/sdk/src/network/error.rs @@ -0,0 +1,39 @@ +use thiserror::Error; +use tonic::Status; + +/// An error that can occur when interacting with the prover network. +#[derive(Error, Debug)] +pub enum Error { + /// The program execution failed. + #[error("Program simulation failed")] + SimulationFailed, + + /// The proof request is unexecutable. + #[error("Proof request 0x{} is unexecutable", hex::encode(.request_id))] + RequestUnexecutable { + /// The ID of the request that cannot be executed. + request_id: Vec, + }, + + /// The proof request is unfulfillable. + #[error("Proof request 0x{} is unfulfillable", hex::encode(.request_id))] + RequestUnfulfillable { + /// The ID of the request that cannot be fulfilled. + request_id: Vec, + }, + + /// The proof request timed out. + #[error("Proof request 0x{} timed out", hex::encode(.request_id))] + RequestTimedOut { + /// The ID of the request that timed out. + request_id: Vec, + }, + + /// An error occurred while interacting with the RPC server. + #[error("RPC error")] + RpcError(#[from] Status), + + /// An unknown error occurred. + #[error("Other error: {0}")] + Other(#[from] anyhow::Error), +} diff --git a/crates/sdk/src/network/mod.rs b/crates/sdk/src/network/mod.rs index 6cc201f327..6ebb2790dd 100644 --- a/crates/sdk/src/network/mod.rs +++ b/crates/sdk/src/network/mod.rs @@ -4,19 +4,28 @@ 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; +mod error; pub mod prove; pub mod utils; +pub use error::*; + 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/"; +/// The default RPC URL for the prover network. +pub(crate) const DEFAULT_NETWORK_RPC_URL: &str = "https://rpc.production.succinct.tools/"; + +/// The default timeout for the prover network (4 hours). pub(crate) const DEFAULT_TIMEOUT_SECS: u64 = 14400; + +/// The default cycle limit for the prover network (100M cycles). +/// +/// This will only be used if both simulation is skipped and the cycle limit is not explicitly set. pub(crate) const DEFAULT_CYCLE_LIMIT: u64 = 100_000_000; diff --git a/crates/sdk/src/network/proto/artifact.rs b/crates/sdk/src/network/proto/artifact.rs index e1ff3ad034..bda90769e9 100644 --- a/crates/sdk/src/network/proto/artifact.rs +++ b/crates/sdk/src/network/proto/artifact.rs @@ -4,6 +4,9 @@ pub struct CreateArtifactRequest { /// The signature of the user on a pre-defined message. Used for authentication. #[prost(bytes = "vec", tag = "1")] pub signature: ::prost::alloc::vec::Vec, + /// The type of artifact to create. + #[prost(enumeration = "ArtifactType", tag = "2")] + pub artifact_type: i32, } #[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] pub struct CreateArtifactResponse { @@ -14,11 +17,58 @@ pub struct CreateArtifactResponse { #[prost(string, tag = "2")] pub artifact_presigned_url: ::prost::alloc::string::String, } +#[derive( + serde::Serialize, + serde::Deserialize, + Clone, + Copy, + Debug, + PartialEq, + Eq, + Hash, + PartialOrd, + Ord, + ::prost::Enumeration, +)] +#[repr(i32)] +pub enum ArtifactType { + UnspecifiedArtifactType = 0, + /// A program artifact. + Program = 1, + /// A stdin artifact. + Stdin = 2, + /// A proof artifact. + Proof = 3, +} +impl ArtifactType { + /// 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::UnspecifiedArtifactType => "UNSPECIFIED_ARTIFACT_TYPE", + Self::Program => "PROGRAM", + Self::Stdin => "STDIN", + Self::Proof => "PROOF", + } + } + /// Creates an enum from field names used in the ProtoBuf definition. + pub fn from_str_name(value: &str) -> ::core::option::Option { + match value { + "UNSPECIFIED_ARTIFACT_TYPE" => Some(Self::UnspecifiedArtifactType), + "PROGRAM" => Some(Self::Program), + "STDIN" => Some(Self::Stdin), + "PROOF" => Some(Self::Proof), + _ => None, + } + } +} /// Generated client implementations. pub mod artifact_store_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}; + use tonic::codegen::*; #[derive(Debug, Clone)] pub struct ArtifactStoreClient { inner: tonic::client::Grpc, @@ -57,11 +107,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 +173,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::{Arc, Body, BoxFuture, CompressionEncoding, Context, EnabledCompressionEncodings, InterceptedService, Poll, StdError, async_trait, empty_body, http}; + use tonic::codegen::*; /// 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 48eb63675a..95ba33205e 100644 --- a/crates/sdk/src/network/proto/mod.rs +++ b/crates/sdk/src/network/proto/mod.rs @@ -1,2 +1,4 @@ +#![allow(clippy::doc_markdown, clippy::must_use_candidate, clippy::wildcard_imports)] + 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 52691b93ab..6c411f84ab 100644 --- a/crates/sdk/src/network/proto/network.rs +++ b/crates/sdk/src/network/proto/network.rs @@ -254,20 +254,28 @@ pub struct ProofRequest { /// 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. + /// The unix timestamp of when the request was fulfilled. Only included if + /// the request has a fulfillment status of 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. + /// The cycle used during the execution of the request. Only included if the + /// request has an execution status of EXECUTED. #[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. + /// The public values hash from the execution of the request. Only included if + /// the request has an execution status of EXECUTED. + #[prost(bytes = "vec", optional, tag = "23")] + pub public_values_hash: ::core::option::Option<::prost::alloc::vec::Vec>, + /// The amount deducted from the fulfiller's balance. Only included if the + /// request has a fulfillment status of ASSIGNED. #[prost(string, optional, tag = "24")] + pub deduction_amount: ::core::option::Option<::prost::alloc::string::String>, + /// The amount refunded to the fulfiller's balance. Only included if the + /// request has a fulfillment status of EXECUTED. + #[prost(string, optional, tag = "25")] pub refund_amount: ::core::option::Option<::prost::alloc::string::String>, } #[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] @@ -287,14 +295,22 @@ pub struct GetProofRequestStatusResponse { /// The transaction hash of the request. #[prost(bytes = "vec", tag = "3")] pub request_tx_hash: ::prost::alloc::vec::Vec, + /// The deadline of the request. A request should be ignored if it is past + /// its deadline. + #[prost(uint64, tag = "4")] + pub deadline: u64, /// 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")] + #[prost(bytes = "vec", optional, tag = "5")] 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")] + #[prost(string, optional, tag = "6")] pub proof_uri: ::core::option::Option<::prost::alloc::string::String>, + /// The optional public values hash from the execution of the request. Only + /// included if the request has an execution status of EXECUTED. + #[prost(bytes = "vec", optional, tag = "7")] + pub public_values_hash: ::core::option::Option<::prost::alloc::vec::Vec>, } #[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] pub struct GetProofRequestDetailsRequest { @@ -557,6 +573,38 @@ pub struct RemoveDelegationResponse { #[derive(serde::Serialize, serde::Deserialize, Clone, Copy, PartialEq, ::prost::Message)] pub struct RemoveDelegationResponseBody {} #[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] +pub struct TerminateDelegationRequest { + /// 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 TerminateDelegationRequestBody { + /// The account nonce of the sender. + #[prost(uint64, tag = "1")] + pub nonce: u64, + /// The address of the owner whose delegation to terminate. + #[prost(bytes = "vec", tag = "2")] + pub owner: ::prost::alloc::vec::Vec, +} +#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] +pub struct TerminateDelegationResponse { + /// 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 TerminateDelegationResponseBody {} +#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] pub struct AcceptDelegationRequest { /// The message format of the body. #[prost(enumeration = "MessageFormat", tag = "1")] @@ -949,14 +997,17 @@ pub struct Reservation { #[prost(uint64, tag = "5")] pub created_at: u64, } -#[derive(serde::Serialize, serde::Deserialize, Clone, Copy, PartialEq, ::prost::Message)] +#[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] pub struct GetFilteredReservationsRequest { + /// Requester address to filter for. + #[prost(bytes = "vec", optional, tag = "1")] + pub requester: ::core::option::Option<::prost::alloc::vec::Vec>, /// The optional maximum number of reservations to return (default is 10, /// maximum is 100). - #[prost(uint32, optional, tag = "1")] + #[prost(uint32, optional, tag = "2")] pub limit: ::core::option::Option, /// The optional page number to return (default is 1). - #[prost(uint32, optional, tag = "2")] + #[prost(uint32, optional, tag = "3")] pub page: ::core::option::Option, } #[derive(serde::Serialize, serde::Deserialize, Clone, PartialEq, ::prost::Message)] @@ -1120,19 +1171,19 @@ pub enum MessageFormat { Json = 2, } impl MessageFormat { - /// 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. - #[must_use] pub fn as_str_name(&self) -> &'static str { + /// (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. - #[must_use] pub fn from_str_name(value: &str) -> ::core::option::Option { + /// 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), @@ -1167,11 +1218,11 @@ pub enum ProofMode { 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. - #[must_use] pub fn as_str_name(&self) -> &'static str { + /// (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", @@ -1180,8 +1231,8 @@ impl ProofMode { Self::Groth16 => "GROTH16", } } - /// Creates an enum from field names used in the `ProtoBuf` definition. - #[must_use] pub fn from_str_name(value: &str) -> ::core::option::Option { + /// 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), @@ -1219,11 +1270,11 @@ pub enum FulfillmentStrategy { Auction = 3, } impl FulfillmentStrategy { - /// 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. - #[must_use] pub fn as_str_name(&self) -> &'static str { + /// (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", @@ -1231,8 +1282,8 @@ impl FulfillmentStrategy { Self::Auction => "AUCTION", } } - /// Creates an enum from field names used in the `ProtoBuf` definition. - #[must_use] pub fn from_str_name(value: &str) -> ::core::option::Option { + /// 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), @@ -1269,11 +1320,11 @@ pub enum FulfillmentStatus { Unfulfillable = 4, } impl FulfillmentStatus { - /// 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. - #[must_use] pub fn as_str_name(&self) -> &'static str { + /// (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", @@ -1282,8 +1333,8 @@ impl FulfillmentStatus { Self::Unfulfillable => "UNFULFILLABLE", } } - /// Creates an enum from field names used in the `ProtoBuf` definition. - #[must_use] pub fn from_str_name(value: &str) -> ::core::option::Option { + /// 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), @@ -1319,11 +1370,11 @@ pub enum ExecutionStatus { Unexecutable = 3, } impl ExecutionStatus { - /// 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. - #[must_use] pub fn as_str_name(&self) -> &'static str { + /// (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", @@ -1331,8 +1382,8 @@ impl ExecutionStatus { Self::Unexecutable => "UNEXECUTABLE", } } - /// Creates an enum from field names used in the `ProtoBuf` definition. - #[must_use] pub fn from_str_name(value: &str) -> ::core::option::Option { + /// 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), @@ -1373,11 +1424,11 @@ pub enum BalanceOperation { Bid = 6, } impl BalanceOperation { - /// 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. - #[must_use] pub fn as_str_name(&self) -> &'static str { + /// (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", @@ -1388,8 +1439,8 @@ impl BalanceOperation { Self::Bid => "BID", } } - /// Creates an enum from field names used in the `ProtoBuf` definition. - #[must_use] pub fn from_str_name(value: &str) -> ::core::option::Option { + /// 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), @@ -1406,7 +1457,7 @@ impl BalanceOperation { 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}; + use tonic::codegen::*; #[derive(Debug, Clone)] pub struct ProverNetworkClient { inner: tonic::client::Grpc, @@ -1806,6 +1857,26 @@ pub mod prover_network_client { .insert(GrpcMethod::new("network.ProverNetwork", "RemoveDelegation")); self.inner.unary(req, path, codec).await } + /// Terminate a delegation. Only callable by the delegate of a delegation. + pub async fn terminate_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/TerminateDelegation"); + let mut req = request.into_request(); + req.extensions_mut() + .insert(GrpcMethod::new("network.ProverNetwork", "TerminateDelegation")); + 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, @@ -2181,7 +2252,7 @@ pub mod prover_network_client { /// 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}; + 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 { @@ -2277,6 +2348,11 @@ pub mod prover_network_server { &self, request: tonic::Request, ) -> std::result::Result, tonic::Status>; + /// Terminate a delegation. Only callable by the delegate of a delegation. + async fn terminate_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, @@ -3123,6 +3199,48 @@ pub mod prover_network_server { }; Box::pin(fut) } + "/network.ProverNetwork/TerminateDelegation" => { + #[allow(non_camel_case_types)] + struct TerminateDelegationSvc(pub Arc); + impl + tonic::server::UnaryService + for TerminateDelegationSvc + { + type Response = super::TerminateDelegationResponse; + type Future = BoxFuture, tonic::Status>; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::terminate_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 = TerminateDelegationSvc(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); diff --git a/crates/sdk/src/network/prove.rs b/crates/sdk/src/network/prove.rs index 293c69f204..92057640df 100644 --- a/crates/sdk/src/network/prove.rs +++ b/crates/sdk/src/network/prove.rs @@ -241,7 +241,7 @@ impl<'a> NetworkProveBuilder<'a> { /// the simulation step locally. /// /// The cycle limit ensures that a prover on the network will stop generating a proof once the - /// cycle limit is reached, which prevents DoS attacks. + /// cycle limit is reached, which prevents `DoS` attacks. /// /// # Example /// ```rust,no_run @@ -284,8 +284,11 @@ impl<'a> NetworkProveBuilder<'a> { /// .unwrap(); /// ``` pub async fn request(self) -> Result> { - let Self { prover, mode, pk, stdin, timeout, strategy, skip_simulation, cycle_limit } = self; - prover.request_proof_impl(pk, &stdin, mode, strategy, timeout, skip_simulation, cycle_limit).await + let Self { prover, mode, pk, stdin, timeout, strategy, skip_simulation, cycle_limit } = + self; + prover + .request_proof_impl(pk, &stdin, mode, strategy, timeout, skip_simulation, cycle_limit) + .await } /// Run the prover with the built arguments. @@ -308,7 +311,8 @@ impl<'a> NetworkProveBuilder<'a> { /// .unwrap(); /// ``` pub fn run(self) -> Result { - let Self { prover, mode, pk, stdin, timeout, strategy, mut skip_simulation, cycle_limit } = self; + let Self { prover, mode, pk, stdin, timeout, strategy, mut skip_simulation, cycle_limit } = + self; // Check for deprecated environment variable if let Ok(val) = std::env::var("SKIP_SIMULATION") { @@ -320,7 +324,15 @@ impl<'a> NetworkProveBuilder<'a> { sp1_dump(&pk.elf, &stdin); - block_on(prover.prove_impl(pk, &stdin, mode, strategy, timeout, skip_simulation, cycle_limit)) + block_on(prover.prove_impl( + pk, + &stdin, + mode, + strategy, + timeout, + skip_simulation, + cycle_limit, + )) } /// Run the prover with the built arguments asynchronously. @@ -341,7 +353,8 @@ impl<'a> NetworkProveBuilder<'a> { /// .run_async(); /// ``` pub async fn run_async(self) -> Result { - let Self { prover, mode, pk, stdin, timeout, strategy, mut skip_simulation, cycle_limit } = self; + let Self { prover, mode, pk, stdin, timeout, strategy, mut skip_simulation, cycle_limit } = + self; // Check for deprecated environment variable if let Ok(val) = std::env::var("SKIP_SIMULATION") { diff --git a/crates/sdk/src/network/prover.rs b/crates/sdk/src/network/prover.rs index f6a718686a..ca1f71f98b 100644 --- a/crates/sdk/src/network/prover.rs +++ b/crates/sdk/src/network/prover.rs @@ -5,12 +5,12 @@ use std::time::{Duration, Instant}; -use super::proto::network::GetProofRequestStatusResponse; 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::proto::network::GetProofRequestStatusResponse; +use crate::network::{Error, DEFAULT_NETWORK_RPC_URL, DEFAULT_TIMEOUT_SECS}; use crate::{ network::client::NetworkClient, network::proto::network::{ExecutionStatus, FulfillmentStatus, FulfillmentStrategy, ProofMode}, @@ -203,7 +203,7 @@ impl NetworkProver { 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 { + if self.client.rpc_url == DEFAULT_NETWORK_RPC_URL { log::info!( "View request status at: https://network.succinct.xyz/request/{}", request_id_hex @@ -215,7 +215,7 @@ impl NetworkProver { /// 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(crate) async fn wait_proof( + pub async fn wait_proof( &self, request_id: &[u8], timeout: Option, @@ -227,7 +227,7 @@ impl NetworkProver { // Calculate the remaining timeout. if let Some(timeout) = timeout { if start_time.elapsed() > timeout { - return Err(anyhow::anyhow!("proof request timed out.")); + return Err(Error::RequestTimedOut { request_id: request_id.to_vec() }.into()); } } let remaining_timeout = timeout.map(|t| { @@ -239,17 +239,24 @@ impl NetworkProver { } }); - // Get status with retries. + // Get the status with retries. let (status, maybe_proof) = with_retry( - || async { self.client.get_proof_request_status::

(request_id).await }, + || async { self.client.get_proof_request_status(request_id).await }, remaining_timeout, "getting proof request status", ) .await?; + // Check the deadline. + if status.deadline < Instant::now().elapsed().as_secs() { + return Err(Error::RequestTimedOut { request_id: request_id.to_vec() }.into()); + } + // Check the execution status. - if status.execution_status == ExecutionStatus::Unexecutable as i32 { - return Err(anyhow::anyhow!("proof request is unexecutable")); + if let Ok(ExecutionStatus::Unexecutable) = + ExecutionStatus::try_from(status.execution_status) + { + return Err(Error::RequestUnexecutable { request_id: request_id.to_vec() }.into()); } // Check the fulfillment status. @@ -259,12 +266,14 @@ impl NetworkProver { } Ok(FulfillmentStatus::Assigned) => { if !is_assigned { - log::info!("proof request assigned, proving..."); + log::info!("Proof request assigned, proving..."); is_assigned = true; } } Ok(FulfillmentStatus::Unfulfillable) => { - return Err(anyhow::anyhow!("proof request is unfulfillable")); + return Err( + Error::RequestUnfulfillable { request_id: request_id.to_vec() }.into() + ); } _ => {} } @@ -273,7 +282,7 @@ impl NetworkProver { } } - /// Requests a proof from the prover network. + #[allow(clippy::too_many_arguments)] pub(crate) async fn request_proof_impl( &self, pk: &SP1ProvingKey, @@ -289,7 +298,7 @@ impl NetworkProver { self.request_proof(&vk_hash, stdin, mode.into(), strategy, cycle_limit, timeout).await } - /// Requests a proof from the prover network and waits for it to be generated. + #[allow(clippy::too_many_arguments)] pub(crate) async fn prove_impl( &self, pk: &SP1ProvingKey, @@ -326,9 +335,11 @@ impl NetworkProver { 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) + self.prover + .inner() + .execute(elf, stdin, SP1Context::default()) + .map(|(_, report)| report.total_instruction_count()) + .map_err(|_| Error::SimulationFailed.into()) } } } diff --git a/crates/sdk/src/network/sign_message.rs b/crates/sdk/src/network/sign_message.rs deleted file mode 100644 index 9d12891525..0000000000 --- a/crates/sdk/src/network/sign_message.rs +++ /dev/null @@ -1,97 +0,0 @@ -use alloy_primitives::{Address, Signature}; -use prost::Message; -use thiserror::Error; - -use crate::network::proto::network::{FulfillProofRequest, MessageFormat, RequestProofRequest}; -use crate::network::utils::{format_json_message, JsonFormatError}; - -#[allow(dead_code)] -pub trait SignedMessage { - fn signature(&self) -> Vec; - fn nonce(&self) -> Result; - fn message(&self) -> Result, MessageError>; - fn recover_sender(&self) -> Result<(Address, Vec), RecoverSenderError>; -} - -#[derive(Error, Debug)] -#[allow(dead_code)] -pub enum MessageError { - #[error("Empty message")] - EmptyMessage, - #[error("JSON error: {0}")] - JsonError(String), - #[error("Binary error: {0}")] - BinaryError(String), -} - -#[derive(Error, Debug)] -pub enum RecoverSenderError { - #[error("Failed to deserialize signature: {0}")] - SignatureDeserializationError(String), - #[error("Empty message")] - EmptyMessage, - #[error("Failed to recover address: {0}")] - AddressRecoveryError(String), -} - -macro_rules! impl_signed_message { - ($type:ty) => { - impl SignedMessage for $type { - fn signature(&self) -> Vec { - self.signature.clone() - } - - fn nonce(&self) -> Result { - match &self.body { - Some(body) => Ok(body.nonce as u64), - None => Err(MessageError::EmptyMessage), - } - } - - fn message(&self) -> Result, MessageError> { - let format = MessageFormat::try_from(self.format).unwrap_or(MessageFormat::Binary); - - match &self.body { - Some(body) => match format { - MessageFormat::Json => format_json_message(body).map_err(|e| match e { - JsonFormatError::SerializationError(msg) => { - MessageError::JsonError(msg) - } - }), - MessageFormat::Binary => { - let proto_bytes = body.encode_to_vec(); - Ok(proto_bytes) - } - MessageFormat::UnspecifiedMessageFormat => { - let proto_bytes = body.encode_to_vec(); - Ok(proto_bytes) - } - }, - None => Err(MessageError::EmptyMessage), - } - } - - fn recover_sender(&self) -> Result<(Address, Vec), RecoverSenderError> { - let message = self.message().map_err(|_| RecoverSenderError::EmptyMessage)?; - let sender = recover_sender_raw(self.signature.clone(), message.clone())?; - Ok((sender, message)) - } - } - }; -} - -impl_signed_message!(RequestProofRequest); -impl_signed_message!(FulfillProofRequest); - -#[allow(clippy::needless_pass_by_value)] -pub fn recover_sender_raw( - signature: Vec, - message: Vec, -) -> Result { - let signature = Signature::try_from(signature.as_slice()) - .map_err(|e| RecoverSenderError::SignatureDeserializationError(e.to_string()))?; - - signature - .recover_address_from_msg(message) - .map_err(|e| RecoverSenderError::AddressRecoveryError(e.to_string())) -} diff --git a/crates/sdk/src/network/utils.rs b/crates/sdk/src/network/utils.rs index e1b7d749b5..22ded7c94b 100644 --- a/crates/sdk/src/network/utils.rs +++ b/crates/sdk/src/network/utils.rs @@ -1,11 +1,11 @@ +#![allow(deprecated)] + //! # Network Utils //! //! This module provides utility functions for the network module. use alloy_signer::{Signature, SignerSync}; use prost::Message; -use serde::Serialize; -use thiserror::Error; pub(crate) trait Signable: Message { fn sign(&self, signer: &S) -> Signature; @@ -16,55 +16,3 @@ impl Signable for T { signer.sign_message_sync(&self.encode_to_vec()).unwrap() } } - -#[derive(Error, Debug)] -pub(crate) enum JsonFormatError { - #[error("Serialization error: {0}")] - SerializationError(String), -} - -pub(crate) fn format_json_message(body: &T) -> Result, JsonFormatError> -where - T: Message + Serialize, -{ - match serde_json::to_string(body) { - Ok(json_str) => { - if json_str.starts_with('"') && json_str.ends_with('"') { - let inner = &json_str[1..json_str.len() - 1]; - let unescaped = inner.replace("\\\"", "\""); - Ok(unescaped.into_bytes()) - } else { - Ok(json_str.into_bytes()) - } - } - Err(e) => Err(JsonFormatError::SerializationError(e.to_string())), - } -} - -#[cfg(test)] -mod tests { - use super::*; - use prost::Message as ProstMessage; - use serde::{Deserialize, Serialize}; - - // Test message for JSON formatting. - #[derive(Clone, ProstMessage, Serialize, Deserialize)] - struct TestMessage { - #[prost(string, tag = 1)] - value: String, - } - - #[test] - fn test_format_json_message_simple() { - let msg = TestMessage { value: "hello".to_string() }; - let result = format_json_message(&msg).unwrap(); - assert_eq!(result, b"{\"value\":\"hello\"}"); - } - - #[test] - fn test_format_json_message_with_quotes() { - let msg = TestMessage { value: "hello \"world\"".to_string() }; - let result = format_json_message(&msg).unwrap(); - assert_eq!(result, b"{\"value\":\"hello \\\"world\\\"\"}"); - } -} diff --git a/examples/aggregation/script/src/main.rs b/examples/aggregation/script/src/main.rs index 2b1227d6c4..554e2c6de8 100644 --- a/examples/aggregation/script/src/main.rs +++ b/examples/aggregation/script/src/main.rs @@ -34,17 +34,17 @@ fn main() { let proof_1 = tracing::info_span!("generate fibonacci proof n=10").in_scope(|| { let mut stdin = SP1Stdin::new(); stdin.write(&10); - client.prove(&fibonacci_pk, stdin).compressed().run().expect("proving failed") + client.prove(&fibonacci_pk, &stdin).compressed().run().expect("proving failed") }); let proof_2 = tracing::info_span!("generate fibonacci proof n=20").in_scope(|| { let mut stdin = SP1Stdin::new(); stdin.write(&20); - client.prove(&fibonacci_pk, stdin).compressed().run().expect("proving failed") + client.prove(&fibonacci_pk, &stdin).compressed().run().expect("proving failed") }); let proof_3 = tracing::info_span!("generate fibonacci proof n=30").in_scope(|| { let mut stdin = SP1Stdin::new(); stdin.write(&30); - client.prove(&fibonacci_pk, stdin).compressed().run().expect("proving failed") + client.prove(&fibonacci_pk, &stdin).compressed().run().expect("proving failed") }); // Setup the inputs to the aggregation program. @@ -76,6 +76,6 @@ fn main() { } // Generate the plonk bn254 proof. - client.prove(&aggregation_pk, stdin).plonk().run().expect("proving failed"); + client.prove(&aggregation_pk, &stdin).plonk().run().expect("proving failed"); }); } diff --git a/examples/bls12381/script/src/main.rs b/examples/bls12381/script/src/main.rs index 7e6c02fd40..096c805db1 100644 --- a/examples/bls12381/script/src/main.rs +++ b/examples/bls12381/script/src/main.rs @@ -7,7 +7,7 @@ fn main() { let stdin = SP1Stdin::new(); let client = ProverClient::from_env(); - let (_public_values, report) = client.execute(ELF, stdin).run().expect("failed to prove"); + 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 cd9c6e5057..7aa091e1f1 100644 --- a/examples/bn254/script/src/main.rs +++ b/examples/bn254/script/src/main.rs @@ -7,7 +7,7 @@ fn main() { let stdin = SP1Stdin::new(); let client = ProverClient::from_env(); - let (_public_values, report) = client.execute(ELF, stdin).run().expect("failed to prove"); + 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 3a1df33e50..a08496647a 100644 --- a/examples/chess/script/src/main.rs +++ b/examples/chess/script/src/main.rs @@ -15,7 +15,7 @@ fn main() { let client = ProverClient::from_env(); let (pk, vk) = client.setup(ELF); - let mut proof = client.prove(&pk, stdin).run().unwrap(); + let mut proof = client.prove(&pk, &stdin).run().unwrap(); // Read output. let is_valid_move = proof.public_values.read::(); diff --git a/examples/cycle-tracking/script/src/main.rs b/examples/cycle-tracking/script/src/main.rs index 03a76a80f2..ee845c6ced 100644 --- a/examples/cycle-tracking/script/src/main.rs +++ b/examples/cycle-tracking/script/src/main.rs @@ -10,10 +10,11 @@ fn main() { // Execute the normal program. let client = ProverClient::from_env(); - let (_, _) = client.execute(NORMAL_ELF, SP1Stdin::new()).run().expect("proving failed"); + let stdin = SP1Stdin::new(); + let (_, _) = client.execute(NORMAL_ELF, &stdin).run().expect("proving failed"); // Execute the report program. - let (_, report) = client.execute(REPORT_ELF, SP1Stdin::new()).run().expect("proving failed"); + let (_, report) = client.execute(REPORT_ELF, &stdin).run().expect("proving failed"); // Get the "setup" cycle count from the report program. let setup_cycles = report.cycle_tracker.get("setup").unwrap(); diff --git a/examples/fibonacci/script/Cargo.toml b/examples/fibonacci/script/Cargo.toml index 308d3eeede..a7ffb4d7a1 100644 --- a/examples/fibonacci/script/Cargo.toml +++ b/examples/fibonacci/script/Cargo.toml @@ -28,6 +28,10 @@ path = "bin/compressed.rs" name = "execute" path = "bin/execute.rs" +[[bin]] +name = "network" +path = "bin/network.rs" + [[bin]] name = "fibonacci-script" path = "src/main.rs" diff --git a/examples/fibonacci/script/bin/compressed.rs b/examples/fibonacci/script/bin/compressed.rs index 632f9cd15f..c14b23736c 100644 --- a/examples/fibonacci/script/bin/compressed.rs +++ b/examples/fibonacci/script/bin/compressed.rs @@ -15,7 +15,7 @@ fn main() { // Generate the constant-sized proof for the given program and input. let client = ProverClient::from_env(); let (pk, vk) = client.setup(ELF); - let mut proof = client.prove(&pk, stdin).compressed().run().unwrap(); + let mut proof = client.prove(&pk, &stdin).compressed().run().unwrap(); println!("generated proof"); // Read and verify the output. diff --git a/examples/fibonacci/script/bin/execute.rs b/examples/fibonacci/script/bin/execute.rs index 7b92525a71..7ded48ad37 100644 --- a/examples/fibonacci/script/bin/execute.rs +++ b/examples/fibonacci/script/bin/execute.rs @@ -15,7 +15,7 @@ fn main() { // Only execute the program and get a `SP1PublicValues` object. let client = ProverClient::from_env(); - let (mut public_values, execution_report) = client.execute(ELF, stdin).run().unwrap(); + 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 // the RISC-V opcode and syscall counts. diff --git a/examples/fibonacci/script/bin/groth16_bn254.rs b/examples/fibonacci/script/bin/groth16_bn254.rs index 98e9fa96af..55f421b9c9 100644 --- a/examples/fibonacci/script/bin/groth16_bn254.rs +++ b/examples/fibonacci/script/bin/groth16_bn254.rs @@ -19,7 +19,7 @@ fn main() { println!("vk: {:?}", vk.bytes32()); // Generate the Groth16 proof. - let proof = client.prove(&pk, stdin).groth16().run().unwrap(); + let proof = client.prove(&pk, &stdin).groth16().run().unwrap(); println!("generated proof"); // Get the public values as bytes. diff --git a/examples/fibonacci/script/bin/network.rs b/examples/fibonacci/script/bin/network.rs new file mode 100644 index 0000000000..153a60949a --- /dev/null +++ b/examples/fibonacci/script/bin/network.rs @@ -0,0 +1,77 @@ +use sp1_sdk::network::Error; +use sp1_sdk::{include_elf, utils, ProverClient, SP1ProofWithPublicValues, SP1Stdin}; + +/// The ELF we want to execute inside the zkVM. +const ELF: &[u8] = include_elf!("fibonacci-program"); + +fn main() { + // Setup logging. + utils::setup_logger(); + + // Create an input stream and write '500' to it. + let n = 1000u32; + + // The input stream that the program will read from using `sp1_zkvm::io::read`. Note that the + // types of the elements in the input stream must match the types being read in the program. + let mut stdin = SP1Stdin::new(); + stdin.write(&n); + + // Create a `ProverClient` method. + let client = ProverClient::from_env(); + + // Generate the proof for the given program and input. + let (pk, vk) = client.setup(ELF); + let proof_result = client.prove(&pk, &stdin).compressed().run(); + + // Handle possible prover network errors. + let mut proof = match proof_result { + Ok(proof) => proof, + Err(e) => { + if let Some(network_error) = e.downcast_ref::() { + match network_error { + Error::RequestUnexecutable { request_id: _ } => { + eprintln!("Program is unexecutable: {}", e); + std::process::exit(1); + } + Error::RequestUnfulfillable { request_id: _ } => { + eprintln!("Proof request cannot be fulfilled: {}", e); + std::process::exit(1); + } + _ => { + eprintln!("Unexpected error: {}", e); + std::process::exit(1); + } + } + } else { + eprintln!("Unexpected error: {}", e); + std::process::exit(1); + } + } + }; + + println!("generated proof"); + + // Read and verify the output. + // + // Note that this output is read from values committed to in the program using + // `sp1_zkvm::io::commit`. + let _ = proof.public_values.read::(); + let a = proof.public_values.read::(); + let b = proof.public_values.read::(); + + println!("a: {}", a); + println!("b: {}", b); + + // Verify proof and public values + client.verify(&proof, &vk).expect("verification failed"); + + // Test a round trip of proof serialization and deserialization. + proof.save("proof-with-pis.bin").expect("saving proof failed"); + let deserialized_proof = + SP1ProofWithPublicValues::load("proof-with-pis.bin").expect("loading proof failed"); + + // Verify the deserialized proof. + client.verify(&deserialized_proof, &vk).expect("verification failed"); + + println!("successfully generated and verified proof for the program!") +} diff --git a/examples/fibonacci/script/bin/plonk_bn254.rs b/examples/fibonacci/script/bin/plonk_bn254.rs index 48f9c51a37..5f7b3be903 100644 --- a/examples/fibonacci/script/bin/plonk_bn254.rs +++ b/examples/fibonacci/script/bin/plonk_bn254.rs @@ -19,7 +19,7 @@ fn main() { println!("vk: {:?}", vk.bytes32()); // Generate the Plonk proof. - let proof = client.prove(&pk, stdin).plonk().run().unwrap(); + let proof = client.prove(&pk, &stdin).plonk().run().unwrap(); println!("generated proof"); // Get the public values as bytes. diff --git a/examples/fibonacci/script/src/main.rs b/examples/fibonacci/script/src/main.rs index 442fce04c5..eb3a16f4da 100644 --- a/examples/fibonacci/script/src/main.rs +++ b/examples/fibonacci/script/src/main.rs @@ -19,12 +19,12 @@ fn main() { 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(); + let (_, report) = client.execute(ELF, &stdin).run().unwrap(); println!("executed program with {} cycles", report.total_instruction_count()); // Generate the proof for the given program and input. let (pk, vk) = client.setup(ELF); - let mut proof = client.prove(&pk, stdin).run().unwrap(); + let mut proof = client.prove(&pk, &stdin).run().unwrap(); println!("generated proof"); diff --git a/examples/groth16/script/src/main.rs b/examples/groth16/script/src/main.rs index 2fecb5493a..498a2e65ca 100644 --- a/examples/groth16/script/src/main.rs +++ b/examples/groth16/script/src/main.rs @@ -28,7 +28,7 @@ fn generate_fibonacci_proof() -> (Vec, Vec, String) { // Generate the groth16 proof for the Fibonacci program. let (pk, vk) = client.setup(FIBONACCI_ELF); println!("vk: {:?}", vk.bytes32()); - let proof = client.prove(&pk, stdin).groth16().run().unwrap(); + let proof = client.prove(&pk, &stdin).groth16().run().unwrap(); (proof.bytes(), proof.public_values.to_vec(), vk.bytes32()) } @@ -49,7 +49,7 @@ fn main() { 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(); + let (_, report) = client.execute(GROTH16_ELF, &stdin).run().unwrap(); println!("executed groth16 program with {} cycles", report.total_instruction_count()); println!("{}", report); } diff --git a/examples/io/script/src/main.rs b/examples/io/script/src/main.rs index 008c69e09d..fa8812c389 100644 --- a/examples/io/script/src/main.rs +++ b/examples/io/script/src/main.rs @@ -25,7 +25,7 @@ fn main() { // Generate the proof for the given program. let client = ProverClient::from_env(); let (pk, vk) = client.setup(ELF); - let mut proof = client.prove(&pk, stdin).run().unwrap(); + let mut proof = client.prove(&pk, &stdin).run().unwrap(); // Read the output. let r = proof.public_values.read::(); diff --git a/examples/is-prime/script/src/main.rs b/examples/is-prime/script/src/main.rs index c965775743..1d866645e9 100644 --- a/examples/is-prime/script/src/main.rs +++ b/examples/is-prime/script/src/main.rs @@ -16,7 +16,7 @@ fn main() { // Generate and verify the proof let client = ProverClient::from_env(); let (pk, vk) = client.setup(ELF); - let mut proof = client.prove(&pk, stdin).run().unwrap(); + let mut proof = client.prove(&pk, &stdin).run().unwrap(); let is_prime = proof.public_values.read::(); println!("Is 29 prime? {}", is_prime); diff --git a/examples/json/script/src/main.rs b/examples/json/script/src/main.rs index 4c3eaa03a4..6c98a6e48d 100644 --- a/examples/json/script/src/main.rs +++ b/examples/json/script/src/main.rs @@ -36,7 +36,7 @@ fn main() { let client = ProverClient::from_env(); let (pk, vk) = client.setup(JSON_ELF); - let mut proof = client.prove(&pk, stdin).run().expect("proving failed"); + let mut proof = client.prove(&pk, &stdin).run().expect("proving failed"); // Read output. let val = proof.public_values.read::(); diff --git a/examples/patch-testing/script/src/main.rs b/examples/patch-testing/script/src/main.rs index 5e85f2b825..7195bfee41 100644 --- a/examples/patch-testing/script/src/main.rs +++ b/examples/patch-testing/script/src/main.rs @@ -9,7 +9,7 @@ pub fn main() { let stdin = SP1Stdin::new(); let client = ProverClient::from_env(); - let (_, report) = client.execute(PATCH_TEST_ELF, stdin).run().expect("executing failed"); + let (_, report) = client.execute(PATCH_TEST_ELF, &stdin).run().expect("executing failed"); // Confirm there was at least 1 SHA_COMPUTE syscall. assert_ne!(report.syscall_counts[sp1_core_executor::syscalls::SyscallCode::SHA_COMPRESS], 0); diff --git a/examples/regex/script/src/main.rs b/examples/regex/script/src/main.rs index 63c8c6fe66..e5ddb0c07f 100644 --- a/examples/regex/script/src/main.rs +++ b/examples/regex/script/src/main.rs @@ -20,7 +20,7 @@ fn main() { // Generate the proof for the given program and input. let client = ProverClient::from_env(); let (pk, vk) = client.setup(REGEX_IO_ELF); - let mut proof = client.prove(&pk, stdin).run().expect("proving failed"); + let mut proof = client.prove(&pk, &stdin).run().expect("proving failed"); // Read the output. let res = proof.public_values.read::(); diff --git a/examples/rsa/script/src/main.rs b/examples/rsa/script/src/main.rs index 991a458d7d..1b7cae8484 100644 --- a/examples/rsa/script/src/main.rs +++ b/examples/rsa/script/src/main.rs @@ -54,7 +54,7 @@ fn main() { // Generate the proof for the given program and input. let client = ProverClient::from_env(); let (pk, vk) = client.setup(RSA_ELF); - let proof = client.prove(&pk, stdin).run().expect("proving failed"); + let proof = client.prove(&pk, &stdin).run().expect("proving failed"); // Verify proof. client.verify(&proof, &vk).expect("verification failed"); diff --git a/examples/rsp/script/src/main.rs b/examples/rsp/script/src/main.rs index 08ded491e0..f1dabacebf 100644 --- a/examples/rsp/script/src/main.rs +++ b/examples/rsp/script/src/main.rs @@ -42,8 +42,7 @@ fn main() { stdin.write_vec(buffer); // Only execute the program. - let (mut public_values, execution_report) = - client.execute(&pk.elf, stdin.clone()).run().unwrap(); + let (mut public_values, execution_report) = client.execute(&pk.elf, &stdin).run().unwrap(); println!( "Finished executing the block in {} cycles", execution_report.total_instruction_count() @@ -57,7 +56,7 @@ fn main() { // It is strongly recommended you use the network prover given the size of these programs. if args.prove { println!("Starting proof generation."); - let proof = client.prove(&pk, stdin).run().expect("Proving should work."); + let proof = client.prove(&pk, &stdin).run().expect("Proving should work."); println!("Proof generation finished."); client.verify(&proof, &vk).expect("proof verification should succeed"); diff --git a/examples/ssz-withdrawals/script/src/main.rs b/examples/ssz-withdrawals/script/src/main.rs index 9a6450bc7d..0da0683968 100644 --- a/examples/ssz-withdrawals/script/src/main.rs +++ b/examples/ssz-withdrawals/script/src/main.rs @@ -10,7 +10,7 @@ fn main() { let stdin = SP1Stdin::new(); let client = ProverClient::from_env(); let (pk, vk) = client.setup(ELF); - let proof = client.prove(&pk, stdin).run().expect("proving failed"); + let proof = client.prove(&pk, &stdin).run().expect("proving failed"); // Verify proof. client.verify(&proof, &vk).expect("verification failed"); diff --git a/examples/tendermint/script/src/main.rs b/examples/tendermint/script/src/main.rs index 298b8ee75f..43ac8cbef4 100644 --- a/examples/tendermint/script/src/main.rs +++ b/examples/tendermint/script/src/main.rs @@ -44,9 +44,9 @@ pub fn main() { let client = ProverClient::from_env(); let (pk, vk) = client.setup(TENDERMINT_ELF); - client.execute(TENDERMINT_ELF, stdin.clone()).run().expect("proving failed"); + client.execute(TENDERMINT_ELF, &stdin).run().expect("proving failed"); - let proof = client.prove(&pk, stdin).run().expect("proving failed"); + let proof = client.prove(&pk, &stdin).run().expect("proving failed"); // Verify proof. client.verify(&proof, &vk).expect("verification failed");