diff --git a/crates/merkle-tree/src/class.rs b/crates/merkle-tree/src/class.rs index 83ca0360ff..4153bb8f67 100644 --- a/crates/merkle-tree/src/class.rs +++ b/crates/merkle-tree/src/class.rs @@ -8,6 +8,7 @@ use pathfinder_common::{ SierraHash, }; use pathfinder_crypto::Felt; +use pathfinder_storage::storage_index::TrieStorageIndex; use pathfinder_storage::{Transaction, TrieUpdate}; use crate::tree::{GetProofError, MerkleTree, TrieNodeWithHash}; @@ -78,14 +79,14 @@ impl<'tx> ClassCommitmentTree<'tx> { tx: &'tx Transaction<'tx>, block: BlockNumber, class_hash: ClassHash, - root: u64, + root: TrieStorageIndex, ) -> Result, GetProofError> { let storage = ClassStorage { tx, block: Some(block), }; - MerkleTree::::get_proof(root, &storage, class_hash.0.view_bits()) + MerkleTree::::get_proof(root.get(), &storage, class_hash.0.view_bits()) } /// Generates proofs for the given list of `class_hashes`. See @@ -118,12 +119,12 @@ struct ClassStorage<'tx> { } impl crate::storage::Storage for ClassStorage<'_> { - fn get(&self, index: u64) -> anyhow::Result> { - self.tx.class_trie_node(index) + fn get(&self, index: TrieStorageIndex) -> anyhow::Result> { + self.tx.class_trie_node(index.get()) } - fn hash(&self, index: u64) -> anyhow::Result> { - self.tx.class_trie_node_hash(index) + fn hash(&self, index: TrieStorageIndex) -> anyhow::Result> { + self.tx.class_trie_node_hash(index.get()) } fn leaf( diff --git a/crates/merkle-tree/src/contract.rs b/crates/merkle-tree/src/contract.rs index 418827c2cb..2f0fc75bc2 100644 --- a/crates/merkle-tree/src/contract.rs +++ b/crates/merkle-tree/src/contract.rs @@ -20,6 +20,7 @@ use pathfinder_common::{ StorageValue, }; use pathfinder_crypto::Felt; +use pathfinder_storage::storage_index::TrieStorageIndex; use pathfinder_storage::{Transaction, TrieUpdate}; use crate::merkle_node::InternalNode; @@ -230,7 +231,7 @@ impl<'tx> StorageCommitmentTree<'tx> { tx: &'tx Transaction<'tx>, block: BlockNumber, addresses: &[ContractAddress], - root: u64, + root: TrieStorageIndex, ) -> Result>, GetProofError> { let storage = StorageTrieStorage { tx, @@ -242,7 +243,7 @@ impl<'tx> StorageCommitmentTree<'tx> { .map(|addr| addr.0.view_bits()) .collect::>(); - MerkleTree::::get_proofs(root, &storage, &keys) + MerkleTree::::get_proofs(root.get(), &storage, &keys) } /// See [`MerkleTree::dfs`] @@ -261,12 +262,12 @@ struct ContractStorage<'tx> { } impl crate::storage::Storage for ContractStorage<'_> { - fn get(&self, index: u64) -> anyhow::Result> { - self.tx.contract_trie_node(index) + fn get(&self, index: TrieStorageIndex) -> anyhow::Result> { + self.tx.contract_trie_node(index.get()) } - fn hash(&self, index: u64) -> anyhow::Result> { - self.tx.contract_trie_node_hash(index) + fn hash(&self, index: TrieStorageIndex) -> anyhow::Result> { + self.tx.contract_trie_node_hash(index.get()) } fn leaf(&self, path: &BitSlice) -> anyhow::Result> { @@ -294,12 +295,12 @@ struct StorageTrieStorage<'tx> { } impl crate::storage::Storage for StorageTrieStorage<'_> { - fn get(&self, index: u64) -> anyhow::Result> { - self.tx.storage_trie_node(index) + fn get(&self, index: TrieStorageIndex) -> anyhow::Result> { + self.tx.storage_trie_node(index.get()) } - fn hash(&self, index: u64) -> anyhow::Result> { - self.tx.storage_trie_node_hash(index) + fn hash(&self, index: TrieStorageIndex) -> anyhow::Result> { + self.tx.storage_trie_node_hash(index.get()) } fn leaf(&self, path: &BitSlice) -> anyhow::Result> { diff --git a/crates/merkle-tree/src/merkle_node.rs b/crates/merkle-tree/src/merkle_node.rs index b162208bff..b6aa5ece77 100644 --- a/crates/merkle-tree/src/merkle_node.rs +++ b/crates/merkle-tree/src/merkle_node.rs @@ -12,6 +12,7 @@ use bitvec::prelude::BitVec; use bitvec::slice::BitSlice; use pathfinder_common::hash::FeltHash; use pathfinder_crypto::Felt; +use pathfinder_storage::storage_index::TrieStorageIndex; /// A node in a Binary Merkle-Patricia Tree graph. #[derive(Clone, Debug, PartialEq)] @@ -19,7 +20,7 @@ pub enum InternalNode { /// A node that has not been fetched from storage yet. /// /// As such, all we know is its index. - Unresolved(u64), + Unresolved(TrieStorageIndex), /// A branch node with exactly two children. Binary(BinaryNode), /// Describes a path connecting two other nodes. @@ -32,7 +33,7 @@ pub enum InternalNode { #[derive(Clone, Debug, PartialEq)] pub struct BinaryNode { /// The storage index of this node (if it was loaded from storage). - pub storage_index: Option, + pub storage_index: Option, /// The height of this node in the tree. pub height: usize, /// [Left](Direction::Left) child. @@ -44,7 +45,7 @@ pub struct BinaryNode { #[derive(Clone, Debug, PartialEq)] pub struct EdgeNode { /// The storage index of this node (if it was loaded from storage). - pub storage_index: Option, + pub storage_index: Option, /// The starting height of this node in the tree. pub height: usize, /// The path this edge takes. @@ -144,9 +145,11 @@ impl InternalNode { matches!(self, InternalNode::Leaf) } - pub fn storage_index(&self) -> Option { + pub fn storage_index(&self) -> Option { match self { - InternalNode::Unresolved(storage_index) => Some(*storage_index), + InternalNode::Unresolved(storage_index) => { + Some(TrieStorageIndex::new(storage_index.get())) + } InternalNode::Binary(binary) => binary.storage_index, InternalNode::Edge(edge) => edge.storage_index, InternalNode::Leaf => None, @@ -231,8 +234,12 @@ mod tests { let uut = BinaryNode { storage_index: None, height: 1, - left: Rc::new(RefCell::new(InternalNode::Unresolved(1))), - right: Rc::new(RefCell::new(InternalNode::Unresolved(2))), + left: Rc::new(RefCell::new(InternalNode::Unresolved( + TrieStorageIndex::new(1), + ))), + right: Rc::new(RefCell::new(InternalNode::Unresolved( + TrieStorageIndex::new(2), + ))), }; let mut zero_key = bitvec![u8, Msb0; 1; 251]; @@ -250,8 +257,12 @@ mod tests { #[test] fn get_child() { - let left = Rc::new(RefCell::new(InternalNode::Unresolved(1))); - let right = Rc::new(RefCell::new(InternalNode::Unresolved(2))); + let left = Rc::new(RefCell::new(InternalNode::Unresolved( + TrieStorageIndex::new(1), + ))); + let right = Rc::new(RefCell::new(InternalNode::Unresolved( + TrieStorageIndex::new(2), + ))); let uut = BinaryNode { storage_index: None, @@ -319,7 +330,9 @@ mod tests { #[test] fn full() { let key = felt!("0x123456789abcdef"); - let child = Rc::new(RefCell::new(InternalNode::Unresolved(1))); + let child = Rc::new(RefCell::new(InternalNode::Unresolved( + TrieStorageIndex::new(1), + ))); let uut = EdgeNode { storage_index: None, @@ -334,7 +347,9 @@ mod tests { #[test] fn prefix() { let key = felt!("0x123456789abcdef"); - let child = Rc::new(RefCell::new(InternalNode::Unresolved(1))); + let child = Rc::new(RefCell::new(InternalNode::Unresolved( + TrieStorageIndex::new(1), + ))); let path = key.view_bits()[..45].to_bitvec(); @@ -351,7 +366,9 @@ mod tests { #[test] fn suffix() { let key = felt!("0x123456789abcdef"); - let child = Rc::new(RefCell::new(InternalNode::Unresolved(1))); + let child = Rc::new(RefCell::new(InternalNode::Unresolved( + TrieStorageIndex::new(1), + ))); let path = key.view_bits()[50..].to_bitvec(); @@ -368,7 +385,9 @@ mod tests { #[test] fn middle_slice() { let key = felt!("0x123456789abcdef"); - let child = Rc::new(RefCell::new(InternalNode::Unresolved(1))); + let child = Rc::new(RefCell::new(InternalNode::Unresolved( + TrieStorageIndex::new(1), + ))); let path = key.view_bits()[230..235].to_bitvec(); diff --git a/crates/merkle-tree/src/storage.rs b/crates/merkle-tree/src/storage.rs index cc7938c3a5..34cc45d943 100644 --- a/crates/merkle-tree/src/storage.rs +++ b/crates/merkle-tree/src/storage.rs @@ -1,13 +1,13 @@ use bitvec::prelude::*; use pathfinder_crypto::Felt; -use pathfinder_storage::StoredNode; +use pathfinder_storage::{storage_index::TrieStorageIndex, StoredNode}; /// Read-only storage used by the [Merkle tree](crate::tree::MerkleTree). pub trait Storage { /// Returns the node stored at the given index. - fn get(&self, index: u64) -> anyhow::Result>; + fn get(&self, index: TrieStorageIndex) -> anyhow::Result>; /// Returns the hash of the node at the given index. - fn hash(&self, index: u64) -> anyhow::Result>; + fn hash(&self, index: TrieStorageIndex) -> anyhow::Result>; /// Returns the value of the leaf at the given path. fn leaf(&self, path: &BitSlice) -> anyhow::Result>; } diff --git a/crates/merkle-tree/src/transaction.rs b/crates/merkle-tree/src/transaction.rs index a3c091b14a..59bfc876fd 100644 --- a/crates/merkle-tree/src/transaction.rs +++ b/crates/merkle-tree/src/transaction.rs @@ -1,7 +1,7 @@ use bitvec::view::BitView; use pathfinder_common::hash::FeltHash; use pathfinder_crypto::Felt; -use pathfinder_storage::StoredNode; +use pathfinder_storage::{storage_index::TrieStorageIndex, StoredNode}; use crate::tree::MerkleTree; @@ -30,11 +30,11 @@ impl Default for TransactionOrEventTree { struct NullStorage; impl crate::storage::Storage for NullStorage { - fn get(&self, _: u64) -> anyhow::Result> { + fn get(&self, _: TrieStorageIndex) -> anyhow::Result> { Ok(None) } - fn hash(&self, _: u64) -> anyhow::Result> { + fn hash(&self, _: TrieStorageIndex) -> anyhow::Result> { Ok(None) } diff --git a/crates/merkle-tree/src/tree.rs b/crates/merkle-tree/src/tree.rs index ead526b83a..7bf947e741 100644 --- a/crates/merkle-tree/src/tree.rs +++ b/crates/merkle-tree/src/tree.rs @@ -61,6 +61,7 @@ use bitvec::prelude::{BitSlice, BitVec, Msb0}; use pathfinder_common::hash::FeltHash; use pathfinder_common::trie::TrieNode; use pathfinder_crypto::Felt; +use pathfinder_storage::storage_index::TrieStorageIndex; use pathfinder_storage::{Node, NodeRef, StoredNode, TrieUpdate}; use crate::merkle_node::{BinaryNode, Direction, EdgeNode, InternalNode}; @@ -71,7 +72,7 @@ use crate::storage::Storage; pub struct MerkleTree { root: Option>>, leaves: HashMap, Felt>, - nodes_removed: Vec, + nodes_removed: Vec, _hasher: std::marker::PhantomData, /// If enables, node hashes are verified as they are resolved. This allows /// testing for database corruption. @@ -79,7 +80,7 @@ pub struct MerkleTree { } impl MerkleTree { - pub fn new(root: u64) -> Self { + pub fn new(root: TrieStorageIndex) -> Self { let root = Some(Rc::new(RefCell::new(InternalNode::Unresolved(root)))); Self { root, @@ -136,11 +137,11 @@ impl MerkleTree { Felt::ZERO }; - removed.extend(self.nodes_removed); + removed.extend(self.nodes_removed.iter().map(|value| value.get())); Ok(TrieUpdate { nodes_added: added, - nodes_removed: removed, + nodes_removed: removed.into_iter().map(TrieStorageIndex::new).collect(), root_commitment: root_hash, }) } @@ -168,7 +169,7 @@ impl MerkleTree { .hash(*idx) .context("Fetching stored node's hash")? .context("Stored node's hash is missing")?; - (hash, Some(NodeRef::StorageIndex(*idx))) + (hash, Some(NodeRef::TrieStorageIndex(idx.get()))) } InternalNode::Leaf => { let hash = if let Some(value) = self.leaves.get(&path) { @@ -214,7 +215,7 @@ impl MerkleTree { }; if let Some(storage_index) = binary.storage_index { - removed.push(storage_index); + removed.push(storage_index.get()); }; let node_index = added.len(); @@ -247,7 +248,7 @@ impl MerkleTree { let node_index = added.len(); added.push((hash, persisted_node)); if let Some(storage_index) = edge.storage_index { - removed.push(storage_index); + removed.push(storage_index.get()); }; (hash, Some(NodeRef::Index(node_index))) @@ -438,7 +439,7 @@ impl MerkleTree { InternalNode::Binary(_) => false, _ => { if let Some(index) = node.storage_index() { - indexes_removed.push(index); + indexes_removed.push(index.get()); }; true } @@ -478,7 +479,11 @@ impl MerkleTree { // We reached the root without a hitting binary node. The new tree // must therefore be empty. self.root = None; - self.nodes_removed.extend(indexes_removed); + self.nodes_removed.extend( + indexes_removed + .iter() + .map(|value| TrieStorageIndex::new(*value)), + ); return Ok(()); } }; @@ -492,7 +497,11 @@ impl MerkleTree { } // All nodes below the binary node were deleted - self.nodes_removed.extend(indexes_removed); + self.nodes_removed.extend( + indexes_removed + .iter() + .map(|value| TrieStorageIndex::new(*value)), + ); Ok(()) } @@ -566,7 +575,7 @@ impl MerkleTree { let node = match node_cache.get(&index) { Some(node) => node.clone(), None => { - let Some(node) = storage.get(index).context("Resolving node")? else { + let Some(node) = storage.get(TrieStorageIndex::new(index)).context("Resolving node")? else { return Err(GetProofError::StorageNodeMissing(index)); }; node_cache.insert(index, node.clone()); @@ -578,8 +587,8 @@ impl MerkleTree { StoredNode::Binary { left, right } => { // Choose the direction to go in. next = match key.get(height).map(|b| Direction::from(*b)) { - Some(Direction::Left) => Some(left), - Some(Direction::Right) => Some(right), + Some(Direction::Left) => Some(left.get()), + Some(Direction::Right) => Some(right.get()), None => { return Err( anyhow::anyhow!("Key path too short for binary node").into() @@ -608,7 +617,7 @@ impl MerkleTree { // If the path matches then we continue otherwise the proof is complete. if key == path { - next = Some(child); + next = Some(child.get()); } let child = storage @@ -652,7 +661,7 @@ impl MerkleTree { Some(&hash) => hash, None => { let hash = storage - .hash(index) + .hash(TrieStorageIndex::new(index)) .context("Querying node hash")? .context("Node hash is missing")?; node_hash_cache.insert(index, hash); @@ -699,7 +708,7 @@ impl MerkleTree { let next = match current_tmp { Unresolved(idx) => { - let node = self.resolve(storage, idx, height)?; + let node = self.resolve(storage, idx.get(), height)?; current.replace(node); current } @@ -742,30 +751,30 @@ impl MerkleTree { ); let node = storage - .get(index)? + .get(TrieStorageIndex::new(index))? .with_context(|| format!("Node {index} at height {height} is missing"))?; let node = match node { StoredNode::Binary { left, right } => InternalNode::Binary(BinaryNode { - storage_index: Some(index), + storage_index: Some(TrieStorageIndex::new(index)), height, left: Rc::new(RefCell::new(InternalNode::Unresolved(left))), right: Rc::new(RefCell::new(InternalNode::Unresolved(right))), }), StoredNode::Edge { child, path } => InternalNode::Edge(EdgeNode { - storage_index: Some(index), + storage_index: Some(TrieStorageIndex::new(index)), height, path, child: Rc::new(RefCell::new(InternalNode::Unresolved(child))), }), StoredNode::LeafBinary => InternalNode::Binary(BinaryNode { - storage_index: Some(index), + storage_index: Some(TrieStorageIndex::new(index)), height, left: Rc::new(RefCell::new(InternalNode::Leaf)), right: Rc::new(RefCell::new(InternalNode::Leaf)), }), StoredNode::LeafEdge { path } => InternalNode::Edge(EdgeNode { - storage_index: Some(index), + storage_index: Some(TrieStorageIndex::new(index)), height, path, child: Rc::new(RefCell::new(InternalNode::Leaf)), @@ -786,7 +795,7 @@ impl MerkleTree { fn merge_edges(&mut self, storage: &impl Storage, parent: &mut EdgeNode) -> anyhow::Result<()> { let resolved_child = match &*parent.child.borrow() { InternalNode::Unresolved(hash) => { - self.resolve(storage, *hash, parent.height + parent.path.len())? + self.resolve(storage, hash.get(), parent.height + parent.path.len())? } other => other.clone(), }; @@ -894,7 +903,7 @@ impl MerkleTree { visiting.push(VisitedNode { node: Rc::new(RefCell::new(self.resolve( storage, - *idx, + idx.get(), path.len(), )?)), path, @@ -958,12 +967,12 @@ mod tests { } impl Storage for TestStorage { - fn get(&self, index: u64) -> anyhow::Result> { - Ok(self.nodes.get(&index).map(|x| x.1.clone())) + fn get(&self, index: TrieStorageIndex) -> anyhow::Result> { + Ok(self.nodes.get(&index.get()).map(|x| x.1.clone())) } - fn hash(&self, index: u64) -> anyhow::Result> { - Ok(self.nodes.get(&index).map(|x| x.0)) + fn hash(&self, index: TrieStorageIndex) -> anyhow::Result> { + Ok(self.nodes.get(&index.get()).map(|x| x.0)) } fn leaf(&self, path: &BitSlice) -> anyhow::Result> { @@ -1004,7 +1013,7 @@ mod tests { if prune_nodes { for idx in update.nodes_removed { - storage.nodes.remove(&idx); + storage.nodes.remove(&idx.get()); } } @@ -1014,24 +1023,30 @@ mod tests { let node = match node { Node::Binary { left, right } => { let left = match left { - NodeRef::StorageIndex(idx) => idx, + NodeRef::TrieStorageIndex(idx) => idx, NodeRef::Index(idx) => storage.next_index + (idx as u64), }; let right = match right { - NodeRef::StorageIndex(idx) => idx, + NodeRef::TrieStorageIndex(idx) => idx, NodeRef::Index(idx) => storage.next_index + (idx as u64), }; - StoredNode::Binary { left, right } + StoredNode::Binary { + left: TrieStorageIndex::new(left), + right: TrieStorageIndex::new(right), + } } Node::Edge { child, path } => { let child = match child { - NodeRef::StorageIndex(idx) => idx, + NodeRef::TrieStorageIndex(idx) => idx, NodeRef::Index(idx) => storage.next_index + (idx as u64), }; - StoredNode::Edge { child, path } + StoredNode::Edge { + child: TrieStorageIndex::new(child), + path, + } } Node::LeafBinary => StoredNode::LeafBinary, Node::LeafEdge { path } => StoredNode::LeafEdge { path }, @@ -1369,7 +1384,7 @@ mod tests { ); assert_eq!(storage.nodes.len(), 1); - let tree = TestTree::new(root.1); + let tree = TestTree::new(TrieStorageIndex::new(root.1)); let root = commit_and_persist_without_pruning(tree, &mut storage); assert_eq!( root.0, @@ -1392,7 +1407,7 @@ mod tests { ); assert_eq!(storage.nodes.len(), 1); - let mut tree = TestTree::new(root.1); + let mut tree = TestTree::new(TrieStorageIndex::new(root.1)); tree.set(&storage, felt!("0x1").view_bits().to_bitvec(), Felt::ZERO) .unwrap(); let root = commit_and_persist_with_pruning(tree, &mut storage); @@ -1423,7 +1438,7 @@ mod tests { let root = commit_and_persist_with_pruning(uut, &mut storage); - let uut = TestTree::new(root.1); + let uut = TestTree::new(TrieStorageIndex::new(root.1)); assert_eq!(uut.get(&storage, key0).unwrap(), Some(val0)); assert_eq!(uut.get(&storage, key1).unwrap(), Some(val1)); @@ -1471,7 +1486,7 @@ mod tests { // Delete the final leaf; this exercises the bug as the nodes are all in storage // (unresolved). - let mut uut = TestTree::new(root.1); + let mut uut = TestTree::new(TrieStorageIndex::new(root.1)); let key = leaves[4].0.view_bits().to_bitvec(); let val = leaves[4].1; uut.set(&storage, key, val).unwrap(); @@ -1496,25 +1511,25 @@ mod tests { uut.set(&storage, key0.clone(), val0).unwrap(); let root0 = commit_and_persist_without_pruning(uut, &mut storage); - let mut uut = TestTree::new(root0.1); + let mut uut = TestTree::new(TrieStorageIndex::new(root0.1)); uut.set(&storage, key1.clone(), val1).unwrap(); let root1 = commit_and_persist_without_pruning(uut, &mut storage); - let mut uut = TestTree::new(root1.1); + let mut uut = TestTree::new(TrieStorageIndex::new(root1.1)); uut.set(&storage, key2.clone(), val2).unwrap(); let root2 = commit_and_persist_without_pruning(uut, &mut storage); - let uut = TestTree::new(root0.1); + let uut = TestTree::new(TrieStorageIndex::new(root0.1)); assert_eq!(uut.get(&storage, key0.clone()).unwrap(), Some(val0)); assert_eq!(uut.get(&storage, key1.clone()).unwrap(), None); assert_eq!(uut.get(&storage, key2.clone()).unwrap(), None); - let uut = TestTree::new(root1.1); + let uut = TestTree::new(TrieStorageIndex::new(root1.1)); assert_eq!(uut.get(&storage, key0.clone()).unwrap(), Some(val0)); assert_eq!(uut.get(&storage, key1.clone()).unwrap(), Some(val1)); assert_eq!(uut.get(&storage, key2.clone()).unwrap(), None); - let uut = TestTree::new(root2.1); + let uut = TestTree::new(TrieStorageIndex::new(root2.1)); assert_eq!(uut.get(&storage, key0).unwrap(), Some(val0)); assert_eq!(uut.get(&storage, key1).unwrap(), Some(val1)); assert_eq!(uut.get(&storage, key2).unwrap(), Some(val2)); @@ -1535,25 +1550,25 @@ mod tests { uut.set(&storage, key0.clone(), val0).unwrap(); let root0 = commit_and_persist_without_pruning(uut, &mut storage); - let mut uut = TestTree::new(root0.1); + let mut uut = TestTree::new(TrieStorageIndex::new(root0.1)); uut.set(&storage, key1.clone(), val1).unwrap(); let root1 = commit_and_persist_without_pruning(uut, &mut storage); - let mut uut = TestTree::new(root0.1); + let mut uut = TestTree::new(TrieStorageIndex::new(root0.1)); uut.set(&storage, key2.clone(), val2).unwrap(); let root2 = commit_and_persist_without_pruning(uut, &mut storage); - let uut = TestTree::new(root0.1); + let uut = TestTree::new(TrieStorageIndex::new(root0.1)); assert_eq!(uut.get(&storage, key0.clone()).unwrap(), Some(val0)); assert_eq!(uut.get(&storage, key1.clone()).unwrap(), None); assert_eq!(uut.get(&storage, key2.clone()).unwrap(), None); - let uut = TestTree::new(root1.1); + let uut = TestTree::new(TrieStorageIndex::new(root1.1)); assert_eq!(uut.get(&storage, key0.clone()).unwrap(), Some(val0)); assert_eq!(uut.get(&storage, key1.clone()).unwrap(), Some(val1)); assert_eq!(uut.get(&storage, key2.clone()).unwrap(), None); - let uut = TestTree::new(root2.1); + let uut = TestTree::new(TrieStorageIndex::new(root2.1)); assert_eq!(uut.get(&storage, key0).unwrap(), Some(val0)); assert_eq!(uut.get(&storage, key1).unwrap(), None); assert_eq!(uut.get(&storage, key2).unwrap(), Some(val2)); @@ -1570,10 +1585,10 @@ mod tests { let root0 = commit_and_persist_with_pruning(uut, &mut storage); - let uut = TestTree::new(root0.1); + let uut = TestTree::new(TrieStorageIndex::new(root0.1)); let root1 = commit_and_persist_with_pruning(uut, &mut storage); - let uut = TestTree::new(root1.1); + let uut = TestTree::new(TrieStorageIndex::new(root1.1)); let root2 = commit_and_persist_with_pruning(uut, &mut storage); assert_eq!(root0.0, root1.0); @@ -1583,11 +1598,7 @@ mod tests { mod real_world { use pathfinder_common::{ - class_commitment, - class_commitment_leaf_hash, - felt, - sierra_hash, - BlockNumber, + class_commitment, class_commitment_leaf_hash, felt, sierra_hash, BlockNumber, ClassCommitmentLeafHash, }; use pathfinder_storage::RootIndexUpdate; @@ -1684,7 +1695,7 @@ mod tests { ); let root = commit_and_persist_with_pruning(uut, &mut storage); - let mut uut = TestTree::new(root.1); + let mut uut = TestTree::new(TrieStorageIndex::new(root.1)); set!( uut, felt!("0x5c5e36947656f78c487b42ca69d96e79c01eac62f50d996f3972c9851bd5f64"), @@ -1692,7 +1703,7 @@ mod tests { ); let root = commit_and_persist_with_pruning(uut, &mut storage); - let mut uut = TestTree::new(root.1); + let mut uut = TestTree::new(TrieStorageIndex::new(root.1)); let mut visited = vec![]; let mut visitor_fn = |node: &InternalNode, path: &BitSlice| { @@ -1708,7 +1719,7 @@ mod tests { ); let root = commit_and_persist_with_pruning(uut, &mut storage); - let mut uut = TestTree::new(root.1); + let mut uut = TestTree::new(TrieStorageIndex::new(root.1)); let mut visited = vec![]; let mut visitor_fn = |node: &InternalNode, path: &BitSlice| { @@ -1766,13 +1777,13 @@ mod tests { let RootIndexUpdate::Updated(root_index) = root_index_update else { panic!("Expected root index to be updated"); }; - assert_eq!(root_index, 1); + assert_eq!(root_index, TrieStorageIndex::new(1)); tx.insert_class_root(BlockNumber::GENESIS, root_index_update) .unwrap(); assert!(tx.class_root_exists(BlockNumber::GENESIS).unwrap()); assert_eq!( tx.class_root_index(BlockNumber::GENESIS).unwrap(), - Some(root_index) + Some(TrieStorageIndex::new(root_index.get())) ); // Open the tree but do no updates. @@ -1793,7 +1804,10 @@ mod tests { tx.insert_class_root(block_number, root_index_update) .unwrap(); assert!(!tx.class_root_exists(block_number).unwrap()); - assert_eq!(tx.class_root_index(block_number).unwrap(), Some(root_index)); + assert_eq!( + tx.class_root_index(block_number).unwrap(), + Some(TrieStorageIndex::new(root_index.get())) + ); // Delete value let mut uut = crate::class::ClassCommitmentTree::load(&tx, block_number).unwrap(); diff --git a/crates/rpc/src/method/get_storage_proof.rs b/crates/rpc/src/method/get_storage_proof.rs index 1b96f4f9ad..85deb5cbc5 100644 --- a/crates/rpc/src/method/get_storage_proof.rs +++ b/crates/rpc/src/method/get_storage_proof.rs @@ -361,7 +361,7 @@ fn get_class_proofs( }; let class_root_hash = tx - .class_trie_node_hash(class_root_idx) + .class_trie_node_hash(class_root_idx.get()) .context("Querying class root hash")? .context("Class root hash missing")?; @@ -370,7 +370,7 @@ fn get_class_proofs( }; let nodes: Vec = - ClassCommitmentTree::get_proofs(tx, block_number, class_hashes, class_root_idx)? + ClassCommitmentTree::get_proofs(tx, block_number, class_hashes, class_root_idx.get())? .into_iter() .flatten() .map(|(node, node_hash)| NodeHashToNodeMapping { @@ -406,7 +406,7 @@ fn get_contract_proofs( }; let storage_root_hash = tx - .storage_trie_node_hash(storage_root_idx) + .storage_trie_node_hash(storage_root_idx.get()) .context("Querying storage root hash")? .context("Storage root hash missing")?; @@ -414,17 +414,21 @@ fn get_contract_proofs( return Ok((storage_root_hash, NodeHashToNodeMappings(vec![]), vec![])); }; - let nodes = - StorageCommitmentTree::get_proofs(tx, block_number, contract_addresses, storage_root_idx)? - .into_iter() - .flatten() - .map(|(node, node_hash)| NodeHashToNodeMapping { - node_hash, - node: ProofNode(node), - }) - .collect::>() - .into_iter() - .collect(); + let nodes = StorageCommitmentTree::get_proofs( + tx, + block_number, + contract_addresses, + storage_root_idx, + )? + .into_iter() + .flatten() + .map(|(node, node_hash)| NodeHashToNodeMapping { + node_hash, + node: ProofNode(node), + }) + .collect::>() + .into_iter() + .collect(); let contract_proof_nodes = NodeHashToNodeMappings(nodes); @@ -471,7 +475,7 @@ fn get_contract_storage_proofs( csk.contract_address, block_number, &csk.storage_keys, - root, + root.get(), )? .into_iter() .flatten() diff --git a/crates/rpc/src/pathfinder/methods/get_proof.rs b/crates/rpc/src/pathfinder/methods/get_proof.rs index c3b4fa41cd..971b01ab63 100644 --- a/crates/rpc/src/pathfinder/methods/get_proof.rs +++ b/crates/rpc/src/pathfinder/methods/get_proof.rs @@ -288,7 +288,7 @@ pub async fn get_proof( &tx, header.number, &input.contract_address, - storage_root_idx, + storage_root_idx.get(), )? .into_iter() .map(|(node, _)| node) @@ -336,7 +336,7 @@ pub async fn get_proof( input.contract_address, header.number, k.view_bits(), - root, + root.get(), )? .into_iter() .map(|(node, _)| node) @@ -428,11 +428,15 @@ pub async fn get_class_proof( // Generate a proof for this class. If the class does not exist, this will // be a "non membership" proof. - let class_proof = - ClassCommitmentTree::get_proof(&tx, header.number, input.class_hash, class_root_idx)? - .into_iter() - .map(|(node, _)| node) - .collect(); + let class_proof = ClassCommitmentTree::get_proof( + &tx, + header.number, + input.class_hash, + class_root_idx, + )? + .into_iter() + .map(|(node, _)| node) + .collect(); let class_proof = ProofNodes(class_proof); @@ -451,6 +455,7 @@ mod tests { use pathfinder_common::macro_prelude::*; use pathfinder_merkle_tree::starknet_state::update_starknet_state; + use pathfinder_storage::storage_index::TrieStorageIndex; use super::*; @@ -499,7 +504,9 @@ mod tests { tx.insert_storage_trie( &pathfinder_storage::TrieUpdate { nodes_added: vec![(Felt::from_u64(0), pathfinder_storage::Node::LeafBinary)], - nodes_removed: (0..100).collect(), + nodes_removed: (0..100) + .map(|value| TrieStorageIndex::new(value as u64)) + .collect(), root_commitment: Felt::ZERO, }, BlockNumber::GENESIS + 3, diff --git a/crates/storage/src/connection.rs b/crates/storage/src/connection.rs index bd1c9f35e0..87e232183d 100644 --- a/crates/storage/src/connection.rs +++ b/crates/storage/src/connection.rs @@ -8,6 +8,7 @@ mod reference; mod reorg_counter; mod signature; mod state_update; +pub mod storage_index; pub(crate) mod transaction; mod trie; diff --git a/crates/storage/src/connection/storage_index.rs b/crates/storage/src/connection/storage_index.rs new file mode 100644 index 0000000000..68b8db8b0d --- /dev/null +++ b/crates/storage/src/connection/storage_index.rs @@ -0,0 +1,15 @@ +/// A newtype for the storage index of a trie node. +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub struct TrieStorageIndex(u64); + +impl TrieStorageIndex { + /// Create a new StorageIndex. + pub fn new(index: u64) -> Self { + Self(index) + } + + /// Get the inner u64 value. + pub fn get(&self) -> u64 { + self.0 + } +} diff --git a/crates/storage/src/connection/trie.rs b/crates/storage/src/connection/trie.rs index 11fe530526..c27244d0a8 100644 --- a/crates/storage/src/connection/trie.rs +++ b/crates/storage/src/connection/trie.rs @@ -6,11 +6,15 @@ use bitvec::vec::BitVec; use pathfinder_common::prelude::*; use pathfinder_crypto::Felt; +use super::storage_index::TrieStorageIndex; use crate::prelude::*; use crate::{BlockId, TriePruneMode}; impl Transaction<'_> { - pub fn class_root_index(&self, block_number: BlockNumber) -> anyhow::Result> { + pub fn class_root_index( + &self, + block_number: BlockNumber, + ) -> anyhow::Result> { self.inner() .query_row( "SELECT root_index FROM class_roots WHERE block_number <= ? ORDER BY block_number \ @@ -19,7 +23,7 @@ impl Transaction<'_> { |row| row.get::<_, Option>(0), ) .optional() - .map(|x| x.flatten()) + .map(|option_u64| option_u64.flatten().map(TrieStorageIndex::new)) .map_err(Into::into) } @@ -33,7 +37,10 @@ impl Transaction<'_> { .map_err(Into::into) } - pub fn storage_root_index(&self, block_number: BlockNumber) -> anyhow::Result> { + pub fn storage_root_index( + &self, + block_number: BlockNumber, + ) -> anyhow::Result> { self.inner() .query_row( "SELECT root_index FROM storage_roots WHERE block_number <= ? ORDER BY \ @@ -42,7 +49,7 @@ impl Transaction<'_> { |row| row.get::<_, Option>(0), ) .optional() - .map(|x| x.flatten()) + .map(|option_u64| option_u64.flatten().map(TrieStorageIndex::new)) .map_err(Into::into) } @@ -60,7 +67,7 @@ impl Transaction<'_> { &self, block_number: BlockNumber, contract: ContractAddress, - ) -> anyhow::Result> { + ) -> anyhow::Result> { self.inner() .query_row( "SELECT root_index FROM contract_roots WHERE contract_address = ? AND \ @@ -69,7 +76,7 @@ impl Transaction<'_> { |row| row.get::<_, Option>(0), ) .optional() - .map(|x| x.flatten()) + .map(|x| x.flatten().map(TrieStorageIndex::new)) .map_err(Into::into) } @@ -97,7 +104,7 @@ impl Transaction<'_> { ) -> anyhow::Result<()> { let new_root_index = match update { RootIndexUpdate::Unchanged => return Ok(()), - RootIndexUpdate::Updated(idx) => Some(idx), + RootIndexUpdate::Updated(idx) => Some(idx.get()), RootIndexUpdate::TrieEmpty => None, }; @@ -209,7 +216,7 @@ impl Transaction<'_> { ) -> anyhow::Result<()> { let new_root_index = match update { RootIndexUpdate::Unchanged => return Ok(()), - RootIndexUpdate::Updated(idx) => Some(idx), + RootIndexUpdate::Updated(idx) => Some(idx.get()), RootIndexUpdate::TrieEmpty => None, }; self.inner().execute( @@ -256,7 +263,7 @@ impl Transaction<'_> { ) -> anyhow::Result<()> { let new_root_index = match update { RootIndexUpdate::Unchanged => return Ok(()), - RootIndexUpdate::Updated(idx) => Some(idx), + RootIndexUpdate::Updated(idx) => Some(idx.get()), RootIndexUpdate::TrieEmpty => None, }; self.inner().execute( @@ -311,11 +318,11 @@ impl Transaction<'_> { } pub fn contract_trie_node(&self, index: u64) -> anyhow::Result> { - self.trie_node(index, "trie_contracts") + self.trie_node(TrieStorageIndex::new(index), "trie_contracts") } pub fn contract_trie_node_hash(&self, index: u64) -> anyhow::Result> { - self.trie_node_hash(index, "trie_contracts") + self.trie_node_hash(TrieStorageIndex::new(index), "trie_contracts") } pub fn insert_class_trie( @@ -327,11 +334,11 @@ impl Transaction<'_> { } pub fn class_trie_node(&self, index: u64) -> anyhow::Result> { - self.trie_node(index, "trie_class") + self.trie_node(TrieStorageIndex::new(index), "trie_class") } pub fn class_trie_node_hash(&self, index: u64) -> anyhow::Result> { - self.trie_node_hash(index, "trie_class") + self.trie_node_hash(TrieStorageIndex::new(index), "trie_class") } pub fn insert_storage_trie( @@ -343,11 +350,11 @@ impl Transaction<'_> { } pub fn storage_trie_node(&self, index: u64) -> anyhow::Result> { - self.trie_node(index, "trie_storage") + self.trie_node(TrieStorageIndex::new(index), "trie_storage") } pub fn storage_trie_node_hash(&self, index: u64) -> anyhow::Result> { - self.trie_node_hash(index, "trie_storage") + self.trie_node_hash(TrieStorageIndex::new(index), "trie_storage") } /// Prune tries by removing nodes that are no longer needed at the given @@ -375,7 +382,7 @@ impl Transaction<'_> { /// Mark the input nodes as ready for removal. fn remove_trie( &self, - removed: &[u64], + removed: &[TrieStorageIndex], block_number: BlockNumber, table: &'static str, ) -> anyhow::Result<()> { @@ -388,8 +395,14 @@ impl Transaction<'_> { .context("Creating statement to insert removal marker")?; stmt.execute(params![ &block_number, - &bincode::encode_to_vec(removed, bincode::config::standard()) - .context("Serializing indices")? + &bincode::encode_to_vec( + removed + .iter() + .map(|trie_storaage_index| trie_storaage_index.get()) + .collect::>(), + bincode::config::standard() + ) + .context("Serializing indices")? ]) .context("Inserting removal marker")?; } @@ -555,15 +568,18 @@ impl Transaction<'_> { metrics::increment_counter!(METRIC_TRIE_NODES_ADDED, "table" => table); } - Ok(RootIndexUpdate::Updated( - *indices - .get(&(update.nodes_added.len() - 1)) + Ok(RootIndexUpdate::Updated(TrieStorageIndex::new( + *(indices.get(&(update.nodes_added.len() - 1))) .expect("Root index must exist as we just inserted it"), - )) + ))) } /// Returns the node with the given index. - fn trie_node(&self, index: u64, table: &'static str) -> anyhow::Result> { + fn trie_node( + &self, + index: TrieStorageIndex, + table: &'static str, + ) -> anyhow::Result> { // We rely on sqlite caching the statement here. Storing the statement would be // nice, however that leads to &mut requirements or interior mutable // work-arounds. @@ -573,7 +589,7 @@ impl Transaction<'_> { .context("Creating get statement")?; let Some(data): Option> = stmt - .query_row(params![&index], |row| row.get(0)) + .query_row(params![&index.get()], |row| row.get(0)) .optional()? else { return Ok(None); @@ -585,7 +601,11 @@ impl Transaction<'_> { } /// Returns the hash of the node with the given index. - fn trie_node_hash(&self, index: u64, table: &'static str) -> anyhow::Result> { + fn trie_node_hash( + &self, + index: TrieStorageIndex, + table: &'static str, + ) -> anyhow::Result> { // We rely on sqlite caching the statement here. Storing the statement would be // nice, however that leads to &mut requirements or interior mutable // work-arounds. @@ -613,7 +633,7 @@ pub struct TrieUpdate { /// The last node is the root of the trie. pub nodes_added: Vec<(Felt, Node)>, /// Nodes committed to storage that have been removed. - pub nodes_removed: Vec, + pub nodes_removed: Vec, /// New root commitment of the trie. pub root_commitment: Felt, } @@ -622,7 +642,7 @@ pub struct TrieUpdate { #[derive(Debug, PartialEq)] pub enum RootIndexUpdate { Unchanged, - Updated(u64), + Updated(TrieStorageIndex), TrieEmpty, } @@ -645,7 +665,7 @@ pub enum Node { #[derive(Copy, Clone, Debug)] pub enum NodeRef { // A reference to a node that has already been committed to storage. - StorageIndex(u64), + TrieStorageIndex(u64), // A reference to a node that has not yet been committed to storage. // The index within the `nodes_added` vector is used as a reference. Index(usize), @@ -653,10 +673,18 @@ pub enum NodeRef { #[derive(Clone, Debug, PartialEq)] pub enum StoredNode { - Binary { left: u64, right: u64 }, - Edge { child: u64, path: BitVec }, + Binary { + left: TrieStorageIndex, + right: TrieStorageIndex, + }, + Edge { + child: TrieStorageIndex, + path: BitVec, + }, LeafBinary, - LeafEdge { path: BitVec }, + LeafEdge { + path: BitVec, + }, } #[derive(Clone, Debug, bincode::Encode, bincode::BorrowDecode)] @@ -675,8 +703,8 @@ impl StoredNode { fn encode(&self, buffer: &mut [u8]) -> Result { let helper = match self { Self::Binary { left, right } => StoredSerde::Binary { - left: *left, - right: *right, + left: left.get(), + right: right.get(), }, Self::Edge { child, path } => { let path_length = path.len() as u8; @@ -687,7 +715,7 @@ impl StoredNode { path.push(path_length); StoredSerde::Edge { - child: *child, + child: child.get(), path, } } @@ -712,14 +740,20 @@ impl StoredNode { let helper = bincode::borrow_decode_from_slice(data, Self::CODEC_CFG)?; let node = match helper.0 { - StoredSerde::Binary { left, right } => Self::Binary { left, right }, + StoredSerde::Binary { left, right } => Self::Binary { + left: TrieStorageIndex::new(left), + right: TrieStorageIndex::new(right), + }, StoredSerde::Edge { child, mut path } => { let path_length = path.pop().ok_or(bincode::error::DecodeError::Other( "Edge node's path length is missing", ))?; let mut path = bitvec::vec::BitVec::from_vec(path); path.resize(path_length as usize, false); - Self::Edge { child, path } + Self::Edge { + child: TrieStorageIndex::new(child), + path, + } } StoredSerde::LeafBinary => Self::LeafBinary, StoredSerde::LeafEdge { mut path } => { @@ -741,31 +775,34 @@ impl Node { let node = match self { Node::Binary { left, right } => { let left = match left { - NodeRef::StorageIndex(id) => *id, + NodeRef::TrieStorageIndex(id) => *id, NodeRef::Index(idx) => *storage_indices .get(idx) .context("Left child index missing")?, }; let right = match right { - NodeRef::StorageIndex(id) => *id, + NodeRef::TrieStorageIndex(id) => *id, NodeRef::Index(idx) => *storage_indices .get(idx) .context("Right child index missing")?, }; - StoredNode::Binary { left, right } + StoredNode::Binary { + left: TrieStorageIndex::new(left), + right: TrieStorageIndex::new(right), + } } Node::Edge { child, path } => { let child = match child { - NodeRef::StorageIndex(id) => id, + NodeRef::TrieStorageIndex(id) => id, NodeRef::Index(idx) => { storage_indices.get(idx).context("Child index missing")? } }; StoredNode::Edge { - child: *child, + child: TrieStorageIndex::new(*child), path: path.clone(), } } @@ -794,28 +831,37 @@ mod tests { let result = tx.class_root_index(BlockNumber::GENESIS).unwrap(); assert_eq!(result, None); - tx.insert_class_root(BlockNumber::GENESIS, RootIndexUpdate::Updated(123)) - .unwrap(); + tx.insert_class_root( + BlockNumber::GENESIS, + RootIndexUpdate::Updated(TrieStorageIndex::new(123)), + ) + .unwrap(); let result = tx.class_root_index(BlockNumber::GENESIS).unwrap(); - assert_eq!(result, Some(123)); + assert_eq!(result, Some(TrieStorageIndex::new(123))); - tx.insert_class_root(BlockNumber::GENESIS + 1, RootIndexUpdate::Updated(456)) - .unwrap(); + tx.insert_class_root( + BlockNumber::GENESIS + 1, + RootIndexUpdate::Updated(TrieStorageIndex::new(456)), + ) + .unwrap(); let result = tx.class_root_index(BlockNumber::GENESIS).unwrap(); - assert_eq!(result, Some(123)); + assert_eq!(result, Some(TrieStorageIndex::new(123))); let result = tx.class_root_index(BlockNumber::GENESIS + 1).unwrap(); - assert_eq!(result, Some(456)); + assert_eq!(result, Some(TrieStorageIndex::new(456))); let result = tx.class_root_index(BlockNumber::GENESIS + 2).unwrap(); - assert_eq!(result, Some(456)); + assert_eq!(result, Some(TrieStorageIndex::new(456))); - tx.insert_class_root(BlockNumber::GENESIS + 10, RootIndexUpdate::Updated(789)) - .unwrap(); + tx.insert_class_root( + BlockNumber::GENESIS + 10, + RootIndexUpdate::Updated(TrieStorageIndex::new(789)), + ) + .unwrap(); let result = tx.class_root_index(BlockNumber::GENESIS + 9).unwrap(); - assert_eq!(result, Some(456)); + assert_eq!(result, Some(TrieStorageIndex::new(456))); let result = tx.class_root_index(BlockNumber::GENESIS + 10).unwrap(); - assert_eq!(result, Some(789)); + assert_eq!(result, Some(TrieStorageIndex::new(789))); let result = tx.class_root_index(BlockNumber::GENESIS + 11).unwrap(); - assert_eq!(result, Some(789)); + assert_eq!(result, Some(TrieStorageIndex::new(789))); tx.insert_class_root(BlockNumber::GENESIS + 12, RootIndexUpdate::TrieEmpty) .unwrap(); @@ -836,28 +882,37 @@ mod tests { let result = tx.storage_root_index(BlockNumber::GENESIS).unwrap(); assert_eq!(result, None); - tx.insert_storage_root(BlockNumber::GENESIS, RootIndexUpdate::Updated(123)) - .unwrap(); + tx.insert_storage_root( + BlockNumber::GENESIS, + RootIndexUpdate::Updated(TrieStorageIndex::new(123)), + ) + .unwrap(); let result = tx.storage_root_index(BlockNumber::GENESIS).unwrap(); - assert_eq!(result, Some(123)); + assert_eq!(result, Some(TrieStorageIndex::new(123))); - tx.insert_storage_root(BlockNumber::GENESIS + 1, RootIndexUpdate::Updated(456)) - .unwrap(); + tx.insert_storage_root( + BlockNumber::GENESIS + 1, + RootIndexUpdate::Updated(TrieStorageIndex::new(456)), + ) + .unwrap(); let result = tx.storage_root_index(BlockNumber::GENESIS).unwrap(); - assert_eq!(result, Some(123)); + assert_eq!(result, Some(TrieStorageIndex::new(123))); let result = tx.storage_root_index(BlockNumber::GENESIS + 1).unwrap(); - assert_eq!(result, Some(456)); + assert_eq!(result, Some(TrieStorageIndex::new(456))); let result = tx.storage_root_index(BlockNumber::GENESIS + 2).unwrap(); - assert_eq!(result, Some(456)); + assert_eq!(result, Some(TrieStorageIndex::new(456))); - tx.insert_storage_root(BlockNumber::GENESIS + 10, RootIndexUpdate::Updated(789)) - .unwrap(); + tx.insert_storage_root( + BlockNumber::GENESIS + 10, + RootIndexUpdate::Updated(TrieStorageIndex::new(789)), + ) + .unwrap(); let result = tx.storage_root_index(BlockNumber::GENESIS + 9).unwrap(); - assert_eq!(result, Some(456)); + assert_eq!(result, Some(TrieStorageIndex::new(456))); let result = tx.storage_root_index(BlockNumber::GENESIS + 10).unwrap(); - assert_eq!(result, Some(789)); + assert_eq!(result, Some(TrieStorageIndex::new(789))); let result = tx.storage_root_index(BlockNumber::GENESIS + 11).unwrap(); - assert_eq!(result, Some(789)); + assert_eq!(result, Some(TrieStorageIndex::new(789))); tx.insert_storage_root(BlockNumber::GENESIS + 12, RootIndexUpdate::TrieEmpty) .unwrap(); @@ -924,8 +979,12 @@ mod tests { tx.insert_contract_root(BlockNumber::GENESIS + 1, c1, idx1_update) .unwrap(); - tx.insert_contract_root(BlockNumber::GENESIS + 1, c2, RootIndexUpdate::Updated(888)) - .unwrap(); + tx.insert_contract_root( + BlockNumber::GENESIS + 1, + c2, + RootIndexUpdate::Updated(TrieStorageIndex::new(888)), + ) + .unwrap(); let result1 = tx.contract_root_index(BlockNumber::GENESIS, c1).unwrap(); let result2 = tx.contract_root_index(BlockNumber::GENESIS, c2).unwrap(); let hash1 = tx.contract_root(BlockNumber::GENESIS, c1).unwrap(); @@ -940,7 +999,7 @@ mod tests { .unwrap(); let hash1 = tx.contract_root(BlockNumber::GENESIS + 1, c1).unwrap(); assert_eq!(result1, Some(idx1)); - assert_eq!(result2, Some(888)); + assert_eq!(result2, Some(TrieStorageIndex::new(888))); assert_eq!(hash1, Some(root1)); let result1 = tx .contract_root_index(BlockNumber::GENESIS + 2, c1) @@ -950,7 +1009,7 @@ mod tests { .unwrap(); let hash1 = tx.contract_root(BlockNumber::GENESIS + 2, c1).unwrap(); assert_eq!(result1, Some(idx1)); - assert_eq!(result2, Some(888)); + assert_eq!(result2, Some(TrieStorageIndex::new(888))); assert_eq!(hash1, Some(root1)); let root2 = contract_root_bytes!(b"root 2"); @@ -968,8 +1027,12 @@ mod tests { tx.insert_contract_root(BlockNumber::GENESIS + 10, c1, idx2_update) .unwrap(); - tx.insert_contract_root(BlockNumber::GENESIS + 11, c2, RootIndexUpdate::Updated(999)) - .unwrap(); + tx.insert_contract_root( + BlockNumber::GENESIS + 11, + c2, + RootIndexUpdate::Updated(TrieStorageIndex::new(999)), + ) + .unwrap(); let result1 = tx .contract_root_index(BlockNumber::GENESIS + 9, c1) .unwrap(); @@ -978,7 +1041,7 @@ mod tests { .unwrap(); let hash1 = tx.contract_root(BlockNumber::GENESIS + 9, c1).unwrap(); assert_eq!(result1, Some(idx1)); - assert_eq!(result2, Some(888)); + assert_eq!(result2, Some(TrieStorageIndex::new(888))); assert_eq!(hash1, Some(root1)); let result1 = tx .contract_root_index(BlockNumber::GENESIS + 10, c1) @@ -988,13 +1051,13 @@ mod tests { .unwrap(); let hash1 = tx.contract_root(BlockNumber::GENESIS + 10, c1).unwrap(); assert_eq!(result1, Some(idx2)); - assert_eq!(result2, Some(888)); + assert_eq!(result2, Some(TrieStorageIndex::new(888))); assert_eq!(hash1, Some(root2)); let result2 = tx .contract_root_index(BlockNumber::GENESIS + 11, c2) .unwrap(); let hash1 = tx.contract_root(BlockNumber::GENESIS + 11, c1).unwrap(); - assert_eq!(result2, Some(999)); + assert_eq!(result2, Some(TrieStorageIndex::new(999))); assert_eq!(hash1, Some(root2)); tx.insert_contract_root(BlockNumber::GENESIS + 12, c1, RootIndexUpdate::TrieEmpty) @@ -1015,10 +1078,10 @@ mod tests { #[rstest::rstest] #[case::binary(StoredNode::Binary { - left: 12, right: 34 + left: TrieStorageIndex::new(12), right: TrieStorageIndex::new(34) })] #[case::edge(StoredNode::Edge { - child: 123, + child: TrieStorageIndex::new(123), path: bitvec::bitvec![u8, Msb0; 1,0,0,1,0,1,0,0,0,0,0,1,1,1,1] })] #[case::binary(StoredNode::LeafBinary)] @@ -1026,11 +1089,11 @@ mod tests { path: bitvec::bitvec![u8, Msb0; 1,0,0,1,0,1,0,0,0,0,0,1,1,1,1] })] #[case::edge_max_path(StoredNode::Edge { - child: 123, + child: TrieStorageIndex::new(123), path: bitvec::bitvec![u8, Msb0; 1; 251] })] #[case::edge_min_path(StoredNode::Edge { - child: 123, + child: TrieStorageIndex::new(123), path: bitvec::bitvec![u8, Msb0; 0] })] fn serde(#[case] node: StoredNode) { @@ -1121,7 +1184,7 @@ mod tests { (felt!("4"), Node::LeafBinary), (felt!("5"), Node::LeafBinary), ], - nodes_removed: vec![1], + nodes_removed: vec![TrieStorageIndex::new(1)], root_commitment: Felt::ZERO, }, BlockNumber::GENESIS + 1, @@ -1235,7 +1298,7 @@ mod tests { (felt!("4"), Node::LeafBinary), (felt!("5"), Node::LeafBinary), ], - nodes_removed: vec![1], + nodes_removed: vec![TrieStorageIndex::new(1)], root_commitment: Felt::ZERO, }, BlockNumber::GENESIS + 1, @@ -1402,7 +1465,11 @@ mod tests { (felt!("4"), Node::LeafBinary), (felt!("5"), Node::LeafBinary), ], - nodes_removed: vec![1, 2, 3], + nodes_removed: vec![ + TrieStorageIndex::new(1), + TrieStorageIndex::new(2), + TrieStorageIndex::new(3), + ], root_commitment: Felt::ZERO, }, BlockNumber::GENESIS + 1, @@ -1464,7 +1531,10 @@ mod tests { BlockNumber::GENESIS, ) .unwrap(); - assert_eq!(root_update, RootIndexUpdate::Updated(1)); + assert_eq!( + root_update, + RootIndexUpdate::Updated(TrieStorageIndex::new(TrieStorageIndex::new(1).get())) + ); } #[test] @@ -1477,13 +1547,22 @@ mod tests { .unwrap(); let tx = db.transaction().unwrap(); - tx.insert_class_root(BlockNumber::GENESIS, RootIndexUpdate::Updated(1)) - .unwrap(); - tx.insert_class_root(BlockNumber::new_or_panic(1), RootIndexUpdate::Updated(2)) - .unwrap(); + tx.insert_class_root( + BlockNumber::GENESIS, + RootIndexUpdate::Updated(TrieStorageIndex::new(1)), + ) + .unwrap(); + tx.insert_class_root( + BlockNumber::new_or_panic(1), + RootIndexUpdate::Updated(TrieStorageIndex::new(2)), + ) + .unwrap(); // no root inserted for block 2 - tx.insert_class_root(BlockNumber::new_or_panic(3), RootIndexUpdate::Updated(3)) - .unwrap(); + tx.insert_class_root( + BlockNumber::new_or_panic(3), + RootIndexUpdate::Updated(TrieStorageIndex::new(3)), + ) + .unwrap(); assert!(!tx.class_root_exists(BlockNumber::GENESIS).unwrap()); // root at block 1 cannot be deleted because it is still required for @@ -1502,10 +1581,16 @@ mod tests { .unwrap(); let tx = db.transaction().unwrap(); - tx.insert_class_root(BlockNumber::GENESIS, RootIndexUpdate::Updated(1)) - .unwrap(); - tx.insert_class_root(BlockNumber::new_or_panic(1), RootIndexUpdate::Updated(2)) - .unwrap(); + tx.insert_class_root( + BlockNumber::GENESIS, + RootIndexUpdate::Updated(TrieStorageIndex::new(1)), + ) + .unwrap(); + tx.insert_class_root( + BlockNumber::new_or_panic(1), + RootIndexUpdate::Updated(TrieStorageIndex::new(2)), + ) + .unwrap(); assert!(!tx.class_root_exists(BlockNumber::GENESIS).unwrap()); assert!(tx.class_root_exists(BlockNumber::new_or_panic(1)).unwrap()); @@ -1597,13 +1682,22 @@ mod tests { .unwrap(); let tx = db.transaction().unwrap(); - tx.insert_storage_root(BlockNumber::GENESIS, RootIndexUpdate::Updated(1)) - .unwrap(); - tx.insert_storage_root(BlockNumber::new_or_panic(1), RootIndexUpdate::Updated(2)) - .unwrap(); + tx.insert_storage_root( + BlockNumber::GENESIS, + RootIndexUpdate::Updated(TrieStorageIndex::new(1)), + ) + .unwrap(); + tx.insert_storage_root( + BlockNumber::new_or_panic(1), + RootIndexUpdate::Updated(TrieStorageIndex::new(2)), + ) + .unwrap(); // no new root index for block 2 - tx.insert_storage_root(BlockNumber::new_or_panic(3), RootIndexUpdate::Updated(3)) - .unwrap(); + tx.insert_storage_root( + BlockNumber::new_or_panic(3), + RootIndexUpdate::Updated(TrieStorageIndex::new(3)), + ) + .unwrap(); assert!(!tx.storage_root_exists(BlockNumber::GENESIS).unwrap()); assert!(tx @@ -1624,10 +1718,16 @@ mod tests { .unwrap(); let tx = db.transaction().unwrap(); - tx.insert_storage_root(BlockNumber::GENESIS, RootIndexUpdate::Updated(1)) - .unwrap(); - tx.insert_storage_root(BlockNumber::new_or_panic(1), RootIndexUpdate::Updated(2)) - .unwrap(); + tx.insert_storage_root( + BlockNumber::GENESIS, + RootIndexUpdate::Updated(TrieStorageIndex::new(1)), + ) + .unwrap(); + tx.insert_storage_root( + BlockNumber::new_or_panic(1), + RootIndexUpdate::Updated(TrieStorageIndex::new(2)), + ) + .unwrap(); assert!(!tx.storage_root_exists(BlockNumber::GENESIS).unwrap()); assert!(tx @@ -1646,19 +1746,23 @@ mod tests { let tx = db.transaction().unwrap(); let contract = contract_address!("0xdeadbeef"); - tx.insert_contract_root(BlockNumber::GENESIS, contract, RootIndexUpdate::Updated(1)) - .unwrap(); + tx.insert_contract_root( + BlockNumber::GENESIS, + contract, + RootIndexUpdate::Updated(TrieStorageIndex::new(1)), + ) + .unwrap(); tx.insert_contract_root( BlockNumber::new_or_panic(1), contract, - RootIndexUpdate::Updated(2), + RootIndexUpdate::Updated(TrieStorageIndex::new(2)), ) .unwrap(); // no new root for block 2 tx.insert_contract_root( BlockNumber::new_or_panic(3), contract, - RootIndexUpdate::Updated(3), + RootIndexUpdate::Updated(TrieStorageIndex::new(3)), ) .unwrap(); @@ -1670,12 +1774,12 @@ mod tests { assert_eq!( tx.contract_root_index(BlockNumber::new_or_panic(2), contract) .unwrap(), - Some(2) + Some(TrieStorageIndex::new(2)) ); assert_eq!( tx.contract_root_index(BlockNumber::new_or_panic(3), contract) .unwrap(), - Some(3) + Some(TrieStorageIndex::new(3)) ); } @@ -1690,12 +1794,16 @@ mod tests { let tx = db.transaction().unwrap(); let contract = contract_address!("0xdeadbeef"); - tx.insert_contract_root(BlockNumber::GENESIS, contract, RootIndexUpdate::Updated(1)) - .unwrap(); + tx.insert_contract_root( + BlockNumber::GENESIS, + contract, + RootIndexUpdate::Updated(TrieStorageIndex::new(1)), + ) + .unwrap(); tx.insert_contract_root( BlockNumber::new_or_panic(1), contract, - RootIndexUpdate::Updated(2), + RootIndexUpdate::Updated(TrieStorageIndex::new(2)), ) .unwrap(); @@ -1707,7 +1815,7 @@ mod tests { assert_eq!( tx.contract_root_index(BlockNumber::new_or_panic(1), contract) .unwrap(), - Some(2) + Some(TrieStorageIndex::new(2)) ); } } diff --git a/crates/storage/src/params.rs b/crates/storage/src/params.rs index 2a82e08754..cf5a616d95 100644 --- a/crates/storage/src/params.rs +++ b/crates/storage/src/params.rs @@ -85,7 +85,7 @@ impl ToSql for L1DataAvailabilityMode { }; ToSqlOutput::Owned(rusqlite::types::Value::Integer(value)) } -} +} to_sql_felt!( BlockHash, @@ -126,6 +126,8 @@ to_sql_compressed_felt!(ContractNonce, StorageValue, TransactionNonce); to_sql_int!(BlockNumber, BlockTimestamp); to_sql_int!(L1BlockNumber); +to_sql_int!(TrieStorageIndex); + to_sql_builtin!( String, @@ -503,6 +505,8 @@ macro_rules! row_felt_wrapper { }; } +use crate::storage_index::TrieStorageIndex; + use { row_felt_wrapper, to_sql_builtin,