1use crate::{
76 Context,
77 index::immutable::Index,
78 journal::{
79 authenticated,
80 contiguous::{Contiguous, Mutable},
81 },
82 merkle::{Family, Location, Proof, full::Config as MerkleConfig},
83 qmdb::{
84 Error, any::ValueEncoding, chain, metrics::Metrics, operation::Key, single_operation_root,
85 sync::source,
86 },
87 translator::Translator,
88};
89use commonware_codec::EncodeShared;
90use commonware_cryptography::Hasher;
91use commonware_macros::boxed;
92use commonware_parallel::Strategy;
93use commonware_runtime::{Handle, ReadOptions};
94use core::num::{NonZeroU64, NonZeroUsize};
95use futures::{StreamExt, pin_mut};
96use std::{ops::Range, sync::Arc};
97use tracing::warn;
98
99pub mod batch;
100mod compact;
101pub mod fixed;
102mod operation;
103pub mod sync;
104pub mod variable;
105
106pub use compact::{
107 Config as CompactConfig, Db as CompactDb, MerkleizedBatch as CompactMerkleizedBatch,
108 UnmerkleizedBatch as CompactUnmerkleizedBatch,
109};
110pub use operation::Operation;
111
112async fn build_snapshot<F, E, K, V, C, T>(
117 context: E,
118 translator: T,
119 inactivity_floor_loc: Location<F>,
120 log: &C,
121 init_buffer: NonZeroUsize,
122) -> Result<Index<T>, Error<F>>
123where
124 F: Family,
125 E: Context,
126 K: Key,
127 V: ValueEncoding,
128 C: Contiguous<Item = Operation<F, K, V>>,
129 T: Translator,
130{
131 let end = log.bounds().end;
135 let mut snapshot = Index::new(
136 context,
137 translator,
138 *inactivity_floor_loc,
139 usize::try_from(end - *inactivity_floor_loc)
140 .expect("operations since the floor must fit in usize"),
141 );
142
143 let stream = log
146 .replay(
147 *inactivity_floor_loc..end,
148 init_buffer,
149 ReadOptions::DONT_CACHE,
150 )
151 .await?;
152 pin_mut!(stream);
153 while let Some(batch) = stream.next().await {
154 for (loc, op) in batch? {
155 if let Operation::Set(key, _) = op {
156 snapshot.insert(&key, loc);
157 }
158 }
159 }
160 Ok(snapshot)
161}
162
163pub fn initial_root<F, K, V, H>() -> H::Digest
167where
168 F: Family,
169 K: Key,
170 V: ValueEncoding,
171 H: Hasher,
172 Operation<F, K, V>: EncodeShared,
173{
174 single_operation_root::<F, H>(&Operation::<F, K, V>::Commit(None, Location::new(0)))
175}
176
177#[derive(Clone)]
179pub struct Config<T: Translator, J, S: Strategy> {
180 pub merkle_config: MerkleConfig<S>,
182
183 pub log: J,
185
186 pub translator: T,
188
189 pub init_buffer: NonZeroUsize,
191}
192
193pub struct Immutable<
202 F: Family,
203 E: Context,
204 K: Key,
205 V: ValueEncoding,
206 C: Mutable<Item = Operation<F, K, V>>,
207 H: Hasher,
208 T: Translator,
209 S: Strategy,
210> where
211 C::Item: EncodeShared,
212{
213 journal: authenticated::Journal<F, E, C, H, S>,
215
216 pub(crate) root: H::Digest,
218
219 pub(crate) snapshot: Index<T>,
222
223 pub(crate) inactivity_floor_loc: Location<F>,
226
227 metrics: Metrics<E>,
229}
230
231impl<F, E, K, V, C, H, T, S> std::fmt::Debug for Immutable<F, E, K, V, C, H, T, S>
232where
233 F: Family,
234 E: Context,
235 K: Key,
236 V: ValueEncoding,
237 C: Mutable<Item = Operation<F, K, V>>,
238 C::Item: EncodeShared,
239 H: Hasher,
240 T: Translator,
241 S: Strategy,
242{
243 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
244 f.debug_struct("Immutable")
245 .field("bounds", &self.bounds())
246 .field("inactivity_floor_loc", &self.inactivity_floor_loc())
247 .finish_non_exhaustive()
248 }
249}
250
251impl<F, E, K, V, C, H, T, S> Immutable<F, E, K, V, C, H, T, S>
253where
254 F: Family,
255 E: Context,
256 K: Key,
257 V: ValueEncoding,
258 C: Mutable<Item = Operation<F, K, V>>,
259 C::Item: EncodeShared,
260 H: Hasher,
261 T: Translator,
262 S: Strategy,
263{
264 #[boxed]
268 pub async fn init(
269 context: E,
270 cfg: Config<T, C::Config, S>,
271 max_size: Option<Location<F>>,
272 ) -> Result<Self, Error<F>>
273 where
274 C: authenticated::Backing<E>,
275 {
276 let mut journal = crate::qmdb::init_journal::<F, E, C, H, S>(
279 context.child("journal"),
280 cfg.merkle_config,
281 cfg.log,
282 max_size,
283 true,
284 )
285 .await?;
286 if journal.size() == 0 {
287 warn!("Authenticated log is empty, initialized new db.");
288 (journal, _) = journal
289 .append(&Operation::Commit(None, Location::new(0)))
290 .await?;
291 journal = journal.sync().await?;
292 }
293
294 let (last_commit_loc, inactivity_floor_loc, snapshot) = {
297 let bounds = journal.journal.bounds();
298 let last_commit_loc =
299 Location::new(bounds.end.checked_sub(1).expect("commit should exist"));
300
301 let last_op = journal.journal.read(*last_commit_loc).await?;
303 let inactivity_floor_loc = last_op
304 .has_floor()
305 .expect("last operation should be a commit with floor");
306
307 let snapshot = build_snapshot(
309 context.child("snapshot"),
310 cfg.translator,
311 inactivity_floor_loc,
312 &journal.journal,
313 cfg.init_buffer,
314 )
315 .await?;
316
317 (last_commit_loc, inactivity_floor_loc, snapshot)
318 };
319 let inactive_peaks = F::inactive_peaks(last_commit_loc + 1, inactivity_floor_loc);
320 let root = journal.root(inactive_peaks)?;
321
322 let metrics = Metrics::new(context);
323 let db = Self {
324 journal,
325 root,
326 snapshot,
327 inactivity_floor_loc,
328 metrics,
329 };
330 db.update_metrics();
331 Ok(db)
332 }
333
334 pub const fn inactivity_floor_loc(&self) -> Location<F> {
336 self.inactivity_floor_loc
337 }
338
339 pub fn size(&self) -> Location<F> {
341 self.bounds().end
342 }
343
344 pub fn bounds(&self) -> Range<Location<F>> {
348 Location::new(self.journal.bounds().start)..Location::new(self.journal.bounds().end)
349 }
350
351 fn update_metrics(&self) {
353 let bounds = self.journal.bounds();
354 self.metrics.update(
355 bounds.end,
356 bounds.start,
357 *self.inactivity_floor_loc,
358 bounds.end - 1,
359 );
360 }
361
362 pub const fn sync_boundary(&self) -> Location<F> {
366 self.inactivity_floor_loc
367 }
368
369 pub async fn get(&self, key: &K) -> Result<Option<V::Value>, Error<F>> {
375 self.get_from(key, Location::new(0)).await
376 }
377
378 pub(crate) async fn get_from(
380 &self,
381 key: &K,
382 floor: Location<F>,
383 ) -> Result<Option<V::Value>, Error<F>> {
384 let _timer = self.metrics.get_timer();
385 self.metrics.get_calls.inc();
386 self.metrics.lookups_requested.inc();
387 for loc in self.snapshot.get(key) {
388 let loc = Location::new(loc);
389 if loc < floor {
390 continue;
391 }
392 if let Some(v) = Self::get_from_loc(&self.journal, key, loc).await? {
393 return Ok(Some(v));
394 }
395 }
396 Ok(None)
397 }
398
399 pub async fn get_many(&self, keys: &[&K]) -> Result<Vec<Option<V::Value>>, Error<F>> {
404 self.get_many_from(keys, Location::new(0)).await
405 }
406
407 pub(crate) async fn get_many_from(
409 &self,
410 keys: &[&K],
411 floor: Location<F>,
412 ) -> Result<Vec<Option<V::Value>>, Error<F>> {
413 if keys.is_empty() {
414 return Ok(Vec::new());
415 }
416
417 let _timer = self.metrics.get_many_timer();
418 self.metrics.get_many_calls.inc();
419 self.metrics.lookups_requested.inc_by(keys.len() as u64);
420 let mut candidates: Vec<(usize, u64)> = Vec::with_capacity(keys.len());
421 let mut results: Vec<Option<V::Value>> = vec![None; keys.len()];
422
423 for (key_idx, key) in keys.iter().enumerate() {
427 for loc in self.snapshot.get(key) {
428 if loc < *floor {
429 continue;
430 }
431 candidates.push((key_idx, loc));
432 }
433 }
434
435 if candidates.is_empty() {
436 return Ok(results);
437 }
438
439 candidates.sort_unstable_by_key(|&(_, pos)| pos);
440
441 let same_pos = |a: &(usize, u64), b: &(usize, u64)| a.1 == b.1;
442 let positions: Vec<u64> = candidates
443 .chunk_by(same_pos)
444 .map(|group| group[0].1)
445 .collect();
446
447 let ops = self.journal.read_many(&positions).await?;
448 assert_eq!(
449 ops.len(),
450 positions.len(),
451 "read_many returns one operation per position"
452 );
453
454 for (op, group) in ops.into_iter().zip(candidates.chunk_by(same_pos)) {
455 let Operation::Set(k, v) = op else {
456 return Err(Error::UnexpectedData(Location::new(group[0].1)));
457 };
458 let mut pending = None;
459 for &(key_idx, _) in group {
460 if results[key_idx].is_some() || k != *keys[key_idx] {
461 continue;
462 }
463 if let Some(prev) = pending.replace(key_idx) {
464 results[prev] = Some(v.clone());
465 }
466 }
467 if let Some(last) = pending {
468 results[last] = Some(v);
469 }
470 }
471
472 Ok(results)
473 }
474
475 async fn get_from_loc(
479 reader: &impl Contiguous<Item = Operation<F, K, V>>,
480 key: &K,
481 loc: Location<F>,
482 ) -> Result<Option<V::Value>, Error<F>> {
483 if loc < reader.bounds().start {
484 return Err(Error::OperationPruned(loc));
485 }
486
487 let Operation::Set(k, v) = reader.read(*loc).await? else {
488 return Err(Error::UnexpectedData(loc));
489 };
490
491 if k != *key { Ok(None) } else { Ok(Some(v)) }
492 }
493
494 pub async fn get_metadata(&self) -> Result<Option<V::Value>, Error<F>> {
496 let last_commit_loc = self.size() - 1;
498 let Operation::Commit(metadata, _floor) =
499 self.journal.journal.read(*last_commit_loc).await?
500 else {
501 unreachable!("no commit operation at location of last commit {last_commit_loc}");
502 };
503
504 Ok(metadata)
505 }
506
507 #[allow(clippy::type_complexity)]
527 #[tracing::instrument(
528 name = "qmdb.immutable.db.historical_proof",
529 level = "info",
530 skip_all,
531 fields(
532 op_count = *op_count,
533 start_loc = *start_loc,
534 max_ops = max_ops.get(),
535 ),
536 )]
537 pub async fn historical_proof(
538 &self,
539 op_count: Location<F>,
540 start_loc: Location<F>,
541 max_ops: NonZeroU64,
542 ) -> Result<(Proof<F, H::Digest>, Vec<Operation<F, K, V>>), Error<F>> {
543 if op_count > self.journal.size() {
544 return Err(crate::merkle::Error::RangeOutOfBounds(op_count).into());
545 }
546
547 let inactive_peaks =
548 crate::qmdb::inactive_peaks_at::<F, _>(&self.journal, op_count).await?;
549
550 Ok(self
551 .journal
552 .historical_proof(op_count, start_loc, max_ops, inactive_peaks)
553 .await?)
554 }
555
556 pub async fn proof(
563 &self,
564 start_index: Location<F>,
565 max_ops: NonZeroU64,
566 ) -> Result<(Proof<F, H::Digest>, Vec<Operation<F, K, V>>), Error<F>> {
567 let op_count = self.bounds().end;
568 self.historical_proof(op_count, start_index, max_ops).await
569 }
570
571 #[tracing::instrument(name = "qmdb.immutable.db.prune", level = "info", skip_all)]
583 #[boxed]
584 pub async fn prune(mut self, loc: Location<F>) -> Result<Self, Error<F>> {
585 let _timer = self.metrics.prune_timer();
586 self.metrics.prune_calls.inc();
587 if loc > self.inactivity_floor_loc {
588 return Err(Error::PruneBeyondMinRequired(
589 loc,
590 self.inactivity_floor_loc,
591 ));
592 }
593 (self.journal, _) = self.journal.prune(loc).await?;
594 self.snapshot.prune(*self.bounds().start);
595 self.update_metrics();
596 Ok(self)
597 }
598
599 pub const fn root(&self) -> H::Digest {
601 self.root
602 }
603
604 pub const fn strategy(&self) -> &S {
606 self.journal.strategy()
607 }
608
609 pub async fn pinned_nodes_at(&self, loc: Location<F>) -> Result<Vec<H::Digest>, Error<F>> {
611 self.journal
612 .merkle
613 .pinned_nodes_at(loc)
614 .await
615 .map_err(Into::into)
616 }
617
618 #[tracing::instrument(name = "qmdb.immutable.db.sync", level = "info", skip_all)]
622 pub async fn sync(mut self) -> Result<Self, Error<F>> {
623 let _timer = self.metrics.sync_timer();
624 self.metrics.sync_calls.inc();
625 self.journal = self.journal.sync().await?;
626 Ok(self)
627 }
628
629 #[tracing::instrument(name = "qmdb.immutable.db.start_sync", level = "info", skip_all)]
640 pub async fn start_sync(mut self) -> Result<(Self, Handle<()>), Error<F>> {
641 self.metrics.start_sync_calls.inc();
642 let handle;
643 (self.journal, handle) = self.journal.start_sync().await?;
644 Ok((self, handle))
645 }
646
647 #[tracing::instrument(name = "qmdb.immutable.db.commit", level = "info", skip_all)]
649 pub async fn commit(mut self) -> Result<Self, Error<F>> {
650 let _timer = self.metrics.commit_timer();
651 self.metrics.commit_calls.inc();
652 self.journal = self.journal.commit().await?;
653 Ok(self)
654 }
655
656 #[boxed]
658 pub async fn destroy(self) -> Result<(), Error<F>> {
659 Ok(self.journal.destroy().await?)
660 }
661
662 pub(crate) fn commitment(&self) -> chain::Commitment<F, H::Digest> {
664 chain::Commitment::new(self.size(), self.root)
665 }
666
667 pub fn new_batch(&self) -> batch::UnmerkleizedBatch<F, H, K, V, S> {
669 batch::UnmerkleizedBatch::new(self, self.commitment())
670 }
671
672 pub fn validate_batch(
678 &self,
679 batch: &batch::MerkleizedBatch<F, H::Digest, K, V, S>,
680 ) -> Result<(), Error<F>> {
681 batch.bounds.validate_apply_to(self.commitment())
682 }
683
684 #[tracing::instrument(name = "qmdb.immutable.db.apply_batch", level = "info", skip_all)]
695 pub async fn apply_batch(
696 mut self,
697 batch: Arc<batch::MerkleizedBatch<F, H::Digest, K, V, S>>,
698 ) -> Result<Self, Error<F>> {
699 let _timer = self.metrics.apply_batch_timer();
700 self.metrics.apply_batch_calls.inc();
701 self.validate_batch(&batch)?;
702 let db_size = self.size();
703
704 let apply_snapshot = async {
706 for (key, entry) in batch.diff.iter() {
707 self.snapshot.insert(key, *entry.loc);
708 }
709 for (i, ancestor_diff) in batch.ancestor_diffs.iter().enumerate() {
710 if batch.bounds.ancestors[i].size <= db_size {
711 continue;
712 }
713 for (key, entry) in ancestor_diff.iter() {
714 self.snapshot.insert(key, *entry.loc);
715 }
716 }
717 };
718 let (journal, ()) = futures::join!(
719 self.journal.apply_batch(&batch.journal_batch),
720 apply_snapshot
721 );
722 self.journal = journal?;
723
724 self.inactivity_floor_loc = batch.bounds.inactivity_floor;
726 self.root = batch.root();
727 self.update_metrics();
728 self.metrics
729 .operations_applied
730 .inc_by(*batch.bounds.tip.size - *db_size);
731 Ok(self)
732 }
733}
734
735impl<F, E, K, V, C, H, T, S> crate::qmdb::sync::Source for Immutable<F, E, K, V, C, H, T, S>
736where
737 F: Family,
738 E: Context,
739 K: Key,
740 V: ValueEncoding,
741 C: Mutable<Item = Operation<F, K, V>>,
742 Operation<F, K, V>: EncodeShared,
743 H: Hasher,
744 T: Translator,
745 S: Strategy,
746{
747 type Family = F;
748 type Digest = H::Digest;
749 type Op = Operation<F, K, V>;
750 type Error = Error<F>;
751
752 async fn serve(&self, request: crate::qmdb::sync::Request<F>) -> source::Result<Self> {
753 self.journal.serve(request).await
754 }
755}
756
757#[cfg(test)]
758pub(super) mod tests {
759 use super::*;
760 use crate::{
761 merkle::{Family, Location},
762 qmdb::{verify_proof, verify_proof_and_pinned_nodes},
763 translator::TwoCap,
764 };
765 use commonware_codec::EncodeShared;
766 use commonware_cryptography::{Sha256, sha256, sha256::Digest};
767 use commonware_runtime::{Supervisor as _, deterministic};
768 use commonware_utils::NZU64;
769 use core::{future::Future, pin::Pin};
770
771 const ITEMS_PER_SECTION: u64 = 5;
772
773 macro_rules! immutable_tests {
775 ($($name:ident => $scenario:ident, $open:ident;)*) => {
776 $(
777 #[test_traced]
778 fn $name() {
779 deterministic::Runner::default().start(|ctx| async move {
780 immutable_tests!(@fixture $open, $scenario, mmr, ctx);
781 });
782 }
783 )*
784 paste::paste! {
785 $(
786 #[test_traced]
787 fn [<$name _mmb>]() {
788 deterministic::Runner::default().start(|ctx| async move {
789 immutable_tests!(@fixture $open, $scenario, mmb, ctx);
790 });
791 }
792 )*
793 }
794 };
795 (@fixture pair, $scenario:ident, $family:ident, $ctx:ident) => {
796 let db = Db::<$family::Family, _, Digest, Digest, Sha256, TwoCap, Sequential>::init(
797 $ctx.child("db"), config("db"), None,
798 ).await.unwrap();
799 let foreign = Db::<$family::Family, _, Digest, Digest, Sha256, TwoCap, Sequential>::init(
800 $ctx.child("foreign"), config("foreign"), None,
801 ).await.unwrap();
802 tests::$scenario(db, foreign).await;
803 };
804 (@fixture $open:ident, $scenario:ident, $family:ident, $ctx:ident) => {
805 tests::$scenario($ctx, $open::<$family::Family>).await;
806 };
807 }
808
809 pub(super) use immutable_tests;
810
811 type TestDb<F, V, C> = Immutable<
812 F,
813 deterministic::Context,
814 Digest,
815 V,
816 C,
817 Sha256,
818 TwoCap,
819 commonware_parallel::Sequential,
820 >;
821
822 #[boxed]
825 pub(crate) async fn run_dropped_ancestor_reads<F: Family, V, C>(
826 context: deterministic::Context,
827 open_db: impl Fn(
828 deterministic::Context,
829 ) -> Pin<Box<dyn Future<Output = TestDb<F, V, C>> + Send>>,
830 ) where
831 V: ValueEncoding<Value = Digest>,
832 C: Mutable<Item = Operation<F, Digest, V>>,
833 C::Item: EncodeShared,
834 {
835 let db = open_db(context.child("db")).await;
836
837 let untouched = Sha256::fill(0u8);
839 let untouched_value = Sha256::fill(100u8);
840 let seed = db
841 .new_batch()
842 .set(untouched, untouched_value)
843 .merkleize(&db, None, Location::new(0))
844 .await
845 .unwrap();
846 let db = db.apply_batch(seed).await.unwrap();
847
848 let a = db
850 .new_batch()
851 .set(Sha256::fill(1u8), Sha256::fill(101u8))
852 .merkleize(&db, None, Location::new(0))
853 .await
854 .unwrap();
855 let b = a
856 .new_batch::<Sha256>()
857 .set(Sha256::fill(2u8), Sha256::fill(102u8))
858 .merkleize(&db, None, Location::new(0))
859 .await
860 .unwrap();
861 let c = b
862 .new_batch::<Sha256>()
863 .set(Sha256::fill(3u8), Sha256::fill(103u8))
864 .merkleize(&db, None, Location::new(0))
865 .await
866 .unwrap();
867 let child = c.new_batch::<Sha256>();
868 drop(a);
869 drop(b);
870
871 for i in 0..4u8 {
874 let key = Sha256::fill(i);
875 let expected = Some(Sha256::fill(i.wrapping_add(100)));
876 assert_eq!(c.get(&key, &db).await.unwrap(), expected);
877 assert_eq!(child.get(&key, &db).await.unwrap(), expected);
878 }
879 let keys: Vec<_> = (0..4u8).map(Sha256::fill).collect();
880 let key_refs: Vec<_> = keys.iter().collect();
881 let expected: Vec<_> = (0..4u8)
882 .map(|i| Some(Sha256::fill(i.wrapping_add(100))))
883 .collect();
884 assert_eq!(c.get_many(&key_refs, &db).await.unwrap(), expected);
885 assert_eq!(child.get_many(&key_refs, &db).await.unwrap(), expected);
886
887 assert!(matches!(
889 child.merkleize(&db, None, Location::new(0)).await,
890 Err(Error::StaleBatch)
891 ));
892
893 let db = db.apply_batch(c).await.unwrap();
895 for i in 0..4u8 {
896 assert_eq!(
897 db.get(&Sha256::fill(i)).await.unwrap(),
898 Some(Sha256::fill(i.wrapping_add(100)))
899 );
900 }
901 assert_eq!(db.get(&untouched).await.unwrap(), Some(untouched_value));
902 db.destroy().await.unwrap();
903 }
904
905 #[boxed]
908 pub(crate) async fn run_multi_key_batch_reads<F: Family, V, C>(
909 context: deterministic::Context,
910 open_db: impl Fn(
911 deterministic::Context,
912 ) -> Pin<Box<dyn Future<Output = TestDb<F, V, C>> + Send>>,
913 ) where
914 V: ValueEncoding<Value = Digest>,
915 C: Mutable<Item = Operation<F, Digest, V>>,
916 C::Item: EncodeShared,
917 {
918 let db = open_db(context.child("db")).await;
919
920 let value = |i: u8| Sha256::fill(i.wrapping_add(100));
922 let mut batch = db.new_batch();
923 for i in (0..8u8).rev() {
924 batch = batch.set(Sha256::fill(i), value(i));
925 }
926 let parent = batch.merkleize(&db, None, Location::new(0)).await.unwrap();
927
928 let keys: Vec<_> = (0..8u8).map(Sha256::fill).collect();
929 let key_refs: Vec<_> = keys.iter().collect();
930 let expected: Vec<_> = (0..8u8).map(|i| Some(value(i))).collect();
931
932 assert_eq!(parent.get_many(&key_refs, &db).await.unwrap(), expected);
935 let draft = parent.new_batch::<Sha256>();
936 assert_eq!(draft.get_many(&key_refs, &db).await.unwrap(), expected);
937 let child = draft.merkleize(&db, None, Location::new(0)).await.unwrap();
938 assert_eq!(child.get_many(&key_refs, &db).await.unwrap(), expected);
939 for i in 0..8u8 {
940 assert_eq!(
941 child.get(&Sha256::fill(i), &db).await.unwrap(),
942 Some(value(i))
943 );
944 }
945
946 db.destroy().await.unwrap();
947 }
948
949 #[boxed]
951 pub(crate) async fn run_proof_refused_after_sibling_apply<F: Family, V, C>(
952 context: deterministic::Context,
953 open_db: impl Fn(
954 deterministic::Context,
955 ) -> Pin<Box<dyn Future<Output = TestDb<F, V, C>> + Send>>,
956 ) where
957 V: ValueEncoding<Value = Digest>,
958 C: Mutable<Item = Operation<F, Digest, V>>,
959 C::Item: EncodeShared,
960 {
961 let db = open_db(context.child("db")).await;
962 let batch = db
963 .new_batch()
964 .set(Sha256::fill(1u8), Sha256::fill(101u8))
965 .merkleize(&db, None, Location::new(0))
966 .await
967 .unwrap();
968 let sibling = db
969 .new_batch()
970 .set(Sha256::fill(1u8), Sha256::fill(102u8))
971 .merkleize(&db, None, Location::new(0))
972 .await
973 .unwrap();
974 assert!(batch.proof(&db).is_ok());
975 assert!(batch.pinned_nodes(&db).is_ok());
976
977 let db = db.apply_batch(sibling).await.unwrap();
979 assert!(matches!(batch.proof(&db), Err(Error::StaleRead)));
980 assert!(matches!(batch.pinned_nodes(&db), Err(Error::StaleRead)));
981 db.destroy().await.unwrap();
982 }
983
984 #[boxed]
987 pub(crate) async fn run_reads_ignore_inactive_operations<F: Family, V, C>(
988 context: deterministic::Context,
989 open_db: impl Fn(
990 deterministic::Context,
991 ) -> Pin<Box<dyn Future<Output = TestDb<F, V, C>> + Send>>,
992 ) where
993 V: ValueEncoding<Value = Digest>,
994 C: Mutable<Item = Operation<F, Digest, V>>,
995 C::Item: EncodeShared,
996 {
997 let db = open_db(context.child("db")).await;
998 let (old, fresh, own) = (Sha256::fill(1u8), Sha256::fill(2u8), Sha256::fill(3u8));
999
1000 let seed = db
1002 .new_batch()
1003 .set(old, Sha256::fill(101u8))
1004 .merkleize(&db, None, Location::new(0))
1005 .await
1006 .unwrap();
1007 let db = db.apply_batch(seed).await.unwrap();
1008
1009 let mut filler = db.new_batch();
1011 for i in 10..18u8 {
1012 filler = filler.set(Sha256::fill(i), Sha256::fill(i));
1013 }
1014 let filler = filler.merkleize(&db, None, Location::new(0)).await.unwrap();
1015 let db = db.apply_batch(filler).await.unwrap();
1016
1017 let base = db.bounds().end;
1019 let parent = db
1020 .new_batch()
1021 .set(fresh, Sha256::fill(102u8))
1022 .merkleize(&db, None, base)
1023 .await
1024 .unwrap();
1025 assert_eq!(parent.get(&old, &db).await.unwrap(), None);
1026 assert_eq!(
1027 parent.get(&fresh, &db).await.unwrap(),
1028 Some(Sha256::fill(102u8))
1029 );
1030 let child = parent.new_batch::<Sha256>();
1031 assert_eq!(child.get(&old, &db).await.unwrap(), None);
1032 assert_eq!(
1033 child.get_many(&[&old, &fresh], &db).await.unwrap(),
1034 vec![None, Some(Sha256::fill(102u8))]
1035 );
1036
1037 let grandchild = child
1039 .set(own, Sha256::fill(103u8))
1040 .merkleize(&db, None, base + 3)
1041 .await
1042 .unwrap();
1043 assert_eq!(
1044 grandchild
1045 .get_many(&[&old, &fresh, &own], &db)
1046 .await
1047 .unwrap(),
1048 vec![None, None, None]
1049 );
1050 drop(grandchild);
1051
1052 let db = db.apply_batch(parent).await.unwrap();
1055 let db = db.commit().await.unwrap();
1056 let expected = vec![None, Some(Sha256::fill(102u8))];
1057 assert_eq!(
1058 db.new_batch().get_many(&[&old, &fresh], &db).await.unwrap(),
1059 expected
1060 );
1061 assert_eq!(
1062 db.new_batch().get(&fresh, &db).await.unwrap(),
1063 Some(Sha256::fill(102u8))
1064 );
1065
1066 let mut twin = [1u8; 32];
1069 twin[31] = 9;
1070 let twin = Digest(twin);
1071 let collision = db
1072 .new_batch()
1073 .set(twin, Sha256::fill(104u8))
1074 .merkleize(&db, None, base)
1075 .await
1076 .unwrap();
1077 let db = db.apply_batch(collision).await.unwrap();
1078 let db = db.commit().await.unwrap();
1079 let collided = vec![None, Some(Sha256::fill(104u8))];
1080 assert_eq!(db.new_batch().get(&old, &db).await.unwrap(), None);
1081 assert_eq!(
1082 db.new_batch().get(&twin, &db).await.unwrap(),
1083 Some(Sha256::fill(104u8))
1084 );
1085 assert_eq!(
1086 db.new_batch().get_many(&[&old, &twin], &db).await.unwrap(),
1087 collided
1088 );
1089 let db = db.prune(base).await.unwrap();
1090 assert!(db.bounds().start > Location::new(1), "`old` must be pruned");
1091 assert_eq!(
1092 db.new_batch().get_many(&[&old, &fresh], &db).await.unwrap(),
1093 expected
1094 );
1095 assert_eq!(
1096 db.new_batch().get_many(&[&old, &twin], &db).await.unwrap(),
1097 collided
1098 );
1099 drop(db);
1100 let db = open_db(context.child("db")).await;
1101 assert_eq!(
1102 db.new_batch().get_many(&[&old, &fresh], &db).await.unwrap(),
1103 expected
1104 );
1105 assert_eq!(db.new_batch().get(&old, &db).await.unwrap(), None);
1106 assert_eq!(
1107 db.new_batch().get_many(&[&old, &twin], &db).await.unwrap(),
1108 collided
1109 );
1110 assert_eq!(
1111 db.new_batch().get(&twin, &db).await.unwrap(),
1112 Some(Sha256::fill(104u8))
1113 );
1114 db.destroy().await.unwrap();
1115 }
1116
1117 #[boxed]
1120 pub(crate) async fn run_merkleize_across_prune<F: Family, V, C>(
1121 context: deterministic::Context,
1122 open_db: impl Fn(
1123 deterministic::Context,
1124 ) -> Pin<Box<dyn Future<Output = TestDb<F, V, C>> + Send>>,
1125 ) where
1126 V: ValueEncoding<Value = Digest>,
1127 C: Mutable<Item = Operation<F, Digest, V>>,
1128 C::Item: EncodeShared,
1129 {
1130 let db = open_db(context.child("db")).await;
1131
1132 let mut seed = db.new_batch();
1135 for i in 0..40u8 {
1136 seed = seed.set(Sha256::fill(i), Sha256::fill(i.wrapping_add(100)));
1137 }
1138 let seed = seed.merkleize(&db, None, Location::new(0)).await.unwrap();
1139 let db = db.apply_batch(seed).await.unwrap();
1140 let db = db.commit().await.unwrap();
1141
1142 let parent_floor = db.bounds().end + 1;
1144 let parent = db
1145 .new_batch()
1146 .set(Sha256::fill(200u8), Sha256::fill(212u8))
1147 .merkleize(&db, None, parent_floor)
1148 .await
1149 .unwrap();
1150
1151 let child = parent
1154 .new_batch::<Sha256>()
1155 .set(Sha256::fill(201u8), Sha256::fill(213u8));
1156 let twin = parent
1157 .new_batch::<Sha256>()
1158 .set(Sha256::fill(201u8), Sha256::fill(213u8));
1159 let expected = twin
1160 .merkleize(&db, None, parent_floor)
1161 .await
1162 .unwrap()
1163 .root();
1164
1165 let db = db.apply_batch(Arc::clone(&parent)).await.unwrap();
1167 let db = db.commit().await.unwrap();
1168 let floor = db.inactivity_floor_loc();
1169 let db = db.prune(floor).await.unwrap();
1170 assert!(*db.bounds().start > 0, "the prune must remove history");
1171
1172 let merkleized = child.merkleize(&db, None, parent_floor).await.unwrap();
1174 assert_eq!(merkleized.root(), expected);
1175 db.destroy().await.unwrap();
1176 }
1177
1178 #[boxed]
1181 pub(crate) async fn run_stale_fork_refuses<F: Family, V, C>(
1182 context: deterministic::Context,
1183 open_db: impl Fn(
1184 deterministic::Context,
1185 ) -> Pin<Box<dyn Future<Output = TestDb<F, V, C>> + Send>>,
1186 ) where
1187 V: ValueEncoding<Value = Digest>,
1188 C: Mutable<Item = Operation<F, Digest, V>>,
1189 C::Item: EncodeShared,
1190 {
1191 let db = open_db(context.child("db")).await;
1192 let k1 = Sha256::fill(1u8);
1193 let k2 = Sha256::fill(2u8);
1194 let floor = db.inactivity_floor_loc();
1195 let winner = db
1196 .new_batch()
1197 .set(k1, Sha256::fill(3u8))
1198 .merkleize(&db, None, floor)
1199 .await
1200 .unwrap();
1201 let loser = db
1202 .new_batch()
1203 .set(k1, Sha256::fill(4u8))
1204 .merkleize(&db, None, floor)
1205 .await
1206 .unwrap();
1207 assert_eq!(winner.bounds().tip.size, loser.bounds().tip.size);
1208 assert_ne!(winner.root(), loser.root());
1209
1210 let child = loser.new_batch::<Sha256>().set(k2, Sha256::fill(5u8));
1211 let direct = db.new_batch().set(k2, Sha256::fill(6u8));
1212 let db = db.apply_batch(winner).await.unwrap();
1213
1214 assert!(matches!(direct.get(&k1, &db).await, Err(Error::StaleRead)));
1216 assert!(matches!(
1217 direct.get_many(&[&k1], &db).await,
1218 Err(Error::StaleRead)
1219 ));
1220
1221 assert!(matches!(child.get(&k1, &db).await, Err(Error::StaleRead)));
1222 assert!(matches!(
1223 child.get_many(&[&k1], &db).await,
1224 Err(Error::StaleRead)
1225 ));
1226 assert!(matches!(loser.get(&k1, &db).await, Err(Error::StaleRead)));
1227
1228 let no_keys: [&Digest; 0] = [];
1231 assert!(matches!(
1232 child.get_many(&no_keys, &db).await,
1233 Err(Error::StaleRead)
1234 ));
1235 assert!(matches!(
1236 loser.get_many(&no_keys, &db).await,
1237 Err(Error::StaleRead)
1238 ));
1239 assert!(matches!(
1240 child.merkleize(&db, None, floor).await,
1241 Err(Error::StaleBatch)
1242 ));
1243 assert!(matches!(db.validate_batch(&loser), Err(Error::StaleBatch)));
1244 db.destroy().await.unwrap();
1245 }
1246
1247 #[boxed]
1250 pub(crate) async fn run_descendant_apply_makes_parent_reads_stale<F: Family, V, C>(
1251 context: deterministic::Context,
1252 open_db: impl Fn(
1253 deterministic::Context,
1254 ) -> Pin<Box<dyn Future<Output = TestDb<F, V, C>> + Send>>,
1255 ) where
1256 V: ValueEncoding<Value = Digest>,
1257 C: Mutable<Item = Operation<F, Digest, V>>,
1258 C::Item: EncodeShared,
1259 {
1260 let db = open_db(context.child("db")).await;
1261 let (k1, k2) = (Sha256::fill(1u8), Sha256::fill(2u8));
1262 let floor = db.inactivity_floor_loc();
1263 let parent = db
1264 .new_batch()
1265 .set(k1, Sha256::fill(3u8))
1266 .merkleize(&db, None, floor)
1267 .await
1268 .unwrap();
1269 assert_eq!(parent.get(&k1, &db).await.unwrap(), Some(Sha256::fill(3u8)));
1270 let child = parent
1271 .new_batch::<Sha256>()
1272 .set(k2, Sha256::fill(4u8))
1273 .merkleize(&db, None, floor)
1274 .await
1275 .unwrap();
1276
1277 let db = db.apply_batch(child.clone()).await.unwrap();
1278 assert_eq!(child.get(&k1, &db).await.unwrap(), Some(Sha256::fill(3u8)));
1279 assert!(matches!(parent.get(&k1, &db).await, Err(Error::StaleRead)));
1280 assert!(matches!(
1281 parent.get_many(&[&k1], &db).await,
1282 Err(Error::StaleRead)
1283 ));
1284 db.destroy().await.unwrap();
1285 }
1286
1287 #[boxed]
1288 pub(crate) async fn run_empty<F: Family, V, C>(
1289 context: deterministic::Context,
1290 open_db: impl Fn(
1291 deterministic::Context,
1292 ) -> Pin<Box<dyn Future<Output = TestDb<F, V, C>> + Send>>,
1293 ) where
1294 V: ValueEncoding<Value = Digest>,
1295 C: Mutable<Item = Operation<F, Digest, V>>,
1296 C::Item: EncodeShared,
1297 {
1298 let db = open_db(context.child("first")).await;
1299 let bounds = db.bounds();
1300 assert_eq!(bounds.end, 1);
1301 assert_eq!(bounds.start, Location::new(0));
1302 assert_eq!(db.inactivity_floor_loc(), Location::new(0));
1303 assert!(db.get_metadata().await.unwrap().is_none());
1304
1305 let k1 = Sha256::fill(1u8);
1307 let v1 = Sha256::fill(2u8);
1308 let root = db.root();
1309 {
1310 let _batch = db.new_batch().set(k1, v1);
1311
1312 }
1314 drop(db);
1315 let db = open_db(context.child("second")).await;
1316 assert_eq!(db.root(), root);
1317 assert_eq!(db.bounds().end, 1);
1318
1319 let merkleized = db
1321 .new_batch()
1322 .merkleize(&db, None, Location::new(0))
1323 .await
1324 .unwrap();
1325 let db = db.apply_batch(merkleized).await.unwrap();
1326 let db = db.commit().await.unwrap();
1327 assert_eq!(db.bounds().end, 2); let root = db.root();
1329 drop(db);
1330
1331 let db = open_db(context.child("third")).await;
1332 assert_eq!(db.root(), root);
1333
1334 db.destroy().await.unwrap();
1335 }
1336
1337 #[boxed]
1338 pub(crate) async fn run_commit_after_sync_recovery<F: Family, V, C>(
1339 context: deterministic::Context,
1340 open_db: impl Fn(
1341 deterministic::Context,
1342 ) -> Pin<Box<dyn Future<Output = TestDb<F, V, C>> + Send>>,
1343 ) where
1344 V: ValueEncoding<Value = Digest>,
1345 C: Mutable<Item = Operation<F, Digest, V>>,
1346 C::Item: EncodeShared,
1347 {
1348 let db = open_db(context.child("first")).await;
1349 let k1 = Sha256::fill(1u8);
1350 let k2 = Sha256::fill(2u8);
1351 let v1 = Sha256::fill(3u8);
1352 let v2 = Sha256::fill(4u8);
1353
1354 let db = commit_sets(db, [(k1, v1)], None).await;
1356 let db = db.sync().await.unwrap();
1357
1358 let db = commit_sets(db, [(k2, v2)], None).await;
1360 let committed_bounds = db.bounds();
1361 let committed_root = db.root();
1362 drop(db);
1363
1364 let db = open_db(context.child("second")).await;
1365 assert_eq!(db.bounds(), committed_bounds);
1366 assert_eq!(db.root(), committed_root);
1367 assert_eq!(db.get(&k1).await.unwrap(), Some(v1));
1368 assert_eq!(db.get(&k2).await.unwrap(), Some(v2));
1369
1370 db.destroy().await.unwrap();
1371 }
1372
1373 #[boxed]
1374 pub(crate) async fn run_build_basic<F: Family, V, C>(
1375 context: deterministic::Context,
1376 open_db: impl Fn(
1377 deterministic::Context,
1378 ) -> Pin<Box<dyn Future<Output = TestDb<F, V, C>> + Send>>,
1379 ) where
1380 V: ValueEncoding<Value = Digest>,
1381 C: Mutable<Item = Operation<F, Digest, V>>,
1382 C::Item: EncodeShared,
1383 {
1384 let db = open_db(context.child("first")).await;
1386
1387 let k1 = Sha256::fill(1u8);
1388 let k2 = Sha256::fill(2u8);
1389 let v1 = Sha256::fill(3u8);
1390 let v2 = Sha256::fill(4u8);
1391
1392 assert!(db.get(&k1).await.unwrap().is_none());
1393 assert!(db.get(&k2).await.unwrap().is_none());
1394
1395 let metadata = Some(Sha256::fill(99u8));
1397 let merkleized = db
1398 .new_batch()
1399 .set(k1, v1)
1400 .merkleize(&db, metadata, Location::new(0))
1401 .await
1402 .unwrap();
1403 let db = db.apply_batch(merkleized).await.unwrap();
1404 let db = db.commit().await.unwrap();
1405 assert_eq!(db.get(&k1).await.unwrap().unwrap(), v1);
1406 assert!(db.get(&k2).await.unwrap().is_none());
1407 assert_eq!(db.bounds().end, 3);
1408 assert_eq!(db.get_metadata().await.unwrap(), Some(Sha256::fill(99u8)));
1409
1410 let merkleized = db
1412 .new_batch()
1413 .set(k2, v2)
1414 .merkleize(&db, None, Location::new(0))
1415 .await
1416 .unwrap();
1417 let db = db.apply_batch(merkleized).await.unwrap();
1418 let db = db.commit().await.unwrap();
1419 assert_eq!(db.get(&k1).await.unwrap().unwrap(), v1);
1420 assert_eq!(db.get(&k2).await.unwrap().unwrap(), v2);
1421 assert_eq!(db.bounds().end, 5);
1422 assert_eq!(db.get_metadata().await.unwrap(), None);
1423
1424 let root = db.root();
1426
1427 let k3 = Sha256::fill(5u8);
1429 let v3 = Sha256::fill(6u8);
1430 {
1431 let _batch = db.new_batch().set(k3, v3);
1432
1433 }
1435
1436 drop(db); let db = open_db(context.child("second")).await;
1439 assert!(db.get(&k3).await.unwrap().is_none());
1440 assert_eq!(db.root(), root);
1441 assert_eq!(db.get(&k1).await.unwrap().unwrap(), v1);
1442 assert_eq!(db.get(&k2).await.unwrap().unwrap(), v2);
1443 assert_eq!(db.bounds().end, 5);
1444 assert_eq!(db.get_metadata().await.unwrap(), None);
1445
1446 db.destroy().await.unwrap();
1448 }
1449
1450 #[boxed]
1451 pub(crate) async fn run_proof_verify<F: Family, V, C>(
1452 context: deterministic::Context,
1453 open_db: impl Fn(
1454 deterministic::Context,
1455 ) -> Pin<Box<dyn Future<Output = TestDb<F, V, C>> + Send>>,
1456 ) where
1457 V: ValueEncoding<Value = Digest>,
1458 C: Mutable<Item = Operation<F, Digest, V>>,
1459 C::Item: EncodeShared,
1460 {
1461 let db = open_db(context.child("first")).await;
1462
1463 let k1 = Sha256::fill(1u8);
1464 let v1 = Sha256::fill(10u8);
1465 let merkleized = db
1466 .new_batch()
1467 .set(k1, v1)
1468 .merkleize(&db, None, Location::new(0))
1469 .await
1470 .unwrap();
1471 let db = db.apply_batch(merkleized).await.unwrap();
1472 let db = db.commit().await.unwrap();
1473
1474 let (proof, ops) = db.proof(Location::new(0), NZU64!(100)).await.unwrap();
1475 let root = db.root();
1476 assert!(verify_proof::<Sha256, _, _>(
1477 &proof,
1478 Location::new(0),
1479 &ops,
1480 &root
1481 ));
1482
1483 db.destroy().await.unwrap();
1484 }
1485
1486 #[boxed]
1487 pub(crate) async fn run_prune<F: Family, V, C>(
1488 context: deterministic::Context,
1489 open_db: impl Fn(
1490 deterministic::Context,
1491 ) -> Pin<Box<dyn Future<Output = TestDb<F, V, C>> + Send>>,
1492 ) where
1493 V: ValueEncoding<Value = Digest>,
1494 C: Mutable<Item = Operation<F, Digest, V>>,
1495 C::Item: EncodeShared,
1496 {
1497 let mut db = open_db(context.child("first")).await;
1498
1499 for i in 0..20u8 {
1500 let key = Sha256::fill(i);
1501 let value = Sha256::fill(i.wrapping_add(100));
1502 let floor = db.bounds().end;
1503 let merkleized = db
1504 .new_batch()
1505 .set(key, value)
1506 .merkleize(&db, None, floor)
1507 .await
1508 .unwrap();
1509 db = db.apply_batch(merkleized).await.unwrap();
1510 db = db.commit().await.unwrap();
1511 }
1512
1513 let root_before = db.root();
1514 let bounds_before = db.bounds();
1515
1516 let prune_loc = bounds_before.end - 5;
1517 let db = db.prune(prune_loc).await.unwrap();
1518
1519 assert_eq!(db.root(), root_before);
1520
1521 let key_0 = Sha256::fill(0u8);
1522 assert!(db.get(&key_0).await.unwrap().is_none());
1523
1524 let key_19 = Sha256::fill(19u8);
1525 assert_eq!(
1526 db.get(&key_19).await.unwrap(),
1527 Some(Sha256::fill(19u8.wrapping_add(100)))
1528 );
1529
1530 db.destroy().await.unwrap();
1531 }
1532
1533 #[boxed]
1537 pub(crate) async fn run_prune_after_uncommitted_apply_batch_recovery<F: Family, V, C>(
1538 context: deterministic::Context,
1539 open_db: impl Fn(
1540 deterministic::Context,
1541 ) -> Pin<Box<dyn Future<Output = TestDb<F, V, C>> + Send>>,
1542 ) where
1543 V: ValueEncoding<Value = Digest>,
1544 C: Mutable<Item = Operation<F, Digest, V>>,
1545 C::Item: EncodeShared,
1546 {
1547 let db = open_db(context.child("first")).await;
1548
1549 let mut batch = db.new_batch();
1552 for i in 0..6u8 {
1553 batch = batch.set(Sha256::fill(i), Sha256::fill(i.wrapping_add(10)));
1554 }
1555 let merkleized = batch.merkleize(&db, None, Location::new(0)).await.unwrap();
1556 let db = db.apply_batch(merkleized).await.unwrap();
1557 let db = db.sync().await.unwrap();
1558 let durable_state = (db.root(), db.inactivity_floor_loc(), db.bounds().end);
1559
1560 let buffered_floor = db.bounds().end;
1563 let key = Sha256::fill(100);
1564 let value = Sha256::fill(101);
1565 let merkleized = db
1566 .new_batch()
1567 .set(key, value)
1568 .merkleize(&db, None, buffered_floor)
1569 .await
1570 .unwrap();
1571 let db = db.apply_batch(merkleized).await.unwrap();
1572 let buffered_state = (db.root(), db.inactivity_floor_loc(), db.bounds().end);
1573 assert_ne!(buffered_state, durable_state);
1574
1575 let db = db.prune(buffered_floor).await.unwrap();
1576 assert!(db.bounds().start > Location::new(0));
1577 drop(db);
1578
1579 let db = open_db(context.child("second")).await;
1582 assert!(db.bounds().start <= db.inactivity_floor_loc());
1583 let recovered_state = (db.root(), db.inactivity_floor_loc(), db.bounds().end);
1584 assert!(
1585 recovered_state == durable_state || recovered_state == buffered_state,
1586 "recovered state is neither the durable baseline nor the buffered state"
1587 );
1588
1589 db.destroy().await.unwrap();
1590 }
1591
1592 #[boxed]
1596 pub(crate) async fn run_operations_match_applied_log<F: Family, V, C>(
1597 context: deterministic::Context,
1598 open_db: impl Fn(
1599 deterministic::Context,
1600 ) -> Pin<Box<dyn Future<Output = TestDb<F, V, C>> + Send>>,
1601 ) where
1602 V: ValueEncoding<Value = Digest>,
1603 C: Mutable<Item = Operation<F, Digest, V>>,
1604 C::Item: EncodeShared + PartialEq + core::fmt::Debug,
1605 {
1606 let db = open_db(context.child("db")).await;
1607
1608 let seed = db
1609 .new_batch()
1610 .set(Sha256::fill(1u8), Sha256::fill(11u8))
1611 .set(Sha256::fill(2u8), Sha256::fill(12u8))
1612 .merkleize(&db, None, db.inactivity_floor_loc())
1613 .await
1614 .unwrap();
1615 let (seed_start, seed_ops) = seed.operations();
1616 let seed_root = seed.root();
1617 let seed_proof = seed.proof(&db).unwrap();
1618 let seed_pins = seed.pinned_nodes(&db).unwrap();
1619 let applied_start = db.bounds().end;
1620 let db = db.apply_batch(seed).await.unwrap();
1621 let seed_range = applied_start..db.bounds().end;
1622 assert_eq!(seed_start, seed_range.start);
1623 assert_eq!(*seed_start + seed_ops.len() as u64, *seed_range.end);
1624
1625 let parent = db
1627 .new_batch()
1628 .set(Sha256::fill(3u8), Sha256::fill(13u8))
1629 .merkleize(&db, None, db.inactivity_floor_loc())
1630 .await
1631 .unwrap();
1632 let child = parent
1633 .new_batch::<Sha256>()
1634 .set(Sha256::fill(4u8), Sha256::fill(14u8))
1635 .merkleize(&db, None, db.inactivity_floor_loc())
1636 .await
1637 .unwrap();
1638 let (parent_start, parent_ops) = parent.operations();
1639 let (child_start, child_ops) = child.operations();
1640 let (parent_root, child_root) = (parent.root(), child.root());
1641 let (parent_pins, child_pins) = (
1642 parent.pinned_nodes(&db).unwrap(),
1643 child.pinned_nodes(&db).unwrap(),
1644 );
1645 let (parent_proof, child_proof) = (parent.proof(&db).unwrap(), child.proof(&db).unwrap());
1646 let applied_start = db.bounds().end;
1647 let db = db.apply_batch(parent).await.unwrap();
1648 let parent_range = applied_start..db.bounds().end;
1649
1650 assert_eq!(child.proof(&db).unwrap(), child_proof);
1653 assert_eq!(child.pinned_nodes(&db).unwrap(), child_pins);
1654 let applied_start = db.bounds().end;
1655 let db = db.apply_batch(child).await.unwrap();
1656 let child_range = applied_start..db.bounds().end;
1657 assert_eq!(parent_start, parent_range.start);
1658 assert_eq!(*parent_start + parent_ops.len() as u64, *parent_range.end);
1659 assert_eq!(child_start, child_range.start);
1660 assert_eq!(*child_start + child_ops.len() as u64, *child_range.end);
1661
1662 let empty = db
1664 .new_batch()
1665 .merkleize(&db, None, db.inactivity_floor_loc())
1666 .await
1667 .unwrap();
1668 let (empty_start, empty_ops) = empty.operations();
1669 let (empty_root, empty_proof) = (empty.root(), empty.proof(&db).unwrap());
1670 let empty_pins = empty.pinned_nodes(&db).unwrap();
1671 let applied_start = db.bounds().end;
1672 let db = db.apply_batch(empty).await.unwrap();
1673 let empty_range = applied_start..db.bounds().end;
1674 assert_eq!(empty_start, empty_range.start);
1675 assert_eq!(*empty_start + empty_ops.len() as u64, *empty_range.end);
1676
1677 for (start, ops, proof, pins, root) in [
1680 (seed_start, seed_ops, seed_proof, seed_pins, seed_root),
1681 (
1682 parent_start,
1683 parent_ops,
1684 parent_proof,
1685 parent_pins,
1686 parent_root,
1687 ),
1688 (child_start, child_ops, child_proof, child_pins, child_root),
1689 (empty_start, empty_ops, empty_proof, empty_pins, empty_root),
1690 ] {
1691 let len = core::num::NonZeroU64::new(ops.len() as u64).unwrap();
1692 let end = Location::new(*start + ops.len() as u64);
1693 let (log_proof, log_ops) = db.historical_proof(end, start, len).await.unwrap();
1694 assert_eq!(log_ops, *ops);
1695 assert_eq!(log_proof, proof);
1696 assert!(verify_proof::<Sha256, _, _>(&proof, start, &ops, &root));
1697 assert!(verify_proof_and_pinned_nodes::<Sha256, _, _>(
1698 &proof, start, &ops, &pins, &root
1699 ));
1700 }
1701
1702 let late = db
1705 .new_batch()
1706 .set(Sha256::fill(5u8), Sha256::fill(15u8))
1707 .merkleize(&db, None, db.inactivity_floor_loc())
1708 .await
1709 .unwrap();
1710 let db = db.apply_batch(Arc::clone(&late)).await.unwrap();
1711 let db = db.commit().await.unwrap();
1712 assert!(matches!(
1713 late.proof(&db),
1714 Err(crate::qmdb::Error::Merkle(
1715 crate::merkle::Error::ElementPruned(_)
1716 ))
1717 ));
1718 assert!(matches!(
1719 late.pinned_nodes(&db),
1720 Err(crate::qmdb::Error::Merkle(
1721 crate::merkle::Error::ElementPruned(_)
1722 ))
1723 ));
1724
1725 let flushed = db
1727 .new_batch()
1728 .set(Sha256::fill(6u8), Sha256::fill(16u8))
1729 .merkleize(&db, None, db.inactivity_floor_loc())
1730 .await
1731 .unwrap();
1732 let (flushed_start, flushed_ops) = flushed.operations();
1733 let flushed_root = flushed.root();
1734 let flushed_proof = flushed.proof(&db).unwrap();
1735 let flushed_pins = flushed.pinned_nodes(&db).unwrap();
1736 assert!(verify_proof_and_pinned_nodes::<Sha256, _, _>(
1737 &flushed_proof,
1738 flushed_start,
1739 &flushed_ops,
1740 &flushed_pins,
1741 &flushed_root
1742 ));
1743 let applied_start = db.bounds().end;
1744 let db = db.apply_batch(flushed).await.unwrap();
1745 let flushed_range = applied_start..db.bounds().end;
1746 assert_eq!(flushed_start, flushed_range.start);
1747 assert_eq!(
1748 *flushed_start + flushed_ops.len() as u64,
1749 *flushed_range.end
1750 );
1751
1752 db.destroy().await.unwrap();
1753 }
1754
1755 #[boxed]
1756 pub(crate) async fn run_batch_chain<F: Family, V, C>(
1757 context: deterministic::Context,
1758 open_db: impl Fn(
1759 deterministic::Context,
1760 ) -> Pin<Box<dyn Future<Output = TestDb<F, V, C>> + Send>>,
1761 ) where
1762 V: ValueEncoding<Value = Digest>,
1763 C: Mutable<Item = Operation<F, Digest, V>>,
1764 C::Item: EncodeShared,
1765 {
1766 let db = open_db(context.child("first")).await;
1767
1768 let k1 = Sha256::fill(1u8);
1769 let k2 = Sha256::fill(2u8);
1770 let k3 = Sha256::fill(3u8);
1771 let v1 = Sha256::fill(11u8);
1772 let v2 = Sha256::fill(12u8);
1773 let v3 = Sha256::fill(13u8);
1774
1775 let parent = db
1776 .new_batch()
1777 .set(k1, v1)
1778 .merkleize(&db, None, Location::new(0))
1779 .await
1780 .unwrap();
1781 let child = parent
1782 .new_batch::<Sha256>()
1783 .set(k2, v2)
1784 .merkleize(&db, None, Location::new(0))
1785 .await
1786 .unwrap();
1787
1788 assert_eq!(child.get(&k1, &db).await.unwrap(), Some(v1));
1789 assert_eq!(child.get(&k2, &db).await.unwrap(), Some(v2));
1790 assert!(child.get(&k3, &db).await.unwrap().is_none());
1791
1792 let db = db.apply_batch(child).await.unwrap().commit().await.unwrap();
1793
1794 assert_eq!(db.get(&k1).await.unwrap(), Some(v1));
1795 assert_eq!(db.get(&k2).await.unwrap(), Some(v2));
1796
1797 let merkleized = db
1798 .new_batch()
1799 .set(k3, v3)
1800 .merkleize(&db, None, Location::new(0))
1801 .await
1802 .unwrap();
1803 let db = db.apply_batch(merkleized).await.unwrap();
1804 let db = db.commit().await.unwrap();
1805 assert_eq!(db.get(&k3).await.unwrap(), Some(v3));
1806
1807 db.destroy().await.unwrap();
1808 }
1809
1810 #[boxed]
1811 pub(crate) async fn run_build_and_authenticate<F: Family, V, C>(
1812 context: deterministic::Context,
1813 open_db: impl Fn(
1814 deterministic::Context,
1815 ) -> Pin<Box<dyn Future<Output = TestDb<F, V, C>> + Send>>,
1816 ) where
1817 V: ValueEncoding<Value = Digest>,
1818 C: Mutable<Item = Operation<F, Digest, V>>,
1819 C::Item: EncodeShared,
1820 {
1821 let db = open_db(context.child("first")).await;
1823
1824 let mut batch = db.new_batch();
1825 for i in 0u64..2_000 {
1826 let k = Sha256::hash(&[&i.to_be_bytes()]);
1827 let v = Sha256::fill(i as u8);
1828 batch = batch.set(k, v);
1829 }
1830 let merkleized = batch.merkleize(&db, None, Location::new(0)).await.unwrap();
1831 let db = db.apply_batch(merkleized).await.unwrap();
1832 let db = db.commit().await.unwrap();
1833 assert_eq!(db.bounds().end, 2_000 + 2);
1834
1835 let root = db.root();
1837 drop(db);
1838
1839 let db = open_db(context.child("second")).await;
1840 assert_eq!(root, db.root());
1841 assert_eq!(db.bounds().end, 2_000 + 2);
1842 for i in 0u64..2_000 {
1843 let k = Sha256::hash(&[&i.to_be_bytes()]);
1844 let v = Sha256::fill(i as u8);
1845 assert_eq!(db.get(&k).await.unwrap().unwrap(), v);
1846 }
1847
1848 let max_ops = NZU64!(5);
1851 for i in 0..*db.bounds().end {
1852 let (proof, log) = db.proof(Location::new(i), max_ops).await.unwrap();
1853 assert!(verify_proof::<Sha256, _, _>(
1854 &proof,
1855 Location::new(i),
1856 &log,
1857 &root
1858 ));
1859 }
1860
1861 db.destroy().await.unwrap();
1862 }
1863
1864 #[boxed]
1865 pub(crate) async fn run_recovery_from_failed_merkle_sync<F: Family, V, C>(
1866 context: deterministic::Context,
1867 open_db: impl Fn(
1868 deterministic::Context,
1869 ) -> Pin<Box<dyn Future<Output = TestDb<F, V, C>> + Send>>,
1870 ) where
1871 V: ValueEncoding<Value = Digest>,
1872 C: Mutable<Item = Operation<F, Digest, V>>,
1873 C::Item: EncodeShared,
1874 {
1875 const ELEMENTS: u64 = 1000;
1877 let db = open_db(context.child("first")).await;
1878
1879 let mut batch = db.new_batch();
1880 for i in 0u64..ELEMENTS {
1881 let k = Sha256::hash(&[&i.to_be_bytes()]);
1882 let v = Sha256::fill(i as u8);
1883 batch = batch.set(k, v);
1884 }
1885 let merkleized = batch.merkleize(&db, None, Location::new(0)).await.unwrap();
1886 let db = db.apply_batch(merkleized).await.unwrap();
1887 let db = db.commit().await.unwrap();
1888 assert_eq!(db.bounds().end, ELEMENTS + 2);
1889 let db = db.sync().await.unwrap();
1890 let halfway_root = db.root();
1891
1892 let mut batch = db.new_batch();
1894 for i in ELEMENTS..ELEMENTS * 2 {
1895 let k = Sha256::hash(&[&i.to_be_bytes()]);
1896 let v = Sha256::fill(i as u8);
1897 batch = batch.set(k, v);
1898 }
1899 let merkleized = batch.merkleize(&db, None, Location::new(0)).await.unwrap();
1900 let db = db.apply_batch(merkleized).await.unwrap();
1901 db.commit().await.unwrap(); let db = open_db(context.child("second")).await;
1906 assert_eq!(db.bounds().end, 2003);
1907 let root = db.root();
1908 assert_ne!(root, halfway_root);
1909
1910 drop(db);
1912 let db = open_db(context.child("third")).await;
1913 assert_eq!(db.bounds().end, 2003);
1914 assert_eq!(db.root(), root);
1915
1916 db.destroy().await.unwrap();
1917 }
1918
1919 #[boxed]
1920 pub(crate) async fn run_recovery_from_failed_log_sync<F: Family, V, C>(
1921 context: deterministic::Context,
1922 open_db: impl Fn(
1923 deterministic::Context,
1924 ) -> Pin<Box<dyn Future<Output = TestDb<F, V, C>> + Send>>,
1925 ) where
1926 V: ValueEncoding<Value = Digest>,
1927 C: Mutable<Item = Operation<F, Digest, V>>,
1928 C::Item: EncodeShared,
1929 {
1930 let db = open_db(context.child("first")).await;
1931
1932 let k1 = Sha256::fill(1u8);
1934 let v1 = Sha256::fill(3u8);
1935 let merkleized = db
1936 .new_batch()
1937 .set(k1, v1)
1938 .merkleize(&db, None, Location::new(0))
1939 .await
1940 .unwrap();
1941 let db = db.apply_batch(merkleized).await.unwrap();
1942 let db = db.commit().await.unwrap();
1943 let first_commit_root = db.root();
1944
1945 drop(db);
1948
1949 let db = open_db(context.child("second")).await;
1951 assert_eq!(db.bounds().end, 3);
1952 let root = db.root();
1953 assert_eq!(root, first_commit_root);
1954
1955 db.destroy().await.unwrap();
1956 }
1957
1958 #[boxed]
1959 pub(crate) async fn run_pruning<F: Family, V, C>(
1960 context: deterministic::Context,
1961 open_db: impl Fn(
1962 deterministic::Context,
1963 ) -> Pin<Box<dyn Future<Output = TestDb<F, V, C>> + Send>>,
1964 ) where
1965 V: ValueEncoding<Value = Digest>,
1966 C: Mutable<Item = Operation<F, Digest, V>>,
1967 C::Item: EncodeShared,
1968 {
1969 const ELEMENTS: u64 = 2_000;
1971 let db = open_db(context.child("first")).await;
1972
1973 let mut sorted_keys: Vec<sha256::Digest> = (1u64..ELEMENTS + 1)
1976 .map(|i| Sha256::hash(&[&i.to_be_bytes()]))
1977 .collect();
1978 sorted_keys.sort();
1979 let mut batch = db.new_batch();
1984 for i in 1u64..ELEMENTS + 1 {
1985 let k = Sha256::hash(&[&i.to_be_bytes()]);
1986 let v = Sha256::fill(i as u8);
1987 batch = batch.set(k, v);
1988 }
1989 let inactivity_floor = Location::new(ELEMENTS / 2 + ITEMS_PER_SECTION * 2 - 1);
1992 let merkleized = batch.merkleize(&db, None, inactivity_floor).await.unwrap();
1993 let db = db.apply_batch(merkleized).await.unwrap();
1994 assert_eq!(db.bounds().end, ELEMENTS + 2);
1995
1996 let db = db.prune(Location::new((ELEMENTS + 2) / 2)).await.unwrap();
1998 let bounds = db.bounds();
1999 assert_eq!(bounds.end, ELEMENTS + 2);
2000
2001 let oldest_retained_loc = bounds.start;
2004 assert_eq!(oldest_retained_loc, Location::new(ELEMENTS / 2));
2005
2006 let pruned_key = sorted_keys[*oldest_retained_loc as usize - 2];
2008 assert!(db.get(&pruned_key).await.unwrap().is_none());
2009
2010 let unpruned_key = sorted_keys[*oldest_retained_loc as usize - 1];
2012 assert!(db.get(&unpruned_key).await.unwrap().is_some());
2013
2014 let root = db.root();
2016 db.sync().await.unwrap();
2017
2018 let db = open_db(context.child("second")).await;
2019 assert_eq!(root, db.root());
2020 let bounds = db.bounds();
2021 assert_eq!(bounds.end, ELEMENTS + 2);
2022 let oldest_retained_loc = bounds.start;
2023 assert_eq!(oldest_retained_loc, Location::new(ELEMENTS / 2));
2024
2025 let loc = Location::new(ELEMENTS / 2 + (ITEMS_PER_SECTION * 2 - 1));
2027 let db = db.prune(loc).await.unwrap();
2028 let oldest_retained_loc = db.bounds().start;
2030 assert_eq!(
2031 oldest_retained_loc,
2032 Location::new(ELEMENTS / 2 + ITEMS_PER_SECTION)
2033 );
2034
2035 db.sync().await.unwrap();
2037 let db = open_db(context.child("third")).await;
2038 let oldest_retained_loc = db.bounds().start;
2039 assert_eq!(
2040 oldest_retained_loc,
2041 Location::new(ELEMENTS / 2 + ITEMS_PER_SECTION)
2042 );
2043
2044 let floor_val = ELEMENTS / 2 + ITEMS_PER_SECTION * 2 - 1;
2046 let inactive_key = sorted_keys[floor_val as usize - 2];
2047 assert!(db.get(&inactive_key).await.unwrap().is_none());
2048
2049 let active_key = sorted_keys[floor_val as usize - 1];
2051 assert!(db.get(&active_key).await.unwrap().is_some());
2052
2053 let pruned_pos = ELEMENTS / 2;
2055 let proof_result = db
2056 .proof(Location::new(pruned_pos), NZU64!(pruned_pos + 100))
2057 .await;
2058 assert!(
2059 matches!(proof_result, Err(Error::Journal(crate::journal::Error::ItemPruned(pos))) if pos == pruned_pos)
2060 );
2061
2062 db.destroy().await.unwrap();
2063 }
2064
2065 #[boxed]
2066 pub(crate) async fn run_prune_beyond_floor<F: Family, V, C>(
2067 context: deterministic::Context,
2068 open_db: impl Fn(
2069 deterministic::Context,
2070 ) -> Pin<Box<dyn Future<Output = TestDb<F, V, C>> + Send>>,
2071 ) where
2072 V: ValueEncoding<Value = Digest>,
2073 C: Mutable<Item = Operation<F, Digest, V>>,
2074 C::Item: EncodeShared,
2075 {
2076 let db = open_db(context.child("test")).await;
2077
2078 let result = db.prune(Location::new(1)).await;
2080 assert!(
2081 matches!(result, Err(Error::PruneBeyondMinRequired(prune_loc, floor))
2082 if prune_loc == Location::new(1) && floor == Location::new(0))
2083 );
2084
2085 let db = open_db(context.child("test")).await;
2086
2087 let k1 = Digest::from(*b"12345678901234567890123456789012");
2089 let k2 = Digest::from(*b"abcdefghijklmnopqrstuvwxyz123456");
2090 let k3 = Digest::from(*b"99999999999999999999999999999999");
2091 let v1 = Sha256::fill(1u8);
2092 let v2 = Sha256::fill(2u8);
2093 let v3 = Sha256::fill(3u8);
2094
2095 let merkleized = db
2097 .new_batch()
2098 .set(k1, v1)
2099 .set(k2, v2)
2100 .merkleize(&db, None, Location::new(3))
2101 .await
2102 .unwrap();
2103 let db = db.apply_batch(merkleized).await.unwrap();
2104
2105 assert_eq!(*db.size() - 1, 3);
2107
2108 let merkleized = db
2110 .new_batch()
2111 .set(k3, v3)
2112 .merkleize(&db, None, Location::new(5))
2113 .await
2114 .unwrap();
2115 let db = db.apply_batch(merkleized).await.unwrap();
2116
2117 let db = db.prune(Location::new(3)).await.unwrap();
2119
2120 let floor = db.inactivity_floor_loc();
2122 let beyond = floor + 1;
2123 let result = db.prune(beyond).await;
2124 assert!(
2125 matches!(result, Err(Error::PruneBeyondMinRequired(prune_loc, f))
2126 if prune_loc == beyond && f == floor)
2127 );
2128 }
2129
2130 async fn commit_sets<F: Family, V, C>(
2131 db: TestDb<F, V, C>,
2132 sets: impl IntoIterator<Item = (Digest, V::Value)>,
2133 metadata: Option<V::Value>,
2134 ) -> TestDb<F, V, C>
2135 where
2136 V: ValueEncoding<Value = Digest>,
2137 C: Mutable<Item = Operation<F, Digest, V>>,
2138 C::Item: EncodeShared,
2139 {
2140 commit_sets_with_floor(db, sets, metadata, Location::new(0)).await
2141 }
2142
2143 async fn commit_sets_with_floor<F: Family, V, C>(
2144 db: TestDb<F, V, C>,
2145 sets: impl IntoIterator<Item = (Digest, V::Value)>,
2146 metadata: Option<V::Value>,
2147 floor: Location<F>,
2148 ) -> TestDb<F, V, C>
2149 where
2150 V: ValueEncoding<Value = Digest>,
2151 C: Mutable<Item = Operation<F, Digest, V>>,
2152 C::Item: EncodeShared,
2153 {
2154 let mut batch = db.new_batch();
2155 for (key, value) in sets {
2156 batch = batch.set(key, value);
2157 }
2158 let merkleized = batch.merkleize(&db, metadata, floor).await.unwrap();
2159 let expected_end = merkleized.bounds().tip.size;
2160 let db = db.apply_batch(merkleized).await.unwrap();
2161 assert_eq!(db.bounds().end, expected_end);
2162 db.commit().await.unwrap()
2163 }
2164
2165 #[boxed]
2166 pub(crate) async fn run_bounded_initialization_recovery<F: Family, V, C>(
2167 context: deterministic::Context,
2168 open_db: impl Fn(
2169 deterministic::Context,
2170 Option<Location<F>>,
2171 )
2172 -> Pin<Box<dyn Future<Output = Result<TestDb<F, V, C>, Error<F>>> + Send>>,
2173 ) where
2174 V: ValueEncoding<Value = Digest>,
2175 C: Mutable<Item = Operation<F, Digest, V>>,
2176 C::Item: EncodeShared,
2177 {
2178 let db = open_db(context.child("db"), None).await.unwrap();
2179
2180 let key1 = Sha256::hash(&[&1u64.to_be_bytes()]);
2181 let key2 = Sha256::hash(&[&2u64.to_be_bytes()]);
2182 let key3 = Sha256::hash(&[&3u64.to_be_bytes()]);
2183 let key4 = Sha256::hash(&[&4u64.to_be_bytes()]);
2184
2185 let value1 = Sha256::fill(11u8);
2186 let value2 = Sha256::fill(22u8);
2187 let value3 = Sha256::fill(33u8);
2188 let value4 = Sha256::fill(66u8);
2189
2190 let metadata_a = Sha256::fill(44u8);
2191 let db = commit_sets(db, [(key1, value1), (key2, value2)], Some(metadata_a)).await;
2192 let size_before = db.bounds().end;
2193 let root_before = db.root();
2194 let last_commit_before = db.size() - 1;
2195
2196 let metadata_b = Sha256::fill(55u8);
2197 let db = commit_sets(db, [(key3, value3), (key4, value4)], Some(metadata_b)).await;
2198 assert_ne!(db.root(), root_before);
2199 assert_eq!(db.get_metadata().await.unwrap(), Some(metadata_b));
2200 assert_eq!(db.get(&key3).await.unwrap(), Some(value3));
2201 assert_eq!(db.get(&key4).await.unwrap(), Some(value4));
2202
2203 _ = db.sync().await.unwrap();
2204 let db = open_db(context.child("cap"), Some(size_before))
2205 .await
2206 .unwrap();
2207 assert_eq!(db.root(), root_before);
2208 assert_eq!(db.bounds().end, size_before);
2209 assert_eq!(db.size() - 1, last_commit_before);
2210 assert_eq!(db.get_metadata().await.unwrap(), Some(metadata_a));
2211 assert_eq!(db.get(&key1).await.unwrap(), Some(value1));
2212 assert_eq!(db.get(&key2).await.unwrap(), Some(value2));
2213 assert_eq!(db.get(&key3).await.unwrap(), None);
2214 assert_eq!(db.get(&key4).await.unwrap(), None);
2215
2216 db.commit().await.unwrap();
2217 let db = open_db(context.child("reopen"), None).await.unwrap();
2218 assert_eq!(db.root(), root_before);
2219 assert_eq!(db.bounds().end, size_before);
2220 assert_eq!(db.size() - 1, last_commit_before);
2221 assert_eq!(db.get_metadata().await.unwrap(), Some(metadata_a));
2222 assert_eq!(db.get(&key1).await.unwrap(), Some(value1));
2223 assert_eq!(db.get(&key2).await.unwrap(), Some(value2));
2224 assert_eq!(db.get(&key3).await.unwrap(), None);
2225 assert_eq!(db.get(&key4).await.unwrap(), None);
2226
2227 db.destroy().await.unwrap();
2228 }
2229
2230 #[boxed]
2233 pub(crate) async fn run_bounded_initialization_preserves_collision_bucket<F: Family, V, C>(
2234 context: deterministic::Context,
2235 open_db: impl Fn(
2236 deterministic::Context,
2237 Option<Location<F>>,
2238 )
2239 -> Pin<Box<dyn Future<Output = Result<TestDb<F, V, C>, Error<F>>> + Send>>,
2240 ) where
2241 V: ValueEncoding<Value = Digest>,
2242 C: Mutable<Item = Operation<F, Digest, V>>,
2243 C::Item: EncodeShared,
2244 {
2245 let db = open_db(context.child("db"), None).await.unwrap();
2246
2247 let mut k1_bytes = [0u8; 32];
2249 let mut k2_bytes = [0u8; 32];
2250 k1_bytes[0] = 0xAA;
2251 k1_bytes[1] = 0xBB;
2252 k2_bytes[0] = 0xAA;
2253 k2_bytes[1] = 0xBB;
2254 k1_bytes[31] = 0x01;
2255 k2_bytes[31] = 0x02;
2256 let key1 = Digest::from(k1_bytes);
2257 let key2 = Digest::from(k2_bytes);
2258 let value1 = Sha256::fill(11u8);
2259 let value2 = Sha256::fill(22u8);
2260
2261 let db = commit_sets(db, [(key1, value1)], None).await;
2262 let size_after_first = db.bounds().end;
2263 let db = commit_sets(db, [(key2, value2)], None).await;
2264 assert_eq!(db.get(&key1).await.unwrap(), Some(value1));
2265 assert_eq!(db.get(&key2).await.unwrap(), Some(value2));
2266
2267 _ = db.sync().await.unwrap();
2268 let db = open_db(context.child("cap"), Some(size_after_first))
2269 .await
2270 .unwrap();
2271
2272 assert_eq!(db.get(&key1).await.unwrap(), Some(value1));
2275 assert_eq!(db.get(&key2).await.unwrap(), None);
2276
2277 db.destroy().await.unwrap();
2278 }
2279
2280 #[boxed]
2281 pub(crate) async fn run_bounded_initialization_pruned_target_errors<F: Family, V, C>(
2282 context: deterministic::Context,
2283 open_small_sections_db: impl Fn(
2284 deterministic::Context,
2285 Option<Location<F>>,
2286 ) -> Pin<
2287 Box<dyn Future<Output = Result<TestDb<F, V, C>, Error<F>>> + Send>,
2288 >,
2289 ) where
2290 V: ValueEncoding<Value = Digest>,
2291 C: Mutable<Item = Operation<F, Digest, V>>,
2292 C::Item: EncodeShared,
2293 {
2294 let db = open_small_sections_db(context.child("db"), None)
2295 .await
2296 .unwrap();
2297
2298 let first_start = db.bounds().end;
2299 let mut db = commit_sets(
2300 db,
2301 (0u64..16).map(|i| (Sha256::hash(&[&i.to_be_bytes()]), Sha256::fill(i as u8))),
2302 None,
2303 )
2304 .await;
2305
2306 let mut round = 0u64;
2307 loop {
2308 round += 1;
2309 assert!(
2310 round <= 64,
2311 "failed to prune enough history for the bounded initialization test"
2312 );
2313
2314 let floor = db.bounds().end + 16;
2317 db = commit_sets_with_floor(
2318 db,
2319 (0u64..16).map(|i| {
2320 let seed = round * 100 + i;
2321 (
2322 Sha256::hash(&[&seed.to_be_bytes()]),
2323 Sha256::fill(seed as u8),
2324 )
2325 }),
2326 None,
2327 floor,
2328 )
2329 .await;
2330 let last_commit = db.size() - 1;
2331 db = db.prune(last_commit).await.unwrap();
2332
2333 if db.bounds().start > first_start {
2334 break;
2335 }
2336 }
2337
2338 let oldest_retained = db.bounds().start;
2339 _ = db.sync().await.unwrap();
2340 let Err(boundary_err) =
2341 open_small_sections_db(context.child("cap_error"), Some(oldest_retained)).await
2342 else {
2343 panic!("expected bounded initialization to fail");
2344 };
2345 assert!(
2346 matches!(
2347 boundary_err,
2348 Error::Journal(crate::journal::Error::ItemPruned(_))
2349 ),
2350 "unexpected bounded initialization error at retained boundary: {boundary_err:?}"
2351 );
2352
2353 let db = open_small_sections_db(context.child("db"), None)
2354 .await
2355 .unwrap();
2356 _ = db.sync().await.unwrap();
2357 let Err(err) = open_small_sections_db(context.child("cap_error"), Some(first_start)).await
2358 else {
2359 panic!("expected bounded initialization to fail");
2360 };
2361 assert!(
2362 matches!(err, Error::Journal(crate::journal::Error::ItemPruned(_))),
2363 "unexpected bounded initialization error: {err:?}"
2364 );
2365 }
2366
2367 #[boxed]
2369 pub(crate) async fn run_batch_get_read_through<F: Family, V, C>(
2370 context: deterministic::Context,
2371 open_db: impl Fn(
2372 deterministic::Context,
2373 ) -> Pin<Box<dyn Future<Output = TestDb<F, V, C>> + Send>>,
2374 ) where
2375 V: ValueEncoding<Value = Digest>,
2376 C: Mutable<Item = Operation<F, Digest, V>>,
2377 C::Item: EncodeShared,
2378 {
2379 let db = open_db(context.child("db")).await;
2380
2381 let key_a = Sha256::hash(&[&0u64.to_be_bytes()]);
2383 let val_a = Sha256::fill(1u8);
2384 let merkleized = db
2385 .new_batch()
2386 .set(key_a, val_a)
2387 .merkleize(&db, None, Location::new(0))
2388 .await
2389 .unwrap();
2390 let db = db.apply_batch(merkleized).await.unwrap();
2391
2392 let mut batch = db.new_batch();
2394 assert_eq!(batch.get(&key_a, &db).await.unwrap(), Some(val_a));
2395
2396 let key_b = Sha256::hash(&[&1u64.to_be_bytes()]);
2398 let val_b = Sha256::fill(2u8);
2399 batch = batch.set(key_b, val_b);
2400 assert_eq!(batch.get(&key_b, &db).await.unwrap(), Some(val_b));
2401
2402 let key_c = Sha256::hash(&[&2u64.to_be_bytes()]);
2404 assert_eq!(batch.get(&key_c, &db).await.unwrap(), None);
2405
2406 db.destroy().await.unwrap();
2407 }
2408
2409 #[boxed]
2411 pub(crate) async fn run_batch_stacked_get<F: Family, V, C>(
2412 context: deterministic::Context,
2413 open_db: impl Fn(
2414 deterministic::Context,
2415 ) -> Pin<Box<dyn Future<Output = TestDb<F, V, C>> + Send>>,
2416 ) where
2417 V: ValueEncoding<Value = Digest>,
2418 C: Mutable<Item = Operation<F, Digest, V>>,
2419 C::Item: EncodeShared,
2420 {
2421 let db = open_db(context.child("db")).await;
2422
2423 let key_a = Sha256::hash(&[&0u64.to_be_bytes()]);
2425 let val_a = Sha256::fill(10u8);
2426 let parent = db.new_batch().set(key_a, val_a);
2427 let parent_m = parent.merkleize(&db, None, Location::new(0)).await.unwrap();
2428
2429 let mut child = parent_m.new_batch::<Sha256>();
2431 assert_eq!(child.get(&key_a, &db).await.unwrap(), Some(val_a));
2432
2433 let key_b = Sha256::hash(&[&1u64.to_be_bytes()]);
2435 let val_b = Sha256::fill(20u8);
2436 child = child.set(key_b, val_b);
2437 assert_eq!(child.get(&key_b, &db).await.unwrap(), Some(val_b));
2438
2439 let key_c = Sha256::hash(&[&2u64.to_be_bytes()]);
2441 assert_eq!(child.get(&key_c, &db).await.unwrap(), None);
2442
2443 db.destroy().await.unwrap();
2444 }
2445
2446 #[boxed]
2448 pub(crate) async fn run_batch_stacked_apply<F: Family, V, C>(
2449 context: deterministic::Context,
2450 open_db: impl Fn(
2451 deterministic::Context,
2452 ) -> Pin<Box<dyn Future<Output = TestDb<F, V, C>> + Send>>,
2453 ) where
2454 V: ValueEncoding<Value = Digest>,
2455 C: Mutable<Item = Operation<F, Digest, V>>,
2456 C::Item: EncodeShared,
2457 {
2458 let db = open_db(context.child("db")).await;
2459
2460 let mut kvs_first: Vec<(Digest, Digest)> = (0u64..5)
2462 .map(|i| (Sha256::hash(&[&i.to_be_bytes()]), Sha256::fill(i as u8)))
2463 .collect();
2464 kvs_first.sort_by_key(|a| a.0);
2465
2466 let mut kvs_second: Vec<(Digest, Digest)> = (5u64..10)
2467 .map(|i| (Sha256::hash(&[&i.to_be_bytes()]), Sha256::fill(i as u8)))
2468 .collect();
2469 kvs_second.sort_by_key(|a| a.0);
2470
2471 let mut parent = db.new_batch();
2473 for (k, v) in &kvs_first {
2474 parent = parent.set(*k, *v);
2475 }
2476 let parent_m = parent.merkleize(&db, None, Location::new(0)).await.unwrap();
2477
2478 let mut child = parent_m.new_batch::<Sha256>();
2480 for (k, v) in &kvs_second {
2481 child = child.set(*k, *v);
2482 }
2483 let child_m = child.merkleize(&db, None, Location::new(0)).await.unwrap();
2484 let expected_root = child_m.root();
2485 let db = db.apply_batch(child_m).await.unwrap();
2486
2487 assert_eq!(db.root(), expected_root);
2488
2489 for (k, v) in kvs_first.iter().chain(kvs_second.iter()) {
2491 assert_eq!(db.get(k).await.unwrap(), Some(*v));
2492 }
2493
2494 db.destroy().await.unwrap();
2495 }
2496
2497 #[boxed]
2499 pub(crate) async fn run_batch_speculative_root<F: Family, V, C>(
2500 context: deterministic::Context,
2501 open_db: impl Fn(
2502 deterministic::Context,
2503 ) -> Pin<Box<dyn Future<Output = TestDb<F, V, C>> + Send>>,
2504 ) where
2505 V: ValueEncoding<Value = Digest>,
2506 C: Mutable<Item = Operation<F, Digest, V>>,
2507 C::Item: EncodeShared,
2508 {
2509 let db = open_db(context.child("db")).await;
2510
2511 let mut batch = db.new_batch();
2512 for i in 0u8..10 {
2513 let k = Sha256::hash(&[&[i]]);
2514 batch = batch.set(k, Sha256::fill(i));
2515 }
2516 let merkleized = batch.merkleize(&db, None, Location::new(0)).await.unwrap();
2517
2518 let speculative = merkleized.root();
2519 let db = db.apply_batch(merkleized).await.unwrap();
2520 assert_eq!(db.root(), speculative);
2521
2522 let metadata = Some(Sha256::fill(55u8));
2524 let mut batch = db.new_batch();
2525 let k = Sha256::hash(&[&[0xAA]]);
2526 batch = batch.set(k, Sha256::fill(0xAA));
2527 let merkleized = batch
2528 .merkleize(&db, metadata, Location::new(0))
2529 .await
2530 .unwrap();
2531 let speculative = merkleized.root();
2532 let db = db.apply_batch(merkleized).await.unwrap();
2533 assert_eq!(db.root(), speculative);
2534
2535 db.destroy().await.unwrap();
2536 }
2537
2538 #[boxed]
2540 pub(crate) async fn run_merkleized_batch_get<F: Family, V, C>(
2541 context: deterministic::Context,
2542 open_db: impl Fn(
2543 deterministic::Context,
2544 ) -> Pin<Box<dyn Future<Output = TestDb<F, V, C>> + Send>>,
2545 ) where
2546 V: ValueEncoding<Value = Digest>,
2547 C: Mutable<Item = Operation<F, Digest, V>>,
2548 C::Item: EncodeShared,
2549 {
2550 let db = open_db(context.child("db")).await;
2551
2552 let key_a = Sha256::hash(&[&0u64.to_be_bytes()]);
2554 let val_a = Sha256::fill(10u8);
2555 let merkleized = db
2556 .new_batch()
2557 .set(key_a, val_a)
2558 .merkleize(&db, None, Location::new(0))
2559 .await
2560 .unwrap();
2561 let db = db.apply_batch(merkleized).await.unwrap();
2562
2563 let key_b = Sha256::hash(&[&1u64.to_be_bytes()]);
2565 let val_b = Sha256::fill(20u8);
2566 let merkleized = db
2567 .new_batch()
2568 .set(key_b, val_b)
2569 .merkleize(&db, None, Location::new(0))
2570 .await
2571 .unwrap();
2572
2573 assert_eq!(merkleized.get(&key_a, &db).await.unwrap(), Some(val_a));
2575
2576 assert_eq!(merkleized.get(&key_b, &db).await.unwrap(), Some(val_b));
2578
2579 let key_c = Sha256::hash(&[&2u64.to_be_bytes()]);
2581 assert_eq!(merkleized.get(&key_c, &db).await.unwrap(), None);
2582
2583 db.destroy().await.unwrap();
2584 }
2585
2586 #[boxed]
2588 pub(crate) async fn run_batch_sequential_apply<F: Family, V, C>(
2589 context: deterministic::Context,
2590 open_db: impl Fn(
2591 deterministic::Context,
2592 ) -> Pin<Box<dyn Future<Output = TestDb<F, V, C>> + Send>>,
2593 ) where
2594 V: ValueEncoding<Value = Digest>,
2595 C: Mutable<Item = Operation<F, Digest, V>>,
2596 C::Item: EncodeShared,
2597 {
2598 let db = open_db(context.child("db")).await;
2599
2600 let key_a = Sha256::hash(&[&0u64.to_be_bytes()]);
2601 let val_a = Sha256::fill(1u8);
2602
2603 let m = db
2605 .new_batch()
2606 .set(key_a, val_a)
2607 .merkleize(&db, None, Location::new(0))
2608 .await
2609 .unwrap();
2610 let root1 = m.root();
2611 let db = db.apply_batch(m).await.unwrap();
2612 assert_eq!(db.root(), root1);
2613 assert_eq!(db.get(&key_a).await.unwrap(), Some(val_a));
2614
2615 let key_b = Sha256::hash(&[&1u64.to_be_bytes()]);
2617 let val_b = Sha256::fill(2u8);
2618 let m = db
2619 .new_batch()
2620 .set(key_b, val_b)
2621 .merkleize(&db, None, Location::new(0))
2622 .await
2623 .unwrap();
2624 let root2 = m.root();
2625 let db = db.apply_batch(m).await.unwrap();
2626 assert_eq!(db.root(), root2);
2627 assert_eq!(db.get(&key_b).await.unwrap(), Some(val_b));
2628
2629 db.destroy().await.unwrap();
2630 }
2631
2632 #[boxed]
2634 pub(crate) async fn run_batch_many_sequential<F: Family, V, C>(
2635 context: deterministic::Context,
2636 open_db: impl Fn(
2637 deterministic::Context,
2638 ) -> Pin<Box<dyn Future<Output = TestDb<F, V, C>> + Send>>,
2639 ) where
2640 V: ValueEncoding<Value = Digest>,
2641 C: Mutable<Item = Operation<F, Digest, V>>,
2642 C::Item: EncodeShared,
2643 {
2644 let mut db = open_db(context.child("db")).await;
2645
2646 const BATCHES: u64 = 20;
2647 const KEYS_PER_BATCH: u64 = 5;
2648
2649 let mut all_kvs: Vec<(Digest, Digest)> = Vec::new();
2650
2651 for batch_idx in 0..BATCHES {
2652 let mut batch = db.new_batch();
2653 for j in 0..KEYS_PER_BATCH {
2654 let seed = batch_idx * 100 + j;
2655 let k = Sha256::hash(&[&seed.to_be_bytes()]);
2656 let v = Sha256::fill(seed as u8);
2657 batch = batch.set(k, v);
2658 all_kvs.push((k, v));
2659 }
2660 let merkleized = batch.merkleize(&db, None, Location::new(0)).await.unwrap();
2661 db = db.apply_batch(merkleized).await.unwrap();
2662 }
2663
2664 for (k, v) in &all_kvs {
2666 assert_eq!(db.get(k).await.unwrap(), Some(*v));
2667 }
2668
2669 let root = db.root();
2671 let (proof, ops) = db.proof(Location::new(0), NZU64!(10000)).await.unwrap();
2672 assert!(verify_proof::<Sha256, _, _>(
2673 &proof,
2674 Location::new(0),
2675 &ops,
2676 &root
2677 ));
2678
2679 let expected = 1 + BATCHES * (KEYS_PER_BATCH + 1);
2681 assert_eq!(db.bounds().end, expected);
2682
2683 db.destroy().await.unwrap();
2684 }
2685
2686 #[boxed]
2688 pub(crate) async fn run_batch_empty_batch<F: Family, V, C>(
2689 context: deterministic::Context,
2690 open_db: impl Fn(
2691 deterministic::Context,
2692 ) -> Pin<Box<dyn Future<Output = TestDb<F, V, C>> + Send>>,
2693 ) where
2694 V: ValueEncoding<Value = Digest>,
2695 C: Mutable<Item = Operation<F, Digest, V>>,
2696 C::Item: EncodeShared,
2697 {
2698 let db = open_db(context.child("db")).await;
2699
2700 let k = Sha256::hash(&[&[1u8]]);
2702 let merkleized = db
2703 .new_batch()
2704 .set(k, Sha256::fill(1u8))
2705 .merkleize(&db, None, Location::new(0))
2706 .await
2707 .unwrap();
2708 let db = db.apply_batch(merkleized).await.unwrap();
2709 let root_before = db.root();
2710 let size_before = db.bounds().end;
2711
2712 let merkleized = db
2714 .new_batch()
2715 .merkleize(&db, None, Location::new(0))
2716 .await
2717 .unwrap();
2718 let speculative = merkleized.root();
2719 let db = db.apply_batch(merkleized).await.unwrap();
2720
2721 assert_ne!(db.root(), root_before);
2723 assert_eq!(db.root(), speculative);
2724 assert_eq!(db.bounds().end, size_before + 1);
2726
2727 db.destroy().await.unwrap();
2728 }
2729
2730 #[boxed]
2732 pub(crate) async fn run_batch_chained_merkleized_get<F: Family, V, C>(
2733 context: deterministic::Context,
2734 open_db: impl Fn(
2735 deterministic::Context,
2736 ) -> Pin<Box<dyn Future<Output = TestDb<F, V, C>> + Send>>,
2737 ) where
2738 V: ValueEncoding<Value = Digest>,
2739 C: Mutable<Item = Operation<F, Digest, V>>,
2740 C::Item: EncodeShared,
2741 {
2742 let db = open_db(context.child("db")).await;
2743
2744 let key_a = Sha256::hash(&[&0u64.to_be_bytes()]);
2746 let val_a = Sha256::fill(10u8);
2747 let merkleized = db
2748 .new_batch()
2749 .set(key_a, val_a)
2750 .merkleize(&db, None, Location::new(0))
2751 .await
2752 .unwrap();
2753 let db = db.apply_batch(merkleized).await.unwrap();
2754
2755 let key_b = Sha256::hash(&[&1u64.to_be_bytes()]);
2757 let val_b = Sha256::fill(1u8);
2758 let parent_m = db
2759 .new_batch()
2760 .set(key_b, val_b)
2761 .merkleize(&db, None, Location::new(0))
2762 .await
2763 .unwrap();
2764
2765 let key_c = Sha256::hash(&[&2u64.to_be_bytes()]);
2767 let val_c = Sha256::fill(2u8);
2768 let child_m = parent_m
2769 .new_batch::<Sha256>()
2770 .set(key_c, val_c)
2771 .merkleize(&db, None, Location::new(0))
2772 .await
2773 .unwrap();
2774
2775 assert_eq!(child_m.get(&key_a, &db).await.unwrap(), Some(val_a));
2778 assert_eq!(child_m.get(&key_b, &db).await.unwrap(), Some(val_b));
2780 assert_eq!(child_m.get(&key_c, &db).await.unwrap(), Some(val_c));
2782 let key_d = Sha256::hash(&[&3u64.to_be_bytes()]);
2784 assert_eq!(child_m.get(&key_d, &db).await.unwrap(), None);
2785
2786 db.destroy().await.unwrap();
2787 }
2788
2789 #[boxed]
2791 pub(crate) async fn run_batch_large<F: Family, V, C>(
2792 context: deterministic::Context,
2793 open_db: impl Fn(
2794 deterministic::Context,
2795 ) -> Pin<Box<dyn Future<Output = TestDb<F, V, C>> + Send>>,
2796 ) where
2797 V: ValueEncoding<Value = Digest>,
2798 C: Mutable<Item = Operation<F, Digest, V>>,
2799 C::Item: EncodeShared,
2800 {
2801 let db = open_db(context.child("db")).await;
2802
2803 const N: u64 = 500;
2804 let mut kvs: Vec<(Digest, Digest)> = Vec::new();
2805
2806 let mut batch = db.new_batch();
2807 for i in 0..N {
2808 let k = Sha256::hash(&[&i.to_be_bytes()]);
2809 let v = Sha256::fill((i % 256) as u8);
2810 batch = batch.set(k, v);
2811 kvs.push((k, v));
2812 }
2813 let merkleized = batch.merkleize(&db, None, Location::new(0)).await.unwrap();
2814 let db = db.apply_batch(merkleized).await.unwrap();
2815
2816 for (k, v) in &kvs {
2818 assert_eq!(db.get(k).await.unwrap(), Some(*v));
2819 }
2820
2821 let root = db.root();
2823 let (proof, ops) = db.proof(Location::new(0), NZU64!(1000)).await.unwrap();
2824 assert!(verify_proof::<Sha256, _, _>(
2825 &proof,
2826 Location::new(0),
2827 &ops,
2828 &root
2829 ));
2830
2831 assert_eq!(db.bounds().end, 1 + N + 1);
2833
2834 db.destroy().await.unwrap();
2835 }
2836
2837 #[boxed]
2843 pub(crate) async fn run_prune_collision_bucket<F: Family, V, C>(
2844 context: deterministic::Context,
2845 open_db_small_sections: impl Fn(
2846 deterministic::Context,
2847 )
2848 -> Pin<Box<dyn Future<Output = TestDb<F, V, C>> + Send>>,
2849 ) where
2850 V: ValueEncoding<Value = Digest>,
2851 C: Mutable<Item = Operation<F, Digest, V>>,
2852 C::Item: EncodeShared,
2853 {
2854 let db = open_db_small_sections(context.child("db")).await;
2855
2856 let mut k1_bytes = [0u8; 32];
2858 let mut k2_bytes = [0u8; 32];
2859 k1_bytes[0] = 0xAA;
2860 k1_bytes[1] = 0xBB;
2861 k2_bytes[0] = 0xAA;
2862 k2_bytes[1] = 0xBB;
2863 k1_bytes[31] = 0x01;
2864 k2_bytes[31] = 0x02;
2865 let key1 = Digest::from(k1_bytes);
2866 let key2 = Digest::from(k2_bytes);
2867 let key3 = Sha256::fill(3u8);
2868 let v1 = Sha256::fill(1u8);
2869 let v2 = Sha256::fill(2u8);
2870 let v3 = Sha256::fill(3u8);
2871
2872 let merkleized = db
2875 .new_batch()
2876 .set(key1, v1)
2877 .merkleize(&db, None, Location::new(0))
2878 .await
2879 .unwrap();
2880 let db = db.apply_batch(merkleized).await.unwrap();
2881 let merkleized = db
2882 .new_batch()
2883 .set(key2, v2)
2884 .set(key3, v3)
2885 .merkleize(&db, None, Location::new(4))
2886 .await
2887 .unwrap();
2888 let db = db.apply_batch(merkleized).await.unwrap();
2889 assert_eq!(db.get(&key1).await.unwrap(), Some(v1));
2890 assert_eq!(db.get(&key2).await.unwrap(), Some(v2));
2891 assert_eq!(db.snapshot.len(), 3);
2892
2893 let db = db.prune(Location::new(2)).await.unwrap();
2896 assert_eq!(db.bounds().start, Location::new(2));
2897 assert_eq!(db.snapshot.len(), 2);
2898 assert_eq!(db.get(&key1).await.unwrap(), None);
2899 assert_eq!(db.get(&key2).await.unwrap(), Some(v2));
2900 assert_eq!(db.get(&key3).await.unwrap(), Some(v3));
2901
2902 db.destroy().await.unwrap();
2903 }
2904
2905 #[boxed]
2911 pub(crate) async fn run_prune_retires_pruned_sets<F: Family, V, C>(
2912 context: deterministic::Context,
2913 open_db_small_sections: impl Fn(
2914 deterministic::Context,
2915 )
2916 -> Pin<Box<dyn Future<Output = TestDb<F, V, C>> + Send>>,
2917 ) where
2918 V: ValueEncoding<Value = Digest>,
2919 C: Mutable<Item = Operation<F, Digest, V>>,
2920 C::Item: EncodeShared,
2921 {
2922 let mut db = open_db_small_sections(context.child("db")).await;
2923
2924 for i in 0..10u8 {
2926 let floor = db.bounds().end;
2927 let merkleized = db
2928 .new_batch()
2929 .set(Sha256::fill(i), Sha256::fill(i))
2930 .merkleize(&db, None, floor)
2931 .await
2932 .unwrap();
2933 db = db.apply_batch(merkleized).await.unwrap();
2934 }
2935 assert_eq!(db.bounds(), Location::new(0)..Location::new(21));
2936 assert_eq!(db.snapshot.len(), 10);
2937
2938 for loc in [2u64, 4, 6] {
2940 db = db.prune(Location::new(loc)).await.unwrap();
2941 assert_eq!(db.bounds().start, Location::new(loc));
2942 assert_eq!(db.snapshot.len(), 10 - loc as usize / 2);
2943 }
2944 assert!(db.get(&Sha256::fill(0)).await.unwrap().is_none());
2945
2946 db = db.prune(Location::new(9)).await.unwrap();
2948 assert_eq!(db.snapshot.len(), 6);
2949 assert_eq!(
2950 db.get(&Sha256::fill(4)).await.unwrap(),
2951 Some(Sha256::fill(4))
2952 );
2953
2954 db = db.prune(Location::new(10)).await.unwrap();
2956 assert_eq!(db.snapshot.len(), 5);
2957 assert!(db.get(&Sha256::fill(4)).await.unwrap().is_none());
2958 assert_eq!(
2959 db.get(&Sha256::fill(5)).await.unwrap(),
2960 Some(Sha256::fill(5))
2961 );
2962
2963 db.destroy().await.unwrap();
2964 }
2965
2966 #[boxed]
2968 pub(crate) async fn run_batch_metadata<F: Family, V, C>(
2969 context: deterministic::Context,
2970 open_db: impl Fn(
2971 deterministic::Context,
2972 ) -> Pin<Box<dyn Future<Output = TestDb<F, V, C>> + Send>>,
2973 ) where
2974 V: ValueEncoding<Value = Digest>,
2975 C: Mutable<Item = Operation<F, Digest, V>>,
2976 C::Item: EncodeShared,
2977 {
2978 let db = open_db(context.child("db")).await;
2979
2980 let metadata = Sha256::fill(42u8);
2982 let k = Sha256::hash(&[&[1u8]]);
2983 let merkleized = db
2984 .new_batch()
2985 .set(k, Sha256::fill(1u8))
2986 .merkleize(&db, Some(metadata), Location::new(0))
2987 .await
2988 .unwrap();
2989 let db = db.apply_batch(merkleized).await.unwrap();
2990 assert_eq!(db.get_metadata().await.unwrap(), Some(metadata));
2991
2992 let merkleized = db
2994 .new_batch()
2995 .merkleize(&db, None, Location::new(0))
2996 .await
2997 .unwrap();
2998 let db = db.apply_batch(merkleized).await.unwrap();
2999 assert_eq!(db.get_metadata().await.unwrap(), None);
3000
3001 db.destroy().await.unwrap();
3002 }
3003
3004 #[boxed]
3005 pub(crate) async fn run_merkleize_foreign_db<F: Family, V, C>(
3006 db: TestDb<F, V, C>,
3007 foreign: TestDb<F, V, C>,
3008 ) where
3009 V: ValueEncoding<Value = Digest>,
3010 C: Mutable<Item = Operation<F, Digest, V>>,
3011 C::Item: EncodeShared,
3012 {
3013 let key = Sha256::fill(1);
3014 let batch = db
3015 .new_batch()
3016 .set(key, Sha256::fill(11))
3017 .merkleize(&db, None, Location::new(0))
3018 .await
3019 .unwrap();
3020 let db = db.apply_batch(batch).await.unwrap();
3021 let batch = foreign
3022 .new_batch()
3023 .set(key, Sha256::fill(99))
3024 .merkleize(&foreign, None, Location::new(0))
3025 .await
3026 .unwrap();
3027 let foreign = foreign.apply_batch(batch).await.unwrap();
3028 assert_eq!(db.size(), foreign.size());
3029 assert_ne!(db.root(), foreign.root());
3030
3031 let direct = db.new_batch().set(Sha256::fill(2), Sha256::fill(22));
3032 let direct = direct.merkleize(&foreign, None, Location::new(0)).await;
3033 let parent = db
3034 .new_batch()
3035 .set(Sha256::fill(3), Sha256::fill(33))
3036 .merkleize(&db, None, Location::new(0))
3037 .await
3038 .unwrap();
3039 let child = parent
3040 .new_batch::<Sha256>()
3041 .set(Sha256::fill(4), Sha256::fill(44));
3042 let child = child.merkleize(&foreign, None, Location::new(0)).await;
3043 assert!(matches!(direct, Err(Error::StaleBatch)));
3044 assert!(matches!(child, Err(Error::StaleBatch)));
3045 db.destroy().await.unwrap();
3046 foreign.destroy().await.unwrap();
3047 }
3048
3049 #[boxed]
3050 pub(crate) async fn run_merkleize_stale_sibling<F: Family, V, C>(
3051 context: deterministic::Context,
3052 open_db: impl Fn(
3053 deterministic::Context,
3054 ) -> Pin<Box<dyn Future<Output = TestDb<F, V, C>> + Send>>,
3055 ) where
3056 V: ValueEncoding<Value = Digest>,
3057 C: Mutable<Item = Operation<F, Digest, V>>,
3058 C::Item: EncodeShared,
3059 {
3060 let db = open_db(context.child("db")).await;
3061
3062 let direct = db.new_batch().set(Sha256::fill(1), Sha256::fill(11));
3063 let sibling = db
3064 .new_batch()
3065 .set(Sha256::fill(2), Sha256::fill(22))
3066 .merkleize(&db, None, Location::new(0))
3067 .await
3068 .unwrap();
3069 let db = db.apply_batch(sibling).await.unwrap();
3070 let direct = direct.merkleize(&db, None, Location::new(0)).await;
3071 assert!(matches!(direct, Err(Error::StaleBatch)));
3072
3073 let parent = db
3074 .new_batch()
3075 .set(Sha256::fill(3), Sha256::fill(33))
3076 .merkleize(&db, None, Location::new(0))
3077 .await
3078 .unwrap();
3079 let child = parent
3080 .new_batch::<Sha256>()
3081 .set(Sha256::fill(4), Sha256::fill(44));
3082 let sibling = db
3083 .new_batch()
3084 .set(Sha256::fill(5), Sha256::fill(55))
3085 .merkleize(&db, None, Location::new(0))
3086 .await
3087 .unwrap();
3088 let db = db.apply_batch(sibling).await.unwrap();
3089 let child = child.merkleize(&db, None, Location::new(0)).await;
3090 assert!(matches!(child, Err(Error::StaleBatch)));
3091
3092 db.destroy().await.unwrap();
3093 }
3094
3095 #[boxed]
3096 pub(crate) async fn run_stale_batch_rejected<F: Family, V, C>(
3097 context: deterministic::Context,
3098 open_db: impl Fn(
3099 deterministic::Context,
3100 ) -> Pin<Box<dyn Future<Output = TestDb<F, V, C>> + Send>>,
3101 ) where
3102 V: ValueEncoding<Value = Digest>,
3103 C: Mutable<Item = Operation<F, Digest, V>>,
3104 C::Item: EncodeShared,
3105 {
3106 let db = open_db(context.child("db")).await;
3107
3108 let key1 = Sha256::hash(&[&[1]]);
3109 let key2 = Sha256::hash(&[&[2]]);
3110 let v1 = Sha256::fill(10u8);
3111 let v2 = Sha256::fill(20u8);
3112
3113 let batch_a = db
3115 .new_batch()
3116 .set(key1, v1)
3117 .merkleize(&db, None, Location::new(0))
3118 .await
3119 .unwrap();
3120 let batch_b = db
3121 .new_batch()
3122 .set(key2, v2)
3123 .merkleize(&db, None, Location::new(0))
3124 .await
3125 .unwrap();
3126
3127 let db = db.apply_batch(batch_a).await.unwrap();
3129 assert_eq!(db.get(&key1).await.unwrap(), Some(v1));
3130 assert_eq!(db.get(&key2).await.unwrap(), None);
3131 assert_eq!(db.get_metadata().await.unwrap(), None);
3132 let db = db.commit().await.unwrap();
3133 let root = db.root();
3134 let size = db.size();
3135
3136 let result = db.apply_batch(batch_b).await;
3138 assert!(matches!(result, Err(Error::StaleBatch)));
3139
3140 let db = open_db(context.child("reopen")).await;
3142 assert_eq!(db.root(), root);
3143 assert_eq!(db.size(), size);
3144 assert_eq!(db.get(&key1).await.unwrap(), Some(v1));
3145 assert_eq!(db.get(&key2).await.unwrap(), None);
3146 db.destroy().await.unwrap();
3147 }
3148
3149 #[boxed]
3150 pub(crate) async fn run_stale_batch_chained<F: Family, V, C>(
3151 context: deterministic::Context,
3152 open_db: impl Fn(
3153 deterministic::Context,
3154 ) -> Pin<Box<dyn Future<Output = TestDb<F, V, C>> + Send>>,
3155 ) where
3156 V: ValueEncoding<Value = Digest>,
3157 C: Mutable<Item = Operation<F, Digest, V>>,
3158 C::Item: EncodeShared,
3159 {
3160 let db = open_db(context.child("db")).await;
3161
3162 let key1 = Sha256::hash(&[&[1]]);
3163 let key2 = Sha256::hash(&[&[2]]);
3164 let key3 = Sha256::hash(&[&[3]]);
3165
3166 let common_parent = db
3167 .new_batch()
3168 .set(Sha256::hash(&[&[10]]), Sha256::fill(10u8))
3169 .merkleize(&db, None, Location::new(0))
3170 .await
3171 .unwrap();
3172 let sibling_a = common_parent
3173 .new_batch::<Sha256>()
3174 .set(Sha256::hash(&[&[11]]), Sha256::fill(11u8))
3175 .merkleize(&db, None, Location::new(0))
3176 .await
3177 .unwrap();
3178 let sibling_b = common_parent
3179 .new_batch::<Sha256>()
3180 .set(Sha256::hash(&[&[12]]), Sha256::fill(12u8))
3181 .merkleize(&db, None, Location::new(0))
3182 .await
3183 .unwrap();
3184 let db = db.apply_batch(sibling_a).await.unwrap();
3185 assert!(matches!(
3186 db.validate_batch(&sibling_b),
3187 Err(Error::StaleBatch)
3188 ));
3189
3190 let parent_a = db
3192 .new_batch()
3193 .set(key1, Sha256::fill(1u8))
3194 .merkleize(&db, None, Location::new(0))
3195 .await
3196 .unwrap();
3197 let parent_b = db
3198 .new_batch()
3199 .set(key2, Sha256::fill(2u8))
3200 .merkleize(&db, None, Location::new(0))
3201 .await
3202 .unwrap();
3203 let child_b = parent_b
3204 .new_batch::<Sha256>()
3205 .set(key3, Sha256::fill(3u8))
3206 .merkleize(&db, None, Location::new(0))
3207 .await
3208 .unwrap();
3209
3210 let db = db.apply_batch(parent_a).await.unwrap();
3211 assert!(matches!(
3212 db.validate_batch(&child_b),
3213 Err(Error::StaleBatch)
3214 ));
3215 db.destroy().await.unwrap();
3216 }
3217
3218 #[boxed]
3221 pub(crate) async fn run_partial_ancestor_commit<F: Family, V, C>(
3222 context: deterministic::Context,
3223 open_db: impl Fn(
3224 deterministic::Context,
3225 ) -> Pin<Box<dyn Future<Output = TestDb<F, V, C>> + Send>>,
3226 ) where
3227 V: ValueEncoding<Value = Digest>,
3228 C: Mutable<Item = Operation<F, Digest, V>>,
3229 C::Item: EncodeShared,
3230 {
3231 let db = open_db(context.child("db")).await;
3232
3233 let key1 = Sha256::hash(&[&[1]]);
3234 let key2 = Sha256::hash(&[&[2]]);
3235 let key3 = Sha256::hash(&[&[3]]);
3236 let v1 = Sha256::fill(1u8);
3237 let v2 = Sha256::fill(2u8);
3238 let v3 = Sha256::fill(3u8);
3239
3240 let a = db
3242 .new_batch()
3243 .set(key1, v1)
3244 .merkleize(&db, None, Location::new(0))
3245 .await
3246 .unwrap();
3247 let e = a
3248 .new_batch::<Sha256>()
3249 .merkleize(&db, None, Location::new(0))
3250 .await
3251 .unwrap();
3252 let b = e
3253 .new_batch::<Sha256>()
3254 .set(key2, v2)
3255 .merkleize(&db, None, Location::new(0))
3256 .await
3257 .unwrap();
3258 let c = b
3259 .new_batch::<Sha256>()
3260 .set(key3, v3)
3261 .merkleize(&db, None, Location::new(0))
3262 .await
3263 .unwrap();
3264
3265 let expected_root = c.root();
3266
3267 let db = db.apply_batch(a).await.unwrap();
3269 let db = db.apply_batch(c).await.unwrap();
3270
3271 assert_eq!(db.root(), expected_root);
3272 assert_eq!(db.get(&key1).await.unwrap(), Some(v1));
3273 assert_eq!(db.get(&key2).await.unwrap(), Some(v2));
3274 assert_eq!(db.get(&key3).await.unwrap(), Some(v3));
3275
3276 let keys = [key1, key2, key3];
3278 let locations = |db: &TestDb<F, V, C>| {
3279 keys.iter()
3280 .map(|key| {
3281 let mut locations: Vec<_> = db.snapshot.get(key).collect();
3282 locations.sort();
3283 locations
3284 })
3285 .collect::<Vec<_>>()
3286 };
3287 assert_eq!(db.snapshot.len(), keys.len());
3288 let live = locations(&db);
3289
3290 db.sync().await.unwrap();
3292 let db = open_db(context.child("reopen")).await;
3293 assert_eq!(db.snapshot.len(), keys.len());
3294 assert_eq!(locations(&db), live);
3295
3296 db.destroy().await.unwrap();
3297 }
3298
3299 #[boxed]
3300 pub(crate) async fn run_delayed_merkleize_after_ancestor_apply<F: Family, V, C>(
3301 context: deterministic::Context,
3302 open_db: impl Fn(
3303 deterministic::Context,
3304 ) -> Pin<Box<dyn Future<Output = TestDb<F, V, C>> + Send>>,
3305 ) where
3306 V: ValueEncoding<Value = Digest>,
3307 C: Mutable<Item = Operation<F, Digest, V>>,
3308 C::Item: EncodeShared,
3309 {
3310 let db = open_db(context.child("db")).await;
3311
3312 let key1 = Sha256::hash(&[&[1]]);
3313 let key2 = Sha256::hash(&[&[2]]);
3314 let key3 = Sha256::hash(&[&[3]]);
3315 let v1 = Sha256::fill(1u8);
3316 let v2 = Sha256::fill(2u8);
3317 let v3 = Sha256::fill(3u8);
3318
3319 let a = db
3320 .new_batch()
3321 .set(key1, v1)
3322 .merkleize(&db, None, Location::new(0))
3323 .await
3324 .unwrap();
3325 let b = a
3326 .new_batch::<Sha256>()
3327 .set(key2, v2)
3328 .merkleize(&db, None, Location::new(0))
3329 .await
3330 .unwrap();
3331 let pending = b
3332 .new_batch::<Sha256>()
3333 .set(key3, v3)
3334 .merkleize(&db, None, Location::new(0))
3335 .await
3336 .unwrap();
3337 let expected_root = pending.root();
3338 let c = b.new_batch::<Sha256>().set(key3, v3);
3339
3340 let db = db.apply_batch(Arc::clone(&a)).await.unwrap();
3342 let live = b
3343 .new_batch::<Sha256>()
3344 .set(key3, v3)
3345 .merkleize(&db, None, Location::new(0))
3346 .await
3347 .unwrap();
3348 assert_eq!(live.root(), expected_root);
3349
3350 drop(a);
3352 let retired = c.merkleize(&db, None, Location::new(0)).await.unwrap();
3353 assert_eq!(retired.bounds().db, db.commitment());
3354 assert_eq!(retired.root(), expected_root);
3355
3356 let c = b.new_batch::<Sha256>().set(key3, v3);
3357 let db = db.apply_batch(b).await.unwrap();
3358 let c = c.merkleize(&db, None, Location::new(0)).await.unwrap();
3359 assert_eq!(c.root(), expected_root);
3360 let db = db.apply_batch(c).await.unwrap();
3361
3362 assert_eq!(db.root(), expected_root);
3363 assert_eq!(db.get(&key1).await.unwrap(), Some(v1));
3364 assert_eq!(db.get(&key2).await.unwrap(), Some(v2));
3365 assert_eq!(db.get(&key3).await.unwrap(), Some(v3));
3366
3367 db.destroy().await.unwrap();
3368 }
3369
3370 #[boxed]
3371 pub(crate) async fn run_sequential_commit_parent_then_child<F: Family, V, C>(
3372 context: deterministic::Context,
3373 open_db: impl Fn(
3374 deterministic::Context,
3375 ) -> Pin<Box<dyn Future<Output = TestDb<F, V, C>> + Send>>,
3376 ) where
3377 V: ValueEncoding<Value = Digest>,
3378 C: Mutable<Item = Operation<F, Digest, V>>,
3379 C::Item: EncodeShared,
3380 {
3381 let db = open_db(context.child("db")).await;
3382
3383 let key1 = Sha256::hash(&[&[1]]);
3384 let key2 = Sha256::hash(&[&[2]]);
3385 let v1 = Sha256::fill(1u8);
3386 let v2 = Sha256::fill(2u8);
3387
3388 let parent_m = db
3390 .new_batch()
3391 .set(key1, v1)
3392 .merkleize(&db, None, Location::new(0))
3393 .await
3394 .unwrap();
3395
3396 let child_m = parent_m
3398 .new_batch::<Sha256>()
3399 .set(key2, v2)
3400 .merkleize(&db, None, Location::new(0))
3401 .await
3402 .unwrap();
3403
3404 let db = db.apply_batch(parent_m).await.unwrap();
3406 let db = db.apply_batch(child_m).await.unwrap();
3407
3408 assert_eq!(db.get(&key1).await.unwrap(), Some(v1));
3410 assert_eq!(db.get(&key2).await.unwrap(), Some(v2));
3411
3412 db.destroy().await.unwrap();
3413 }
3414
3415 #[boxed]
3416 pub(crate) async fn run_child_root_matches_pending_and_committed<F: Family, V, C>(
3417 context: deterministic::Context,
3418 open_db: impl Fn(
3419 deterministic::Context,
3420 ) -> Pin<Box<dyn Future<Output = TestDb<F, V, C>> + Send>>,
3421 ) where
3422 V: ValueEncoding<Value = Digest>,
3423 C: Mutable<Item = Operation<F, Digest, V>>,
3424 C::Item: EncodeShared,
3425 {
3426 let db = open_db(context.child("db")).await;
3427
3428 let key1 = Sha256::hash(&[&[1]]);
3429 let key2 = Sha256::hash(&[&[2]]);
3430
3431 let parent = db
3433 .new_batch()
3434 .set(key1, Sha256::fill(1u8))
3435 .merkleize(&db, None, Location::new(0))
3436 .await
3437 .unwrap();
3438 let pending_child = parent
3439 .new_batch::<Sha256>()
3440 .set(key2, Sha256::fill(2u8))
3441 .merkleize(&db, None, Location::new(0))
3442 .await
3443 .unwrap();
3444
3445 let db = db.apply_batch(parent).await.unwrap();
3448 let db = db.commit().await.unwrap();
3449
3450 let committed_child = db
3451 .new_batch()
3452 .set(key2, Sha256::fill(2u8))
3453 .merkleize(&db, None, Location::new(0))
3454 .await
3455 .unwrap();
3456
3457 assert_eq!(pending_child.root(), committed_child.root());
3458
3459 db.destroy().await.unwrap();
3460 }
3461
3462 #[boxed]
3463 pub(crate) async fn run_stale_batch_child_applied_before_parent<F: Family, V, C>(
3464 context: deterministic::Context,
3465 open_db: impl Fn(
3466 deterministic::Context,
3467 ) -> Pin<Box<dyn Future<Output = TestDb<F, V, C>> + Send>>,
3468 ) where
3469 V: ValueEncoding<Value = Digest>,
3470 C: Mutable<Item = Operation<F, Digest, V>>,
3471 C::Item: EncodeShared,
3472 {
3473 let db = open_db(context.child("db")).await;
3474
3475 let key1 = Sha256::hash(&[&[1]]);
3476 let key2 = Sha256::hash(&[&[2]]);
3477
3478 let parent_m = db
3480 .new_batch()
3481 .set(key1, Sha256::fill(1u8))
3482 .merkleize(&db, None, Location::new(0))
3483 .await
3484 .unwrap();
3485
3486 let child_m = parent_m
3488 .new_batch::<Sha256>()
3489 .set(key2, Sha256::fill(2u8))
3490 .merkleize(&db, None, Location::new(0))
3491 .await
3492 .unwrap();
3493
3494 let db = db.apply_batch(child_m).await.unwrap();
3496
3497 let result = db.apply_batch(parent_m).await;
3499 assert!(matches!(result, Err(Error::StaleBatch)));
3500 }
3501
3502 #[boxed]
3505 pub(crate) async fn run_to_batch<F: Family, V, C>(
3506 context: deterministic::Context,
3507 open_db: impl Fn(
3508 deterministic::Context,
3509 ) -> Pin<Box<dyn Future<Output = TestDb<F, V, C>> + Send>>,
3510 ) where
3511 V: ValueEncoding<Value = Digest>,
3512 C: Mutable<Item = Operation<F, Digest, V>>,
3513 C::Item: EncodeShared,
3514 {
3515 let db = open_db(context.child("db")).await;
3516
3517 let key1 = Sha256::hash(&[&[1]]);
3519 let v1 = Sha256::fill(10u8);
3520 let merkleized = db
3521 .new_batch()
3522 .set(key1, v1)
3523 .merkleize(&db, None, Location::new(0))
3524 .await
3525 .unwrap();
3526 let db = db.apply_batch(merkleized).await.unwrap();
3527
3528 let snapshot = db.to_batch();
3530 assert_eq!(snapshot.root(), db.root());
3531
3532 let key2 = Sha256::hash(&[&[2]]);
3534 let v2 = Sha256::fill(20u8);
3535 let child = snapshot
3536 .new_batch::<Sha256>()
3537 .set(key2, v2)
3538 .merkleize(&db, None, Location::new(0))
3539 .await
3540 .unwrap();
3541 let db = db.apply_batch(child).await.unwrap();
3542
3543 assert_eq!(db.get(&key1).await.unwrap(), Some(v1));
3544 assert_eq!(db.get(&key2).await.unwrap(), Some(v2));
3545
3546 db.destroy().await.unwrap();
3547 }
3548
3549 #[boxed]
3552 pub(crate) async fn run_apply_after_ancestor_dropped<F: Family, V, C>(
3553 context: deterministic::Context,
3554 open_db: impl Fn(
3555 deterministic::Context,
3556 ) -> Pin<Box<dyn Future<Output = TestDb<F, V, C>> + Send>>,
3557 ) where
3558 V: ValueEncoding<Value = Digest>,
3559 C: Mutable<Item = Operation<F, Digest, V>>,
3560 C::Item: EncodeShared,
3561 {
3562 let db = open_db(context.child("db")).await;
3563
3564 let key1 = Sha256::hash(&[&[1]]);
3565 let key2 = Sha256::hash(&[&[2]]);
3566 let key3 = Sha256::hash(&[&[3]]);
3567 let v1 = Sha256::fill(1u8);
3568 let v2 = Sha256::fill(2u8);
3569 let v3 = Sha256::fill(3u8);
3570
3571 let a = db
3573 .new_batch()
3574 .set(key1, v1)
3575 .merkleize(&db, None, Location::new(0))
3576 .await
3577 .unwrap();
3578 let b = a
3579 .new_batch::<Sha256>()
3580 .set(key2, v2)
3581 .merkleize(&db, None, Location::new(0))
3582 .await
3583 .unwrap();
3584 let c = b
3585 .new_batch::<Sha256>()
3586 .set(key3, v3)
3587 .merkleize(&db, None, Location::new(0))
3588 .await
3589 .unwrap();
3590
3591 drop(a);
3593 drop(b);
3594
3595 let db = db.apply_batch(c).await.unwrap();
3597
3598 assert_eq!(db.get(&key1).await.unwrap(), Some(v1));
3600 assert_eq!(db.get(&key2).await.unwrap(), Some(v2));
3601 assert_eq!(db.get(&key3).await.unwrap(), Some(v3));
3602
3603 db.destroy().await.unwrap();
3604 }
3605
3606 #[boxed]
3609 pub(crate) async fn run_inactivity_floor_tracking<F: Family, V, C>(
3610 context: deterministic::Context,
3611 open_db: impl Fn(
3612 deterministic::Context,
3613 ) -> Pin<Box<dyn Future<Output = TestDb<F, V, C>> + Send>>,
3614 ) where
3615 V: ValueEncoding<Value = Digest>,
3616 C: Mutable<Item = Operation<F, Digest, V>>,
3617 C::Item: EncodeShared,
3618 {
3619 let db = open_db(context.child("test")).await;
3620
3621 assert_eq!(db.inactivity_floor_loc(), Location::new(0));
3623
3624 let k1 = Sha256::fill(1u8);
3626 let v1 = Sha256::fill(2u8);
3627 let merkleized = db
3628 .new_batch()
3629 .set(k1, v1)
3630 .merkleize(&db, None, Location::new(0))
3631 .await
3632 .unwrap();
3633 let db = db.apply_batch(merkleized).await.unwrap();
3634 assert_eq!(db.inactivity_floor_loc(), Location::new(0));
3635
3636 let k2 = Sha256::fill(3u8);
3638 let v2 = Sha256::fill(4u8);
3639 let merkleized = db
3640 .new_batch()
3641 .set(k2, v2)
3642 .merkleize(&db, None, Location::new(3))
3643 .await
3644 .unwrap();
3645 let db = db.apply_batch(merkleized).await.unwrap();
3646 assert_eq!(db.inactivity_floor_loc(), Location::new(3));
3647
3648 let db = db.commit().await.unwrap();
3650 db.sync().await.unwrap();
3651 let db = open_db(context.child("reopen")).await;
3652 assert_eq!(db.inactivity_floor_loc(), Location::new(3));
3653
3654 db.destroy().await.unwrap();
3655 }
3656
3657 #[boxed]
3660 pub(crate) async fn run_floor_monotonicity<F: Family, V, C>(
3661 context: deterministic::Context,
3662 open_db: impl Fn(
3663 deterministic::Context,
3664 ) -> Pin<Box<dyn Future<Output = TestDb<F, V, C>> + Send>>,
3665 ) where
3666 V: ValueEncoding<Value = Digest>,
3667 C: Mutable<Item = Operation<F, Digest, V>>,
3668 C::Item: EncodeShared,
3669 {
3670 let db = open_db(context.child("test")).await;
3671
3672 let k1 = Sha256::fill(1u8);
3675 let v1 = Sha256::fill(2u8);
3676 let merkleized = db
3677 .new_batch()
3678 .set(k1, v1)
3679 .merkleize(&db, None, Location::new(2))
3680 .await
3681 .unwrap();
3682 let db = db.apply_batch(merkleized).await.unwrap();
3683 assert_eq!(db.inactivity_floor_loc(), Location::new(2));
3684
3685 let k2 = Sha256::fill(3u8);
3687 let v2 = Sha256::fill(4u8);
3688 let merkleized = db
3689 .new_batch()
3690 .set(k2, v2)
3691 .merkleize(&db, None, Location::new(2))
3692 .await
3693 .unwrap();
3694 let db = db.apply_batch(merkleized).await.unwrap();
3695 assert_eq!(db.inactivity_floor_loc(), Location::new(2));
3696
3697 let k3 = Sha256::fill(5u8);
3699 let v3 = Sha256::fill(6u8);
3700 let merkleized = db
3701 .new_batch()
3702 .set(k3, v3)
3703 .merkleize(&db, None, Location::new(5))
3704 .await
3705 .unwrap();
3706 let db = db.apply_batch(merkleized).await.unwrap();
3707 assert_eq!(db.inactivity_floor_loc(), Location::new(5));
3708
3709 db.destroy().await.unwrap();
3710 }
3711
3712 #[boxed]
3714 pub(crate) async fn run_bounded_initialization_restores_floor<F: Family, V, C>(
3715 context: deterministic::Context,
3716 open_db: impl Fn(
3717 deterministic::Context,
3718 Option<Location<F>>,
3719 )
3720 -> Pin<Box<dyn Future<Output = Result<TestDb<F, V, C>, Error<F>>> + Send>>,
3721 ) where
3722 V: ValueEncoding<Value = Digest>,
3723 C: Mutable<Item = Operation<F, Digest, V>>,
3724 C::Item: EncodeShared,
3725 {
3726 let db = open_db(context.child("test"), None).await.unwrap();
3727
3728 let k1 = Sha256::fill(1u8);
3730 let v1 = Sha256::fill(2u8);
3731 let merkleized = db
3732 .new_batch()
3733 .set(k1, v1)
3734 .merkleize(&db, None, Location::new(2))
3735 .await
3736 .unwrap();
3737 let db = db.apply_batch(merkleized).await.unwrap();
3738 let db = db.commit().await.unwrap();
3739 let first_size = db.bounds().end;
3740 assert_eq!(db.inactivity_floor_loc(), Location::new(2));
3741
3742 let k2 = Sha256::fill(3u8);
3744 let v2 = Sha256::fill(4u8);
3745 let merkleized = db
3746 .new_batch()
3747 .set(k2, v2)
3748 .merkleize(&db, None, Location::new(4))
3749 .await
3750 .unwrap();
3751 let db = db.apply_batch(merkleized).await.unwrap();
3752 let db = db.commit().await.unwrap();
3753 assert_eq!(db.inactivity_floor_loc(), Location::new(4));
3754
3755 _ = db.sync().await.unwrap();
3757 let db = open_db(context.child("cap"), Some(first_size))
3758 .await
3759 .unwrap();
3760 assert_eq!(db.inactivity_floor_loc(), Location::new(2));
3761
3762 db.destroy().await.unwrap();
3763 }
3764
3765 #[boxed]
3768 pub(crate) async fn run_floor_monotonicity_violation<F: Family, V, C>(
3769 context: deterministic::Context,
3770 open_db: impl Fn(
3771 deterministic::Context,
3772 ) -> Pin<Box<dyn Future<Output = TestDb<F, V, C>> + Send>>,
3773 ) where
3774 V: ValueEncoding<Value = Digest>,
3775 C: Mutable<Item = Operation<F, Digest, V>>,
3776 C::Item: EncodeShared,
3777 {
3778 let db = open_db(context.child("test")).await;
3779
3780 let k1 = Sha256::fill(1u8);
3782 let v1 = Sha256::fill(2u8);
3783 let merkleized = db
3784 .new_batch()
3785 .set(k1, v1)
3786 .merkleize(&db, None, Location::new(2))
3787 .await
3788 .unwrap();
3789 let db = db.apply_batch(merkleized).await.unwrap();
3790
3791 let k2 = Sha256::fill(3u8);
3793 let v2 = Sha256::fill(4u8);
3794 let result = db
3795 .new_batch()
3796 .set(k2, v2)
3797 .merkleize(&db, None, Location::new(1))
3798 .await;
3799 assert!(matches!(result, Err(Error::FloorRegressed(new, current))
3800 if new == Location::new(1) && current == Location::new(2)));
3801 }
3802
3803 #[boxed]
3805 pub(crate) async fn run_floor_beyond_size<F: Family, V, C>(
3806 context: deterministic::Context,
3807 open_db: impl Fn(
3808 deterministic::Context,
3809 ) -> Pin<Box<dyn Future<Output = TestDb<F, V, C>> + Send>>,
3810 ) where
3811 V: ValueEncoding<Value = Digest>,
3812 C: Mutable<Item = Operation<F, Digest, V>>,
3813 C::Item: EncodeShared,
3814 {
3815 let db = open_db(context.child("test")).await;
3816
3817 let k1 = Sha256::fill(1u8);
3820 let v1 = Sha256::fill(2u8);
3821 let result = db
3822 .new_batch()
3823 .set(k1, v1)
3824 .merkleize(&db, None, Location::new(100))
3825 .await;
3826 assert!(matches!(result, Err(Error::FloorBeyondSize(floor, commit))
3827 if floor == Location::new(100) && commit == Location::new(2)));
3828
3829 let k2 = Sha256::fill(3u8);
3833 let v2 = Sha256::fill(4u8);
3834 let result = db
3835 .new_batch()
3836 .set(k2, v2)
3837 .merkleize(&db, None, Location::new(3))
3838 .await;
3839 assert!(matches!(result, Err(Error::FloorBeyondSize(floor, commit))
3840 if floor == Location::new(3) && commit == Location::new(2)));
3841
3842 let merkleized = db
3844 .new_batch()
3845 .set(k2, v2)
3846 .merkleize(&db, None, Location::new(2))
3847 .await
3848 .unwrap();
3849 let db = db.apply_batch(merkleized).await.unwrap();
3850
3851 db.destroy().await.unwrap();
3852 }
3853
3854 #[boxed]
3857 pub(crate) async fn run_chained_floor_regression<F: Family, V, C>(
3858 context: deterministic::Context,
3859 open_db: impl Fn(
3860 deterministic::Context,
3861 ) -> Pin<Box<dyn Future<Output = TestDb<F, V, C>> + Send>>,
3862 ) where
3863 V: ValueEncoding<Value = Digest>,
3864 C: Mutable<Item = Operation<F, Digest, V>>,
3865 C::Item: EncodeShared,
3866 {
3867 let db = open_db(context.child("test")).await;
3868
3869 let a = db
3875 .new_batch()
3876 .set(Sha256::fill(1u8), Sha256::fill(2u8))
3877 .merkleize(&db, None, Location::new(2))
3878 .await
3879 .unwrap();
3880
3881 let Err(err) = a
3882 .new_batch::<Sha256>()
3883 .set(Sha256::fill(3u8), Sha256::fill(4u8))
3884 .merkleize(&db, None, Location::new(1))
3885 .await
3886 else {
3887 panic!("merkleize must reject the invalid floor");
3888 };
3889 assert!(
3890 matches!(err, Error::FloorRegressed(new, prev)
3891 if new == Location::new(1) && prev == Location::new(2)),
3892 "unexpected error: {err:?}"
3893 );
3894
3895 db.destroy().await.unwrap();
3896 }
3897
3898 #[boxed]
3902 pub(crate) async fn run_chained_floor_beyond_commit<F: Family, V, C>(
3903 context: deterministic::Context,
3904 open_db: impl Fn(
3905 deterministic::Context,
3906 ) -> Pin<Box<dyn Future<Output = TestDb<F, V, C>> + Send>>,
3907 ) where
3908 V: ValueEncoding<Value = Digest>,
3909 C: Mutable<Item = Operation<F, Digest, V>>,
3910 C::Item: EncodeShared,
3911 {
3912 let db = open_db(context.child("test")).await;
3913
3914 let a = db
3916 .new_batch()
3917 .set(Sha256::fill(1u8), Sha256::fill(2u8))
3918 .merkleize(&db, None, Location::new(2))
3919 .await
3920 .unwrap();
3921
3922 let Err(err) = a
3925 .new_batch::<Sha256>()
3926 .set(Sha256::fill(3u8), Sha256::fill(4u8))
3927 .merkleize(&db, None, Location::new(5))
3928 .await
3929 else {
3930 panic!("merkleize must reject the invalid floor");
3931 };
3932 assert!(
3933 matches!(err, Error::FloorBeyondSize(floor, commit)
3934 if floor == Location::new(5) && commit == Location::new(4)),
3935 "unexpected error: {err:?}"
3936 );
3937
3938 db.destroy().await.unwrap();
3939 }
3940
3941 #[boxed]
3944 pub(crate) async fn run_bounded_initialization_after_reopen_with_floor_change<F: Family, V, C>(
3945 context: deterministic::Context,
3946 open_db: impl Fn(
3947 deterministic::Context,
3948 Option<Location<F>>,
3949 )
3950 -> Pin<Box<dyn Future<Output = Result<TestDb<F, V, C>, Error<F>>> + Send>>,
3951 ) where
3952 V: ValueEncoding<Value = Digest>,
3953 C: Mutable<Item = Operation<F, Digest, V>>,
3954 C::Item: EncodeShared,
3955 {
3956 let db = open_db(context.child("first"), None).await.unwrap();
3957
3958 let k1 = Sha256::fill(1u8);
3959 let k2 = Sha256::fill(2u8);
3960 let k3 = Sha256::fill(3u8);
3961 let v1 = Sha256::fill(11u8);
3962 let v2 = Sha256::fill(12u8);
3963 let v3 = Sha256::fill(13u8);
3964
3965 let db = commit_sets(db, [(k1, v1), (k2, v2), (k3, v3)], None).await;
3967 let first_size = db.bounds().end;
3968 let first_root = db.root();
3969
3970 let k4 = Sha256::fill(4u8);
3972 let k5 = Sha256::fill(5u8);
3973 let k6 = Sha256::fill(6u8);
3974 let v4 = Sha256::fill(14u8);
3975 let v5 = Sha256::fill(15u8);
3976 let v6 = Sha256::fill(16u8);
3977 let db = commit_sets_with_floor(db, [(k4, v4), (k5, v5), (k6, v6)], None, first_size).await;
3978 db.sync().await.unwrap();
3979
3980 let db = open_db(context.child("second"), None).await.unwrap();
3982
3983 assert!(db.get(&k1).await.unwrap().is_none());
3985
3986 _ = db.sync().await.unwrap();
3988 let db = open_db(context.child("cap"), Some(first_size))
3989 .await
3990 .unwrap();
3991
3992 assert_eq!(db.get(&k1).await.unwrap(), Some(v1));
3994 assert_eq!(db.get(&k2).await.unwrap(), Some(v2));
3995 assert_eq!(db.get(&k3).await.unwrap(), Some(v3));
3996 assert_eq!(db.root(), first_root);
3997 assert_eq!(db.inactivity_floor_loc(), Location::new(0));
3998
3999 assert!(db.get(&k4).await.unwrap().is_none());
4001
4002 db.destroy().await.unwrap();
4003 }
4004
4005 #[boxed]
4008 pub(crate) async fn run_bounded_initialization_after_reopen_partial_floor_gap<F: Family, V, C>(
4009 context: deterministic::Context,
4010 open_db: impl Fn(
4011 deterministic::Context,
4012 Option<Location<F>>,
4013 )
4014 -> Pin<Box<dyn Future<Output = Result<TestDb<F, V, C>, Error<F>>> + Send>>,
4015 ) where
4016 V: ValueEncoding<Value = Digest>,
4017 C: Mutable<Item = Operation<F, Digest, V>>,
4018 C::Item: EncodeShared,
4019 {
4020 let db = open_db(context.child("first"), None).await.unwrap();
4021
4022 let k1 = Sha256::fill(1u8);
4023 let v1 = Sha256::fill(11u8);
4024
4025 let db = commit_sets(db, [(k1, v1)], None).await;
4027 let first_size = db.bounds().end;
4028 let first_root = db.root();
4029
4030 let k2 = Sha256::fill(2u8);
4032 let v2 = Sha256::fill(12u8);
4033 let db = commit_sets_with_floor(db, [(k2, v2)], None, first_size).await;
4034 let second_size = db.bounds().end;
4035
4036 let k3 = Sha256::fill(3u8);
4039 let v3 = Sha256::fill(13u8);
4040 let db = commit_sets_with_floor(db, [(k3, v3)], None, second_size).await;
4041 db.sync().await.unwrap();
4042
4043 let db = open_db(context.child("second"), None).await.unwrap();
4045 assert!(db.get(&k1).await.unwrap().is_none());
4046 assert!(db.get(&k2).await.unwrap().is_none());
4047 assert_eq!(db.get(&k3).await.unwrap(), Some(v3));
4048
4049 _ = db.sync().await.unwrap();
4051 let db = open_db(context.child("cap"), Some(second_size))
4052 .await
4053 .unwrap();
4054 assert!(db.get(&k1).await.unwrap().is_none()); assert_eq!(db.get(&k2).await.unwrap(), Some(v2));
4056 assert!(db.get(&k3).await.unwrap().is_none()); _ = db.sync().await.unwrap();
4060 let db = open_db(context.child("cap"), Some(first_size))
4061 .await
4062 .unwrap();
4063 assert_eq!(db.get(&k1).await.unwrap(), Some(v1));
4064 assert!(db.get(&k2).await.unwrap().is_none()); assert_eq!(db.root(), first_root);
4066 assert_eq!(db.inactivity_floor_loc(), Location::new(0));
4067
4068 db.destroy().await.unwrap();
4069 }
4070
4071 #[boxed]
4081 pub(crate) async fn run_single_commit_live_set<F: Family, V, C>(
4082 context: deterministic::Context,
4083 open_db: impl Fn(
4084 deterministic::Context,
4085 ) -> Pin<Box<dyn Future<Output = TestDb<F, V, C>> + Send>>,
4086 ) where
4087 V: ValueEncoding<Value = Digest>,
4088 C: Mutable<Item = Operation<F, Digest, V>>,
4089 C::Item: EncodeShared,
4090 {
4091 let db = open_db(context.child("test")).await;
4092
4093 let metadata = Sha256::fill(42u8);
4096 let commit_loc = Location::<F>::new(4);
4097 let k1 = Sha256::fill(1u8);
4098 let k2 = Sha256::fill(2u8);
4099 let k3 = Sha256::fill(3u8);
4100 let v1 = Sha256::fill(11u8);
4101 let v2 = Sha256::fill(12u8);
4102 let v3 = Sha256::fill(13u8);
4103 let merkleized = db
4104 .new_batch()
4105 .set(k1, v1)
4106 .set(k2, v2)
4107 .set(k3, v3)
4108 .merkleize(&db, Some(metadata), commit_loc)
4109 .await
4110 .unwrap();
4111 let db = db.apply_batch(merkleized).await.unwrap();
4112 let db = db.commit().await.unwrap();
4113 assert_eq!(db.size() - 1, commit_loc);
4114 assert_eq!(db.inactivity_floor_loc(), commit_loc);
4115 let root_after_commit = db.root();
4116
4117 assert_eq!(db.get(&k1).await.unwrap(), Some(v1));
4119 assert_eq!(db.get(&k2).await.unwrap(), Some(v2));
4120 assert_eq!(db.get(&k3).await.unwrap(), Some(v3));
4121
4122 let db = db.prune(commit_loc).await.unwrap();
4127 let bounds = db.bounds();
4128 assert!(
4129 bounds.start <= commit_loc,
4130 "prune must not advance bounds.start past the floor"
4131 );
4132 assert_eq!(bounds.end, commit_loc + 1);
4133
4134 assert_eq!(db.size() - 1, commit_loc);
4136 assert_eq!(db.inactivity_floor_loc(), commit_loc);
4137 assert_eq!(db.root(), root_after_commit);
4138 assert_eq!(db.get_metadata().await.unwrap(), Some(metadata));
4139
4140 let db = db.sync().await.unwrap();
4143 let Err(err) = db.prune(commit_loc + 1).await else {
4144 panic!("expected prune to fail");
4145 };
4146 assert!(matches!(err, Error::PruneBeyondMinRequired(p, f)
4147 if *p == *commit_loc + 1 && *f == *commit_loc));
4148
4149 let db = open_db(context.child("reopened")).await;
4152 assert_eq!(db.size() - 1, commit_loc);
4153 assert_eq!(db.inactivity_floor_loc(), commit_loc);
4154 assert_eq!(db.root(), root_after_commit);
4155
4156 assert_eq!(db.get_metadata().await.unwrap(), Some(metadata));
4159
4160 assert!(db.get(&k1).await.unwrap().is_none());
4162 assert!(db.get(&k2).await.unwrap().is_none());
4163 assert!(db.get(&k3).await.unwrap().is_none());
4164
4165 let k4 = Sha256::fill(4u8);
4169 let v4 = Sha256::fill(14u8);
4170 let next_commit_loc = Location::<F>::new(6);
4171 let merkleized = db
4172 .new_batch()
4173 .set(k4, v4)
4174 .merkleize(&db, None, next_commit_loc)
4175 .await
4176 .unwrap();
4177 let db = db.apply_batch(merkleized).await.unwrap();
4178 let db = db.commit().await.unwrap();
4179 assert_eq!(db.size() - 1, next_commit_loc);
4180 assert_eq!(db.inactivity_floor_loc(), next_commit_loc);
4181
4182 assert_eq!(db.get(&k4).await.unwrap(), Some(v4));
4184 assert!(db.get(&k1).await.unwrap().is_none());
4185 assert_eq!(db.get_metadata().await.unwrap(), None);
4188
4189 db.destroy().await.unwrap();
4190 }
4191
4192 #[boxed]
4195 pub(crate) async fn run_get_many<F: Family, V, C>(
4196 context: deterministic::Context,
4197 open_db: impl Fn(
4198 deterministic::Context,
4199 ) -> Pin<Box<dyn Future<Output = TestDb<F, V, C>> + Send>>,
4200 ) where
4201 V: ValueEncoding<Value = Digest>,
4202 C: Mutable<Item = Operation<F, Digest, V>>,
4203 C::Item: EncodeShared,
4204 {
4205 let db = open_db(context.child("db")).await;
4206
4207 let k1 = Sha256::fill(1u8);
4208 let k2 = Sha256::fill(2u8);
4209 let k3 = Sha256::fill(3u8);
4210 let k_missing = Sha256::fill(99u8);
4211
4212 let v1 = Sha256::fill(11u8);
4213 let v2 = Sha256::fill(12u8);
4214 let v3 = Sha256::fill(13u8);
4215
4216 let merkleized = db
4218 .new_batch()
4219 .set(k1, v1)
4220 .set(k2, v2)
4221 .merkleize(&db, None, db.inactivity_floor_loc())
4222 .await
4223 .unwrap();
4224 let db = db.apply_batch(merkleized).await.unwrap();
4225 let db = db.commit().await.unwrap();
4226
4227 let results = db.get_many(&[&k1, &k2, &k_missing]).await.unwrap();
4229 assert_eq!(results, vec![Some(v1), Some(v2), None]);
4230
4231 let results = db.get_many(&([] as [&Digest; 0])).await.unwrap();
4233 assert!(results.is_empty());
4234
4235 let batch = db.new_batch().set(k3, v3);
4237 let results = batch.get_many(&[&k3, &k1, &k_missing], &db).await.unwrap();
4238 assert_eq!(results, vec![Some(v3), Some(v1), None]);
4239
4240 let parent = db
4242 .new_batch()
4243 .set(k3, v3)
4244 .merkleize(&db, None, db.inactivity_floor_loc())
4245 .await
4246 .unwrap();
4247 let results = parent.get_many(&[&k1, &k3, &k_missing], &db).await.unwrap();
4248 assert_eq!(results, vec![Some(v1), Some(v3), None]);
4249
4250 let k4 = Sha256::fill(4u8);
4252 let v4 = Sha256::fill(14u8);
4253 let child = parent.new_batch::<Sha256>().set(k4, v4);
4254 let results = child
4255 .get_many(&[&k1, &k3, &k4, &k_missing], &db)
4256 .await
4257 .unwrap();
4258 assert_eq!(results, vec![Some(v1), Some(v3), Some(v4), None]);
4259
4260 db.destroy().await.unwrap();
4261 }
4262
4263 #[boxed]
4265 pub(crate) async fn run_get_many_duplicate_keys<F: Family, V, C>(
4266 context: deterministic::Context,
4267 open_db: impl Fn(
4268 deterministic::Context,
4269 ) -> Pin<Box<dyn Future<Output = TestDb<F, V, C>> + Send>>,
4270 ) where
4271 V: ValueEncoding<Value = Digest>,
4272 C: Mutable<Item = Operation<F, Digest, V>>,
4273 C::Item: EncodeShared,
4274 {
4275 let db = open_db(context.child("db")).await;
4276
4277 let key = Sha256::fill(1u8);
4278 let value = Sha256::fill(11u8);
4279 let k_missing = Sha256::fill(99u8);
4280 let merkleized = db
4281 .new_batch()
4282 .set(key, value)
4283 .merkleize(&db, None, db.inactivity_floor_loc())
4284 .await
4285 .unwrap();
4286 let db = db.apply_batch(merkleized).await.unwrap();
4287 let db = db.commit().await.unwrap();
4288
4289 let results = db.get_many(&[&key, &k_missing, &key, &key]).await.unwrap();
4290 assert_eq!(results, vec![Some(value), None, Some(value), Some(value)]);
4291
4292 db.destroy().await.unwrap();
4293 }
4294
4295 #[boxed]
4297 pub(crate) async fn run_get_many_unexpected_data<F: Family, V, C>(
4298 context: deterministic::Context,
4299 open_db: impl Fn(
4300 deterministic::Context,
4301 ) -> Pin<Box<dyn Future<Output = TestDb<F, V, C>> + Send>>,
4302 ) where
4303 V: ValueEncoding<Value = Digest>,
4304 C: Mutable<Item = Operation<F, Digest, V>>,
4305 C::Item: EncodeShared,
4306 {
4307 let db = open_db(context.child("db")).await;
4308
4309 let key = Sha256::fill(1u8);
4310 let value = Sha256::fill(11u8);
4311 let merkleized = db
4312 .new_batch()
4313 .set(key, value)
4314 .merkleize(&db, None, db.inactivity_floor_loc())
4315 .await
4316 .unwrap();
4317 let db = db.apply_batch(merkleized).await.unwrap();
4318 let mut db = db.commit().await.unwrap();
4319
4320 let bad_key = Sha256::fill(99u8);
4321 let bad_loc = db.size() - 1;
4322 db.snapshot.insert(&bad_key, *bad_loc);
4323
4324 let err = db.get(&bad_key).await.unwrap_err();
4325 assert!(matches!(err, Error::UnexpectedData(loc) if loc == bad_loc));
4326
4327 let err = db.get_many(&[&bad_key]).await.unwrap_err();
4328 assert!(matches!(err, Error::UnexpectedData(loc) if loc == bad_loc));
4329
4330 db.destroy().await.unwrap();
4331 }
4332}