//! A keyless authenticated database for fixed-size data. //! //! For variable-size values, use [super::variable]. use crate::{ journal::{ authenticated, contiguous::fixed::{self, Config as JournalConfig}, }, merkle::Family, qmdb::{ any::value::{FixedEncoding, FixedValue}, keyless::operation::Operation as BaseOperation, operation::Committable, Error, ROOT_BAGGING, }, }; use commonware_cryptography::Hasher; use commonware_parallel::Strategy; use commonware_runtime::{Clock, Metrics, Storage}; /// Keyless operation for fixed-size values. pub type Operation = BaseOperation>; /// A keyless authenticated database for fixed-size data. pub type Db = super::Keyless, fixed::Journal>, H, S>; /// A compact keyless authenticated db for fixed-size data. pub type CompactDb = super::CompactDb, H, (), S>; type Journal = authenticated::Journal>, H, S>; /// Configuration for a fixed-size [keyless](super) authenticated db. pub type Config = super::Config; /// Configuration for a fixed-size [keyless](super) compact db. pub type CompactConfig = super::CompactConfig<(), S>; impl Db { /// Returns a [Db] initialized from `cfg`. Any uncommitted operations will be /// discarded and the state of the db will be as of the last committed operation. pub async fn init(context: E, cfg: Config) -> Result> { let journal: Journal = Journal::new( context.child("journal"), cfg.merkle, cfg.log, Operation::::is_commit, ROOT_BAGGING, ) .await?; Self::init_from_journal(journal, context).await } } impl CompactDb { /// Returns a [CompactDb] initialized from `cfg`. pub async fn init(context: E, cfg: CompactConfig) -> Result> { let merkle = crate::merkle::compact::Merkle::init(context, cfg.merkle).await?; Self::init_from_merkle(merkle, ()).await } } #[cfg(test)] mod test { use super::*; use crate::{ merkle::{mmb, mmr}, qmdb::keyless::tests, }; use commonware_cryptography::Sha256; use commonware_macros::test_traced; use commonware_parallel::{Rayon, Sequential, Strategy}; use commonware_runtime::{ buffer::paged::CacheRef, deterministic, BufferPooler, Runner as _, Supervisor as _, }; use commonware_utils::{NZUsize, NZU16, NZU64}; use std::num::{NonZeroU16, NonZeroUsize}; const PAGE_SIZE: NonZeroU16 = NZU16!(101); const PAGE_CACHE_SIZE: NonZeroUsize = NZUsize!(11); fn db_config(suffix: &str, pooler: &impl BufferPooler, strategy: S) -> Config { let page_cache = CacheRef::from_pooler(pooler, PAGE_SIZE, PAGE_CACHE_SIZE); Config { merkle: crate::merkle::full::Config { journal_partition: format!("fixed-journal-{suffix}"), metadata_partition: format!("fixed-metadata-{suffix}"), items_per_blob: NZU64!(11), write_buffer: NZUsize!(1024), strategy, page_cache: page_cache.clone(), }, log: JournalConfig { partition: format!("fixed-log-journal-{suffix}"), items_per_blob: NZU64!(7), page_cache, write_buffer: NZUsize!(1024), }, } } type TestDb = Db; type TestRayonDb = Db; type TestCompactDb = CompactDb; async fn open_db(context: deterministic::Context) -> TestDb { open_db_with_suffix("partition", context).await } async fn open_db_with_suffix( suffix: &str, context: deterministic::Context, ) -> TestDb { let cfg = db_config(suffix, &context, Sequential); TestDb::init(context, cfg).await.unwrap() } async fn open_rayon_db(context: deterministic::Context) -> TestRayonDb { let cfg = db_config("rayon", &context, Rayon::new(NZUsize!(2)).unwrap()); TestRayonDb::init(context, cfg).await.unwrap() } async fn open_compact( context: deterministic::Context, ) -> TestCompactDb { let cfg = CompactConfig { merkle: crate::merkle::compact::Config { partition: "compact-keyless-fixed".into(), strategy: Sequential, }, commit_codec_config: (), }; TestCompactDb::init(context, cfg).await.unwrap() } fn reopen() -> tests::Reopen> { Box::new(|ctx| Box::pin(open_db(ctx))) } #[test_traced("INFO")] fn test_keyless_fixed_metrics() { deterministic::Runner::default().start(|ctx| async move { let mut db = open_db::(ctx.child("db")).await; let value = commonware_utils::sequence::U64::new(7); let floor = db.inactivity_floor_loc(); let batch = db .new_batch() .append(value.clone()) .merkleize(&db, None, floor); let range = db.apply_batch(batch).await.unwrap(); assert_eq!(db.get(range.start).await.unwrap(), Some(value.clone())); assert_eq!( db.get_many(&[range.start]).await.unwrap(), vec![Some(value)] ); db.commit().await.unwrap(); db.sync().await.unwrap(); db.prune(crate::merkle::Location::new(0)).await.unwrap(); let metrics = ctx.encode(); for expected in [ "db_size 3", "db_pruning_boundary 0", "db_retained 3", "db_inactivity_floor 0", "db_last_commit 2", "db_get_calls_total 1", "db_get_many_calls_total 1", "db_locations_requested_total 2", "db_apply_batch_calls_total 1", "db_operations_applied_total 2", "db_commit_calls_total 1", "db_sync_calls_total 1", "db_prune_calls_total 1", "db_get_duration_count 1", "db_get_many_duration_count 1", "db_apply_batch_duration_count 1", "db_commit_duration_count 1", "db_sync_duration_count 1", "db_prune_duration_count 1", ] { assert!(metrics.contains(expected), "missing {expected}\n{metrics}"); } }); } #[test_traced("INFO")] fn test_keyless_fixed_empty() { deterministic::Runner::default().start(|ctx| async move { let db = open_db::(ctx.child("db").with_attribute("index", 1)).await; tests::test_keyless_db_empty(ctx, db, reopen::()).await; }); } #[test_traced("WARN")] fn test_keyless_fixed_build_basic() { deterministic::Runner::default().start(|ctx| async move { let db = open_db::(ctx.child("db").with_attribute("index", 1)).await; tests::test_keyless_db_build_basic(ctx, db, reopen::()).await; }); } #[test_traced("WARN")] fn test_keyless_fixed_recovery() { deterministic::Runner::default().start(|ctx| async move { let db = open_db::(ctx.child("db").with_attribute("index", 1)).await; tests::test_keyless_db_recovery(ctx, db, reopen::()).await; }); } #[test_traced("WARN")] fn test_keyless_fixed_non_empty_recovery() { deterministic::Runner::default().start(|ctx| async move { let db = open_db::(ctx.child("db").with_attribute("index", 1)).await; tests::test_keyless_db_non_empty_recovery(ctx, db, reopen::()).await; }); } #[test_traced("INFO")] fn test_keyless_fixed_proof() { deterministic::Runner::default().start(|ctx| async move { let db = open_db::(ctx.child("storage")).await; tests::test_keyless_db_proof(db).await; }); } #[test_traced("INFO")] fn test_keyless_fixed_proof_comprehensive() { deterministic::Runner::default().start(|ctx| async move { let db = open_db::(ctx.child("storage")).await; tests::test_keyless_db_proof_comprehensive(db).await; }); } #[test_traced("INFO")] fn test_keyless_fixed_proof_with_pruning() { deterministic::Runner::default().start(|ctx| async move { let db = open_db::(ctx.child("db").with_attribute("index", 1)).await; tests::test_keyless_db_proof_with_pruning(ctx, db, reopen::()).await; }); } #[test_traced("WARN")] fn test_keyless_fixed_empty_db_recovery() { deterministic::Runner::default().start(|ctx| async move { let db = open_db::(ctx.child("db").with_attribute("index", 1)).await; tests::test_keyless_db_empty_db_recovery(ctx, db, reopen::()).await; }); } #[test_traced("WARN")] fn test_keyless_fixed_replay_with_trailing_appends() { deterministic::Runner::default().start(|ctx| async move { let db = open_db::(ctx.child("db").with_attribute("index", 1)).await; tests::test_keyless_db_replay_with_trailing_appends(ctx, db, reopen::()) .await; }); } #[test_traced("INFO")] fn test_keyless_fixed_get_out_of_bounds() { deterministic::Runner::default().start(|ctx| async move { let db = open_db::(ctx.child("storage")).await; tests::test_keyless_db_get_out_of_bounds(db).await; }); } #[test_traced("INFO")] fn test_keyless_fixed_metadata() { deterministic::Runner::default().start(|ctx| async move { let db = open_db::(ctx.child("db")).await; tests::test_keyless_db_metadata(db).await; }); } #[test_traced("INFO")] fn test_keyless_fixed_shared_helper_accepts_rayon_strategy() { deterministic::Runner::default().start(|ctx| async move { let db = open_rayon_db::(ctx.child("db").with_attribute("index", 1)).await; tests::test_keyless_db_metadata(db).await; }); } async fn assert_compact_root_compatibility( ctx: deterministic::Context, ) { let mut db = open_db::(ctx.child("db")).await; let mut compact = open_compact::(ctx.child("compact")).await; assert_eq!(db.root(), compact.root()); let v1 = commonware_utils::sequence::U64::new(1); let v2 = commonware_utils::sequence::U64::new(2); let metadata = commonware_utils::sequence::U64::new(99); let floor = db.inactivity_floor_loc(); let retained = db .new_batch() .append(v1.clone()) .append(v2.clone()) .merkleize(&db, Some(metadata.clone()), floor); let compact_batch = compact.new_batch().append(v1).append(v2).merkleize( &compact, Some(metadata.clone()), floor, ); assert_eq!(retained.root(), compact_batch.root()); db.apply_batch(retained).await.unwrap(); compact.apply_batch(compact_batch).unwrap(); db.commit().await.unwrap(); compact.commit().await.unwrap(); assert_eq!(db.root(), compact.root()); assert_eq!(compact.get_metadata(), Some(metadata.clone())); drop(compact); let reopened = open_compact::(ctx.child("reopen")).await; assert_eq!(db.root(), reopened.root()); assert_eq!(reopened.get_metadata(), Some(metadata)); reopened.destroy().await.unwrap(); db.destroy().await.unwrap(); } #[test_traced("INFO")] fn test_keyless_fixed_compact_root_compatibility() { deterministic::Runner::default().start(|ctx| async move { assert_compact_root_compatibility::(ctx).await; }); } #[test_traced("INFO")] fn test_keyless_fixed_compact_root_compatibility_mmb() { deterministic::Runner::default().start(|ctx| async move { assert_compact_root_compatibility::(ctx).await; }); } #[test_traced("INFO")] fn test_keyless_fixed_pruning() { deterministic::Runner::default().start(|ctx| async move { let db = open_db::(ctx.child("db")).await; tests::test_keyless_db_pruning(db).await; }); } #[test_traced("INFO")] fn test_keyless_fixed_batch_get() { deterministic::Runner::default().start(|ctx| async move { let db = open_db::(ctx.child("db")).await; tests::test_keyless_batch_get(db).await; }); } #[test_traced("INFO")] fn test_keyless_fixed_batch_stacked_get() { deterministic::Runner::default().start(|ctx| async move { let db = open_db::(ctx.child("db")).await; tests::test_keyless_batch_stacked_get(db).await; }); } #[test_traced("INFO")] fn test_keyless_fixed_batch_speculative_root() { deterministic::Runner::default().start(|ctx| async move { let db = open_db::(ctx.child("db")).await; tests::test_keyless_batch_speculative_root(db).await; }); } #[test_traced("INFO")] fn test_keyless_fixed_merkleized_batch_get() { deterministic::Runner::default().start(|ctx| async move { let db = open_db::(ctx.child("db")).await; tests::test_keyless_merkleized_batch_get(db).await; }); } #[test_traced("INFO")] fn test_keyless_fixed_get_many() { deterministic::Runner::default().start(|ctx| async move { let db = open_db::(ctx.child("db")).await; tests::test_keyless_get_many(db).await; }); } #[test_traced("INFO")] fn test_keyless_fixed_batch_chained() { deterministic::Runner::default().start(|ctx| async move { let db = open_db::(ctx.child("db")).await; tests::test_keyless_batch_chained(db).await; }); } #[test_traced("INFO")] fn test_keyless_fixed_batch_chained_apply_sequential() { deterministic::Runner::default().start(|ctx| async move { let db = open_db::(ctx.child("db")).await; tests::test_keyless_batch_chained_apply_sequential(db).await; }); } #[test_traced("INFO")] fn test_keyless_fixed_batch_many_sequential() { deterministic::Runner::default().start(|ctx| async move { let db = open_db::(ctx.child("db")).await; tests::test_keyless_batch_many_sequential(db).await; }); } #[test_traced("INFO")] fn test_keyless_fixed_batch_empty() { deterministic::Runner::default().start(|ctx| async move { let db = open_db::(ctx.child("db")).await; tests::test_keyless_batch_empty(db).await; }); } #[test_traced("INFO")] fn test_keyless_fixed_batch_chained_merkleized_get() { deterministic::Runner::default().start(|ctx| async move { let db = open_db::(ctx.child("db")).await; tests::test_keyless_batch_chained_merkleized_get(db).await; }); } #[test_traced("INFO")] fn test_keyless_fixed_batch_large() { deterministic::Runner::default().start(|ctx| async move { let db = open_db::(ctx.child("db")).await; tests::test_keyless_batch_large(db).await; }); } #[test_traced] fn test_keyless_fixed_stale_batch() { deterministic::Runner::default().start(|ctx| async move { let db = open_db::(ctx.child("db")).await; tests::test_keyless_stale_batch(db).await; }); } #[test_traced] fn test_keyless_fixed_stale_batch_chained() { deterministic::Runner::default().start(|ctx| async move { let db = open_db::(ctx.child("db")).await; tests::test_keyless_stale_batch_chained(db).await; }); } #[test_traced] fn test_keyless_fixed_sequential_commit_parent_then_child() { deterministic::Runner::default().start(|ctx| async move { let db = open_db::(ctx.child("db")).await; tests::test_keyless_sequential_commit_parent_then_child(db).await; }); } #[test_traced] fn test_keyless_fixed_stale_batch_child_before_parent() { deterministic::Runner::default().start(|ctx| async move { let db = open_db::(ctx.child("db")).await; tests::test_keyless_stale_batch_child_before_parent(db).await; }); } #[test_traced] fn test_keyless_fixed_to_batch() { deterministic::Runner::default().start(|ctx| async move { let db = open_db::(ctx.child("db")).await; tests::test_keyless_to_batch(db).await; }); } #[test_traced] fn test_keyless_fixed_child_root_matches_pending_and_committed() { deterministic::Runner::default().start(|ctx| async move { let db = open_db::(ctx.child("db")).await; tests::test_keyless_child_root_matches_pending_and_committed(db).await; }); } #[test_traced("INFO")] fn test_keyless_fixed_rewind_recovery() { deterministic::Runner::default().start(|ctx| async move { let db = open_db::(ctx.child("db")).await; tests::test_keyless_db_rewind_recovery(ctx, db, reopen::()).await; }); } #[test_traced("INFO")] fn test_keyless_fixed_rewind_pruned_target_errors() { deterministic::Runner::default().start(|ctx| async move { let db = open_db::(ctx.child("db")).await; tests::test_keyless_db_rewind_pruned_target_errors(db).await; }); } #[test_traced("INFO")] fn test_keyless_fixed_floor_tracking() { deterministic::Runner::default().start(|ctx| async move { let db = open_db::(ctx.child("db").with_attribute("index", 1)).await; tests::test_keyless_db_floor_tracking(ctx, db, reopen::()).await; }); } #[test_traced("INFO")] fn test_keyless_fixed_floor_regression_rejected() { deterministic::Runner::default().start(|ctx| async move { let db = open_db::(ctx.child("db")).await; tests::test_keyless_db_floor_regression_rejected(db).await; }); } #[test_traced("INFO")] fn test_keyless_fixed_floor_beyond_commit_loc_rejected() { deterministic::Runner::default().start(|ctx| async move { let db = open_db::(ctx.child("db")).await; tests::test_keyless_db_floor_beyond_commit_loc_rejected(db).await; }); } #[test_traced("INFO")] fn test_keyless_fixed_rewind_restores_floor() { deterministic::Runner::default().start(|ctx| async move { let db = open_db::(ctx.child("db")).await; tests::test_keyless_db_rewind_restores_floor(db).await; }); } #[test_traced("INFO")] fn test_keyless_fixed_floor_changes_root() { deterministic::Runner::default().start(|ctx| async move { let db_a = open_db_with_suffix::("root-a", ctx.child("a")).await; let db_b = open_db_with_suffix::("root-b", ctx.child("b")).await; tests::test_keyless_db_floor_changes_root(db_a, db_b).await; }); } #[test_traced("INFO")] fn test_keyless_fixed_floor_at_commit_loc_accepted() { deterministic::Runner::default().start(|ctx| async move { let db = open_db::(ctx.child("db")).await; tests::test_keyless_db_floor_at_commit_loc_accepted(db).await; }); } #[test_traced("INFO")] fn test_keyless_fixed_rewind_after_reopen_with_floor() { deterministic::Runner::default().start(|ctx| async move { let db = open_db::(ctx.child("db").with_attribute("index", 1)).await; tests::test_keyless_db_rewind_after_reopen_with_floor(ctx, db, reopen::()) .await; }); } #[test_traced("INFO")] fn test_keyless_fixed_ancestor_floor_regression_rejected() { deterministic::Runner::default().start(|ctx| async move { let db = open_db::(ctx.child("db")).await; tests::test_keyless_db_ancestor_floor_regression_rejected(db).await; }); } #[test_traced("INFO")] fn test_keyless_fixed_ancestor_floor_beyond_commit_loc_rejected() { deterministic::Runner::default().start(|ctx| async move { let db = open_db::(ctx.child("db")).await; tests::test_keyless_db_ancestor_floor_beyond_commit_loc_rejected(db).await; }); } #[test_traced("INFO")] fn test_keyless_fixed_chained_apply_with_valid_floors_succeeds() { deterministic::Runner::default().start(|ctx| async move { let db = open_db::(ctx.child("db")).await; tests::test_keyless_db_chained_apply_with_valid_floors_succeeds(db).await; }); } #[test_traced("INFO")] fn test_keyless_fixed_single_commit_live_set() { deterministic::Runner::default().start(|ctx| async move { let db = open_db::(ctx.child("db").with_attribute("index", 1)).await; tests::test_keyless_db_single_commit_live_set(ctx, db, reopen::()).await; }); } // mmb::Family variants #[test_traced("INFO")] fn test_keyless_fixed_empty_mmb() { deterministic::Runner::default().start(|ctx| async move { let db = open_db::(ctx.child("db").with_attribute("index", 1)).await; tests::test_keyless_db_empty(ctx, db, reopen::()).await; }); } #[test_traced("WARN")] fn test_keyless_fixed_build_basic_mmb() { deterministic::Runner::default().start(|ctx| async move { let db = open_db::(ctx.child("db").with_attribute("index", 1)).await; tests::test_keyless_db_build_basic(ctx, db, reopen::()).await; }); } #[test_traced("WARN")] fn test_keyless_fixed_recovery_mmb() { deterministic::Runner::default().start(|ctx| async move { let db = open_db::(ctx.child("db").with_attribute("index", 1)).await; tests::test_keyless_db_recovery(ctx, db, reopen::()).await; }); } #[test_traced("WARN")] fn test_keyless_fixed_non_empty_recovery_mmb() { deterministic::Runner::default().start(|ctx| async move { let db = open_db::(ctx.child("db").with_attribute("index", 1)).await; tests::test_keyless_db_non_empty_recovery(ctx, db, reopen::()).await; }); } #[test_traced("INFO")] fn test_keyless_fixed_proof_mmb() { deterministic::Runner::default().start(|ctx| async move { let db = open_db::(ctx.child("storage")).await; tests::test_keyless_db_proof(db).await; }); } #[test_traced("INFO")] fn test_keyless_fixed_proof_comprehensive_mmb() { deterministic::Runner::default().start(|ctx| async move { let db = open_db::(ctx.child("storage")).await; tests::test_keyless_db_proof_comprehensive(db).await; }); } #[test_traced("INFO")] fn test_keyless_fixed_proof_with_pruning_mmb() { deterministic::Runner::default().start(|ctx| async move { let db = open_db::(ctx.child("db").with_attribute("index", 1)).await; tests::test_keyless_db_proof_with_pruning(ctx, db, reopen::()).await; }); } #[test_traced("WARN")] fn test_keyless_fixed_empty_db_recovery_mmb() { deterministic::Runner::default().start(|ctx| async move { let db = open_db::(ctx.child("db").with_attribute("index", 1)).await; tests::test_keyless_db_empty_db_recovery(ctx, db, reopen::()).await; }); } #[test_traced("WARN")] fn test_keyless_fixed_replay_with_trailing_appends_mmb() { deterministic::Runner::default().start(|ctx| async move { let db = open_db::(ctx.child("db").with_attribute("index", 1)).await; tests::test_keyless_db_replay_with_trailing_appends(ctx, db, reopen::()) .await; }); } #[test_traced("INFO")] fn test_keyless_fixed_get_out_of_bounds_mmb() { deterministic::Runner::default().start(|ctx| async move { let db = open_db::(ctx.child("storage")).await; tests::test_keyless_db_get_out_of_bounds(db).await; }); } #[test_traced("INFO")] fn test_keyless_fixed_metadata_mmb() { deterministic::Runner::default().start(|ctx| async move { let db = open_db::(ctx.child("db")).await; tests::test_keyless_db_metadata(db).await; }); } #[test_traced("INFO")] fn test_keyless_fixed_pruning_mmb() { deterministic::Runner::default().start(|ctx| async move { let db = open_db::(ctx.child("db")).await; tests::test_keyless_db_pruning(db).await; }); } #[test_traced("INFO")] fn test_keyless_fixed_batch_get_mmb() { deterministic::Runner::default().start(|ctx| async move { let db = open_db::(ctx.child("db")).await; tests::test_keyless_batch_get(db).await; }); } #[test_traced("INFO")] fn test_keyless_fixed_batch_stacked_get_mmb() { deterministic::Runner::default().start(|ctx| async move { let db = open_db::(ctx.child("db")).await; tests::test_keyless_batch_stacked_get(db).await; }); } #[test_traced("INFO")] fn test_keyless_fixed_batch_speculative_root_mmb() { deterministic::Runner::default().start(|ctx| async move { let db = open_db::(ctx.child("db")).await; tests::test_keyless_batch_speculative_root(db).await; }); } #[test_traced("INFO")] fn test_keyless_fixed_merkleized_batch_get_mmb() { deterministic::Runner::default().start(|ctx| async move { let db = open_db::(ctx.child("db")).await; tests::test_keyless_merkleized_batch_get(db).await; }); } #[test_traced("INFO")] fn test_keyless_fixed_batch_chained_mmb() { deterministic::Runner::default().start(|ctx| async move { let db = open_db::(ctx.child("db")).await; tests::test_keyless_batch_chained(db).await; }); } #[test_traced("INFO")] fn test_keyless_fixed_batch_chained_apply_sequential_mmb() { deterministic::Runner::default().start(|ctx| async move { let db = open_db::(ctx.child("db")).await; tests::test_keyless_batch_chained_apply_sequential(db).await; }); } #[test_traced("INFO")] fn test_keyless_fixed_batch_many_sequential_mmb() { deterministic::Runner::default().start(|ctx| async move { let db = open_db::(ctx.child("db")).await; tests::test_keyless_batch_many_sequential(db).await; }); } #[test_traced("INFO")] fn test_keyless_fixed_batch_empty_mmb() { deterministic::Runner::default().start(|ctx| async move { let db = open_db::(ctx.child("db")).await; tests::test_keyless_batch_empty(db).await; }); } #[test_traced("INFO")] fn test_keyless_fixed_batch_chained_merkleized_get_mmb() { deterministic::Runner::default().start(|ctx| async move { let db = open_db::(ctx.child("db")).await; tests::test_keyless_batch_chained_merkleized_get(db).await; }); } #[test_traced("INFO")] fn test_keyless_fixed_batch_large_mmb() { deterministic::Runner::default().start(|ctx| async move { let db = open_db::(ctx.child("db")).await; tests::test_keyless_batch_large(db).await; }); } #[test_traced] fn test_keyless_fixed_stale_batch_mmb() { deterministic::Runner::default().start(|ctx| async move { let db = open_db::(ctx.child("db")).await; tests::test_keyless_stale_batch(db).await; }); } #[test_traced] fn test_keyless_fixed_stale_batch_chained_mmb() { deterministic::Runner::default().start(|ctx| async move { let db = open_db::(ctx.child("db")).await; tests::test_keyless_stale_batch_chained(db).await; }); } #[test_traced] fn test_keyless_fixed_sequential_commit_parent_then_child_mmb() { deterministic::Runner::default().start(|ctx| async move { let db = open_db::(ctx.child("db")).await; tests::test_keyless_sequential_commit_parent_then_child(db).await; }); } #[test_traced] fn test_keyless_fixed_stale_batch_child_before_parent_mmb() { deterministic::Runner::default().start(|ctx| async move { let db = open_db::(ctx.child("db")).await; tests::test_keyless_stale_batch_child_before_parent(db).await; }); } #[test_traced] fn test_keyless_fixed_to_batch_mmb() { deterministic::Runner::default().start(|ctx| async move { let db = open_db::(ctx.child("db")).await; tests::test_keyless_to_batch(db).await; }); } #[test_traced] fn test_keyless_fixed_child_root_matches_pending_and_committed_mmb() { deterministic::Runner::default().start(|ctx| async move { let db = open_db::(ctx.child("db")).await; tests::test_keyless_child_root_matches_pending_and_committed(db).await; }); } #[test_traced("INFO")] fn test_keyless_fixed_rewind_recovery_mmb() { deterministic::Runner::default().start(|ctx| async move { let db = open_db::(ctx.child("db")).await; tests::test_keyless_db_rewind_recovery(ctx, db, reopen::()).await; }); } #[test_traced("INFO")] fn test_keyless_fixed_rewind_pruned_target_errors_mmb() { deterministic::Runner::default().start(|ctx| async move { let db = open_db::(ctx.child("db")).await; tests::test_keyless_db_rewind_pruned_target_errors(db).await; }); } #[test_traced("INFO")] fn test_keyless_fixed_floor_tracking_mmb() { deterministic::Runner::default().start(|ctx| async move { let db = open_db::(ctx.child("db").with_attribute("index", 1)).await; tests::test_keyless_db_floor_tracking(ctx, db, reopen::()).await; }); } #[test_traced("INFO")] fn test_keyless_fixed_floor_regression_rejected_mmb() { deterministic::Runner::default().start(|ctx| async move { let db = open_db::(ctx.child("db")).await; tests::test_keyless_db_floor_regression_rejected(db).await; }); } #[test_traced("INFO")] fn test_keyless_fixed_floor_beyond_commit_loc_rejected_mmb() { deterministic::Runner::default().start(|ctx| async move { let db = open_db::(ctx.child("db")).await; tests::test_keyless_db_floor_beyond_commit_loc_rejected(db).await; }); } #[test_traced("INFO")] fn test_keyless_fixed_rewind_restores_floor_mmb() { deterministic::Runner::default().start(|ctx| async move { let db = open_db::(ctx.child("db")).await; tests::test_keyless_db_rewind_restores_floor(db).await; }); } #[test_traced("INFO")] fn test_keyless_fixed_floor_changes_root_mmb() { deterministic::Runner::default().start(|ctx| async move { let db_a = open_db_with_suffix::("root-a", ctx.child("a")).await; let db_b = open_db_with_suffix::("root-b", ctx.child("b")).await; tests::test_keyless_db_floor_changes_root(db_a, db_b).await; }); } #[test_traced("INFO")] fn test_keyless_fixed_floor_at_commit_loc_accepted_mmb() { deterministic::Runner::default().start(|ctx| async move { let db = open_db::(ctx.child("db")).await; tests::test_keyless_db_floor_at_commit_loc_accepted(db).await; }); } #[test_traced("INFO")] fn test_keyless_fixed_rewind_after_reopen_with_floor_mmb() { deterministic::Runner::default().start(|ctx| async move { let db = open_db::(ctx.child("db").with_attribute("index", 1)).await; tests::test_keyless_db_rewind_after_reopen_with_floor(ctx, db, reopen::()) .await; }); } #[test_traced("INFO")] fn test_keyless_fixed_ancestor_floor_regression_rejected_mmb() { deterministic::Runner::default().start(|ctx| async move { let db = open_db::(ctx.child("db")).await; tests::test_keyless_db_ancestor_floor_regression_rejected(db).await; }); } #[test_traced("INFO")] fn test_keyless_fixed_ancestor_floor_beyond_commit_loc_rejected_mmb() { deterministic::Runner::default().start(|ctx| async move { let db = open_db::(ctx.child("db")).await; tests::test_keyless_db_ancestor_floor_beyond_commit_loc_rejected(db).await; }); } #[test_traced("INFO")] fn test_keyless_fixed_chained_apply_with_valid_floors_succeeds_mmb() { deterministic::Runner::default().start(|ctx| async move { let db = open_db::(ctx.child("db")).await; tests::test_keyless_db_chained_apply_with_valid_floors_succeeds(db).await; }); } #[test_traced("INFO")] fn test_keyless_fixed_single_commit_live_set_mmb() { deterministic::Runner::default().start(|ctx| async move { let db = open_db::(ctx.child("db").with_attribute("index", 1)).await; tests::test_keyless_db_single_commit_live_set(ctx, db, reopen::()).await; }); } /// Smoke test: verify the sync engine works end-to-end with a fixed-size keyless database. /// The full sync test suite runs against the variable variant via the harness in /// [`super::super::sync::tests`]; this test covers the fixed-size code path. #[test_traced("WARN")] fn test_keyless_fixed_sync() { use crate::{ merkle::Location, qmdb::sync::{self, engine::Config, Target}, }; use commonware_utils::{non_empty_range, sequence::U64}; use std::sync::Arc; deterministic::Runner::default().start(|ctx| async move { let target_config = db_config("sync-target", &ctx, Sequential); let mut target_db: TestDb = TestDb::init(ctx.child("target"), target_config) .await .unwrap(); let mut batch = target_db.new_batch(); for i in 0..20u64 { batch = batch.append(U64::new(i * 10 + 1)); } let floor = target_db.inactivity_floor_loc(); let merkleized = batch.merkleize(&target_db, None, floor); target_db.apply_batch(merkleized).await.unwrap(); let target_root = target_db.root(); let bounds = target_db.bounds().await; let lower_bound = bounds.start; let upper_bound = bounds.end; let client_config = db_config("sync-client", &ctx, Sequential); let target_db = Arc::new(target_db); let config = Config { db_config: client_config, fetch_batch_size: NZU64!(5), target: Target { root: target_root, range: non_empty_range!(lower_bound, upper_bound), }, context: ctx.child("client"), resolver: target_db.clone(), apply_batch_size: 1024, max_outstanding_requests: 1, update_rx: None, finish_rx: None, reached_target_tx: None, max_retained_roots: 8, }; let synced_db: TestDb = sync::sync(config).await.unwrap(); assert_eq!(synced_db.root(), target_root); let bounds = synced_db.bounds().await; assert_eq!(bounds.end, upper_bound); assert_eq!(bounds.start, lower_bound); for i in 0..20u64 { let got = synced_db.get(Location::new(i + 1)).await.unwrap(); assert_eq!(got, Some(U64::new(i * 10 + 1))); } synced_db.destroy().await.unwrap(); let target_db = Arc::try_unwrap(target_db).unwrap_or_else(|_| panic!("failed to unwrap Arc")); target_db.destroy().await.unwrap(); }); } }