Skip to main content

commonware_storage/qmdb/sync/
resolver.rs

1use crate::{
2    merkle::{Family, Location, Proof},
3    qmdb::{
4        self,
5        any::{
6            ordered::{
7                fixed::{Db as OrderedFixedDb, Operation as OrderedFixedOperation},
8                variable::{Db as OrderedVariableDb, Operation as OrderedVariableOperation},
9            },
10            unordered::{
11                fixed::{Db as FixedDb, Operation as FixedOperation},
12                variable::{Db as VariableDb, Operation as VariableOperation},
13            },
14            FixedValue, VariableValue,
15        },
16        immutable::{
17            fixed::{Db as ImmutableFixedDb, Operation as ImmutableFixedOp},
18            variable::{Db as ImmutableVariableDb, Operation as ImmutableVariableOp},
19        },
20        keyless::{
21            fixed::{Db as KeylessFixedDb, Operation as KeylessFixedOp},
22            variable::{Db as KeylessVariableDb, Operation as KeylessVariableOp},
23        },
24        operation::Key,
25    },
26    translator::Translator,
27    Context,
28};
29use commonware_cryptography::{Digest, Hasher};
30use commonware_parallel::Strategy;
31use commonware_utils::{
32    channel::oneshot,
33    sync::{AsyncRwLock, TracedAsyncRwLock},
34    Array,
35};
36use std::{future::Future, num::NonZeroU64, sync::Arc};
37
38/// Result from a fetch operation.
39pub struct FetchResult<F: Family, Op, D: Digest> {
40    /// The proof for the operations
41    pub proof: Proof<F, D>,
42    /// The operations that were fetched
43    pub operations: Vec<Op>,
44    /// Pinned merkle nodes at the start location, if requested
45    pub pinned_nodes: Option<Vec<D>>,
46    /// Optional callback for resolvers that observe downstream validation feedback.
47    pub callback: Option<oneshot::Sender<bool>>,
48}
49
50impl<F: Family, Op, D: Digest> FetchResult<F, Op, D> {
51    /// Creates a fetch result that does not observe the validation acknowledgement.
52    pub const fn new(
53        proof: Proof<F, D>,
54        operations: Vec<Op>,
55        pinned_nodes: Option<Vec<D>>,
56    ) -> Self {
57        Self {
58            proof,
59            operations,
60            pinned_nodes,
61            callback: None,
62        }
63    }
64
65    /// Creates a fetch result using an externally managed validation callback.
66    pub const fn with_callback(
67        proof: Proof<F, D>,
68        operations: Vec<Op>,
69        pinned_nodes: Option<Vec<D>>,
70        callback: oneshot::Sender<bool>,
71    ) -> Self {
72        Self {
73            proof,
74            operations,
75            pinned_nodes,
76            callback: Some(callback),
77        }
78    }
79}
80
81/// Operations fetched from a resolver before packaging as a [`FetchResult`].
82pub struct FetchedOperations<F: Family, Op, D: Digest> {
83    /// The proof for the operations
84    pub proof: Proof<F, D>,
85    /// The operations that were fetched
86    pub operations: Vec<Op>,
87    /// Pinned merkle nodes at the start location, if requested
88    pub pinned_nodes: Option<Vec<D>>,
89}
90
91impl<F: Family, Op, D: Digest> FetchedOperations<F, Op, D> {
92    /// Creates fetched operations with optional pinned nodes.
93    pub const fn new(
94        proof: Proof<F, D>,
95        operations: Vec<Op>,
96        pinned_nodes: Option<Vec<D>>,
97    ) -> Self {
98        Self {
99            proof,
100            operations,
101            pinned_nodes,
102        }
103    }
104}
105
106impl<F: Family, Op: std::fmt::Debug, D: Digest> std::fmt::Debug for FetchResult<F, Op, D> {
107    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
108        f.debug_struct("FetchResult")
109            .field("proof", &self.proof)
110            .field("operations", &self.operations)
111            .field("pinned_nodes", &self.pinned_nodes)
112            .field("callback", &self.callback.as_ref().map(|_| "<callback>"))
113            .finish()
114    }
115}
116
117/// Fetch an operation range with a caller-provided callback and package it as a
118/// [`FetchResult`].
119///
120/// Use this when the source returns the proof, operations, and optional pinned nodes together,
121/// such as a network `get_operations` request.
122pub async fn fetch_operation_range<F, Op, D, Error, Fetch, FetchFuture>(
123    op_count: Location<F>,
124    start_loc: Location<F>,
125    max_ops: NonZeroU64,
126    include_pinned_nodes: bool,
127    fetch: Fetch,
128) -> Result<FetchResult<F, Op, D>, Error>
129where
130    F: Family,
131    D: Digest,
132    Fetch: FnOnce(Location<F>, Location<F>, NonZeroU64, bool) -> FetchFuture,
133    FetchFuture: Future<Output = Result<FetchedOperations<F, Op, D>, Error>>,
134{
135    let FetchedOperations {
136        proof,
137        operations,
138        pinned_nodes,
139    } = fetch(op_count, start_loc, max_ops, include_pinned_nodes).await?;
140    Ok(FetchResult::new(proof, operations, pinned_nodes))
141}
142
143/// Fetch an operation range from separate local-store callbacks and package it as a
144/// [`FetchResult`].
145///
146/// Use this for database APIs that expose `historical_proof` separately from
147/// `pinned_nodes_at`; pinned nodes are fetched only when `include_pinned_nodes` is true.
148pub async fn fetch_operations<
149    F,
150    Op,
151    D,
152    Error,
153    HistoricalProof,
154    HistoricalFuture,
155    Pins,
156    PinsFuture,
157>(
158    op_count: Location<F>,
159    start_loc: Location<F>,
160    max_ops: NonZeroU64,
161    include_pinned_nodes: bool,
162    historical_proof: HistoricalProof,
163    pinned_nodes_at: Pins,
164) -> Result<FetchResult<F, Op, D>, Error>
165where
166    F: Family,
167    D: Digest,
168    HistoricalProof: FnOnce(Location<F>, Location<F>, NonZeroU64) -> HistoricalFuture,
169    HistoricalFuture: Future<Output = Result<(Proof<F, D>, Vec<Op>), Error>>,
170    Pins: FnOnce(Location<F>) -> PinsFuture,
171    PinsFuture: Future<Output = Result<Vec<D>, Error>>,
172{
173    fetch_operation_range(
174        op_count,
175        start_loc,
176        max_ops,
177        include_pinned_nodes,
178        |op_count, start_loc, max_ops, include_pinned_nodes| async move {
179            let (proof, operations) = historical_proof(op_count, start_loc, max_ops).await?;
180            let pinned_nodes = if include_pinned_nodes {
181                Some(pinned_nodes_at(start_loc).await?)
182            } else {
183                None
184            };
185            Ok(FetchedOperations::new(proof, operations, pinned_nodes))
186        },
187    )
188    .await
189}
190
191/// Trait for network communication with the sync server.
192pub trait Resolver: Send + Sync + Clone + 'static {
193    /// The merkle family backing the resolver's proofs
194    type Family: Family;
195
196    /// The digest type used in proofs returned by the resolver
197    type Digest: Digest;
198
199    /// The type of operations returned by the resolver
200    type Op;
201
202    /// The error type returned by the resolver
203    type Error: std::error::Error + Send + 'static;
204
205    /// Get the operations starting at `start_loc` in the database, up to `max_ops` operations.
206    /// Returns the operations and a proof that they were present in the database when it had
207    /// `op_count` operations. If `include_pinned_nodes` is true, the result will include the
208    /// pinned merkle nodes at `start_loc`.
209    ///
210    /// The corresponding `cancel_tx` is dropped when the engine no longer needs this
211    /// request (e.g. due to a target update), causing `cancel_rx.await` to return
212    /// `Err`. Implementations may `select!` on it to abort in-flight work early.
213    #[allow(clippy::type_complexity)]
214    fn get_operations<'a>(
215        &'a self,
216        op_count: Location<Self::Family>,
217        start_loc: Location<Self::Family>,
218        max_ops: NonZeroU64,
219        include_pinned_nodes: bool,
220        cancel_rx: oneshot::Receiver<()>,
221    ) -> impl Future<Output = Result<FetchResult<Self::Family, Self::Op, Self::Digest>, Self::Error>>
222           + Send
223           + 'a;
224}
225
226macro_rules! impl_resolver {
227    ($db:ident, $op:ident, $val_bound:ident) => {
228        impl<F, E, K, V, H, T, S> Resolver for Arc<$db<F, E, K, V, H, T, S>>
229        where
230            F: Family,
231            E: Context,
232            K: Array,
233            V: $val_bound + Send + Sync + 'static,
234            H: Hasher,
235            T: Translator + Send + Sync + 'static,
236            T::Key: Send + Sync,
237            S: Strategy,
238        {
239            type Family = F;
240            type Digest = H::Digest;
241            type Op = $op<F, K, V>;
242            type Error = qmdb::Error<F>;
243
244            async fn get_operations(
245                &self,
246                op_count: Location<Self::Family>,
247                start_loc: Location<Self::Family>,
248                max_ops: NonZeroU64,
249                include_pinned_nodes: bool,
250                _cancel_rx: oneshot::Receiver<()>,
251            ) -> Result<FetchResult<Self::Family, Self::Op, Self::Digest>, Self::Error> {
252                fetch_operations(
253                    op_count,
254                    start_loc,
255                    max_ops,
256                    include_pinned_nodes,
257                    |op_count, start_loc, max_ops| {
258                        self.historical_proof(op_count, start_loc, max_ops)
259                    },
260                    |start_loc| self.pinned_nodes_at(start_loc),
261                )
262                .await
263            }
264        }
265        impl_resolver!(@locked $db, $op, $val_bound, AsyncRwLock);
266        impl_resolver!(@locked $db, $op, $val_bound, TracedAsyncRwLock);
267    };
268    (@locked $db:ident, $op:ident, $val_bound:ident, $lock:ident) => {
269
270        impl<F, E, K, V, H, T, S> Resolver for Arc<$lock<$db<F, E, K, V, H, T, S>>>
271        where
272            F: Family,
273            E: Context,
274            K: Array,
275            V: $val_bound + Send + Sync + 'static,
276            H: Hasher,
277            T: Translator + Send + Sync + 'static,
278            T::Key: Send + Sync,
279            S: Strategy,
280        {
281            type Family = F;
282            type Digest = H::Digest;
283            type Op = $op<F, K, V>;
284            type Error = qmdb::Error<F>;
285
286            async fn get_operations(
287                &self,
288                op_count: Location<Self::Family>,
289                start_loc: Location<Self::Family>,
290                max_ops: NonZeroU64,
291                include_pinned_nodes: bool,
292                _cancel_rx: oneshot::Receiver<()>,
293            ) -> Result<FetchResult<Self::Family, Self::Op, Self::Digest>, Self::Error> {
294                let db = self.read().await;
295                fetch_operations(
296                    op_count,
297                    start_loc,
298                    max_ops,
299                    include_pinned_nodes,
300                    |op_count, start_loc, max_ops| {
301                        db.historical_proof(op_count, start_loc, max_ops)
302                    },
303                    |start_loc| db.pinned_nodes_at(start_loc),
304                )
305                .await
306            }
307        }
308
309        impl<F, E, K, V, H, T, S> Resolver for Arc<$lock<Option<$db<F, E, K, V, H, T, S>>>>
310        where
311            F: Family,
312            E: Context,
313            K: Array,
314            V: $val_bound + Send + Sync + 'static,
315            H: Hasher,
316            T: Translator + Send + Sync + 'static,
317            T::Key: Send + Sync,
318            S: Strategy,
319        {
320            type Family = F;
321            type Digest = H::Digest;
322            type Op = $op<F, K, V>;
323            type Error = qmdb::Error<F>;
324
325            async fn get_operations(
326                &self,
327                op_count: Location<Self::Family>,
328                start_loc: Location<Self::Family>,
329                max_ops: NonZeroU64,
330                include_pinned_nodes: bool,
331                _cancel_rx: oneshot::Receiver<()>,
332            ) -> Result<FetchResult<Self::Family, Self::Op, Self::Digest>, Self::Error> {
333                let guard = self.read().await;
334                let db = guard.as_ref().ok_or(qmdb::Error::KeyNotFound)?;
335                fetch_operations(
336                    op_count,
337                    start_loc,
338                    max_ops,
339                    include_pinned_nodes,
340                    |op_count, start_loc, max_ops| {
341                        db.historical_proof(op_count, start_loc, max_ops)
342                    },
343                    |start_loc| db.pinned_nodes_at(start_loc),
344                )
345                .await
346            }
347        }
348    };
349}
350
351// Unordered Fixed
352impl_resolver!(FixedDb, FixedOperation, FixedValue);
353
354// Unordered Variable
355impl_resolver!(VariableDb, VariableOperation, VariableValue);
356
357// Ordered Fixed
358impl_resolver!(OrderedFixedDb, OrderedFixedOperation, FixedValue);
359
360// Ordered Variable
361impl_resolver!(OrderedVariableDb, OrderedVariableOperation, VariableValue);
362
363// Immutable types need a separate macro because the key bound varies
364// (Array for fixed, Key for variable) unlike the other DB types which
365// always use Array.
366macro_rules! impl_resolver_immutable {
367    ($db:ident, $op:ident, $val_bound:ident, $key_bound:path) => {
368        impl<F, E, K, V, H, T, S> Resolver for Arc<$db<F, E, K, V, H, T, S>>
369        where
370            F: Family,
371            E: Context,
372            K: $key_bound,
373            V: $val_bound + Send + Sync + 'static,
374            H: Hasher,
375            T: Translator + Send + Sync + 'static,
376            T::Key: Send + Sync,
377            S: Strategy,
378        {
379            type Family = F;
380            type Digest = H::Digest;
381            type Op = $op<F, K, V>;
382            type Error = qmdb::Error<F>;
383
384            async fn get_operations(
385                &self,
386                op_count: Location<Self::Family>,
387                start_loc: Location<Self::Family>,
388                max_ops: NonZeroU64,
389                include_pinned_nodes: bool,
390                _cancel_rx: oneshot::Receiver<()>,
391            ) -> Result<FetchResult<Self::Family, Self::Op, Self::Digest>, Self::Error> {
392                fetch_operations(
393                    op_count,
394                    start_loc,
395                    max_ops,
396                    include_pinned_nodes,
397                    |op_count, start_loc, max_ops| {
398                        self.historical_proof(op_count, start_loc, max_ops)
399                    },
400                    |start_loc| self.pinned_nodes_at(start_loc),
401                )
402                .await
403            }
404        }
405        impl_resolver_immutable!(@locked $db, $op, $val_bound, $key_bound, AsyncRwLock);
406        impl_resolver_immutable!(@locked $db, $op, $val_bound, $key_bound, TracedAsyncRwLock);
407    };
408    (@locked $db:ident, $op:ident, $val_bound:ident, $key_bound:path, $lock:ident) => {
409
410        impl<F, E, K, V, H, T, S> Resolver for Arc<$lock<$db<F, E, K, V, H, T, S>>>
411        where
412            F: Family,
413            E: Context,
414            K: $key_bound,
415            V: $val_bound + Send + Sync + 'static,
416            H: Hasher,
417            T: Translator + Send + Sync + 'static,
418            T::Key: Send + Sync,
419            S: Strategy,
420        {
421            type Family = F;
422            type Digest = H::Digest;
423            type Op = $op<F, K, V>;
424            type Error = qmdb::Error<F>;
425
426            async fn get_operations(
427                &self,
428                op_count: Location<Self::Family>,
429                start_loc: Location<Self::Family>,
430                max_ops: NonZeroU64,
431                include_pinned_nodes: bool,
432                _cancel_rx: oneshot::Receiver<()>,
433            ) -> Result<FetchResult<Self::Family, Self::Op, Self::Digest>, Self::Error> {
434                let db = self.read().await;
435                fetch_operations(
436                    op_count,
437                    start_loc,
438                    max_ops,
439                    include_pinned_nodes,
440                    |op_count, start_loc, max_ops| {
441                        db.historical_proof(op_count, start_loc, max_ops)
442                    },
443                    |start_loc| db.pinned_nodes_at(start_loc),
444                )
445                .await
446            }
447        }
448
449        impl<F, E, K, V, H, T, S> Resolver for Arc<$lock<Option<$db<F, E, K, V, H, T, S>>>>
450        where
451            F: Family,
452            E: Context,
453            K: $key_bound,
454            V: $val_bound + Send + Sync + 'static,
455            H: Hasher,
456            T: Translator + Send + Sync + 'static,
457            T::Key: Send + Sync,
458            S: Strategy,
459        {
460            type Family = F;
461            type Digest = H::Digest;
462            type Op = $op<F, K, V>;
463            type Error = qmdb::Error<F>;
464
465            async fn get_operations(
466                &self,
467                op_count: Location<Self::Family>,
468                start_loc: Location<Self::Family>,
469                max_ops: NonZeroU64,
470                include_pinned_nodes: bool,
471                _cancel_rx: oneshot::Receiver<()>,
472            ) -> Result<FetchResult<Self::Family, Self::Op, Self::Digest>, Self::Error> {
473                let guard = self.read().await;
474                let db = guard.as_ref().ok_or(qmdb::Error::KeyNotFound)?;
475                fetch_operations(
476                    op_count,
477                    start_loc,
478                    max_ops,
479                    include_pinned_nodes,
480                    |op_count, start_loc, max_ops| {
481                        db.historical_proof(op_count, start_loc, max_ops)
482                    },
483                    |start_loc| db.pinned_nodes_at(start_loc),
484                )
485                .await
486            }
487        }
488    };
489}
490
491// Immutable Fixed
492impl_resolver_immutable!(ImmutableFixedDb, ImmutableFixedOp, FixedValue, Array);
493
494// Immutable Variable
495impl_resolver_immutable!(ImmutableVariableDb, ImmutableVariableOp, VariableValue, Key);
496
497// Keyless types have no key or translator, so they need their own macro.
498macro_rules! impl_resolver_keyless {
499    ($db:ident, $op:ident, $val_bound:ident) => {
500        impl<F, E, V, H, S> Resolver for Arc<$db<F, E, V, H, S>>
501        where
502            F: Family,
503            E: Context,
504            V: $val_bound + Send + Sync + 'static,
505            H: Hasher,
506            S: Strategy,
507        {
508            type Family = F;
509            type Digest = H::Digest;
510            type Op = $op<F, V>;
511            type Error = qmdb::Error<F>;
512
513            async fn get_operations(
514                &self,
515                op_count: Location<Self::Family>,
516                start_loc: Location<Self::Family>,
517                max_ops: NonZeroU64,
518                include_pinned_nodes: bool,
519                _cancel_rx: oneshot::Receiver<()>,
520            ) -> Result<FetchResult<Self::Family, Self::Op, Self::Digest>, Self::Error> {
521                fetch_operations(
522                    op_count,
523                    start_loc,
524                    max_ops,
525                    include_pinned_nodes,
526                    |op_count, start_loc, max_ops| {
527                        self.historical_proof(op_count, start_loc, max_ops)
528                    },
529                    |start_loc| self.pinned_nodes_at(start_loc),
530                )
531                .await
532            }
533        }
534        impl_resolver_keyless!(@locked $db, $op, $val_bound, AsyncRwLock);
535        impl_resolver_keyless!(@locked $db, $op, $val_bound, TracedAsyncRwLock);
536    };
537    (@locked $db:ident, $op:ident, $val_bound:ident, $lock:ident) => {
538
539        impl<F, E, V, H, S> Resolver for Arc<$lock<$db<F, E, V, H, S>>>
540        where
541            F: Family,
542            E: Context,
543            V: $val_bound + Send + Sync + 'static,
544            H: Hasher,
545            S: Strategy,
546        {
547            type Family = F;
548            type Digest = H::Digest;
549            type Op = $op<F, V>;
550            type Error = qmdb::Error<F>;
551
552            async fn get_operations(
553                &self,
554                op_count: Location<Self::Family>,
555                start_loc: Location<Self::Family>,
556                max_ops: NonZeroU64,
557                include_pinned_nodes: bool,
558                _cancel_rx: oneshot::Receiver<()>,
559            ) -> Result<FetchResult<Self::Family, Self::Op, Self::Digest>, Self::Error> {
560                let db = self.read().await;
561                fetch_operations(
562                    op_count,
563                    start_loc,
564                    max_ops,
565                    include_pinned_nodes,
566                    |op_count, start_loc, max_ops| {
567                        db.historical_proof(op_count, start_loc, max_ops)
568                    },
569                    |start_loc| db.pinned_nodes_at(start_loc),
570                )
571                .await
572            }
573        }
574
575        impl<F, E, V, H, S> Resolver for Arc<$lock<Option<$db<F, E, V, H, S>>>>
576        where
577            F: Family,
578            E: Context,
579            V: $val_bound + Send + Sync + 'static,
580            H: Hasher,
581            S: Strategy,
582        {
583            type Family = F;
584            type Digest = H::Digest;
585            type Op = $op<F, V>;
586            type Error = qmdb::Error<F>;
587
588            async fn get_operations(
589                &self,
590                op_count: Location<Self::Family>,
591                start_loc: Location<Self::Family>,
592                max_ops: NonZeroU64,
593                include_pinned_nodes: bool,
594                _cancel_rx: oneshot::Receiver<()>,
595            ) -> Result<FetchResult<Self::Family, Self::Op, Self::Digest>, Self::Error> {
596                let guard = self.read().await;
597                let db = guard.as_ref().ok_or(qmdb::Error::KeyNotFound)?;
598                fetch_operations(
599                    op_count,
600                    start_loc,
601                    max_ops,
602                    include_pinned_nodes,
603                    |op_count, start_loc, max_ops| {
604                        db.historical_proof(op_count, start_loc, max_ops)
605                    },
606                    |start_loc| db.pinned_nodes_at(start_loc),
607                )
608                .await
609            }
610        }
611    };
612}
613
614// Keyless Fixed
615impl_resolver_keyless!(KeylessFixedDb, KeylessFixedOp, FixedValue);
616
617// Keyless Variable
618impl_resolver_keyless!(KeylessVariableDb, KeylessVariableOp, VariableValue);
619
620#[cfg(test)]
621pub(crate) mod tests {
622    use super::*;
623    use crate::{
624        merkle::mmr,
625        translator::{OneCap, TwoCap},
626    };
627    use commonware_cryptography::{sha256::Digest as ShaDigest, Sha256};
628    use commonware_parallel::Rayon;
629    use commonware_runtime::deterministic;
630    use commonware_utils::sync::AsyncRwLock;
631    use std::{marker::PhantomData, sync::Arc};
632
633    macro_rules! assert_resolver_variants {
634        ($db:ty) => {
635            assert_resolver::<Arc<$db>>();
636            assert_resolver::<Arc<AsyncRwLock<$db>>>();
637            assert_resolver::<Arc<AsyncRwLock<Option<$db>>>>();
638        };
639    }
640
641    fn assert_resolver<R: Resolver>() {}
642
643    fn empty_proof() -> Proof<mmr::Family, ShaDigest> {
644        Proof {
645            leaves: Location::new(0),
646            inactive_peaks: 0,
647            digests: vec![],
648        }
649    }
650
651    #[test]
652    fn test_fetch_result_new_has_no_success_acknowledgement() {
653        let result = FetchResult::<mmr::Family, (), ShaDigest>::new(empty_proof(), vec![], None);
654        assert!(result.callback.is_none());
655    }
656
657    #[test]
658    fn test_fetch_result_with_callback_reports_to_external_receiver() {
659        let (success_tx, mut success_rx) = oneshot::channel();
660        let result = FetchResult::<mmr::Family, (), ShaDigest>::with_callback(
661            empty_proof(),
662            vec![],
663            None,
664            success_tx,
665        );
666        assert!(result.callback.expect("success sender").send(true).is_ok());
667        assert_eq!(success_rx.try_recv(), Ok(true));
668    }
669
670    /// A resolver that always fails.
671    #[derive(Clone)]
672    pub struct FailResolver<F: Family, Op, D> {
673        _phantom: PhantomData<(F, Op, D)>,
674    }
675
676    impl<F, Op, D> Resolver for FailResolver<F, Op, D>
677    where
678        F: Family,
679        D: Digest,
680        Op: Send + Sync + Clone + 'static,
681    {
682        type Family = F;
683        type Digest = D;
684        type Op = Op;
685        type Error = qmdb::Error<F>;
686
687        async fn get_operations(
688            &self,
689            _op_count: Location<F>,
690            _start_loc: Location<F>,
691            _max_ops: NonZeroU64,
692            _include_pinned_nodes: bool,
693            _cancel: oneshot::Receiver<()>,
694        ) -> Result<FetchResult<F, Op, D>, qmdb::Error<F>> {
695            Err(qmdb::Error::KeyNotFound) // Arbitrary dummy error
696        }
697    }
698
699    impl<F: Family, Op, D> FailResolver<F, Op, D> {
700        pub fn new() -> Self {
701            Self {
702                _phantom: PhantomData,
703            }
704        }
705    }
706
707    #[test]
708    fn test_all_qmdb_variants_implement_strategy_resolvers() {
709        type AnyOrderedFixed = crate::qmdb::any::ordered::fixed::Db<
710            mmr::Family,
711            deterministic::Context,
712            ShaDigest,
713            ShaDigest,
714            Sha256,
715            OneCap,
716            Rayon,
717        >;
718        type AnyOrderedVariable = crate::qmdb::any::ordered::variable::Db<
719            mmr::Family,
720            deterministic::Context,
721            ShaDigest,
722            Vec<u8>,
723            Sha256,
724            OneCap,
725            Rayon,
726        >;
727        type AnyUnorderedFixed = crate::qmdb::any::unordered::fixed::Db<
728            mmr::Family,
729            deterministic::Context,
730            ShaDigest,
731            ShaDigest,
732            Sha256,
733            TwoCap,
734            Rayon,
735        >;
736        type AnyUnorderedVariable = crate::qmdb::any::unordered::variable::Db<
737            mmr::Family,
738            deterministic::Context,
739            ShaDigest,
740            Vec<u8>,
741            Sha256,
742            TwoCap,
743            Rayon,
744        >;
745        type CurrentOrderedFixed = crate::qmdb::current::ordered::fixed::Db<
746            mmr::Family,
747            deterministic::Context,
748            ShaDigest,
749            ShaDigest,
750            Sha256,
751            OneCap,
752            32,
753            Rayon,
754        >;
755        type CurrentOrderedVariable = crate::qmdb::current::ordered::variable::Db<
756            mmr::Family,
757            deterministic::Context,
758            ShaDigest,
759            Vec<u8>,
760            Sha256,
761            OneCap,
762            32,
763            Rayon,
764        >;
765        type CurrentUnorderedFixed = crate::qmdb::current::unordered::fixed::Db<
766            mmr::Family,
767            deterministic::Context,
768            ShaDigest,
769            ShaDigest,
770            Sha256,
771            TwoCap,
772            32,
773            Rayon,
774        >;
775        type CurrentUnorderedVariable = crate::qmdb::current::unordered::variable::Db<
776            mmr::Family,
777            deterministic::Context,
778            ShaDigest,
779            Vec<u8>,
780            Sha256,
781            TwoCap,
782            32,
783            Rayon,
784        >;
785        type ImmutableFixed = crate::qmdb::immutable::fixed::Db<
786            mmr::Family,
787            deterministic::Context,
788            ShaDigest,
789            ShaDigest,
790            Sha256,
791            TwoCap,
792            Rayon,
793        >;
794        type ImmutableVariable = crate::qmdb::immutable::variable::Db<
795            mmr::Family,
796            deterministic::Context,
797            ShaDigest,
798            Vec<u8>,
799            Sha256,
800            TwoCap,
801            Rayon,
802        >;
803        type KeylessFixed = crate::qmdb::keyless::fixed::Db<
804            mmr::Family,
805            deterministic::Context,
806            ShaDigest,
807            Sha256,
808            Rayon,
809        >;
810        type KeylessVariable = crate::qmdb::keyless::variable::Db<
811            mmr::Family,
812            deterministic::Context,
813            Vec<u8>,
814            Sha256,
815            Rayon,
816        >;
817
818        assert_resolver_variants!(AnyOrderedFixed);
819        assert_resolver_variants!(AnyOrderedVariable);
820        assert_resolver_variants!(AnyUnorderedFixed);
821        assert_resolver_variants!(AnyUnorderedVariable);
822        assert_resolver_variants!(CurrentOrderedFixed);
823        assert_resolver_variants!(CurrentOrderedVariable);
824        assert_resolver_variants!(CurrentUnorderedFixed);
825        assert_resolver_variants!(CurrentUnorderedVariable);
826        assert_resolver_variants!(ImmutableFixed);
827        assert_resolver_variants!(ImmutableVariable);
828        assert_resolver_variants!(KeylessFixed);
829        assert_resolver_variants!(KeylessVariable);
830    }
831}