commonware_storage/qmdb/current/ordered/
db.rs1use crate::{
7 index::Ordered as OrderedIndex,
8 journal::contiguous::{Contiguous, Mutable, Reader},
9 merkle::{self, Location},
10 qmdb::{
11 any::{
12 ordered::{Operation, Update},
13 ValueEncoding,
14 },
15 current::proof::OperationProof,
16 operation::Key,
17 Error,
18 },
19 Context,
20};
21use commonware_codec::Codec;
22use commonware_cryptography::{Digest, Hasher};
23use futures::stream::Stream;
24
25#[derive(Clone, Eq, PartialEq, Debug)]
27pub struct KeyValueProof<F: merkle::Family, K: Key, D: Digest, const N: usize> {
28 pub proof: OperationProof<F, D, N>,
29 pub next_key: K,
30}
31
32pub type Db<F, E, C, K, V, I, H, const N: usize> =
37 crate::qmdb::current::db::Db<F, E, C, I, H, Update<K, V>, N>;
38
39impl<
41 F: merkle::Graftable,
42 E: Context,
43 C: Contiguous<Item = Operation<F, K, V>>,
44 K: Key,
45 V: ValueEncoding,
46 I: OrderedIndex<Value = Location<F>>,
47 H: Hasher,
48 const N: usize,
49 > Db<F, E, C, K, V, I, H, N>
50where
51 Operation<F, K, V>: Codec,
52{
53 pub async fn get(&self, key: &K) -> Result<Option<V::Value>, Error<F>> {
55 self.any.get(key).await
56 }
57
58 pub fn verify_key_value_proof(
61 hasher: &mut H,
62 key: K,
63 value: V::Value,
64 proof: &KeyValueProof<F, K, H::Digest, N>,
65 root: &H::Digest,
66 ) -> bool {
67 let op = Operation::Update(Update {
68 key,
69 value,
70 next_key: proof.next_key.clone(),
71 });
72
73 proof.proof.verify(hasher, op, root)
74 }
75
76 pub async fn get_span(&self, key: &K) -> Result<Option<(Location<F>, Update<K, V>)>, Error<F>> {
79 self.any.get_span(key).await
80 }
81
82 pub async fn stream_range<'a>(
85 &'a self,
86 start: K,
87 ) -> Result<impl Stream<Item = Result<(K, V::Value), Error<F>>> + 'a, Error<F>>
88 where
89 V: 'a,
90 {
91 self.any.stream_range(start).await
92 }
93
94 pub fn verify_exclusion_proof(
97 hasher: &mut H,
98 key: &K,
99 proof: &super::ExclusionProof<F, K, V, H::Digest, N>,
100 root: &H::Digest,
101 ) -> bool {
102 let (op_proof, op) = match proof {
103 super::ExclusionProof::KeyValue(op_proof, data) => {
104 if data.key == *key {
105 return false;
107 }
108 if !crate::qmdb::any::db::Db::<F, E, C, I, H, Update<K, V>>::span_contains(
109 &data.key,
110 &data.next_key,
111 key,
112 ) {
113 return false;
116 }
117
118 (op_proof, Operation::Update(data.clone()))
119 }
120 super::ExclusionProof::Commit(op_proof, metadata) => {
121 let floor_loc = op_proof.loc;
125 (
126 op_proof,
127 Operation::CommitFloor(metadata.clone(), floor_loc),
128 )
129 }
130 };
131
132 op_proof.verify(hasher, op, root)
133 }
134}
135
136impl<
137 F: merkle::Graftable,
138 E: Context,
139 C: Mutable<Item = Operation<F, K, V>>,
140 K: Key,
141 V: ValueEncoding,
142 I: OrderedIndex<Value = Location<F>>,
143 H: Hasher,
144 const N: usize,
145 > Db<F, E, C, K, V, I, H, N>
146where
147 Operation<F, K, V>: Codec,
148{
149 pub async fn key_value_proof(
157 &self,
158 hasher: &mut H,
159 key: K,
160 ) -> Result<KeyValueProof<F, K, H::Digest, N>, Error<F>> {
161 let op_loc = self.any.get_with_loc(&key).await?;
162 let Some((data, loc)) = op_loc else {
163 return Err(Error::<F>::KeyNotFound);
164 };
165 let proof = self.operation_proof(hasher, loc).await?;
166
167 Ok(KeyValueProof {
168 proof,
169 next_key: data.next_key,
170 })
171 }
172
173 pub async fn exclusion_proof(
179 &self,
180 hasher: &mut H,
181 key: &K,
182 ) -> Result<super::ExclusionProof<F, K, V, H::Digest, N>, Error<F>> {
183 match self.any.get_span(key).await? {
184 Some((loc, key_data)) => {
185 if key_data.key == *key {
186 return Err(Error::<F>::KeyExists);
188 }
189 let op_proof = self.operation_proof(hasher, loc).await?;
190 Ok(super::ExclusionProof::KeyValue(op_proof, key_data))
191 }
192 None => {
193 let op = self
197 .any
198 .log
199 .reader()
200 .await
201 .read(*self.any.last_commit_loc)
202 .await?;
203 let Operation::CommitFloor(value, floor) = op else {
204 unreachable!("last_commit_loc should always point to a CommitFloor");
205 };
206 assert_eq!(
207 floor, self.any.last_commit_loc,
208 "inconsistent commit floor: expected last_commit_loc={}, got floor={}",
209 self.any.last_commit_loc, floor
210 );
211 let op_proof = self
212 .operation_proof(hasher, self.any.last_commit_loc)
213 .await?;
214 Ok(super::ExclusionProof::Commit(op_proof, value))
215 }
216 }
217 }
218}