Skip to content

Commit

Permalink
Remove Bonsai SDK ImageIdExists error (#848)
Browse files Browse the repository at this point in the history
Now upload_img() returns a boolean for a user to check if the image
exists within bonsai instead of a Err variant.

---------

Co-authored-by: Rami Lukata <32602478+rlukata@users.noreply.github.com>
  • Loading branch information
mothran and rlukata committed Sep 11, 2023
1 parent 27b5d75 commit 37a82fa
Show file tree
Hide file tree
Showing 8 changed files with 64 additions and 63 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ use std::sync::Arc;
use bonsai_ethereum_contracts::i_bonsai_relay::CallbackRequestFilter;
use bonsai_sdk::{
alpha::Client,
alpha_async::{create_session, put_input},
alpha_async::{create_session, upload_input},
};
use tokio::sync::Notify;
use tracing::info;
Expand Down Expand Up @@ -52,7 +52,8 @@ impl<S: Storage + Sync + Send> EventProcessor for ProxyCallbackProofRequestProce
&self,
event: CallbackRequestFilter,
) -> Result<(), crate::api::error::Error> {
let input_id = put_input(self.bonsai_client.clone(), event.input.clone().to_vec()).await?;
let input_id =
upload_input(self.bonsai_client.clone(), event.input.clone().to_vec()).await?;
let bonsai_session_id = create_session(
self.bonsai_client.clone(),
hex::encode(event.image_id),
Expand Down
20 changes: 8 additions & 12 deletions bonsai/ethereum-relay/tests/e2e_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ mod tests {
Relayer,
};
use bonsai_sdk::{
alpha::{Client as BonsaiClient, SdkErr},
alpha_async::{get_client_from_parts, put_image},
alpha::Client as BonsaiClient,
alpha_async::{get_client_from_parts, upload_img},
};
use ethers::types::{Bytes, H256 as ethers_H256, U256};
use risc0_zkvm::{MemoryImage, Program, MEM_SIZE, PAGE_SIZE};
Expand Down Expand Up @@ -166,11 +166,9 @@ mod tests {
.expect("unable to create memory image");
let image_id = hex::encode(image.compute_id());
let image = bincode::serialize(&image).expect("Failed to serialize memory img");
let upload_result = put_image(bonsai_client.clone(), image_id.clone(), image).await;
match upload_result {
Ok(_) | Err(SdkErr::ImageIdExists) => {}
Err(_) => upload_result.expect("unable to upload result"),
}
upload_img(bonsai_client.clone(), image_id.clone(), image)
.await
.expect("unable to upload result");
image_id
};
dbg!(&image_key);
Expand Down Expand Up @@ -313,11 +311,9 @@ mod tests {
MemoryImage::new(&program, PAGE_SIZE as u32).expect("unable to create memory image");
let image_id = hex::encode(image.compute_id());
let image = bincode::serialize(&image).expect("Failed to serialize memory img");
let upload_result = put_image(bonsai_client.clone(), image_id.clone(), image).await;
match upload_result {
Ok(_) | Err(SdkErr::ImageIdExists) => {}
Err(_) => upload_result.expect("unable to upload result"),
}
upload_img(bonsai_client.clone(), image_id.clone(), image)
.await
.expect("unable to upload result");

// Since we are using the True Elf, the first 4 bytes need to be the length
// of the slice (in little endian)
Expand Down
8 changes: 2 additions & 6 deletions bonsai/examples/governance/relay/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
use std::time::Duration;

use anyhow::{anyhow, bail, Context, Result};
use bonsai_sdk::alpha::{responses::SnarkProof, Client, SdkErr};
use bonsai_sdk::alpha::{responses::SnarkProof, Client};
use risc0_build::GuestListEntry;
use risc0_zkvm::{
Executor, ExecutorEnv, MemoryImage, Program, Receipt, ReceiptMetadata, MEM_SIZE, PAGE_SIZE,
Expand Down Expand Up @@ -65,11 +65,7 @@ pub fn prove_alpha(elf: &[u8], input: Vec<u8>) -> Result<Output> {

let img_id = get_digest(elf).context("Failed to generate elf memory image")?;

match client.upload_img(&img_id, elf.to_vec()) {
Ok(()) => (),
Err(SdkErr::ImageIdExists) => (),
Err(err) => return Err(err.into()),
}
client.upload_img(&img_id, elf.to_vec())?;

let input_id = client
.upload_input(input)
Expand Down
12 changes: 4 additions & 8 deletions bonsai/examples/governance/relay/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ use anyhow::Context;
use bonsai_ethereum_relay::{EthersClientConfig, Relayer};
use bonsai_ethereum_relay_cli::{resolve_guest_entry, resolve_image_output, Output};
use bonsai_sdk::{
alpha::{responses::SnarkProof, SdkErr},
alpha_async::{get_client_from_parts, put_image},
alpha::responses::SnarkProof,
alpha_async::{get_client_from_parts, upload_img},
};
use clap::{Args, Parser, Subcommand};
use ethers::{
Expand Down Expand Up @@ -295,16 +295,12 @@ async fn upload_images(
get_client_from_parts(bonsai_api_url.to_string(), bonsai_api_key.to_string()).await?;
let img_id = image_id.clone();

match put_image(
upload_img(
bonsai_client.clone(),
img_id.clone(),
guest_entry.elf.to_vec(),
)
.await
{
Ok(()) | Err(SdkErr::ImageIdExists) => Ok::<_, anyhow::Error>(()),
Err(err) => Err(err.into()),
}?;
.await?;

image_ids.push(guest_entry.image_id.into());
}
Expand Down
4 changes: 2 additions & 2 deletions bonsai/rest-api-mock/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -111,12 +111,12 @@ mod test {
let image = MemoryImage::new(&program, PAGE_SIZE as u32)?;
let image_id = hex::encode(image.compute_id());
let image = bincode::serialize(&image).expect("Failed to serialize memory img");
bonsai_sdk::put_image(client.clone(), image_id.clone(), image).await?;
bonsai_sdk::upload_img(client.clone(), image_id.clone(), image).await?;
image_id
};

// Prepare input data and upload it.
let input_id = bonsai_sdk::put_input(client.clone(), vec![]).await?;
let input_id = bonsai_sdk::upload_input(client.clone(), vec![]).await?;

// Start a session running the prover
let session = bonsai_sdk::create_session(client.clone(), img_id, input_id).await?;
Expand Down
59 changes: 37 additions & 22 deletions bonsai/sdk/src/alpha.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,6 @@ use self::responses::{
/// Bonsai Alpha SDK error classes
#[derive(Debug, Error)]
pub enum SdkErr {
/// The API already has the supplied imageID
#[error("the supplied imageId already exists")]
ImageIdExists,
/// Server side failure
#[error("server error `{0}`")]
InternalServerErr(String),
Expand Down Expand Up @@ -213,6 +210,11 @@ pub struct Client {
pub(crate) client: BlockingClient,
}

enum ImageExistsOpt {
Exists,
New(ImgUploadRes),
}

/// Creates a [reqwest::Client] for internal connection pooling
fn construct_req_client(api_key: &str) -> Result<BlockingClient, SdkErr> {
let mut headers = header::HeaderMap::new();
Expand Down Expand Up @@ -264,22 +266,22 @@ impl Client {
Ok(res.json::<UploadRes>()?)
}

fn get_image_upload_url(&self, image_id: &str) -> Result<ImgUploadRes, SdkErr> {
fn get_image_upload_url(&self, image_id: &str) -> Result<ImageExistsOpt, SdkErr> {
let res = self
.client
.get(format!("{}/images/upload/{}", self.url, image_id))
.send()?;

if res.status() == 204 {
return Err(SdkErr::ImageIdExists);
return Ok(ImageExistsOpt::Exists);
}

if !res.status().is_success() {
let body = res.text()?;
return Err(SdkErr::InternalServerErr(body));
}

Ok(res.json::<ImgUploadRes>()?)
Ok(ImageExistsOpt::New(res.json::<ImgUploadRes>()?))
}

/// Upload body to a given URL
Expand All @@ -297,27 +299,39 @@ impl Client {

/// Upload a image buffer to the /images/ route
///
/// The boolean return indicates if the image already exists in bonsai
///
/// The image data can be either:
/// * ELF file bytes
/// * bincode encoded MemoryImage
pub fn upload_img(&self, image_id: &str, buf: Vec<u8>) -> Result<(), SdkErr> {
let upload_res = self.get_image_upload_url(image_id)?;
self.put_data(&upload_res.url, buf)?;
Ok(())
pub fn upload_img(&self, image_id: &str, buf: Vec<u8>) -> Result<bool, SdkErr> {
let res_or_exists = self.get_image_upload_url(image_id)?;
match res_or_exists {
ImageExistsOpt::Exists => Ok(true),
ImageExistsOpt::New(upload_res) => {
self.put_data(&upload_res.url, buf)?;
Ok(false)
}
}
}

/// Upload a image file to the /images/ route
///
/// The boolean return indicates if the image already exists in bonsai
///
/// The image data can be either:
/// * ELF file bytes
/// * bincode encoded MemoryImage
pub fn upload_img_file(&self, image_id: &str, path: &Path) -> Result<(), SdkErr> {
let upload_data = self.get_image_upload_url(image_id)?;

let fd = File::open(path)?;
self.put_data(&upload_data.url, fd)?;

Ok(())
pub fn upload_img_file(&self, image_id: &str, path: &Path) -> Result<bool, SdkErr> {
let res_or_exists = self.get_image_upload_url(image_id)?;
match res_or_exists {
ImageExistsOpt::Exists => Ok(true),
ImageExistsOpt::New(upload_res) => {
let fd = File::open(path)?;
self.put_data(&upload_res.url, fd)?;
Ok(false)
}
}
}

// - /inputs
Expand Down Expand Up @@ -478,17 +492,17 @@ mod tests {
let server_url = format!("http://{}", server.address());
let client = super::Client::from_parts(server_url, TEST_KEY.to_string())
.expect("Failed to construct client");
client
let exists = client
.upload_img(TEST_ID, data)
.expect("Failed to upload input");
assert!(!exists);
get_mock.assert();
put_mock.assert();
}

#[test]
#[should_panic(expected = "value: ImageIdExists")]
fn image_upload_dup() {
let data = vec![];
let data = vec![0x41];

let server = MockServer::start();

Expand All @@ -510,12 +524,13 @@ mod tests {
let server_url = format!("http://{}", server.address());
let client = super::Client::from_parts(server_url, TEST_KEY.to_string())
.expect("Failed to construct client");
client.upload_img(TEST_ID, data).unwrap()
let exists = client.upload_img(TEST_ID, data).unwrap();
assert!(exists);
}

#[test]
fn input_upload() {
env_logger::init();
// env_logger::init();
let data = vec![];

let server = MockServer::start();
Expand Down
8 changes: 5 additions & 3 deletions bonsai/sdk/src/alpha_async.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,22 +35,24 @@ pub async fn get_client_from_parts(url: String, api_key: String) -> Result<Clien
}

/// Upload a input buffer to the /inputs/ route
pub async fn put_input(bonsai_client: Client, buf: Vec<u8>) -> Result<String, SdkErr> {
pub async fn upload_input(bonsai_client: Client, buf: Vec<u8>) -> Result<String, SdkErr> {
tokio::task::spawn_blocking(move || bonsai_client.upload_input(buf))
.await
.map_err(|err| SdkErr::InternalServerErr(format!("{err}")))?
}

/// Upload a image buffer to the /images/ route
///
/// The boolean return indicates if the image already exists in bonsai
///
/// The image data can be either:
/// * ELF file bytes
/// * bincode encoded MemoryImage
pub async fn put_image(
pub async fn upload_img(
bonsai_client: Client,
image_id: String,
image: Vec<u8>,
) -> Result<(), SdkErr> {
) -> Result<bool, SdkErr> {
tokio::task::spawn_blocking(move || bonsai_client.upload_img(&image_id, image))
.await
.map_err(|err| SdkErr::InternalServerErr(format!("{err}")))?
Expand Down
11 changes: 3 additions & 8 deletions risc0/zkvm/src/host/client/prove/bonsai.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
use core::time::Duration;

use anyhow::{anyhow, bail, Result};
use bonsai_sdk::alpha::{Client, SdkErr};
use bonsai_sdk::alpha::Client;
use risc0_binfmt::MemoryImage;

use super::Prover;
Expand Down Expand Up @@ -53,13 +53,8 @@ impl Prover for BonsaiProver {
let image_id = hex::encode(image.compute_id());
let image = bincode::serialize(&image)?;

// ImageIdExists indicates that this image has already been uploaded to bonsai.
// If this is the case, simply move on to uploading the input.
match client.upload_img(&image_id, image) {
Ok(()) => (),
Err(SdkErr::ImageIdExists) => (),
Err(err) => return Err(err.into()),
}
// return value 'exists' is ignored here
client.upload_img(&image_id, image)?;

// upload input data
let input_id = client.upload_input(env.input)?;
Expand Down

0 comments on commit 37a82fa

Please sign in to comment.