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}