Skip to content
Merged
42 changes: 30 additions & 12 deletions examples/sync/src/databases/keyless.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
//! Keyless database types and helpers for the sync example.
//!
//! A `keyless` database is append-only: operations are stored by location rather than by key.
//! It supports `Append(value)` and `Commit(metadata)` operations. For sync, the engine targets
//! the Merkle root over all operations, and the client reconstructs the same state by replaying
//! the fetched operations.
//! It supports `Append(value)` and `Commit(metadata, floor)` operations. For sync, the engine
//! targets the Merkle root over all operations, and the client reconstructs the same state by
//! replaying the fetched operations.

use crate::{Hasher, Key, Value};
use commonware_cryptography::{Hasher as CryptoHasher, Sha256};
Expand All @@ -28,7 +28,7 @@ use tracing::error;
pub type Database<E> = fixed::Db<mmr::Family, E, Value, Hasher>;

/// Operation type alias.
pub type Operation = fixed::Operation<Value>;
pub type Operation = fixed::Operation<mmr::Family, Value>;

/// Create a database configuration for the keyless variant.
pub fn create_config(context: &(impl BufferPooler + commonware_runtime::Metrics)) -> fixed::Config {
Expand Down Expand Up @@ -56,11 +56,23 @@ pub fn create_config(context: &(impl BufferPooler + commonware_runtime::Metrics)
}

/// Create deterministic test operations for demonstration purposes.
/// Generates Append operations and periodic Commit operations.
///
/// Generates Append operations and periodic Commit operations, advancing the inactivity
/// floor at each commit to the *previous* commit's location. This models a realistic
/// application that declares older commits inactive over time (enabling pruning) while
/// always keeping the most recent commit readable.
pub fn create_test_operations(count: usize, seed: u64) -> Vec<Operation> {
let mut operations = Vec::new();
let mut hasher = <Hasher as CryptoHasher>::new();

// The DB's initial commit lands at location 0 before any of these ops are applied.
// `op_count` tracks the total ops that will exist on disk (including this initial commit
// and everything we push below). `prev_commit_loc` tracks the last commit's location
// and is used as the next commit's floor — always <= the next commit's own location, so
// the per-commit floor bound is satisfied.
let mut op_count: u64 = 1;
let mut prev_commit_loc: u64 = 0;

for i in 0..count {
let value = {
hasher.update(&i.to_be_bytes());
Expand All @@ -69,14 +81,20 @@ pub fn create_test_operations(count: usize, seed: u64) -> Vec<Operation> {
};

operations.push(Operation::Append(value));
op_count += 1;

if (i + 1) % 10 == 0 {
operations.push(Operation::Commit(None));
operations.push(Operation::Commit(None, Location::new(prev_commit_loc)));
prev_commit_loc = op_count;
op_count += 1;
}
}

// Always end with a commit
operations.push(Operation::Commit(Some(Sha256::fill(1))));
// Always end with a commit, floor set to the previous commit's location.
operations.push(Operation::Commit(
Some(Sha256::fill(1)),
Location::new(prev_commit_loc),
));
operations
}

Expand Down Expand Up @@ -107,8 +125,8 @@ where
Operation::Append(value) => {
batch = batch.append(value);
}
Operation::Commit(metadata) => {
let merkleized = batch.merkleize(self, metadata);
Operation::Commit(metadata, floor) => {
let merkleized = batch.merkleize(self, metadata, floor);
self.apply_batch(merkleized).await?;
self.commit().await?;
batch = self.new_batch();
Expand All @@ -127,7 +145,7 @@ where
}

async fn sync_boundary(&self) -> Location {
self.sync_boundary().await
self.sync_boundary()
}

async fn historical_proof(
Expand Down Expand Up @@ -161,7 +179,7 @@ mod tests {
let ops = <KeylessDb as Syncable>::create_test_operations(5, 12345);
assert_eq!(ops.len(), 6); // 5 operations + 1 commit

if let Operation::Commit(Some(_)) = &ops[5] {
if let Operation::Commit(Some(_), _) = &ops[5] {
// ok
} else {
panic!("last operation should be a commit with metadata");
Expand Down
16 changes: 8 additions & 8 deletions storage/conformance.toml
Original file line number Diff line number Diff line change
Expand Up @@ -220,19 +220,19 @@ hash = "f32fda4f6c0bbde62f8f1959edeb2ac67b28f5347bd108e4118e740aa1fd8fd1"

["commonware_storage::qmdb::conformance::KeylessMmbFixedConf"]
n_cases = 200
hash = "41f832011239e8d76ded66ea5e2559a6eaeb6ef65875b9d50db1296a2f26e5f8"
hash = "d9ad4deb528e8bc514d028efa34e9b31b6642584c8a0c0e98c7a6d9b36f355df"

["commonware_storage::qmdb::conformance::KeylessMmbVariableConf"]
n_cases = 200
hash = "ce612a2c4c3c43db5e797cdeff7df04b872660529ccdfb825feb0efcaaf322a3"
hash = "c1f535aaa1a4ff8d8594b70d4d121a2ee48c342a68c8549c4b411d299cfa43dc"

["commonware_storage::qmdb::conformance::KeylessMmrFixedConf"]
n_cases = 200
hash = "79ac92e88026d3d73d1cf37edf85fcd82a5fd6824566b05fe04d0ad1fd7ec9e0"
hash = "49c54ba4ea198f1e5811abfb3a1a077925d1075b006c620cb3e4aa3769c997cb"

["commonware_storage::qmdb::conformance::KeylessMmrVariableConf"]
n_cases = 200
hash = "aa70f866ae6b4104e94c741f46806a430b2ce76e3af5798ba2fb23dff6d1fbd9"
hash = "aee37bfef687a6855e53f2e4a2ef7190cf9d33cdb67b5e177a7f56f7b44e4b9b"

["commonware_storage::qmdb::immutable::operation::fixed::tests::conformance::CodecConformance<FixedOp>"]
n_cases = 65536
Expand All @@ -246,13 +246,13 @@ hash = "cce5f888e506282f861e0e49e176b26c65f92e457f0c5f5353fc9b7196f07478"
n_cases = 65536
hash = "fdca5df62d243b28676ee15034663694cd219d5ef80749079126b0ed73effe0d"

["commonware_storage::qmdb::keyless::operation::tests::conformance::CodecConformance<Operation<FixedEncoding<U64>>>"]
["commonware_storage::qmdb::keyless::operation::tests::conformance::CodecConformance<Operation<mmr::Family,FixedEncoding<U64>>>"]
n_cases = 65536
hash = "c692a20fa40180844888e7a26401f99a45ce3127faeca5f1228a41b454424623"
hash = "1ad07a5388e328474b353c153617b6a8a3a4713a9895f3f505148f919c49b86d"

["commonware_storage::qmdb::keyless::operation::tests::conformance::CodecConformance<Operation<VariableEncoding<U64>>>"]
["commonware_storage::qmdb::keyless::operation::tests::conformance::CodecConformance<Operation<mmr::Family,VariableEncoding<U64>>>"]
n_cases = 65536
hash = "b41d6c6ec560bde9caf2e206526864c618a0721af367585a1719617ca7ce9291"
hash = "c6702e8b8d2e96438df00786289df9ee4ec92a767974fa1484766a246ebc71b7"

["commonware_storage::qmdb::sync::target::tests::conformance::CodecConformance<Target<MmrFamily,sha256::Digest>>"]
n_cases = 65536
Expand Down
Loading
Loading