Skip to content

Commit cb6aefc

Browse files
committed
feat: benchmark MKMapProof generation for multiple leaves
1 parent ca73683 commit cb6aefc

File tree

2 files changed

+86
-18
lines changed

2 files changed

+86
-18
lines changed

mithril-common/benches/merkle_map.rs

+69-18
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use std::ops::Range;
22

33
use criterion::{criterion_group, criterion_main, BenchmarkId, Criterion};
44
use mithril_common::{
5-
crypto_helper::{MKMap, MKMapNode, MKMapProof, MKMapValue, MKTree},
5+
crypto_helper::{MKMap, MKMapNode, MKMapProof, MKMapValue, MKTree, MKTreeNode},
66
entities::BlockRange,
77
};
88

@@ -23,6 +23,7 @@ const TOTAL_TRANSACTIONS_BENCHES: &[u64] = &[
2323
];
2424
const BLOCK_RANGE_LENGTH_BENCH: u64 = 15;
2525
const TOTAL_TRANSACTIONS_PER_BLOCK: u64 = 50;
26+
const MAX_TRANSACTIONS_PER_PROOF_BENCH: u64 = 100;
2627

2728
fn generate_block_ranges_nodes_iterator(
2829
total_transactions: u64,
@@ -32,6 +33,10 @@ fn generate_block_ranges_nodes_iterator(
3233
) -> impl Iterator<Item = (BlockRange, MKMapNode<BlockRange>)> {
3334
let total_block_ranges =
3435
total_transactions / (total_transactions_per_block * block_range_length);
36+
assert!(
37+
total_block_ranges > 0,
38+
"total_block_ranges should be strictly greater than 0"
39+
);
3540
(0..total_block_ranges).map(move |block_range_index| {
3641
let block_range = BlockRange::new(
3742
block_range_index * total_transactions_per_block * block_range_length,
@@ -55,15 +60,15 @@ fn generate_merkle_map_compressed(
5560
block_ranges_nodes_iterator: impl Iterator<Item = (BlockRange, MKMapNode<BlockRange>)>,
5661
) -> MKMap<BlockRange, MKMapNode<BlockRange>> {
5762
let mut mk_map = MKMap::new(&[]).unwrap();
58-
for (block_range, mk_tree) in block_ranges_nodes_iterator {
63+
for (block_range, mk_map_node) in block_ranges_nodes_iterator {
5964
mk_map
60-
.insert(block_range, mk_tree.compute_root().unwrap().into())
65+
.insert(block_range, mk_map_node.compute_root().unwrap().into())
6166
.unwrap();
6267
}
6368
mk_map
6469
}
6570

66-
fn generate_merkle_map_proof(
71+
fn generate_merkle_map_root(
6772
block_ranges_nodes_iterator: impl Iterator<Item = (BlockRange, MKMapNode<BlockRange>)>,
6873
mk_map_compressed: &MKMap<BlockRange, MKMapNode<BlockRange>>,
6974
) -> MKMapProof<BlockRange> {
@@ -72,7 +77,7 @@ fn generate_merkle_map_proof(
7277
let mktree_to_prove = if let MKMapNode::Tree(mktree_to_prove) = mk_map_node_to_prove {
7378
mktree_to_prove
7479
} else {
75-
panic!("Expected MKMapNode::TreeNode");
80+
panic!("Expected MKMapNode::Tree");
7681
};
7782
let leaves_to_prove = mktree_to_prove
7883
.leaves()
@@ -89,9 +94,43 @@ fn generate_merkle_map_proof(
8994
mk_map_compressed.compute_proof(&leaves_to_prove).unwrap()
9095
}
9196

92-
fn create_merkle_map_compressed_benches(c: &mut Criterion) {
97+
fn generate_merkle_map_proof(
98+
block_ranges_nodes_iterator: impl Iterator<Item = (BlockRange, MKMapNode<BlockRange>)>,
99+
mk_map_compressed: &MKMap<BlockRange, MKMapNode<BlockRange>>,
100+
total_proofs: u64,
101+
) -> MKMapProof<BlockRange> {
102+
let mut leaves_to_prove_all: Vec<MKTreeNode> = vec![];
103+
let mut mk_map_compressed = mk_map_compressed.clone();
104+
for (mk_map_key_to_prove, mk_map_node_to_prove) in &block_ranges_nodes_iterator
105+
.take(total_proofs as usize)
106+
.collect::<Vec<_>>()
107+
{
108+
let mktree_to_prove = if let MKMapNode::Tree(mktree_to_prove) = mk_map_node_to_prove {
109+
mktree_to_prove
110+
} else {
111+
panic!("Expected MKMapNode::Tree");
112+
};
113+
let leaves_to_prove = mktree_to_prove
114+
.leaves()
115+
.into_iter()
116+
.take(1)
117+
.collect::<Vec<_>>();
118+
leaves_to_prove_all.extend(leaves_to_prove);
119+
mk_map_compressed
120+
.insert(
121+
mk_map_key_to_prove.to_owned(),
122+
mk_map_node_to_prove.to_owned(),
123+
)
124+
.unwrap();
125+
}
126+
mk_map_compressed
127+
.compute_proof(&leaves_to_prove_all)
128+
.unwrap()
129+
}
130+
131+
fn create_merkle_map_root_benches(c: &mut Criterion) {
93132
let mut group = c.benchmark_group(format!(
94-
"create_merkle_map_compressed(blocks_ranges_length={BLOCK_RANGE_LENGTH_BENCH},txs_per_block={TOTAL_TRANSACTIONS_PER_BLOCK})"
133+
"create_merkle_map_root(blocks_ranges_length={BLOCK_RANGE_LENGTH_BENCH},txs_per_block={TOTAL_TRANSACTIONS_PER_BLOCK})"
95134
));
96135
for total_leaves in TOTAL_TRANSACTIONS_BENCHES.iter() {
97136
let mk_trees_by_block_range_iterator = generate_block_ranges_nodes_iterator(
@@ -106,8 +145,13 @@ fn create_merkle_map_compressed_benches(c: &mut Criterion) {
106145
total_leaves,
107146
|b, &_total_leaves| {
108147
b.iter(|| {
109-
let mk_map_compressed_clone = mk_map_compressed.clone();
110-
mk_map_compressed_clone.compute_root().unwrap();
148+
let mk_trees_by_block_range_iterator = generate_block_ranges_nodes_iterator(
149+
*total_leaves,
150+
TOTAL_TRANSACTIONS_PER_BLOCK,
151+
BLOCK_RANGE_LENGTH_BENCH,
152+
1,
153+
);
154+
generate_merkle_map_root(mk_trees_by_block_range_iterator, &mk_map_compressed);
111155
});
112156
},
113157
);
@@ -117,14 +161,14 @@ fn create_merkle_map_compressed_benches(c: &mut Criterion) {
117161

118162
fn create_merkle_map_proof_benches(c: &mut Criterion) {
119163
let mut group = c.benchmark_group(format!(
120-
"create_merkle_map_proof_(blocks_ranges_length={BLOCK_RANGE_LENGTH_BENCH},txs_per_block={TOTAL_TRANSACTIONS_PER_BLOCK})"
164+
"create_merkle_map_proof_(blocks_ranges_length={BLOCK_RANGE_LENGTH_BENCH},txs_per_block={TOTAL_TRANSACTIONS_PER_BLOCK},txs_per_proof={MAX_TRANSACTIONS_PER_PROOF_BENCH})"
121165
));
122166
for total_leaves in TOTAL_TRANSACTIONS_BENCHES.iter() {
123167
let mk_trees_by_block_range_iterator = generate_block_ranges_nodes_iterator(
124168
*total_leaves,
125169
TOTAL_TRANSACTIONS_PER_BLOCK,
126170
BLOCK_RANGE_LENGTH_BENCH,
127-
1,
171+
MAX_TRANSACTIONS_PER_PROOF_BENCH,
128172
);
129173
let mk_map_compressed = generate_merkle_map_compressed(mk_trees_by_block_range_iterator);
130174

@@ -137,9 +181,13 @@ fn create_merkle_map_proof_benches(c: &mut Criterion) {
137181
*total_leaves,
138182
TOTAL_TRANSACTIONS_PER_BLOCK,
139183
BLOCK_RANGE_LENGTH_BENCH,
140-
1,
184+
MAX_TRANSACTIONS_PER_PROOF_BENCH,
185+
);
186+
generate_merkle_map_proof(
187+
mk_trees_by_block_range_iterator,
188+
&mk_map_compressed,
189+
MAX_TRANSACTIONS_PER_PROOF_BENCH,
141190
);
142-
generate_merkle_map_proof(mk_trees_by_block_range_iterator, &mk_map_compressed);
143191
});
144192
},
145193
);
@@ -149,7 +197,7 @@ fn create_merkle_map_proof_benches(c: &mut Criterion) {
149197

150198
fn verify_merkle_map_proof_benches(c: &mut Criterion) {
151199
let mut group = c.benchmark_group(format!(
152-
"verify_merkle_map_proof_(blocks_ranges_length={BLOCK_RANGE_LENGTH_BENCH},txs_per_block={TOTAL_TRANSACTIONS_PER_BLOCK})"
200+
"verify_merkle_map_proof_(blocks_ranges_length={BLOCK_RANGE_LENGTH_BENCH},txs_per_block={TOTAL_TRANSACTIONS_PER_BLOCK},txs_per_proof={MAX_TRANSACTIONS_PER_PROOF_BENCH})"
153201
));
154202
for total_leaves in TOTAL_TRANSACTIONS_BENCHES.iter() {
155203
let mk_trees_by_block_range_iterator = generate_block_ranges_nodes_iterator(
@@ -163,10 +211,13 @@ fn verify_merkle_map_proof_benches(c: &mut Criterion) {
163211
*total_leaves,
164212
TOTAL_TRANSACTIONS_PER_BLOCK,
165213
BLOCK_RANGE_LENGTH_BENCH,
166-
1,
214+
MAX_TRANSACTIONS_PER_PROOF_BENCH,
215+
);
216+
let mk_map_proof = generate_merkle_map_proof(
217+
mk_trees_by_block_range_iterator,
218+
&mk_map_compressed,
219+
MAX_TRANSACTIONS_PER_PROOF_BENCH,
167220
);
168-
let mk_map_proof =
169-
generate_merkle_map_proof(mk_trees_by_block_range_iterator, &mk_map_compressed);
170221

171222
group.bench_with_input(
172223
BenchmarkId::from_parameter(total_leaves),
@@ -183,7 +234,7 @@ criterion_group!(
183234
name = benches;
184235
config = Criterion::default().sample_size(10);
185236
targets =
186-
create_merkle_map_compressed_benches,
237+
create_merkle_map_root_benches,
187238
create_merkle_map_proof_benches,
188239
verify_merkle_map_proof_benches
189240
);

mithril-common/src/crypto_helper/merkle_map.rs

+17
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,9 @@ impl<K: MKMapKey, V: MKMapValue<K>> MKMap<K, V> {
122122
&self,
123123
leaves: &[T],
124124
) -> StdResult<MKMapProof<K>> {
125+
if leaves.is_empty() {
126+
return Err(anyhow!("MKMap could not compute proof for empty leaves"));
127+
}
125128
let leaves_by_keys: HashMap<K, Vec<MKTreeNode>> = leaves
126129
.iter()
127130
.filter_map(|leaf| match self.contains(&leaf.to_owned().into()) {
@@ -537,6 +540,20 @@ mod tests {
537540
);
538541
}
539542

543+
#[test]
544+
fn test_mk_map_should_not_compute_proof_for_no_leaves() {
545+
let entries = generate_merkle_trees(100000, 100);
546+
let mktree_nodes_to_certify: &[MKTreeNode] = &[];
547+
let merkle_tree_node_entries = &entries
548+
.into_iter()
549+
.map(|(range, mktree)| (range.to_owned(), mktree.into()))
550+
.collect::<Vec<(_, MKMapNode<_>)>>();
551+
let mk_map_full = MKMap::new(merkle_tree_node_entries.as_slice()).unwrap();
552+
mk_map_full
553+
.compute_proof(mktree_nodes_to_certify)
554+
.expect_err("MKMap should not compute proof for no leaves");
555+
}
556+
540557
#[test]
541558
fn test_mk_map_should_compute_and_verify_valid_proof() {
542559
let entries = generate_merkle_trees(100000, 100);

0 commit comments

Comments
 (0)