delta_domain_sdk/views/
verifiables.rs

1use domain_runtime::{
2    ports::DbQueriesPort,
3    sdls::types::{
4        SdlProofInput,
5        SdlState,
6        VerifiableStatus,
7    },
8    storage::{
9        PendingVerifiablesColumnFamily,
10        SdlProofInputColumnFamily,
11        SdlStateColumnFamily,
12        VerifiableToSdlColumnFamily,
13    },
14};
15use snafu::{
16    ResultExt,
17    Snafu,
18};
19use storage::{
20    column_family::StorageQuery,
21    database::StorageError,
22};
23use verifiable::types::{
24    VerifiableId,
25    VerifiableWithDiffs,
26};
27
28/// Errors occurring in the [Verifiables] helper
29#[derive(Debug, Snafu)]
30pub enum Error {
31    /// Error when reading from storage
32    #[snafu(display("Error while reading from storage: {source}"))]
33    Storage {
34        /// The underlying storage error
35        source: StorageError,
36    },
37}
38
39/// Helper to access verifiable status and data
40#[derive(Debug, Clone)]
41pub struct Verifiables<Db> {
42    db: Db,
43}
44
45impl<Db> Verifiables<Db> {
46    pub(crate) const fn new(db: Db) -> Self {
47        Self { db }
48    }
49}
50
51impl<Db> Verifiables<Db>
52where
53    Db: DbQueriesPort,
54{
55    /// Get a verifiable by its ID, searching both SDL index and pending queue.
56    ///
57    /// # Eventually Consistent
58    ///
59    /// During transitions from pending to SDL (3 separate writes: clear pending, write
60    /// proof input, write index), reads may briefly observe intermediate states where
61    /// the verifiable appears not to exist.
62    ///
63    /// # Parameters
64    ///
65    /// * `verifiable_id` - The ID of the verifiable to query
66    ///
67    /// # Returns
68    ///
69    /// * `Ok(Some(verifiable))` - Verifiable was found
70    /// * `Ok(None)` - Verifiable was not found (not pending, not in SDL, or already finalized)
71    /// * `Err(error)` - Query failed
72    pub fn get(&self, verifiable_id: &VerifiableId) -> Result<Option<VerifiableWithDiffs>, Error> {
73        // First check index
74        if let Some(sdl_id) =
75            StorageQuery::<VerifiableToSdlColumnFamily>::get_value(&self.db, verifiable_id)
76                .context(StorageSnafu)?
77        {
78            // Get proof input to find the verifiable
79            let proof_input: Option<SdlProofInput> =
80                StorageQuery::<SdlProofInputColumnFamily>::get_value(&self.db, &sdl_id)
81                    .context(StorageSnafu)?;
82
83            // Find the verifiable in the SDL's proof input
84            return Ok(proof_input.and_then(|proof_input| {
85                proof_input
86                    .verifiables
87                    .into_iter()
88                    .find(|v| v.verifiable.verifiable_id() == *verifiable_id)
89            }));
90        }
91
92        // Fall back to pending verifiables
93        self.find_pending(verifiable_id)
94    }
95
96    /// Get the status of a verifiable without loading the full data.
97    ///
98    /// # Eventually Consistent
99    ///
100    /// During transitions from pending to SDL (3 separate writes: clear pending, write
101    /// proof input, write index), reads may briefly observe intermediate states where
102    /// the verifiable appears not to exist.
103    ///
104    /// # Parameters
105    ///
106    /// * `verifiable_id` - The ID of the verifiable to query
107    ///
108    /// # Returns
109    ///
110    /// * `Ok(Some(status))` - Verifiable status if found
111    /// * `Ok(None)` - Verifiable was not found
112    /// * `Err(error)` - Query failed
113    pub fn get_status(
114        &self,
115        verifiable_id: &VerifiableId,
116    ) -> Result<Option<VerifiableStatus>, Error> {
117        // First check index
118        if let Some(sdl_id) =
119            StorageQuery::<VerifiableToSdlColumnFamily>::get_value(&self.db, verifiable_id)
120                .context(StorageSnafu)?
121        {
122            // Get just the SDL state, no need to fetch the full proof input
123            let sdl_state: Option<SdlState> =
124                StorageQuery::<SdlStateColumnFamily>::get_value(&self.db, &sdl_id)
125                    .context(StorageSnafu)?;
126
127            return Ok(Some(VerifiableStatus::InSdl {
128                sdl_id,
129                sdl_state: sdl_state.unwrap_or(SdlState::Submitted),
130            }));
131        }
132
133        // Fall back to pending verifiables
134        Ok(self
135            .find_pending(verifiable_id)?
136            .map(|_| VerifiableStatus::Pending))
137    }
138
139    /// Helper to find a verifiable in the pending queue by its ID.
140    ///
141    /// # Returns
142    ///
143    /// * `Ok(Some(verifiable))` - Found in pending queue
144    /// * `Ok(None)` - Not in pending queue
145    /// * `Err(error)` - Storage error during search
146    fn find_pending(
147        &self,
148        verifiable_id: &VerifiableId,
149    ) -> Result<Option<VerifiableWithDiffs>, Error> {
150        StorageQuery::<PendingVerifiablesColumnFamily>::iter(&self.db)
151            .find(|r| {
152                r.as_ref()
153                    .is_ok_and(|(_, v)| v.verifiable.verifiable_id() == *verifiable_id)
154                    || r.is_err()
155            })
156            .map(|result| result.map(|(_, v)| v))
157            .transpose()
158            .context(StorageSnafu)
159    }
160}