diff --git a/Cargo.toml b/Cargo.toml index 85e7393..1e5edd4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,11 +35,6 @@ rocksdb = { optional = true, version = "0.21.0", features = [ ] } [dev-dependencies] -mp-felt = { git = "https://github.com/keep-starknet-strange/madara.git", branch = "main", package = "mp-felt", features = [ - "parity-scale-codec", - "serde", -] } -mp-hashers = { git = "https://github.com/keep-starknet-strange/madara.git", branch = "main", package = "mp-hashers" } pathfinder-common = { git = "https://github.com/massalabs/pathfinder.git", package = "pathfinder-common", rev = "b7b6d76a76ab0e10f92e5f84ce099b5f727cb4db" } pathfinder-crypto = { git = "https://github.com/massalabs/pathfinder.git", package = "pathfinder-crypto", rev = "b7b6d76a76ab0e10f92e5f84ce099b5f727cb4db" } pathfinder-merkle-tree = { git = "https://github.com/massalabs/pathfinder.git", package = "pathfinder-merkle-tree", rev = "b7b6d76a76ab0e10f92e5f84ce099b5f727cb4db" } diff --git a/src/id.rs b/src/id.rs index a768b2c..763c86a 100644 --- a/src/id.rs +++ b/src/id.rs @@ -3,12 +3,12 @@ use alloc::vec::Vec; use core::{fmt::Debug, hash}; /// Trait to be implemented on any type that can be used as an ID. -pub trait Id: hash::Hash + PartialEq + Eq + PartialOrd + Ord + Debug + Copy { +pub trait Id: hash::Hash + PartialEq + Eq + PartialOrd + Ord + Debug + Copy + Default { fn to_bytes(&self) -> Vec; } /// A basic ID type that can be used for testing. -#[derive(Hash, PartialEq, Eq, PartialOrd, Ord, Debug, Clone, Copy)] +#[derive(Hash, PartialEq, Eq, PartialOrd, Ord, Debug, Clone, Copy, Default)] pub struct BasicId(u64); impl Id for BasicId { diff --git a/src/tests/simple.rs b/src/tests/simple.rs index e8c238a..d235c2e 100644 --- a/src/tests/simple.rs +++ b/src/tests/simple.rs @@ -1,10 +1,10 @@ #![cfg(feature = "std")] use crate::{ - databases::{create_rocks_db, RocksDB, RocksDBConfig}, - id::BasicIdBuilder, + databases::{create_rocks_db, HashMapDb, RocksDB, RocksDBConfig}, + id::{BasicId, BasicIdBuilder}, BonsaiStorage, BonsaiStorageConfig, Change, }; -use bitvec::vec::BitVec; +use bitvec::{vec::BitVec, view::BitView}; use starknet_types_core::{felt::Felt, hash::Pedersen}; #[test] @@ -53,6 +53,229 @@ fn basics() { ); } +#[test] +fn root_hash_similar_rocks_db() { + let root_hash_1 = { + let tempdir = tempfile::tempdir().unwrap(); + let db = create_rocks_db(tempdir.path()).unwrap(); + let config = BonsaiStorageConfig::default(); + let mut bonsai_storage: BonsaiStorage<_, _, Pedersen> = + BonsaiStorage::new(RocksDB::new(&db, RocksDBConfig::default()), config).unwrap(); + let mut id_builder = BasicIdBuilder::new(); + let pair1 = ( + vec![1, 2, 1], + Felt::from_hex("0x2acf9d2ae5a475818075672b04e317e9da3d5180fed2c5f8d6d8a5fd5a92257") + .unwrap(), + ); + let bitvec = BitVec::from_vec(pair1.0.clone()); + bonsai_storage.insert(&bitvec, &pair1.1).unwrap(); + let pair2 = ( + vec![1, 2, 2], + Felt::from_hex("0x100bd6fbfced88ded1b34bd1a55b747ce3a9fde9a914bca75571e4496b56443") + .unwrap(), + ); + let bitvec = BitVec::from_vec(pair2.0.clone()); + bonsai_storage.insert(&bitvec, &pair2.1).unwrap(); + bonsai_storage.commit(id_builder.new_id()).unwrap(); + let pair3 = ( + vec![1, 2, 3], + Felt::from_hex("0x00a038cda302fedbc4f6117648c6d3faca3cda924cb9c517b46232c6316b152f") + .unwrap(), + ); + let bitvec = BitVec::from_vec(pair3.0.clone()); + bonsai_storage.insert(&bitvec, &pair3.1).unwrap(); + let pair4 = ( + vec![1, 2, 4], + Felt::from_hex("0x02808c7d8f3745e55655ad3f51f096d0c06a41f3d76caf96bad80f9be9ced171") + .unwrap(), + ); + let bitvec = BitVec::from_vec(pair4.0.clone()); + bonsai_storage.insert(&bitvec, &pair4.1).unwrap(); + bonsai_storage.commit(id_builder.new_id()).unwrap(); + bonsai_storage.root_hash().unwrap() + }; + let root_hash_2 = { + let tempdir = tempfile::tempdir().unwrap(); + let db = create_rocks_db(tempdir.path()).unwrap(); + let config = BonsaiStorageConfig::default(); + let mut bonsai_storage: BonsaiStorage<_, _, Pedersen> = + BonsaiStorage::new(RocksDB::new(&db, RocksDBConfig::default()), config).unwrap(); + let mut id_builder = BasicIdBuilder::new(); + let pair1 = ( + vec![1, 2, 3], + Felt::from_hex("0x00a038cda302fedbc4f6117648c6d3faca3cda924cb9c517b46232c6316b152f") + .unwrap(), + ); + let bitvec = BitVec::from_vec(pair1.0.clone()); + bonsai_storage.insert(&bitvec, &pair1.1).unwrap(); + let pair2 = ( + vec![1, 2, 4], + Felt::from_hex("0x02808c7d8f3745e55655ad3f51f096d0c06a41f3d76caf96bad80f9be9ced171") + .unwrap(), + ); + let bitvec = BitVec::from_vec(pair2.0.clone()); + bonsai_storage.insert(&bitvec, &pair2.1).unwrap(); + bonsai_storage.commit(id_builder.new_id()).unwrap(); + bonsai_storage.root_hash().unwrap() + }; + println!("root_hash_1: {:?}", root_hash_1.to_string()); + println!("root_hash_2: {:?}", root_hash_2.to_string()); + assert_ne!(root_hash_1, root_hash_2); +} + +#[test] +fn starknet_specific() { + struct ContractState { + address: &'static str, + state_hash: &'static str, + } + + let tempdir1 = tempfile::tempdir().unwrap(); + let db1 = create_rocks_db(tempdir1.path()).unwrap(); + let config1 = BonsaiStorageConfig::default(); + let mut bonsai_storage1: BonsaiStorage<_, _, Pedersen> = + BonsaiStorage::new(RocksDB::new(&db1, RocksDBConfig::default()), config1).unwrap(); + + let tempdir2 = tempfile::tempdir().unwrap(); + let db2 = create_rocks_db(tempdir2.path()).unwrap(); + let config2 = BonsaiStorageConfig::default(); + let mut bonsai_storage2: BonsaiStorage<_, _, Pedersen> = + BonsaiStorage::new(RocksDB::new(&db2, RocksDBConfig::default()), config2).unwrap(); + let mut id_builder = BasicIdBuilder::new(); + + let contract_states = vec![ + ContractState { + address: "0x020cfa74ee3564b4cd5435cdace0f9c4d43b939620e4a0bb5076105df0a626c6", + state_hash: "0x3a1606fc1a168e11bc31605aa32265a1a887c185feebb255a56bcac189fd5b6", + }, + ContractState { + address: "0x06ee3440b08a9c805305449ec7f7003f27e9f7e287b83610952ec36bdc5a6bae", + state_hash: "0x4fc78cbac87f833e56c91dfd6eda5be3362204d86d24f1e1e81577d509f963b", + }, + ]; + + for contract_state in contract_states { + let key = contract_state.address; + let value = contract_state.state_hash; + let key = Felt::from_hex(key).unwrap().to_bytes_be().view_bits()[5..].to_bitvec(); + let value = Felt::from_hex(value).unwrap(); + bonsai_storage1 + .insert(&key, &value) + .expect("Failed to insert storage update into trie"); + bonsai_storage2 + .insert(&key, &value) + .expect("Failed to insert storage update into trie"); + } + + let id = id_builder.new_id(); + bonsai_storage1 + .commit(id) + .expect("Failed to commit to bonsai storage"); + + let contract_states = vec![ContractState { + address: "0x06538fdd3aa353af8a87f5fe77d1f533ea82815076e30a86d65b72d3eb4f0b80", + state_hash: "0x2acf9d2ae5a475818075672b04e317e9da3d5180fed2c5f8d6d8a5fd5a92257", + }]; + + for contract_state in contract_states { + let key = contract_state.address; + let value = contract_state.state_hash; + let key = Felt::from_hex(key).unwrap().to_bytes_be().view_bits()[5..].to_bitvec(); + let value = Felt::from_hex(value).unwrap(); + + bonsai_storage1 + .insert(&key, &value) + .expect("Failed to insert storage update into trie"); + bonsai_storage2 + .insert(&key, &value) + .expect("Failed to insert storage update into trie"); + } + + let id = id_builder.new_id(); + bonsai_storage1 + .commit(id) + .expect("Failed to commit to bonsai storage"); + let root_hash1 = bonsai_storage1 + .root_hash() + .expect("Failed to get root hash"); + + bonsai_storage2 + .commit(id) + .expect("Failed to commit to bonsai storage"); + let root_hash2 = bonsai_storage2 + .root_hash() + .expect("Failed to get root hash"); + assert_eq!(root_hash1, root_hash2); +} + +#[test] +fn root_hash_similar_hashmap_db() { + let root_hash_1 = { + let db = HashMapDb::::default(); + let config = BonsaiStorageConfig::default(); + let mut bonsai_storage: BonsaiStorage<_, _, Pedersen> = + BonsaiStorage::new(db, config).unwrap(); + let mut id_builder = BasicIdBuilder::new(); + let pair1 = ( + vec![1, 2, 1], + Felt::from_hex("0x2acf9d2ae5a475818075672b04e317e9da3d5180fed2c5f8d6d8a5fd5a92257") + .unwrap(), + ); + let bitvec = BitVec::from_vec(pair1.0.clone()); + bonsai_storage.insert(&bitvec, &pair1.1).unwrap(); + let pair2 = ( + vec![1, 2, 2], + Felt::from_hex("0x100bd6fbfced88ded1b34bd1a55b747ce3a9fde9a914bca75571e4496b56443") + .unwrap(), + ); + let bitvec = BitVec::from_vec(pair2.0.clone()); + bonsai_storage.insert(&bitvec, &pair2.1).unwrap(); + bonsai_storage.commit(id_builder.new_id()).unwrap(); + let pair3 = ( + vec![1, 2, 3], + Felt::from_hex("0x00a038cda302fedbc4f6117648c6d3faca3cda924cb9c517b46232c6316b152f") + .unwrap(), + ); + let bitvec = BitVec::from_vec(pair3.0.clone()); + bonsai_storage.insert(&bitvec, &pair3.1).unwrap(); + let pair4 = ( + vec![1, 2, 4], + Felt::from_hex("0x02808c7d8f3745e55655ad3f51f096d0c06a41f3d76caf96bad80f9be9ced171") + .unwrap(), + ); + let bitvec = BitVec::from_vec(pair4.0.clone()); + bonsai_storage.insert(&bitvec, &pair4.1).unwrap(); + bonsai_storage.commit(id_builder.new_id()).unwrap(); + bonsai_storage.root_hash().unwrap() + }; + let root_hash_2 = { + let db = HashMapDb::::default(); + let config = BonsaiStorageConfig::default(); + let mut bonsai_storage: BonsaiStorage<_, _, Pedersen> = + BonsaiStorage::new(db, config).unwrap(); + let mut id_builder = BasicIdBuilder::new(); + let pair1 = ( + vec![1, 2, 3], + Felt::from_hex("0x00a038cda302fedbc4f6117648c6d3faca3cda924cb9c517b46232c6316b152f") + .unwrap(), + ); + let bitvec = BitVec::from_vec(pair1.0.clone()); + bonsai_storage.insert(&bitvec, &pair1.1).unwrap(); + let pair2 = ( + vec![1, 2, 4], + Felt::from_hex("0x02808c7d8f3745e55655ad3f51f096d0c06a41f3d76caf96bad80f9be9ced171") + .unwrap(), + ); + let bitvec = BitVec::from_vec(pair2.0.clone()); + bonsai_storage.insert(&bitvec, &pair2.1).unwrap(); + bonsai_storage.commit(id_builder.new_id()).unwrap(); + bonsai_storage.root_hash().unwrap() + }; + println!("root_hash_1: {:?}", root_hash_1.to_string()); + println!("root_hash_2: {:?}", root_hash_2.to_string()); + assert_ne!(root_hash_1, root_hash_2); +} + #[test] fn get_changes() { let tempdir = tempfile::tempdir().unwrap(); diff --git a/src/trie/merkle_tree.rs b/src/trie/merkle_tree.rs index 0cd861d..6c23b1e 100644 --- a/src/trie/merkle_tree.rs +++ b/src/trie/merkle_tree.rs @@ -225,7 +225,11 @@ impl MerkleTree { binary.hash = Some(hash); binary.left = NodeHandle::Hash(left_hash); binary.right = NodeHandle::Hash(right_hash); - let key_bytes = [&[path.0.len() as u8], path.0.as_raw_slice()].concat(); + let key_bytes = if path.0.is_empty() { + vec![] + } else { + [&[path.0.len() as u8], path.0.as_raw_slice()].concat() + }; self.db.insert( &TrieKey::Trie(key_bytes), &Node::Binary(binary).encode(),