diff --git a/CHANGELOG.md b/CHANGELOG.md index 9fac4644d..6db4426ea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## Next release +- fix(root): Cleaned state root commitments crate - fix(hash): declare tx v0 hash computation - perf(db): db contract history parallel fetching and batching - remove RuntimeApi on RPC diff --git a/crates/client/sync/src/commitments/classes.rs b/crates/client/sync/src/commitments/classes.rs new file mode 100644 index 000000000..79254aef1 --- /dev/null +++ b/crates/client/sync/src/commitments/classes.rs @@ -0,0 +1,58 @@ +use blockifier::state::cached_state::CommitmentStateDiff; +use mc_db::storage_handler::{self, DeoxysStorageError}; +use mp_felt::Felt252Wrapper; +use mp_hashers::poseidon::PoseidonHasher; +use mp_hashers::HasherT; +use rayon::prelude::*; +use starknet_ff::FieldElement; + +// "CONTRACT_CLASS_LEAF_V0" +const CONTRACT_CLASS_HASH_VERSION: FieldElement = + FieldElement::from_mont([9331882290187415277, 12057587991035439952, 18444375821049509847, 115292049744600508]); + +/// Calculates the class trie root +/// +/// # Arguments +/// +/// * `csd` - Commitment state diff for the current block. +/// * `bonsai_class` - Bonsai db used to store class hashes. +/// * `block_number` - The current block number. +/// +/// # Returns +/// +/// The class root. +pub fn class_trie_root(csd: &CommitmentStateDiff, block_number: u64) -> Result { + let mut handler_class = storage_handler::class_trie_mut(); + + let updates = csd + .class_hash_to_compiled_class_hash + .iter() + .par_bridge() + .map(|(class_hash, compiled_class_hash)| { + let compiled_class_hash = FieldElement::from_bytes_be(&compiled_class_hash.0.0).unwrap(); + + let hash = PoseidonHasher::hash_elements(CONTRACT_CLASS_HASH_VERSION, compiled_class_hash); + + (class_hash, hash) + }) + .collect::>(); + + handler_class.init()?; + handler_class.update(updates)?; + handler_class.commit(block_number)?; + + Ok(handler_class.root()?.into()) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_contract_class_hash_version() { + assert_eq!( + CONTRACT_CLASS_HASH_VERSION, + FieldElement::from_byte_slice_be("CONTRACT_CLASS_LEAF_V0".as_bytes()).unwrap(), + ); + } +} diff --git a/crates/client/sync/src/commitments/contracts.rs b/crates/client/sync/src/commitments/contracts.rs index 9b43f2bf0..fcea6c8d6 100644 --- a/crates/client/sync/src/commitments/contracts.rs +++ b/crates/client/sync/src/commitments/contracts.rs @@ -1,620 +1,142 @@ -use bitvec::order::Msb0; -use bitvec::vec::BitVec; -use bitvec::view::BitView; -use bonsai_trie::id::BasicId; -use bonsai_trie::BonsaiStorage; -use indexmap::IndexMap; -use mc_db::bonsai_db::BonsaiDb; +use std::collections::HashSet; + +use blockifier::state::cached_state::CommitmentStateDiff; +use mc_db::storage_handler::{self, DeoxysStorageError, StorageView}; use mp_felt::Felt252Wrapper; +use mp_hashers::pedersen::PedersenHasher; use mp_hashers::HasherT; -use sp_core::hexdisplay::AsBytesRef; +use rayon::prelude::*; use starknet_api::core::ContractAddress; -use starknet_api::hash::StarkFelt; -use starknet_api::state::StorageKey; -use starknet_types_core::hash::Pedersen; - -#[derive(Debug)] -pub struct ContractLeafParams { - pub class_hash: Felt252Wrapper, - pub storage_root: Felt252Wrapper, - pub nonce: Felt252Wrapper, -} +use starknet_ff::FieldElement; +use starknet_types_core::felt::Felt; -/// Calculates the storage root in memory recomupting all the storage changes for a specific -/// contract. NOTE: in the future this function should be persistent, replaced with a more efficient -/// way computing only changes. -/// -/// `storage_root` is the root of another Merkle-Patricia trie of height 251 that is constructed -/// from the contract’s storage. +/// Calculates the contract trie root /// /// # Arguments /// -/// * `overrides` - The storage overrides. -/// * `contract_address` - The contract address. -/// * `storage_updates` - The storage updates. -/// * `maybe_block_hash` - The block hash. +/// * `csd` - Commitment state diff for the current block. +/// * `block_number` - The current block number. /// /// # Returns /// -/// The storage root hash. -pub fn update_storage_trie( - contract_address: &ContractAddress, - storage_updates: &IndexMap, - bonsai_contract_storage: &mut BonsaiStorage, -) { - let identifier = identifier(contract_address); - bonsai_contract_storage.init_tree(identifier).expect("Failed to init tree"); - - // Insert new storage changes - for (key, value) in storage_updates { - let (key, value) = convert_storage(*key, *value); - bonsai_contract_storage - .insert(identifier, &key, &value.into()) - .expect("Failed to insert storage update into trie"); +/// The contract root. +pub fn contract_trie_root(csd: &CommitmentStateDiff, block_number: u64) -> Result { + // NOTE: handlers implicitely acquire a lock on their respective tries + // for the duration of their livetimes + let mut handler_contract = storage_handler::contract_trie_mut(); + let mut handler_storage_trie = storage_handler::contract_storage_trie_mut(); + + // First we insert the contract storage changes + for (contract_address, updates) in csd.storage_updates.iter() { + handler_storage_trie.init(contract_address)?; + + for (key, value) in updates { + handler_storage_trie.insert(*contract_address, *key, *value)?; + } } -} -fn convert_storage(storage_key: StorageKey, storage_value: StarkFelt) -> (BitVec, Felt252Wrapper) { - let key = Felt252Wrapper::from(storage_key.0.0).0.to_bytes_be().view_bits()[5..].to_owned(); - let value = Felt252Wrapper::from(storage_value); + // Then we commit them + handler_storage_trie.commit(block_number)?; + + // We need to initialize the contract trie for each contract that has a class_hash or nonce update + // to retrieve the corresponding storage root + for contract_address in csd.address_to_class_hash.keys().chain(csd.address_to_nonce.keys()) { + if !csd.storage_updates.contains_key(contract_address) { + // Initialize the storage trie if this contract address does not have storage updates + handler_storage_trie.init(contract_address)?; + } + } - (key, value) + // We need to calculate the contract_state_leaf_hash for each contract + // that not appear in the storage_updates but has a class_hash or nonce update + let all_contract_address: HashSet = csd + .storage_updates + .keys() + .chain(csd.address_to_class_hash.keys()) + .chain(csd.address_to_nonce.keys()) + .cloned() + .collect(); + + // Then we compute the leaf hashes retrieving the corresponding storage root + let updates = all_contract_address + .iter() + .par_bridge() + .map(|contract_address| { + let storage_root = handler_storage_trie.root(contract_address)?; + let leaf_hash = contract_state_leaf_hash(csd, contract_address, storage_root)?; + + Ok::<(&ContractAddress, Felt), DeoxysStorageError>((contract_address, leaf_hash)) + }) + .collect::, _>>()?; + + // then we compute the contract root by applying the changes so far + handler_contract.update(updates)?; + handler_contract.commit(block_number)?; + + Ok(handler_contract.root()?.into()) } -/// Calculates the contract state hash. +/// Computes the contract state leaf hash /// /// # Arguments /// -/// * `hash` - The hash of the contract definition. -/// * `root` - The root of root of another Merkle-Patricia trie of height 251 that is constructed -/// from the contract’s storage. -/// * `nonce` - The current nonce of the contract. +/// * `csd` - Commitment state diff for the current block. +/// * `contract_address` - The contract address. +/// * `storage_root` - The storage root of the contract. /// /// # Returns /// /// The contract state leaf hash. -pub fn calculate_contract_state_leaf_hash(contract_leaf_params: ContractLeafParams) -> Felt252Wrapper { - // Define the constant for the contract state hash version - const CONTRACT_STATE_HASH_VERSION: Felt252Wrapper = Felt252Wrapper::ZERO; +fn contract_state_leaf_hash( + csd: &CommitmentStateDiff, + contract_address: &ContractAddress, + storage_root: Felt, +) -> Result { + let (class_hash, nonce) = class_hash_and_nonce(csd, contract_address)?; - let contract_state_hash = H::hash_elements(contract_leaf_params.class_hash.0, contract_leaf_params.storage_root.0); - let contract_state_hash = H::hash_elements(contract_state_hash, contract_leaf_params.nonce.0); - let contract_state_hash = H::hash_elements(contract_state_hash, CONTRACT_STATE_HASH_VERSION.0); + let storage_root = FieldElement::from_bytes_be(&storage_root.to_bytes_be()).unwrap(); - contract_state_hash.into() -} + // computes the contract state leaf hash + let contract_state_hash = PedersenHasher::hash_elements(class_hash, storage_root); + let contract_state_hash = PedersenHasher::hash_elements(contract_state_hash, nonce); + let contract_state_hash = PedersenHasher::hash_elements(contract_state_hash, FieldElement::ZERO); -pub fn identifier(contract_address: &ContractAddress) -> &[u8] { - contract_address.0.0.0.as_bytes_ref() + Ok(Felt::from_bytes_be(&contract_state_hash.to_bytes_be())) } -#[cfg(test)] -mod tests { - use bonsai_trie::databases::HashMapDb; - use bonsai_trie::id::{BasicId, BasicIdBuilder}; - use bonsai_trie::{BonsaiStorage, BonsaiStorageConfig}; - use mp_felt::Felt252Wrapper; - use mp_hashers::pedersen::PedersenHasher; - use starknet_api::hash::StarkFelt; - use starknet_types_core::hash::Pedersen; - - use super::calculate_contract_state_leaf_hash; - use crate::commitments::lib::key as keyer; - - #[test] - fn test_contract_leaf_hash() { - let contract_leaf_params = super::ContractLeafParams { - class_hash: Felt252Wrapper::from_hex_be( - "0x2ff4903e17f87b298ded00c44bfeb22874c5f73be2ced8f1d9d9556fb509779", - ) - .unwrap(), - storage_root: Felt252Wrapper::from_hex_be( - "0x4fb440e8ca9b74fc12a22ebffe0bc0658206337897226117b985434c239c028", - ) - .unwrap(), - nonce: Felt252Wrapper::ZERO, - }; - - let expected = - Felt252Wrapper::from_hex_be("0x7161b591c893836263a64f2a7e0d829c92f6956148a60ce5e99a3f55c7973f3").unwrap(); - - let result = calculate_contract_state_leaf_hash::(contract_leaf_params); - - assert_eq!(result, expected); - } - - #[test] - fn test_insert_zero() { - let config = BonsaiStorageConfig::default(); - let bonsai_db = HashMapDb::::default(); - let mut bonsai_storage = - BonsaiStorage::<_, _, Pedersen>::new(bonsai_db, config).expect("Failed to create bonsai storage"); - let identifier = "0x056e4fed965fccd7fb01fcadd827470338f35ced62275328929d0d725b5707ba".as_bytes(); - - // Insert Block 3 storage changes for contract - // `0x056e4fed965fccd7fb01fcadd827470338f35ced62275328929d0d725b5707ba` - let block_3 = [ - ("0x5", "0x456"), - ( - "0x378e096bb5e74b0f4ca78660a6b49b4a8035e571b024c018713c80b4b969735", - "0x205d119502a165dae3830f627fa93fbdf5bfb13edd8f00e4c72621d0cda24", - ), - ( - "0x41139bbf557d599fe8e96983251ecbfcb5bf4c4138c85946b0c4a6a68319f24", - "0x7eec291f712520293664c7e3a8bb39ab00babf51cb0d9c1fb543147f37b485f", - ), - ( - "0x77ae79c60260b3e48516a7da1aa173ac2765a5ced420f8ffd1539c394fbc03c", - "0x6025343ab6a7ac36acde4eba3b6fc21f53d5302ee26e6f28e8de5a62bbfd847", - ), - ( - "0x751901aac66fdc1f455c73022d02f1c085602cd0c9acda907cfca5418769e9c", - "0x3f23078d48a4bf1d5f8ca0348f9efe9300834603625a379cae5d6d81100adef", - ), - ( - "0x751901aac66fdc1f455c73022d02f1c085602cd0c9acda907cfca5418769e9d", - "0xbd858a06904cadc3787ecbad97409606dcee50ea6fc30b94930bcf3d8843d5", - ), - ]; - - for (key_hex, value_hex) in block_3.iter() { - let key: StarkFelt = Felt252Wrapper::from_hex_be(key_hex).unwrap().into(); - let value = Felt252Wrapper::from_hex_be(value_hex).unwrap(); - bonsai_storage - .insert(identifier, keyer(key).as_bitslice(), &value.into()) - .expect("Failed to insert storage update into trie"); - } - - let mut id_builder = BasicIdBuilder::new(); - let id = id_builder.new_id(); - bonsai_storage.commit(id).expect("Failed to commit to bonsai storage"); - let root_hash = bonsai_storage.root_hash(identifier).expect("Failed to get root hash"); - - println!( - "Expected: 0x069064A05C14A9A2B4ED81C479C14D30872A9AE9CE2DEA8E4B4509542C2DCC1F\nFound: {:?}", - Felt252Wrapper::from(root_hash) - ); - assert_eq!( - Felt252Wrapper::from(root_hash), - Felt252Wrapper::from_hex_be("0x069064A05C14A9A2B4ED81C479C14D30872A9AE9CE2DEA8E4B4509542C2DCC1F").unwrap() - ); - - // Insert Block 4 storage changes for contract - // `0x056e4fed965fccd7fb01fcadd827470338f35ced62275328929d0d725b5707ba` - let block_4 = [ - ("0x5", "0x0"), // Inserting key = 0x0 - ("0x4b81c1bca2d1b7e08535a5abe231b2e94399674db5e8f1d851fd8f4af4abd34", "0x7c7"), - ("0x6f8cf54aaec1f42d5f3868d597fcd7393da888264dc5a6e93c7bd528b6d6fee", "0x7e5"), - ( - "0x2a315469199dfde4b05906db8c33f6962916d462d8f1cf5252b748dfa174a20", - "0xdae79d0308bb710af439eb36e82b405dc2bca23b351d08b4867d9525226e9d", - ), - ( - "0x2d1ed96c7561dd8e5919657790ffba8473b80872fea3f7ef8279a7253dc3b33", - "0x750387f4d66b0e9be1f2f330e8ad309733c46bb74e0be4df0a8c58fb4e89a25", - ), - ("0x6a93bcb89fc1f31fa544377c7de6de1dd3e726e1951abc95c4984995e84ad0d", "0x7e5"), - ("0x6b3b4780013c33cdca6799e8aa3ef922b64f5a2d356573b33693d81504deccf", "0x7c7"), - ]; - - for (key_hex, value_hex) in block_4.iter() { - let key: StarkFelt = Felt252Wrapper::from_hex_be(key_hex).unwrap().into(); - let value = Felt252Wrapper::from_hex_be(value_hex).unwrap(); - bonsai_storage - .insert(identifier, keyer(key).as_bitslice(), &value.into()) - .expect("Failed to insert storage update into trie"); - } - - let id = id_builder.new_id(); - bonsai_storage.commit(id).expect("Failed to commit to bonsai storage"); - let root_hash = bonsai_storage.root_hash(identifier).expect("Failed to get root hash"); - - println!( - "Expected: 0x0112998A41A3A2C720E758F82D184E4C39E9382620F12076B52C516D14622E57\nFound: {:?}", - Felt252Wrapper::from(root_hash) - ); - assert_eq!( - Felt252Wrapper::from(root_hash), - Felt252Wrapper::from_hex_be("0x0112998A41A3A2C720E758F82D184E4C39E9382620F12076B52C516D14622E57").unwrap() - ); - - // Insert Block 5 storage changes for contract - // `0x056e4fed965fccd7fb01fcadd827470338f35ced62275328929d0d725b5707ba` - let block_5 = [("0x5", "0x456")]; - - for (key_hex, value_hex) in block_5.iter() { - let key: StarkFelt = Felt252Wrapper::from_hex_be(key_hex).unwrap().into(); - let value = Felt252Wrapper::from_hex_be(value_hex).unwrap(); - bonsai_storage - .insert(identifier, keyer(key).as_bitslice(), &value.into()) - .expect("Failed to insert storage update into trie"); - } - - let id = id_builder.new_id(); - bonsai_storage.commit(id).expect("Failed to commit to bonsai storage"); - let root_hash = bonsai_storage.root_hash(identifier).expect("Failed to get root hash"); - - println!( - "Expected: 0x072E79A6F71E3E63D7DE40EDF4322A22E64388D4D5BFE817C1271C78028B73BF\nFound: {:?}", - Felt252Wrapper::from(root_hash) - ); - assert_eq!( - Felt252Wrapper::from(root_hash), - Felt252Wrapper::from_hex_be("0x072E79A6F71E3E63D7DE40EDF4322A22E64388D4D5BFE817C1271C78028B73BF").unwrap() - ); - } - - #[test] - fn test_undefined_zero() { - let config = BonsaiStorageConfig::default(); - let bonsai_db = HashMapDb::::default(); - let mut bonsai_storage = - BonsaiStorage::<_, _, Pedersen>::new(bonsai_db, config).expect("Failed to create bonsai storage"); - let identifier = "0x4d56b8ac0ed905936da10323328cba5def12957a2936920f043d8bf6a1e902d".as_bytes(); - - // Insert Block 3 storage changes for contract - // `0x4d56b8ac0ed905936da10323328cba5def12957a2936920f043d8bf6a1e902d` - let block_3 = [ - ( - "0x67c2665fbdd32ded72c0665f9658c05a5f9233c8de2002b3eba8ae046174efd", - "0x2221def5413ed3e128051d5dff3ec816dbfb9db4454b98f4aa47804cb7a13d2", - ), - ("0x5", "0x66"), - ( - "0x101c2b102c8eb6bf091f5debcf97d8edde85983e23f9778e9cabbe0b5a4f997", - "0x99a58a9612fe930f39c4c399b6be14e8bb7c8229d06eab8d0a3a97877a6667", - ), - ( - "0x1aabd3b2e12959bab2c4ab530c1d8f0e675e0dc5ab29d1f10b7f1a154cabef9", - "0x41d4ae0ba9013f2f6e1551b62a9c9187053727e0e65217be97eae8922d5b2df", - ), - ( - "0x1aabd3b2e12959bab2c4ab530c1d8f0e675e0dc5ab29d1f10b7f1a154cabefa", - "0x6eda96627bd3de7af5b4f932ff1e858bd396c897229d64b6dd3f0f936f0ea17", - ), - ]; - - for (key_hex, value_hex) in block_3.iter() { - let key: StarkFelt = Felt252Wrapper::from_hex_be(key_hex).unwrap().into(); - let value = Felt252Wrapper::from_hex_be(value_hex).unwrap(); - bonsai_storage - .insert(identifier, keyer(key).as_bitslice(), &value.into()) - .expect("Failed to insert storage update into trie"); - } - - let mut id_builder = BasicIdBuilder::new(); - let id = id_builder.new_id(); - bonsai_storage.commit(id).expect("Failed to commit to bonsai storage"); - let root_hash = bonsai_storage.root_hash(identifier).expect("Failed to get root hash"); - - println!( - "Expected: 0x0297DE74ABD178CAF7EA2F1AE1B4588CA7433B1B11A98172B6F56E3E02739FD0\nFound: {:?}", - Felt252Wrapper::from(root_hash) - ); - assert_eq!( - Felt252Wrapper::from(root_hash), - Felt252Wrapper::from_hex_be("0x0297DE74ABD178CAF7EA2F1AE1B4588CA7433B1B11A98172B6F56E3E02739FD0").unwrap() - ); - - // Insert Block 4 storage changes for contract - // `0x4d56b8ac0ed905936da10323328cba5def12957a2936920f043d8bf6a1e902d` - let block_4 = [ - ("0x3c14ddc99b06b00340bffd81ef1c4e10f74b800a911ee22c22bb28e4b516da5", "0x7e5"), - ("0x5", "0x64"), - ( - "0x5201dd2a5f567a653e9a2b7a62816919d0d695d1e2f39d516f9befda30da720", - "0x29ed6ea046ebe50aaacb9cd6477ac368644c8f4242ee0687d31f6c2ac20c146", - ), - ( - "0x5b3856459ac954d3fd24d85924d978263709880e3ee4cafdfe0b7c95ee6b26a", - "0x4c90411b3376d5230a88496e58acf58c19431d52b89f1ab91924075f4b35ac1", - ), - ( - "0x5b3856459ac954d3fd24d85924d978263709880e3ee4cafdfe0b7c95ee6b26b", - "0x72a56d83fab34872a880dd35d936117a084b928fb9d47306abb2558472633c", - ), - ("0x6a93bcb89fc1f31fa544377c7de6de1dd3e726e1951abc95c4984995e84ad0d", "0x7c7"), - ("0x6f8cf54aaec1f42d5f3868d597fcd7393da888264dc5a6e93c7bd528b6d6fee", "0x7c7"), - ("0x6b30a5f1341c0c949f847afe7f761a6ea8cdc3337baa20e68a2891f62389052", "0x7e5"), - ("0x6b3b4780013c33cdca6799e8aa3ef922b64f5a2d356573b33693d81504deccf", "0x7e5"), - ( - "0x6f649e057570e0f3cc710d260c2067297542f8e18407a7e75008808e12e6099", - "0x61395ebfa1746f9449711a7e361254ddb90f642861807b7e5e05276c11033ec", - ), - ( - "0x6f649e057570e0f3cc710d260c2067297542f8e18407a7e75008808e12e609a", - "0x304d0ec8cc0ea6faf0f7ad67903bcffc6bc4474d25f93e1c961b239370b8c07", - ), - ]; - - for (key_hex, value_hex) in block_4.iter() { - let key: StarkFelt = Felt252Wrapper::from_hex_be(key_hex).unwrap().into(); - let value = Felt252Wrapper::from_hex_be(value_hex).unwrap(); - bonsai_storage - .insert(identifier, keyer(key).as_bitslice(), &value.into()) - .expect("Failed to insert storage update into trie"); - } - - let id = id_builder.new_id(); - bonsai_storage.commit(id).expect("Failed to commit to bonsai storage"); - let root_hash = bonsai_storage.root_hash(identifier).expect("Failed to get root hash"); - - println!( - "Expected: 0x07A4CA1440AF3858CEB11386BA7E2A0FC553BB73E741043218845D820009BCCB\nFound: {:?}", - Felt252Wrapper::from(root_hash) - ); - assert_eq!( - Felt252Wrapper::from(root_hash), - Felt252Wrapper::from_hex_be("0x07A4CA1440AF3858CEB11386BA7E2A0FC553BB73E741043218845D820009BCCB").unwrap() - ); - - // Insert Block 5 storage changes for contract - // `0x4d56b8ac0ed905936da10323328cba5def12957a2936920f043d8bf6a1e902d` - let block_5 = [ - ("0x272cd29c23c7fd72ef13352ac037c6fabfee4c03056ea413c326be6501b4f31", "0x7c7"), - ("0x2bb6a7dd9cbb9cec8fdad9c0557bd539683f7ea65d4f14d41fe4d72311775e3", "0x7e5"), - ]; - - for (key_hex, value_hex) in block_5.iter() { - let key: StarkFelt = Felt252Wrapper::from_hex_be(key_hex).unwrap().into(); - let value = Felt252Wrapper::from_hex_be(value_hex).unwrap(); - bonsai_storage - .insert(identifier, keyer(key).as_bitslice(), &value.into()) - .expect("Failed to insert storage update into trie"); - } - - let id = id_builder.new_id(); - bonsai_storage.commit(id).expect("Failed to commit to bonsai storage"); - let root_hash = bonsai_storage.root_hash(identifier).expect("Failed to get root hash"); - - println!( - "Expected: 0x002363DCD04D065C6B50A4D46F930EBC91AC7F4B15DCF1B0A8D0165B0BA0F143\nFound: {:?}", - Felt252Wrapper::from(root_hash) - ); - assert_eq!( - Felt252Wrapper::from(root_hash), - Felt252Wrapper::from_hex_be("0x002363DCD04D065C6B50A4D46F930EBC91AC7F4B15DCF1B0A8D0165B0BA0F143").unwrap() - ); - - // Insert Block 6 storage changes for contract - // `0x4d56b8ac0ed905936da10323328cba5def12957a2936920f043d8bf6a1e902d` - let block_6 = [("0x5", "0x22b")]; - - for (key_hex, value_hex) in block_6.iter() { - let key: StarkFelt = Felt252Wrapper::from_hex_be(key_hex).unwrap().into(); - let value = Felt252Wrapper::from_hex_be(value_hex).unwrap(); - bonsai_storage - .insert(identifier, keyer(key).as_bitslice(), &value.into()) - .expect("Failed to insert storage update into trie"); - } - - let id = id_builder.new_id(); - bonsai_storage.commit(id).expect("Failed to commit to bonsai storage"); - let root_hash = bonsai_storage.root_hash(identifier).expect("Failed to get root hash"); - - println!( - "Expected: 0x00C656C01BB43291BEA976CEACE3AFE89A5621045E3B6F23E4BCFFFBB4B66832\nFound: {:?}", - Felt252Wrapper::from(root_hash) - ); - assert_eq!( - Felt252Wrapper::from(root_hash), - Felt252Wrapper::from_hex_be("0x00C656C01BB43291BEA976CEACE3AFE89A5621045E3B6F23E4BCFFFBB4B66832").unwrap() - ); - - // Insert Block 6 storage changes for contract - // `0x4d56b8ac0ed905936da10323328cba5def12957a2936920f043d8bf6a1e902d` - let block_7 = [("0x5", "0x0")]; - - for (key_hex, value_hex) in block_7.iter() { - let key: StarkFelt = Felt252Wrapper::from_hex_be(key_hex).unwrap().into(); - let value = Felt252Wrapper::from_hex_be(value_hex).unwrap(); - bonsai_storage - .insert(identifier, keyer(key).as_bitslice(), &value.into()) - .expect("Failed to insert storage update into trie"); - } - - let id = id_builder.new_id(); - bonsai_storage.commit(id).expect("Failed to commit to bonsai storage"); - let root_hash = bonsai_storage.root_hash(identifier).expect("Failed to get root hash"); - - println!( - "Expected: 0x032C61E78534A30DD005DB4B9136AA64893CC2F6E10C4535DD6F29BFB2ADC726\nFound: {:?}", - Felt252Wrapper::from(root_hash) - ); - assert_eq!( - Felt252Wrapper::from(root_hash), - Felt252Wrapper::from_hex_be("0x032C61E78534A30DD005DB4B9136AA64893CC2F6E10C4535DD6F29BFB2ADC726").unwrap() - ); - } - - #[test] - fn test_undefined_zero_2() { - let config = BonsaiStorageConfig::default(); - let bonsai_db = HashMapDb::::default(); - let mut bonsai_storage = - BonsaiStorage::<_, _, Pedersen>::new(bonsai_db, config).expect("Failed to create bonsai storage"); - let identifier = "0x421203c58e1b4a6c3675be26cfaa18d2b6b42695ca206be1f08ce29f7f1bc7c".as_bytes(); - - // Insert Block 5 storage changes for contract - // `0x421203c58e1b4a6c3675be26cfaa18d2b6b42695ca206be1f08ce29f7f1bc7c` - let block_5 = [ - ("0x2bb6a7dd9cbb9cec8fdad9c0557bd539683f7ea65d4f14d41fe4d72311775e3", "0x7c7"), - ( - "0x584d53558c6731da8923f60f2d182027312ffa4e811e7eddc6401232d33400e", - "0x29bc2bad472c81f00b7873d7d27a68d63dc9ebd3a3661e2b4c3d6c90d732454", - ), - ( - "0x6c27ff92eab8802ca5141a60a5699e5075725d5526752c5fb368c12582af00c", - "0x645a108cc9b963369b91cad8a8b5c2ce774b79e871368d301d518012925abc6", - ), - ("0x5", "0x66"), - ( - "0x744f7d93c67c2ac6fbcdf632d530cebdbffa112d0cfacce28ed5773babfba60", - "0x2a49283d206395239d0c1d505a8ba2f446419e58a1fd40caccf796e810759d5", - ), - ( - "0x11f391c712bb4996774106b93766bc49f8bdb29b416cae0da0d981752c1a28b", - "0x43f3925b460d387343381e31e2f9299100609bc833f289bfd67316a0a06ce40", - ), - ( - "0x11f391c712bb4996774106b93766bc49f8bdb29b416cae0da0d981752c1a28c", - "0x2b72713e2fc2dec7cfe8e7c428f02728a031f17f876bb50841d4ee3eb12834", - ), - ( - "0x66631ce6af4e11972e05bed46e9b20a5480ffea4ae2a4d95e1d71fb37f25c0", - "0x1329ffd6765c348b5e7195b777241cf5eb84e438c0f5fa3acb5800ada846332", - ), - ]; - - for (key_hex, value_hex) in block_5.iter() { - let key: StarkFelt = Felt252Wrapper::from_hex_be(key_hex).unwrap().into(); - let value = Felt252Wrapper::from_hex_be(value_hex).unwrap(); - bonsai_storage - .insert(identifier, keyer(key).as_bitslice(), &value.into()) - .expect("Failed to insert storage update into trie"); - } - - let mut id_builder = BasicIdBuilder::new(); - let id = id_builder.new_id(); - bonsai_storage.commit(id).expect("Failed to commit to bonsai storage"); - let root_hash = bonsai_storage.root_hash(identifier).expect("Failed to get root hash"); - - println!( - "Expected: 0x03846F4AE281ADBCC68518766579DB77C27EF31955E9FC3183C397C2731A7627\nFound: {:?}", - Felt252Wrapper::from(root_hash) - ); - assert_eq!( - Felt252Wrapper::from(root_hash), - Felt252Wrapper::from_hex_be("0x03846F4AE281ADBCC68518766579DB77C27EF31955E9FC3183C397C2731A7627").unwrap() - ); - - // Insert Block 6 storage changes for contract - // `0x421203c58e1b4a6c3675be26cfaa18d2b6b42695ca206be1f08ce29f7f1bc7c` - let block_6 = [ - ( - "0x591192c633e49a7e6ca0aae77da4e9a1df2c6db51cabb3cc929280a44745635", - "0x1b3479bec749469312a35a2001dc8cfaf38723c0a8763e01ad2abaefb2214e5", - ), - ( - "0x58bfc110ce09fc2bcff40dbb4887bfb32f5156f2195e8f6ea22e15784c01768", - "0x71cc8515287a6f5d8b81675bc7e41ca1fcd75afcc60984701033f0cdd05acd", - ), - ( - "0x58bfc110ce09fc2bcff40dbb4887bfb32f5156f2195e8f6ea22e15784c01769", - "0x6a8a49d797b80ef2be0ec8a72f71dccb655c07297f95e022a26a65787c3199c", - ), - ]; - - for (key_hex, value_hex) in block_6.iter() { - let key: StarkFelt = Felt252Wrapper::from_hex_be(key_hex).unwrap().into(); - let value = Felt252Wrapper::from_hex_be(value_hex).unwrap(); - bonsai_storage - .insert(identifier, keyer(key).as_bitslice(), &value.into()) - .expect("Failed to insert storage update into trie"); - } - - let id = id_builder.new_id(); - bonsai_storage.commit(id).expect("Failed to commit to bonsai storage"); - let root_hash = bonsai_storage.root_hash(identifier).expect("Failed to get root hash"); - - println!( - "Expected: 0x06E02FE529D3CBDCC5324D0981F991E777DAFC3F0C24E7CB56CE3D379BE9B510\nFound: {:?}", - Felt252Wrapper::from(root_hash) - ); - assert_eq!( - Felt252Wrapper::from(root_hash), - Felt252Wrapper::from_hex_be("0x06E02FE529D3CBDCC5324D0981F991E777DAFC3F0C24E7CB56CE3D379BE9B510").unwrap() - ); - - // Insert Block 6 storage changes for contract - // `0x421203c58e1b4a6c3675be26cfaa18d2b6b42695ca206be1f08ce29f7f1bc7c` - let block_7 = [("0x5", "0x0")]; - - for (key_hex, value_hex) in block_7.iter() { - let key: StarkFelt = Felt252Wrapper::from_hex_be(key_hex).unwrap().into(); - let value = Felt252Wrapper::from_hex_be(value_hex).unwrap(); - bonsai_storage - .insert(identifier, keyer(key).as_bitslice(), &value.into()) - .expect("Failed to insert storage update into trie"); +/// Retrieves the class hash and nonce of a contract address +/// +/// # Arguments +/// +/// * `csd` - Commitment state diff for the current block. +/// * `contract_address` - The contract address. +/// +/// # Returns +/// +/// The class hash and nonce of the contract address. +fn class_hash_and_nonce( + csd: &CommitmentStateDiff, + contract_address: &ContractAddress, +) -> Result<(FieldElement, FieldElement), DeoxysStorageError> { + let class_hash = csd.address_to_class_hash.get(contract_address); + let nonce = csd.address_to_nonce.get(contract_address); + + let (class_hash, nonce) = match (class_hash, nonce) { + (Some(class_hash), Some(nonce)) => (*class_hash, *nonce), + (Some(class_hash), None) => { + let nonce = storage_handler::contract_data().get_nonce(contract_address)?.unwrap_or_default(); + (*class_hash, nonce) } - - let id = id_builder.new_id(); - bonsai_storage.commit(id).expect("Failed to commit to bonsai storage"); - let root_hash = bonsai_storage.root_hash(identifier).expect("Failed to get root hash"); - - println!( - "Expected: 0x0528E360EA90E94F670451A76A7698900F0F7C1F2E88583F8B0162D486BF7947\nFound: {:?}", - Felt252Wrapper::from(root_hash) - ); - assert_eq!( - Felt252Wrapper::from(root_hash), - Felt252Wrapper::from_hex_be("0x0528E360EA90E94F670451A76A7698900F0F7C1F2E88583F8B0162D486BF7947").unwrap() - ); - } - - #[test] - fn test_block_9() { - let config = BonsaiStorageConfig::default(); - let bonsai_db = HashMapDb::::default(); - let mut bonsai_storage = - BonsaiStorage::<_, _, Pedersen>::new(bonsai_db, config).expect("Failed to create bonsai storage"); - let identifier = "0x06F3C934BA4EC49245CB9A42FC715E4D589AA502AF69BE13916127A538D525CE".as_bytes(); - - // Insert Block 8 storage changes for contract - // `0x06F3C934BA4EC49245CB9A42FC715E4D589AA502AF69BE13916127A538D525CE` - let block_8 = [ - ("0x5", "0x456"), - ( - "0x4b788ad12d2e47b2be358d61cc38d813aa79165ddbc0b29d4878ef0fbc18c15", - "0x612af3160e28962cb3dd6146a9c2f7bd7adeea1fddd39f767d936c7b5bcca97", - ), - ]; - - for (key_hex, value_hex) in block_8.iter() { - let key: StarkFelt = Felt252Wrapper::from_hex_be(key_hex).unwrap().into(); - let value = Felt252Wrapper::from_hex_be(value_hex).unwrap(); - bonsai_storage - .insert(identifier, keyer(key).as_bitslice(), &value.into()) - .expect("Failed to insert storage update into trie"); + (None, Some(nonce)) => { + let class_hash = storage_handler::contract_data().get_class_hash(contract_address)?.unwrap_or_default(); + (class_hash, *nonce) } - - let mut id_builder = BasicIdBuilder::new(); - let id = id_builder.new_id(); - bonsai_storage.commit(id).expect("Failed to commit to bonsai storage"); - let root_hash = bonsai_storage.root_hash(identifier).expect("Failed to get root hash"); - - println!( - "Expected: 0x010AA5D1D36847AE64BA074B3A878BFD1A9AEAA952F6777C727EEA6AE6B2C99F\nFound: {:?}", - Felt252Wrapper::from(root_hash) - ); - assert_eq!( - Felt252Wrapper::from(root_hash), - Felt252Wrapper::from_hex_be("0x010AA5D1D36847AE64BA074B3A878BFD1A9AEAA952F6777C727EEA6AE6B2C99F").unwrap() - ); - - // Insert Block 9 storage changes for contract - // `0x06F3C934BA4EC49245CB9A42FC715E4D589AA502AF69BE13916127A538D525CE` - let block_9 = [("0x5", "0x0")]; - - for (key_hex, value_hex) in block_9.iter() { - let key: StarkFelt = Felt252Wrapper::from_hex_be(key_hex).unwrap().into(); - let value = Felt252Wrapper::from_hex_be(value_hex).unwrap(); - bonsai_storage - .insert(identifier, keyer(key).as_bitslice(), &value.into()) - .expect("Failed to insert storage update into trie"); + (None, None) => { + let contract_data = storage_handler::contract_data().get(contract_address)?.unwrap_or_default(); + let nonce = contract_data.nonce.get().cloned().unwrap_or_default(); + let class_hash = contract_data.class_hash.get().cloned().unwrap_or_default(); + (class_hash, nonce) } - - let id = id_builder.new_id(); - bonsai_storage.commit(id).expect("Failed to commit to bonsai storage"); - let root_hash = bonsai_storage.root_hash(identifier).expect("Failed to get root hash"); - - println!( - "Expected: 0x00072F7E2EC1A2F05342503B49AECD83E14884AE374A8570F2F6F7B868CF94AE\nFound: {:?}", - Felt252Wrapper::from(root_hash) - ); - assert_eq!( - Felt252Wrapper::from(root_hash), - Felt252Wrapper::from_hex_be("0x00072F7E2EC1A2F05342503B49AECD83E14884AE374A8570F2F6F7B868CF94AE").unwrap() - ); - } + }; + Ok((FieldElement::from_bytes_be(&class_hash.0.0).unwrap(), FieldElement::from_bytes_be(&nonce.0.0).unwrap())) } diff --git a/crates/client/sync/src/commitments/lib.rs b/crates/client/sync/src/commitments/lib.rs index 3752b198f..02fa2673d 100644 --- a/crates/client/sync/src/commitments/lib.rs +++ b/crates/client/sync/src/commitments/lib.rs @@ -1,14 +1,9 @@ -use std::collections::HashSet; - use blockifier::state::cached_state::CommitmentStateDiff; use indexmap::IndexMap; -use mc_db::storage_handler::{self, DeoxysStorageError, StorageView}; use mp_convert::field_element::FromFieldElement; use mp_felt::Felt252Wrapper; -use mp_hashers::pedersen::PedersenHasher; use mp_hashers::poseidon::PoseidonHasher; use mp_hashers::HasherT; -use rayon::prelude::*; use starknet_api::core::{ClassHash, CompiledClassHash, ContractAddress, Nonce}; use starknet_api::hash::StarkFelt; use starknet_api::state::StorageKey; @@ -18,8 +13,9 @@ use starknet_core::types::{ StorageEntry, }; use starknet_ff::FieldElement; -use starknet_types_core::felt::Felt; +use super::classes::class_trie_root; +use super::contracts::contract_trie_root; use super::events::memory_event_commitment; use super::transactions::memory_transaction_commitment; @@ -35,7 +31,7 @@ use super::transactions::memory_transaction_commitment; /// # Returns /// /// The transaction and the event commitment as `Felt252Wrapper`. -pub fn calculate_commitments( +pub fn calculate_tx_and_event_commitments( transactions: &[Transaction], events: &[Event], chain_id: Felt252Wrapper, @@ -160,165 +156,3 @@ pub fn update_state_root(csd: CommitmentStateDiff, block_number: u64) -> Felt252 ); calculate_state_root::(contract_trie_root, class_trie_root) } - -/// Calculates the contract trie root -/// -/// # Arguments -/// -/// * `csd` - Commitment state diff for the current block. -/// * `bonsai_contract` - Bonsai db used to store contract hashes. -/// * `block_number` - The current block number. -/// -/// # Returns -/// -/// The contract root. -fn contract_trie_root(csd: &CommitmentStateDiff, block_number: u64) -> Result { - // NOTE: handlers implicitely acquire a lock on their respective tries - // for the duration of their livetimes - let mut handler_contract = storage_handler::contract_trie_mut(); - let mut handler_storage_trie = storage_handler::contract_storage_trie_mut(); - - // First we insert the contract storage changes - for (contract_address, updates) in csd.storage_updates.iter() { - handler_storage_trie.init(contract_address)?; - - for (key, value) in updates { - handler_storage_trie.insert(*contract_address, *key, *value)?; - } - } - - // Then we commit them - handler_storage_trie.commit(block_number)?; - - // We need to initialize the contract trie for each contract that has a class_hash or nonce update - // to retrieve the corresponding storage root - for contract_address in csd.address_to_class_hash.keys().chain(csd.address_to_nonce.keys()) { - if !csd.storage_updates.contains_key(contract_address) { - // Initialize the storage trie if this contract address does not have storage updates - handler_storage_trie.init(contract_address)?; - } - } - - // We need to calculate the contract_state_leaf_hash for each contract - // that not appear in the storage_updates but has a class_hash or nonce update - let all_contract_address: HashSet = csd - .storage_updates - .keys() - .chain(csd.address_to_class_hash.keys()) - .chain(csd.address_to_nonce.keys()) - .cloned() - .collect(); - - // Then we compute the leaf hashes retrieving the corresponding storage root - let updates = all_contract_address - .iter() - .par_bridge() - .map(|contract_address| { - let storage_root = handler_storage_trie.root(contract_address)?; - let leaf_hash = contract_state_leaf_hash(csd, contract_address, storage_root)?; - - Ok::<(&ContractAddress, Felt), DeoxysStorageError>((contract_address, leaf_hash)) - }) - .collect::, _>>()?; - - // then we compute the contract root by applying the changes so far - handler_contract.update(updates)?; - handler_contract.commit(block_number)?; - - Ok(handler_contract.root()?.into()) -} - -fn contract_state_leaf_hash( - csd: &CommitmentStateDiff, - contract_address: &ContractAddress, - storage_root: Felt, -) -> Result { - let (class_hash, nonce) = class_hash_and_nonce(csd, contract_address)?; - - let storage_root = FieldElement::from_bytes_be(&storage_root.to_bytes_be()).unwrap(); - - // computes the contract state leaf hash - let contract_state_hash = PedersenHasher::hash_elements(class_hash, storage_root); - let contract_state_hash = PedersenHasher::hash_elements(contract_state_hash, nonce); - let contract_state_hash = PedersenHasher::hash_elements(contract_state_hash, FieldElement::ZERO); - - Ok(Felt::from_bytes_be(&contract_state_hash.to_bytes_be())) -} - -fn class_hash_and_nonce( - csd: &CommitmentStateDiff, - contract_address: &ContractAddress, -) -> Result<(FieldElement, FieldElement), DeoxysStorageError> { - let class_hash = csd.address_to_class_hash.get(contract_address); - let nonce = csd.address_to_nonce.get(contract_address); - - let (class_hash, nonce) = match (class_hash, nonce) { - (Some(class_hash), Some(nonce)) => (*class_hash, *nonce), - (Some(class_hash), None) => { - let nonce = storage_handler::contract_data().get_nonce(contract_address)?.unwrap_or_default(); - (*class_hash, nonce) - } - (None, Some(nonce)) => { - let class_hash = storage_handler::contract_data().get_class_hash(contract_address)?.unwrap_or_default(); - (class_hash, *nonce) - } - (None, None) => { - let contract_data = storage_handler::contract_data().get(contract_address)?.unwrap_or_default(); - let nonce = contract_data.nonce.get().cloned().unwrap_or_default(); - let class_hash = contract_data.class_hash.get().cloned().unwrap_or_default(); - (class_hash, nonce) - } - }; - Ok((FieldElement::from_bytes_be(&class_hash.0.0).unwrap(), FieldElement::from_bytes_be(&nonce.0.0).unwrap())) -} - -// "CONTRACT_CLASS_LEAF_V0" -const CONTRACT_CLASS_HASH_VERSION: FieldElement = - FieldElement::from_mont([9331882290187415277, 12057587991035439952, 18444375821049509847, 115292049744600508]); - -/// Calculates the class trie root -/// -/// # Arguments -/// -/// * `csd` - Commitment state diff for the current block. -/// * `bonsai_class` - Bonsai db used to store class hashes. -/// * `block_number` - The current block number. -/// -/// # Returns -/// -/// The class root. -fn class_trie_root(csd: &CommitmentStateDiff, block_number: u64) -> Result { - let mut handler_class = storage_handler::class_trie_mut(); - - let updates = csd - .class_hash_to_compiled_class_hash - .iter() - .par_bridge() - .map(|(class_hash, compiled_class_hash)| { - let compiled_class_hash = FieldElement::from_bytes_be(&compiled_class_hash.0.0).unwrap(); - - let hash = PoseidonHasher::hash_elements(CONTRACT_CLASS_HASH_VERSION, compiled_class_hash); - - (class_hash, hash) - }) - .collect::>(); - - handler_class.init()?; - handler_class.update(updates)?; - handler_class.commit(block_number)?; - - Ok(handler_class.root()?.into()) -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_contract_class_hash_version() { - assert_eq!( - CONTRACT_CLASS_HASH_VERSION, - FieldElement::from_byte_slice_be("CONTRACT_CLASS_LEAF_V0".as_bytes()).unwrap(), - ); - } -} diff --git a/crates/client/sync/src/commitments/mod.rs b/crates/client/sync/src/commitments/mod.rs index e70eb5119..5d6c8bcc0 100644 --- a/crates/client/sync/src/commitments/mod.rs +++ b/crates/client/sync/src/commitments/mod.rs @@ -1,3 +1,5 @@ +pub mod classes; +pub mod contracts; pub mod events; pub mod lib; pub mod transactions; diff --git a/crates/client/sync/src/utils/convert.rs b/crates/client/sync/src/utils/convert.rs index 2bbe88daf..7e94653ce 100644 --- a/crates/client/sync/src/utils/convert.rs +++ b/crates/client/sync/src/utils/convert.rs @@ -22,7 +22,7 @@ use starknet_providers::sequencer::models::state_update::{ }; use starknet_providers::sequencer::models::{self as p, StateUpdate as StateUpdateProvider}; -use crate::commitments::lib::calculate_commitments; +use crate::commitments::lib::calculate_tx_and_event_commitments; use crate::l2::L2SyncError; use crate::utility; @@ -402,7 +402,8 @@ fn commitments( ) -> (StarkFelt, StarkFelt) { let chain_id = chain_id(); - let (commitment_tx, commitment_event) = calculate_commitments(transactions, events, chain_id, block_number); + let (commitment_tx, commitment_event) = + calculate_tx_and_event_commitments(transactions, events, chain_id, block_number); (commitment_tx.into(), commitment_event.into()) }