Skip to content

Commit df56110

Browse files
refactor: enabling the node variant of merkle tree to contain data
- Removes MerkleTree::Leaf tuple with a struct - Removes the impl_modify_map_collect function - Replaces the uses of the mentioned function with a non-recursive direct implementation.
1 parent 3c97a83 commit df56110

File tree

12 files changed

+225
-215
lines changed

12 files changed

+225
-215
lines changed

data/src/components/atom/tests.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ use crate::components::atom::Atom;
1212
use crate::hash::Hash;
1313
use crate::hash::PartialHash;
1414
use crate::merkle_tree::MerkleTree;
15+
use crate::merkle_tree::MerkleTreeLeafData;
1516
use crate::mode::Mode;
1617
use crate::mode::Normal;
1718
use crate::mode::Prove;
@@ -219,7 +220,11 @@ fn proof_gen() {
219220
let merkle_tree = MerkleTree::from_foldable(&proof_atoms);
220221
merkle_tree.check_root_hash();
221222
match merkle_tree {
222-
MerkleTree::Leaf(hash, access_info, _) => {
223+
MerkleTree::Leaf(MerkleTreeLeafData {
224+
hash,
225+
access_info,
226+
..
227+
}) => {
223228
prop_assert_eq!(hash, initial_root_hash);
224229
prop_assert!(access_info);
225230
}

data/src/components/data_space/tests.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ use super::PageId;
2020
use crate::components::data_space::DataSpace;
2121
use crate::hash::Hash;
2222
use crate::merkle_tree::MerkleTree;
23+
use crate::merkle_tree::MerkleTreeLeafData;
2324
use crate::mode::Normal;
2425
use crate::mode::Prove;
2526
use crate::mode::utils::assert_eq_found;
@@ -261,7 +262,7 @@ fn generate_proof() {
261262
let mut queue = VecDeque::with_capacity(LEAVES + 1);
262263

263264
let pages_tree = match merkle_tree {
264-
MerkleTree::Leaf(_, _, _) => panic!("Did not expect leaf"),
265+
MerkleTree::Leaf(_) => panic!("Did not expect leaf"),
265266
MerkleTree::Node(_, mut children) => {
266267
// The node for the pages is the second child.
267268
children.remove(1)
@@ -273,7 +274,10 @@ fn generate_proof() {
273274
while let Some(node) = queue.pop_front() {
274275
match node {
275276
MerkleTree::Node(_, children) => queue.extend(children),
276-
MerkleTree::Leaf(_, access_info, _) => {
277+
MerkleTree::Leaf(MerkleTreeLeafData {
278+
access_info,
279+
..
280+
}) => {
277281
prop_assert_eq!(
278282
access_info,
279283
read_leaves.contains(&leaf) ||

data/src/merkle_proof.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
88
pub mod proof_tree;
99
pub mod tag;
10-
pub mod transform;
1110

1211
use std::error;
1312

data/src/merkle_proof/proof_tree.rs

Lines changed: 76 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,6 @@ use bincode::enc::write::Writer;
55

66
use super::tag::LeafTag;
77
use super::tag::Tag;
8-
use super::transform::ModifyResult;
9-
use super::transform::impl_modify_map_collect;
108
use crate::hash::Hash;
119
use crate::tree::Tree;
1210

@@ -77,6 +75,42 @@ pub enum MerkleProofLeaf {
7775
Read(Vec<u8>),
7876
}
7977

78+
enum NodeLeaf {
79+
Node,
80+
Leaf,
81+
}
82+
83+
/// [`struct@HashState`] is associated with the state of hashing a [`MerkleProof`].
84+
/// We record whether the node is a leaf or an internal node, the index of its parent(
85+
/// see [`MerkleProof::root_hash`] for more details) and the hashes of its children
86+
/// if it's a node and its own hash if its a leaf.
87+
struct HashState {
88+
node_leaf: NodeLeaf,
89+
parent_index: usize,
90+
hashes: Vec<Hash>,
91+
}
92+
93+
impl HashState {
94+
fn new(node_leaf: NodeLeaf, parent_index: usize, hashes: Vec<Hash>) -> Self {
95+
Self {
96+
node_leaf,
97+
parent_index,
98+
hashes,
99+
}
100+
}
101+
102+
fn push(&mut self, hash: Hash) {
103+
self.hashes.push(hash);
104+
}
105+
106+
fn hash(&self) -> Hash {
107+
match self.node_leaf {
108+
NodeLeaf::Node => Hash::combine_hashes(&self.hashes),
109+
NodeLeaf::Leaf => self.hashes[0],
110+
}
111+
}
112+
}
113+
80114
impl MerkleProof {
81115
/// Create a new Merkle proof as a read leaf.
82116
pub fn leaf_read(data: Vec<u8>) -> Self {
@@ -90,18 +124,46 @@ impl MerkleProof {
90124

91125
/// Compute the root hash of the Merkle proof.
92126
pub fn root_hash(&self) -> Hash {
93-
impl_modify_map_collect(
94-
self,
95-
|subtree| match subtree {
96-
Tree::Node(vec) => ModifyResult::NodeContinue((), vec.iter().collect()),
97-
Tree::Leaf(data) => ModifyResult::LeafStop(data),
98-
},
99-
|leaf| match leaf {
100-
MerkleProofLeaf::Blind(hash) => *hash,
101-
MerkleProofLeaf::Read(data) => Hash::hash_bytes(data.as_slice()),
102-
},
103-
|(), leaves| Hash::combine_hashes(leaves),
104-
)
127+
// The nodes is essentially used as a stack of pairs where the pair is made up
128+
// of a [`MerkleProof`] node and the index of its parent in hash_states.
129+
let mut nodes: Vec<(&MerkleProof, usize)> = vec![(self, 0)];
130+
// hash_states contains the hashing state associated with a node.
131+
// See [`HashState`] for more details.
132+
let mut hash_states: Vec<HashState> = vec![];
133+
134+
// Going through all the nodes of the [`MerkleProof`] in a DFS fashion.
135+
while let Some((node, parent_index)) = nodes.pop() {
136+
match node {
137+
Tree::Leaf(MerkleProofLeaf::Blind(hash)) => {
138+
hash_states.push(HashState::new(NodeLeaf::Leaf, parent_index, vec![*hash]));
139+
}
140+
Tree::Leaf(MerkleProofLeaf::Read(data)) => {
141+
hash_states.push(HashState::new(
142+
NodeLeaf::Leaf,
143+
parent_index,
144+
vec![Hash::hash_bytes(data.as_slice())],
145+
));
146+
}
147+
Tree::Node(children) => {
148+
hash_states.push(HashState::new(NodeLeaf::Node, parent_index, vec![]));
149+
let new_parent_index = hash_states.len() - 1;
150+
for child in children.iter() {
151+
nodes.push((child, new_parent_index));
152+
}
153+
}
154+
}
155+
}
156+
157+
// Pops the hash states and adds them to their parents.
158+
while let Some(hash_state) = hash_states.pop() {
159+
if hash_states.is_empty() {
160+
// Returns the root hash
161+
return hash_state.hash();
162+
}
163+
hash_states[hash_state.parent_index].push(hash_state.hash());
164+
}
165+
166+
unreachable!("hash_states can't be an empty vector");
105167
}
106168
}
107169

data/src/merkle_proof/transform.rs

Lines changed: 0 additions & 89 deletions
This file was deleted.

data/src/merkle_tree.rs

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,22 @@ use crate::foldable::Foldable;
88
use crate::foldable::NodeFold;
99
use crate::hash::Hash;
1010

11+
/// Struct which holds data for the leaves of a [`MerkleTree`]
12+
#[derive(Debug, Clone)]
13+
pub struct MerkleTreeLeafData {
14+
pub hash: Hash,
15+
pub access_info: bool,
16+
pub data: Vec<u8>,
17+
}
18+
1119
/// A variable-width Merkle tree with access metadata for leaves.
1220
///
1321
/// Values of this type are produced by the proof-generating backend to capture
1422
/// a snapshot of the machine state along with access information for leaves
1523
/// which hold data that was used in a particular evaluation step.
1624
#[derive(Debug, Clone)]
1725
pub enum MerkleTree {
18-
Leaf(Hash, bool, Vec<u8>),
26+
Leaf(MerkleTreeLeafData),
1927
Node(Hash, Vec<Self>),
2028
}
2129

@@ -38,14 +46,18 @@ impl MerkleTree {
3846
pub fn root_hash(&self) -> Hash {
3947
match self {
4048
Self::Node(hash, _) => *hash,
41-
Self::Leaf(hash, _, _) => *hash,
49+
Self::Leaf(MerkleTreeLeafData { hash, .. }) => *hash,
4250
}
4351
}
4452

4553
/// Creates a merkle tree which is a single leaf
4654
pub fn make_merkle_leaf(data: Vec<u8>, access_info: bool) -> Self {
4755
let hash = Hash::hash_bytes(&data);
48-
MerkleTree::Leaf(hash, access_info, data)
56+
MerkleTree::Leaf(MerkleTreeLeafData {
57+
hash,
58+
access_info,
59+
data,
60+
})
4961
}
5062

5163
/// Takes a list of children nodes and creates a
@@ -65,7 +77,9 @@ impl MerkleTree {
6577

6678
while let Some(node) = deque.pop_front() {
6779
let is_valid_hash = match node {
68-
Self::Leaf(hash, _, data) => &Hash::hash_bytes(data) == hash,
80+
Self::Leaf(MerkleTreeLeafData { hash, data, .. }) => {
81+
&Hash::hash_bytes(data) == hash
82+
}
6983
Self::Node(hash, children) => {
7084
let children_hashes: Vec<Hash> = children
7185
.iter()

data/src/tree.rs

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,3 @@ pub enum Tree<A> {
88
Node(Vec<Self>),
99
Leaf(A),
1010
}
11-
12-
/// Used in [`crate::merkle_proof::transform::impl_modify_map_collect`]
13-
impl<D> From<D> for Tree<D> {
14-
fn from(value: D) -> Self {
15-
Tree::Leaf(value)
16-
}
17-
}

src/riscv/lib/src/pvm/common.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,8 @@ use crate::pvm::hooks::PvmHooks;
5454
use crate::pvm::tezos;
5555
use crate::range_utils::less_than_bound;
5656
use crate::state_backend::ProofTree;
57-
use crate::state_backend::proof_backend::merkle::merkle_tree_to_merkle_proof;
57+
use crate::state_backend::proof_backend::merkle::CompressedMerkleTree;
58+
use crate::state_backend::proof_backend::merkle::merkle_tree_to_compressed_merkle_tree;
5859
use crate::state_backend::proof_backend::proof::Proof;
5960
use crate::state_backend::proof_backend::proof::deserialise_owned;
6061

@@ -370,7 +371,9 @@ where
370371
let _ = self.input_request();
371372

372373
let merkle_tree = MerkleTree::from_foldable(self);
373-
let merkle_proof = merkle_tree_to_merkle_proof(merkle_tree);
374+
let compressed_merkle_tree: CompressedMerkleTree =
375+
merkle_tree_to_compressed_merkle_tree(merkle_tree);
376+
let merkle_proof: MerkleProof = compressed_merkle_tree.to_proof();
374377

375378
let final_hash = Hash::from_foldable(self);
376379
let proof = Proof::new(merkle_proof, final_hash);

src/riscv/lib/src/state_backend.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ mod tests {
4848
use rand::RngCore;
4949

5050
use super::*;
51-
use crate::state_backend::proof_backend::merkle::merkle_tree_to_merkle_proof;
51+
use crate::state_backend::proof_backend::merkle::merkle_tree_to_compressed_merkle_tree;
5252
use crate::state_backend::proof_backend::proof::deserialise_owned::ProofTreeDeserialiser;
5353

5454
/// Data structure whose [`Elem`] implementation only writes to part of the given space
@@ -106,7 +106,7 @@ mod tests {
106106

107107
// The Verify mode needs a proof, so we generate it from the Prove mode
108108
let merkle_tree = MerkleTree::from_foldable(&mem_prove);
109-
let proof_tree = merkle_tree_to_merkle_proof(merkle_tree);
109+
let proof_tree = merkle_tree_to_compressed_merkle_tree(merkle_tree).to_proof();
110110
let proof_deser = ProofTreeDeserialiser::from(ProofTree::Present(&proof_tree));
111111
let mut mem_verify = DataSpace::from_proof(proof_deser).unwrap().into_result();
112112

0 commit comments

Comments
 (0)