From 586adba246578ef3fcf3b4e82e12ef0840d5c66f Mon Sep 17 00:00:00 2001 From: Pote <81638931+willpote@users.noreply.github.com> Date: Wed, 27 Aug 2025 18:40:36 -0500 Subject: [PATCH 1/4] Modify client upload_input to reduce risk of error --- crates/boundless-market/src/client.rs | 42 +++++++++++++++++-- .../site/pages/developers/tooling/sdk.mdx | 7 +++- .../pages/developers/tutorials/request.mdx | 4 +- .../tutorials/smart-contract-requestor.mdx | 2 +- 4 files changed, 47 insertions(+), 8 deletions(-) diff --git a/crates/boundless-market/src/client.rs b/crates/boundless-market/src/client.rs index 56a813ece..5d74d079b 100644 --- a/crates/boundless-market/src/client.rs +++ b/crates/boundless-market/src/client.rs @@ -50,6 +50,7 @@ use crate::{ StorageProviderConfig, }, util::NotProvided, + GuestEnv, }; /// Builder for the [Client] with standard implementations for the required components. @@ -629,20 +630,55 @@ where .map_err(|_| anyhow!("Failed to upload program"))?) } - /// Upload input to the storage provider. - pub async fn upload_input(&self, input: &[u8]) -> Result + /// Upload program input to the storage provider. + /// + /// Boundless uses a structured input format for guest programs, defined by the [GuestEnv] struct. + /// + /// ```rust + /// # use boundless_market::client::Client; + /// # use boundless_market::GuestEnv; + /// # |client: Client| { + /// let input_bytes = b"Hello, world!"; + /// let guest_env = GuestEnv::from_stdin(input_bytes); + /// client.upload_input(&guest_env); + /// # }; + /// ``` + pub async fn upload_input(&self, guest_env: &GuestEnv) -> Result where St: StorageProvider, { + let input = guest_env.encode().context("Failed to encode guest env")?; Ok(self .storage_provider .as_ref() .context("Storage provider not set")? - .upload_input(input) + .upload_input(&input) .await .map_err(|_| anyhow!("Failed to upload input"))?) } + /// Upload program input, provided as bytes, to the storage provider. + /// + /// Boundless uses a structured input format for guest programs, defined by the [GuestEnv] struct. + /// + /// This method is a convenience method that creates a [GuestEnv] struct, where the provided bytes + /// are set as the stdin, and uploads it to the storage provider. + /// + /// ```rust + /// # use boundless_market::client::Client; + /// # use boundless_market::GuestEnv; + /// # |client: Client, input_bytes: &[u8]| { + /// client.upload_input_bytes(input_bytes); + /// # }; + /// ``` + pub async fn upload_input_bytes(&self, input_bytes: &[u8]) -> Result + where + St: StorageProvider, + { + let guest_env = GuestEnv::from_stdin(input_bytes); + self.upload_input(&guest_env).await + } + /// Initial parameters that will be used to build a [ProofRequest] using the [RequestBuilder]. pub fn new_request(&self) -> Params where diff --git a/documentation/site/pages/developers/tooling/sdk.mdx b/documentation/site/pages/developers/tooling/sdk.mdx index 529f55507..9e5ca6d5e 100644 --- a/documentation/site/pages/developers/tooling/sdk.mdx +++ b/documentation/site/pages/developers/tooling/sdk.mdx @@ -44,8 +44,10 @@ let client = Client::builder() ```rust +# use std::time::SystemTime; # use boundless_market::{Client, storage::storage_provider_from_env}; # use alloy::signers::local::LocalSigner; +# use std::borrow::Cow; # use url::Url; # async fn upload_program_and_input(rpc_url: Url) -> anyhow::Result<()> { # let client = Client::builder() @@ -54,8 +56,9 @@ let client = Client::builder() # .with_storage_provider(Some(storage_provider_from_env()?)) # .build() # .await?; -let program_url = client.upload_program(&std::fs::read("guest.bin")?).await?; -let input_url = client.upload_input(&[0x41, 0x42, 0x43]).await?; +let input = format!("{:?}", SystemTime::now()); +let program: Cow<'static, [u8]> = std::fs::read("guest.bin")?.into(); +let request = client.new_request().with_program(program).with_stdin(input.as_bytes()); # Ok(()) # } ``` diff --git a/documentation/site/pages/developers/tutorials/request.mdx b/documentation/site/pages/developers/tutorials/request.mdx index 10b1a149e..6157ac13f 100644 --- a/documentation/site/pages/developers/tutorials/request.mdx +++ b/documentation/site/pages/developers/tutorials/request.mdx @@ -287,12 +287,12 @@ Program inputs are uploaded to the same storage provider. This can be done manua ```rust # use boundless_market::{Client, storage::storage_provider_from_env}; -# async fn upload_input(input_bytes: Vec) -> Result<(), Box> { +# async fn upload_input_bytes(input_bytes: Vec) -> Result<(), Box> { # let client = Client::builder() # .with_storage_provider(Some(storage_provider_from_env()?)) # .build() # .await?; -let input_url = client.upload_input(&input_bytes).await?; +let input_url = client.upload_input_bytes(&input_bytes).await?; # Ok(()) # } ``` diff --git a/documentation/site/pages/developers/tutorials/smart-contract-requestor.mdx b/documentation/site/pages/developers/tutorials/smart-contract-requestor.mdx index a05816783..21871179b 100644 --- a/documentation/site/pages/developers/tutorials/smart-contract-requestor.mdx +++ b/documentation/site/pages/developers/tutorials/smart-contract-requestor.mdx @@ -106,7 +106,7 @@ First we execute the guest program locally with our expected input, to generate let input = days_since_epoch.to_be_bytes(); let guest_env = GuestEnv::from_stdin(input); let input_url = client - .upload_input(&guest_env.encode()?) + .upload_input(&guest_env) .await .context("failed to upload input")?; From 10137fc5ae7bac30515a2e49ec3805551ce3744b Mon Sep 17 00:00:00 2001 From: Pote <81638931+willpote@users.noreply.github.com> Date: Wed, 27 Aug 2025 19:22:15 -0500 Subject: [PATCH 2/4] Upload fixes --- crates/boundless-market/src/client.rs | 40 +++++++++++++++++++++++---- 1 file changed, 35 insertions(+), 5 deletions(-) diff --git a/crates/boundless-market/src/client.rs b/crates/boundless-market/src/client.rs index 5d74d079b..9d5521f23 100644 --- a/crates/boundless-market/src/client.rs +++ b/crates/boundless-market/src/client.rs @@ -657,7 +657,7 @@ where .map_err(|_| anyhow!("Failed to upload input"))?) } - /// Upload program input, provided as bytes, to the storage provider. + /// Upload program input, with stdin set to the provided bytes array, to the storage provider. /// /// Boundless uses a structured input format for guest programs, defined by the [GuestEnv] struct. /// @@ -667,6 +667,31 @@ where /// ```rust /// # use boundless_market::client::Client; /// # use boundless_market::GuestEnv; + /// # |client: Client, stdin_bytes: &[u8]| { + /// client.upload_input_stdin(stdin_bytes); + /// # }; + /// ``` + pub async fn upload_input_stdin(&self, stdin_bytes: &[u8]) -> Result + where + St: StorageProvider, + { + let guest_env = GuestEnv::from_stdin(stdin_bytes); + self.upload_input(&guest_env).await + } + + /// Upload program input as the provided bytes array, to the storage provider. + /// + /// The bytes array _must_ be encoded using the scheme defined in [GuestEnv] in + /// order for the input to be used on Boundless. + /// + /// Note: Typically, you will want to use [upload_input] or [upload_input_stdin], which + /// handle encoding inputs into the structured format that is expected by Boundless provers. + /// + /// Note: + /// + /// ```rust + /// # use boundless_market::client::Client; + /// # use boundless_market::GuestEnv; /// # |client: Client, input_bytes: &[u8]| { /// client.upload_input_bytes(input_bytes); /// # }; @@ -675,11 +700,16 @@ where where St: StorageProvider, { - let guest_env = GuestEnv::from_stdin(input_bytes); - self.upload_input(&guest_env).await + Ok(self + .storage_provider + .as_ref() + .context("Storage provider not set")? + .upload_input(input_bytes) + .await + .map_err(|_| anyhow!("Failed to upload input"))?) } - - /// Initial parameters that will be used to build a [ProofRequest] using the [RequestBuilder]. + + /// Create a new request builder. pub fn new_request(&self) -> Params where R: RequestBuilder, From 2c91806b14ddba42f89d5c83b4a4eaaafc2f6bdf Mon Sep 17 00:00:00 2001 From: Pote <81638931+willpote@users.noreply.github.com> Date: Fri, 29 Aug 2025 13:59:03 -0500 Subject: [PATCH 3/4] Lint --- crates/boundless-market/src/client.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/boundless-market/src/client.rs b/crates/boundless-market/src/client.rs index 9d5521f23..599f5d39a 100644 --- a/crates/boundless-market/src/client.rs +++ b/crates/boundless-market/src/client.rs @@ -684,10 +684,10 @@ where /// The bytes array _must_ be encoded using the scheme defined in [GuestEnv] in /// order for the input to be used on Boundless. /// - /// Note: Typically, you will want to use [upload_input] or [upload_input_stdin], which + /// Note: Typically, you will want to use [`Self::upload_input`] or [`Self::upload_input_stdin`], which /// handle encoding inputs into the structured format that is expected by Boundless provers. - /// - /// Note: + /// + /// Note: /// /// ```rust /// # use boundless_market::client::Client; @@ -708,7 +708,7 @@ where .await .map_err(|_| anyhow!("Failed to upload input"))?) } - + /// Create a new request builder. pub fn new_request(&self) -> Params where From 026babdd9d909e71b45c82494c5d329be4696f42 Mon Sep 17 00:00:00 2001 From: Pote <81638931+willpote@users.noreply.github.com> Date: Sat, 30 Aug 2025 10:15:20 -0500 Subject: [PATCH 4/4] Fix compilation errors in documentation and tests --- contracts/deployment-test/Deploymnet.t.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/contracts/deployment-test/Deploymnet.t.sol b/contracts/deployment-test/Deploymnet.t.sol index c0cdfe485..8f44d2bb5 100644 --- a/contracts/deployment-test/Deploymnet.t.sol +++ b/contracts/deployment-test/Deploymnet.t.sol @@ -122,7 +122,7 @@ contract DeploymentTest is Test { require(address(stakeToken) != address(0), "no stake token address is set"); require(keccak256(address(stakeToken).code) != keccak256(bytes("")), "stake token code is empty"); require( - address(stakeToken) == BoundlessMarket(address(boundlessMarket)).STAKE_TOKEN_CONTRACT(), + address(stakeToken) == BoundlessMarket(address(boundlessMarket)).STAKE_TOKEN_CONTRACT, "stake token address does not match boundless market" ); }