commonware_sync/databases/
immutable.rs1use crate::{Hasher, Key, Translator, Value};
4use commonware_cryptography::{Hasher as CryptoHasher, Sha256};
5use commonware_runtime::{BufferPooler, Clock, Metrics, Storage};
6use commonware_storage::{
7 journal::contiguous::variable::Config as VConfig,
8 merkle::{
9 journaled::Config as MmrConfig,
10 mmr::{self, Location, Proof},
11 },
12 qmdb::{
13 self,
14 immutable::{self, Config},
15 },
16};
17use commonware_utils::{NZUsize, NZU16, NZU64};
18use std::{future::Future, num::NonZeroU64};
19use tracing::error;
20
21pub type Database<E> = immutable::variable::Db<mmr::Family, E, Key, Value, Hasher, Translator>;
23
24pub type Operation = immutable::variable::Operation<Key, Value>;
26
27pub fn create_config(context: &impl BufferPooler) -> Config<Translator, VConfig<((), ())>> {
29 let page_cache = commonware_runtime::buffer::paged::CacheRef::from_pooler(
30 context,
31 NZU16!(2048),
32 NZUsize!(10),
33 );
34 Config {
35 merkle_config: MmrConfig {
36 journal_partition: "mmr-journal".into(),
37 metadata_partition: "mmr-metadata".into(),
38 items_per_blob: NZU64!(4096),
39 write_buffer: NZUsize!(4096),
40 thread_pool: None,
41 page_cache: page_cache.clone(),
42 },
43 log: VConfig {
44 partition: "log".into(),
45 items_per_section: NZU64!(4096),
46 compression: None,
47 codec_config: ((), ()),
48 write_buffer: NZUsize!(4096),
49 page_cache,
50 },
51 translator: commonware_storage::translator::EightCap,
52 }
53}
54
55pub fn create_test_operations(count: usize, seed: u64) -> Vec<Operation> {
58 let mut operations = Vec::new();
59 let mut hasher = <Hasher as CryptoHasher>::new();
60
61 for i in 0..count {
62 let key = {
63 hasher.update(&i.to_be_bytes());
64 hasher.update(&seed.to_be_bytes());
65 hasher.finalize()
66 };
67
68 let value = {
69 hasher.update(&key);
70 hasher.update(b"value");
71 hasher.finalize()
72 };
73
74 operations.push(Operation::Set(key, value));
75
76 if (i + 1) % 10 == 0 {
77 operations.push(Operation::Commit(None));
78 }
79 }
80
81 operations.push(Operation::Commit(Some(Sha256::fill(1))));
83 operations
84}
85
86impl<E> super::Syncable for Database<E>
87where
88 E: Storage + Clock + Metrics,
89{
90 type Family = mmr::Family;
91 type Operation = Operation;
92
93 fn create_test_operations(count: usize, seed: u64) -> Vec<Self::Operation> {
94 create_test_operations(count, seed)
95 }
96
97 async fn add_operations(
98 &mut self,
99 operations: Vec<Self::Operation>,
100 ) -> Result<(), commonware_storage::qmdb::Error<mmr::Family>> {
101 if operations.last().is_none() || !operations.last().unwrap().is_commit() {
102 error!("operations must end with a commit");
104 return Ok(());
105 }
106
107 let mut batch = self.new_batch();
108 for operation in operations {
109 match operation {
110 Operation::Set(key, value) => {
111 batch = batch.set(key, value);
112 }
113 Operation::Commit(metadata) => {
114 let merkleized = batch.merkleize(self, metadata);
115 self.apply_batch(merkleized).await?;
116 self.commit().await?;
117 batch = self.new_batch();
118 }
119 }
120 }
121 Ok(())
122 }
123
124 fn root(&self) -> Key {
125 self.root()
126 }
127
128 async fn size(&self) -> Location {
129 self.bounds().await.end
130 }
131
132 async fn inactivity_floor(&self) -> Location {
133 self.bounds().await.start
136 }
137
138 fn historical_proof(
139 &self,
140 op_count: Location,
141 start_loc: Location,
142 max_ops: NonZeroU64,
143 ) -> impl Future<Output = Result<(Proof<Key>, Vec<Self::Operation>), qmdb::Error<mmr::Family>>> + Send
144 {
145 self.historical_proof(op_count, start_loc, max_ops)
146 }
147
148 fn pinned_nodes_at(
149 &self,
150 loc: Location,
151 ) -> impl Future<Output = Result<Vec<Key>, qmdb::Error<mmr::Family>>> + Send {
152 self.pinned_nodes_at(loc)
153 }
154
155 fn name() -> &'static str {
156 "immutable"
157 }
158}