From 15785b9079cc78a7c1f9bf0e14e0c13c2e5df035 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 19 Feb 2026 20:09:48 +0000 Subject: [PATCH 1/2] Initial plan From 6b06025b9799b29dd148ef35ffeff05d098ebe45 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 19 Feb 2026 20:35:40 +0000 Subject: [PATCH 2/2] chore: resolve merge conflicts with next branch (incorporate be2771da) Co-authored-by: mmagician <8402446+mmagician@users.noreply.github.com> --- Cargo.lock | 23 ++- Cargo.toml | 2 + crates/db/Cargo.toml | 23 +++ crates/db/src/conv.rs | 183 ++++++++++++++++++ .../{ntx-builder/src/db => db/src}/errors.rs | 112 ++++++----- crates/db/src/lib.rs | 76 ++++++++ crates/{store/src/db => db/src}/manager.rs | 6 +- crates/ntx-builder/Cargo.toml | 4 +- crates/ntx-builder/src/db/manager.rs | 86 -------- crates/ntx-builder/src/db/migrations.rs | 2 +- crates/ntx-builder/src/db/mod.rs | 116 ----------- crates/ntx-builder/src/db/schema_hash.rs | 5 +- crates/ntx-builder/src/lib.rs | 4 +- crates/store/Cargo.toml | 2 +- crates/store/src/db/migrations.rs | 2 +- crates/store/src/db/mod.rs | 94 +++------ crates/store/src/db/models/queries/notes.rs | 17 +- crates/store/src/db/schema_hash.rs | 8 +- crates/store/src/errors.rs | 134 +------------ crates/store/src/lib.rs | 3 +- crates/validator/Cargo.toml | 3 +- crates/validator/src/block_validation/mod.rs | 2 +- crates/validator/src/db/migrations.rs | 2 +- crates/validator/src/db/mod.rs | 9 +- crates/validator/src/db/models.rs | 2 +- crates/validator/src/server/mod.rs | 7 +- 26 files changed, 439 insertions(+), 488 deletions(-) create mode 100644 crates/db/Cargo.toml create mode 100644 crates/db/src/conv.rs rename crates/{ntx-builder/src/db => db/src}/errors.rs (51%) create mode 100644 crates/db/src/lib.rs rename crates/{store/src/db => db/src}/manager.rs (95%) delete mode 100644 crates/ntx-builder/src/db/manager.rs diff --git a/Cargo.lock b/Cargo.lock index 74529eeb24..89c88cad89 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1026,7 +1026,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "524bc3df0d57e98ecd022e21ba31166c2625e7d3e5bcc4510efaeeab4abcab04" dependencies = [ "deadpool-runtime", - "tracing", ] [[package]] @@ -2810,6 +2809,19 @@ dependencies = [ "winterfell", ] +[[package]] +name = "miden-node-db" +version = "0.14.0" +dependencies = [ + "deadpool", + "deadpool-diesel", + "deadpool-sync", + "diesel", + "miden-protocol", + "thiserror 2.0.18", + "tracing", +] + [[package]] name = "miden-node-grpc-error-macro" version = "0.14.0" @@ -2823,14 +2835,12 @@ name = "miden-node-ntx-builder" version = "0.14.0" dependencies = [ "anyhow", - "deadpool", - "deadpool-diesel", - "deadpool-sync", "diesel", "diesel_migrations", "futures", "indexmap 2.13.0", "libsqlite3-sys", + "miden-node-db", "miden-node-proto", "miden-node-test-macro", "miden-node-utils", @@ -2928,7 +2938,6 @@ dependencies = [ "criterion", "deadpool", "deadpool-diesel", - "deadpool-sync", "diesel", "diesel_migrations", "fs-err", @@ -2938,6 +2947,7 @@ dependencies = [ "libsqlite3-sys", "miden-block-prover", "miden-crypto", + "miden-node-db", "miden-node-proto", "miden-node-proto-build", "miden-node-rocksdb-cxx-linkage-fix", @@ -3027,12 +3037,11 @@ name = "miden-node-validator" version = "0.14.0" dependencies = [ "anyhow", - "deadpool-diesel", "diesel", "diesel_migrations", + "miden-node-db", "miden-node-proto", "miden-node-proto-build", - "miden-node-store", "miden-node-utils", "miden-protocol", "miden-tx", diff --git a/Cargo.toml b/Cargo.toml index db02abc0d1..116e3548c8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,6 +5,7 @@ members = [ "bin/remote-prover", "bin/stress-test", "crates/block-producer", + "crates/db", "crates/grpc-error-macro", "crates/ntx-builder", "crates/proto", @@ -41,6 +42,7 @@ debug = true [workspace.dependencies] # Workspace crates. miden-node-block-producer = { path = "crates/block-producer", version = "0.14" } +miden-node-db = { path = "crates/db", version = "0.14" } miden-node-grpc-error-macro = { path = "crates/grpc-error-macro", version = "0.14" } miden-node-ntx-builder = { path = "crates/ntx-builder", version = "0.14" } miden-node-proto = { path = "crates/proto", version = "0.14" } diff --git a/crates/db/Cargo.toml b/crates/db/Cargo.toml new file mode 100644 index 0000000000..2a42af4305 --- /dev/null +++ b/crates/db/Cargo.toml @@ -0,0 +1,23 @@ +[package] +authors.workspace = true +description = "Shared database capabilities for Miden node" +edition.workspace = true +homepage.workspace = true +keywords = ["database", "miden", "node"] +license.workspace = true +name = "miden-node-db" +repository.workspace = true +rust-version.workspace = true +version.workspace = true + +[lints] +workspace = true + +[dependencies] +deadpool = { default-features = false, workspace = true } +deadpool-diesel = { features = ["sqlite"], workspace = true } +deadpool-sync = { default-features = false, workspace = true } +diesel = { features = ["sqlite"], workspace = true } +miden-protocol = { workspace = true } +thiserror = { workspace = true } +tracing = { workspace = true } diff --git a/crates/db/src/conv.rs b/crates/db/src/conv.rs new file mode 100644 index 0000000000..64c853c73d --- /dev/null +++ b/crates/db/src/conv.rs @@ -0,0 +1,183 @@ +//! Central place to define conversion from and to database primitive types +//! +//! Eventually, all of them should have types and we can implement a trait for them +//! rather than function pairs. +//! +//! Notice: All of them are infallible. The invariant is a sane content of the database +//! and humans ensure the sanity of casts. +//! +//! Notice: Keep in mind if you _need_ to expand the datatype, only if you require sorting this is +//! mandatory! +//! +//! Notice: Ensure you understand what casting does at the bit-level before changing any. +//! +//! Notice: Changing any of these are _backwards-incompatible_ changes that are not caught/covered +//! by migrations! + +#![expect( + clippy::inline_always, + reason = "Just unification helpers of 1-2 lines of casting types" +)] +#![expect( + dead_code, + reason = "Not all converters are used bidirectionally, however, keeping them is a good thing" +)] +#![expect( + clippy::cast_sign_loss, + reason = "This is the one file where we map the signed database types to the working types" +)] +#![expect( + clippy::cast_possible_wrap, + reason = "We will not approach the item count where i64 and usize casting will cause issues + on relevant platforms" +)] + +use miden_protocol::Felt; +use miden_protocol::account::{StorageSlotName, StorageSlotType}; +use miden_protocol::block::BlockNumber; +use miden_protocol::note::NoteTag; + +#[derive(Debug, thiserror::Error)] +#[error("failed to convert from database type {from_type} into {into_type}")] +pub struct DatabaseTypeConversionError { + source: Box, + from_type: &'static str, + into_type: &'static str, +} + +/// Convert from and to it's database representation and back +/// +/// We do not assume sanity of DB types. +pub trait SqlTypeConvert: Sized { + type Raw: Sized; + + fn to_raw_sql(self) -> Self::Raw; + fn from_raw_sql(_raw: Self::Raw) -> Result; + + fn map_err( + source: E, + ) -> DatabaseTypeConversionError { + DatabaseTypeConversionError { + source: Box::new(source), + from_type: std::any::type_name::(), + into_type: std::any::type_name::(), + } + } +} + +impl SqlTypeConvert for BlockNumber { + type Raw = i64; + + fn from_raw_sql(raw: Self::Raw) -> Result { + u32::try_from(raw).map(BlockNumber::from).map_err(Self::map_err) + } + + fn to_raw_sql(self) -> Self::Raw { + i64::from(self.as_u32()) + } +} + +impl SqlTypeConvert for NoteTag { + type Raw = i32; + + #[inline(always)] + fn from_raw_sql(raw: Self::Raw) -> Result { + #[expect(clippy::cast_sign_loss)] + Ok(NoteTag::new(raw as u32)) + } + + #[inline(always)] + fn to_raw_sql(self) -> Self::Raw { + self.as_u32() as i32 + } +} + +impl SqlTypeConvert for StorageSlotType { + type Raw = i32; + + #[inline(always)] + fn from_raw_sql(raw: Self::Raw) -> Result { + #[derive(Debug, thiserror::Error)] + #[error("invalid storage slot type value {0}")] + struct ValueError(i32); + + Ok(match raw { + 0 => StorageSlotType::Value, + 1 => StorageSlotType::Map, + invalid => { + return Err(Self::map_err(ValueError(invalid))); + }, + }) + } + + #[inline(always)] + fn to_raw_sql(self) -> Self::Raw { + match self { + StorageSlotType::Value => 0, + StorageSlotType::Map => 1, + } + } +} + +impl SqlTypeConvert for StorageSlotName { + type Raw = String; + + fn from_raw_sql(raw: Self::Raw) -> Result { + StorageSlotName::new(raw).map_err(Self::map_err) + } + + fn to_raw_sql(self) -> Self::Raw { + String::from(self) + } +} + +// Raw type conversions - eventually introduce wrapper types +// =========================================================== + +#[inline(always)] +pub(crate) fn raw_sql_to_nullifier_prefix(raw: i32) -> u16 { + debug_assert!(raw >= 0); + raw as u16 +} +#[inline(always)] +pub(crate) fn nullifier_prefix_to_raw_sql(prefix: u16) -> i32 { + i32::from(prefix) +} + +#[inline(always)] +pub(crate) fn raw_sql_to_nonce(raw: i64) -> Felt { + debug_assert!(raw >= 0); + Felt::new(raw as u64) +} +#[inline(always)] +pub(crate) fn nonce_to_raw_sql(nonce: Felt) -> i64 { + nonce.as_int() as i64 +} + +#[inline(always)] +pub(crate) fn raw_sql_to_fungible_delta(raw: i64) -> i64 { + raw +} +#[inline(always)] +pub(crate) fn fungible_delta_to_raw_sql(delta: i64) -> i64 { + delta +} + +#[inline(always)] +#[expect(clippy::cast_sign_loss)] +pub(crate) fn raw_sql_to_note_type(raw: i32) -> u8 { + raw as u8 +} +#[inline(always)] +pub(crate) fn note_type_to_raw_sql(note_type: u8) -> i32 { + i32::from(note_type) +} + +#[inline(always)] +pub(crate) fn raw_sql_to_idx(raw: i32) -> usize { + raw as usize +} +#[inline(always)] +pub(crate) fn idx_to_raw_sql(idx: usize) -> i32 { + idx as i32 +} diff --git a/crates/ntx-builder/src/db/errors.rs b/crates/db/src/errors.rs similarity index 51% rename from crates/ntx-builder/src/db/errors.rs rename to crates/db/src/errors.rs index 1ea43e3824..222f1166e1 100644 --- a/crates/ntx-builder/src/db/errors.rs +++ b/crates/db/src/errors.rs @@ -1,59 +1,19 @@ -use deadpool_sync::InteractError; - -use crate::db::manager::ConnectionManagerError; - -// DATABASE ERRORS -// ================================================================================================ - -#[derive(Debug, thiserror::Error)] -pub enum DatabaseError { - #[error("setup deadpool connection pool failed")] - ConnectionPoolObtainError(#[from] Box), - #[error(transparent)] - Diesel(#[from] diesel::result::Error), - #[error("SQLite pool interaction failed: {0}")] - InteractError(String), - #[error("schema verification failed")] - SchemaVerification(#[from] SchemaVerificationError), - #[error("connection manager error")] - ConnectionManager(#[source] ConnectionManagerError), -} +use std::any::type_name; +use std::io; -impl DatabaseError { - /// Converts from `InteractError`. - /// - /// Required since `InteractError` has at least one enum variant that is _not_ `Send + - /// Sync` and hence prevents the `Sync` auto implementation. This does an internal - /// conversion to string while maintaining convenience. - pub fn interact(msg: &(impl ToString + ?Sized), e: &InteractError) -> Self { - let msg = msg.to_string(); - Self::InteractError(format!("{msg} failed: {e:?}")) - } -} - -// DATABASE SETUP ERRORS -// ================================================================================================ - -#[derive(Debug, thiserror::Error)] -pub enum DatabaseSetupError { - #[error("I/O error")] - Io(#[from] std::io::Error), - #[error("database error")] - Database(#[from] DatabaseError), - #[error("pool build error")] - PoolBuild(#[source] deadpool::managed::BuildError), -} +use deadpool_sync::InteractError; +use thiserror::Error; -// SCHEMA VERIFICATION ERRORS -// ================================================================================================ +// SCHEMA VERIFICATION ERROR +// ================================================================================================= /// Errors that can occur during schema verification. -#[derive(Debug, thiserror::Error)] +#[derive(Debug, Error)] pub enum SchemaVerificationError { #[error("failed to create in-memory reference database")] InMemoryDbCreation(#[source] diesel::ConnectionError), #[error("failed to apply migrations to reference database")] - MigrationApplication(#[source] Box), + MigrationApplication(#[source] Box), #[error("failed to extract schema from database")] SchemaExtraction(#[source] diesel::result::Error), #[error( @@ -67,3 +27,59 @@ pub enum SchemaVerificationError { extra_count: usize, }, } + +// DATABASE ERROR +// ================================================================================================= + +#[derive(Debug, Error)] +pub enum DatabaseError { + #[error("SQLite pool interaction failed: {0}")] + InteractError(String), + #[error("setup deadpool connection pool failed")] + ConnectionPoolObtainError(#[from] Box), + #[error("conversion from SQL to rust type {to} failed")] + ConversionSqlToRust { + #[source] + inner: Option>, + to: &'static str, + }, + #[error(transparent)] + Diesel(#[from] diesel::result::Error), + #[error("schema verification failed")] + SchemaVerification(#[from] SchemaVerificationError), + #[error("I/O error")] + Io(#[from] io::Error), + #[error("pool build error")] + PoolBuild(#[from] deadpool::managed::BuildError), + #[error("Setup deadpool connection pool failed")] + Pool(#[from] deadpool::managed::PoolError), +} + +impl DatabaseError { + /// Converts from `InteractError` + /// + /// Note: Required since `InteractError` has at least one enum + /// variant that is _not_ `Send + Sync` and hence prevents the + /// `Sync` auto implementation. + /// This does an internal conversion to string while maintaining + /// convenience. + /// + /// Using `MSG` as const so it can be called as + /// `.map_err(DatabaseError::interact::<"Your message">)` + pub fn interact(msg: &(impl ToString + ?Sized), e: &InteractError) -> Self { + let msg = msg.to_string(); + Self::InteractError(format!("{msg} failed: {e:?}")) + } + + /// Failed to convert an SQL entry to a rust representation + pub fn conversiont_from_sql(err: MaybeE) -> DatabaseError + where + MaybeE: Into>, + E: std::error::Error + Send + Sync + 'static, + { + DatabaseError::ConversionSqlToRust { + inner: err.into().map(|err| Box::new(err) as Box), + to: type_name::(), + } + } +} diff --git a/crates/db/src/lib.rs b/crates/db/src/lib.rs new file mode 100644 index 0000000000..c3358eae3d --- /dev/null +++ b/crates/db/src/lib.rs @@ -0,0 +1,76 @@ +mod conv; +mod errors; +mod manager; + +use std::path::Path; + +pub use conv::{DatabaseTypeConversionError, SqlTypeConvert}; +use diesel::{RunQueryDsl, SqliteConnection}; +pub use errors::{DatabaseError, SchemaVerificationError}; +pub use manager::{ConnectionManager, ConnectionManagerError, configure_connection_on_creation}; +use tracing::Instrument; + +pub type Result = std::result::Result; + +/// Database handle that provides fundamental operations that various components of Miden Node can +/// utililze for their storage needs. +pub struct Db { + pool: deadpool_diesel::Pool>, +} + +impl Db { + /// Creates a new database instance with the provided connection pool. + pub fn new(database_filepath: &Path) -> Result { + let manager = ConnectionManager::new(database_filepath.to_str().unwrap()); + let pool = deadpool_diesel::Pool::builder(manager).max_size(16).build()?; + Ok(Self { pool }) + } + + /// Create and commit a transaction with the queries added in the provided closure + pub async fn transact(&self, msg: M, query: Q) -> std::result::Result + where + Q: Send + + for<'a, 't> FnOnce(&'a mut SqliteConnection) -> std::result::Result + + 'static, + R: Send + 'static, + M: Send + ToString, + E: From, + E: From, + E: std::error::Error + Send + Sync + 'static, + { + let conn = self + .pool + .get() + .in_current_span() + .await + .map_err(|e| DatabaseError::ConnectionPoolObtainError(Box::new(e)))?; + + conn.interact(|conn| <_ as diesel::Connection>::transaction::(conn, query)) + .in_current_span() + .await + .map_err(|err| E::from(DatabaseError::interact(&msg.to_string(), &err)))? + } + + /// Run the query _without_ a transaction + pub async fn query(&self, msg: M, query: Q) -> std::result::Result + where + Q: Send + FnOnce(&mut SqliteConnection) -> std::result::Result + 'static, + R: Send + 'static, + M: Send + ToString, + E: From, + E: std::error::Error + Send + Sync + 'static, + { + let conn = self + .pool + .get() + .await + .map_err(|e| DatabaseError::ConnectionPoolObtainError(Box::new(e)))?; + + conn.interact(move |conn| { + let r = query(conn)?; + Ok(r) + }) + .await + .map_err(|err| E::from(DatabaseError::interact(&msg.to_string(), &err)))? + } +} diff --git a/crates/store/src/db/manager.rs b/crates/db/src/manager.rs similarity index 95% rename from crates/store/src/db/manager.rs rename to crates/db/src/manager.rs index 5ac72e0ad8..e3b21be184 100644 --- a/crates/store/src/db/manager.rs +++ b/crates/db/src/manager.rs @@ -75,11 +75,11 @@ impl deadpool::managed::Manager for ConnectionManager { } } -pub(crate) fn configure_connection_on_creation( +pub fn configure_connection_on_creation( conn: &mut SqliteConnection, ) -> Result<(), ConnectionManagerError> { - // Wait up to 5 seconds for writer locks before erroring. - diesel::sql_query("PRAGMA busy_timeout=5000") + // Wait up to 3 seconds for writer locks before erroring. + diesel::sql_query("PRAGMA busy_timeout=3000") .execute(conn) .map_err(ConnectionManagerError::ConnectionParamSetup)?; diff --git a/crates/ntx-builder/Cargo.toml b/crates/ntx-builder/Cargo.toml index 1d34db1282..169a47207a 100644 --- a/crates/ntx-builder/Cargo.toml +++ b/crates/ntx-builder/Cargo.toml @@ -15,14 +15,12 @@ workspace = true [dependencies] anyhow = { workspace = true } -deadpool = { features = ["managed", "rt_tokio_1"], workspace = true } -deadpool-diesel = { features = ["sqlite"], workspace = true } -deadpool-sync = { features = ["tracing"], workspace = true } diesel = { features = ["numeric", "sqlite"], workspace = true } diesel_migrations = { features = ["sqlite"], workspace = true } futures = { workspace = true } indexmap = { workspace = true } libsqlite3-sys = { workspace = true } +miden-node-db = { workspace = true } miden-node-proto = { workspace = true } miden-node-utils = { workspace = true } miden-protocol = { default-features = true, workspace = true } diff --git a/crates/ntx-builder/src/db/manager.rs b/crates/ntx-builder/src/db/manager.rs deleted file mode 100644 index 4234e09dde..0000000000 --- a/crates/ntx-builder/src/db/manager.rs +++ /dev/null @@ -1,86 +0,0 @@ -//! A minimal connection manager wrapper. -//! -//! Only required to setup connection parameters, specifically `WAL`. - -use deadpool_sync::InteractError; -use diesel::{RunQueryDsl, SqliteConnection}; - -#[derive(thiserror::Error, Debug)] -pub enum ConnectionManagerError { - #[error("failed to apply connection parameter")] - ConnectionParamSetup(#[source] diesel::result::Error), - #[error("SQLite pool interaction failed: {0}")] - InteractError(String), - #[error("failed to create a new connection")] - ConnectionCreate(#[source] deadpool_diesel::Error), - #[error("failed to recycle connection")] - PoolRecycle(#[source] deadpool::managed::RecycleError), -} - -impl ConnectionManagerError { - /// Converts from `InteractError`. - /// - /// Required since `InteractError` has at least one enum variant that is _not_ `Send + - /// Sync` and hence prevents the `Sync` auto implementation. - pub fn interact(msg: &(impl ToString + ?Sized), e: &InteractError) -> Self { - let msg = msg.to_string(); - Self::InteractError(format!("{msg} failed: {e:?}")) - } -} - -/// Create a connection manager with per-connection setup. -/// -/// Particularly, `foreign_key` checks are enabled and using a write-append-log for journaling. -pub(crate) struct ConnectionManager { - pub(crate) manager: deadpool_diesel::sqlite::Manager, -} - -impl ConnectionManager { - pub(crate) fn new(database_path: &str) -> Self { - let manager = deadpool_diesel::sqlite::Manager::new( - database_path.to_owned(), - deadpool_diesel::sqlite::Runtime::Tokio1, - ); - Self { manager } - } -} - -impl deadpool::managed::Manager for ConnectionManager { - type Type = deadpool_sync::SyncWrapper; - type Error = ConnectionManagerError; - - async fn create(&self) -> Result { - let conn = self.manager.create().await.map_err(ConnectionManagerError::ConnectionCreate)?; - - conn.interact(configure_connection_on_creation) - .await - .map_err(|e| ConnectionManagerError::interact("Connection setup", &e))??; - Ok(conn) - } - - async fn recycle( - &self, - conn: &mut Self::Type, - metrics: &deadpool_diesel::Metrics, - ) -> deadpool::managed::RecycleResult { - self.manager.recycle(conn, metrics).await.map_err(|err| { - deadpool::managed::RecycleError::Backend(ConnectionManagerError::PoolRecycle(err)) - })?; - Ok(()) - } -} - -pub(crate) fn configure_connection_on_creation( - conn: &mut SqliteConnection, -) -> Result<(), ConnectionManagerError> { - // Enable the WAL mode. This allows concurrent reads while a write is in progress. - diesel::sql_query("PRAGMA journal_mode=WAL") - .execute(conn) - .map_err(ConnectionManagerError::ConnectionParamSetup)?; - - // Enable foreign key checks. - diesel::sql_query("PRAGMA foreign_keys=ON") - .execute(conn) - .map_err(ConnectionManagerError::ConnectionParamSetup)?; - Ok(()) -} diff --git a/crates/ntx-builder/src/db/migrations.rs b/crates/ntx-builder/src/db/migrations.rs index 069bdd4111..f3955cb2ad 100644 --- a/crates/ntx-builder/src/db/migrations.rs +++ b/crates/ntx-builder/src/db/migrations.rs @@ -1,9 +1,9 @@ use diesel::SqliteConnection; use diesel_migrations::{EmbeddedMigrations, MigrationHarness, embed_migrations}; +use miden_node_db::DatabaseError; use tracing::instrument; use crate::COMPONENT; -use crate::db::errors::DatabaseError; use crate::db::schema_hash::verify_schema; // The rebuild is automatically triggered by `build.rs` as described in diff --git a/crates/ntx-builder/src/db/mod.rs b/crates/ntx-builder/src/db/mod.rs index 488673b916..3d1c27bee7 100644 --- a/crates/ntx-builder/src/db/mod.rs +++ b/crates/ntx-builder/src/db/mod.rs @@ -1,121 +1,5 @@ -use std::path::PathBuf; - -use anyhow::Context; -use diesel::{Connection, SqliteConnection}; -use tracing::{info, instrument}; - -use crate::COMPONENT; -use crate::db::errors::{DatabaseError, DatabaseSetupError}; -use crate::db::manager::{ConnectionManager, configure_connection_on_creation}; -use crate::db::migrations::apply_migrations; - -pub mod errors; -pub(crate) mod manager; - mod migrations; mod schema_hash; /// [diesel](https://diesel.rs) generated schema. pub(crate) mod schema; - -pub type Result = std::result::Result; - -pub struct Db { - pool: deadpool_diesel::Pool>, -} - -impl Db { - /// Creates a new database file, configures it, and applies migrations. - /// - /// This is a synchronous one-shot setup used during node initialization. - /// For runtime access with a connection pool, use [`Db::load`]. - #[instrument( - target = COMPONENT, - name = "ntx_builder.database.bootstrap", - skip_all, - fields(path=%database_filepath.display()), - err, - )] - pub fn bootstrap(database_filepath: PathBuf) -> anyhow::Result<()> { - let mut conn: SqliteConnection = diesel::sqlite::SqliteConnection::establish( - database_filepath.to_str().context("database filepath is invalid")?, - ) - .context("failed to open a database connection")?; - - configure_connection_on_creation(&mut conn)?; - - // Run migrations. - apply_migrations(&mut conn).context("failed to apply database migrations")?; - - Ok(()) - } - - /// Create and commit a transaction with the queries added in the provided closure. - #[expect(dead_code)] - pub(crate) async fn transact(&self, msg: M, query: Q) -> std::result::Result - where - Q: Send - + for<'a, 't> FnOnce(&'a mut SqliteConnection) -> std::result::Result - + 'static, - R: Send + 'static, - M: Send + ToString, - E: From, - E: From, - E: std::error::Error + Send + Sync + 'static, - { - let conn = self - .pool - .get() - .await - .map_err(|e| DatabaseError::ConnectionPoolObtainError(Box::new(e)))?; - - conn.interact(|conn| <_ as diesel::Connection>::transaction::(conn, query)) - .await - .map_err(|err| E::from(DatabaseError::interact(&msg.to_string(), &err)))? - } - - /// Run the query _without_ a transaction. - pub(crate) async fn query(&self, msg: M, query: Q) -> std::result::Result - where - Q: Send + FnOnce(&mut SqliteConnection) -> std::result::Result + 'static, - R: Send + 'static, - M: Send + ToString, - E: From, - E: std::error::Error + Send + Sync + 'static, - { - let conn = self - .pool - .get() - .await - .map_err(|e| DatabaseError::ConnectionPoolObtainError(Box::new(e)))?; - - conn.interact(move |conn| { - let r = query(conn)?; - Ok(r) - }) - .await - .map_err(|err| E::from(DatabaseError::interact(&msg.to_string(), &err)))? - } - - /// Opens a connection pool to an existing database and re-applies pending migrations. - /// - /// Use [`Db::bootstrap`] first to create and initialize the database file. - #[instrument(target = COMPONENT, skip_all)] - pub async fn load(database_filepath: PathBuf) -> Result { - let manager = ConnectionManager::new(database_filepath.to_str().unwrap()); - let pool = deadpool_diesel::Pool::builder(manager) - .max_size(16) - .build() - .map_err(DatabaseSetupError::PoolBuild)?; - - info!( - target: COMPONENT, - sqlite = %database_filepath.display(), - "Connected to the database" - ); - - let me = Db { pool }; - me.query("migrations", apply_migrations).await?; - Ok(me) - } -} diff --git a/crates/ntx-builder/src/db/schema_hash.rs b/crates/ntx-builder/src/db/schema_hash.rs index 21ebb0c7b4..80d00b4c47 100644 --- a/crates/ntx-builder/src/db/schema_hash.rs +++ b/crates/ntx-builder/src/db/schema_hash.rs @@ -11,10 +11,10 @@ use diesel::{Connection, RunQueryDsl, SqliteConnection}; use diesel_migrations::MigrationHarness; +use miden_node_db::SchemaVerificationError; use tracing::instrument; use crate::COMPONENT; -use crate::db::errors::SchemaVerificationError; use crate::db::migrations::MIGRATIONS; /// Represents a schema object for comparison. @@ -131,8 +131,9 @@ pub fn verify_schema(conn: &mut SqliteConnection) -> Result<(), SchemaVerificati #[cfg(test)] mod tests { + use miden_node_db::DatabaseError; + use super::*; - use crate::db::errors::DatabaseError; use crate::db::migrations::apply_migrations; #[test] diff --git a/crates/ntx-builder/src/lib.rs b/crates/ntx-builder/src/lib.rs index d77a8dd7de..04c631c054 100644 --- a/crates/ntx-builder/src/lib.rs +++ b/crates/ntx-builder/src/lib.rs @@ -16,7 +16,9 @@ mod actor; mod block_producer; mod builder; mod coordinator; -#[expect(dead_code, reason = "will be used as part of follow-up work")] +// TODO(santi): Remove this attr when the module is actually used. Dead code lint fails due to the +// tests. +#[cfg(test)] pub(crate) mod db; mod store; diff --git a/crates/store/Cargo.toml b/crates/store/Cargo.toml index 5ce4daee74..82466fcba0 100644 --- a/crates/store/Cargo.toml +++ b/crates/store/Cargo.toml @@ -18,7 +18,6 @@ workspace = true anyhow = { workspace = true } deadpool = { default-features = false, features = ["managed", "rt_tokio_1"], version = "0.12" } deadpool-diesel = { features = ["sqlite"], version = "0.6" } -deadpool-sync = { default-features = false, features = ["tracing"], version = "0.1" } diesel = { features = ["numeric", "sqlite"], version = "2.3" } diesel_migrations = { features = ["sqlite"], version = "2.3" } fs-err = { workspace = true } @@ -28,6 +27,7 @@ indexmap = { workspace = true } libsqlite3-sys = { workspace = true } miden-block-prover = { workspace = true } miden-crypto = { features = ["concurrent", "hashmaps"], workspace = true } +miden-node-db = { workspace = true } miden-node-proto = { workspace = true } miden-node-proto-build = { features = ["internal"], workspace = true } miden-node-utils = { workspace = true } diff --git a/crates/store/src/db/migrations.rs b/crates/store/src/db/migrations.rs index 8aa0f0a00e..10ce01409e 100644 --- a/crates/store/src/db/migrations.rs +++ b/crates/store/src/db/migrations.rs @@ -13,7 +13,7 @@ pub const MIGRATIONS: EmbeddedMigrations = embed_migrations!("src/db/migrations" #[instrument(level = "debug", target = COMPONENT, skip_all, err)] pub fn apply_migrations( conn: &mut SqliteConnection, -) -> std::result::Result<(), crate::errors::DatabaseError> { +) -> std::result::Result<(), miden_node_db::DatabaseError> { let migrations = conn.pending_migrations(MIGRATIONS).expect("In memory migrations never fail"); tracing::info!(target = COMPONENT, migrations = migrations.len(), "Applying migrations"); diff --git a/crates/store/src/db/mod.rs b/crates/store/src/db/mod.rs index 5ab4d55b11..803d532f08 100644 --- a/crates/store/src/db/mod.rs +++ b/crates/store/src/db/mod.rs @@ -1,5 +1,5 @@ use std::collections::{BTreeMap, BTreeSet, HashSet}; -use std::ops::RangeInclusive; +use std::ops::{Deref, DerefMut, RangeInclusive}; use std::path::PathBuf; use anyhow::Context; @@ -23,10 +23,9 @@ use miden_protocol::note::{ use miden_protocol::transaction::TransactionId; use miden_protocol::utils::{Deserializable, Serializable}; use tokio::sync::oneshot; -use tracing::{Instrument, info, instrument}; +use tracing::{info, instrument}; use crate::COMPONENT; -use crate::db::manager::{ConnectionManager, configure_connection_on_creation}; use crate::db::migrations::apply_migrations; use crate::db::models::conv::SqlTypeConvert; use crate::db::models::queries::StorageMapValuesPage; @@ -36,11 +35,9 @@ pub use crate::db::models::queries::{ PublicAccountIdsPage, }; use crate::db::models::{Page, queries}; -use crate::errors::{DatabaseError, DatabaseSetupError, NoteSyncError}; +use crate::errors::{DatabaseError, NoteSyncError}; use crate::genesis::GenesisBlock; -pub(crate) mod manager; - mod migrations; mod schema_hash; @@ -54,8 +51,25 @@ pub(crate) mod schema; pub type Result = std::result::Result; +/// The Store's database. +/// +/// Extends the underlying [`miden_node_db::Db`] type with functionality specific to the Store. pub struct Db { - pool: deadpool_diesel::Pool>, + db: miden_node_db::Db, +} + +impl Deref for Db { + type Target = miden_node_db::Db; + + fn deref(&self) -> &Self::Target { + &self.db + } +} + +impl DerefMut for Db { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.db + } } /// Describes the value of an asset for an account ID at `block_num` specifically. @@ -209,11 +223,6 @@ impl From for NoteSyncRecord { } impl Db { - /// Creates a new database instance with the provided connection pool. - pub fn new(pool: deadpool_diesel::Pool) -> Self { - Self { pool } - } - /// Creates a new database and inserts the genesis block. #[instrument( target = COMPONENT, @@ -233,7 +242,7 @@ impl Db { ) .context("failed to open a database connection")?; - configure_connection_on_creation(&mut conn)?; + miden_node_db::configure_connection_on_creation(&mut conn)?; // Run migrations. apply_migrations(&mut conn).context("failed to apply database migrations")?; @@ -255,69 +264,18 @@ impl Db { Ok(()) } - /// Create and commit a transaction with the queries added in the provided closure - pub async fn transact(&self, msg: M, query: Q) -> std::result::Result - where - Q: Send - + for<'a, 't> FnOnce(&'a mut SqliteConnection) -> std::result::Result - + 'static, - R: Send + 'static, - M: Send + ToString, - E: From, - E: From, - E: std::error::Error + Send + Sync + 'static, - { - let conn = self - .pool - .get() - .in_current_span() - .await - .map_err(|e| DatabaseError::ConnectionPoolObtainError(Box::new(e)))?; - - conn.interact(|conn| <_ as diesel::Connection>::transaction::(conn, query)) - .in_current_span() - .await - .map_err(|err| E::from(DatabaseError::interact(&msg.to_string(), &err)))? - } - - /// Run the query _without_ a transaction - pub async fn query(&self, msg: M, query: Q) -> std::result::Result - where - Q: Send + FnOnce(&mut SqliteConnection) -> std::result::Result + 'static, - R: Send + 'static, - M: Send + ToString, - E: From, - E: std::error::Error + Send + Sync + 'static, - { - let conn = self - .pool - .get() - .await - .map_err(|e| DatabaseError::ConnectionPoolObtainError(Box::new(e)))?; - - conn.interact(move |conn| { - let r = query(conn)?; - Ok(r) - }) - .await - .map_err(|err| E::from(DatabaseError::interact(&msg.to_string(), &err)))? - } - /// Open a connection to the DB and apply any pending migrations. #[instrument(target = COMPONENT, skip_all)] - pub async fn load(database_filepath: PathBuf) -> Result { - let manager = ConnectionManager::new(database_filepath.to_str().unwrap()); - let pool = deadpool_diesel::Pool::builder(manager).max_size(16).build()?; - + pub async fn load(database_filepath: PathBuf) -> Result { + let db = miden_node_db::Db::new(&database_filepath)?; info!( target: COMPONENT, sqlite= %database_filepath.display(), "Connected to the database" ); - let me = Db { pool }; - me.query("migrations", apply_migrations).await?; - Ok(me) + db.query("migrations", apply_migrations).await?; + Ok(Self { db }) } /// Returns a page of nullifiers for tree rebuilding. diff --git a/crates/store/src/db/models/queries/notes.rs b/crates/store/src/db/models/queries/notes.rs index 68c39c8a7b..49bdce4198 100644 --- a/crates/store/src/db/models/queries/notes.rs +++ b/crates/store/src/db/models/queries/notes.rs @@ -682,9 +682,14 @@ impl TryInto for NoteRecordWithScriptRawJoined { { let storage = NoteStorage::read_from_bytes(&storage[..])?; let serial_num = Word::read_from_bytes(&serial_num[..])?; - let script = script.ok_or_else(|| { - DatabaseError::conversiont_from_sql::(None) - })?; + let script = + script.ok_or_else(|| { + miden_node_db::DatabaseError::conversiont_from_sql::< + NoteRecipient, + DatabaseError, + _, + >(None) + })?; let recipient = NoteRecipient::new(serial_num, script, storage); let assets = NoteAssets::read_from_bytes(&assets[..])?; Some(NoteDetails::new(assets, recipient)) @@ -744,7 +749,7 @@ impl TryInto for NoteMetadataRawRow { fn try_into(self) -> Result { let sender = AccountId::read_from_bytes(&self.sender[..])?; let note_type = NoteType::try_from(self.note_type as u32) - .map_err(DatabaseError::conversiont_from_sql::)?; + .map_err(miden_node_db::DatabaseError::conversiont_from_sql::)?; let tag = NoteTag::new(self.tag as u32); let attachment = NoteAttachment::read_from_bytes(&self.attachment)?; Ok(NoteMetadata::new(sender, note_type).with_tag(tag).with_attachment(attachment)) @@ -766,7 +771,9 @@ impl TryInto for BlockNoteIndexRawRow { let batch_index = self.batch_index as usize; let note_index = self.note_index as usize; let index = BlockNoteIndex::new(batch_index, note_index).ok_or_else(|| { - DatabaseError::conversiont_from_sql::(None) + miden_node_db::DatabaseError::conversiont_from_sql::( + None, + ) })?; Ok(index) } diff --git a/crates/store/src/db/schema_hash.rs b/crates/store/src/db/schema_hash.rs index bcb417ce9f..9a5ad1328a 100644 --- a/crates/store/src/db/schema_hash.rs +++ b/crates/store/src/db/schema_hash.rs @@ -11,11 +11,11 @@ use diesel::{Connection, RunQueryDsl, SqliteConnection}; use diesel_migrations::MigrationHarness; +use miden_node_db::SchemaVerificationError; use tracing::instrument; use crate::COMPONENT; use crate::db::migrations::MIGRATIONS; -use crate::errors::SchemaVerificationError; /// Represents a schema object for comparison. #[derive(Debug, PartialEq, Eq, PartialOrd, Ord)] @@ -139,7 +139,6 @@ pub fn verify_schema(conn: &mut SqliteConnection) -> Result<(), SchemaVerificati mod tests { use super::*; use crate::db::migrations::apply_migrations; - use crate::errors::DatabaseError; #[test] fn verify_schema_passes_for_correct_schema() { @@ -191,6 +190,9 @@ mod tests { .execute(&mut conn) .unwrap(); - assert!(matches!(apply_migrations(&mut conn), Err(DatabaseError::SchemaVerification(_)))); + assert!(matches!( + apply_migrations(&mut conn), + Err(miden_node_db::DatabaseError::SchemaVerification(_)) + )); } } diff --git a/crates/store/src/errors.rs b/crates/store/src/errors.rs index 947a0bcfc2..61bbf3e996 100644 --- a/crates/store/src/errors.rs +++ b/crates/store/src/errors.rs @@ -1,7 +1,5 @@ -use std::any::type_name; use std::io; -use deadpool_sync::InteractError; use miden_node_proto::domain::account::NetworkAccountError; use miden_node_proto::domain::block::InvalidBlockRange; use miden_node_proto::errors::{ConversionError, GrpcError}; @@ -30,7 +28,6 @@ use thiserror::Error; use tokio::sync::oneshot::error::RecvError; use tonic::Status; -use crate::db::manager::ConnectionManagerError; use crate::db::models::conv::DatabaseTypeConversionError; use crate::inner_forest::{InnerForestError, WitnessError}; @@ -41,60 +38,30 @@ use crate::inner_forest::{InnerForestError, WitnessError}; pub enum DatabaseError { // ERRORS WITH AUTOMATIC CONVERSIONS FROM NESTED ERROR TYPES // --------------------------------------------------------------------------------------------- - #[error("account is incomplete")] - AccountIncomplete, #[error("account error")] AccountError(#[from] AccountError), - #[error("account delta error")] - AccountDeltaError(#[from] AccountDeltaError), #[error("asset vault error")] AssetVaultError(#[from] AssetVaultError), #[error("asset error")] AssetError(#[from] AssetError), #[error("closed channel")] ClosedChannel(#[from] RecvError), + #[error("database error")] + DatabaseError(#[from] miden_node_db::DatabaseError), #[error("deserialization failed")] DeserializationError(#[from] DeserializationError), - #[error("hex parsing error")] - FromHexError(#[from] hex::FromHexError), #[error("I/O error")] IoError(#[from] io::Error), #[error("merkle error")] MerkleError(#[from] MerkleError), - #[error("network account error")] - NetworkAccountError(#[from] NetworkAccountError), #[error("note error")] NoteError(#[from] NoteError), #[error("storage map error")] StorageMapError(#[from] StorageMapError), - #[error("setup deadpool connection pool failed")] - Deadpool(#[from] deadpool::managed::PoolError), - #[error("setup deadpool connection pool failed")] - ConnectionPoolObtainError(#[from] Box), #[error(transparent)] Diesel(#[from] diesel::result::Error), - #[error("sqlite FFI boundary NUL termination error (not much you can do, file an issue)")] - DieselSqliteFfi(#[from] std::ffi::NulError), - #[error(transparent)] - DeadpoolDiesel(#[from] deadpool_diesel::Error), - #[error(transparent)] - PoolRecycle(#[from] deadpool::managed::RecycleError), - #[error("summing over column {column} of table {table} exceeded {limit}")] - ColumnSumExceedsLimit { - table: &'static str, - column: &'static str, - limit: &'static str, - #[source] - source: Box, - }, #[error(transparent)] QueryParamLimit(#[from] QueryLimitError), - #[error("conversion from SQL to rust type {to} failed")] - ConversionSqlToRust { - #[source] - inner: Option>, - to: &'static str, - }, // OTHER ERRORS // --------------------------------------------------------------------------------------------- @@ -102,39 +69,16 @@ pub enum DatabaseError { AccountCommitmentsMismatch { expected: Word, calculated: Word }, #[error("account {0} not found")] AccountNotFoundInDb(AccountId), - #[error("account {0} state at block height {1} not found")] - AccountAtBlockHeightNotFoundInDb(AccountId, BlockNumber), - #[error("block {0} not found in database")] - BlockNotFound(BlockNumber), - #[error("historical block {block_num} not available: {reason}")] - HistoricalBlockNotAvailable { block_num: BlockNumber, reason: String }, #[error("accounts {0:?} not found")] AccountsNotFoundInDb(Vec), #[error("account {0} is not on the chain")] AccountNotPublic(AccountId), #[error("invalid block parameters: block_from ({from}) > block_to ({to})")] InvalidBlockRange { from: BlockNumber, to: BlockNumber }, - #[error("invalid storage slot type: {0}")] - InvalidStorageSlotType(i32), #[error("data corrupted: {0}")] DataCorrupted(String), - #[error("SQLite pool interaction failed: {0}")] - InteractError(String), - #[error("invalid Felt: {0}")] - InvalidFelt(String), - #[error( - "unsupported database version. There is no migration chain from/to this version. \ - Remove all database files and try again." - )] - UnsupportedDatabaseVersion, - #[error("schema verification failed")] - SchemaVerification(#[from] SchemaVerificationError), - #[error(transparent)] - ConnectionManager(#[from] ConnectionManagerError), #[error(transparent)] SqlValueConversion(#[from] DatabaseTypeConversionError), - #[error("Not implemented: {0}")] - NotImplemented(String), #[error("storage root not found for account {account_id}, slot {slot_name}, block {block_num}")] StorageRootNotFound { account_id: AccountId, @@ -143,35 +87,6 @@ pub enum DatabaseError { }, } -impl DatabaseError { - /// Converts from `InteractError` - /// - /// Note: Required since `InteractError` has at least one enum - /// variant that is _not_ `Send + Sync` and hence prevents the - /// `Sync` auto implementation. - /// This does an internal conversion to string while maintaining - /// convenience. - /// - /// Using `MSG` as const so it can be called as - /// `.map_err(DatabaseError::interact::<"Your message">)` - pub fn interact(msg: &(impl ToString + ?Sized), e: &InteractError) -> Self { - let msg = msg.to_string(); - Self::InteractError(format!("{msg} failed: {e:?}")) - } - - /// Failed to convert an SQL entry to a rust representation - pub fn conversiont_from_sql(err: MaybeE) -> DatabaseError - where - MaybeE: Into>, - E: std::error::Error + Send + Sync + 'static, - { - DatabaseError::ConversionSqlToRust { - inner: err.into().map(|err| Box::new(err) as Box), - to: type_name::(), - } - } -} - impl From for Status { fn from(err: DatabaseError) -> Self { match err { @@ -204,7 +119,7 @@ pub enum StateInitializationError { #[error("failed to load block store")] BlockStoreLoadError(#[source] std::io::Error), #[error("failed to load database")] - DatabaseLoadError(#[from] DatabaseSetupError), + DatabaseLoadError(#[from] miden_node_db::DatabaseError), #[error("inner forest error")] InnerForestError(#[from] InnerForestError), #[error( @@ -224,20 +139,6 @@ pub enum StateInitializationError { AccountToDeltaConversionFailed(String), } -#[derive(Debug, Error)] -pub enum DatabaseSetupError { - #[error("I/O error")] - Io(#[from] io::Error), - #[error("database error")] - Database(#[from] DatabaseError), - #[error("genesis block error")] - GenesisBlock(#[from] GenesisError), - #[error("pool build error")] - PoolBuild(#[from] deadpool::managed::BuildError), - #[error("Setup deadpool connection pool failed")] - Pool(#[from] deadpool::managed::PoolError), -} - #[derive(Debug, Error)] pub enum GenesisError { // ERRORS WITH AUTOMATIC CONVERSIONS FROM NESTED ERROR TYPES @@ -383,6 +284,9 @@ pub enum NoteSyncError { #[error("database error")] #[grpc(internal)] DatabaseError(#[from] DatabaseError), + #[error("database error")] + #[grpc(internal)] + UnderlyingDatabaseError(#[from] miden_node_db::DatabaseError), #[error("block headers table is empty")] #[grpc(internal)] EmptyBlockHeadersTable, @@ -590,30 +494,6 @@ pub enum GetWitnessesError { WitnessError(#[from] WitnessError), } -// SCHEMA VERIFICATION ERRORS -// ================================================================================================= - -/// Errors that can occur during schema verification. -#[derive(Debug, Error)] -pub enum SchemaVerificationError { - #[error("failed to create in-memory reference database")] - InMemoryDbCreation(#[source] diesel::ConnectionError), - #[error("failed to apply migrations to reference database")] - MigrationApplication(#[source] Box), - #[error("failed to extract schema from database")] - SchemaExtraction(#[source] diesel::result::Error), - #[error( - "schema mismatch: expected {expected_count} objects, found {actual_count} \ - ({missing_count} missing, {extra_count} unexpected)" - )] - Mismatch { - expected_count: usize, - actual_count: usize, - missing_count: usize, - extra_count: usize, - }, -} - #[cfg(test)] mod get_account_error_tests { use miden_protocol::account::AccountId; @@ -701,7 +581,6 @@ mod compile_tests { AccountDeltaError, AccountError, DatabaseError, - DatabaseSetupError, DeserializationError, GenesisError, NetworkAccountError, @@ -733,7 +612,6 @@ mod compile_tests { ensure_is_error::>(PhantomData); ensure_is_error::(PhantomData); - ensure_is_error::(PhantomData); ensure_is_error::(PhantomData); ensure_is_error::(PhantomData); ensure_is_error::(PhantomData); diff --git a/crates/store/src/lib.rs b/crates/store/src/lib.rs index 06bba2fe8a..519f8504b9 100644 --- a/crates/store/src/lib.rs +++ b/crates/store/src/lib.rs @@ -11,9 +11,8 @@ pub mod state; pub use accounts::PersistentAccountTree; pub use accounts::{AccountTreeWithHistory, HistoricalError, InMemoryAccountTree}; pub use db::Db; -pub use db::manager::ConnectionManager; pub use db::models::conv::SqlTypeConvert; -pub use errors::{DatabaseError, DatabaseSetupError}; +pub use errors::DatabaseError; pub use genesis::GenesisState; pub use server::block_prover_client::BlockProver; pub use server::{DataDirectory, Store}; diff --git a/crates/validator/Cargo.toml b/crates/validator/Cargo.toml index 26a76a2b3b..570f2a8d2d 100644 --- a/crates/validator/Cargo.toml +++ b/crates/validator/Cargo.toml @@ -18,12 +18,11 @@ workspace = true [dependencies] anyhow = { workspace = true } -deadpool-diesel = { workspace = true } diesel = { workspace = true } diesel_migrations = { workspace = true } +miden-node-db = { workspace = true } miden-node-proto = { workspace = true } miden-node-proto-build = { features = ["internal"], workspace = true } -miden-node-store = { workspace = true } miden-node-utils = { features = ["testing"], workspace = true } miden-protocol = { workspace = true } miden-tx = { workspace = true } diff --git a/crates/validator/src/block_validation/mod.rs b/crates/validator/src/block_validation/mod.rs index 853218ed5d..69b46c4e30 100644 --- a/crates/validator/src/block_validation/mod.rs +++ b/crates/validator/src/block_validation/mod.rs @@ -1,4 +1,4 @@ -use miden_node_store::{DatabaseError, Db}; +use miden_node_db::{DatabaseError, Db}; use miden_protocol::block::ProposedBlock; use miden_protocol::crypto::dsa::ecdsa_k256_keccak::{SecretKey, Signature}; use miden_protocol::errors::ProposedBlockError; diff --git a/crates/validator/src/db/migrations.rs b/crates/validator/src/db/migrations.rs index 6896082bed..240c29033b 100644 --- a/crates/validator/src/db/migrations.rs +++ b/crates/validator/src/db/migrations.rs @@ -1,6 +1,6 @@ use diesel::SqliteConnection; use diesel_migrations::{EmbeddedMigrations, MigrationHarness, embed_migrations}; -use miden_node_store::DatabaseError; +use miden_node_db::DatabaseError; use tracing::instrument; use crate::COMPONENT; diff --git a/crates/validator/src/db/mod.rs b/crates/validator/src/db/mod.rs index 14d85e34f0..4c8fe665be 100644 --- a/crates/validator/src/db/mod.rs +++ b/crates/validator/src/db/mod.rs @@ -7,7 +7,7 @@ use std::path::PathBuf; use diesel::SqliteConnection; use diesel::dsl::exists; use diesel::prelude::*; -use miden_node_store::{ConnectionManager, DatabaseError, DatabaseSetupError}; +use miden_node_db::{DatabaseError, Db}; use miden_protocol::transaction::TransactionId; use miden_protocol::utils::Serializable; use tracing::instrument; @@ -19,17 +19,14 @@ use crate::tx_validation::ValidatedTransaction; /// Open a connection to the DB and apply any pending migrations. #[instrument(target = COMPONENT, skip_all)] -pub async fn load(database_filepath: PathBuf) -> Result { - let manager = ConnectionManager::new(database_filepath.to_str().unwrap()); - let pool = deadpool_diesel::Pool::builder(manager).max_size(16).build()?; - +pub async fn load(database_filepath: PathBuf) -> Result { + let db = Db::new(&database_filepath)?; tracing::info!( target: COMPONENT, sqlite= %database_filepath.display(), "Connected to the database" ); - let db = miden_node_store::Db::new(pool); db.query("migrations", apply_migrations).await?; Ok(db) } diff --git a/crates/validator/src/db/models.rs b/crates/validator/src/db/models.rs index e1e67086af..9a50b7a393 100644 --- a/crates/validator/src/db/models.rs +++ b/crates/validator/src/db/models.rs @@ -1,5 +1,5 @@ use diesel::prelude::*; -use miden_node_store::SqlTypeConvert; +use miden_node_db::SqlTypeConvert; use miden_tx::utils::Serializable; use crate::db::schema; diff --git a/crates/validator/src/server/mod.rs b/crates/validator/src/server/mod.rs index 427dde9379..02f52e1fcc 100644 --- a/crates/validator/src/server/mod.rs +++ b/crates/validator/src/server/mod.rs @@ -4,10 +4,10 @@ use std::sync::Arc; use std::time::Duration; use anyhow::Context; +use miden_node_db::Db; use miden_node_proto::generated::validator::api_server; use miden_node_proto::generated::{self as proto}; use miden_node_proto_build::validator_api_descriptor; -use miden_node_store::Db; use miden_node_utils::ErrorReport; use miden_node_utils::panic::catch_panic_layer_fn; use miden_node_utils::tracing::OpenTelemetrySpanExt; @@ -155,7 +155,10 @@ impl api_server::Api for ValidatorServer { // Store the validated transaction. self.db .transact("insert_transaction", move |conn| insert_transaction(conn, &tx_info)) - .await?; + .await + .map_err(|err| { + Status::internal(err.as_report_context("Failed to insert transaction")) + })?; Ok(tonic::Response::new(())) }