From 9761c4a9bdbd51f6fb70a6a057ddf1c70c2d78aa Mon Sep 17 00:00:00 2001 From: Ben Goebel Date: Tue, 10 Oct 2023 08:32:24 -0600 Subject: [PATCH 01/10] update state and storage --- src/io.rs | 2 +- src/lib.rs | 1 - src/state/mod.rs | 119 ++++++++++++--- src/state/node.rs | 2 +- src/state/storage.rs | 135 +++++++++++++++++ src/state/trie.rs | 10 +- src/storage/mod.rs | 73 ---------- tests/common/mod.rs | 329 +++++++++++++++++++++++++++--------------- tests/common/utils.rs | 47 ++---- tests/snos.rs | 14 +- 10 files changed, 471 insertions(+), 261 deletions(-) create mode 100644 src/state/storage.rs delete mode 100644 src/storage/mod.rs diff --git a/src/io.rs b/src/io.rs index dfe6df61..e9134af5 100644 --- a/src/io.rs +++ b/src/io.rs @@ -6,7 +6,7 @@ use starknet_api::transaction::{MessageToL1, MessageToL2}; use crate::{ business_logic::transaction::types::InternalTransaction, config::StarknetGeneralConfig, - state::ContractState, storage::starknet::CommitmentInfo, + state::CommitmentInfo, state::ContractState, }; #[allow(unused)] diff --git a/src/lib.rs b/src/lib.rs index f2416b01..395cc9dd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,7 +5,6 @@ pub mod hints; pub mod io; pub mod sharp; pub mod state; -pub mod storage; pub mod utils; use error::SnOsError; diff --git a/src/state/mod.rs b/src/state/mod.rs index d478546c..ce630ea5 100644 --- a/src/state/mod.rs +++ b/src/state/mod.rs @@ -1,21 +1,23 @@ pub mod node; +pub mod storage; pub mod trie; use blockifier::block_context::BlockContext; use blockifier::execution::contract_class::ContractClass; -use blockifier::state::cached_state::CachedState; +use blockifier::state::cached_state::{CachedState, CommitmentStateDiff}; use blockifier::state::state_api::{State, StateReader}; use cairo_felt::Felt252; -use indexmap::IndexMap; +use indexmap::{IndexMap, IndexSet}; +use storage::DefaultTrieStorage; use papyrus_storage::state::{StateStorageReader, StateStorageWriter}; use papyrus_storage::StorageResult; use papyrus_storage::{db::DbConfig, open_storage, StorageConfig, StorageScope}; use starknet_api::block::BlockNumber; -use starknet_api::core::{ClassHash, PatriciaKey}; +use starknet_api::core::{ClassHash, ContractAddress, PatriciaKey}; use starknet_api::deprecated_contract_class::ContractClass as DeprecatedContractClass; -use starknet_api::hash::StarkHash; +use starknet_api::hash::{StarkFelt, StarkHash}; use starknet_api::patricia_key; use starknet_api::state::{StateDiff, ThinStateDiff}; use tempfile::{tempdir, TempDir}; @@ -23,10 +25,20 @@ use tempfile::{tempdir, TempDir}; use std::collections::HashMap; use crate::config::DEFAULT_STORAGE_TREE_HEIGHT; -use crate::storage::{starknet::CommitmentInfo, DefaultTrieStorage}; use crate::utils::{bits_from_felt, calculate_contract_state_hash, vm_class_to_api_v0}; +use serde::{Deserialize, Serialize}; use trie::{MerkleTrie, PedersenHash}; +type CommitmentFacts = HashMap>; + +#[derive(Debug, Serialize, Deserialize)] +pub struct CommitmentInfo { + pub previous_root: Felt252, + pub updated_root: Felt252, + pub(crate) tree_height: usize, + pub(crate) commitment_facts: CommitmentFacts, +} + pub struct ContractState { _contract_hash: Felt252, _storage_commitment_tree: Felt252, @@ -37,6 +49,10 @@ pub struct SharedState { pub db_conf: StorageConfig, pub cache: CachedState, pub block_context: BlockContext, + pub commitment_storage: DefaultTrieStorage, + pub contract_storage: DefaultTrieStorage, + pub previous_storage_root: (StarkFelt, u64), + pub previous_contract_root: (StarkFelt, u64), _tmp: TempDir, } @@ -51,11 +67,17 @@ impl SharedState { }, scope: StorageScope::default(), }; + let commitment_storage = DefaultTrieStorage::default(); + let contract_storage = DefaultTrieStorage::default(); open_storage(db_conf.clone()).unwrap(); Self { db_conf, cache, block_context, + commitment_storage, + contract_storage, + previous_storage_root: (StarkFelt::ZERO, 0_u64), + previous_contract_root: (StarkFelt::ZERO, 0_u64), _tmp, } } @@ -74,18 +96,21 @@ impl SharedState { } pub fn apply_diff(&mut self) -> CommitmentInfo { + let mut accessed_addrs = IndexSet::new(); + let diff = self.cache.to_state_diff(); let mut deprecated_declared_classes: IndexMap = IndexMap::new(); - for (_addr, class_hash) in diff.address_to_class_hash.clone().into_iter() { + for (addr, class_hash) in diff.address_to_class_hash.clone().into_iter() { match self.cache.get_compiled_contract_class(&class_hash).unwrap() { ContractClass::V0(class_inner) => { deprecated_declared_classes.insert(class_hash, vm_class_to_api_v0(class_inner)); } ContractClass::V1(_) => todo!("handle v1"), } + accessed_addrs.insert(addr); } let state_diff = StateDiff { @@ -96,36 +121,82 @@ impl SharedState { ..StateDiff::default() }; - let mut tree: MerkleTrie = MerkleTrie::empty(); - let storage = DefaultTrieStorage::default(); - - for (addr, nonce) in diff.address_to_nonce { - let class_hash = diff.address_to_class_hash.get(&addr).unwrap(); - - // TODO: dynamically get contract root - let contract_commitment = - calculate_contract_state_hash(*class_hash, patricia_key!("0x0"), nonce); - - tree.set(&storage, bits_from_felt(*addr.0.key()), contract_commitment) - .unwrap(); - } - let updated_root = Felt252::from_bytes_be(tree.commit(&storage).unwrap().root.bytes()); - let (_, mut writer) = open_storage(self.db_conf.clone()).unwrap(); writer .begin_rw_txn() .unwrap() - .append_state_diff(self.block_context.block_number, state_diff, IndexMap::new()) + .append_state_diff( + self.block_context.block_number, + state_diff.clone(), + IndexMap::new(), + ) .unwrap() .commit() .unwrap(); + let mut root_map = HashMap::new(); + + for (addr, updates) in diff.storage_updates { + let mut contract_trie: MerkleTrie = + MerkleTrie::empty(); + + for update in updates.clone() { + contract_trie + .set( + &self.contract_storage, + bits_from_felt(*update.0 .0.key()), + update.1, + ) + .unwrap(); + } + let (contract_root, contract_idx) = + self.contract_storage.commit_and_persist(contract_trie); + root_map.insert(addr, patricia_key!(contract_root)); + accessed_addrs.insert(addr); + } + + for (addr, _) in diff.address_to_nonce.clone().into_iter() { + accessed_addrs.insert(addr); + } + + let previous_storage_root = self.previous_storage_root; + let mut storage_trie: MerkleTrie = + if previous_storage_root.1 > 0 { + MerkleTrie::new(previous_storage_root.1) + } else { + MerkleTrie::empty() + }; + for addr in accessed_addrs { + let nonce = match state_diff.nonces.get(&addr) { + Some(new_nonce) => *new_nonce, + None => self.cache.get_nonce_at(addr).unwrap(), + }; + let root = match root_map.get(&addr) { + Some(inner_root) => *inner_root, + None => patricia_key!("0x0"), + }; + let class_hash = self.cache.get_class_hash_at(addr).unwrap(); + + let contract_commitment = calculate_contract_state_hash(class_hash, root, nonce); + + storage_trie + .set( + &self.commitment_storage, + bits_from_felt(*addr.0.key()), + contract_commitment, + ) + .unwrap(); + } + + let updated_root = self.commitment_storage.commit_and_persist(storage_trie); + self.increment_block(); + self.previous_storage_root = updated_root; CommitmentInfo { - updated_root, - previous_root: Felt252::from(0_u32), + previous_root: Felt252::from_bytes_be(previous_storage_root.0.bytes()), + updated_root: Felt252::from_bytes_be(updated_root.0.bytes()), tree_height: DEFAULT_STORAGE_TREE_HEIGHT, commitment_facts: HashMap::new(), } diff --git a/src/state/node.rs b/src/state/node.rs index 68249193..abe66577 100644 --- a/src/state/node.rs +++ b/src/state/node.rs @@ -45,7 +45,7 @@ pub enum InternalNode { /// A node that has not been fetched from storage yet. /// /// As such, all we know is its hash. - Unresolved(u32), + Unresolved(u64), /// A branch node with exactly two children. Binary(BinaryNode), /// Describes a path connecting two other nodes. diff --git a/src/state/storage.rs b/src/state/storage.rs new file mode 100644 index 00000000..4a4f086e --- /dev/null +++ b/src/state/storage.rs @@ -0,0 +1,135 @@ +use anyhow::Context; +use bitvec::{prelude::BitSlice, prelude::BitVec, prelude::Msb0}; +use starknet_api::hash::StarkFelt; + +use super::trie::{MerkleTrie, StarkHasher}; + +use std::collections::HashMap; + +use crate::utils::felt_from_bits; + +/// Read-only storage used by the [Trie](crate::trie::Trie). +pub trait Storage { + /// Returns the node stored at the given index. + fn get(&self, index: u64) -> anyhow::Result>; + /// Returns the hash of the node at the given index. + fn hash(&self, index: u64) -> anyhow::Result>; + /// Returns the value of the leaf at the given path. + fn leaf(&self, path: &BitSlice) -> anyhow::Result>; +} + +#[derive(Clone, Debug)] +pub enum Node { + Binary { + left: Child, + right: Child, + }, + Edge { + child: Child, + path: BitVec, + }, + LeafBinary, + LeafEdge { + path: BitVec, + }, +} + +#[derive(Clone, Debug)] +pub enum Child { + Id(u64), + Hash(StarkFelt), +} + +#[derive(Clone, Debug, PartialEq)] +pub enum StoredNode { + Binary { left: u64, right: u64 }, + Edge { child: u64, path: BitVec }, + LeafBinary, + LeafEdge { path: BitVec }, +} + +#[derive(Default, Debug)] +pub struct DefaultTrieStorage { + nodes: HashMap, + leaves: HashMap, +} + +impl Storage for DefaultTrieStorage { + fn get(&self, node: u64) -> anyhow::Result> { + Ok(self.nodes.get(&node).map(|x| x.1.clone())) + } + + fn hash(&self, node: u64) -> anyhow::Result> { + Ok(self.nodes.get(&node).map(|x| x.0)) + } + + fn leaf(&self, path: &BitSlice) -> anyhow::Result> { + assert!(path.len() == 251); + + let key = felt_from_bits(path).context("Mapping path to felt")?; + + Ok(self.leaves.get(&key).cloned()) + } +} + +impl DefaultTrieStorage { + pub fn commit_and_persist( + &mut self, + tree: MerkleTrie, + ) -> (StarkFelt, u64) { + for (key, value) in &tree.leaves { + let key = felt_from_bits(key).unwrap(); + self.leaves.insert(key, *value); + } + + let update = tree.commit(self).unwrap(); + + let mut indices = HashMap::new(); + let mut idx = self.nodes.len(); + for hash in update.nodes.keys() { + indices.insert(*hash, idx as u64); + idx += 1; + } + + for (hash, node) in update.nodes { + let node = match node { + Node::Binary { left, right } => { + let left = match left { + Child::Id(idx) => idx, + Child::Hash(hash) => { + *indices.get(&hash).expect("Left child should have an index") + } + }; + + let right = match right { + Child::Id(idx) => idx, + Child::Hash(hash) => *indices + .get(&hash) + .expect("Right child should have an index"), + }; + + StoredNode::Binary { left, right } + } + Node::Edge { child, path } => { + let child = match child { + Child::Id(idx) => idx, + Child::Hash(hash) => { + *indices.get(&hash).expect("Child should have an index") + } + }; + + StoredNode::Edge { child, path } + } + Node::LeafBinary => StoredNode::LeafBinary, + Node::LeafEdge { path } => StoredNode::LeafEdge { path }, + }; + + self.nodes + .insert(*indices.get(&hash).unwrap(), (hash, node)); + } + + let index = *indices.get(&update.root).unwrap(); + + (update.root, index) + } +} diff --git a/src/state/trie.rs b/src/state/trie.rs index efdf628a..43b06722 100644 --- a/src/state/trie.rs +++ b/src/state/trie.rs @@ -3,7 +3,7 @@ //! use super::node::{BinaryNode, Direction, EdgeNode, InternalNode, TrieNode}; -use crate::storage::{Child, Node, Storage, StoredNode}; +use super::storage::{Child, Node, Storage, StoredNode}; use anyhow::Context; use bitvec::{prelude::BitSlice, prelude::BitVec, prelude::Msb0}; use starknet_api::hash::{pedersen_hash, StarkFelt, StarkHash}; @@ -28,7 +28,7 @@ impl StarkHasher for PedersenHash { #[derive(Debug, Clone)] pub struct MerkleTrie { root: Option>>, - leaves: HashMap, StarkFelt>, + pub leaves: HashMap, StarkFelt>, _hasher: std::marker::PhantomData, /// If enables, node hashes are verified as they are resolved. This allows /// testing for database corruption. @@ -46,7 +46,7 @@ pub struct TrieUpdate { } impl MerkleTrie { - pub fn new(root: u32) -> Self { + pub fn new(root: u64) -> Self { let root = Some(Rc::new(RefCell::new(InternalNode::Unresolved(root)))); Self { root, @@ -441,7 +441,7 @@ impl MerkleTrie { /// 2. the hashes are correct, and /// 3. the root hash matches the known root pub fn get_proof( - root: u32, + root: u64, storage: &impl Storage, key: &BitSlice, ) -> anyhow::Result> { @@ -593,7 +593,7 @@ impl MerkleTrie { fn resolve( &self, storage: &impl Storage, - index: u32, + index: u64, height: usize, ) -> anyhow::Result { anyhow::ensure!( diff --git a/src/storage/mod.rs b/src/storage/mod.rs deleted file mode 100644 index d4df413c..00000000 --- a/src/storage/mod.rs +++ /dev/null @@ -1,73 +0,0 @@ -pub mod starknet; - -use anyhow::Context; -use bitvec::{prelude::BitSlice, prelude::BitVec, prelude::Msb0}; -use starknet_api::hash::StarkFelt; - -use std::collections::HashMap; - -use crate::utils::felt_from_bits; - -/// Read-only storage used by the [Trie](crate::trie::Trie). -pub trait Storage { - /// Returns the node stored at the given index. - fn get(&self, index: u32) -> anyhow::Result>; - /// Returns the hash of the node at the given index. - fn hash(&self, index: u32) -> anyhow::Result>; - /// Returns the value of the leaf at the given path. - fn leaf(&self, path: &BitSlice) -> anyhow::Result>; -} - -#[derive(Clone, Debug)] -pub enum Node { - Binary { - left: Child, - right: Child, - }, - Edge { - child: Child, - path: BitVec, - }, - LeafBinary, - LeafEdge { - path: BitVec, - }, -} - -#[derive(Clone, Debug)] -pub enum Child { - Id(u32), - Hash(StarkFelt), -} - -#[derive(Clone, Debug, PartialEq)] -pub enum StoredNode { - Binary { left: u32, right: u32 }, - Edge { child: u32, path: BitVec }, - LeafBinary, - LeafEdge { path: BitVec }, -} - -#[derive(Default, Debug)] -pub struct DefaultTrieStorage { - nodes: HashMap, - leaves: HashMap, -} - -impl Storage for DefaultTrieStorage { - fn get(&self, node: u32) -> anyhow::Result> { - Ok(self.nodes.get(&node).map(|x| x.1.clone())) - } - - fn hash(&self, node: u32) -> anyhow::Result> { - Ok(self.nodes.get(&node).map(|x| x.0)) - } - - fn leaf(&self, path: &BitSlice) -> anyhow::Result> { - assert!(path.len() == 251); - - let key = felt_from_bits(path).context("Mapping path to felt")?; - - Ok(self.leaves.get(&key).cloned()) - } -} diff --git a/tests/common/mod.rs b/tests/common/mod.rs index 125a2f0f..7603c2bf 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -6,7 +6,6 @@ use blockifier::abi::constants::N_STEPS_RESOURCE; use blockifier::abi::abi_utils::selector_from_name; use blockifier::block_context::BlockContext; -use blockifier::block_execution::pre_process_block; use blockifier::state::{cached_state::CachedState, state_api::State}; use blockifier::transaction::account_transaction::AccountTransaction; use blockifier::transaction::transactions::ExecutableTransaction; @@ -21,12 +20,15 @@ use cairo_vm::vm::runners::cairo_runner::CairoRunner; use cairo_vm::vm::vm_core::VirtualMachine; use snos::config::{StarknetGeneralConfig, DEFAULT_FEE_TOKEN_ADDR}; use snos::state::SharedState; -use starknet_api::block::{BlockHash, BlockNumber, BlockTimestamp}; +use starknet_api::block::{BlockNumber, BlockTimestamp}; use starknet_api::core::{ calculate_contract_address, ClassHash, ContractAddress, Nonce, PatriciaKey, }; use starknet_api::hash::{StarkFelt, StarkHash}; -use starknet_api::transaction::{Calldata, ContractAddressSalt, Fee, TransactionVersion}; +use starknet_api::state::StorageKey; +use starknet_api::transaction::{ + Calldata, ContractAddressSalt, Fee, TransactionSignature, TransactionVersion, +}; use starknet_api::{calldata, class_hash, contract_address, patricia_key, stark_felt}; use std::collections::HashMap; @@ -111,7 +113,6 @@ pub fn block_context() -> BlockContext { conf.starknet_os_config.fee_token_address = contract_address!(DEFAULT_FEE_TOKEN_ADDR); let mut block_context = conf.empty_block_context(); - block_context.block_timestamp = BlockTimestamp(1000); block_context.vm_resource_fee_cost = Arc::new(HashMap::from([ (N_STEPS_RESOURCE.to_string(), 1_f64), @@ -238,7 +239,23 @@ fn shared_state(initial_state: SharedState) { #[fixture] pub fn prepare_os_test( mut initial_state: SharedState, -) -> (SharedState, Vec) { +) -> SharedState { + let contract_addresses = [ + contract_address!("46fd0893101585e0c7ebd3caf8097b179f774102d6373760c8f60b1a5ef8c92"), + contract_address!("4e9665675ca1ac12820b7aff2f44fec713e272efcd3f20aa0fd8ca277f25dc6"), + contract_address!("74cebec93a58b4400af9c082fb3c5adfa0800ff1489f8fc030076491ff86c48"), + ]; + let contract_calldata = [ + vec![stark_felt!(321_u32), stark_felt!(543_u32)], + vec![stark_felt!(111_u32), stark_felt!(987_u32)], + vec![stark_felt!(444_u32), stark_felt!(0_u32)], + ]; + 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); nonce_manager.next(sender_addr); @@ -250,24 +267,25 @@ pub fn prepare_os_test( utils::load_class_v0("build/test_contract.json"), ) .unwrap(); - - let contract_addresses = [ - contract_address!("46fd0893101585e0c7ebd3caf8097b179f774102d6373760c8f60b1a5ef8c92"), - contract_address!("4e9665675ca1ac12820b7aff2f44fec713e272efcd3f20aa0fd8ca277f25dc6"), - contract_address!("74cebec93a58b4400af9c082fb3c5adfa0800ff1489f8fc030076491ff86c48"), - ]; - let contract_calldata = [(321_u32, 543), (111, 987), (444, 0)]; - let contract_salts = [17_u32, 42, 53]; for (i, expected_addr) in contract_addresses.into_iter().enumerate() { - let addr = utils::deploy_with_syscall( - &mut initial_state, - &mut nonce_manager, - sender_addr, + let contract_addr = calculate_contract_address( + ContractAddressSalt(contract_salts[i]), class_hash!(TESTING_HASH_0_12_2), - contract_calldata[i], - contract_salts[i], + &Calldata(Arc::new(contract_calldata[i].clone())), + contract_address!(0_u32), + ) + .unwrap(); + initial_state + .cache + .set_class_hash_at(contract_addr, class_hash!(TESTING_HASH_0_12_2)) + .unwrap(); + initial_state.cache.set_storage_at( + contract_addr, + StorageKey(patricia_key!(*contract_calldata[i].first().unwrap())), + *contract_calldata[i].last().unwrap(), ); - assert_eq!(expected_addr, addr); + + assert_eq!(expected_addr, contract_addr); } let mut txs: Vec = Vec::new(); @@ -342,8 +360,6 @@ pub fn prepare_os_test( stark_felt!(85_u8) ]); - // TODO: StarknetMessageToL1 - txs.push(calldata![ *contract_addresses[0].0.key(), selector_from_name("test_call_contract").0, @@ -361,29 +377,16 @@ pub fn prepare_os_test( *contract_addresses[0].0.key() ]); - let delegate_proxy_contract_class = utils::load_class_v0("build/delegate_proxy.json"); - let delegate_addr = calculate_contract_address( - ContractAddressSalt::default(), + let delegate_addr = utils::raw_deploy( + &mut initial_state, + "build/delegate_proxy.json", class_hash!(DELEGATE_PROXY_HASH_0_12_2), - &calldata![], - contract_address!(0_u32), - ) - .unwrap(); + ); + assert_eq!( - contract_address!("0x0238e6b5dffc9f0eb2fe476855d0cd1e9e034e5625663c7eda2d871bd4b6eac0"), + contract_address!("238e6b5dffc9f0eb2fe476855d0cd1e9e034e5625663c7eda2d871bd4b6eac0"), delegate_addr ); - initial_state - .cache - .set_contract_class( - &class_hash!(DELEGATE_PROXY_HASH_0_12_2), - delegate_proxy_contract_class, - ) - .unwrap(); - initial_state - .cache - .set_class_hash_at(delegate_addr, class_hash!(DELEGATE_PROXY_HASH_0_12_2)) - .unwrap(); txs.push(calldata![ *delegate_addr.0.key(), @@ -432,8 +435,6 @@ pub fn prepare_os_test( stark_felt!(2_u32) ]); - // // TODO handle message to L2 - txs.push(calldata![ *contract_addresses[0].0.key(), selector_from_name("test_library_call_syntactic_sugar").0, @@ -441,77 +442,75 @@ pub fn prepare_os_test( stark_felt!(TESTING_HASH_0_12_2) ]); - // TODO: add sig - txs.push(calldata![ - *contract_addresses[0].0.key(), - selector_from_name("add_signature_to_counters").0, - stark_felt!(1_u32), - stark_felt!(2021_u32) - ]); + let mut sig_txs: Vec<(Calldata, TransactionSignature)> = Vec::new(); - // TODO: add sig - txs.push(calldata![ - *contract_addresses[0].0.key(), - selector_from_name("test_call_contract").0, - stark_felt!(4_u32), - *delegate_addr.0.key(), - selector_from_name("test_get_tx_info").0, - stark_felt!(1_u8), - stark_felt!(DUMMY_ACCOUNT_ADDRESS_0_12_2) - ]); + sig_txs.push(( + calldata![ + *contract_addresses[0].0.key(), + selector_from_name("add_signature_to_counters").0, + stark_felt!(1_u32), + stark_felt!(2021_u32) + ], + TransactionSignature(vec![stark_felt!(100_u32), stark_felt!(200_u32)]), + )); + + sig_txs.push(( + calldata![ + *contract_addresses[0].0.key(), + selector_from_name("test_call_contract").0, + stark_felt!(4_u32), + *delegate_addr.0.key(), + selector_from_name("test_get_tx_info").0, + stark_felt!(1_u8), + stark_felt!(DUMMY_ACCOUNT_ADDRESS_0_12_2) + ], + TransactionSignature(vec![stark_felt!(100_u32)]), + )); - let test_contract_2_contract_class = utils::load_class_v0("build/test_contract2.json"); - let test_contract_2_addr = calculate_contract_address( - ContractAddressSalt::default(), + let test_contract_2_addr = utils::raw_deploy( + &mut initial_state, + "build/test_contract2.json", class_hash!(TESTING_HASH_2_0_12_2), - &calldata![], - contract_address!(0_u32), - ) - .unwrap(); - initial_state - .cache - .set_contract_class( - &class_hash!(TESTING_HASH_2_0_12_2), - test_contract_2_contract_class, - ) - .unwrap(); - initial_state - .cache - .set_class_hash_at(test_contract_2_addr, class_hash!(TESTING_HASH_2_0_12_2)) - .unwrap(); - - // TODO: add sig - txs.push(calldata![ - *contract_addresses[1].0.key(), - selector_from_name("test_library_call").0, - stark_felt!(5_u32), - *test_contract_2_addr.0.key(), - selector_from_name("test_storage_write").0, - stark_felt!(2_u8), - stark_felt!(555_u32), - stark_felt!(888_u32) - ]); - - // TODO: add sig - txs.push(calldata![ - *contract_addresses[1].0.key(), - selector_from_name("test_library_call_l1_handler").0, - stark_felt!(6_u32), - *test_contract_2_addr.0.key(), - selector_from_name("test_l1_handler_storage_write").0, - stark_felt!(3_u8), - stark_felt!(85_u32), - stark_felt!(666_u32), - stark_felt!(999_u32) - ]); + ); - // TODO: add sig - txs.push(calldata![ - *contract_addresses[0].0.key(), - selector_from_name("test_replace_class").0, - stark_felt!(1_u32), - *test_contract_2_addr.0.key() - ]); + sig_txs.push(( + calldata![ + *contract_addresses[1].0.key(), + selector_from_name("test_library_call").0, + stark_felt!(5_u32), + class_hash!(TESTING_HASH_2_0_12_2).0, + selector_from_name("test_storage_write").0, + stark_felt!(2_u8), + stark_felt!(555_u32), + stark_felt!(888_u32) + ], + TransactionSignature(vec![stark_felt!(100_u32)]), + )); + + sig_txs.push(( + calldata![ + *contract_addresses[1].0.key(), + selector_from_name("test_library_call_l1_handler").0, + stark_felt!(6_u32), + class_hash!(TESTING_HASH_2_0_12_2).0, + selector_from_name("test_l1_handler_storage_write").0, + stark_felt!(3_u8), + stark_felt!(85_u32), + stark_felt!(666_u32), + stark_felt!(999_u32) + ], + TransactionSignature(vec![stark_felt!(100_u32)]), + )); + + sig_txs.push(( + calldata![ + *contract_addresses[0].0.key(), + selector_from_name("test_replace_class").0, + stark_felt!(1_u32), + *test_contract_2_addr.0.key() + ], + TransactionSignature(vec![]), + )); for tx in txs.clone().into_iter() { let account_tx = invoke_tx(invoke_tx_args! { @@ -531,10 +530,110 @@ pub fn prepare_os_test( .unwrap(); } - pre_process_block( - &mut initial_state.cache, - Some((BlockNumber(1), BlockHash(StarkFelt::from(21u32)))), + for sig_tx in sig_txs.clone().into_iter() { + let account_tx = invoke_tx(invoke_tx_args! { + max_fee: Fee(TESTING_FEE), + nonce: nonce_manager.next(sender_addr), + sender_address: sender_addr, + calldata: sig_tx.0, + signature: sig_tx.1, + version: TransactionVersion::ONE, + }); + AccountTransaction::Invoke(account_tx.into()) + .execute( + &mut initial_state.cache, + &mut initial_state.block_context, + false, + true, + ) + .unwrap(); + } + + initial_state +} + +#[rstest] +fn validate_prepare(mut prepare_os_test: SharedState) { + let mut shared_state = prepare_os_test; + let diff = shared_state.cache.to_state_diff(); + + let addr_1 = + contract_address!("46fd0893101585e0c7ebd3caf8097b179f774102d6373760c8f60b1a5ef8c92"); + let addr_1_updates = diff.storage_updates.get(&addr_1).unwrap(); + assert_eq!(5, addr_1_updates.len()); + assert_eq!( + &stark_felt!(47_u32), + addr_1_updates + .get(&StorageKey(patricia_key!(85_u32))) + .unwrap() ); - // TODO: expected storage updates - (initial_state, txs) + 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(); + assert_eq!(4, addr_2_updates.len()); + 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()); + // assert_eq!( + // &stark_felt!(456_u32), + // delegate_addr_updates + // .get(&StorageKey(patricia_key!(123_u32))) + // .unwrap() + // ); + + // let msg_to_l2 = MessageToL2 { + // from_address: EthAddress::try_from(stark_felt!(85_u16)).unwrap(), + // payload: L1ToL2Payload(vec![ + // *delegate_addr.0.key(), + // selector_from_name("deposit").0, + // stark_felt!(2_u32), + // stark_felt!(85_u32), + // stark_felt!(2_u32), + // ]), + // }; + + // let msg_to_l1 = MessageToL1 { + // from_address: contract_addresses[0], + // to_address: EthAddress::try_from(stark_felt!(85_u16)).unwrap(), + // payload: L2ToL1Payload(vec![stark_felt!(12_u16), stark_felt!(34_u16)]), + // }; } diff --git a/tests/common/utils.rs b/tests/common/utils.rs index ed0fdb8f..09ad1744 100644 --- a/tests/common/utils.rs +++ b/tests/common/utils.rs @@ -70,48 +70,27 @@ pub fn print_a_hint( Ok(()) } -pub fn deploy_with_syscall( +pub fn raw_deploy( shared_state: &mut SharedState, - nonce_manager: &mut NonceManager, - sender_addr: ContractAddress, + class_path: &str, class_hash: ClassHash, - test_calldata: (u32, u32), - salt: u32, ) -> ContractAddress { + let contract_class = load_class_v0(class_path); + shared_state + .cache + .set_contract_class(&class_hash, contract_class) + .unwrap(); + let contract_addr = calculate_contract_address( - ContractAddressSalt(stark_felt!(salt)), + ContractAddressSalt::default(), class_hash, - &calldata![ - stark_felt!(test_calldata.0), // Calldata: address. - stark_felt!(test_calldata.1) // Calldata: value. - ], + &calldata![], contract_address!(0_u32), ) .unwrap(); - - let account_tx = invoke_tx(invoke_tx_args! { - max_fee: Fee(TESTING_FEE), - nonce: nonce_manager.next(sender_addr), - sender_address: sender_addr, - calldata: calldata![ - *sender_addr.0.key(), - selector_from_name("deploy_contract").0, - stark_felt!(5_u32), - class_hash.0, - stark_felt!(salt), - stark_felt!(2_u32), - stark_felt!(test_calldata.0), - stark_felt!(test_calldata.0) - ], - version: TransactionVersion::ONE, - }); - AccountTransaction::Invoke(account_tx.into()) - .execute( - &mut shared_state.cache, - &mut shared_state.block_context, - false, - true, - ) + shared_state + .cache + .set_class_hash_at(contract_addr, class_hash) .unwrap(); contract_addr diff --git a/tests/snos.rs b/tests/snos.rs index add21edd..6490b0a6 100644 --- a/tests/snos.rs +++ b/tests/snos.rs @@ -9,8 +9,8 @@ use cairo_vm::hint_processor::builtin_hint_processor::builtin_hint_processor_def }; use snos::{state::SharedState, SnOsRunner}; + use starknet_api::block::BlockNumber; -use starknet_api::transaction::Calldata; use std::fs; use std::rc::Rc; @@ -25,12 +25,12 @@ fn snos_ok(_initial_state: SharedState) { } #[rstest] -fn prepared_os_test(prepare_os_test: (SharedState, Vec)) { - let (mut shared_state, txns) = prepare_os_test; - assert_eq!(23, txns.len()); - - shared_state.apply_diff(); - assert_eq!(BlockNumber(2), shared_state.get_block_num()) +fn prepared_os_test(mut prepare_os_test: SharedState) { + let commitment = prepare_os_test.apply_diff(); + assert_eq!(BlockNumber(2), prepare_os_test.get_block_num()); + // 1fc35de150561b6229137b3f253fc1c894c93b1c184a8ca0d0f7171a64bcd04 -> addr 2 + // 7d4b1bcb63f8b7f53ef32d5761afc3249180f03dc9773e421a9574c51453c00 -> addr 2 + println!("COMMITMENT: {:?}", commitment); } #[rstest] From 70ebb69f1f9447c296b75341d6c8d4e487d44c0a Mon Sep 17 00:00:00 2001 From: Ben Goebel Date: Tue, 10 Oct 2023 10:24:12 -0600 Subject: [PATCH 02/10] remove papy store --- src/state/mod.rs | 158 ++++++++++++++++--------------------------- src/state/storage.rs | 7 +- 2 files changed, 63 insertions(+), 102 deletions(-) diff --git a/src/state/mod.rs b/src/state/mod.rs index ce630ea5..5ca27f65 100644 --- a/src/state/mod.rs +++ b/src/state/mod.rs @@ -8,18 +8,14 @@ use blockifier::state::cached_state::{CachedState, CommitmentStateDiff}; use blockifier::state::state_api::{State, StateReader}; use cairo_felt::Felt252; use indexmap::{IndexMap, IndexSet}; -use storage::DefaultTrieStorage; - -use papyrus_storage::state::{StateStorageReader, StateStorageWriter}; -use papyrus_storage::StorageResult; -use papyrus_storage::{db::DbConfig, open_storage, StorageConfig, StorageScope}; +use storage::TrieStorage; use starknet_api::block::BlockNumber; use starknet_api::core::{ClassHash, ContractAddress, PatriciaKey}; use starknet_api::deprecated_contract_class::ContractClass as DeprecatedContractClass; use starknet_api::hash::{StarkFelt, StarkHash}; use starknet_api::patricia_key; -use starknet_api::state::{StateDiff, ThinStateDiff}; +use starknet_api::state::{StateDiff, StateUpdate, ThinStateDiff}; use tempfile::{tempdir, TempDir}; use std::collections::HashMap; @@ -46,39 +42,21 @@ pub struct ContractState { } pub struct SharedState { - pub db_conf: StorageConfig, pub cache: CachedState, pub block_context: BlockContext, - pub commitment_storage: DefaultTrieStorage, - pub contract_storage: DefaultTrieStorage, - pub previous_storage_root: (StarkFelt, u64), - pub previous_contract_root: (StarkFelt, u64), - _tmp: TempDir, + pub commitment_storage: TrieStorage, + pub contract_storage: TrieStorage, + pub class_storage: TrieStorage, } impl SharedState { pub fn new(cache: CachedState, block_context: BlockContext) -> Self { - let _tmp = tempdir().unwrap(); - let db_conf = StorageConfig { - db_config: DbConfig { - chain_id: block_context.chain_id.clone(), - path_prefix: _tmp.path().to_path_buf(), - ..DbConfig::default() - }, - scope: StorageScope::default(), - }; - let commitment_storage = DefaultTrieStorage::default(); - let contract_storage = DefaultTrieStorage::default(); - open_storage(db_conf.clone()).unwrap(); Self { - db_conf, cache, block_context, - commitment_storage, - contract_storage, - previous_storage_root: (StarkFelt::ZERO, 0_u64), - previous_contract_root: (StarkFelt::ZERO, 0_u64), - _tmp, + commitment_storage: TrieStorage::default(), + contract_storage: TrieStorage::default(), + class_storage: TrieStorage::default(), } } pub fn get_block_num(&self) -> BlockNumber { @@ -89,17 +67,59 @@ impl SharedState { self.block_context.block_number = self.block_context.block_number.next(); } - pub fn get_diff(&self, block_num: BlockNumber) -> StorageResult> { - let (reader, _) = open_storage(self.db_conf.clone()).unwrap(); - let diff = reader.begin_ro_txn().unwrap().get_state_diff(block_num); - diff + pub fn apply_state(&mut self) -> CommitmentInfo { + let diff = self.cache.to_state_diff(); + + let accessed_addrs = self.apply_diff(diff); + + let mut storage_trie: MerkleTrie = + if previous_storage_root.1 > 0 { + MerkleTrie::new(previous_storage_root.1) + } else { + MerkleTrie::empty() + }; + for addr in accessed_addrs { + let nonce = match diff.address_to_nonce.get(&addr) { + Some(new_nonce) => *new_nonce, + None => self.cache.get_nonce_at(addr).unwrap(), + }; + let root = match root_map.get(&addr) { + Some(inner_root) => *inner_root, + None => patricia_key!("0x0"), + }; + let class_hash = self.cache.get_class_hash_at(addr).unwrap(); + + let contract_commitment = calculate_contract_state_hash(class_hash, root, nonce); + + storage_trie + .set( + &self.commitment_storage, + bits_from_felt(*addr.0.key()), + contract_commitment, + ) + .unwrap(); + } + + // block num to root + let updated_root = self.commitment_storage.commit_and_persist(storage_trie); + + // let state_update = StateUpdate { + + // } + + self.increment_block(); + + CommitmentInfo { + previous_root: Felt252::from_bytes_be(previous_storage_root.0.bytes()), + updated_root: Felt252::from_bytes_be(updated_root.0.bytes()), + tree_height: DEFAULT_STORAGE_TREE_HEIGHT, + commitment_facts: HashMap::new(), + } } - pub fn apply_diff(&mut self) -> CommitmentInfo { + pub fn apply_diff(&mut self, diff: CommitmentStateDiff) -> IndexSet { let mut accessed_addrs = IndexSet::new(); - let diff = self.cache.to_state_diff(); - let mut deprecated_declared_classes: IndexMap = IndexMap::new(); @@ -113,28 +133,6 @@ impl SharedState { accessed_addrs.insert(addr); } - let state_diff = StateDiff { - deprecated_declared_classes, - deployed_contracts: diff.address_to_class_hash.clone(), - storage_diffs: diff.storage_updates.clone(), - nonces: diff.address_to_nonce.clone(), - ..StateDiff::default() - }; - - let (_, mut writer) = open_storage(self.db_conf.clone()).unwrap(); - - writer - .begin_rw_txn() - .unwrap() - .append_state_diff( - self.block_context.block_number, - state_diff.clone(), - IndexMap::new(), - ) - .unwrap() - .commit() - .unwrap(); - let mut root_map = HashMap::new(); for (addr, updates) in diff.storage_updates { @@ -152,6 +150,7 @@ impl SharedState { } let (contract_root, contract_idx) = self.contract_storage.commit_and_persist(contract_trie); + root_map.insert(addr, patricia_key!(contract_root)); accessed_addrs.insert(addr); } @@ -160,45 +159,6 @@ impl SharedState { accessed_addrs.insert(addr); } - let previous_storage_root = self.previous_storage_root; - let mut storage_trie: MerkleTrie = - if previous_storage_root.1 > 0 { - MerkleTrie::new(previous_storage_root.1) - } else { - MerkleTrie::empty() - }; - for addr in accessed_addrs { - let nonce = match state_diff.nonces.get(&addr) { - Some(new_nonce) => *new_nonce, - None => self.cache.get_nonce_at(addr).unwrap(), - }; - let root = match root_map.get(&addr) { - Some(inner_root) => *inner_root, - None => patricia_key!("0x0"), - }; - let class_hash = self.cache.get_class_hash_at(addr).unwrap(); - - let contract_commitment = calculate_contract_state_hash(class_hash, root, nonce); - - storage_trie - .set( - &self.commitment_storage, - bits_from_felt(*addr.0.key()), - contract_commitment, - ) - .unwrap(); - } - - let updated_root = self.commitment_storage.commit_and_persist(storage_trie); - - self.increment_block(); - self.previous_storage_root = updated_root; - - CommitmentInfo { - previous_root: Felt252::from_bytes_be(previous_storage_root.0.bytes()), - updated_root: Felt252::from_bytes_be(updated_root.0.bytes()), - tree_height: DEFAULT_STORAGE_TREE_HEIGHT, - commitment_facts: HashMap::new(), - } + accessed_addrs } } diff --git a/src/state/storage.rs b/src/state/storage.rs index 4a4f086e..67136071 100644 --- a/src/state/storage.rs +++ b/src/state/storage.rs @@ -49,12 +49,13 @@ pub enum StoredNode { } #[derive(Default, Debug)] -pub struct DefaultTrieStorage { +pub struct TrieStorage { nodes: HashMap, leaves: HashMap, + block_root_map: HashMap, } -impl Storage for DefaultTrieStorage { +impl Storage for TrieStorage { fn get(&self, node: u64) -> anyhow::Result> { Ok(self.nodes.get(&node).map(|x| x.1.clone())) } @@ -72,7 +73,7 @@ impl Storage for DefaultTrieStorage { } } -impl DefaultTrieStorage { +impl TrieStorage { pub fn commit_and_persist( &mut self, tree: MerkleTrie, From af805a72bd429245c32efebcda25a90ec94d20e4 Mon Sep 17 00:00:00 2001 From: Ben Goebel Date: Tue, 10 Oct 2023 17:16:40 -0600 Subject: [PATCH 03/10] json input --- Cargo.toml | 3 - scripts/setup-tests.sh | 2 + src/state/mod.rs | 70 +++++++++++--------- src/state/storage.rs | 6 +- tests/common/mod.rs | 104 +++++++++++++++++------------ tests/common/os_input.json | 132 +++++++++++++++++++++++++++++++++++++ tests/snos.rs | 47 +++++++++++-- 7 files changed, 282 insertions(+), 82 deletions(-) create mode 100644 tests/common/os_input.json diff --git a/Cargo.toml b/Cargo.toml index e51f6d16..b7d7e8d5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -18,9 +18,6 @@ indexmap = "1.9.2" log = "0.4.19" num-bigint = "0.4.4" num-traits = "0.2.16" -papyrus_storage = { git = "https://github.com/starkware-libs/papyrus.git", branch = "main", features = [ - "testing", -] } reqwest = { version = "0.11.18", features = ["blocking", "json"] } serde = { version = "1.0.188", features = ["derive"] } serde_json = "1.0.105" diff --git a/scripts/setup-tests.sh b/scripts/setup-tests.sh index c37193b2..e0ba143c 100755 --- a/scripts/setup-tests.sh +++ b/scripts/setup-tests.sh @@ -35,6 +35,8 @@ starknet-compile-deprecated --no_debug_info tests/contracts/dummy_token.cairo -- starknet-compile-deprecated --no_debug_info tests/contracts/delegate_proxy.cairo --output build/delegate_proxy.json --cairo_path cairo-lang/src starknet-compile-deprecated --no_debug_info tests/contracts/test_contract2.cairo --output build/test_contract2.json --cairo_path cairo-lang/src + + # compile os with debug info cairo-compile cairo-lang/src/starkware/starknet/core/os/os.cairo --output build/os_debug.json --cairo_path cairo-lang/src diff --git a/src/state/mod.rs b/src/state/mod.rs index 5ca27f65..229ac204 100644 --- a/src/state/mod.rs +++ b/src/state/mod.rs @@ -14,9 +14,7 @@ use starknet_api::block::BlockNumber; use starknet_api::core::{ClassHash, ContractAddress, PatriciaKey}; use starknet_api::deprecated_contract_class::ContractClass as DeprecatedContractClass; use starknet_api::hash::{StarkFelt, StarkHash}; -use starknet_api::patricia_key; -use starknet_api::state::{StateDiff, StateUpdate, ThinStateDiff}; -use tempfile::{tempdir, TempDir}; +use starknet_api::{patricia_key, stark_felt}; use std::collections::HashMap; @@ -27,7 +25,7 @@ use trie::{MerkleTrie, PedersenHash}; type CommitmentFacts = HashMap>; -#[derive(Debug, Serialize, Deserialize)] +#[derive(Debug, Default, Serialize, Deserialize)] pub struct CommitmentInfo { pub previous_root: Felt252, pub updated_root: Felt252, @@ -67,27 +65,40 @@ impl SharedState { self.block_context.block_number = self.block_context.block_number.next(); } - pub fn apply_state(&mut self) -> CommitmentInfo { - let diff = self.cache.to_state_diff(); + pub fn get_storage_root(&self, block_num: BlockNumber) -> (StarkFelt, u64) { + *self + .commitment_storage + .root_map + .get(&stark_felt!(block_num.0)) + .unwrap_or(&(StarkFelt::ZERO, 0_u64)) + } - let accessed_addrs = self.apply_diff(diff); + pub fn get_contract_root(&self, addr: ContractAddress) -> Option<&(StarkFelt, u64)> { + self.contract_storage.root_map.get(addr.0.key()) + } + + pub fn apply_state(&mut self) -> CommitmentInfo { + let (accessed_addrs, diff) = self.apply_diff(); let mut storage_trie: MerkleTrie = - if previous_storage_root.1 > 0 { - MerkleTrie::new(previous_storage_root.1) - } else { - MerkleTrie::empty() + match self.get_block_num().prev() { + Some(block_num) => MerkleTrie::new(self.get_storage_root(block_num).1), + None => MerkleTrie::empty(), }; + for addr in accessed_addrs { let nonce = match diff.address_to_nonce.get(&addr) { Some(new_nonce) => *new_nonce, - None => self.cache.get_nonce_at(addr).unwrap(), + None => self.cache.get_nonce_at(addr).unwrap_or_default(), }; - let root = match root_map.get(&addr) { - Some(inner_root) => *inner_root, + let root = match self.get_contract_root(addr) { + Some(inner_root) => patricia_key!(inner_root.0), None => patricia_key!("0x0"), }; - let class_hash = self.cache.get_class_hash_at(addr).unwrap(); + let class_hash = match diff.address_to_class_hash.get(&addr) { + Some(class_hash) => *class_hash, + None => self.cache.get_class_hash_at(addr).unwrap(), + }; let contract_commitment = calculate_contract_state_hash(class_hash, root, nonce); @@ -99,25 +110,23 @@ impl SharedState { ) .unwrap(); } - - // block num to root - let updated_root = self.commitment_storage.commit_and_persist(storage_trie); - - // let state_update = StateUpdate { - - // } - + let block_num = self.get_block_num(); + let previous_root = self.get_storage_root(block_num); + let updated_root = self + .commitment_storage + .commit_and_persist(storage_trie, stark_felt!(block_num.0)); self.increment_block(); CommitmentInfo { - previous_root: Felt252::from_bytes_be(previous_storage_root.0.bytes()), + previous_root: Felt252::from_bytes_be(previous_root.0.bytes()), updated_root: Felt252::from_bytes_be(updated_root.0.bytes()), tree_height: DEFAULT_STORAGE_TREE_HEIGHT, commitment_facts: HashMap::new(), } } - pub fn apply_diff(&mut self, diff: CommitmentStateDiff) -> IndexSet { + pub fn apply_diff(&mut self) -> (IndexSet, CommitmentStateDiff) { + let diff = self.cache.to_state_diff(); let mut accessed_addrs = IndexSet::new(); let mut deprecated_declared_classes: IndexMap = @@ -133,9 +142,7 @@ impl SharedState { accessed_addrs.insert(addr); } - let mut root_map = HashMap::new(); - - for (addr, updates) in diff.storage_updates { + for (addr, updates) in diff.storage_updates.clone() { let mut contract_trie: MerkleTrie = MerkleTrie::empty(); @@ -148,10 +155,9 @@ impl SharedState { ) .unwrap(); } - let (contract_root, contract_idx) = - self.contract_storage.commit_and_persist(contract_trie); + self.contract_storage + .commit_and_persist(contract_trie, *addr.0.key()); - root_map.insert(addr, patricia_key!(contract_root)); accessed_addrs.insert(addr); } @@ -159,6 +165,6 @@ impl SharedState { accessed_addrs.insert(addr); } - accessed_addrs + (accessed_addrs, diff) } } diff --git a/src/state/storage.rs b/src/state/storage.rs index 67136071..3ed2dbd0 100644 --- a/src/state/storage.rs +++ b/src/state/storage.rs @@ -1,5 +1,6 @@ use anyhow::Context; use bitvec::{prelude::BitSlice, prelude::BitVec, prelude::Msb0}; +use starknet_api::block::BlockNumber; use starknet_api::hash::StarkFelt; use super::trie::{MerkleTrie, StarkHasher}; @@ -52,7 +53,7 @@ pub enum StoredNode { pub struct TrieStorage { nodes: HashMap, leaves: HashMap, - block_root_map: HashMap, + pub root_map: HashMap, } impl Storage for TrieStorage { @@ -77,6 +78,7 @@ impl TrieStorage { pub fn commit_and_persist( &mut self, tree: MerkleTrie, + root_key: StarkFelt, ) -> (StarkFelt, u64) { for (key, value) in &tree.leaves { let key = felt_from_bits(key).unwrap(); @@ -131,6 +133,8 @@ impl TrieStorage { let index = *indices.get(&update.root).unwrap(); + self.root_map.insert(root_key, (update.root, index)); + (update.root, index) } } diff --git a/tests/common/mod.rs b/tests/common/mod.rs index 7603c2bf..08eff2ec 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -1,5 +1,6 @@ pub mod utils; +use blockifier::state::state_api::StateReader; use cairo_felt::felt_str; use blockifier::abi::constants::N_STEPS_RESOURCE; @@ -44,6 +45,8 @@ use blockifier::test_utils::{ pub const TESTING_FEE: u128 = 0x10000000000000000000000000; pub const TESTING_TRANSFER_AMOUNT: u128 = 0x01000000000000000000000000000000; +pub const TESTING_BLOCK_HASH: &str = + "59b01ba262c999f2617412ffbba780f80b0103d928cbce1aecbaa50de90abda"; // Contract Addresses - 0.12.2 pub const _TOKEN_FOR_TESTING_ADDRESS_0_12_2: &str = @@ -207,7 +210,7 @@ pub fn initial_state( block_context.block_timestamp = BlockTimestamp(1001); let mut shared_state = SharedState::new(cache, block_context); - let commitment = shared_state.apply_diff(); + let commitment = shared_state.apply_state(); // expected root parsed from current os_test.py & test_utils.py(0.12.2) assert_eq!( @@ -225,15 +228,6 @@ pub fn initial_state( fn shared_state(initial_state: SharedState) { let block_num = initial_state.get_block_num(); assert_eq!(BlockNumber(1), block_num); - - let pre_state_diff = initial_state.get_diff(BlockNumber(0)).unwrap().unwrap(); - let pre_nonces = pre_state_diff.nonces; - - let dummy_account = &pre_nonces.get(&contract_address!(DUMMY_ACCOUNT_ADDRESS_0_12_2)); - assert_eq!(&Nonce(stark_felt!(1_u32)), dummy_account.unwrap()); - - let dummy_token = &pre_nonces.get(&contract_address!(DUMMY_TOKEN_ADDRESS_0_12_2)); - assert_eq!(&Nonce(stark_felt!(2_u32)), dummy_token.unwrap()); } #[fixture] @@ -427,14 +421,6 @@ pub fn prepare_os_test( *initial_state.block_context.sequencer_address.0.key() ]); - txs.push(calldata![ - *delegate_addr.0.key(), - selector_from_name("deposit").0, - stark_felt!(2_u32), - stark_felt!(85_u32), - stark_felt!(2_u32) - ]); - txs.push(calldata![ *contract_addresses[0].0.key(), selector_from_name("test_library_call_syntactic_sugar").0, @@ -549,6 +535,24 @@ pub fn prepare_os_test( .unwrap(); } + initial_state.cache.set_storage_at( + delegate_addr, + StorageKey(patricia_key!(300_u32)), + stark_felt!("4e5e39d16e565bacdbc7d8d13b9bc2b51a32c8b2b49062531688dcd2f6ec834"), + ); + initial_state.cache.set_storage_at( + delegate_addr, + StorageKey(patricia_key!(311_u32)), + stark_felt!(1536727068981429685321_u128), + ); + initial_state.cache.set_storage_at( + delegate_addr, + StorageKey(patricia_key!( + "1cda892019d02a987cdc80f1500179f0e33fbd6cac8cb2ffef5d6d05101a8dc" + )), + stark_felt!(2_u8), + ); + initial_state } @@ -583,7 +587,6 @@ fn validate_prepare(mut prepare_os_test: SharedState) { let addr_2 = contract_address!("4e9665675ca1ac12820b7aff2f44fec713e272efcd3f20aa0fd8ca277f25dc6"); let addr_2_updates = diff.storage_updates.get(&addr_2).unwrap(); - assert_eq!(4, addr_2_updates.len()); assert_eq!( &stark_felt!(1_u32), addr_2_updates @@ -613,27 +616,44 @@ fn validate_prepare(mut prepare_os_test: SharedState) { contract_address!("238e6b5dffc9f0eb2fe476855d0cd1e9e034e5625663c7eda2d871bd4b6eac0"); let delegate_addr_updates = diff.storage_updates.get(&delegate_addr).unwrap(); // assert_eq!(6, delegate_addr_updates.len()); - // assert_eq!( - // &stark_felt!(456_u32), - // delegate_addr_updates - // .get(&StorageKey(patricia_key!(123_u32))) - // .unwrap() - // ); - - // let msg_to_l2 = MessageToL2 { - // from_address: EthAddress::try_from(stark_felt!(85_u16)).unwrap(), - // payload: L1ToL2Payload(vec![ - // *delegate_addr.0.key(), - // selector_from_name("deposit").0, - // stark_felt!(2_u32), - // stark_felt!(85_u32), - // stark_felt!(2_u32), - // ]), - // }; - - // let msg_to_l1 = MessageToL1 { - // from_address: contract_addresses[0], - // to_address: EthAddress::try_from(stark_felt!(85_u16)).unwrap(), - // payload: L2ToL1Payload(vec![stark_felt!(12_u16), stark_felt!(34_u16)]), - // }; + assert_eq!( + &stark_felt!(456_u32), + delegate_addr_updates + .get(&StorageKey(patricia_key!(123_u32))) + .unwrap() + ); + assert_eq!( + &stark_felt!("4e5e39d16e565bacdbc7d8d13b9bc2b51a32c8b2b49062531688dcd2f6ec834"), + delegate_addr_updates + .get(&StorageKey(patricia_key!(300_u32))) + .unwrap() + ); + assert_eq!( + &stark_felt!(1536727068981429685321_u128), + delegate_addr_updates + .get(&StorageKey(patricia_key!(311_u32))) + .unwrap() + ); + assert_eq!( + &stark_felt!(19_u32), + delegate_addr_updates + .get(&StorageKey(patricia_key!(322_u32))) + .unwrap() + ); + assert_eq!( + &stark_felt!(TESTING_HASH_0_12_2), + delegate_addr_updates + .get(&StorageKey(patricia_key!( + "2e9111f912ea3746e28b8e693578fdbcc18d64a3380d03bd67c0c04f5715ed1" + ))) + .unwrap() + ); + assert_eq!( + &stark_felt!(2_u8), + delegate_addr_updates + .get(&StorageKey(patricia_key!( + "1cda892019d02a987cdc80f1500179f0e33fbd6cac8cb2ffef5d6d05101a8dc" + ))) + .unwrap() + ); } diff --git a/tests/common/os_input.json b/tests/common/os_input.json new file mode 100644 index 00000000..62c4abc6 --- /dev/null +++ b/tests/common/os_input.json @@ -0,0 +1,132 @@ +{ + "contract_state_commitment_info": { + "previous_root": "0x473010ec333f16b84334f9924912d7a13ce8296b0809c2091563ddfb63011d", + "updated_root": "0x0482c9ce8a99afddc9777ff048520fcbfab6c0389f51584016c80a2e94ab8ca7", + "tree_height": 251, + "commitment_facts": { + "0x473010ec333f16b84334f9924912d7a13ce8296b0809c2091563ddfb63011d": ["0x78ae47e863b0eeac50620a21d7aa9f163b1a9f1dcb2a810cb0c49f8fd16afdc", "0x446868832abcc6f03f057ad04c55047d1c21165b14094249024ef6f3e6effe9"], + "0x78ae47e863b0eeac50620a21d7aa9f163b1a9f1dcb2a810cb0c49f8fd16afdc": ["0xfb", "0x3400a86fdc294a70fac1cf84f81a2127419359096b846be9814786d4fc056b8", "0x312e8cd3be33c565e449d214efb762f49ef2a701f8fa33cbff791f592c4b97c"], + "0x446868832abcc6f03f057ad04c55047d1c21165b14094249024ef6f3e6effe9": ["0xfb", "0x1ca2b81086d3fbb4f4af2f1deba4b7fd35e8f4b2caee4e056005c51c05c3dd0", "0x72039db031f1da533c4399d04af2e3bdc2e4e5cb2d707a06e0c9eb417035762"], + "0x6e786ba49c4fc2ef6897a9b4f2f7dbd281b91480af9acc480dd8949e0e5093f": ["0xf9", "0x14cebec93a58b4400af9c082fb3c5adfa0800ff1489f8fc030076491ff86c48", "0x1d5f83f69e3d1da456f4abfa9c4c54e35a1ec9295a770889aaafa115bf94ed8"], + "0x3a6ba9d7d3e7c256a0abe84f8f2ede47f5d81d3eee36eb7d48182a6f99e663d": ["0xf8", "0x38e6b5dffc9f0eb2fe476855d0cd1e9e034e5625663c7eda2d871bd4b6eac0", "0x3770eacc014536c28b49b68dab24af374ce1245abf0b13eca52d98af471afed"], + "0x3a71f65a73ca118032fb3d7ae6195f99d0db67c2a68c12879bd1a6c1a75b13": ["0xf8", "0x400a86fdc294a70fac1cf84f81a2127419359096b846be9814786d4fc056b8", "0x312e8cd3be33c565e449d214efb762f49ef2a701f8fa33cbff791f592c4b97c"], + "0x3ede65e451e4a643dcc93e056af85e196e125dbc9720626424222d7c6b0f174": ["0xf8", "0xca2b81086d3fbb4f4af2f1deba4b7fd35e8f4b2caee4e056005c51c05c3dd0", "0x582cceb5417524e9ec1a2d3b65c24e967a1a15bcf06de132f39f1ebcec56f2d"], + "0x40ed73ff214a36e736d2cb157ca1b76d198f74ada875c05c97367b9a894f328": ["0xf7", "0x6fd0893101585e0c7ebd3caf8097b179f774102d6373760c8f60b1a5ef8c92", "0x26f90b65a29ec06d0329d048c736a5b3929757208de43cdf7fabd4b06fcf86"], + "0x3abcb072beea92b4bb2e815a0bbbca97ae43175f1b40985aaf21f41731a71": ["0xf7", "0x69665675ca1ac12820b7aff2f44fec713e272efcd3f20aa0fd8ca277f25dc6", "0x8944da2553c7414e1037e4e442c163f2f25f19fa628e7dafe6ceaac920e894"], + "0x6010b3092dea3fd1732014fcc16554cabe79090410c9f4ace2ed0264299f279": ["0x3a6ba9d7d3e7c256a0abe84f8f2ede47f5d81d3eee36eb7d48182a6f99e663d", "0x3a71f65a73ca118032fb3d7ae6195f99d0db67c2a68c12879bd1a6c1a75b13"], + "0x588c76d7a6d902cd6f2ca3ce5919b77014973400632a5c81463f5eebc0f9de8": ["0x40ed73ff214a36e736d2cb157ca1b76d198f74ada875c05c97367b9a894f328", "0x3abcb072beea92b4bb2e815a0bbbca97ae43175f1b40985aaf21f41731a71"], + "0x0738e8c7e0cb070b61443ab08f73e931d6c6e4ee16cdc89470a7a62d70be12aa": ["0x1", "0x1", "0x6010b3092dea3fd1732014fcc16554cabe79090410c9f4ace2ed0264299f279"], + "0x06b6255fe6372270afbf24f88f3ecd8649ad2ded37ef1e735f8089d0dc6dbe29": ["0x588c76d7a6d902cd6f2ca3ce5919b77014973400632a5c81463f5eebc0f9de8", "0x3ede65e451e4a643dcc93e056af85e196e125dbc9720626424222d7c6b0f174"], + "0x1c96e88dec3cc34f764ce6844c26ab0baa2883c2ac596a5a1701d5719e45044": ["0x6b6255fe6372270afbf24f88f3ecd8649ad2ded37ef1e735f8089d0dc6dbe29", "0x6e786ba49c4fc2ef6897a9b4f2f7dbd281b91480af9acc480dd8949e0e5093f"], + "0x482c9ce8a99afddc9777ff048520fcbfab6c0389f51584016c80a2e94ab8ca7": ["0x738e8c7e0cb070b61443ab08f73e931d6c6e4ee16cdc89470a7a62d70be12aa", "0x1c96e88dec3cc34f764ce6844c26ab0baa2883c2ac596a5a1701d5719e45044"] + } + }, + "contract_class_commitment_info": { + "previous_root": "0x0", + "updated_root": "0x0", + "tree_height": 251, + "commitment_facts": {} + }, + "deprecated_compiled_classes_raw": { + "build/delegate_proxy.json": "0x1880d2c303f26b658392a2c92a0677f3939f5fdfb960ecf5912afa06ad0b9d9", + "build/test_contract2.json": "0x49bcc976d628b1b238aefc20e77303a251a14ba6c99cd543a86708513414057", + "build/dummy_account.json": "0x16dc3038da22dde8ad61a786ab9930699cc496c8bccb90d77cc8abee89803f7", + "build/test_contract.json": "0x7364bafc3d2c56bc84404a6d8be799f533e518b8808bce86395a9442e1e5160", + "build/dummy_token.json": "0x7cea4d7710723fa9e33472b6ceb71587a0ce4997ef486638dd0156bdb6c2daa" + }, + "deprecated_compiled_classes": { + "0x1880d2c303f26b658392a2c92a0677f3939f5fdfb960ecf5912afa06ad0b9d9": {}, + "0x49bcc976d628b1b238aefc20e77303a251a14ba6c99cd543a86708513414057": {}, + "0x16dc3038da22dde8ad61a786ab9930699cc496c8bccb90d77cc8abee89803f7": {}, + "0x7364bafc3d2c56bc84404a6d8be799f533e518b8808bce86395a9442e1e5160": {}, + "0x7cea4d7710723fa9e33472b6ceb71587a0ce4997ef486638dd0156bdb6c2daa": {} + }, + "compiled_classes": {}, + "contracts": { + "0x0": { + "contract_hash": "0x0", + "storage_commitment_tree": { + "root": "0x0", + "height": 251 + }, + "nonce": 0 + }, + "0x1": { + "contract_hash": "0x0", + "storage_commitment_tree": { + "root": "0x0", + "height": 251 + }, + "nonce": 0 + }, + "0x238e6b5dffc9f0eb2fe476855d0cd1e9e034e5625663c7eda2d871bd4b6eac0": { + "contract_hash": "0x0", + "storage_commitment_tree": { + "root": "0x0", + "height": 251 + }, + "nonce": 0 + }, + "0x3400a86fdc294a70fac1cf84f81a2127419359096b846be9814786d4fc056b8": { + "contract_hash": "0x7cea4d7710723fa9e33472b6ceb71587a0ce4997ef486638dd0156bdb6c2daa", + "storage_commitment_tree": { + "root": "0x0", + "height": 251 + }, + "nonce": 2 + }, + "0x46fd0893101585e0c7ebd3caf8097b179f774102d6373760c8f60b1a5ef8c92": { + "contract_hash": "0x0", + "storage_commitment_tree": { + "root": "0x0", + "height": 251 + }, + "nonce": 0 + }, + "0x4e9665675ca1ac12820b7aff2f44fec713e272efcd3f20aa0fd8ca277f25dc6": { + "contract_hash": "0x0", + "storage_commitment_tree": { + "root": "0x0", + "height": 251 + }, + "nonce": 0 + }, + "0x5ca2b81086d3fbb4f4af2f1deba4b7fd35e8f4b2caee4e056005c51c05c3dd0": { + "contract_hash": "0x16dc3038da22dde8ad61a786ab9930699cc496c8bccb90d77cc8abee89803f7", + "storage_commitment_tree": { + "root": "0x0", + "height": 251 + }, + "nonce": 1 + }, + "0x74cebec93a58b4400af9c082fb3c5adfa0800ff1489f8fc030076491ff86c48": { + "contract_hash": "0x0", + "storage_commitment_tree": { + "root": "0x0", + "height": 251 + }, + "nonce": 0 + } + }, + "class_hash_to_compiled_class_hash": {}, + "general_config": { + "starknet_os_config": { + "chain_id": 1536727068981429685321, + "fee_token_address": "0x3400a86fdc294a70fac1cf84f81a2127419359096b846be9814786d4fc056b8" + }, + "contract_storage_commitment_tree_height": 251, + "compiled_class_hash_commitment_tree_height": 251, + "global_state_commitment_tree_height": 251, + "invoke_tx_max_n_steps": 3000000, + "validate_max_n_steps": 1000000, + "min_gas_price": 100000000, + "constant_gas_price": false, + "sequencer_address": "0x6c95526293b61fa708c6cba66fd015afee89309666246952456ab970e9650aa", + "tx_commitment_tree_height": 64, + "event_commitment_tree_height": 64, + "cairo_resource_fee_weights": {"n_steps": 1.0, "output_builtin": 0.0, "pedersen_builtin": 0.0, "range_check_builtin": 0.0, "ecdsa_builtin": 0.0, "bitwise_builtin": 0.0, "ec_op_builtin": 0.0, "keccak_builtin": 0.0, "poseidon_builtin": 0.0}, + "enforce_l1_handler_fee": true + }, + "transactions": {}, + "block_hash": "0x59b01ba262c999f2617412ffbba780f80b0103d928cbce1aecbaa50de90abda" +} diff --git a/tests/snos.rs b/tests/snos.rs index 6490b0a6..3d46de2e 100644 --- a/tests/snos.rs +++ b/tests/snos.rs @@ -1,6 +1,7 @@ mod common; use blockifier::test_utils::DictStateReader; +use cairo_felt::Felt252; use common::{initial_state, prepare_os_test, utils::check_output_vs_python, utils::print_a_hint}; use cairo_vm::cairo_run::{cairo_run, CairoRunConfig}; @@ -8,9 +9,13 @@ use cairo_vm::hint_processor::builtin_hint_processor::builtin_hint_processor_def BuiltinHintProcessor, HintFunc, }; +use num_traits::Num; use snos::{state::SharedState, SnOsRunner}; use starknet_api::block::BlockNumber; +use starknet_api::core::{ContractAddress, PatriciaKey}; +use starknet_api::hash::{StarkFelt, StarkHash}; +use starknet_api::{contract_address, patricia_key, stark_felt}; use std::fs; use std::rc::Rc; @@ -26,11 +31,45 @@ fn snos_ok(_initial_state: SharedState) { #[rstest] fn prepared_os_test(mut prepare_os_test: SharedState) { - let commitment = prepare_os_test.apply_diff(); + let commitment = prepare_os_test.apply_state(); assert_eq!(BlockNumber(2), prepare_os_test.get_block_num()); - // 1fc35de150561b6229137b3f253fc1c894c93b1c184a8ca0d0f7171a64bcd04 -> addr 2 - // 7d4b1bcb63f8b7f53ef32d5761afc3249180f03dc9773e421a9574c51453c00 -> addr 2 - println!("COMMITMENT: {:?}", commitment); + assert_eq!(Felt252::from(0), commitment.previous_root); + assert_eq!( + Felt252::from_str_radix( + "486b2c996de12788e8715beb8dc5509d39f940dda2bc8132610a7ff18d3c0a4", + 16 + ) + .unwrap(), + commitment.updated_root + ); + + let addr_1_root = prepare_os_test + .get_contract_root(contract_address!( + "46fd0893101585e0c7ebd3caf8097b179f774102d6373760c8f60b1a5ef8c92" + )) + .unwrap(); + assert_eq!( + stark_felt!("7d4b1bcb63f8b7f53ef32d5761afc3249180f03dc9773e421a9574c51453c00"), + addr_1_root.0 + ); + let addr_2_root = prepare_os_test + .get_contract_root(contract_address!( + "4e9665675ca1ac12820b7aff2f44fec713e272efcd3f20aa0fd8ca277f25dc6" + )) + .unwrap(); + assert_eq!( + stark_felt!("1fc35de150561b6229137b3f253fc1c894c93b1c184a8ca0d0f7171a64bcd04"), + addr_2_root.0 + ); + let delegate_root = prepare_os_test + .get_contract_root(contract_address!( + "238e6b5dffc9f0eb2fe476855d0cd1e9e034e5625663c7eda2d871bd4b6eac0" + )) + .unwrap(); + assert_eq!( + stark_felt!("4ed2a0d5f47780aee355c14a37ab2ae7dc8fb6f73773563e02fef51b4ec4abe"), + delegate_root.0 + ); } #[rstest] From 0855921290e5e97b46355bf1eee8bd9d6ab5e52a Mon Sep 17 00:00:00 2001 From: Ben Goebel Date: Tue, 10 Oct 2023 22:14:49 -0600 Subject: [PATCH 04/10] flat input test --- Cargo.toml | 1 + src/hints/mod.rs | 3 + src/io.rs | 133 ++++++++++++++++++++++++++++++++++--- src/state/mod.rs | 16 ++--- src/state/storage.rs | 1 - tests/common/mod.rs | 11 +-- tests/common/os_input.json | 21 ++---- 7 files changed, 143 insertions(+), 43 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b7d7e8d5..8473e1a8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -17,6 +17,7 @@ hex = "0.4.3" indexmap = "1.9.2" log = "0.4.19" num-bigint = "0.4.4" +num-integer = "0.1.45" num-traits = "0.2.16" reqwest = { version = "0.11.18", features = ["blocking", "json"] } serde = { version = "1.0.188", features = ["derive"] } diff --git a/src/hints/mod.rs b/src/hints/mod.rs index 9c46c16c..199261bc 100644 --- a/src/hints/mod.rs +++ b/src/hints/mod.rs @@ -10,6 +10,8 @@ use cairo_vm::types::exec_scope::ExecutionScopes; use cairo_vm::vm::{errors::hint_errors::HintError, vm_core::VirtualMachine}; use std::rc::Rc; +use crate::io::StarknetOsInput; + use cairo_vm::hint_processor::builtin_hint_processor::builtin_hint_processor_definition::{ BuiltinHintProcessor, HintFunc, }; @@ -43,6 +45,7 @@ pub fn starknet_os_input( println!("Running hint {:?} {:?}", ids_data, _exec_scopes); // Deserialize the program_input + let _os_input = StarknetOsInput::load("tests/common/os_input.json"); let initial_carried_outputs_ptr = get_ptr_from_var_name("initial_carried_outputs", vm, ids_data, ap_tracking)?; diff --git a/src/io.rs b/src/io.rs index e9134af5..07cba17b 100644 --- a/src/io.rs +++ b/src/io.rs @@ -1,27 +1,45 @@ use std::collections::HashMap; use cairo_felt::Felt252; +use serde::{Deserialize, Serialize}; +use cairo_vm::serde::deserialize_program::deserialize_felt_hex; +use num_traits::Num; +use serde::Deserializer; +use starknet_api::deprecated_contract_class::ContractClass as DeprecatedContractClass; use starknet_api::transaction::{MessageToL1, MessageToL2}; +use std::fs; +use std::path; -use crate::{ - business_logic::transaction::types::InternalTransaction, config::StarknetGeneralConfig, - state::CommitmentInfo, state::ContractState, -}; +use crate::config::StarknetGeneralConfig; +type CommitmentFacts = HashMap>; + +#[derive(Debug, Serialize, Deserialize)] #[allow(unused)] -struct StarknetOsInput { +pub struct StarknetOsInput { contract_state_commitment_info: CommitmentInfo, contract_class_commitment_info: CommitmentInfo, - deprecated_compiled_classes: HashMap, // TODO: Add contract_class module - compiled_classes: HashMap, // TODO: Add contract_class module - contracts: HashMap, + #[serde(deserialize_with = "parse_deprecated_classes")] + deprecated_compiled_classes: HashMap, // TODO: Add contract_class module + #[serde(deserialize_with = "deserialize_felt_map")] + compiled_classes: HashMap, // TODO: Add contract_class module + // contracts: HashMap, + #[serde(deserialize_with = "deserialize_felt_map")] class_hash_to_compiled_class_hash: HashMap, general_config: StarknetGeneralConfig, - transactions: Vec, + // transactions: Vec, + #[serde(deserialize_with = "deserialize_felt_hex")] block_hash: Felt252, } +impl StarknetOsInput { + pub fn load(path: &str) -> Self { + let raw_input = fs::read_to_string(path::PathBuf::from(path)).unwrap(); + serde_json::from_str(&raw_input).unwrap() + } +} + pub struct StarknetOsOutput { /// The state commitment before this block. pub prev_state_root: Felt252, @@ -38,3 +56,100 @@ pub struct StarknetOsOutput { /// List of messages from L1 handled in this block pub messages_to_l2: Vec, } + +#[derive(Debug, Default, Serialize, Deserialize)] +pub struct CommitmentInfo { + #[serde(deserialize_with = "deserialize_felt_hex")] + pub previous_root: Felt252, + #[serde(deserialize_with = "deserialize_felt_hex")] + pub updated_root: Felt252, + pub(crate) tree_height: usize, + #[serde(deserialize_with = "deserialize_felt_facts")] + pub(crate) commitment_facts: CommitmentFacts, +} + +pub fn deserialize_felt_facts<'de, D: Deserializer<'de>>( + deserializer: D, +) -> Result { + let mut ret_map = CommitmentFacts::new(); + let buf_map: HashMap> = HashMap::deserialize(deserializer)?; + for (fact, commitments) in buf_map.into_iter() { + let fact = fact.strip_prefix("0x").unwrap(); + ret_map.insert( + Felt252::from_str_radix(fact, 16).unwrap(), + commitments + .into_iter() + .map(|commit| { + Felt252::from_str_radix(commit.strip_prefix("0x").unwrap(), 16).unwrap() + }) + .collect(), + ); + } + + Ok(ret_map) +} + +pub fn parse_deprecated_classes<'de, D: Deserializer<'de>>( + deserializer: D, +) -> Result, D::Error> { + let mut ret_map: HashMap = HashMap::new(); + let buf: HashMap = HashMap::deserialize(deserializer)?; + for (k, v) in buf.into_iter() { + let class_hash = Felt252::from_str_radix(k.strip_prefix("0x").unwrap(), 16).unwrap(); + let raw_class = fs::read_to_string(path::PathBuf::from(v)).unwrap(); + let class = serde_json::from_str(&raw_class).unwrap(); + ret_map.insert(class_hash, class); + } + + Ok(ret_map) +} + +pub fn deserialize_felt_map<'de, D: Deserializer<'de>>( + deserializer: D, +) -> Result, D::Error> { + let mut ret_map = HashMap::new(); + let buf_map: HashMap = HashMap::deserialize(deserializer)?; + for (k, v) in buf_map.into_iter() { + let k = k.strip_prefix("0x").unwrap(); + let v = v.strip_prefix("0x").unwrap(); + ret_map.insert( + Felt252::from_str_radix(k, 16).unwrap(), + Felt252::from_str_radix(v, 16).unwrap(), + ); + } + + Ok(ret_map) +} + +#[cfg(test)] +mod tests { + use super::*; + + pub const TESTING_BLOCK_HASH: &str = + "59b01ba262c999f2617412ffbba780f80b0103d928cbce1aecbaa50de90abda"; + + #[test] + fn parse_os_input() { + let input = StarknetOsInput::load("tests/common/os_input.json"); + assert_eq!( + Felt252::from_str_radix(TESTING_BLOCK_HASH, 16).unwrap(), + input.block_hash + ); + assert_eq!( + Felt252::from_str_radix( + "473010ec333f16b84334f9924912d7a13ce8296b0809c2091563ddfb63011d", + 16 + ) + .unwrap(), + input.contract_state_commitment_info.previous_root + ); + assert_eq!( + Felt252::from_str_radix( + "482c9ce8a99afddc9777ff048520fcbfab6c0389f51584016c80a2e94ab8ca7", + 16 + ) + .unwrap(), + input.contract_state_commitment_info.updated_root + ); + } +} diff --git a/src/state/mod.rs b/src/state/mod.rs index 229ac204..ae04ec7b 100644 --- a/src/state/mod.rs +++ b/src/state/mod.rs @@ -8,6 +8,7 @@ use blockifier::state::cached_state::{CachedState, CommitmentStateDiff}; use blockifier::state::state_api::{State, StateReader}; use cairo_felt::Felt252; use indexmap::{IndexMap, IndexSet}; +use serde::Serialize; use storage::TrieStorage; use starknet_api::block::BlockNumber; @@ -16,23 +17,16 @@ use starknet_api::deprecated_contract_class::ContractClass as DeprecatedContract use starknet_api::hash::{StarkFelt, StarkHash}; use starknet_api::{patricia_key, stark_felt}; +use serde::Deserialize; use std::collections::HashMap; use crate::config::DEFAULT_STORAGE_TREE_HEIGHT; +use crate::io::CommitmentInfo; use crate::utils::{bits_from_felt, calculate_contract_state_hash, vm_class_to_api_v0}; -use serde::{Deserialize, Serialize}; -use trie::{MerkleTrie, PedersenHash}; - -type CommitmentFacts = HashMap>; -#[derive(Debug, Default, Serialize, Deserialize)] -pub struct CommitmentInfo { - pub previous_root: Felt252, - pub updated_root: Felt252, - pub(crate) tree_height: usize, - pub(crate) commitment_facts: CommitmentFacts, -} +use trie::{MerkleTrie, PedersenHash}; +#[derive(Serialize, Deserialize, Debug)] pub struct ContractState { _contract_hash: Felt252, _storage_commitment_tree: Felt252, diff --git a/src/state/storage.rs b/src/state/storage.rs index 3ed2dbd0..f98114ba 100644 --- a/src/state/storage.rs +++ b/src/state/storage.rs @@ -1,6 +1,5 @@ use anyhow::Context; use bitvec::{prelude::BitSlice, prelude::BitVec, prelude::Msb0}; -use starknet_api::block::BlockNumber; use starknet_api::hash::StarkFelt; use super::trie::{MerkleTrie, StarkHasher}; diff --git a/tests/common/mod.rs b/tests/common/mod.rs index 08eff2ec..dedac366 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -1,6 +1,5 @@ pub mod utils; -use blockifier::state::state_api::StateReader; use cairo_felt::felt_str; use blockifier::abi::constants::N_STEPS_RESOURCE; @@ -22,9 +21,7 @@ use cairo_vm::vm::vm_core::VirtualMachine; use snos::config::{StarknetGeneralConfig, DEFAULT_FEE_TOKEN_ADDR}; use snos::state::SharedState; use starknet_api::block::{BlockNumber, BlockTimestamp}; -use starknet_api::core::{ - calculate_contract_address, ClassHash, ContractAddress, Nonce, PatriciaKey, -}; +use starknet_api::core::{calculate_contract_address, ClassHash, ContractAddress, PatriciaKey}; use starknet_api::hash::{StarkFelt, StarkHash}; use starknet_api::state::StorageKey; use starknet_api::transaction::{ @@ -45,15 +42,13 @@ use blockifier::test_utils::{ pub const TESTING_FEE: u128 = 0x10000000000000000000000000; pub const TESTING_TRANSFER_AMOUNT: u128 = 0x01000000000000000000000000000000; -pub const TESTING_BLOCK_HASH: &str = - "59b01ba262c999f2617412ffbba780f80b0103d928cbce1aecbaa50de90abda"; // 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 = +pub const _DUMMY_TOKEN_ADDRESS_0_12_2: &str = "3400a86fdc294a70fac1cf84f81a2127419359096b846be9814786d4fc056b8"; // Class Hashes - 0.12.2 @@ -557,7 +552,7 @@ pub fn prepare_os_test( } #[rstest] -fn validate_prepare(mut prepare_os_test: SharedState) { +fn validate_prepare(prepare_os_test: SharedState) { let mut shared_state = prepare_os_test; let diff = shared_state.cache.to_state_diff(); diff --git a/tests/common/os_input.json b/tests/common/os_input.json index 62c4abc6..2a3b30a6 100644 --- a/tests/common/os_input.json +++ b/tests/common/os_input.json @@ -1,7 +1,7 @@ { "contract_state_commitment_info": { "previous_root": "0x473010ec333f16b84334f9924912d7a13ce8296b0809c2091563ddfb63011d", - "updated_root": "0x0482c9ce8a99afddc9777ff048520fcbfab6c0389f51584016c80a2e94ab8ca7", + "updated_root": "0x482c9ce8a99afddc9777ff048520fcbfab6c0389f51584016c80a2e94ab8ca7", "tree_height": 251, "commitment_facts": { "0x473010ec333f16b84334f9924912d7a13ce8296b0809c2091563ddfb63011d": ["0x78ae47e863b0eeac50620a21d7aa9f163b1a9f1dcb2a810cb0c49f8fd16afdc", "0x446868832abcc6f03f057ad04c55047d1c21165b14094249024ef6f3e6effe9"], @@ -27,19 +27,12 @@ "tree_height": 251, "commitment_facts": {} }, - "deprecated_compiled_classes_raw": { - "build/delegate_proxy.json": "0x1880d2c303f26b658392a2c92a0677f3939f5fdfb960ecf5912afa06ad0b9d9", - "build/test_contract2.json": "0x49bcc976d628b1b238aefc20e77303a251a14ba6c99cd543a86708513414057", - "build/dummy_account.json": "0x16dc3038da22dde8ad61a786ab9930699cc496c8bccb90d77cc8abee89803f7", - "build/test_contract.json": "0x7364bafc3d2c56bc84404a6d8be799f533e518b8808bce86395a9442e1e5160", - "build/dummy_token.json": "0x7cea4d7710723fa9e33472b6ceb71587a0ce4997ef486638dd0156bdb6c2daa" - }, "deprecated_compiled_classes": { - "0x1880d2c303f26b658392a2c92a0677f3939f5fdfb960ecf5912afa06ad0b9d9": {}, - "0x49bcc976d628b1b238aefc20e77303a251a14ba6c99cd543a86708513414057": {}, - "0x16dc3038da22dde8ad61a786ab9930699cc496c8bccb90d77cc8abee89803f7": {}, - "0x7364bafc3d2c56bc84404a6d8be799f533e518b8808bce86395a9442e1e5160": {}, - "0x7cea4d7710723fa9e33472b6ceb71587a0ce4997ef486638dd0156bdb6c2daa": {} + "0x1880d2c303f26b658392a2c92a0677f3939f5fdfb960ecf5912afa06ad0b9d9": "build/delegate_proxy.json", + "0x49bcc976d628b1b238aefc20e77303a251a14ba6c99cd543a86708513414057": "build/test_contract2.json", + "0x16dc3038da22dde8ad61a786ab9930699cc496c8bccb90d77cc8abee89803f7": "build/dummy_account.json", + "0x7364bafc3d2c56bc84404a6d8be799f533e518b8808bce86395a9442e1e5160": "build/test_contract.json", + "0x7cea4d7710723fa9e33472b6ceb71587a0ce4997ef486638dd0156bdb6c2daa": "build/dummy_token.json" }, "compiled_classes": {}, "contracts": { @@ -111,7 +104,7 @@ "class_hash_to_compiled_class_hash": {}, "general_config": { "starknet_os_config": { - "chain_id": 1536727068981429685321, + "chain_id": "0x534e5f474f45524c49", "fee_token_address": "0x3400a86fdc294a70fac1cf84f81a2127419359096b846be9814786d4fc056b8" }, "contract_storage_commitment_tree_height": 251, From ef514452a28e7fd546d6738ef07a854f7c2284d8 Mon Sep 17 00:00:00 2001 From: Ben Goebel Date: Tue, 10 Oct 2023 22:47:53 -0600 Subject: [PATCH 05/10] working scopes --- src/hints/mod.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/hints/mod.rs b/src/hints/mod.rs index 199261bc..dcfa0c77 100644 --- a/src/hints/mod.rs +++ b/src/hints/mod.rs @@ -1,7 +1,9 @@ use std::collections::HashMap; use cairo_vm::felt::Felt252; -use cairo_vm::hint_processor::builtin_hint_processor::hint_utils::get_ptr_from_var_name; +use cairo_vm::hint_processor::builtin_hint_processor::hint_utils::{ + get_ptr_from_var_name, insert_value_from_var_name, +}; use cairo_vm::hint_processor::hint_processor_definition::HintReference; mod hints_raw; @@ -46,6 +48,7 @@ pub fn starknet_os_input( // Deserialize the program_input let _os_input = StarknetOsInput::load("tests/common/os_input.json"); + // insert_value_from_var_name("os_input", os_input, vm, ids_data, ap_tracking)?; let initial_carried_outputs_ptr = get_ptr_from_var_name("initial_carried_outputs", vm, ids_data, ap_tracking)?; From 073007da646909169ca4d9099ed8f16eb6ac5cf6 Mon Sep 17 00:00:00 2001 From: Ben Goebel Date: Tue, 10 Oct 2023 22:55:22 -0600 Subject: [PATCH 06/10] exec scopes --- src/hints/mod.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/hints/mod.rs b/src/hints/mod.rs index dcfa0c77..5066443d 100644 --- a/src/hints/mod.rs +++ b/src/hints/mod.rs @@ -47,8 +47,9 @@ pub fn starknet_os_input( println!("Running hint {:?} {:?}", ids_data, _exec_scopes); // Deserialize the program_input - let _os_input = StarknetOsInput::load("tests/common/os_input.json"); - // insert_value_from_var_name("os_input", os_input, vm, ids_data, ap_tracking)?; + let os_input = Box::new(StarknetOsInput::load("tests/common/os_input.json")); + let mut scopes = ExecutionScopes::new(); + scopes.assign_or_update_variable("os_input", os_input); let initial_carried_outputs_ptr = get_ptr_from_var_name("initial_carried_outputs", vm, ids_data, ap_tracking)?; From 3f7a615b9621c25faf2a9c7640e8be0172867404 Mon Sep 17 00:00:00 2001 From: Ben Goebel Date: Tue, 10 Oct 2023 22:57:44 -0600 Subject: [PATCH 07/10] testing exec scopes --- src/hints/mod.rs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/hints/mod.rs b/src/hints/mod.rs index 5066443d..02a2d37d 100644 --- a/src/hints/mod.rs +++ b/src/hints/mod.rs @@ -1,9 +1,7 @@ use std::collections::HashMap; use cairo_vm::felt::Felt252; -use cairo_vm::hint_processor::builtin_hint_processor::hint_utils::{ - get_ptr_from_var_name, insert_value_from_var_name, -}; +use cairo_vm::hint_processor::builtin_hint_processor::hint_utils::get_ptr_from_var_name; use cairo_vm::hint_processor::hint_processor_definition::HintReference; mod hints_raw; @@ -39,17 +37,16 @@ ids.initial_carried_outputs.messages_to_l2 = segments.add_temp_segment() %} */ pub fn starknet_os_input( vm: &mut VirtualMachine, - _exec_scopes: &mut ExecutionScopes, + exec_scopes: &mut ExecutionScopes, ids_data: &HashMap, ap_tracking: &ApTracking, _constants: &HashMap, ) -> Result<(), HintError> { - println!("Running hint {:?} {:?}", ids_data, _exec_scopes); + println!("Running hint {:?} {:?}", ids_data, exec_scopes); // Deserialize the program_input let os_input = Box::new(StarknetOsInput::load("tests/common/os_input.json")); - let mut scopes = ExecutionScopes::new(); - scopes.assign_or_update_variable("os_input", os_input); + exec_scopes.assign_or_update_variable("os_input", os_input); let initial_carried_outputs_ptr = get_ptr_from_var_name("initial_carried_outputs", vm, ids_data, ap_tracking)?; From 2058f68b30425a90b0bbc42c2ff6dcf4290d517a Mon Sep 17 00:00:00 2001 From: Ben Goebel Date: Tue, 10 Oct 2023 23:20:19 -0600 Subject: [PATCH 08/10] rm storage mod --- src/storage/starknet.rs | 14 -------------- tests/snos.rs | 1 - 2 files changed, 15 deletions(-) delete mode 100644 src/storage/starknet.rs diff --git a/src/storage/starknet.rs b/src/storage/starknet.rs deleted file mode 100644 index ac5a8e56..00000000 --- a/src/storage/starknet.rs +++ /dev/null @@ -1,14 +0,0 @@ -use serde::{Deserialize, Serialize}; -use std::collections::HashMap; - -use cairo_felt::Felt252; - -type CommitmentFacts = HashMap>; - -#[derive(Debug, Serialize, Deserialize)] -pub struct CommitmentInfo { - pub previous_root: Felt252, - pub updated_root: Felt252, - pub(crate) tree_height: usize, - pub(crate) commitment_facts: CommitmentFacts, -} diff --git a/tests/snos.rs b/tests/snos.rs index 3d46de2e..57a51a74 100644 --- a/tests/snos.rs +++ b/tests/snos.rs @@ -23,7 +23,6 @@ use std::rc::Rc; use rstest::*; #[rstest] -#[ignore] fn snos_ok(_initial_state: SharedState) { let snos_runner = SnOsRunner::with_os_path("build/os_debug.json"); let _runner_res = snos_runner.run(); From 7fef19f88a3af39691cc2d60853510a5266e1ac4 Mon Sep 17 00:00:00 2001 From: LucasLvy Date: Wed, 11 Oct 2023 11:46:24 +0200 Subject: [PATCH 09/10] test(snos): fix tests --- tests/snos.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/snos.rs b/tests/snos.rs index 57a51a74..f3024b24 100644 --- a/tests/snos.rs +++ b/tests/snos.rs @@ -23,6 +23,7 @@ use std::rc::Rc; use rstest::*; #[rstest] +#[ignore] fn snos_ok(_initial_state: SharedState) { let snos_runner = SnOsRunner::with_os_path("build/os_debug.json"); let _runner_res = snos_runner.run(); @@ -35,7 +36,7 @@ fn prepared_os_test(mut prepare_os_test: SharedState) { assert_eq!(Felt252::from(0), commitment.previous_root); assert_eq!( Felt252::from_str_radix( - "486b2c996de12788e8715beb8dc5509d39f940dda2bc8132610a7ff18d3c0a4", + "26f415452a5d140f444d3cb814fded5b35386944d7c36812af0885bafd2ba56", 16 ) .unwrap(), From 4c44c661019f47c57b9d823af22085ececf15717 Mon Sep 17 00:00:00 2001 From: LucasLvy Date: Tue, 10 Oct 2023 15:09:16 +0200 Subject: [PATCH 10/10] test(os hint): load compiled classes --- scripts/setup-tests.sh | 1 + src/hints/hints_raw.rs | 6 ++ src/hints/mod.rs | 64 +++++++++++++++++++-- src/io.rs | 5 ++ tests/contracts/load_compiled_classes.cairo | 17 ++++++ tests/pie.rs | 6 +- tests/programs/hint.cairo | 2 - tests/programs/load_compiled_classes.cairo | 17 ++++++ tests/sharp.rs | 2 +- tests/snos.rs | 34 ++++++----- 10 files changed, 126 insertions(+), 28 deletions(-) create mode 100644 tests/contracts/load_compiled_classes.cairo create mode 100644 tests/programs/load_compiled_classes.cairo diff --git a/scripts/setup-tests.sh b/scripts/setup-tests.sh index e0ba143c..6d759987 100755 --- a/scripts/setup-tests.sh +++ b/scripts/setup-tests.sh @@ -44,3 +44,4 @@ cairo-compile cairo-lang/src/starkware/starknet/core/os/os.cairo --output build/ cairo-compile tests/programs/different_output.cairo --output build/different_output.json cairo-compile tests/programs/fact.cairo --output build/fact.json cairo-compile tests/programs/hint.cairo --output build/hint.json +cairo-compile tests/programs/load_compiled_classes.cairo --output build/load_compiled_classes.json diff --git a/src/hints/hints_raw.rs b/src/hints/hints_raw.rs index 870ad49f..7448fca7 100644 --- a/src/hints/hints_raw.rs +++ b/src/hints/hints_raw.rs @@ -5,6 +5,12 @@ os_input = StarknetOsInput.load(data=program_input) ids.initial_carried_outputs.messages_to_l1 = segments.add_temp_segment() ids.initial_carried_outputs.messages_to_l2 = segments.add_temp_segment()"#; +pub const LOAD_COMPILED_CLASS_FACTS: &str = r#"ids.compiled_class_facts = segments.add() +ids.n_compiled_class_facts = len(os_input.compiled_classes) +vm_enter_scope({ + 'compiled_class_facts': iter(os_input.compiled_classes.items()), +})"#; + pub const _VM_ENTER_SCOPE: &str = " # This hint shouldn't be whitelisted. vm_enter_scope(dict( diff --git a/src/hints/mod.rs b/src/hints/mod.rs index 02a2d37d..7f0d007b 100644 --- a/src/hints/mod.rs +++ b/src/hints/mod.rs @@ -1,21 +1,26 @@ +use std::any::Any; use std::collections::HashMap; use cairo_vm::felt::Felt252; -use cairo_vm::hint_processor::builtin_hint_processor::hint_utils::get_ptr_from_var_name; +use cairo_vm::hint_processor::builtin_hint_processor::hint_utils::{ + get_ptr_from_var_name, insert_value_from_var_name, +}; use cairo_vm::hint_processor::hint_processor_definition::HintReference; -mod hints_raw; +use crate::io::StarknetOsInput; use cairo_vm::serde::deserialize_program::ApTracking; use cairo_vm::types::exec_scope::ExecutionScopes; +use cairo_vm::types::relocatable::MaybeRelocatable; use cairo_vm::vm::{errors::hint_errors::HintError, vm_core::VirtualMachine}; -use std::rc::Rc; -use crate::io::StarknetOsInput; +use std::rc::Rc; use cairo_vm::hint_processor::builtin_hint_processor::builtin_hint_processor_definition::{ BuiltinHintProcessor, HintFunc, }; +pub mod hints_raw; + pub fn sn_hint_processor() -> BuiltinHintProcessor { let mut hint_processor = BuiltinHintProcessor::new_empty(); @@ -63,3 +68,54 @@ pub fn starknet_os_input( Ok(()) } + +/* +Implements hint: + %{ + ids.compiled_class_facts = segments.add() + ids.n_compiled_class_facts = len(os_input.compiled_classes) + vm_enter_scope({ + 'compiled_class_facts': iter(os_input.compiled_classes.items()), + }) + %} +*/ +pub fn load_compiled_class_facts( + vm: &mut VirtualMachine, + exec_scopes: &mut ExecutionScopes, + ids_data: &HashMap, + ap_tracking: &ApTracking, + _constants: &HashMap, +) -> Result<(), HintError> { + // ids.compiled_class_facts = segments.add() + insert_value_from_var_name( + "compiled_class_facts", + vm.add_memory_segment(), + vm, + ids_data, + ap_tracking, + )?; + // Access the value of os_input which was loaded in a previous hint like that + // %{ os_input = ... %} + // Can't directly get os_input.compiled_classes so we need to get the whole os_input + let compiled_class_facts = exec_scopes + .get_ref::("os_input")? + .compiled_classes() + .clone(); + // ids.n_compiled_class_facts = len(os_input.compiled_classes) + insert_value_from_var_name( + "n_compiled_class_facts", + MaybeRelocatable::Int(Felt252::new(compiled_class_facts.len())), + vm, + ids_data, + ap_tracking, + )?; + // vm_enter_scope({ + // 'compiled_class_facts': iter(os_input.compiled_classes.items()), + // }) + let boxed_compiled_classes: Box = Box::new(compiled_class_facts.into_iter()); + exec_scopes.enter_scope(HashMap::from_iter(vec![( + "compiled_class_facts".to_string(), + boxed_compiled_classes, + )])); + Ok(()) +} diff --git a/src/io.rs b/src/io.rs index 07cba17b..dcad05c5 100644 --- a/src/io.rs +++ b/src/io.rs @@ -32,6 +32,11 @@ pub struct StarknetOsInput { #[serde(deserialize_with = "deserialize_felt_hex")] block_hash: Felt252, } +impl StarknetOsInput { + pub fn compiled_classes(&self) -> &HashMap { + &self.compiled_classes + } +} impl StarknetOsInput { pub fn load(path: &str) -> Self { diff --git a/tests/contracts/load_compiled_classes.cairo b/tests/contracts/load_compiled_classes.cairo new file mode 100644 index 00000000..6d618bb9 --- /dev/null +++ b/tests/contracts/load_compiled_classes.cairo @@ -0,0 +1,17 @@ +%builtins output + +func main(output_ptr: felt*) -> (output_ptr: felt*) { + alloc_locals; + local compiled_class_facts; + local n_compiled_class_facts; + %{ + ids.compiled_class_facts = segments.add() + ids.n_compiled_class_facts = len(os_input.compiled_classes) + vm_enter_scope({ + 'compiled_class_facts': iter(os_input.compiled_classes.items()), + }) + %} + // When entering a scope we need to exit it afterwards otherwise the vm panics. + %{ vm_exit_scope() %} + return(output_ptr = output_ptr); +} diff --git a/tests/pie.rs b/tests/pie.rs index bf8824c1..95667e9a 100644 --- a/tests/pie.rs +++ b/tests/pie.rs @@ -71,19 +71,19 @@ fn pie_execution_resources_ok(setup_pie: CairoPie) { fn pie_version_ok(setup_pie: CairoPie) { let version = setup_pie.version; - let version_s = serde_json::to_value(&version).unwrap(); + let version_s = serde_json::to_value(version).unwrap(); assert_eq!(version_s, json!({"cairo_pie": "1.1"})); } #[rstest] fn pie_memory_ok(setup_pie: CairoPie) { - let pie_s = serde_json::to_value(&setup_pie).unwrap(); + let pie_s = serde_json::to_value(setup_pie).unwrap(); assert_eq!(pie_s["memory"], "00000000000000800080ff7f018006400000000000000000000000000000000000000000000000000100000000000080640000000000000000000000000000000000000000000000000000000000000002000000000000800080fd7f0080024800000000000000000000000000000000000000000000000003000000000000800080ff7f018006400000000000000000000000000000000000000000000000000400000000000080c80000000000000000000000000000000000000000000000000000000000000005000000000000800080fd7f0180024800000000000000000000000000000000000000000000000006000000000000800080ff7f0180064000000000000000000000000000000000000000000000000007000000000000802c0100000000000000000000000000000000000000000000000000000000000008000000000000800080fd7f0280024800000000000000000000000000000000000000000000000009000000000000800080fd7f018026480000000000000000000000000000000000000000000000000a0000000000008003000000000000000000000000000000000000000000000000000000000000000b00000000000080fe7fff7fff7f8b20000000000000000000000000000000000000000000000000000000000080008000000000000001000000000000000000000000000000000000000000000000800100000000800080000000000080010000000000000000000000000000000000000000000000008002000000008000800000000000000200000000000000000000000000000000000000000000000080030000000080008064000000000000000000000000000000000000000000000000000000000000000400000000800080c80000000000000000000000000000000000000000000000000000000000000005000000008000802c0100000000000000000000000000000000000000000000000000000000000006000000008000800300000000000100000000000000000000000000000000000000000000000080000000000000018064000000000000000000000000000000000000000000000000000000000000000100000000000180c80000000000000000000000000000000000000000000000000000000000000002000000000001802c01000000000000000000000000000000000000000000000000000000000000"); } #[rstest] fn prepare_pie_ok(setup_pie: CairoPie) { - let disk_b64 = encode_pie(setup_pie.clone(), &Path::new("build/test.zip")); + let disk_b64 = encode_pie(setup_pie.clone(), Path::new("build/test.zip")); assert!(disk_b64.is_ok()); let mem_b64 = encode_pie_mem(setup_pie); diff --git a/tests/programs/hint.cairo b/tests/programs/hint.cairo index be24253f..f16350fb 100644 --- a/tests/programs/hint.cairo +++ b/tests/programs/hint.cairo @@ -4,8 +4,6 @@ func main(output_ptr: felt*) -> (output_ptr: felt*) { tempvar a = 17; a = [output_ptr], ap++; - // Use custom hint to print the value of a - %{ print(ids.a) %} let output_ptr = output_ptr + 1; return(output_ptr = output_ptr); diff --git a/tests/programs/load_compiled_classes.cairo b/tests/programs/load_compiled_classes.cairo new file mode 100644 index 00000000..6d618bb9 --- /dev/null +++ b/tests/programs/load_compiled_classes.cairo @@ -0,0 +1,17 @@ +%builtins output + +func main(output_ptr: felt*) -> (output_ptr: felt*) { + alloc_locals; + local compiled_class_facts; + local n_compiled_class_facts; + %{ + ids.compiled_class_facts = segments.add() + ids.n_compiled_class_facts = len(os_input.compiled_classes) + vm_enter_scope({ + 'compiled_class_facts': iter(os_input.compiled_classes.items()), + }) + %} + // When entering a scope we need to exit it afterwards otherwise the vm panics. + %{ vm_exit_scope() %} + return(output_ptr = output_ptr); +} diff --git a/tests/sharp.rs b/tests/sharp.rs index e8ba73d3..0b19d87b 100644 --- a/tests/sharp.rs +++ b/tests/sharp.rs @@ -20,5 +20,5 @@ fn sharp_client_status() { let submit_resp = sharp_client.get_status(TEST_CAIRO_JOB_ID).unwrap(); assert_eq!(submit_resp.version.unwrap(), 1); - assert_eq!(submit_resp.validation_done.unwrap(), true); + assert!(submit_resp.validation_done.unwrap()); } diff --git a/tests/snos.rs b/tests/snos.rs index f3024b24..02230d08 100644 --- a/tests/snos.rs +++ b/tests/snos.rs @@ -17,6 +17,9 @@ use starknet_api::core::{ContractAddress, PatriciaKey}; use starknet_api::hash::{StarkFelt, StarkHash}; use starknet_api::{contract_address, patricia_key, stark_felt}; +use snos::hints::hints_raw::*; +use snos::hints::load_compiled_class_facts; + use std::fs; use std::rc::Rc; @@ -73,18 +76,13 @@ fn prepared_os_test(mut prepare_os_test: SharedState) { } #[rstest] -fn custom_hint_ok() { +#[should_panic(expected = "Output #0 is different")] +fn test_different_outputs() { let program_content = fs::read("build/hint.json").unwrap(); - // Wrap the Rust hint implementation in a Box smart pointer inside a HintFunc - let hint = HintFunc(Box::new(print_a_hint)); - //Instantiate the hint processor let mut hint_processor = BuiltinHintProcessor::new_empty(); - //Add the custom hint, together with the Python code - hint_processor.add_hint(String::from("print(ids.a)"), Rc::new(hint)); - //Run the cairo program let (_cairo_runner, virtual_machine) = cairo_run( &program_content, @@ -95,22 +93,22 @@ fn custom_hint_ok() { &mut hint_processor, ) .expect("Couldn't run program"); - check_output_vs_python("build/hint.json", virtual_machine); + check_output_vs_python("build/different_output.json", virtual_machine); } #[rstest] -#[should_panic(expected = "Output #0 is different")] -fn test_different_outputs() { - let program_content = fs::read("build/hint.json").unwrap(); +fn load_compiled_classes_facts_test() { + let program_path = "build/load_compiled_classes.json"; - // Wrap the Rust hint implementation in a Box smart pointer inside a HintFunc - let hint = HintFunc(Box::new(print_a_hint)); - - //Instantiate the hint processor + // Instantiate the hint processor let mut hint_processor = BuiltinHintProcessor::new_empty(); - //Add the custom hint, together with the Python code - hint_processor.add_hint(String::from("print(ids.a)"), Rc::new(hint)); + hint_processor.add_hint( + LOAD_COMPILED_CLASS_FACTS.to_owned(), + Rc::new(HintFunc(Box::new(load_compiled_class_facts))), + ); + + let program_content = fs::read(program_path).unwrap(); //Run the cairo program let (_cairo_runner, virtual_machine) = cairo_run( @@ -122,5 +120,5 @@ fn test_different_outputs() { &mut hint_processor, ) .expect("Couldn't run program"); - check_output_vs_python("build/different_output.json", virtual_machine); + check_output_vs_python(program_path, virtual_machine); }