diff --git a/src/sharp/mod.rs b/src/sharp/mod.rs index 3db5cd1a..fb2566b6 100644 --- a/src/sharp/mod.rs +++ b/src/sharp/mod.rs @@ -3,7 +3,8 @@ pub mod pie; use std::path::PathBuf; use cairo_vm::vm::runners::cairo_pie::CairoPie; -use serde::Deserialize; +use reqwest::blocking::Client; +use serde::{Deserialize, Serialize}; use serde_json::json; use uuid::Uuid; @@ -13,81 +14,79 @@ use crate::error::SnOsError; pub const DEFUALT_SHARP_URL: &str = "https://testnet.provingservice.io"; pub const _LAMBDA_MAX_PIE_MB: u64 = 20_971_520; -#[derive(Debug)] -#[allow(dead_code)] +#[derive(Default, Clone, Debug, Deserialize, Serialize, PartialEq)] +#[allow(non_camel_case_types)] pub enum CairoJobStatus { - Unknown, - NotCreated, - InProgress, - Processed, - Onchain, - Invalid, - Failed, + #[default] + UNKNOWN, + NOT_CREATED, + IN_PROGRESS, + PROCESSED, + ONCHAIN, + INVALID, + FAILED, } -#[allow(dead_code)] -impl CairoJobStatus { - fn as_str(&self) -> &'static str { - match self { - CairoJobStatus::Unknown => "UNKNOWN", - CairoJobStatus::NotCreated => "NOT_CREATED", - CairoJobStatus::InProgress => "IN_PROGRESS", - CairoJobStatus::Processed => "PROCESSED", - CairoJobStatus::Onchain => "ONCHAIN", - CairoJobStatus::Invalid => "INVALID", - CairoJobStatus::Failed => "FAILED", - } - } +#[derive(Default, Clone, Debug, Deserialize, Serialize, PartialEq)] +#[allow(non_camel_case_types)] +pub enum InvalidReason { + #[default] + CAIRO_PIE_RUN_FAILURE, + FAILED_TO_GENERATE_FACT, + INCOMPATIBLE_PRIME, + NO_COMPATIBLE_LAYOUT, + INVALID_BUILTIN_ORDER_DECLERATION, + INVALID_BUILTIN_USAGE, + INVALID_CAIRO_PIE_FILE_FORMAT, + INVALID_CAIRO_PIE_STORAGE_KEY, + PAGE_SIZE_EXCEEDS_LIMIT, + SECURITY_CHECK_FAILURE, } -#[derive(Default, Debug, Clone, PartialEq, Deserialize)] -#[serde(rename_all = "camelCase")] +#[derive(Clone, Default, Debug, PartialEq, Deserialize)] pub struct CairoStatusResponse { - pub status: Option, - #[serde(rename = "validation_done")] + pub status: CairoJobStatus, + pub version: u64, pub validation_done: Option, - pub version: Option, + pub error_log: Option, + pub invalid_reason: Option, } #[derive(Default, Debug, Clone, PartialEq, Deserialize)] pub struct CairoJobResponse { + pub version: u64, pub cairo_job_key: Option, - pub version: Option, - #[serde(rename = "errorMessage")] pub error_message: Option, - #[serde(rename = "errorType")] pub error_type: Option, - #[serde(rename = "stackTrace")] pub stack_trace: Option>, } pub struct SharpClient { - client: reqwest::blocking::Client, + client: Client, sharp_addr: String, pie_path: Option, } -pub enum SharPie { +pub enum SharpPie { EncodedPie(String), PieObject(CairoPie), } impl SharpClient { pub fn new(sharp_addr: Option, pie_path: Option) -> Self { - Self { client: reqwest::blocking::Client::new(), sharp_addr: sharp_addr.unwrap_or_default(), pie_path } + Self { client: Client::new(), sharp_addr: sharp_addr.unwrap_or_default(), pie_path } } - pub fn submit_pie(&self, pie: SharPie) -> Result { + pub fn submit_pie(&self, pie: SharpPie) -> Result { let pie_enc = match pie { - SharPie::EncodedPie(encoded_pie) => encoded_pie, - SharPie::PieObject(pie_object) => match &self.pie_path { + SharpPie::EncodedPie(encoded_pie) => encoded_pie, + SharpPie::PieObject(pie_object) => match &self.pie_path { Some(pp) => pie::encode_pie(pie_object, pp.as_path())?, None => pie::encode_pie_mem(pie_object)?, }, }; let data = json!({ "action": "add_job", "request": { "cairo_pie": pie_enc } }); - println!("DATA: {:?}", data); // CAREFUL NOT TO OVERWHELM SHARP DUE TO SHORT BLOCK TIMES let resp = self @@ -122,6 +121,6 @@ impl SharpClient { impl Default for SharpClient { fn default() -> Self { - Self { client: reqwest::blocking::Client::new(), sharp_addr: DEFUALT_SHARP_URL.to_string(), pie_path: None } + Self { client: Client::new(), sharp_addr: DEFUALT_SHARP_URL.to_string(), pie_path: None } } } diff --git a/src/sharp/pie.rs b/src/sharp/pie.rs index 7f16e094..b1074605 100644 --- a/src/sharp/pie.rs +++ b/src/sharp/pie.rs @@ -1,6 +1,6 @@ use std::fs::File; use std::io::{Cursor, Read, Seek, Write}; -use std::path::Path; +use std::path::{Path, PathBuf}; use base64::engine::general_purpose; use base64::Engine as _; @@ -66,8 +66,12 @@ fn write_to_zip(pie: CairoPie, mut zip: ZipWriter) -> Result } /// Convert the base64 encoding of the pie to an unzipped folder. -pub fn decode_base64_to_unzipped(encoded_pie: &str) -> Result<(), SnOsError> { - let buffer = general_purpose::STANDARD.decode(encoded_pie.as_bytes()).unwrap(); - ZipArchive::new(Cursor::new(&buffer)).unwrap().extract(&Path::new("build/pie")).unwrap(); +pub fn decode_base64_to_unzipped(pie_str: &str, dst: &str) -> Result<(), SnOsError> { + let buffer = + general_purpose::STANDARD.decode(pie_str.as_bytes()).map_err(|e| SnOsError::PieZipping(format!("{e}")))?; + ZipArchive::new(Cursor::new(&buffer)) + .unwrap() + .extract(&PathBuf::from(dst)) + .map_err(|e| SnOsError::PieZipping(format!("{e}")))?; Ok(()) } diff --git a/tests/common/mod.rs b/tests/common/mod.rs index 73d8b2ab..79c29df4 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -25,6 +25,7 @@ use cairo_vm::vm::runners::builtin_runner::{ use cairo_vm::vm::runners::cairo_pie::CairoPie; use cairo_vm::vm::runners::cairo_runner::CairoRunner; use cairo_vm::vm::vm_core::VirtualMachine; +use lazy_static::lazy_static; use rstest::{fixture, rstest}; use snos::config::{StarknetGeneralConfig, DEFAULT_FEE_TOKEN_ADDR, DEFAULT_INPUT_PATH}; use snos::io::output::decode_output; @@ -40,26 +41,26 @@ use starknet_api::{calldata, class_hash, contract_address, patricia_key, stark_f pub const TESTING_FEE: u128 = 0x10000000000000000000000000; pub const TESTING_TRANSFER_AMOUNT: u128 = 0x01000000000000000000000000000000; -// Contract Addresses - 0.12.2 -pub const _TOKEN_FOR_TESTING_ADDRESS_0_12_2: &str = "572b6542feb4bf285b57a056b588d649e067b9cfab2a88c2b2df9ea6bae6049"; -pub const DUMMY_ACCOUNT_ADDRESS_0_12_2: &str = "5ca2b81086d3fbb4f4af2f1deba4b7fd35e8f4b2caee4e056005c51c05c3dd0"; -pub const _DUMMY_TOKEN_ADDRESS_0_12_2: &str = "3400a86fdc294a70fac1cf84f81a2127419359096b846be9814786d4fc056b8"; +// -------------------------------Contract Addresses - 0.12.2------------------------------- +lazy_static! { + pub static ref DUMMY_ACCOUNT_ADDRESS_0_12_2: ContractAddress = + contract_address!("5ca2b81086d3fbb4f4af2f1deba4b7fd35e8f4b2caee4e056005c51c05c3dd0"); + pub static ref TESTING_1_ADDREESS_0_12_2: ContractAddress = + contract_address!("46fd0893101585e0c7ebd3caf8097b179f774102d6373760c8f60b1a5ef8c92"); + pub static ref TESTING_2_ADDREESS_0_12_2: ContractAddress = + contract_address!("4e9665675ca1ac12820b7aff2f44fec713e272efcd3f20aa0fd8ca277f25dc6"); + pub static ref TESTING_3_ADDREESS_0_12_2: ContractAddress = + contract_address!("74cebec93a58b4400af9c082fb3c5adfa0800ff1489f8fc030076491ff86c48"); + pub static ref TESTING_DELEGATE_ADDREESS_0_12_2: ContractAddress = + contract_address!("238e6b5dffc9f0eb2fe476855d0cd1e9e034e5625663c7eda2d871bd4b6eac0"); +} -// Class Hashes - 0.12.2 -// int - 1950604961159131904798252922088285101498625538306083185117403934352241550198 +// -------------------------------Class Hashes - 0.12.2------------------------------- pub const TOKEN_FOR_TESTING_HASH_0_12_2: &str = "45000d731e6d5ad0023e448dd15cab6f997b04a39120daf56a8816d9f436376"; - -// int - 646245114977324210659279014519951538684823368221946044944492064370769527799 pub const DUMMY_ACCOUNT_HASH_0_12_2: &str = "16dc3038da22dde8ad61a786ab9930699cc496c8bccb90d77cc8abee89803f7"; - -// int - 3531298130119845387864440863187980726515137569165069484670944625223023734186 pub const DUMMY_TOKEN_HASH_0_12_2: &str = "7cea4d7710723fa9e33472b6ceb71587a0ce4997ef486638dd0156bdb6c2daa"; - -// int - 3262122051170176624039908867798875903980511552421730070376672653403179864416 pub const TESTING_HASH_0_12_2: &str = "7364bafc3d2c56bc84404a6d8be799f533e518b8808bce86395a9442e1e5160"; - pub const TESTING_HASH_2_0_12_2: &str = "49bcc976d628b1b238aefc20e77303a251a14ba6c99cd543a86708513414057"; - pub const DELEGATE_PROXY_HASH_0_12_2: &str = "1880d2c303f26b658392a2c92a0677f3939f5fdfb960ecf5912afa06ad0b9d9"; #[allow(dead_code)] @@ -182,7 +183,7 @@ pub fn initial_state( *deploy_token_tx.contract_address.0.key(), tranfer_selector.0, stark_felt!(3_u8), - stark_felt!(DUMMY_ACCOUNT_ADDRESS_0_12_2), + *DUMMY_ACCOUNT_ADDRESS_0_12_2.0.key(), stark_felt!(TESTING_TRANSFER_AMOUNT), stark_felt!(0_u8) ], @@ -216,11 +217,7 @@ fn shared_state(initial_state: SharedState) { pub fn prepare_os_test( mut initial_state: SharedState, ) -> (SharedState, Vec) { - let contract_addresses = [ - contract_address!("46fd0893101585e0c7ebd3caf8097b179f774102d6373760c8f60b1a5ef8c92"), - contract_address!("4e9665675ca1ac12820b7aff2f44fec713e272efcd3f20aa0fd8ca277f25dc6"), - contract_address!("74cebec93a58b4400af9c082fb3c5adfa0800ff1489f8fc030076491ff86c48"), - ]; + let contract_addresses = [*TESTING_1_ADDREESS_0_12_2, *TESTING_2_ADDREESS_0_12_2, *TESTING_3_ADDREESS_0_12_2]; let contract_calldata = [ vec![stark_felt!(321_u32), stark_felt!(543_u32)], vec![stark_felt!(111_u32), stark_felt!(987_u32)], @@ -229,7 +226,7 @@ pub fn prepare_os_test( let contract_salts = [stark_felt!(17_u32), stark_felt!(42_u32), stark_felt!(53_u32)]; let mut nonce_manager = NonceManager::default(); - let sender_addr = contract_address!(DUMMY_ACCOUNT_ADDRESS_0_12_2); + let sender_addr = *DUMMY_ACCOUNT_ADDRESS_0_12_2; nonce_manager.next(sender_addr); initial_state @@ -334,7 +331,7 @@ pub fn prepare_os_test( class_hash!(DELEGATE_PROXY_HASH_0_12_2), ); - assert_eq!(contract_address!("238e6b5dffc9f0eb2fe476855d0cd1e9e034e5625663c7eda2d871bd4b6eac0"), delegate_addr); + assert_eq!(*TESTING_DELEGATE_ADDREESS_0_12_2, delegate_addr); txs.push(calldata![ *delegate_addr.0.key(), @@ -362,7 +359,7 @@ pub fn prepare_os_test( *delegate_addr.0.key(), selector_from_name("test_get_caller_address").0, stark_felt!(1_u32), - stark_felt!(DUMMY_ACCOUNT_ADDRESS_0_12_2) + *DUMMY_ACCOUNT_ADDRESS_0_12_2.0.key() ]); txs.push(calldata![ @@ -402,7 +399,7 @@ pub fn prepare_os_test( *delegate_addr.0.key(), selector_from_name("test_get_tx_info").0, stark_felt!(1_u8), - stark_felt!(DUMMY_ACCOUNT_ADDRESS_0_12_2) + *DUMMY_ACCOUNT_ADDRESS_0_12_2.0.key() ], TransactionSignature(vec![stark_felt!(100_u32)]), )); @@ -509,3 +506,8 @@ pub fn load_output() -> StarknetOsOutput { decode_output(raw_output.0).unwrap() } + +#[fixture] +pub fn os_pie_string() -> String { + std::fs::read_to_string("tests/common/data/output_pie.b64").unwrap() +} diff --git a/tests/pie.rs b/tests/pie.rs index da080ce6..2ab09f57 100644 --- a/tests/pie.rs +++ b/tests/pie.rs @@ -5,10 +5,10 @@ use std::path::Path; use cairo_vm::vm::runners::builtin_runner::OUTPUT_BUILTIN_NAME; use cairo_vm::vm::runners::cairo_pie::{BuiltinAdditionalData, CairoPie, OutputBuiltinAdditionalData, SegmentInfo}; use cairo_vm::vm::runners::cairo_runner::ExecutionResources; -use common::setup_pie; +use common::{os_pie_string, setup_pie}; use rstest::rstest; use serde_json::json; -use snos::sharp::pie::{decode_base64_to_unzipped, encode_pie, PIE_FILES}; +use snos::sharp::pie::{decode_base64_to_unzipped, PIE_FILES}; #[rstest] fn pie_metadata_ok(setup_pie: CairoPie) { @@ -78,12 +78,14 @@ fn pie_memory_ok(setup_pie: CairoPie) { } #[rstest] -fn convert_b64_to_raw() { - decode_base64_to_unzipped(&std::fs::read_to_string("tests/common/data/output_pie.b64").unwrap()).unwrap(); +fn convert_b64_to_raw(os_pie_string: String) { + let dst = "build/pie/"; + + decode_base64_to_unzipped(&os_pie_string, dst).unwrap(); for file in PIE_FILES { assert!( - Path::new(&format!("build/pie/{file:}.{:}", if file != "memory" { "json" } else { "bin" })).exists(), + Path::new(&format!("{dst}{file:}.{:}", if file != "memory" { "json" } else { "bin" })).exists(), "Missing file {file:}" ); } diff --git a/tests/sharp.rs b/tests/sharp.rs index 57947dd0..74b5b6ac 100644 --- a/tests/sharp.rs +++ b/tests/sharp.rs @@ -1,33 +1,40 @@ mod common; -use rstest::*; -use snos::sharp::SharpClient; +use common::os_pie_string; +use rstest::rstest; +use snos::sharp::{CairoJobStatus, InvalidReason, SharpClient, SharpPie}; -const _TEST_CAIRO_JOB_ID: &str = "3a24bbca-ad75-49d5-8ced-12796c6c0738"; -const NEW_CAIRO_JOB: &str = "59b5138d-4c6e-49d3-9234-6495223acb43"; +#[rstest] +fn sharp_submit_pie(os_pie_string: String) { + let sharp_client = SharpClient::default(); + let submit_resp = sharp_client.submit_pie(SharpPie::EncodedPie(os_pie_string)).unwrap(); + println!("{submit_resp:?}"); -// #[rstest] -// fn sharp_client_submit(setup_pie: CairoPie) { -// // TODO: implement mocks here, so as to not overwhelm the SHARP -// let sharp_client = SharpClient::default(); -// let submit_resp = sharp_client.submit_pie(setup_pie).unwrap(); -// assert_eq!(submit_resp.cairo_job_key.unwrap().as_bytes().len(), 16); -// } + let job_id = submit_resp.cairo_job_key.unwrap().to_string(); + let status_resp = sharp_client.get_status(&job_id).unwrap(); + println!("RESP: {status_resp:?}"); +} #[rstest] -fn sharp_client_status() { +fn sharp_get_status() { + let good_cairo_job_id = "3a24bbca-ad75-49d5-8ced-12796c6c0738"; + let sharp_client = SharpClient::default(); - let submit_resp = sharp_client.get_status(NEW_CAIRO_JOB).unwrap(); - println!("{submit_resp:?}"); + let status_resp = sharp_client.get_status(good_cairo_job_id).unwrap(); - assert_eq!(submit_resp.version.unwrap(), 1); - assert!(submit_resp.validation_done.unwrap()); + assert_eq!(1, status_resp.version); + assert_eq!(CairoJobStatus::PROCESSED, status_resp.status); } #[rstest] -fn prove_os_run() { +fn sharp_get_status_err() { + let bad_cairo_job_id = "43454c8e-8f43-444f-aab2-edab05bef512"; + let sharp_client = SharpClient::default(); - let pie = std::fs::read_to_string("tests/common/data/output_pie.b64").unwrap(); - let submit_resp = sharp_client.submit_pie(snos::sharp::SharPie::EncodedPie(pie)).unwrap(); - println!("{submit_resp:?}"); + let status_resp = sharp_client.get_status(bad_cairo_job_id).unwrap(); + println!("STATUS: {:?}", status_resp); + + assert_eq!(1, status_resp.version); + assert_eq!(CairoJobStatus::INVALID, status_resp.status); + assert_eq!(InvalidReason::SECURITY_CHECK_FAILURE, status_resp.invalid_reason.unwrap()); } diff --git a/tests/snos.rs b/tests/snos.rs index 583c1f2f..8ee3d4da 100644 --- a/tests/snos.rs +++ b/tests/snos.rs @@ -6,7 +6,8 @@ use blockifier::transaction::objects::TransactionExecutionInfo; use cairo_felt::{felt_str, Felt252}; use common::{ initial_state, load_input, load_output, prepare_os_test, EXPECTED_PREV_ROOT, EXPECTED_UPDATED_ROOT, - TESTING_BLOCK_HASH, TESTING_HASH_0_12_2, + TESTING_1_ADDREESS_0_12_2, TESTING_2_ADDREESS_0_12_2, TESTING_BLOCK_HASH, TESTING_DELEGATE_ADDREESS_0_12_2, + TESTING_HASH_0_12_2, }; use rstest::rstest; use snos::io::{StarknetOsInput, StarknetOsOutput}; @@ -14,10 +15,10 @@ use snos::state::SharedState; use snos::utils::felt_api2vm; use snos::SnOsRunner; use starknet_api::block::BlockNumber; -use starknet_api::core::{ContractAddress, PatriciaKey}; +use starknet_api::core::PatriciaKey; use starknet_api::hash::{StarkFelt, StarkHash}; use starknet_api::state::StorageKey; -use starknet_api::{contract_address, patricia_key, stark_felt}; +use starknet_api::{patricia_key, stark_felt}; #[rstest] fn snos_run_test(_load_input: &StarknetOsInput, initial_state: SharedState) { @@ -28,27 +29,23 @@ fn snos_run_test(_load_input: &StarknetOsInput, initial_state: SharedState, Vec)) { +fn validate_prepared_os_test(prepare_os_test: (SharedState, Vec)) { let (mut prepare_os_test, _) = prepare_os_test; let diff = prepare_os_test.cache.to_state_diff(); - let addr_1 = contract_address!("46fd0893101585e0c7ebd3caf8097b179f774102d6373760c8f60b1a5ef8c92"); - let addr_1_updates = diff.storage_updates.get(&addr_1).unwrap(); + let addr_1_updates = diff.storage_updates.get(&(*TESTING_1_ADDREESS_0_12_2)).unwrap(); assert_eq!(5, addr_1_updates.len()); assert_eq!(&stark_felt!(47_u32), addr_1_updates.get(&StorageKey(patricia_key!(85_u32))).unwrap()); assert_eq!(&stark_felt!(543_u32), addr_1_updates.get(&StorageKey(patricia_key!(321_u32))).unwrap()); assert_eq!(&stark_felt!(666_u32), addr_1_updates.get(&StorageKey(patricia_key!(444_u32))).unwrap()); - let addr_2 = contract_address!("4e9665675ca1ac12820b7aff2f44fec713e272efcd3f20aa0fd8ca277f25dc6"); - let addr_2_updates = diff.storage_updates.get(&addr_2).unwrap(); + let addr_2_updates = diff.storage_updates.get(&(*TESTING_2_ADDREESS_0_12_2)).unwrap(); assert_eq!(&stark_felt!(1_u32), addr_2_updates.get(&StorageKey(patricia_key!(15_u32))).unwrap()); assert_eq!(&stark_felt!(987_u32), addr_2_updates.get(&StorageKey(patricia_key!(111_u32))).unwrap()); assert_eq!(&stark_felt!(888_u32), addr_2_updates.get(&StorageKey(patricia_key!(555_u32))).unwrap()); assert_eq!(&stark_felt!(999_u32), addr_2_updates.get(&StorageKey(patricia_key!(666_u32))).unwrap()); - let delegate_addr = contract_address!("238e6b5dffc9f0eb2fe476855d0cd1e9e034e5625663c7eda2d871bd4b6eac0"); - let delegate_addr_updates = diff.storage_updates.get(&delegate_addr).unwrap(); - // assert_eq!(6, delegate_addr_updates.len()); + let delegate_addr_updates = diff.storage_updates.get(&(*TESTING_DELEGATE_ADDREESS_0_12_2)).unwrap(); assert_eq!(&stark_felt!(456_u32), delegate_addr_updates.get(&StorageKey(patricia_key!(123_u32))).unwrap()); assert_eq!( &stark_felt!("4e5e39d16e565bacdbc7d8d13b9bc2b51a32c8b2b49062531688dcd2f6ec834"), @@ -75,17 +72,11 @@ fn prepared_os_test(prepare_os_test: (SharedState, Vec