commonware_sync/databases/
any.rs1use crate::{Hasher, Key, Translator, Value};
4use commonware_cryptography::Hasher as CryptoHasher;
5use commonware_runtime::{buffer, Clock, Metrics, Storage};
6use commonware_storage::{
7 mmr::{Location, Proof},
8 qmdb::{
9 self,
10 any::{
11 unordered::{
12 fixed::{Db, Operation as FixedOperation},
13 Update,
14 },
15 FixedConfig as Config,
16 },
17 store::CleanStore,
18 },
19};
20use commonware_utils::{NZUsize, NZU64};
21use std::{future::Future, num::NonZeroU64};
22
23pub type Database<E> = Db<E, Key, Value, Hasher, Translator>;
25
26pub type Operation = FixedOperation<Key, Value>;
28
29pub fn create_config() -> Config<Translator> {
31 Config {
32 mmr_journal_partition: "mmr_journal".into(),
33 mmr_metadata_partition: "mmr_metadata".into(),
34 mmr_items_per_blob: NZU64!(4096),
35 mmr_write_buffer: NZUsize!(1024),
36 log_journal_partition: "log_journal".into(),
37 log_items_per_blob: NZU64!(4096),
38 log_write_buffer: NZUsize!(1024),
39 translator: Translator::default(),
40 thread_pool: None,
41 buffer_pool: buffer::PoolRef::new(NZUsize!(1024), NZUsize!(10)),
42 }
43}
44
45impl<E> crate::databases::Syncable for Database<E>
46where
47 E: Storage + Clock + Metrics,
48{
49 type Operation = Operation;
50
51 fn create_test_operations(count: usize, seed: u64) -> Vec<Self::Operation> {
52 let mut hasher = <Hasher as CryptoHasher>::new();
53 let mut operations = Vec::new();
54 for i in 0..count {
55 let key = {
56 hasher.update(&i.to_be_bytes());
57 hasher.update(&seed.to_be_bytes());
58 hasher.finalize()
59 };
60
61 let value = {
62 hasher.update(&key);
63 hasher.update(b"value");
64 hasher.finalize()
65 };
66
67 operations.push(Operation::Update(Update(key, value)));
68
69 if (i + 1) % 10 == 0 {
70 operations.push(Operation::CommitFloor(None, Location::from(i + 1)));
71 }
72 }
73
74 operations.push(Operation::CommitFloor(None, Location::from(count)));
76 operations
77 }
78
79 async fn add_operations(
80 database: &mut Self,
81 operations: Vec<Self::Operation>,
82 ) -> Result<(), commonware_storage::qmdb::Error> {
83 for operation in operations {
84 match operation {
85 Operation::Update(Update(key, value)) => {
86 database.update(key, value).await?;
87 }
88 Operation::Delete(key) => {
89 database.delete(key).await?;
90 }
91 Operation::CommitFloor(metadata, _) => {
92 database.commit(metadata).await?;
93 }
94 }
95 }
96 Ok(())
97 }
98
99 async fn commit(&mut self) -> Result<(), commonware_storage::qmdb::Error> {
100 self.commit(None).await?;
101 Ok(())
102 }
103
104 fn root(&self) -> Key {
105 CleanStore::root(self)
106 }
107
108 fn op_count(&self) -> Location {
109 self.op_count()
110 }
111
112 fn lower_bound(&self) -> Location {
113 self.inactivity_floor_loc()
114 }
115
116 fn historical_proof(
117 &self,
118 op_count: Location,
119 start_loc: Location,
120 max_ops: NonZeroU64,
121 ) -> impl Future<Output = Result<(Proof<Key>, Vec<Self::Operation>), qmdb::Error>> + Send {
122 CleanStore::historical_proof(self, op_count, start_loc, max_ops)
123 }
124
125 fn name() -> &'static str {
126 "any"
127 }
128}
129
130#[cfg(test)]
131mod tests {
132 use super::*;
133 use crate::databases::Syncable;
134 use commonware_runtime::deterministic;
135
136 type AnyDb = Database<deterministic::Context>;
137
138 #[test]
139 fn test_create_test_operations() {
140 let ops = <AnyDb as Syncable>::create_test_operations(5, 12345);
141 assert_eq!(ops.len(), 6); if let Operation::CommitFloor(_, loc) = &ops[5] {
144 assert_eq!(*loc, 5);
145 } else {
146 panic!("Last operation should be a commit");
147 }
148 }
149
150 #[test]
151 fn test_deterministic_operations() {
152 let ops1 = <AnyDb as Syncable>::create_test_operations(3, 12345);
154 let ops2 = <AnyDb as Syncable>::create_test_operations(3, 12345);
155 assert_eq!(ops1, ops2);
156
157 let ops3 = <AnyDb as Syncable>::create_test_operations(3, 54321);
159 assert_ne!(ops1, ops3);
160 }
161}