Skip to content

Commit dec68db

Browse files
[storage/qmdb/current] support split (pyramid) bagging in qmdb-current (#3693)
1 parent 2e641a0 commit dec68db

72 files changed

Lines changed: 1656 additions & 841 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/benchmark-tracking.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ cargo_flags = ["--features", "test-traits"]
4949

5050
[[packages.benchmarks]]
5151
name = "qmdb"
52+
criterion_args = ["--sample-size", "100", "--significance-level", "0.01"]
5253
variants = [
5354
"qmdb::merkleize/variant=any::unordered::fixed::mmr keys=10000 ch=false sync=false",
55+
"qmdb::merkleize/variant=current::ordered::fixed::mmb chunk=256 keys=10000 ch=true sync=false",
5456
]

examples/sync/src/databases/current.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@
77
//! documentation for more details.
88
//!
99
//! For sync, the engine targets the **ops root** (not the canonical root). The operations and proof
10-
//! format are identical to `any` -- the bitmap is reconstructed deterministically from the
11-
//! operations after sync completes. See the [Root structure](commonware_storage::qmdb::current)
12-
//! module documentation for details.
10+
//! format are identical to `any`; direct proof verifiers should use `qmdb::hasher`. The bitmap is
11+
//! reconstructed deterministically from the operations after sync completes. See the
12+
//! [Root structure](commonware_storage::qmdb::current) module documentation for details.
1313
//!
1414
//! This module re-uses the same [`Operation`] type as [`super::any`] since the underlying
1515
//! operations log is the same.

storage/conformance.toml

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -168,35 +168,35 @@ hash = "22374a7cbdfa0bdac17e2e285422a54375fec27017942ef7abea2cf8da298c70"
168168

169169
["commonware_storage::qmdb::conformance::CurrentMmbOrderedFixedConf"]
170170
n_cases = 200
171-
hash = "f265ca1f2f7f571230ef4e576b949d3699b619f108cb0a4e2e28c352f7b32aee"
171+
hash = "c13c9100d657cd01fdf4cff19985bba9e65b7c057391785c5d401a13c976b0af"
172172

173173
["commonware_storage::qmdb::conformance::CurrentMmbOrderedVariableConf"]
174174
n_cases = 200
175-
hash = "74d3a4b1721216ed1bdfc564f5ae07759476b0ceae7dbd1e953c35538a1b0755"
175+
hash = "8fed62bd40fa5ef36f6aebff5152e37d1089e4a66f8dfb9eec8cb00132487efb"
176176

177177
["commonware_storage::qmdb::conformance::CurrentMmbUnorderedFixedConf"]
178178
n_cases = 200
179-
hash = "92b2d71ff19a0f24f337a934d43ee06e3f81a155cd4adc97c58b27cef5cde435"
179+
hash = "81fb100d508803580ae22a96b76955b6480f3526254703c9d75ebb56f0f053f1"
180180

181181
["commonware_storage::qmdb::conformance::CurrentMmbUnorderedVariableConf"]
182182
n_cases = 200
183-
hash = "bad7ded44c7cedc95d202dc3334e3de88877d3aeb63b5808b18bd12c2f59c0d9"
183+
hash = "c46b60791c970b54e936d47a8e2eaae45e9e34c9fb0e1278e678f378392a02f1"
184184

185185
["commonware_storage::qmdb::conformance::CurrentMmrOrderedFixedConf"]
186186
n_cases = 200
187-
hash = "95dc738adeb88d6546c62828e448213fe723d600f57bb4660ecf982ee76e29ef"
187+
hash = "0e5264ac6a0c0d56ace9ebc986635b128f9d7a118471875ad874b08e80f66ebb"
188188

189189
["commonware_storage::qmdb::conformance::CurrentMmrOrderedVariableConf"]
190190
n_cases = 200
191-
hash = "a52a284b8aec813f99234a0545d7c8e651b6f6c93d1912394be3e46075a2681d"
191+
hash = "66cd3cc0299ef062e23d4f9812d5d45896cd808ee0bc65d9745a4265895ae8b5"
192192

193193
["commonware_storage::qmdb::conformance::CurrentMmrUnorderedFixedConf"]
194194
n_cases = 200
195-
hash = "537f4c63d903b112fc045ed47f0127da3e2ca70e38c8406e6535a94b2dddc693"
195+
hash = "8ce052fef8ce8e4d817a2961144cf3a28aec4bd6eb75d32b013499116a6981da"
196196

197197
["commonware_storage::qmdb::conformance::CurrentMmrUnorderedVariableConf"]
198198
n_cases = 200
199-
hash = "93926373351527268aead35fc1884ff27ae2a154df38309dbed50c2c388d4870"
199+
hash = "0d0591823b7d5ed8dcb940d086ec214062eb3cfffd018e9fbadf9e16ce8da0f7"
200200

201201
["commonware_storage::qmdb::conformance::ImmutableMmbCompactFixedConf"]
202202
n_cases = 200

storage/fuzz/fuzz_targets/current_ordered_operations.rs

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ enum CurrentOperation {
5151
bad_digests: Vec<[u8; 32]>,
5252
max_ops: NonZeroU64,
5353
bad_chunks: Vec<[u8; 32]>,
54+
bad_prefix_peaks: Vec<[u8; 32]>,
55+
bad_suffix_peaks: Vec<[u8; 32]>,
5456
},
5557
GetSpan {
5658
key: RawKey,
@@ -267,7 +269,14 @@ fn fuzz_family<F: Graftable>(data: &FuzzInput, suffix: &str) {
267269
}
268270
}
269271

270-
CurrentOperation::ArbitraryProof {start_loc, bad_digests, max_ops, bad_chunks} => {
272+
CurrentOperation::ArbitraryProof {
273+
start_loc,
274+
bad_digests,
275+
max_ops,
276+
bad_chunks,
277+
bad_prefix_peaks,
278+
bad_suffix_peaks,
279+
} => {
271280
let current_op_count = db.bounds().await.end;
272281
if current_op_count == 0 {
273282
continue;
@@ -311,6 +320,36 @@ fn fuzz_family<F: Graftable>(data: &FuzzInput, suffix: &str) {
311320
&root
312321
), "proof with bad chunks should not verify");
313322
}
323+
324+
let bad_prefix_peaks =
325+
bad_prefix_peaks.iter().map(|d| Digest::from(*d)).collect();
326+
if range_proof.unfolded_prefix_peaks != bad_prefix_peaks {
327+
let mut bad_proof = range_proof.clone();
328+
bad_proof.unfolded_prefix_peaks = bad_prefix_peaks;
329+
assert!(!Db::<F>::verify_range_proof(
330+
&mut hasher,
331+
&bad_proof,
332+
start_loc,
333+
&ops,
334+
&chunks,
335+
&root
336+
), "proof with bad prefix peaks should not verify");
337+
}
338+
339+
let bad_suffix_peaks =
340+
bad_suffix_peaks.iter().map(|d| Digest::from(*d)).collect();
341+
if range_proof.unfolded_suffix_peaks != bad_suffix_peaks {
342+
let mut bad_proof = range_proof.clone();
343+
bad_proof.unfolded_suffix_peaks = bad_suffix_peaks;
344+
assert!(!Db::<F>::verify_range_proof(
345+
&mut hasher,
346+
&bad_proof,
347+
start_loc,
348+
&ops,
349+
&chunks,
350+
&root
351+
), "proof with bad suffix peaks should not verify");
352+
}
314353
}
315354
}
316355

