From 3e99e71dbdb25a76e4972da215b703a92e277d03 Mon Sep 17 00:00:00 2001 From: Mr-kay-cloud2 Date: Sun, 24 May 2026 15:29:16 +0100 Subject: [PATCH 1/3] refactor(store): add sql conversions for db binary types --- CHANGELOG.md | 1 + crates/store/src/db/models/conv.rs | 106 +++++++++++++++++++++++++++-- 2 files changed, 103 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f7ab38e17c..c928e77ffb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,6 +34,7 @@ - [BREAKING] Renamed `SubmitProvenBatch` RPC endpoint to `SubmitProvenTxBatch` ([#2094](https://github.com/0xMiden/node/pull/2094)). - Fixed block producer mempool panic when selecting transactions that depend on notes created by pruned committed transactions ([#2097](https://github.com/0xMiden/node/pull/2097)). - Implemented filtering based on the network account note script root allowlist in ntx-builder ([#2042](https://github.com/0xMiden/node/issues/2042)). +- Added SQL conversion trait coverage for common store database binary types ([#1477](https://github.com/0xMiden/node/issues/1477)). - [BREAKING] Renamed `ExplorerStatusDetails` fields in the network monitor's `/status` payload from `number_of_*` to `total_*` (`total_transactions`, `total_nullifiers`, `total_notes`, `total_account_updates`). The values now represent network-wide cumulative totals from the explorer's `overviewStats` query instead of last-block counts. - [BREAKING] Removed `--wallet-filepath` / `--counter-filepath` flags and the `MIDEN_MONITOR_WALLET_FILEPATH` / `MIDEN_MONITOR_COUNTER_FILEPATH` env vars from the network monitor. The monitor now keeps wallet and counter accounts fully in memory and regenerates them on every startup; the dashboard's counter value resets to zero on restart. diff --git a/crates/store/src/db/models/conv.rs b/crates/store/src/db/models/conv.rs index 25b6047f9e..c312a7ada9 100644 --- a/crates/store/src/db/models/conv.rs +++ b/crates/store/src/db/models/conv.rs @@ -33,11 +33,30 @@ )] use miden_crypto::Word; -use miden_crypto::utils::Deserializable; +use miden_crypto::utils::{Deserializable, Serializable}; use miden_protocol::Felt; -use miden_protocol::account::{StorageSlotName, StorageSlotType}; +use miden_protocol::account::{ + AccountCode, + AccountId, + AccountStorageHeader, + StorageMapKey, + StorageSlotName, + StorageSlotType, +}; +use miden_protocol::asset::{Asset, FungibleAsset}; use miden_protocol::block::{BlockHeader, BlockNumber}; -use miden_protocol::note::NoteTag; +use miden_protocol::crypto::merkle::SparseMerklePath; +use miden_protocol::note::{ + NoteAssets, + NoteAttachments, + NoteId, + NoteMetadata, + NoteScript, + NoteStorage, + NoteTag, + Nullifier, +}; +use miden_protocol::transaction::TransactionId; use crate::db::models::queries::{BlockHeaderCommitment, NetworkAccountType}; @@ -91,10 +110,47 @@ impl SqlTypeConvert for BlockHeader { } fn to_raw_sql(self) -> Self::Raw { - miden_crypto::utils::Serializable::to_bytes(&self) + Serializable::to_bytes(&self) } } +macro_rules! impl_binary_sql_convert { + ($($ty:ty),+ $(,)?) => { + $( + impl SqlTypeConvert for $ty { + type Raw = Vec; + + fn from_raw_sql(raw: Self::Raw) -> Result { + ::read_from_bytes(raw.as_slice()).map_err(Self::map_err) + } + + fn to_raw_sql(self) -> Self::Raw { + Serializable::to_bytes(&self) + } + } + )+ + }; +} + +impl_binary_sql_convert!( + AccountCode, + AccountId, + AccountStorageHeader, + Asset, + FungibleAsset, + NoteAssets, + NoteAttachments, + NoteId, + NoteMetadata, + NoteScript, + NoteStorage, + Nullifier, + SparseMerklePath, + StorageMapKey, + TransactionId, + Word, +); + impl SqlTypeConvert for NetworkAccountType { type Raw = i32; @@ -234,3 +290,45 @@ pub(crate) fn raw_sql_to_idx(raw: i32) -> usize { pub(crate) fn idx_to_raw_sql(idx: usize) -> i32 { idx as i32 } + +#[cfg(test)] +mod tests { + use std::fmt::Debug; + + use miden_protocol::account::AccountStorageHeader; + use miden_protocol::asset::FungibleAsset; + use miden_protocol::testing::account_id::{ + ACCOUNT_ID_PRIVATE_SENDER, + ACCOUNT_ID_PUBLIC_FUNGIBLE_FAUCET, + }; + + use super::*; + + fn assert_sql_roundtrip(value: T) + where + T: SqlTypeConvert> + Clone + Debug + PartialEq, + { + let raw = value.clone().to_raw_sql(); + let restored = T::from_raw_sql(raw).expect("database conversion should roundtrip"); + assert_eq!(restored, value); + } + + #[test] + fn binary_sql_conversions_roundtrip_core_types() { + let account_id = AccountId::try_from(ACCOUNT_ID_PRIVATE_SENDER).unwrap(); + let faucet_id = AccountId::try_from(ACCOUNT_ID_PUBLIC_FUNGIBLE_FAUCET).unwrap(); + + assert_sql_roundtrip(Word::from([1, 2, 3, 4])); + assert_sql_roundtrip(account_id); + assert_sql_roundtrip(AccountStorageHeader::new(Vec::new()).unwrap()); + assert_sql_roundtrip(StorageMapKey::from_index(7)); + assert_sql_roundtrip(NoteId::new(Word::from([1, 0, 0, 0]), Word::from([2, 0, 0, 0]))); + assert_sql_roundtrip(Asset::from(FungibleAsset::new(faucet_id, 100).unwrap())); + } + + #[test] + fn binary_sql_conversion_rejects_malformed_bytes() { + let err = AccountId::from_raw_sql(vec![1, 2, 3]).expect_err("invalid account id bytes"); + assert!(err.to_string().contains("failed to convert from database type")); + } +} From 1b88e07affe7cfbf6a4e0012b83cbd4846e768dd Mon Sep 17 00:00:00 2001 From: Mr-kay-cloud2 Date: Sun, 24 May 2026 17:08:39 +0100 Subject: [PATCH 2/3] fix(store): narrow sql conversion coverage --- crates/store/src/db/models/conv.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/crates/store/src/db/models/conv.rs b/crates/store/src/db/models/conv.rs index c312a7ada9..0acff2e127 100644 --- a/crates/store/src/db/models/conv.rs +++ b/crates/store/src/db/models/conv.rs @@ -43,7 +43,7 @@ use miden_protocol::account::{ StorageSlotName, StorageSlotType, }; -use miden_protocol::asset::{Asset, FungibleAsset}; +use miden_protocol::asset::Asset; use miden_protocol::block::{BlockHeader, BlockNumber}; use miden_protocol::crypto::merkle::SparseMerklePath; use miden_protocol::note::{ @@ -137,7 +137,6 @@ impl_binary_sql_convert!( AccountId, AccountStorageHeader, Asset, - FungibleAsset, NoteAssets, NoteAttachments, NoteId, @@ -295,7 +294,6 @@ pub(crate) fn idx_to_raw_sql(idx: usize) -> i32 { mod tests { use std::fmt::Debug; - use miden_protocol::account::AccountStorageHeader; use miden_protocol::asset::FungibleAsset; use miden_protocol::testing::account_id::{ ACCOUNT_ID_PRIVATE_SENDER, @@ -320,7 +318,6 @@ mod tests { assert_sql_roundtrip(Word::from([1, 2, 3, 4])); assert_sql_roundtrip(account_id); - assert_sql_roundtrip(AccountStorageHeader::new(Vec::new()).unwrap()); assert_sql_roundtrip(StorageMapKey::from_index(7)); assert_sql_roundtrip(NoteId::new(Word::from([1, 0, 0, 0]), Word::from([2, 0, 0, 0]))); assert_sql_roundtrip(Asset::from(FungibleAsset::new(faucet_id, 100).unwrap())); From 931b05797d1328b3f05efde6bba6a3a8d440164b Mon Sep 17 00:00:00 2001 From: Mr-kay-cloud2 Date: Sun, 24 May 2026 23:13:26 +0100 Subject: [PATCH 3/3] fix(store): drop brittle conversion tests --- crates/store/src/db/models/conv.rs | 40 ------------------------------ 1 file changed, 40 deletions(-) diff --git a/crates/store/src/db/models/conv.rs b/crates/store/src/db/models/conv.rs index 0acff2e127..0849eee597 100644 --- a/crates/store/src/db/models/conv.rs +++ b/crates/store/src/db/models/conv.rs @@ -289,43 +289,3 @@ pub(crate) fn raw_sql_to_idx(raw: i32) -> usize { pub(crate) fn idx_to_raw_sql(idx: usize) -> i32 { idx as i32 } - -#[cfg(test)] -mod tests { - use std::fmt::Debug; - - use miden_protocol::asset::FungibleAsset; - use miden_protocol::testing::account_id::{ - ACCOUNT_ID_PRIVATE_SENDER, - ACCOUNT_ID_PUBLIC_FUNGIBLE_FAUCET, - }; - - use super::*; - - fn assert_sql_roundtrip(value: T) - where - T: SqlTypeConvert> + Clone + Debug + PartialEq, - { - let raw = value.clone().to_raw_sql(); - let restored = T::from_raw_sql(raw).expect("database conversion should roundtrip"); - assert_eq!(restored, value); - } - - #[test] - fn binary_sql_conversions_roundtrip_core_types() { - let account_id = AccountId::try_from(ACCOUNT_ID_PRIVATE_SENDER).unwrap(); - let faucet_id = AccountId::try_from(ACCOUNT_ID_PUBLIC_FUNGIBLE_FAUCET).unwrap(); - - assert_sql_roundtrip(Word::from([1, 2, 3, 4])); - assert_sql_roundtrip(account_id); - assert_sql_roundtrip(StorageMapKey::from_index(7)); - assert_sql_roundtrip(NoteId::new(Word::from([1, 0, 0, 0]), Word::from([2, 0, 0, 0]))); - assert_sql_roundtrip(Asset::from(FungibleAsset::new(faucet_id, 100).unwrap())); - } - - #[test] - fn binary_sql_conversion_rejects_malformed_bytes() { - let err = AccountId::from_raw_sql(vec![1, 2, 3]).expect_err("invalid account id bytes"); - assert!(err.to_string().contains("failed to convert from database type")); - } -}