#![allow(clippy::needless_doctest_main)]
use alloc::vec::Vec;
use borsh::BorshDeserialize;
use hyli_model::Calldata;
use crate::{utils::as_hyli_output, HyliOutput};
use crate::{RunResult, TransactionalZkContract, ZkContract};
pub trait GuestEnv {
fn log(&self, message: &str);
fn commit(&self, output: Vec<HyliOutput>);
fn read<T: BorshDeserialize + 'static>(&self) -> T;
}
pub struct Risc0Env;
#[cfg(feature = "risc0")]
use alloc::vec;
#[cfg(feature = "risc0")]
impl GuestEnv for Risc0Env {
fn log(&self, message: &str) {
risc0_zkvm::guest::env::log(message);
}
fn commit(&self, output: Vec<HyliOutput>) {
risc0_zkvm::guest::env::commit(&output);
}
fn read<T: BorshDeserialize>(&self) -> T {
let len: usize = risc0_zkvm::guest::env::read();
let mut slice = vec![0u8; len];
risc0_zkvm::guest::env::read_slice(&mut slice);
#[allow(clippy::unwrap_used, reason = "should panic here")]
borsh::from_slice(&slice).unwrap()
}
}
pub struct SP1Env;
#[cfg(feature = "sp1")]
impl GuestEnv for SP1Env {
fn log(&self, message: &str) {
sp1_zkvm::io::hint(&message);
}
fn commit(&self, output: Vec<HyliOutput>) {
#[allow(clippy::unwrap_used, reason = "should panic here")]
let vec = borsh::to_vec(&output).unwrap();
sp1_zkvm::io::commit_slice(&vec);
}
fn read<T: BorshDeserialize>(&self) -> T {
let vec = sp1_zkvm::io::read_vec();
#[allow(clippy::unwrap_used, reason = "should panic here")]
borsh::from_slice(&vec).unwrap()
}
}
pub fn execute<Z>(commitment_metadata: &[u8], calldata: &[Calldata]) -> Vec<HyliOutput>
where
Z: ZkContract + TransactionalZkContract + BorshDeserialize + 'static,
{
#[allow(clippy::expect_used, reason = "Required to generate valid proofs")]
let mut contract: Z =
borsh::from_slice(commitment_metadata).expect("Failed to decode commitment metadata");
let mut initial_state_commitment = contract.commit();
let mut outputs = Vec::with_capacity(calldata.len());
if let Err(e) = contract.initialize() {
for calldata in calldata.iter() {
outputs.push(as_hyli_output(
initial_state_commitment.clone(),
initial_state_commitment.clone(),
calldata,
&mut Err(e.clone()),
));
}
return outputs;
}
for calldata in calldata.iter() {
let initial_contract = contract.initial_state();
let mut res: RunResult = contract.execute(calldata);
let next_state_commitment = if res.is_err() {
contract.revert(initial_contract);
initial_state_commitment.clone()
} else {
contract.on_success()
};
outputs.push(as_hyli_output(
initial_state_commitment,
next_state_commitment.clone(),
calldata,
&mut res,
));
initial_state_commitment = next_state_commitment;
}
outputs
}