storage/fuzz/fuzz_targets/current_unordered_operations.rs

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ enum CurrentOperation {
5151
bad_digests: Vec<[u8; 32]>,
5252
max_ops: NonZeroU64,
5353
bad_chunks: Vec<[u8; 32]>,
54+
bad_prefix_peaks: Vec<[u8; 32]>,
55+
bad_suffix_peaks: Vec<[u8; 32]>,
5456
},
5557
}
5658

@@ -242,7 +244,14 @@ fn fuzz_family<F: Graftable>(data: &FuzzInput, suffix: &str) {
242244
}
243245
}
244246

245-
CurrentOperation::ArbitraryProof {start_loc, bad_digests, max_ops, bad_chunks} => {
247+
CurrentOperation::ArbitraryProof {
248+
start_loc,
249+
bad_digests,
250+
max_ops,
251+
bad_chunks,
252+
bad_prefix_peaks,
253+
bad_suffix_peaks,
254+
} => {
246255
let current_op_count = db.bounds().await.end;
247256
if current_op_count == 0 {
248257
continue;
@@ -283,6 +292,36 @@ fn fuzz_family<F: Graftable>(data: &FuzzInput, suffix: &str) {
283292
&root
284293
), "proof with bad chunks should not verify");
285294
}
295+
296+
let bad_prefix_peaks =
297+
bad_prefix_peaks.iter().map(|d| Digest::from(*d)).collect();
298+
if range_proof.unfolded_prefix_peaks != bad_prefix_peaks {
299+
let mut bad_proof = range_proof.clone();
300+
bad_proof.unfolded_prefix_peaks = bad_prefix_peaks;
301+
assert!(!Db::<F>::verify_range_proof(
302+
&mut hasher,
303+
&bad_proof,
304+
start_loc,
305+
&ops,
306+
&chunks,
307+
&root
308+
), "proof with bad prefix peaks should not verify");
309+
}
310+
311+
let bad_suffix_peaks =
312+
bad_suffix_peaks.iter().map(|d| Digest::from(*d)).collect();
313+
if range_proof.unfolded_suffix_peaks != bad_suffix_peaks {
314+
let mut bad_proof = range_proof.clone();
315+
bad_proof.unfolded_suffix_peaks = bad_suffix_peaks;
316+
assert!(!Db::<F>::verify_range_proof(
317+
&mut hasher,
318+
&bad_proof,
319+
start_loc,
320+
&ops,
321+
&chunks,
322+
&root
323+
), "proof with bad suffix peaks should not verify");
324+
}
286325
}
287326
}
288327

