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::BlockHeaderCommitment;
43use crate::db::models::queries::NetworkAccountType;
44
45#[derive(Debug, thiserror::Error)]
46#[error("failed to convert from database type {from_type} into {into_type}")]
47pub struct DatabaseTypeConversionError {
48 source: Box<dyn std::error::Error + Send + Sync>,
49 from_type: &'static str,
50 into_type: &'static str,
51}
52
53pub trait SqlTypeConvert: Sized {
57 type Raw: Sized;
58
59 fn to_raw_sql(self) -> Self::Raw;
60 fn from_raw_sql(_raw: Self::Raw) -> Result<Self, DatabaseTypeConversionError>;
61
62 fn map_err<E: std::error::Error + Send + Sync + 'static>(
63 source: E,
64 ) -> DatabaseTypeConversionError {
65 DatabaseTypeConversionError {
66 source: Box::new(source),
67 from_type: std::any::type_name::<Self::Raw>(),
68 into_type: std::any::type_name::<Self>(),
69 }
70 }
71}
72
73impl SqlTypeConvert for BlockHeaderCommitment {
74 type Raw = Vec<u8>;
75 fn from_raw_sql(
76 raw: Self::Raw,
77 ) -> Result<Self, crate::db::models::conv::DatabaseTypeConversionError> {
78 let inner =
79 <Word as Deserializable>::read_from_bytes(raw.as_slice()).map_err(Self::map_err)?;
80 Ok(BlockHeaderCommitment(inner))
81 }
82 fn to_raw_sql(self) -> Self::Raw {
83 self.0.as_bytes().to_vec()
84 }
85}
86
87impl SqlTypeConvert for BlockHeader {
88 type Raw = Vec<u8>;
89
90 fn from_raw_sql(raw: Self::Raw) -> Result<Self, DatabaseTypeConversionError> {
91 miden_node_persistence::decode(raw.as_slice()).map_err(Self::map_err)
92 }
93
94 fn to_raw_sql(self) -> Self::Raw {
95 miden_node_persistence::encode(&self)
96 }
97}
98
99impl SqlTypeConvert for NetworkAccountType {
100 type Raw = i32;
101
102 fn to_raw_sql(self) -> Self::Raw {
103 match self {
104 NetworkAccountType::None => 0,
105 NetworkAccountType::Network => 1,
106 }
107 }
108
109 fn from_raw_sql(raw: Self::Raw) -> Result<Self, DatabaseTypeConversionError> {
110 #[derive(Debug, thiserror::Error)]
111 #[error("invalid network account type value {0}")]
112 struct ValueError(i32);
113
114 match raw {
115 0 => Ok(Self::None),
116 1 => Ok(Self::Network),
117 other => Err(Self::map_err(ValueError(other))),
118 }
119 }
120}
121
122impl SqlTypeConvert for BlockNumber {
123 type Raw = i64;
124
125 fn from_raw_sql(raw: Self::Raw) -> Result<Self, DatabaseTypeConversionError> {
126 u32::try_from(raw).map(BlockNumber::from).map_err(Self::map_err)
127 }
128
129 fn to_raw_sql(self) -> Self::Raw {
130 i64::from(self.as_u32())
131 }
132}
133
134impl SqlTypeConvert for NoteTag {
135 type Raw = i32;
136
137 #[inline(always)]
138 fn from_raw_sql(raw: Self::Raw) -> Result<Self, DatabaseTypeConversionError> {
139 #[expect(clippy::cast_sign_loss)]
140 Ok(NoteTag::new(raw as u32))
141 }
142
143 #[inline(always)]
144 fn to_raw_sql(self) -> Self::Raw {
145 self.as_u32() as i32
146 }
147}
148
149impl SqlTypeConvert for StorageSlotType {
150 type Raw = i32;
151
152 #[inline(always)]
153 fn from_raw_sql(raw: Self::Raw) -> Result<Self, DatabaseTypeConversionError> {
154 #[derive(Debug, thiserror::Error)]
155 #[error("invalid storage slot type value {0}")]
156 struct ValueError(i32);
157
158 Ok(match raw {
159 0 => StorageSlotType::Value,
160 1 => StorageSlotType::Map,
161 invalid => {
162 return Err(Self::map_err(ValueError(invalid)));
163 },
164 })
165 }
166
167 #[inline(always)]
168 fn to_raw_sql(self) -> Self::Raw {
169 match self {
170 StorageSlotType::Value => 0,
171 StorageSlotType::Map => 1,
172 }
173 }
174}
175
176impl SqlTypeConvert for StorageSlotName {
177 type Raw = String;
178
179 fn from_raw_sql(raw: Self::Raw) -> Result<Self, DatabaseTypeConversionError> {
180 StorageSlotName::new(raw).map_err(Self::map_err)
181 }
182
183 fn to_raw_sql(self) -> Self::Raw {
184 String::from(self)
185 }
186}
187
188#[inline(always)]
192pub(crate) fn raw_sql_to_nullifier_prefix(raw: i32) -> u16 {
193 debug_assert!(raw >= 0);
194 raw as u16
195}
196#[inline(always)]
197pub(crate) fn nullifier_prefix_to_raw_sql(prefix: u16) -> i32 {
198 i32::from(prefix)
199}
200
201#[inline(always)]
202pub(crate) fn raw_sql_to_nonce(raw: i64) -> Felt {
203 debug_assert!(raw >= 0);
204 Felt::new_unchecked(raw as u64)
209}
210#[inline(always)]
211pub(crate) fn nonce_to_raw_sql(nonce: Felt) -> i64 {
212 nonce.as_canonical_u64() as i64
213}
214
215#[inline(always)]
216pub(crate) fn raw_sql_to_fungible_delta(raw: i64) -> i64 {
217 raw
218}
219#[inline(always)]
220pub(crate) fn fungible_delta_to_raw_sql(delta: i64) -> i64 {
221 delta
222}
223
224#[inline(always)]
225#[expect(clippy::cast_sign_loss)]
226pub(crate) fn raw_sql_to_note_type(raw: i32) -> u8 {
227 raw as u8
228}
229#[inline(always)]
230pub(crate) fn note_type_to_raw_sql(note_type: u8) -> i32 {
231 i32::from(note_type)
232}
233
234#[inline(always)]
235pub(crate) fn raw_sql_to_idx(raw: i32) -> usize {
236 raw as usize
237}
238#[inline(always)]
239pub(crate) fn idx_to_raw_sql(idx: usize) -> i32 {
240 idx as i32
241}