miden_node_store/db/models/
conv.rs1#![expect(
18 clippy::inline_always,
19 reason = "Just unification helpers of 1-2 lines of casting types"
20)]
21#![expect(
22 dead_code,
23 reason = "Not all converters are used bidirectionally, however, keeping them is a good thing"
24)]
25#![expect(
26 clippy::cast_sign_loss,
27 reason = "This is the one file where we map the signed database types to the working types"
28)]
29#![expect(
30 clippy::cast_possible_wrap,
31 reason = "We will not approach the item count where i64 and usize casting will cause issues
32 on relevant platforms"
33)]
34
35use miden_crypto::Word;
36use miden_crypto::utils::Deserializable;
37use miden_protocol::Felt;
38use miden_protocol::account::{StorageSlotName, StorageSlotType};
39use miden_protocol::block::{BlockHeader, BlockNumber};
40use miden_protocol::note::NoteTag;
41
42use crate::db::models::queries::{BlockHeaderCommitment, NetworkAccountType};
43
44#[derive(Debug, thiserror::Error)]
45#[error("failed to convert from database type {from_type} into {into_type}")]
46pub struct DatabaseTypeConversionError {
47 source: Box<dyn std::error::Error + Send + Sync>,
48 from_type: &'static str,
49 into_type: &'static str,
50}
51
52pub trait SqlTypeConvert: Sized {
56 type Raw: Sized;
57
58 fn to_raw_sql(self) -> Self::Raw;
59 fn from_raw_sql(_raw: Self::Raw) -> Result<Self, DatabaseTypeConversionError>;
60
61 fn map_err<E: std::error::Error + Send + Sync + 'static>(
62 source: E,
63 ) -> DatabaseTypeConversionError {
64 DatabaseTypeConversionError {
65 source: Box::new(source),
66 from_type: std::any::type_name::<Self::Raw>(),
67 into_type: std::any::type_name::<Self>(),
68 }
69 }
70}
71
72impl SqlTypeConvert for BlockHeaderCommitment {
73 type Raw = Vec<u8>;
74 fn from_raw_sql(
75 raw: Self::Raw,
76 ) -> Result<Self, crate::db::models::conv::DatabaseTypeConversionError> {
77 let inner =
78 <Word as Deserializable>::read_from_bytes(raw.as_slice()).map_err(Self::map_err)?;
79 Ok(BlockHeaderCommitment(inner))
80 }
81 fn to_raw_sql(self) -> Self::Raw {
82 self.0.as_bytes().to_vec()
83 }
84}
85
86impl SqlTypeConvert for BlockHeader {
87 type Raw = Vec<u8>;
88
89 fn from_raw_sql(raw: Self::Raw) -> Result<Self, DatabaseTypeConversionError> {
90 <Self as Deserializable>::read_from_bytes(raw.as_slice()).map_err(Self::map_err)
91 }
92
93 fn to_raw_sql(self) -> Self::Raw {
94 miden_crypto::utils::Serializable::to_bytes(&self)
95 }
96}
97
98impl SqlTypeConvert for NetworkAccountType {
99 type Raw = i32;
100
101 fn to_raw_sql(self) -> Self::Raw {
102 match self {
103 NetworkAccountType::None => 0,
104 NetworkAccountType::Network => 1,
105 }
106 }
107
108 fn from_raw_sql(raw: Self::Raw) -> Result<Self, DatabaseTypeConversionError> {
109 #[derive(Debug, thiserror::Error)]
110 #[error("invalid network account type value {0}")]
111 struct ValueError(i32);
112
113 match raw {
114 0 => Ok(Self::None),
115 1 => Ok(Self::Network),
116 other => Err(Self::map_err(ValueError(other))),
117 }
118 }
119}
120
121impl SqlTypeConvert for BlockNumber {
122 type Raw = i64;
123
124 fn from_raw_sql(raw: Self::Raw) -> Result<Self, DatabaseTypeConversionError> {
125 u32::try_from(raw).map(BlockNumber::from).map_err(Self::map_err)
126 }
127
128 fn to_raw_sql(self) -> Self::Raw {
129 i64::from(self.as_u32())
130 }
131}
132
133impl SqlTypeConvert for NoteTag {
134 type Raw = i32;
135
136 #[inline(always)]
137 fn from_raw_sql(raw: Self::Raw) -> Result<Self, DatabaseTypeConversionError> {
138 #[expect(clippy::cast_sign_loss)]
139 Ok(NoteTag::new(raw as u32))
140 }
141
142 #[inline(always)]
143 fn to_raw_sql(self) -> Self::Raw {
144 self.as_u32() as i32
145 }
146}
147
148impl SqlTypeConvert for StorageSlotType {
149 type Raw = i32;
150
151 #[inline(always)]
152 fn from_raw_sql(raw: Self::Raw) -> Result<Self, DatabaseTypeConversionError> {
153 #[derive(Debug, thiserror::Error)]
154 #[error("invalid storage slot type value {0}")]
155 struct ValueError(i32);
156
157 Ok(match raw {
158 0 => StorageSlotType::Value,
159 1 => StorageSlotType::Map,
160 invalid => {
161 return Err(Self::map_err(ValueError(invalid)));
162 },
163 })
164 }
165
166 #[inline(always)]
167 fn to_raw_sql(self) -> Self::Raw {
168 match self {
169 StorageSlotType::Value => 0,
170 StorageSlotType::Map => 1,
171 }
172 }
173}
174
175impl SqlTypeConvert for StorageSlotName {
176 type Raw = String;
177
178 fn from_raw_sql(raw: Self::Raw) -> Result<Self, DatabaseTypeConversionError> {
179 StorageSlotName::new(raw).map_err(Self::map_err)
180 }
181
182 fn to_raw_sql(self) -> Self::Raw {
183 String::from(self)
184 }
185}
186
187#[inline(always)]
191pub(crate) fn raw_sql_to_nullifier_prefix(raw: i32) -> u16 {
192 debug_assert!(raw >= 0);
193 raw as u16
194}
195#[inline(always)]
196pub(crate) fn nullifier_prefix_to_raw_sql(prefix: u16) -> i32 {
197 i32::from(prefix)
198}
199
200#[inline(always)]
201pub(crate) fn raw_sql_to_nonce(raw: i64) -> Felt {
202 debug_assert!(raw >= 0);
203 Felt::new_unchecked(raw as u64)
208}
209#[inline(always)]
210pub(crate) fn nonce_to_raw_sql(nonce: Felt) -> i64 {
211 nonce.as_canonical_u64() as i64
212}
213
214#[inline(always)]
215pub(crate) fn raw_sql_to_fungible_delta(raw: i64) -> i64 {
216 raw
217}
218#[inline(always)]
219pub(crate) fn fungible_delta_to_raw_sql(delta: i64) -> i64 {
220 delta
221}
222
223#[inline(always)]
224#[expect(clippy::cast_sign_loss)]
225pub(crate) fn raw_sql_to_note_type(raw: i32) -> u8 {
226 raw as u8
227}
228#[inline(always)]
229pub(crate) fn note_type_to_raw_sql(note_type: u8) -> i32 {
230 i32::from(note_type)
231}
232
233#[inline(always)]
234pub(crate) fn raw_sql_to_idx(raw: i32) -> usize {
235 raw as usize
236}
237#[inline(always)]
238pub(crate) fn idx_to_raw_sql(idx: usize) -> i32 {
239 idx as i32
240}