cometbft_light_client/
store.rs

1//! Interface and implementations of the light block store.
2//!
3//! See the `memory` and `sled` modules for:
4//!
5//! - a transient, in-memory implementation for testing purposes
6//! - a persistent, on-disk, sled-backed implementation for production
7
8use std::fmt::Debug;
9
10use crate::{
11    utils::std_ext,
12    verifier::types::{Height, LightBlock, Status},
13};
14
15pub mod memory;
16
17#[cfg(feature = "lightstore-sled")]
18#[cfg_attr(docsrs, doc(cfg(feature = "lightstore-sled")))]
19pub mod sled;
20
21/// Store for light blocks.
22///
23/// The light store records light blocks received from peers, and their verification status.
24/// Additionally, the light store will contain one or more trusted light blocks specified
25/// at initialization time.
26///
27/// ## Implements
28/// - [LCV-DIST-STORE.1]
29pub trait LightStore: Debug + Send + Sync {
30    /// Get the light block at the given height with the given status, or return `None` otherwise.
31    fn get(&self, height: Height, status: Status) -> Option<LightBlock>;
32
33    /// Update the `status` of the given `light_block`.
34    fn update(&mut self, light_block: &LightBlock, status: Status);
35
36    /// Insert a new light block in the store with the given status.
37    /// Overrides any other block with the same height and status.
38    fn insert(&mut self, light_block: LightBlock, status: Status);
39
40    /// Remove the light block with the given height and status, if any.
41    fn remove(&mut self, height: Height, status: Status);
42
43    /// Get the light block of greatest height with the given status.
44    fn highest(&self, status: Status) -> Option<LightBlock>;
45
46    /// Get the light block of greatest height before the given height with the given status.
47    fn highest_before(&self, height: Height, status: Status) -> Option<LightBlock>;
48
49    /// Get the light block of lowest height with the given status.
50    fn lowest(&self, status: Status) -> Option<LightBlock>;
51
52    /// Get an iterator of all light blocks with the given status.
53    fn all(&self, status: Status) -> Box<dyn Iterator<Item = LightBlock>>;
54
55    /// Get a block at a given height whatever its verification status as long as it hasn't failed
56    /// verification (ie. its status is not `Status::Failed`).
57    fn get_non_failed(&self, height: Height) -> Option<(LightBlock, Status)> {
58        None.or_else(|| {
59            self.get(height, Status::Trusted)
60                .map(|lb| (lb, Status::Trusted))
61        })
62        .or_else(|| {
63            self.get(height, Status::Verified)
64                .map(|lb| (lb, Status::Verified))
65        })
66        .or_else(|| {
67            self.get(height, Status::Unverified)
68                .map(|lb| (lb, Status::Unverified))
69        })
70    }
71
72    /// Get the light block of greatest height with the trusted or verified status.
73    fn highest_trusted_or_verified(&self) -> Option<LightBlock> {
74        let latest_trusted = self.highest(Status::Trusted);
75        let latest_verified = self.highest(Status::Verified);
76
77        std_ext::option::select(latest_trusted, latest_verified, |t, v| {
78            std_ext::cmp::max_by_key(t, v, |lb| lb.height())
79        })
80    }
81
82    /// Get the first light block before the given height with the trusted or verified status.
83    fn highest_trusted_or_verified_before(&self, height: Height) -> Option<LightBlock> {
84        let highest_trusted = self.highest_before(height, Status::Trusted);
85        let highest_verified = self.highest_before(height, Status::Verified);
86
87        std_ext::option::select(highest_trusted, highest_verified, |t, v| {
88            std_ext::cmp::max_by_key(t, v, |lb| lb.height())
89        })
90    }
91
92    /// Get the light block of lowest height with the trusted or verified status.
93    fn lowest_trusted_or_verified(&self) -> Option<LightBlock> {
94        let lowest_trusted = self.lowest(Status::Trusted);
95        let lowest_verified = self.lowest(Status::Verified);
96
97        std_ext::option::select(lowest_trusted, lowest_verified, |t, v| {
98            std_ext::cmp::min_by_key(t, v, |lb| lb.height())
99        })
100    }
101
102    /// Get the light block of the given height with the trusted or verified status.
103    fn get_trusted_or_verified(&self, height: Height) -> Option<LightBlock> {
104        self.get(height, Status::Trusted)
105            .or_else(|| self.get(height, Status::Verified))
106    }
107}