storage/fuzz/fuzz_targets/merkle_family_operations.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ use arbitrary::Arbitrary;
44
use commonware_cryptography::{sha256::Digest, Sha256};
55
use commonware_runtime::{deterministic, Runner};
66
use commonware_storage::merkle::{
7-
hasher::Standard, mem::Mem, mmb, mmr, Error, Family as MerkleFamily, Location, Position,
7+
hasher::Standard, mem::Mem, mmb, mmr, Bagging::ForwardFold, Error, Family as MerkleFamily,
8+
Location, Position,
89
};
910
use core::any::type_name;
1011
use libfuzzer_sys::fuzz_target;
@@ -128,7 +129,7 @@ fn fuzz_family<F: MerkleFamily>(operations: &[MerkleOperation]) {
128129
let runner = deterministic::Runner::default();
129130

130131
runner.start(|_context| async move {
131-
let hasher = Standard::<Sha256>::new();
132+
let hasher = Standard::<Sha256>::new(ForwardFold);
132133
let mut merkle = Mem::<F, Digest>::new();
133134
let mut reference = ReferenceMerkle::<F>::new();
134135

storage/fuzz/fuzz_targets/merkle_full.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ use commonware_cryptography::Sha256;
55
use commonware_parallel::Sequential;
66
use commonware_runtime::{buffer::paged::CacheRef, deterministic, BufferPooler, Metrics, Runner};
77
use commonware_storage::merkle::{
8-
full::Config, hasher::Standard, mem::Mem, mmb, mmr, Error, Family as MerkleFamily, Location,
9-
LocationRangeExt as _, Position,
8+
full::Config, hasher::Standard, mem::Mem, mmb, mmr, Bagging::ForwardFold, Error,
9+
Family as MerkleFamily, Location, LocationRangeExt as _, Position,
1010
};
1111
use commonware_utils::{non_empty_range, NZUsize, NZU16, NZU64};
1212
use libfuzzer_sys::fuzz_target;
@@ -92,7 +92,7 @@ fn historical_root<F: MerkleFamily>(
9292
leaves: &[Vec<u8>],
9393
requested_leaves: Location<F>,
9494
) -> <Sha256 as commonware_cryptography::Hasher>::Digest {
95-
let hasher = Standard::<Sha256>::new();
95+
let hasher = Standard::<Sha256>::new(ForwardFold);
9696
let mut mem = Mem::<F, _>::new();
9797
let batch = {
9898
let mut batch = mem.new_batch();
@@ -115,7 +115,7 @@ fn fuzz_family<F: MerkleFamily>(input: &FuzzInput, suffix: &str) {
115115
let operations = input.operations.clone();
116116
async move {
117117
let mut leaves = Vec::new();
118-
let hasher = Standard::<Sha256>::new();
118+
let hasher = Standard::<Sha256>::new(ForwardFold);
119119
let mut merkle =
120120
Merkle::<F, _, _>::init(context.clone(), &hasher, test_config(suffix, &context))
121121
.await
@@ -258,7 +258,7 @@ fn fuzz_family<F: MerkleFamily>(input: &FuzzInput, suffix: &str) {
258258
.await;
259259
match result {
260260
Ok(historical_proof) => {
261-
let verify_hasher = Standard::<Sha256>::new();
261+
let verify_hasher = Standard::<Sha256>::new(ForwardFold);
262262
assert!(historical_proof.verify_range_inclusion(
263263
&verify_hasher,
264264
&leaves[range.to_usize_range()],

storage/fuzz/fuzz_targets/merkle_full_crash_recovery.rs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ use commonware_runtime::{
1010
buffer::paged::CacheRef, deterministic, BufferPooler, Metrics as _, Runner,
1111
};
1212
use commonware_storage::merkle::{
13-
full::Config, hasher::Standard as StandardHasher, mmb, mmr, Family as MerkleFamily, Location,
13+
full::Config, hasher::Standard as StandardHasher, mmb, mmr, Bagging::ForwardFold,
14+
Family as MerkleFamily, Location,
1415
};
1516
use commonware_utils::NZU64;
1617
use libfuzzer_sys::fuzz_target;
@@ -235,7 +236,7 @@ fn fuzz_family<F: MerkleFamily>(input: &FuzzInput, suffix: &str) {
235236
let partition_suffix = partition_suffix.clone();
236237
let operations = operations.clone();
237238
async move {
238-
let hasher = StandardHasher::<Sha256>::new();
239+
let hasher = StandardHasher::<Sha256>::new(ForwardFold);
239240
let mut merkle = Merkle::<F>::init(
240241
ctx.with_label("merkle"),
241242
&hasher,
@@ -267,7 +268,7 @@ fn fuzz_family<F: MerkleFamily>(input: &FuzzInput, suffix: &str) {
267268
runner.start(|ctx| async move {
268269
*ctx.storage_fault_config().write() = deterministic::FaultConfig::default();
269270

270-
let hasher = StandardHasher::<Sha256>::new();
271+
let hasher = StandardHasher::<Sha256>::new(ForwardFold);
271272
let mut merkle = Merkle::<F>::init(
272273
ctx.with_label("recovered"),
273274
&hasher,

storage/fuzz/fuzz_targets/mmr_bitmap.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use arbitrary::Arbitrary;
44
use commonware_cryptography::{sha256, Digest, Sha256};
55
use commonware_parallel::Sequential;
66
use commonware_runtime::{deterministic, Clock, Metrics, Runner, Storage};
7-
use commonware_storage::{MerkleizedBitMap, UnmerkleizedBitMap};
7+
use commonware_storage::{merkle::Bagging::ForwardFold, MerkleizedBitMap, UnmerkleizedBitMap};
88
use commonware_utils::bitmap::BitMap;
99
use libfuzzer_sys::fuzz_target;
1010

@@ -59,7 +59,7 @@ fn fuzz(input: FuzzInput) {
5959
const PARTITION: &str = "fuzz-mmr-bitmap-test-partition";
6060

6161
runner.start(|context| async move {
62-
let hasher = commonware_storage::mmr::StandardHasher::<Sha256>::new();
62+
let hasher = commonware_storage::mmr::StandardHasher::<Sha256>::new(ForwardFold);
6363
let init_bitmap = MerkleizedBitMap::<_, _, CHUNK_SIZE>::init(
6464
context.with_label("bitmap"),
6565
PARTITION,

storage/fuzz/fuzz_targets/proof_store.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ use arbitrary::{Arbitrary, Unstructured};
44
use commonware_codec::Encode as _;
55
use commonware_cryptography::{sha256::Digest, Sha256};
66
use commonware_storage::merkle::{
7-
self, mmb, mmr, verification::ProofStore, Family as MerkleFamily, Location, Position, Proof,
7+
self, mmb, mmr, verification::ProofStore, Bagging::BackwardFold, Family as MerkleFamily,
8+
Location, Position, Proof,
89
};
910
use libfuzzer_sys::fuzz_target;
1011
use std::ops::Range;
@@ -57,7 +58,7 @@ impl<'a, F: MerkleFamily> Arbitrary<'a> for FuzzInput<F> {
5758
}
5859

5960
fn fuzz_family<F: MerkleFamily>(input: &FuzzInput<F>) {
60-
let hasher = merkle::hasher::Standard::<Sha256>::with_bagging(merkle::Bagging::BackwardFold);
61+
let hasher = merkle::hasher::Standard::<Sha256>::new(BackwardFold);
6162
let proof = Proof::<F, Digest> {
6263
leaves: input.proof_leaves,
6364
inactive_peaks: input.inactive_peaks,

0 commit comments

Comments
 (0)