diff --git a/crates/sqlite-store/src/account/accounts.rs b/crates/sqlite-store/src/account/accounts.rs index cb2c5e4b9..e641a60b8 100644 --- a/crates/sqlite-store/src/account/accounts.rs +++ b/crates/sqlite-store/src/account/accounts.rs @@ -2,7 +2,7 @@ use std::collections::BTreeMap; use std::rc::Rc; -use std::string::{String, ToString}; +use std::string::ToString; use std::sync::{Arc, RwLock}; use std::vec::Vec; @@ -93,11 +93,10 @@ impl SqliteStore { conn: &mut Connection, account_commitment: Word, ) -> Result, StoreError> { - let account_commitment_str: String = account_commitment.to_string(); Ok(query_historical_account_headers( conn, "account_commitment = ?", - params![account_commitment_str], + params![account_commitment.to_bytes()], )? .pop() .map(|(header, _)| header)) @@ -388,7 +387,7 @@ impl SqliteStore { const QUERY: &str = insert_sql!(foreign_account_code { account_id, code_commitment } | REPLACE); - tx.execute(QUERY, params![account_id.to_bytes(), code.commitment().to_string()]) + tx.execute(QUERY, params![account_id.to_bytes(), code.commitment().to_bytes()]) .into_store_error()?; Self::insert_account_code(&tx, code)?; @@ -426,7 +425,7 @@ impl SqliteStore { account_code: &AccountCode, ) -> Result<(), StoreError> { const QUERY: &str = insert_sql!(account_code { commitment, code } | IGNORE); - tx.execute(QUERY, params![account_code.commitment().to_hex(), account_code.to_bytes()]) + tx.execute(QUERY, params![account_code.commitment().to_bytes(), account_code.to_bytes()]) .into_store_error()?; Ok(()) } @@ -515,7 +514,7 @@ impl SqliteStore { let commitment_params = Rc::new( discarded_states .iter() - .map(|(_, commitment)| Value::from(commitment.to_hex())) + .map(|(_, commitment)| Value::Blob(commitment.to_bytes())) .collect::>(), ); @@ -893,10 +892,10 @@ impl SqliteStore { // got a past update and shouldn't lock the account. const LOCK_CONDITION: &str = "WHERE id = :account_id AND NOT EXISTS (SELECT 1 FROM historical_account_headers WHERE id = :account_id AND account_commitment = :digest)"; let account_id_bytes = account_id.to_bytes(); - let digest_str = mismatched_digest.to_string(); + let digest_bytes = mismatched_digest.to_bytes(); let params = named_params! { ":account_id": account_id_bytes, - ":digest": digest_str + ":digest": digest_bytes }; let query = format!("UPDATE latest_account_headers SET locked = true {LOCK_CONDITION}"); @@ -924,11 +923,11 @@ impl SqliteStore { watched: bool, ) -> Result<(), StoreError> { let id = new_header.id().to_bytes(); - let code_commitment = new_header.code_commitment().to_string(); - let storage_commitment = new_header.storage_commitment().to_string(); - let vault_root = new_header.vault_root().to_string(); + let code_commitment = new_header.code_commitment().to_bytes(); + let storage_commitment = new_header.storage_commitment().to_bytes(); + let vault_root = new_header.vault_root().to_bytes(); let nonce = u64_to_value(new_header.nonce().as_canonical_u64()); - let commitment = new_header.to_commitment().to_string(); + let commitment = new_header.to_commitment().to_bytes(); let account_seed = account_seed.map(|seed| seed.to_bytes()); const LATEST_QUERY: &str = insert_sql!( @@ -1007,11 +1006,11 @@ impl SqliteStore { // Archive the old header to historical. let old_id = old_header.id().to_bytes(); - let old_code_commitment = old_header.code_commitment().to_string(); - let old_storage_commitment = old_header.storage_commitment().to_string(); - let old_vault_root = old_header.vault_root().to_string(); + let old_code_commitment = old_header.code_commitment().to_bytes(); + let old_storage_commitment = old_header.storage_commitment().to_bytes(); + let old_vault_root = old_header.vault_root().to_bytes(); let old_nonce = u64_to_value(old_header.nonce().as_canonical_u64()); - let old_commitment = old_header.to_commitment().to_string(); + let old_commitment = old_header.to_commitment().to_bytes(); let replaced_at_nonce = u64_to_value(new_header.nonce().as_canonical_u64()); const HISTORICAL_QUERY: &str = insert_sql!( @@ -1064,7 +1063,7 @@ impl SqliteStore { let mut total_deleted: usize = 0; // Collect code commitments from headers we are about to delete. - let candidate_code_commitments: Vec = { + let candidate_code_commitments: Vec> = { let mut stmt = tx .prepare( "SELECT DISTINCT code_commitment FROM historical_account_headers \ @@ -1074,7 +1073,7 @@ impl SqliteStore { let rows = stmt .query_map(params![&account_id_bytes, &boundary_val], |row| row.get(0)) .into_store_error()?; - rows.collect::, _>>().into_store_error()? + rows.collect::>, _>>().into_store_error()? }; // Delete historical entries. diff --git a/crates/sqlite-store/src/account/helpers.rs b/crates/sqlite-store/src/account/helpers.rs index cbf930f5a..69a708cca 100644 --- a/crates/sqlite-store/src/account/helpers.rs +++ b/crates/sqlite-store/src/account/helpers.rs @@ -25,9 +25,9 @@ use crate::sql_error::SqlResultExt; pub(crate) struct SerializedHeaderData { pub id: Vec, pub nonce: u64, - pub vault_root: String, - pub storage_commitment: String, - pub code_commitment: String, + pub vault_root: Vec, + pub storage_commitment: Vec, + pub code_commitment: Vec, pub account_seed: Option>, pub locked: bool, } @@ -59,9 +59,9 @@ pub(crate) fn parse_accounts( AccountId::read_from_bytes(&id) .expect("Conversion from stored AccountID should not panic"), nonce, - Word::try_from(&vault_root)?, - Word::try_from(&storage_commitment)?, - Word::try_from(&code_commitment)?, + Word::read_from_bytes(&vault_root)?, + Word::read_from_bytes(&storage_commitment)?, + Word::read_from_bytes(&code_commitment)?, ), status, )) @@ -84,9 +84,9 @@ pub(crate) fn query_latest_account_headers( .query_map(params, |row| { let id: Vec = row.get(0)?; let nonce: u64 = column_value_as_u64(row, 1)?; - let vault_root: String = row.get(2)?; - let storage_commitment: String = row.get(3)?; - let code_commitment: String = row.get(4)?; + let vault_root: Vec = row.get(2)?; + let storage_commitment: Vec = row.get(3)?; + let code_commitment: Vec = row.get(4)?; let account_seed: Option> = row.get(5)?; let locked: bool = row.get(6)?; let watched: bool = row.get(7)?; @@ -132,9 +132,9 @@ pub(crate) fn query_historical_account_headers( .query_map(params, |row| { let id: Vec = row.get(0)?; let nonce: u64 = column_value_as_u64(row, 1)?; - let vault_root: String = row.get(2)?; - let storage_commitment: String = row.get(3)?; - let code_commitment: String = row.get(4)?; + let vault_root: Vec = row.get(2)?; + let storage_commitment: Vec = row.get(3)?; + let code_commitment: Vec = row.get(4)?; let account_seed: Option> = row.get(5)?; let locked: bool = row.get(6)?; @@ -163,7 +163,7 @@ pub(crate) fn query_account_code( conn.prepare_cached(CODE_QUERY) .into_store_error()? - .query_map(params![commitment.to_hex()], |row| { + .query_map(params![commitment.to_bytes()], |row| { let code: Vec = row.get(0)?; Ok(code) }) @@ -207,15 +207,15 @@ pub(crate) fn query_vault_assets( conn.prepare(VAULT_QUERY) .into_store_error()? .query_map(params![account_id.to_bytes()], |row| { - let vault_key: String = row.get(0)?; - let asset: String = row.get(1)?; + let vault_key: Vec = row.get(0)?; + let asset: Vec = row.get(1)?; Ok((vault_key, asset)) }) .into_store_error()? .map(|result| { - let (vault_key_str, asset_str): (String, String) = result.into_store_error()?; - let key_word = Word::try_from(vault_key_str)?; - let value_word = Word::try_from(asset_str)?; + let (vault_key_bytes, asset_bytes): (Vec, Vec) = result.into_store_error()?; + let key_word = Word::read_from_bytes(&vault_key_bytes)?; + let value_word = Word::read_from_bytes(&asset_bytes)?; Ok(Asset::from_key_value_words(key_word, value_word)?) }) .collect::, StoreError>>() @@ -248,7 +248,7 @@ pub(crate) fn query_storage_slots( format!("{base_query} AND slot_name IN ({placeholders})") }, AccountStorageFilter::Root(root) => { - values_params.push(Value::Text(root.to_hex())); + values_params.push(Value::Blob(root.to_bytes())); format!("{base_query} AND slot_value = ?2") }, }; @@ -257,7 +257,7 @@ pub(crate) fn query_storage_slots( let storage_values = stmt .query_map(params_from_iter(values_params.iter()), |row| { let slot_name: String = row.get(0)?; - let value: String = row.get(1)?; + let value: Vec = row.get(1)?; let slot_type: u8 = row.get(2)?; Ok((slot_name, value, slot_type)) }) @@ -268,7 +268,7 @@ pub(crate) fn query_storage_slots( .map_err(|err| StoreError::ParsingError(err.to_string()))?; let slot_type = StorageSlotType::try_from(slot_type) .map_err(|e| StoreError::ParsingError(e.to_string()))?; - Ok((slot_name, Word::try_from(value)?, slot_type)) + Ok((slot_name, Word::read_from_bytes(&value)?, slot_type)) }) .collect::, StoreError>>()?; @@ -332,8 +332,8 @@ pub(crate) fn query_storage_maps( let map_entries = stmt .query_map(params_from_iter(map_params.iter()), |row| { let slot_name: String = row.get(0)?; - let key: String = row.get(1)?; - let value: String = row.get(2)?; + let key: Vec = row.get(1)?; + let value: Vec = row.get(2)?; Ok((slot_name, key, value)) }) @@ -342,7 +342,11 @@ pub(crate) fn query_storage_maps( let (slot_name, key, value) = result.into_store_error()?; let slot_name = StorageSlotName::new(slot_name) .map_err(|err| StoreError::ParsingError(err.to_string()))?; - Ok((slot_name, StorageMapKey::new(Word::try_from(key)?), Word::try_from(value)?)) + Ok(( + slot_name, + StorageMapKey::new(Word::read_from_bytes(&key)?), + Word::read_from_bytes(&value)?, + )) }) .collect::, StoreError>>()?; @@ -366,7 +370,7 @@ pub(crate) fn query_storage_values( .into_store_error()? .query_map(params![account_id.to_bytes()], |row| { let slot_name: String = row.get(0)?; - let value: String = row.get(1)?; + let value: Vec = row.get(1)?; let slot_type: u8 = row.get(2)?; Ok((slot_name, value, slot_type)) }) @@ -377,7 +381,7 @@ pub(crate) fn query_storage_values( .map_err(|err| StoreError::ParsingError(err.to_string()))?; let slot_type = StorageSlotType::try_from(slot_type) .map_err(|e| StoreError::ParsingError(e.to_string()))?; - Ok((slot_name, (slot_type, Word::try_from(value)?))) + Ok((slot_name, (slot_type, Word::read_from_bytes(&value)?))) }) .collect() } diff --git a/crates/sqlite-store/src/account/storage.rs b/crates/sqlite-store/src/account/storage.rs index d7e872136..c2339bfa8 100644 --- a/crates/sqlite-store/src/account/storage.rs +++ b/crates/sqlite-store/src/account/storage.rs @@ -15,7 +15,7 @@ use miden_client::account::{ StorageSlotType, }; use miden_client::store::{AccountSmtForest, StoreError}; -use miden_client::{EMPTY_WORD, Serializable, Word}; +use miden_client::{Deserializable, EMPTY_WORD, Serializable, Word}; use rusqlite::types::Value; use rusqlite::{OptionalExtension, Transaction, params}; @@ -53,7 +53,7 @@ impl SqliteStore { .into_store_error()? .query_map(params![account_id.to_bytes(), Rc::new(map_slot_names)], |row| { let name: String = row.get(0)?; - let value: String = row.get(1)?; + let value: Vec = row.get(1)?; Ok((name, value)) }) .into_store_error()? @@ -61,7 +61,7 @@ impl SqliteStore { let (name, value) = result.into_store_error()?; let slot_name = StorageSlotName::new(name) .map_err(|err| StoreError::ParsingError(err.to_string()))?; - Ok((slot_name, Word::try_from(value)?)) + Ok((slot_name, Word::read_from_bytes(&value)?)) }) .collect() } @@ -94,11 +94,16 @@ impl SqliteStore { for slot in account_storage { let slot_name_str = slot.name().to_string(); - let slot_value_hex = slot.value().to_hex(); + let slot_value_bytes = slot.value().to_bytes(); let slot_type_val = slot.slot_type() as u8; latest_slot_stmt - .execute(params![&account_id_bytes, &slot_name_str, &slot_value_hex, slot_type_val]) + .execute(params![ + &account_id_bytes, + &slot_name_str, + &slot_value_bytes, + slot_type_val + ]) .into_store_error()?; if let StorageSlotContent::Map(map) = slot.content() { @@ -107,8 +112,8 @@ impl SqliteStore { .execute(params![ &account_id_bytes, &slot_name_str, - key.to_hex(), - value.to_hex(), + key.to_bytes(), + value.to_bytes(), ]) .into_store_error()?; } @@ -185,11 +190,11 @@ impl SqliteStore { for (slot_name, (value, slot_type)) in updated_slots { let slot_name_str = slot_name.to_string(); - let slot_value_hex = value.to_hex(); + let slot_value_bytes = value.to_bytes(); let slot_type_val = *slot_type as u8; // Read old slot value from latest (NULL if slot is new) - let old_slot_value: Option = tx + let old_slot_value: Option> = tx .query_row(READ_OLD_SLOT, params![&account_id_bytes, &slot_name_str], |row| { row.get(0) }) @@ -210,7 +215,12 @@ impl SqliteStore { // Update latest slot latest_slot_stmt - .execute(params![&account_id_bytes, &slot_name_str, &slot_value_hex, slot_type_val]) + .execute(params![ + &account_id_bytes, + &slot_name_str, + &slot_value_bytes, + slot_type_val + ]) .into_store_error()?; if let Some(changed_entries) = delta_map_entries.get(slot_name) { @@ -243,13 +253,13 @@ impl SqliteStore { const DELETE_LATEST_MAP_ENTRY: &str = "DELETE FROM latest_storage_map_entries WHERE account_id = ? AND slot_name = ? AND key = ?"; for (key, value) in changed_entries { - let key_hex = key.to_hex(); + let key_bytes = key.to_bytes(); // Read old map entry value from latest (NULL if entry is new) - let old_entry_value: Option = tx + let old_entry_value: Option> = tx .query_row( READ_OLD_MAP_ENTRY, - params![account_id_bytes, slot_name_str, &key_hex], + params![account_id_bytes, slot_name_str, &key_bytes], |row| row.get(0), ) .optional() @@ -262,7 +272,7 @@ impl SqliteStore { account_id_bytes, nonce_val, slot_name_str, - &key_hex, + &key_bytes, old_entry_value, ]) .into_store_error()?; @@ -271,12 +281,14 @@ impl SqliteStore { if *value == EMPTY_WORD { tx.execute( DELETE_LATEST_MAP_ENTRY, - params![account_id_bytes, slot_name_str, &key_hex], + params![account_id_bytes, slot_name_str, &key_bytes], ) .into_store_error()?; } else { latest_map_stmt - .execute(params![account_id_bytes, slot_name_str, &key_hex, value.to_hex(),]) + .execute( + params![account_id_bytes, slot_name_str, &key_bytes, value.to_bytes(),], + ) .into_store_error()?; } } diff --git a/crates/sqlite-store/src/account/tests.rs b/crates/sqlite-store/src/account/tests.rs index 33e49cf04..4b7d18ca6 100644 --- a/crates/sqlite-store/src/account/tests.rs +++ b/crates/sqlite-store/src/account/tests.rs @@ -922,7 +922,7 @@ async fn prune_removes_orphaned_account_code() -> anyhow::Result<()> { // Simulate the nonce-1 state having a different code commitment by updating // the latest header's code_commitment directly. This makes the nonce-0 // historical header the only reference to the original code. - let original_code_commitment: String = store + let original_code_commitment: Vec = store .interact_with_connection(move |conn| { conn.query_row( "SELECT code_commitment FROM historical_account_headers WHERE id = ?", @@ -937,14 +937,15 @@ async fn prune_removes_orphaned_account_code() -> anyhow::Result<()> { // orphaned when we prune the historical header. store .interact_with_connection(move |conn| { + let new_code_commitment = vec![1u8; 32]; conn.execute( "INSERT INTO account_code (commitment, code) VALUES (?, ?)", - params!["new_code_commitment", vec![0u8; 16]], + params![new_code_commitment, vec![0u8; 16]], ) .into_store_error()?; conn.execute( "UPDATE latest_account_headers SET code_commitment = ? WHERE id = ?", - params!["new_code_commitment", account_id.to_bytes()], + params![new_code_commitment, account_id.to_bytes()], ) .into_store_error()?; Ok(()) diff --git a/crates/sqlite-store/src/account/vault.rs b/crates/sqlite-store/src/account/vault.rs index 3f2d47b08..54b966972 100644 --- a/crates/sqlite-store/src/account/vault.rs +++ b/crates/sqlite-store/src/account/vault.rs @@ -7,7 +7,7 @@ use std::vec::Vec; use miden_client::account::{AccountDelta, AccountHeader, AccountId}; use miden_client::asset::{Asset, FungibleAsset, NonFungibleDeltaAction}; use miden_client::store::{AccountSmtForest, StoreError}; -use miden_client::{Serializable, Word}; +use miden_client::{Deserializable, Serializable, Word}; use miden_protocol::asset::AssetVaultKey; use miden_protocol::crypto::merkle::MerkleError; use rusqlite::types::Value; @@ -31,7 +31,7 @@ impl SqliteStore { .vault() .fungible() .iter() - .map(|(vault_key, _)| Value::Text(vault_key.to_string())) + .map(|(vault_key, _)| Value::Blob(vault_key.to_bytes())) .collect::>(); const QUERY: &str = "SELECT vault_key, asset FROM latest_account_assets WHERE account_id = ? AND vault_key IN rarray(?)"; @@ -40,15 +40,15 @@ impl SqliteStore { .prepare(QUERY) .into_store_error()? .query_map(params![account_id.to_bytes(), Rc::new(vault_keys)], |row| { - let vault_key: String = row.get(0)?; - let asset: String = row.get(1)?; + let vault_key: Vec = row.get(0)?; + let asset: Vec = row.get(1)?; Ok((vault_key, asset)) }) .into_store_error()? .map(|result| { - let (vault_key_str, asset_str): (String, String) = result.into_store_error()?; - let key_word = Word::try_from(vault_key_str)?; - let value_word = Word::try_from(asset_str)?; + let (vault_key_bytes, asset_bytes): (Vec, Vec) = result.into_store_error()?; + let key_word = Word::read_from_bytes(&vault_key_bytes)?; + let value_word = Word::read_from_bytes(&asset_bytes)?; Ok(Asset::from_key_value_words(key_word, value_word)?) }) .collect::, StoreError>>()? @@ -76,11 +76,11 @@ impl SqliteStore { let account_id_bytes = account_id.to_bytes(); for asset in assets { - let vault_key_hex = asset.vault_key().to_string(); - let asset_hex = asset.to_value_word().to_hex(); + let vault_key_bytes = asset.vault_key().to_bytes(); + let asset_bytes = asset.to_value_word().to_bytes(); latest_stmt - .execute(params![&account_id_bytes, &vault_key_hex, &asset_hex]) + .execute(params![&account_id_bytes, &vault_key_bytes, &asset_bytes]) .into_store_error()?; } @@ -205,11 +205,11 @@ impl SqliteStore { // Archive and delete removed assets for vault_key in removed_vault_keys { - let vault_key_hex = vault_key.to_string(); + let vault_key_bytes = vault_key.to_bytes(); // Read old asset value from latest (should exist since we're removing it) - let old_asset: Option = tx - .query_row(READ_OLD_ASSET, params![account_id_bytes, &vault_key_hex], |row| { + let old_asset: Option> = tx + .query_row(READ_OLD_ASSET, params![account_id_bytes, &vault_key_bytes], |row| { row.get(0) }) .optional() @@ -218,7 +218,7 @@ impl SqliteStore { // Archive old value to historical hist_stmt - .execute(params![account_id_bytes, nonce_val, &vault_key_hex, old_asset,]) + .execute(params![account_id_bytes, nonce_val, &vault_key_bytes, old_asset,]) .into_store_error()?; } @@ -233,7 +233,7 @@ impl SqliteStore { Rc::new( removed_vault_keys .iter() - .map(|k| Value::from(k.to_string())) + .map(|k| Value::Blob(k.to_bytes())) .collect::>(), ), ], @@ -243,12 +243,12 @@ impl SqliteStore { // Archive old values and insert updated assets for asset in updated_assets { - let vault_key_hex = asset.vault_key().to_string(); - let asset_hex = asset.to_value_word().to_hex(); + let vault_key_bytes = asset.vault_key().to_bytes(); + let asset_bytes = asset.to_value_word().to_bytes(); // Read old asset value from latest (NULL if asset is new) - let old_asset: Option = tx - .query_row(READ_OLD_ASSET, params![account_id_bytes, &vault_key_hex], |row| { + let old_asset: Option> = tx + .query_row(READ_OLD_ASSET, params![account_id_bytes, &vault_key_bytes], |row| { row.get(0) }) .optional() @@ -257,12 +257,12 @@ impl SqliteStore { // Archive old value to historical (NULL old_asset = asset was new) hist_stmt - .execute(params![account_id_bytes, nonce_val, &vault_key_hex, old_asset,]) + .execute(params![account_id_bytes, nonce_val, &vault_key_bytes, old_asset,]) .into_store_error()?; // Insert/update in latest latest_stmt - .execute(params![account_id_bytes, &vault_key_hex, &asset_hex]) + .execute(params![account_id_bytes, &vault_key_bytes, &asset_bytes]) .into_store_error()?; } diff --git a/crates/sqlite-store/src/chain_data.rs b/crates/sqlite-store/src/chain_data.rs index 832dc4006..c61ac6d5f 100644 --- a/crates/sqlite-store/src/chain_data.rs +++ b/crates/sqlite-store/src/chain_data.rs @@ -31,11 +31,11 @@ struct SerializedBlockHeaderParts { struct SerializedPartialBlockchainNodeData { id: i64, - node: String, + node: Vec, } struct SerializedPartialBlockchainNodeParts { id: u64, - node: String, + node: Vec, } impl SqliteStore { @@ -351,7 +351,7 @@ fn serialize_partial_blockchain_node( node: Word, ) -> SerializedPartialBlockchainNodeData { let id = i64::try_from(id.inner()).expect("id is a valid i64"); - let node = node.to_hex(); + let node = node.to_bytes(); SerializedPartialBlockchainNodeData { id, node } } @@ -373,7 +373,7 @@ fn parse_partial_blockchain_nodes( ) .unwrap(), ); - let node: Word = Word::try_from(&serialized_partial_blockchain_node_parts.node)?; + let node: Word = Word::read_from_bytes(&serialized_partial_blockchain_node_parts.node)?; Ok((id, node)) } diff --git a/crates/sqlite-store/src/note/filters.rs b/crates/sqlite-store/src/note/filters.rs index 0ede5c99f..6db1c2039 100644 --- a/crates/sqlite-store/src/note/filters.rs +++ b/crates/sqlite-store/src/note/filters.rs @@ -52,14 +52,14 @@ pub(super) fn note_filter_output_notes_condition(filter: &NoteFilter) -> (String }, NoteFilter::Processing | NoteFilter::Unverified => "1 = 0".to_string(), NoteFilter::Unique(note_id) => { - let note_ids_list = vec![Value::Text(note_id.as_word().to_string())]; + let note_ids_list = vec![Value::Blob(note_id.as_word().to_bytes())]; params.push(Rc::new(note_ids_list)); "note.note_id IN rarray(?)".to_string() }, NoteFilter::List(note_ids) => { let note_ids_list = note_ids .iter() - .map(|note_id| Value::Text(note_id.as_word().to_string())) + .map(|note_id| Value::Blob(note_id.as_word().to_bytes())) .collect::>(); params.push(Rc::new(note_ids_list)); @@ -68,7 +68,7 @@ pub(super) fn note_filter_output_notes_condition(filter: &NoteFilter) -> (String NoteFilter::DetailsCommitments(commitments) => { let commitments_list = commitments .iter() - .map(|commitment| Value::Text(commitment.to_hex())) + .map(|commitment| Value::Blob(commitment.to_bytes())) .collect::>(); params.push(Rc::new(commitments_list)); @@ -77,7 +77,7 @@ pub(super) fn note_filter_output_notes_condition(filter: &NoteFilter) -> (String NoteFilter::Nullifiers(nullifiers) => { let nullifiers_list = nullifiers .iter() - .map(|nullifier| Value::Text(nullifier.to_string())) + .map(|nullifier| Value::Blob(nullifier.to_bytes())) .collect::>(); params.push(Rc::new(nullifiers_list)); @@ -187,14 +187,14 @@ pub(super) fn note_filter_input_notes_condition(filter: &NoteFilter) -> (String, ) }, NoteFilter::Unique(note_id) => { - let note_ids_list = vec![Value::Text(note_id.as_word().to_string())]; + let note_ids_list = vec![Value::Blob(note_id.as_word().to_bytes())]; params.push(Rc::new(note_ids_list)); "(note.note_id IN rarray(?))".to_string() }, NoteFilter::List(note_ids) => { let note_ids_list = note_ids .iter() - .map(|note_id| Value::Text(note_id.as_word().to_string())) + .map(|note_id| Value::Blob(note_id.as_word().to_bytes())) .collect::>(); params.push(Rc::new(note_ids_list)); @@ -203,7 +203,7 @@ pub(super) fn note_filter_input_notes_condition(filter: &NoteFilter) -> (String, NoteFilter::DetailsCommitments(commitments) => { let commitments_list = commitments .iter() - .map(|commitment| Value::Text(commitment.to_hex())) + .map(|commitment| Value::Blob(commitment.to_bytes())) .collect::>(); params.push(Rc::new(commitments_list)); @@ -212,7 +212,7 @@ pub(super) fn note_filter_input_notes_condition(filter: &NoteFilter) -> (String, NoteFilter::Nullifiers(nullifiers) => { let nullifiers_list = nullifiers .iter() - .map(|nullifier| Value::Text(nullifier.to_string())) + .map(|nullifier| Value::Blob(nullifier.to_bytes())) .collect::>(); params.push(Rc::new(nullifiers_list)); diff --git a/crates/sqlite-store/src/note/mod.rs b/crates/sqlite-store/src/note/mod.rs index 8a2064a16..c12adf5c1 100644 --- a/crates/sqlite-store/src/note/mod.rs +++ b/crates/sqlite-store/src/note/mod.rs @@ -2,7 +2,7 @@ use std::collections::BTreeMap; use std::rc::Rc; -use std::string::{String, ToString}; +use std::string::ToString; use std::vec::Vec; use miden_client::Word; @@ -57,15 +57,15 @@ mod tests; /// Represents an `InputNoteRecord` serialized to be stored in the database. struct SerializedInputNoteData { - pub details_commitment: String, - pub id: Option, + pub details_commitment: Vec, + pub id: Option>, pub assets: Vec, pub attachments: Vec, pub serial_number: Vec, pub inputs: Vec, - pub script_root: String, + pub script_root: Vec, pub script: Vec, - pub nullifier: Option, + pub nullifier: Option>, pub state_discriminant: u8, pub state: Vec, pub created_at: u64, @@ -76,12 +76,12 @@ struct SerializedInputNoteData { /// Represents an `OutputNoteRecord` serialized to be stored in the database. struct SerializedOutputNoteData { - pub details_commitment: String, - pub id: String, + pub details_commitment: Vec, + pub id: Vec, pub assets: Vec, pub metadata: Vec, - pub nullifier: Option, - pub recipient_digest: String, + pub nullifier: Option>, + pub recipient_digest: Vec, pub expected_height: u32, pub state_discriminant: u8, pub state: Vec, @@ -103,7 +103,7 @@ struct SerializedInputNoteParts { struct SerializedOutputNoteParts { pub assets: Vec, pub metadata: Vec, - pub recipient_digest: String, + pub recipient_digest: Vec, pub expected_height: u32, pub state: Vec, pub attachments: Vec, @@ -111,7 +111,7 @@ struct SerializedOutputNoteParts { /// Represents the fields needed to update an existing input note's state. struct SerializedInputNoteStateUpdate { - pub details_commitment: String, + pub details_commitment: Vec, pub state_discriminant: u8, pub state: Vec, pub consumed_block_height: Option, @@ -121,7 +121,7 @@ struct SerializedInputNoteStateUpdate { /// Represents the fields needed to update an existing output note's state. struct SerializedOutputNoteStateUpdate { - pub details_commitment: String, + pub details_commitment: Vec, pub state_discriminant: u8, pub state: Vec, } @@ -236,7 +236,7 @@ impl SqliteStore { .map(|result| { result .map_err(|err| StoreError::ParsingError(err.to_string())) - .and_then(|v: String| Ok(Nullifier::from_hex(&v)?)) + .and_then(|v: Vec| Ok(Nullifier::read_from_bytes(&v)?)) }) .collect::, _>>() } @@ -259,18 +259,17 @@ impl SqliteStore { conn: &mut Connection, script_root: Word, ) -> Result { - let script_root = script_root.to_hex(); let query = "SELECT * FROM notes_scripts WHERE script_root = ?"; let note_script = conn .prepare(query) .into_store_error()? - .query_map([script_root.clone()], parse_note_scripts_columns) + .query_map([script_root.to_bytes()], parse_note_scripts_columns) .expect("no binding parameters used in query") .map(|result| Ok(result.into_store_error()?).and_then(|s| parse_note_script(&s))) .collect::, _>>()? .first() .cloned() - .ok_or(StoreError::NoteScriptNotFound(script_root))?; + .ok_or(StoreError::NoteScriptNotFound(script_root.to_hex()))?; Ok(note_script) } @@ -406,13 +405,14 @@ fn parse_input_note( /// Serialize the provided input note into database compatible types. fn serialize_input_note(note: &InputNoteRecord) -> SerializedInputNoteData { - let details_commitment = note.details_commitment().to_hex(); + let details_commitment = note.details_commitment().to_bytes(); // `note_id` and `nullifier` require metadata, so they're only available when the record // carries it. The columns are NULL-able and get populated once metadata arrives (via // sync / inclusion proof). - let id = note.id().map(|id| id.as_word().to_string()); + let id = note.id().map(|id| id.as_word().to_bytes()); let nullifier = note.metadata().map(|metadata| { - miden_client::note::Nullifier::from_details_and_metadata(note.details(), metadata).to_hex() + miden_client::note::Nullifier::from_details_and_metadata(note.details(), metadata) + .to_bytes() }); let created_at = note.created_at().unwrap_or(0); @@ -425,7 +425,7 @@ fn serialize_input_note(note: &InputNoteRecord) -> SerializedInputNoteData { let script = recipient.script().to_bytes(); let inputs = recipient.storage().to_bytes(); - let script_root = recipient.script().root().to_hex(); + let script_root = recipient.script().root().to_bytes(); let state_discriminant = note.state().discriminant(); let state = note.state().to_bytes(); @@ -457,7 +457,7 @@ fn serialize_input_note(note: &InputNoteRecord) -> SerializedInputNoteData { fn parse_output_note_columns( row: &rusqlite::Row<'_>, ) -> Result { - let recipient_digest: String = row.get(0)?; + let recipient_digest: Vec = row.get(0)?; let assets: Vec = row.get(1)?; let metadata: Vec = row.get(2)?; let expected_height: u32 = row.get(3)?; @@ -487,7 +487,7 @@ fn parse_output_note( attachments, } = serialized_output_note_parts; - let recipient_digest = Word::try_from(recipient_digest)?; + let recipient_digest = Word::read_from_bytes(&recipient_digest)?; let assets = NoteAssets::read_from_bytes(&assets)?; let metadata = NoteMetadata::read_from_bytes(&metadata)?; let state = OutputNoteState::read_from_bytes(&state)?; @@ -510,7 +510,7 @@ fn serialize_input_note_state(note: &InputNoteRecord) -> SerializedInputNoteStat let consumer_account_id = note.consumer_account().map(|id| id.to_bytes()); SerializedInputNoteStateUpdate { - details_commitment: note.details_commitment().to_hex(), + details_commitment: note.details_commitment().to_bytes(), state_discriminant: note.state().discriminant(), state: note.state().to_bytes(), consumed_block_height, @@ -522,7 +522,7 @@ fn serialize_input_note_state(note: &InputNoteRecord) -> SerializedInputNoteStat /// Serialize the provided output note state into a lightweight state-only update. fn serialize_output_note_state(note: &OutputNoteRecord) -> SerializedOutputNoteStateUpdate { SerializedOutputNoteStateUpdate { - details_commitment: note.details_commitment().to_hex(), + details_commitment: note.details_commitment().to_bytes(), state_discriminant: note.state().discriminant(), state: note.state().to_bytes(), } @@ -530,13 +530,13 @@ fn serialize_output_note_state(note: &OutputNoteRecord) -> SerializedOutputNoteS /// Serialize the provided output note into database compatible types. fn serialize_output_note(note: &OutputNoteRecord) -> SerializedOutputNoteData { - let details_commitment = note.details_commitment().to_hex(); - let id = note.id().as_word().to_string(); + let details_commitment = note.details_commitment().to_bytes(); + let id = note.id().as_word().to_bytes(); let assets = note.assets().to_bytes(); - let recipient_digest = note.recipient_digest().to_hex(); + let recipient_digest = note.recipient_digest().to_bytes(); let metadata = note.metadata().to_bytes(); - let nullifier = note.nullifier().map(|nullifier| nullifier.to_hex()); + let nullifier = note.nullifier().map(|nullifier| nullifier.to_bytes()); let state_discriminant = note.state().discriminant(); let state = note.state().to_bytes(); @@ -564,7 +564,7 @@ pub(crate) fn apply_note_updates_tx( // Split input notes into inserts and updates, collecting scripts from new notes. let mut input_inserts = Vec::new(); let mut input_updates = Vec::new(); - let mut scripts: BTreeMap> = BTreeMap::new(); + let mut scripts: BTreeMap, Vec> = BTreeMap::new(); for input_note in note_updates.updated_input_notes() { match input_note.update_type() { @@ -615,7 +615,7 @@ pub(crate) fn apply_note_updates_tx( /// individual inserts. fn batch_upsert_scripts( tx: &Transaction, - scripts: &BTreeMap>, + scripts: &BTreeMap, Vec>, ) -> Result<(), StoreError> { if scripts.is_empty() { return Ok(()); @@ -630,7 +630,7 @@ fn batch_upsert_scripts( ); let mut param_values: Vec = Vec::with_capacity(chunk.len() * 2); for (root, script) in chunk { - param_values.push(Value::Text((*root).clone())); + param_values.push(Value::Blob((*root).clone())); param_values.push(Value::Blob((*script).clone())); } tx.execute(&query, params_from_iter(param_values)).into_store_error()?; @@ -660,18 +660,18 @@ fn batch_insert_input_notes( ); let mut param_values: Vec = Vec::with_capacity(chunk.len() * 14); for note in chunk { - param_values.push(Value::Text(note.details_commitment.clone())); + param_values.push(Value::Blob(note.details_commitment.clone())); match ¬e.id { - Some(id) => param_values.push(Value::Text(id.clone())), + Some(id) => param_values.push(Value::Blob(id.clone())), None => param_values.push(Value::Null), } param_values.push(Value::Blob(note.assets.clone())); param_values.push(Value::Blob(note.attachments.clone())); param_values.push(Value::Blob(note.serial_number.clone())); param_values.push(Value::Blob(note.inputs.clone())); - param_values.push(Value::Text(note.script_root.clone())); + param_values.push(Value::Blob(note.script_root.clone())); match ¬e.nullifier { - Some(n) => param_values.push(Value::Text(n.clone())), + Some(n) => param_values.push(Value::Blob(n.clone())), None => param_values.push(Value::Null), } param_values.push(Value::Integer(i64::from(note.state_discriminant))); @@ -748,13 +748,13 @@ fn batch_insert_output_notes( ); let mut param_values: Vec = Vec::with_capacity(chunk.len() * 10); for note in chunk { - param_values.push(Value::Text(note.details_commitment.clone())); - param_values.push(Value::Text(note.id.clone())); + param_values.push(Value::Blob(note.details_commitment.clone())); + param_values.push(Value::Blob(note.id.clone())); param_values.push(Value::Blob(note.assets.clone())); - param_values.push(Value::Text(note.recipient_digest.clone())); + param_values.push(Value::Blob(note.recipient_digest.clone())); param_values.push(Value::Blob(note.metadata.clone())); match ¬e.nullifier { - Some(n) => param_values.push(Value::Text(n.clone())), + Some(n) => param_values.push(Value::Blob(n.clone())), None => param_values.push(Value::Null), } param_values.push(Value::Integer(i64::from(note.expected_height))); @@ -801,7 +801,7 @@ pub(super) fn upsert_note_script_tx( insert_sql!(notes_scripts { script_root, serialized_note_script } | REPLACE); tx.prepare_cached(QUERY) .into_store_error()? - .execute(params![note_script.root().to_hex(), note_script.to_bytes()]) + .execute(params![note_script.root().to_bytes(), note_script.to_bytes()]) .into_store_error()?; Ok(()) diff --git a/crates/sqlite-store/src/store.sql b/crates/sqlite-store/src/store.sql index 243a7df0d..c182c5a68 100644 --- a/crates/sqlite-store/src/store.sql +++ b/crates/sqlite-store/src/store.sql @@ -19,7 +19,7 @@ CREATE TABLE settings ( -- Create account_code table CREATE TABLE account_code ( - commitment TEXT NOT NULL, -- commitment to the account code + commitment BLOB NOT NULL, -- commitment to the account code code BLOB NOT NULL, -- serialized account code. PRIMARY KEY (commitment) ); @@ -29,10 +29,10 @@ CREATE TABLE account_code ( -- Latest account header: one row per account (current state). CREATE TABLE latest_account_headers ( id BLOB NOT NULL, -- serialized account ID - account_commitment TEXT NOT NULL UNIQUE, -- account state commitment - code_commitment TEXT NOT NULL, -- commitment to the account code - storage_commitment TEXT NOT NULL, -- commitment to the account storage - vault_root TEXT NOT NULL, -- root of the account vault Merkle tree + account_commitment BLOB NOT NULL UNIQUE, -- account state commitment + code_commitment BLOB NOT NULL, -- commitment to the account code + storage_commitment BLOB NOT NULL, -- commitment to the account storage + vault_root BLOB NOT NULL, -- root of the account vault Merkle tree nonce BIGINT NOT NULL, -- account nonce account_seed BLOB NULL, -- seed used to generate the ID; NULL for non-new accounts locked BOOLEAN NOT NULL, -- whether the account is locked @@ -45,10 +45,10 @@ CREATE TABLE latest_account_headers ( -- Each row represents a previous account state that was superseded at replaced_at_nonce. CREATE TABLE historical_account_headers ( id BLOB NOT NULL, -- serialized account ID - account_commitment TEXT NOT NULL UNIQUE, -- commitment of this old state - code_commitment TEXT NOT NULL, -- commitment to the old account code - storage_commitment TEXT NOT NULL, -- commitment to the old account storage - vault_root TEXT NOT NULL, -- root of the old account vault Merkle tree + account_commitment BLOB NOT NULL UNIQUE, -- commitment of this old state + code_commitment BLOB NOT NULL, -- commitment to the old account code + storage_commitment BLOB NOT NULL, -- commitment to the old account storage + vault_root BLOB NOT NULL, -- root of the old account vault Merkle tree nonce BIGINT NOT NULL, -- nonce of this old state account_seed BLOB NULL, -- seed used to generate the ID; NULL for non-new accounts locked BOOLEAN NOT NULL, -- whether the account was locked @@ -65,7 +65,7 @@ CREATE INDEX idx_historical_account_headers_id_replaced_at ON historical_account CREATE TABLE latest_account_storage ( account_id BLOB NOT NULL, -- serialized account ID slot_name TEXT NOT NULL, -- name of the storage slot - slot_value TEXT NULL, -- top-level value of the slot (for maps, contains the root) + slot_value BLOB NULL, -- top-level value of the slot (for maps, contains the root) slot_type INTEGER NOT NULL, -- type of the slot (0 = Value, 1 = Map) PRIMARY KEY (account_id, slot_name) ) WITHOUT ROWID; @@ -76,7 +76,7 @@ CREATE TABLE historical_account_storage ( account_id BLOB NOT NULL, -- serialized account ID replaced_at_nonce BIGINT NOT NULL, -- nonce at which this old value was replaced slot_name TEXT NOT NULL, -- name of the storage slot - old_slot_value TEXT NULL, -- old top-level value (NULL = slot was new) + old_slot_value BLOB NULL, -- old top-level value (NULL = slot was new) slot_type INTEGER NOT NULL, -- type of the slot (0 = Value, 1 = Map) PRIMARY KEY (account_id, replaced_at_nonce, slot_name) ) WITHOUT ROWID; @@ -86,8 +86,8 @@ CREATE TABLE historical_account_storage ( CREATE TABLE latest_storage_map_entries ( account_id BLOB NOT NULL, -- account ID slot_name TEXT NOT NULL, -- name of the storage slot this entry belongs to - key TEXT NOT NULL, -- map entry key - value TEXT NOT NULL, -- map entry value + key BLOB NOT NULL, -- map entry key + value BLOB NOT NULL, -- map entry value PRIMARY KEY (account_id, slot_name, key) ) WITHOUT ROWID; @@ -97,8 +97,8 @@ CREATE TABLE historical_storage_map_entries ( account_id BLOB NOT NULL, -- account ID replaced_at_nonce BIGINT NOT NULL, -- nonce at which this old entry was replaced slot_name TEXT NOT NULL, -- name of the storage slot this entry belongs to - key TEXT NOT NULL, -- map entry key - old_value TEXT NULL, -- old map entry value (NULL = entry was new) + key BLOB NOT NULL, -- map entry key + old_value BLOB NULL, -- old map entry value (NULL = entry was new) PRIMARY KEY (account_id, replaced_at_nonce, slot_name, key) ) WITHOUT ROWID; @@ -106,8 +106,8 @@ CREATE TABLE historical_storage_map_entries ( CREATE TABLE latest_account_assets ( account_id BLOB NOT NULL, -- account ID - vault_key TEXT NOT NULL, -- asset's vault key - asset TEXT NOT NULL, -- serialized asset value + vault_key BLOB NOT NULL, -- asset's vault key + asset BLOB NOT NULL, -- serialized asset value PRIMARY KEY (account_id, vault_key) ) WITHOUT ROWID; @@ -116,8 +116,8 @@ CREATE TABLE latest_account_assets ( CREATE TABLE historical_account_assets ( account_id BLOB NOT NULL, -- account ID replaced_at_nonce BIGINT NOT NULL, -- nonce at which this old asset was replaced - vault_key TEXT NOT NULL, -- asset's vault key - old_asset TEXT NULL, -- old serialized asset value (NULL = asset was new) + vault_key BLOB NOT NULL, -- asset's vault key + old_asset BLOB NULL, -- old serialized asset value (NULL = asset was new) PRIMARY KEY (account_id, replaced_at_nonce, vault_key) ) WITHOUT ROWID; @@ -125,7 +125,7 @@ CREATE TABLE historical_account_assets ( CREATE TABLE foreign_account_code( account_id BLOB NOT NULL, - code_commitment TEXT NOT NULL, + code_commitment BLOB NOT NULL, PRIMARY KEY (account_id), FOREIGN KEY (code_commitment) REFERENCES account_code(commitment) ); @@ -133,9 +133,9 @@ CREATE TABLE foreign_account_code( -- ── Transactions ───────────────────────────────────────────────────────── CREATE TABLE transactions ( - id TEXT NOT NULL, -- Transaction ID (commitment of various components) + id BLOB NOT NULL, -- Transaction ID (commitment of various components) details BLOB NOT NULL, -- Serialized transaction details - script_root TEXT, -- Transaction script root + script_root BLOB, -- Transaction script root block_num UNSIGNED BIG INT, -- Block number for the block against which the transaction was executed. status_variant INT NOT NULL, -- Status variant identifier status BLOB NOT NULL, -- Serialized transaction status @@ -146,7 +146,7 @@ CREATE INDEX idx_transactions_uncommitted ON transactions(status_variant); CREATE TABLE transaction_scripts ( - script_root TEXT NOT NULL, -- Transaction script root + script_root BLOB NOT NULL, -- Transaction script root script BLOB, -- serialized Transaction script PRIMARY KEY (script_root) @@ -155,14 +155,14 @@ CREATE TABLE transaction_scripts ( -- ── Notes ──────────────────────────────────────────────────────────────── CREATE TABLE input_notes ( - details_commitment TEXT NOT NULL, -- commitment to the note details (recipient + assets); stable across the note's lifecycle and independent of metadata - note_id TEXT NULL, -- the full note id (hash(details_commitment, metadata_commitment)); NULL until metadata is known + details_commitment BLOB NOT NULL, -- commitment to the note details (recipient + assets); stable across the note's lifecycle and independent of metadata + note_id BLOB NULL, -- the full note id (hash(details_commitment, metadata_commitment)); NULL until metadata is known assets BLOB NOT NULL, -- the serialized list of assets attachments BLOB NOT NULL, -- the serialized NoteAttachments serial_number BLOB NOT NULL, -- the serial number of the note inputs BLOB NOT NULL, -- the serialized list of note inputs - script_root TEXT NOT NULL, -- the script root of the note, used to join with the notes_scripts table - nullifier TEXT NULL, -- the nullifier of the note, used to query by nullifier; NULL until metadata is known + script_root BLOB NOT NULL, -- the script root of the note, used to join with the notes_scripts table + nullifier BLOB NULL, -- the nullifier of the note, used to query by nullifier; NULL until metadata is known state_discriminant UNSIGNED INT NOT NULL, -- state discriminant of the note, used to query by state state BLOB NOT NULL, -- serialized note state created_at UNSIGNED BIG INT NOT NULL, -- timestamp of the note creation/import @@ -179,15 +179,15 @@ CREATE INDEX idx_input_notes_note_id ON input_notes(note_id); CREATE INDEX idx_input_notes_consumption ON input_notes(consumed_block_height, consumed_tx_order); CREATE TABLE output_notes ( - details_commitment TEXT NOT NULL, -- commitment to the note details (recipient + assets); primary key - note_id TEXT NOT NULL, -- the full note id (hash(details_commitment, metadata_commitment)) - recipient_digest TEXT NOT NULL, -- the note recipient + details_commitment BLOB NOT NULL, -- commitment to the note details (recipient + assets); primary key + note_id BLOB NOT NULL, -- the full note id (hash(details_commitment, metadata_commitment)) + recipient_digest BLOB NOT NULL, -- the note recipient assets BLOB NOT NULL, -- the serialized NoteAssets, including vault commitment and list of assets metadata BLOB NOT NULL, -- serialized metadata - nullifier TEXT NULL, + nullifier BLOB NULL, expected_height UNSIGNED INT NOT NULL, -- the block height after which the note is expected to be created -- TODO: normalize script data for output notes --- script_commitment TEXT NULL, +-- script_commitment BLOB NULL, state_discriminant UNSIGNED INT NOT NULL, -- state discriminant of the note, used to query by state state BLOB NOT NULL, -- serialized note state attachments BLOB NOT NULL, @@ -199,7 +199,7 @@ CREATE INDEX idx_output_notes_nullifier ON output_notes(nullifier); CREATE INDEX idx_output_notes_note_id ON output_notes(note_id); CREATE TABLE notes_scripts ( - script_root TEXT NOT NULL, -- Note script root + script_root BLOB NOT NULL, -- Note script root serialized_note_script BLOB, -- NoteScript, serialized PRIMARY KEY (script_root) diff --git a/crates/sqlite-store/src/transaction.rs b/crates/sqlite-store/src/transaction.rs index 7a1dddc51..f15fd6ccf 100644 --- a/crates/sqlite-store/src/transaction.rs +++ b/crates/sqlite-store/src/transaction.rs @@ -1,7 +1,7 @@ #![allow(clippy::items_after_statements)] use std::rc::Rc; -use std::string::{String, ToString}; +use std::string::ToString; use std::sync::{Arc, RwLock}; use std::vec::Vec; @@ -45,7 +45,7 @@ pub(crate) const INSERT_TRANSACTION_SCRIPT_QUERY: &str = struct SerializedTransactionData { /// Transaction ID - id: String, + id: Vec, /// Script root script_root: Option>, /// Transaction script @@ -62,7 +62,7 @@ struct SerializedTransactionData { struct SerializedTransactionParts { /// Transaction ID - id: String, + id: Vec, /// Transaction script tx_script: Option>, /// Transaction details @@ -79,14 +79,12 @@ impl SqliteStore { ) -> Result, StoreError> { match filter { TransactionFilter::Ids(ids) => { - // Convert transaction IDs to strings for the array parameter - let id_strings = - ids.iter().map(|id| Value::Text(id.to_string())).collect::>(); + let id_blobs = ids.iter().map(|id| Value::Blob(id.to_bytes())).collect::>(); // Create a prepared statement and bind the array parameter conn.prepare(filter.to_query().as_ref()) .into_store_error()? - .query_map(params![Rc::new(id_strings)], parse_transaction_columns) + .query_map(params![Rc::new(id_blobs)], parse_transaction_columns) .into_store_error()? .map(|result| Ok(result.into_store_error()?).and_then(parse_transaction)) .collect::, _>>() @@ -278,7 +276,7 @@ pub(crate) fn upsert_transaction_record( /// Serializes the transaction record into a format suitable for storage in the database. fn serialize_transaction_data(transaction_record: &TransactionRecord) -> SerializedTransactionData { - let transaction_id: String = transaction_record.id.to_hex(); + let transaction_id = transaction_record.id.to_bytes(); let script_root = transaction_record.script.as_ref().map(|script| script.root().to_bytes()); let tx_script = transaction_record.script.as_ref().map(TransactionScript::to_bytes); @@ -297,7 +295,7 @@ fn serialize_transaction_data(transaction_record: &TransactionRecord) -> Seriali fn parse_transaction_columns( row: &rusqlite::Row<'_>, ) -> Result { - let id: String = row.get(0)?; + let id: Vec = row.get(0)?; let tx_script: Option> = row.get(1)?; let details: Vec = row.get(2)?; let status: Vec = row.get(3)?; @@ -311,14 +309,14 @@ fn parse_transaction( ) -> Result { let SerializedTransactionParts { id, tx_script, details, status } = serialized_transaction; - let id: Word = id.as_str().try_into()?; + let id = TransactionId::read_from_bytes(&id)?; let script: Option = tx_script .map(|script| TransactionScript::read_from_bytes(&script)) .transpose()?; Ok(TransactionRecord { - id: TransactionId::from_raw(id), + id, details: TransactionDetails::read_from_bytes(&details)?, script, status: TransactionStatus::read_from_bytes(&status)?,