Skip to content

Commit

Permalink
Bonsai: Migrate SnarkProof types to match backend (#853)
Browse files Browse the repository at this point in the history
Migrated to the more complete SnarkReceipt type from Bonsai to enable
easier ETH verify integrations.
  • Loading branch information
mothran committed Sep 12, 2023
1 parent b5085e5 commit e3ff7ff
Show file tree
Hide file tree
Showing 11 changed files with 115 additions and 161 deletions.
1 change: 1 addition & 0 deletions bonsai/ethereum-relay/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ use ethers::core::types::Address;
use storage::{in_memory::InMemoryStorage, Storage};
use tokio::sync::Notify;
use tracing::info;
pub use uploader::completed_proofs::snark::tokenize_snark_receipt;
use uploader::{
completed_proofs::manager::BonsaiCompleteProofManager,
pending_proofs::manager::BonsaiPendingProofManager,
Expand Down
28 changes: 16 additions & 12 deletions bonsai/ethereum-relay/src/tests/utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@
pub(crate) mod tests {
use bonsai_ethereum_contracts::i_bonsai_relay::CallbackRequestFilter;
use bonsai_sdk::alpha::{
responses::{CreateSessRes, SessionStatusRes, SnarkProof, SnarkStatusRes},
responses::{CreateSessRes, Groth16Seal, SessionStatusRes, SnarkReceipt, SnarkStatusRes},
SessionId,
};
use ethers::types::{Address, Bytes, H256, U256};
use ethers::types::{Address, Bytes, H256};
use risc0_zkvm::{InnerReceipt, Receipt};
use uuid::Uuid;
use wiremock::{
Expand Down Expand Up @@ -51,20 +51,24 @@ pub(crate) mod tests {
let create_snark_res = CreateSessRes {
uuid: receipt_id.to_string(),
};
let zeroes = &U256::zero().to_string();
let a = vec![zeroes.to_string(), zeroes.to_string()];
let zeroes = vec![0x0];
let a = vec![zeroes.clone(), zeroes.clone()];
let b = vec![
vec![zeroes.to_string(), zeroes.to_string()],
vec![zeroes.to_string(), zeroes.to_string()],
vec![zeroes.clone(), zeroes.clone()],
vec![zeroes.clone(), zeroes.clone()],
];
let c = vec![zeroes.to_string(), zeroes.to_string()];
let c = vec![zeroes.clone(), zeroes.clone()];
let public = vec![
zeroes.to_string(),
zeroes.to_string(),
zeroes.to_string(),
zeroes.to_string(),
zeroes.clone(),
zeroes.clone(),
zeroes.clone(),
zeroes.clone(),
];
let dummy_snark = Some(SnarkProof { a, b, c, public });
let dummy_snark = Some(SnarkReceipt {
snark: Groth16Seal { a, b, c, public },
post_state_digest: vec![],
journal: vec![],
});
let snark_status_res = SnarkStatusRes {
status: "SUCCEEDED".to_string(),
output: dummy_snark,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,11 @@ use bonsai_ethereum_contracts::i_bonsai_relay::{
};
use bonsai_sdk::{
alpha::{Client, SessionId},
alpha_async::{download, session_status},
alpha_async::session_status,
};
use ethers::abi;
use risc0_zkvm::Receipt;

use super::snark::tokenize_snark_proof;
use super::snark::tokenize_snark_receipt;
use crate::{api, uploader::completed_proofs::error::CompleteProofError};

#[derive(Debug, Clone)]
Expand All @@ -37,23 +36,7 @@ pub(crate) async fn get_complete_proof(
bonsai_proof_id: SessionId,
callback_request: CallbackRequestFilter,
) -> Result<CompleteProof, CompleteProofError> {
let bonsai_response = session_status(bonsai_client.clone(), bonsai_proof_id.clone())
.await
.map_err(|err| CompleteProofError::ClientAPI {
source: api::error::Error::Bonsai(err),
id: bonsai_proof_id.clone(),
})?;

let receipt_url_result = match bonsai_response.receipt_url {
Some(url) => Ok(url),
None => Err(CompleteProofError::ReceiptNotFound {
id: bonsai_proof_id.clone(),
}),
};

let receipt_url = receipt_url_result?;

let receipt_buf = download(bonsai_client.clone(), receipt_url)
session_status(bonsai_client.clone(), bonsai_proof_id.clone())
.await
.map_err(|err| CompleteProofError::ClientAPI {
source: api::error::Error::Bonsai(err),
Expand All @@ -62,38 +45,30 @@ pub(crate) async fn get_complete_proof(

let snark_id =
super::snark::get_snark_id(bonsai_client.clone(), bonsai_proof_id.clone()).await?;
let snark_proof =
super::snark::get_snark_proof(bonsai_client.clone(), snark_id, bonsai_proof_id.clone())
let snark_receipt =
super::snark::get_snark_receipt(bonsai_client.clone(), snark_id, bonsai_proof_id.clone())
.await?;
let seal = match dev_mode {
true => vec![],
false => abi::encode(&[tokenize_snark_proof(&snark_proof).map_err(|_| {
false => abi::encode(&[tokenize_snark_receipt(&snark_receipt.snark).map_err(|_| {
CompleteProofError::SnarkFailed {
id: bonsai_proof_id.clone(),
}
})?]),
};

let receipt: Receipt =
bincode::deserialize(&receipt_buf).map_err(|_| CompleteProofError::InvalidReceipt {
id: bonsai_proof_id.clone(),
})?;
let post_state_digest: [u8; 32] = match dev_mode {
false => {
let metadata =
receipt
.get_metadata()
.map_err(|_| CompleteProofError::InvalidReceipt {
id: bonsai_proof_id.clone(),
})?;
metadata.post.digest().into()
}
false => snark_receipt.post_state_digest.try_into().map_err(|_err| {
CompleteProofError::SnarkFailed {
id: bonsai_proof_id.clone(),
}
})?,
true => [0u8; 32],
};

let payload = [
callback_request.function_selector.as_slice(),
receipt.journal.as_slice(),
snark_receipt.journal.as_slice(),
callback_request.image_id.as_slice(),
]
.concat();
Expand Down
6 changes: 0 additions & 6 deletions bonsai/ethereum-relay/src/uploader/completed_proofs/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,6 @@ impl BonsaiCompleteProofManagerError {
pub(crate) enum CompleteProofError {
/// bonsai client error for proof
ClientAPI { source: Error, id: ProofID },
/// bonsai receipt was not found for proof
ReceiptNotFound { id: ProofID },
/// bonsai snark conversion for proof failed
SnarkFailed { id: ProofID },
/// bonsai snark timed out
Expand All @@ -76,8 +74,6 @@ pub(crate) enum CompleteProofError {
SnarkAborted { id: ProofID },
/// bonsai snark is in unknown state
SnarkUnknown { id: ProofID },
/// invalid receipt
InvalidReceipt { id: ProofID },
}

impl CompleteProofError {
Expand All @@ -87,8 +83,6 @@ impl CompleteProofError {
| CompleteProofError::SnarkFailed { id }
| CompleteProofError::SnarkTimedOut { id }
| CompleteProofError::SnarkUnknown { id }
| CompleteProofError::ReceiptNotFound { id }
| CompleteProofError::InvalidReceipt { id }
| CompleteProofError::ClientAPI { id, .. } => id,
}
}
Expand Down
2 changes: 1 addition & 1 deletion bonsai/ethereum-relay/src/uploader/completed_proofs/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,4 @@
mod complete_proof;
mod error;
pub(crate) mod manager;
mod snark;
pub(crate) mod snark;
50 changes: 31 additions & 19 deletions bonsai/ethereum-relay/src/uploader/completed_proofs/snark.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
use std::time::Duration;

use bonsai_sdk::{
alpha::{responses::SnarkProof, Client, SessionId, SnarkId},
alpha::{responses::Groth16Seal, Client, SessionId, SnarkId},
alpha_async::{create_snark, snark_status},
};
use ethers::{
Expand All @@ -40,11 +40,11 @@ pub(crate) async fn get_snark_id(
Ok(snark_id)
}

pub(crate) async fn get_snark_proof(
pub(crate) async fn get_snark_receipt(
client: Client,
snark_id: SnarkId,
session_id: SessionId,
) -> Result<bonsai_sdk::alpha::responses::SnarkProof, CompleteProofError> {
) -> Result<bonsai_sdk::alpha::responses::SnarkReceipt, CompleteProofError> {
// Hit the Bonsai API until the receipt is ready
// TODO: This is not the most efficient way to do this. We should convert to
// a Future implementation later.
Expand All @@ -57,7 +57,7 @@ pub(crate) async fn get_snark_proof(
})?;
match (snark.status.as_str(), snark.output) {
("RUNNING", _) => tokio::time::sleep(Duration::from_secs(1)).await,
("SUCCEEDED", Some(snark_proof)) => break snark_proof,
("SUCCEEDED", Some(snark_receipt)) => break snark_receipt,
("SUCCEEDED", None) => return Err(CompleteProofError::SnarkFailed { id: session_id }),
("FAILED", _) => return Err(CompleteProofError::SnarkFailed { id: session_id }),
("TIMED_OUT", _) => return Err(CompleteProofError::SnarkTimedOut { id: session_id }),
Expand All @@ -69,17 +69,7 @@ pub(crate) async fn get_snark_proof(
Ok(proof)
}

/// Parse a slice of strings as a fixed array of uint256 tokens.
pub(crate) fn parse_to_tokens(slice: &[String]) -> anyhow::Result<Token> {
Ok(Token::FixedArray(
slice
.iter()
.map(|s| -> anyhow::Result<_> { Ok(U256::from_str_radix(s, 16)?.into_token()) })
.collect::<Result<Vec<_>, _>>()?,
))
}

pub(crate) fn tokenize_snark_proof(proof: &SnarkProof) -> anyhow::Result<Token> {
pub fn tokenize_snark_receipt(proof: &Groth16Seal) -> anyhow::Result<Token> {
if proof.b.len() != 2 {
anyhow::bail!("hex-strings encoded proof is not well formed");
}
Expand All @@ -89,11 +79,33 @@ pub(crate) fn tokenize_snark_proof(proof: &SnarkProof) -> anyhow::Result<Token>
}
}
Ok(Token::FixedArray(vec![
parse_to_tokens(&proof.a)?,
Token::FixedArray(
proof
.a
.iter()
.map(|elm| U256::from_big_endian(elm).into_token())
.collect(),
),
Token::FixedArray(vec![
parse_to_tokens(&proof.b[0])?,
parse_to_tokens(&proof.b[1])?,
Token::FixedArray(
proof.b[0]
.iter()
.map(|elm| U256::from_big_endian(elm).into_token())
.collect(),
),
Token::FixedArray(
proof.b[1]
.iter()
.map(|elm| U256::from_big_endian(elm).into_token())
.collect(),
),
]),
parse_to_tokens(&proof.c)?,
Token::FixedArray(
proof
.c
.iter()
.map(|elm| U256::from_big_endian(elm).into_token())
.collect(),
),
]))
}
27 changes: 7 additions & 20 deletions bonsai/examples/governance/relay/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,22 +15,14 @@
use std::time::Duration;

use anyhow::{anyhow, bail, Context, Result};
use bonsai_sdk::alpha::{responses::SnarkProof, Client};
use bonsai_sdk::alpha::{responses::SnarkReceipt, Client};
use risc0_build::GuestListEntry;
use risc0_zkvm::{
Executor, ExecutorEnv, MemoryImage, Program, Receipt, ReceiptMetadata, MEM_SIZE, PAGE_SIZE,
};
use risc0_zkvm::{Executor, ExecutorEnv, MemoryImage, Program, Receipt, MEM_SIZE, PAGE_SIZE};

/// Result of executing a guest image, possibly containing a proof.
pub enum Output {
Execution {
journal: Vec<u8>,
},
Bonsai {
journal: Vec<u8>,
receipt_metadata: ReceiptMetadata,
snark_proof: SnarkProof,
},
Execution { journal: Vec<u8> },
Bonsai { snark_receipt: SnarkReceipt },
}

/// Execute and prove the guest locally, on this machine, as opposed to sending
Expand Down Expand Up @@ -76,7 +68,7 @@ pub fn prove_alpha(elf: &[u8], input: Vec<u8>) -> Result<Output> {
.context("Failed to create remote proving session")?;

// Poll and await the result of the STARK rollup proving session.
let receipt: Receipt = (|| {
let _receipt: Receipt = (|| {
loop {
let res = match session.status(&client) {
Ok(res) => res,
Expand Down Expand Up @@ -111,10 +103,9 @@ pub fn prove_alpha(elf: &[u8], input: Vec<u8>) -> Result<Output> {
}
}
})()?;
let metadata = receipt.get_metadata()?;

let snark_session = client.create_snark(session.uuid)?;
let snark_proof: SnarkProof = (|| loop {
let snark_receipt: SnarkReceipt = (|| loop {
let res = snark_session.status(&client)?;
match res.status.as_str() {
"RUNNING" => {
Expand All @@ -135,11 +126,7 @@ pub fn prove_alpha(elf: &[u8], input: Vec<u8>) -> Result<Output> {
}
})()?;

Ok(Output::Bonsai {
journal: receipt.journal,
receipt_metadata: metadata,
snark_proof,
})
Ok(Output::Bonsai { snark_receipt })
}

pub fn resolve_guest_entry<'a>(
Expand Down

0 comments on commit e3ff7ff

Please sign in to comment.