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 operation::Committable,
18 store::LogStore,
19 },
20};
21use commonware_utils::{NZUsize, NZU16, NZU64};
22use std::{future::Future, num::NonZeroU64};
23use tracing::error;
24
25pub type Database<E> = Db<E, Key, Value, Hasher, Translator>;
27
28pub type Operation = FixedOperation<Key, Value>;
30
31pub fn create_config() -> Config<Translator> {
33 Config {
34 mmr_journal_partition: "mmr_journal".into(),
35 mmr_metadata_partition: "mmr_metadata".into(),
36 mmr_items_per_blob: NZU64!(4096),
37 mmr_write_buffer: NZUsize!(1024),
38 log_journal_partition: "log_journal".into(),
39 log_items_per_blob: NZU64!(4096),
40 log_write_buffer: NZUsize!(1024),
41 translator: Translator::default(),
42 thread_pool: None,
43 page_cache: buffer::paged::CacheRef::new(NZU16!(1024), NZUsize!(10)),
44 }
45}
46
47impl<E> crate::databases::Syncable for Database<E>
48where
49 E: Storage + Clock + Metrics,
50{
51 type Operation = Operation;
52
53 fn create_test_operations(count: usize, seed: u64) -> Vec<Self::Operation> {
54 let mut hasher = <Hasher as CryptoHasher>::new();
55 let mut operations = Vec::new();
56 for i in 0..count {
57 let key = {
58 hasher.update(&i.to_be_bytes());
59 hasher.update(&seed.to_be_bytes());
60 hasher.finalize()
61 };
62
63 let value = {
64 hasher.update(&key);
65 hasher.update(b"value");
66 hasher.finalize()
67 };
68
69 operations.push(Operation::Update(Update(key, value)));
70
71 if (i + 1) % 10 == 0 {
72 operations.push(Operation::CommitFloor(None, Location::from(i + 1)));
73 }
74 }
75
76 operations.push(Operation::CommitFloor(None, Location::from(count)));
78 operations
79 }
80
81 async fn add_operations(
82 self,
83 operations: Vec<Self::Operation>,
84 ) -> Result<Self, commonware_storage::qmdb::Error> {
85 if operations.last().is_none() || !operations.last().unwrap().is_commit() {
86 error!("operations must end with a commit");
88 return Ok(self);
89 }
90 let mut db = self.into_mutable();
91 let num_ops = operations.len();
92
93 for (i, operation) in operations.into_iter().enumerate() {
94 match operation {
95 Operation::Update(Update(key, value)) => {
96 db.update(key, value).await?;
97 }
98 Operation::Delete(key) => {
99 db.delete(key).await?;
100 }
101 Operation::CommitFloor(metadata, _) => {
102 let (durable_db, _) = db.commit(metadata).await?;
103 if i == num_ops - 1 {
104 return Ok(durable_db.into_merkleized());
106 }
107 db = durable_db.into_mutable();
109 }
110 }
111 }
112 panic!("operations should end with a commit");
113 }
114
115 fn root(&self) -> Key {
116 self.root()
117 }
118
119 fn size(&self) -> Location {
120 LogStore::bounds(self).end
121 }
122
123 fn inactivity_floor(&self) -> Location {
124 self.inactivity_floor_loc()
125 }
126
127 fn historical_proof(
128 &self,
129 op_count: Location,
130 start_loc: Location,
131 max_ops: NonZeroU64,
132 ) -> impl Future<Output = Result<(Proof<Key>, Vec<Self::Operation>), qmdb::Error>> + Send {
133 self.historical_proof(op_count, start_loc, max_ops)
134 }
135
136 fn name() -> &'static str {
137 "any"
138 }
139}
140
141#[cfg(test)]
142mod tests {
143 use super::*;
144 use crate::databases::Syncable;
145 use commonware_runtime::deterministic;
146
147 type AnyDb = Database<deterministic::Context>;
148
149 #[test]
150 fn test_create_test_operations() {
151 let ops = <AnyDb as Syncable>::create_test_operations(5, 12345);
152 assert_eq!(ops.len(), 6); if let Operation::CommitFloor(_, loc) = &ops[5] {
155 assert_eq!(*loc, 5);
156 } else {
157 panic!("Last operation should be a commit");
158 }
159 }
160
161 #[test]
162 fn test_deterministic_operations() {
163 let ops1 = <AnyDb as Syncable>::create_test_operations(3, 12345);
165 let ops2 = <AnyDb as Syncable>::create_test_operations(3, 12345);
166 assert_eq!(ops1, ops2);
167
168 let ops3 = <AnyDb as Syncable>::create_test_operations(3, 54321);
170 assert_ne!(ops1, ops3);
171 }
172}