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