From 2cf07d686b19787b5e97e0d5ed0b4cce7f56549f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BF=97=E5=AE=87?= Date: Fri, 19 Jul 2024 11:20:34 +0000 Subject: [PATCH] refactor(chain,wallet)!: move rusqlite things into it's own file Also fix imports and rename `sqlite` module to `rusqlite_impl`. --- crates/chain/Cargo.toml | 4 +- crates/chain/src/indexer/keychain_txout.rs | 68 --- crates/chain/src/lib.rs | 26 +- crates/chain/src/local_chain.rs | 77 --- crates/chain/src/rusqlite_impl.rs | 530 ++++++++++++++++++ crates/chain/src/sqlite.rs | 234 -------- crates/chain/src/tx_graph.rs | 182 ------ crates/wallet/Cargo.toml | 6 +- crates/wallet/src/lib.rs | 6 +- crates/wallet/src/wallet/changeset.rs | 22 +- crates/wallet/src/wallet/mod.rs | 2 +- crates/wallet/src/wallet/persisted.rs | 20 +- crates/wallet/tests/wallet.rs | 10 +- .../wallet_esplora_async/Cargo.toml | 2 +- 14 files changed, 587 insertions(+), 602 deletions(-) create mode 100644 crates/chain/src/rusqlite_impl.rs delete mode 100644 crates/chain/src/sqlite.rs diff --git a/crates/chain/Cargo.toml b/crates/chain/Cargo.toml index 2e704b1d..19874301 100644 --- a/crates/chain/Cargo.toml +++ b/crates/chain/Cargo.toml @@ -21,7 +21,7 @@ hashbrown = { version = "0.9.1", optional = true, features = ["serde"] } miniscript = { version = "12.0.0", optional = true, default-features = false } # Feature dependencies -rusqlite = { version = "0.31.0", features = ["bundled"], optional = true } +rusqlite_crate = { package = "rusqlite", version = "0.31.0", features = ["bundled"], optional = true } serde_json = {version = "1", optional = true } [dev-dependencies] @@ -32,4 +32,4 @@ proptest = "1.2.0" default = ["std", "miniscript"] std = ["bitcoin/std", "miniscript?/std"] serde = ["serde_crate", "bitcoin/serde", "miniscript?/serde"] -sqlite = ["std", "rusqlite", "serde", "serde_json"] +rusqlite = ["std", "rusqlite_crate", "serde", "serde_json"] diff --git a/crates/chain/src/indexer/keychain_txout.rs b/crates/chain/src/indexer/keychain_txout.rs index 4b81304f..86bd18e2 100644 --- a/crates/chain/src/indexer/keychain_txout.rs +++ b/crates/chain/src/indexer/keychain_txout.rs @@ -783,74 +783,6 @@ impl KeychainTxOutIndex { } } -#[cfg(feature = "sqlite")] -impl ChangeSet { - /// Schema name for the changeset. - pub const SCHEMA_NAME: &'static str = "bdk_keychaintxout"; - /// Name for table that stores last revealed indices per descriptor id. - pub const LAST_REVEALED_TABLE_NAME: &'static str = "bdk_descriptor_last_revealed"; - - /// Initialize sqlite tables for persisting [`KeychainTxOutIndex`]. - fn init_sqlite_tables(db_tx: &rusqlite::Transaction) -> rusqlite::Result<()> { - let schema_v0: &[&str] = &[ - // last revealed - &format!( - "CREATE TABLE {} ( \ - descriptor_id TEXT PRIMARY KEY NOT NULL, \ - last_revealed INTEGER NOT NULL \ - ) STRICT", - Self::LAST_REVEALED_TABLE_NAME, - ), - ]; - crate::sqlite::migrate_schema(db_tx, Self::SCHEMA_NAME, &[schema_v0]) - } - - /// Construct [`KeychainTxOutIndex`] from sqlite database and given parameters. - pub fn from_sqlite(db_tx: &rusqlite::Transaction) -> rusqlite::Result { - Self::init_sqlite_tables(db_tx)?; - use crate::sqlite::Sql; - - let mut changeset = Self::default(); - - let mut statement = db_tx.prepare(&format!( - "SELECT descriptor_id, last_revealed FROM {}", - Self::LAST_REVEALED_TABLE_NAME, - ))?; - let row_iter = statement.query_map([], |row| { - Ok(( - row.get::<_, Sql>("descriptor_id")?, - row.get::<_, u32>("last_revealed")?, - )) - })?; - for row in row_iter { - let (Sql(descriptor_id), last_revealed) = row?; - changeset.last_revealed.insert(descriptor_id, last_revealed); - } - - Ok(changeset) - } - - /// Persist `changeset` to the sqlite database. - pub fn persist_to_sqlite(&self, db_tx: &rusqlite::Transaction) -> rusqlite::Result<()> { - Self::init_sqlite_tables(db_tx)?; - use crate::rusqlite::named_params; - use crate::sqlite::Sql; - - let mut statement = db_tx.prepare_cached(&format!( - "REPLACE INTO {}(descriptor_id, last_revealed) VALUES(:descriptor_id, :last_revealed)", - Self::LAST_REVEALED_TABLE_NAME, - ))?; - for (&descriptor_id, &last_revealed) in &self.last_revealed { - statement.execute(named_params! { - ":descriptor_id": Sql(descriptor_id), - ":last_revealed": last_revealed, - })?; - } - - Ok(()) - } -} - #[derive(Clone, Debug, PartialEq)] /// Error returned from [`KeychainTxOutIndex::insert_descriptor`] pub enum InsertDescriptorError { diff --git a/crates/chain/src/lib.rs b/crates/chain/src/lib.rs index 0070c89b..77759676 100644 --- a/crates/chain/src/lib.rs +++ b/crates/chain/src/lib.rs @@ -55,16 +55,15 @@ mod spk_iter; pub use indexer::keychain_txout; #[cfg(feature = "miniscript")] pub use spk_iter::*; -#[cfg(feature = "sqlite")] -pub mod sqlite; -#[cfg(feature = "sqlite")] -pub use rusqlite; +#[cfg(feature = "rusqlite")] +pub mod rusqlite_impl; pub mod spk_client; #[allow(unused_imports)] #[macro_use] extern crate alloc; - +#[cfg(feature = "rusqlite")] +pub extern crate rusqlite_crate as rusqlite; #[cfg(feature = "serde")] pub extern crate serde_crate as serde; @@ -110,3 +109,20 @@ pub const COINBASE_MATURITY: u32 = 100; pub type Indexed = (u32, T); /// A tuple of keychain `K`, derivation index (`u32`) and a `T` associated with them. pub type KeychainIndexed = ((K, u32), T); + +/// A wrapper that we use to impl remote traits for types in our crate or dependency crates. +pub struct Impl(pub T); + +impl From for Impl { + fn from(value: T) -> Self { + Self(value) + } +} + +impl core::ops::Deref for Impl { + type Target = T; + + fn deref(&self) -> &Self::Target { + &self.0 + } +} diff --git a/crates/chain/src/local_chain.rs b/crates/chain/src/local_chain.rs index 32394bc5..9fcd7a70 100644 --- a/crates/chain/src/local_chain.rs +++ b/crates/chain/src/local_chain.rs @@ -681,83 +681,6 @@ impl FromIterator<(u32, BlockHash)> for ChangeSet { } } -#[cfg(feature = "sqlite")] -impl ChangeSet { - /// Schema name for the changeset. - pub const SCHEMA_NAME: &'static str = "bdk_localchain"; - /// Name of sqlite table that stores blocks of [`LocalChain`]. - pub const BLOCKS_TABLE_NAME: &'static str = "bdk_blocks"; - - /// Initialize sqlite tables for persisting [`LocalChain`]. - fn init_sqlite_tables(db_tx: &rusqlite::Transaction) -> rusqlite::Result<()> { - let schema_v0: &[&str] = &[ - // blocks - &format!( - "CREATE TABLE {} ( \ - block_height INTEGER PRIMARY KEY NOT NULL, \ - block_hash TEXT NOT NULL \ - ) STRICT", - Self::BLOCKS_TABLE_NAME, - ), - ]; - crate::sqlite::migrate_schema(db_tx, Self::SCHEMA_NAME, &[schema_v0]) - } - - /// Construct a [`LocalChain`] from sqlite database. - pub fn from_sqlite(db_tx: &rusqlite::Transaction) -> rusqlite::Result { - Self::init_sqlite_tables(db_tx)?; - use crate::sqlite::Sql; - - let mut changeset = Self::default(); - - let mut statement = db_tx.prepare(&format!( - "SELECT block_height, block_hash FROM {}", - Self::BLOCKS_TABLE_NAME, - ))?; - let row_iter = statement.query_map([], |row| { - Ok(( - row.get::<_, u32>("block_height")?, - row.get::<_, Sql>("block_hash")?, - )) - })?; - for row in row_iter { - let (height, Sql(hash)) = row?; - changeset.blocks.insert(height, Some(hash)); - } - - Ok(changeset) - } - - /// Persist `changeset` to the sqlite database. - pub fn persist_to_sqlite(&self, db_tx: &rusqlite::Transaction) -> rusqlite::Result<()> { - Self::init_sqlite_tables(db_tx)?; - use crate::sqlite::Sql; - use rusqlite::named_params; - - let mut replace_statement = db_tx.prepare_cached(&format!( - "REPLACE INTO {}(block_height, block_hash) VALUES(:block_height, :block_hash)", - Self::BLOCKS_TABLE_NAME, - ))?; - let mut delete_statement = db_tx.prepare_cached(&format!( - "DELETE FROM {} WHERE block_height=:block_height", - Self::BLOCKS_TABLE_NAME, - ))?; - for (&height, &hash) in &self.blocks { - match hash { - Some(hash) => replace_statement.execute(named_params! { - ":block_height": height, - ":block_hash": Sql(hash), - })?, - None => delete_statement.execute(named_params! { - ":block_height": height, - })?, - }; - } - - Ok(()) - } -} - /// An error which occurs when a [`LocalChain`] is constructed without a genesis checkpoint. #[derive(Clone, Debug, PartialEq)] pub struct MissingGenesisError; diff --git a/crates/chain/src/rusqlite_impl.rs b/crates/chain/src/rusqlite_impl.rs new file mode 100644 index 00000000..0ce919d8 --- /dev/null +++ b/crates/chain/src/rusqlite_impl.rs @@ -0,0 +1,530 @@ +//! Module for stuff + +use crate::*; +use core::str::FromStr; + +use alloc::{borrow::ToOwned, boxed::Box, string::ToString, sync::Arc, vec::Vec}; +use bitcoin::consensus::{Decodable, Encodable}; +use rusqlite; +use rusqlite::named_params; +use rusqlite::types::{FromSql, FromSqlError, FromSqlResult, ToSql, ToSqlOutput, ValueRef}; +use rusqlite::OptionalExtension; +use rusqlite::Transaction; + +/// Table name for schemas. +pub const SCHEMAS_TABLE_NAME: &str = "bdk_schemas"; + +/// Initialize the schema table. +fn init_schemas_table(db_tx: &Transaction) -> rusqlite::Result<()> { + let sql = format!("CREATE TABLE IF NOT EXISTS {}( name TEXT PRIMARY KEY NOT NULL, version INTEGER NOT NULL ) STRICT", SCHEMAS_TABLE_NAME); + db_tx.execute(&sql, ())?; + Ok(()) +} + +/// Get schema version of `schema_name`. +fn schema_version(db_tx: &Transaction, schema_name: &str) -> rusqlite::Result> { + let sql = format!( + "SELECT version FROM {} WHERE name=:name", + SCHEMAS_TABLE_NAME + ); + db_tx + .query_row(&sql, named_params! { ":name": schema_name }, |row| { + row.get::<_, u32>("version") + }) + .optional() +} + +/// Set the `schema_version` of `schema_name`. +fn set_schema_version( + db_tx: &Transaction, + schema_name: &str, + schema_version: u32, +) -> rusqlite::Result<()> { + let sql = format!( + "REPLACE INTO {}(name, version) VALUES(:name, :version)", + SCHEMAS_TABLE_NAME, + ); + db_tx.execute( + &sql, + named_params! { ":name": schema_name, ":version": schema_version }, + )?; + Ok(()) +} + +/// Runs logic that initializes/migrates the table schemas. +pub fn migrate_schema( + db_tx: &Transaction, + schema_name: &str, + versioned_scripts: &[&[&str]], +) -> rusqlite::Result<()> { + init_schemas_table(db_tx)?; + let current_version = schema_version(db_tx, schema_name)?; + let exec_from = current_version.map_or(0_usize, |v| v as usize + 1); + let scripts_to_exec = versioned_scripts.iter().enumerate().skip(exec_from); + for (version, &script) in scripts_to_exec { + set_schema_version(db_tx, schema_name, version as u32)?; + for statement in script { + db_tx.execute(statement, ())?; + } + } + Ok(()) +} + +impl FromSql for Impl { + fn column_result(value: ValueRef<'_>) -> FromSqlResult { + bitcoin::Txid::from_str(value.as_str()?) + .map(Self) + .map_err(from_sql_error) + } +} + +impl ToSql for Impl { + fn to_sql(&self) -> rusqlite::Result> { + Ok(self.to_string().into()) + } +} + +impl FromSql for Impl { + fn column_result(value: ValueRef<'_>) -> FromSqlResult { + bitcoin::BlockHash::from_str(value.as_str()?) + .map(Self) + .map_err(from_sql_error) + } +} + +impl ToSql for Impl { + fn to_sql(&self) -> rusqlite::Result> { + Ok(self.to_string().into()) + } +} + +#[cfg(feature = "miniscript")] +impl FromSql for Impl { + fn column_result(value: ValueRef<'_>) -> FromSqlResult { + DescriptorId::from_str(value.as_str()?) + .map(Self) + .map_err(from_sql_error) + } +} + +#[cfg(feature = "miniscript")] +impl ToSql for Impl { + fn to_sql(&self) -> rusqlite::Result> { + Ok(self.to_string().into()) + } +} + +impl FromSql for Impl { + fn column_result(value: ValueRef<'_>) -> FromSqlResult { + bitcoin::Transaction::consensus_decode_from_finite_reader(&mut value.as_bytes()?) + .map(Self) + .map_err(from_sql_error) + } +} + +impl ToSql for Impl { + fn to_sql(&self) -> rusqlite::Result> { + let mut bytes = Vec::::new(); + self.consensus_encode(&mut bytes).map_err(to_sql_error)?; + Ok(bytes.into()) + } +} + +impl FromSql for Impl { + fn column_result(value: ValueRef<'_>) -> FromSqlResult { + Ok(bitcoin::Script::from_bytes(value.as_bytes()?) + .to_owned() + .into()) + } +} + +impl ToSql for Impl { + fn to_sql(&self) -> rusqlite::Result> { + Ok(self.as_bytes().into()) + } +} + +impl FromSql for Impl { + fn column_result(value: ValueRef<'_>) -> FromSqlResult { + Ok(bitcoin::Amount::from_sat(value.as_i64()?.try_into().map_err(from_sql_error)?).into()) + } +} + +impl ToSql for Impl { + fn to_sql(&self) -> rusqlite::Result> { + let amount: i64 = self.to_sat().try_into().map_err(to_sql_error)?; + Ok(amount.into()) + } +} + +impl FromSql for Impl { + fn column_result(value: ValueRef<'_>) -> FromSqlResult { + serde_json::from_str(value.as_str()?) + .map(Impl) + .map_err(from_sql_error) + } +} + +impl ToSql for Impl { + fn to_sql(&self) -> rusqlite::Result> { + serde_json::to_string(&self.0) + .map(Into::into) + .map_err(to_sql_error) + } +} + +#[cfg(feature = "miniscript")] +impl FromSql for Impl> { + fn column_result(value: ValueRef<'_>) -> FromSqlResult { + miniscript::Descriptor::from_str(value.as_str()?) + .map(Self) + .map_err(from_sql_error) + } +} + +#[cfg(feature = "miniscript")] +impl ToSql for Impl> { + fn to_sql(&self) -> rusqlite::Result> { + Ok(self.to_string().into()) + } +} + +impl FromSql for Impl { + fn column_result(value: ValueRef<'_>) -> FromSqlResult { + bitcoin::Network::from_str(value.as_str()?) + .map(Self) + .map_err(from_sql_error) + } +} + +impl ToSql for Impl { + fn to_sql(&self) -> rusqlite::Result> { + Ok(self.to_string().into()) + } +} + +fn from_sql_error(err: E) -> FromSqlError { + FromSqlError::Other(Box::new(err)) +} + +fn to_sql_error(err: E) -> rusqlite::Error { + rusqlite::Error::ToSqlConversionFailure(Box::new(err)) +} + +impl tx_graph::ChangeSet +where + A: Anchor + Clone + Ord + serde::Serialize + serde::de::DeserializeOwned, +{ + /// Schema name for [`tx_graph::ChangeSet`]. + pub const SCHEMA_NAME: &'static str = "bdk_txgraph"; + /// Name of table that stores full transactions and `last_seen` timestamps. + pub const TXS_TABLE_NAME: &'static str = "bdk_txs"; + /// Name of table that stores floating txouts. + pub const TXOUTS_TABLE_NAME: &'static str = "bdk_txouts"; + /// Name of table that stores [`Anchor`]s. + pub const ANCHORS_TABLE_NAME: &'static str = "bdk_anchors"; + + /// Initialize sqlite tables. + fn init_sqlite_tables(db_tx: &rusqlite::Transaction) -> rusqlite::Result<()> { + let schema_v0: &[&str] = &[ + // full transactions + &format!( + "CREATE TABLE {} ( \ + txid TEXT PRIMARY KEY NOT NULL, \ + raw_tx BLOB, \ + last_seen INTEGER \ + ) STRICT", + Self::TXS_TABLE_NAME, + ), + // floating txouts + &format!( + "CREATE TABLE {} ( \ + txid TEXT NOT NULL, \ + vout INTEGER NOT NULL, \ + value INTEGER NOT NULL, \ + script BLOB NOT NULL, \ + PRIMARY KEY (txid, vout) \ + ) STRICT", + Self::TXOUTS_TABLE_NAME, + ), + // anchors + &format!( + "CREATE TABLE {} ( \ + txid TEXT NOT NULL REFERENCES {} (txid), \ + block_height INTEGER NOT NULL, \ + block_hash TEXT NOT NULL, \ + anchor BLOB NOT NULL, \ + PRIMARY KEY (txid, block_height, block_hash) \ + ) STRICT", + Self::ANCHORS_TABLE_NAME, + Self::TXS_TABLE_NAME, + ), + ]; + migrate_schema(db_tx, Self::SCHEMA_NAME, &[schema_v0]) + } + + /// Construct a [`TxGraph`] from an sqlite database. + pub fn from_sqlite(db_tx: &rusqlite::Transaction) -> rusqlite::Result { + Self::init_sqlite_tables(db_tx)?; + + let mut changeset = Self::default(); + + let mut statement = db_tx.prepare(&format!( + "SELECT txid, raw_tx, last_seen FROM {}", + Self::TXS_TABLE_NAME, + ))?; + let row_iter = statement.query_map([], |row| { + Ok(( + row.get::<_, Impl>("txid")?, + row.get::<_, Option>>("raw_tx")?, + row.get::<_, Option>("last_seen")?, + )) + })?; + for row in row_iter { + let (Impl(txid), tx, last_seen) = row?; + if let Some(Impl(tx)) = tx { + changeset.txs.insert(Arc::new(tx)); + } + if let Some(last_seen) = last_seen { + changeset.last_seen.insert(txid, last_seen); + } + } + + let mut statement = db_tx.prepare(&format!( + "SELECT txid, vout, value, script FROM {}", + Self::TXOUTS_TABLE_NAME, + ))?; + let row_iter = statement.query_map([], |row| { + Ok(( + row.get::<_, Impl>("txid")?, + row.get::<_, u32>("vout")?, + row.get::<_, Impl>("value")?, + row.get::<_, Impl>("script")?, + )) + })?; + for row in row_iter { + let (Impl(txid), vout, Impl(value), Impl(script_pubkey)) = row?; + changeset.txouts.insert( + bitcoin::OutPoint { txid, vout }, + bitcoin::TxOut { + value, + script_pubkey, + }, + ); + } + + let mut statement = db_tx.prepare(&format!( + "SELECT json(anchor), txid FROM {}", + Self::ANCHORS_TABLE_NAME, + ))?; + let row_iter = statement.query_map([], |row| { + Ok(( + row.get::<_, Impl>("json(anchor)")?, + row.get::<_, Impl>("txid")?, + )) + })?; + for row in row_iter { + let (Impl(anchor), Impl(txid)) = row?; + changeset.anchors.insert((anchor, txid)); + } + + Ok(changeset) + } + + /// Persist `changeset` to the sqlite database. + pub fn persist_to_sqlite(&self, db_tx: &rusqlite::Transaction) -> rusqlite::Result<()> { + Self::init_sqlite_tables(db_tx)?; + + let mut statement = db_tx.prepare_cached(&format!( + "INSERT INTO {}(txid, raw_tx) VALUES(:txid, :raw_tx) ON CONFLICT(txid) DO UPDATE SET raw_tx=:raw_tx", + Self::TXS_TABLE_NAME, + ))?; + for tx in &self.txs { + statement.execute(named_params! { + ":txid": Impl(tx.compute_txid()), + ":raw_tx": Impl(tx.as_ref().clone()), + })?; + } + + let mut statement = db_tx + .prepare_cached(&format!( + "INSERT INTO {}(txid, last_seen) VALUES(:txid, :last_seen) ON CONFLICT(txid) DO UPDATE SET last_seen=:last_seen", + Self::TXS_TABLE_NAME, + ))?; + for (&txid, &last_seen) in &self.last_seen { + statement.execute(named_params! { + ":txid": Impl(txid), + ":last_seen": Some(last_seen), + })?; + } + + let mut statement = db_tx.prepare_cached(&format!( + "REPLACE INTO {}(txid, vout, value, script) VALUES(:txid, :vout, :value, :script)", + Self::TXOUTS_TABLE_NAME, + ))?; + for (op, txo) in &self.txouts { + statement.execute(named_params! { + ":txid": Impl(op.txid), + ":vout": op.vout, + ":value": Impl(txo.value), + ":script": Impl(txo.script_pubkey.clone()), + })?; + } + + let mut statement = db_tx.prepare_cached(&format!( + "REPLACE INTO {}(txid, block_height, block_hash, anchor) VALUES(:txid, :block_height, :block_hash, jsonb(:anchor))", + Self::ANCHORS_TABLE_NAME, + ))?; + for (anchor, txid) in &self.anchors { + let anchor_block = anchor.anchor_block(); + statement.execute(named_params! { + ":txid": Impl(*txid), + ":block_height": anchor_block.height, + ":block_hash": Impl(anchor_block.hash), + ":anchor": Impl(anchor.clone()), + })?; + } + + Ok(()) + } +} + +impl local_chain::ChangeSet { + /// Schema name for the changeset. + pub const SCHEMA_NAME: &'static str = "bdk_localchain"; + /// Name of sqlite table that stores blocks of [`LocalChain`](local_chain::LocalChain). + pub const BLOCKS_TABLE_NAME: &'static str = "bdk_blocks"; + + /// Initialize sqlite tables for persisting [`local_chain::LocalChain`]. + fn init_sqlite_tables(db_tx: &rusqlite::Transaction) -> rusqlite::Result<()> { + let schema_v0: &[&str] = &[ + // blocks + &format!( + "CREATE TABLE {} ( \ + block_height INTEGER PRIMARY KEY NOT NULL, \ + block_hash TEXT NOT NULL \ + ) STRICT", + Self::BLOCKS_TABLE_NAME, + ), + ]; + migrate_schema(db_tx, Self::SCHEMA_NAME, &[schema_v0]) + } + + /// Construct a [`LocalChain`](local_chain::LocalChain) from sqlite database. + pub fn from_sqlite(db_tx: &rusqlite::Transaction) -> rusqlite::Result { + Self::init_sqlite_tables(db_tx)?; + + let mut changeset = Self::default(); + + let mut statement = db_tx.prepare(&format!( + "SELECT block_height, block_hash FROM {}", + Self::BLOCKS_TABLE_NAME, + ))?; + let row_iter = statement.query_map([], |row| { + Ok(( + row.get::<_, u32>("block_height")?, + row.get::<_, Impl>("block_hash")?, + )) + })?; + for row in row_iter { + let (height, Impl(hash)) = row?; + changeset.blocks.insert(height, Some(hash)); + } + + Ok(changeset) + } + + /// Persist `changeset` to the sqlite database. + pub fn persist_to_sqlite(&self, db_tx: &rusqlite::Transaction) -> rusqlite::Result<()> { + Self::init_sqlite_tables(db_tx)?; + + let mut replace_statement = db_tx.prepare_cached(&format!( + "REPLACE INTO {}(block_height, block_hash) VALUES(:block_height, :block_hash)", + Self::BLOCKS_TABLE_NAME, + ))?; + let mut delete_statement = db_tx.prepare_cached(&format!( + "DELETE FROM {} WHERE block_height=:block_height", + Self::BLOCKS_TABLE_NAME, + ))?; + for (&height, &hash) in &self.blocks { + match hash { + Some(hash) => replace_statement.execute(named_params! { + ":block_height": height, + ":block_hash": Impl(hash), + })?, + None => delete_statement.execute(named_params! { + ":block_height": height, + })?, + }; + } + + Ok(()) + } +} + +#[cfg(feature = "miniscript")] +impl keychain_txout::ChangeSet { + /// Schema name for the changeset. + pub const SCHEMA_NAME: &'static str = "bdk_keychaintxout"; + /// Name for table that stores last revealed indices per descriptor id. + pub const LAST_REVEALED_TABLE_NAME: &'static str = "bdk_descriptor_last_revealed"; + + /// Initialize sqlite tables for persisting + /// [`KeychainTxOutIndex`](keychain_txout::KeychainTxOutIndex). + fn init_sqlite_tables(db_tx: &rusqlite::Transaction) -> rusqlite::Result<()> { + let schema_v0: &[&str] = &[ + // last revealed + &format!( + "CREATE TABLE {} ( \ + descriptor_id TEXT PRIMARY KEY NOT NULL, \ + last_revealed INTEGER NOT NULL \ + ) STRICT", + Self::LAST_REVEALED_TABLE_NAME, + ), + ]; + migrate_schema(db_tx, Self::SCHEMA_NAME, &[schema_v0]) + } + + /// Construct [`KeychainTxOutIndex`](keychain_txout::KeychainTxOutIndex) from sqlite database + /// and given parameters. + pub fn from_sqlite(db_tx: &rusqlite::Transaction) -> rusqlite::Result { + Self::init_sqlite_tables(db_tx)?; + + let mut changeset = Self::default(); + + let mut statement = db_tx.prepare(&format!( + "SELECT descriptor_id, last_revealed FROM {}", + Self::LAST_REVEALED_TABLE_NAME, + ))?; + let row_iter = statement.query_map([], |row| { + Ok(( + row.get::<_, Impl>("descriptor_id")?, + row.get::<_, u32>("last_revealed")?, + )) + })?; + for row in row_iter { + let (Impl(descriptor_id), last_revealed) = row?; + changeset.last_revealed.insert(descriptor_id, last_revealed); + } + + Ok(changeset) + } + + /// Persist `changeset` to the sqlite database. + pub fn persist_to_sqlite(&self, db_tx: &rusqlite::Transaction) -> rusqlite::Result<()> { + Self::init_sqlite_tables(db_tx)?; + + let mut statement = db_tx.prepare_cached(&format!( + "REPLACE INTO {}(descriptor_id, last_revealed) VALUES(:descriptor_id, :last_revealed)", + Self::LAST_REVEALED_TABLE_NAME, + ))?; + for (&descriptor_id, &last_revealed) in &self.last_revealed { + statement.execute(named_params! { + ":descriptor_id": Impl(descriptor_id), + ":last_revealed": last_revealed, + })?; + } + + Ok(()) + } +} diff --git a/crates/chain/src/sqlite.rs b/crates/chain/src/sqlite.rs deleted file mode 100644 index 23dccf10..00000000 --- a/crates/chain/src/sqlite.rs +++ /dev/null @@ -1,234 +0,0 @@ -//! Module for stuff - -use core::{ops::Deref, str::FromStr}; - -use alloc::{borrow::ToOwned, boxed::Box, string::ToString, vec::Vec}; -use bitcoin::consensus::{Decodable, Encodable}; -pub use rusqlite; -pub use rusqlite::Connection; -use rusqlite::OptionalExtension; -pub use rusqlite::Transaction; -use rusqlite::{ - named_params, - types::{FromSql, FromSqlError, FromSqlResult, ToSqlOutput, ValueRef}, - ToSql, -}; - -use crate::Anchor; - -/// Table name for schemas. -pub const SCHEMAS_TABLE_NAME: &str = "bdk_schemas"; - -/// Initialize the schema table. -fn init_schemas_table(db_tx: &Transaction) -> rusqlite::Result<()> { - let sql = format!("CREATE TABLE IF NOT EXISTS {}( name TEXT PRIMARY KEY NOT NULL, version INTEGER NOT NULL ) STRICT", SCHEMAS_TABLE_NAME); - db_tx.execute(&sql, ())?; - Ok(()) -} - -/// Get schema version of `schema_name`. -fn schema_version(db_tx: &Transaction, schema_name: &str) -> rusqlite::Result> { - let sql = format!( - "SELECT version FROM {} WHERE name=:name", - SCHEMAS_TABLE_NAME - ); - db_tx - .query_row(&sql, named_params! { ":name": schema_name }, |row| { - row.get::<_, u32>("version") - }) - .optional() -} - -/// Set the `schema_version` of `schema_name`. -fn set_schema_version( - db_tx: &Transaction, - schema_name: &str, - schema_version: u32, -) -> rusqlite::Result<()> { - let sql = format!( - "REPLACE INTO {}(name, version) VALUES(:name, :version)", - SCHEMAS_TABLE_NAME, - ); - db_tx.execute( - &sql, - named_params! { ":name": schema_name, ":version": schema_version }, - )?; - Ok(()) -} - -/// Runs logic that initializes/migrates the table schemas. -pub fn migrate_schema( - db_tx: &Transaction, - schema_name: &str, - versioned_scripts: &[&[&str]], -) -> rusqlite::Result<()> { - init_schemas_table(db_tx)?; - let current_version = schema_version(db_tx, schema_name)?; - let exec_from = current_version.map_or(0_usize, |v| v as usize + 1); - let scripts_to_exec = versioned_scripts.iter().enumerate().skip(exec_from); - for (version, &script) in scripts_to_exec { - set_schema_version(db_tx, schema_name, version as u32)?; - for statement in script { - db_tx.execute(statement, ())?; - } - } - Ok(()) -} - -/// A wrapper so that we can impl [FromSql] and [ToSql] for multiple types. -pub struct Sql(pub T); - -impl From for Sql { - fn from(value: T) -> Self { - Self(value) - } -} - -impl Deref for Sql { - type Target = T; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl FromSql for Sql { - fn column_result(value: ValueRef<'_>) -> FromSqlResult { - bitcoin::Txid::from_str(value.as_str()?) - .map(Self) - .map_err(from_sql_error) - } -} - -impl ToSql for Sql { - fn to_sql(&self) -> rusqlite::Result> { - Ok(self.to_string().into()) - } -} - -impl FromSql for Sql { - fn column_result(value: ValueRef<'_>) -> FromSqlResult { - bitcoin::BlockHash::from_str(value.as_str()?) - .map(Self) - .map_err(from_sql_error) - } -} - -impl ToSql for Sql { - fn to_sql(&self) -> rusqlite::Result> { - Ok(self.to_string().into()) - } -} - -#[cfg(feature = "miniscript")] -impl FromSql for Sql { - fn column_result(value: ValueRef<'_>) -> FromSqlResult { - crate::DescriptorId::from_str(value.as_str()?) - .map(Self) - .map_err(from_sql_error) - } -} - -#[cfg(feature = "miniscript")] -impl ToSql for Sql { - fn to_sql(&self) -> rusqlite::Result> { - Ok(self.to_string().into()) - } -} - -impl FromSql for Sql { - fn column_result(value: ValueRef<'_>) -> FromSqlResult { - bitcoin::Transaction::consensus_decode_from_finite_reader(&mut value.as_bytes()?) - .map(Self) - .map_err(from_sql_error) - } -} - -impl ToSql for Sql { - fn to_sql(&self) -> rusqlite::Result> { - let mut bytes = Vec::::new(); - self.consensus_encode(&mut bytes).map_err(to_sql_error)?; - Ok(bytes.into()) - } -} - -impl FromSql for Sql { - fn column_result(value: ValueRef<'_>) -> FromSqlResult { - Ok(bitcoin::Script::from_bytes(value.as_bytes()?) - .to_owned() - .into()) - } -} - -impl ToSql for Sql { - fn to_sql(&self) -> rusqlite::Result> { - Ok(self.as_bytes().into()) - } -} - -impl FromSql for Sql { - fn column_result(value: ValueRef<'_>) -> FromSqlResult { - Ok(bitcoin::Amount::from_sat(value.as_i64()?.try_into().map_err(from_sql_error)?).into()) - } -} - -impl ToSql for Sql { - fn to_sql(&self) -> rusqlite::Result> { - let amount: i64 = self.to_sat().try_into().map_err(to_sql_error)?; - Ok(amount.into()) - } -} - -impl FromSql for Sql { - fn column_result(value: ValueRef<'_>) -> FromSqlResult { - serde_json::from_str(value.as_str()?) - .map(Sql) - .map_err(from_sql_error) - } -} - -impl ToSql for Sql { - fn to_sql(&self) -> rusqlite::Result> { - serde_json::to_string(&self.0) - .map(Into::into) - .map_err(to_sql_error) - } -} - -#[cfg(feature = "miniscript")] -impl FromSql for Sql> { - fn column_result(value: ValueRef<'_>) -> FromSqlResult { - miniscript::Descriptor::from_str(value.as_str()?) - .map(Self) - .map_err(from_sql_error) - } -} - -#[cfg(feature = "miniscript")] -impl ToSql for Sql> { - fn to_sql(&self) -> rusqlite::Result> { - Ok(self.to_string().into()) - } -} - -impl FromSql for Sql { - fn column_result(value: ValueRef<'_>) -> FromSqlResult { - bitcoin::Network::from_str(value.as_str()?) - .map(Self) - .map_err(from_sql_error) - } -} - -impl ToSql for Sql { - fn to_sql(&self) -> rusqlite::Result> { - Ok(self.to_string().into()) - } -} - -fn from_sql_error(err: E) -> FromSqlError { - FromSqlError::Other(Box::new(err)) -} - -fn to_sql_error(err: E) -> rusqlite::Error { - rusqlite::Error::ToSqlConversionFailure(Box::new(err)) -} diff --git a/crates/chain/src/tx_graph.rs b/crates/chain/src/tx_graph.rs index 67f6307a..8c11e737 100644 --- a/crates/chain/src/tx_graph.rs +++ b/crates/chain/src/tx_graph.rs @@ -1293,188 +1293,6 @@ impl ChangeSet { } } -#[cfg(feature = "sqlite")] -impl ChangeSet -where - A: Anchor + Clone + Ord + serde::Serialize + serde::de::DeserializeOwned, -{ - /// Schema name for the [`ChangeSet`]. - pub const SCHEMA_NAME: &'static str = "bdk_txgraph"; - /// Name of table that stores full transactions and `last_seen` timestamps. - pub const TXS_TABLE_NAME: &'static str = "bdk_txs"; - /// Name of table that stores floating txouts. - pub const TXOUTS_TABLE_NAME: &'static str = "bdk_txouts"; - /// Name of table that stores [`Anchor`]s. - pub const ANCHORS_TABLE_NAME: &'static str = "bdk_anchors"; - - /// Initialize sqlite tables. - fn init_sqlite_tables(db_tx: &rusqlite::Transaction) -> rusqlite::Result<()> { - let schema_v0: &[&str] = &[ - // full transactions - &format!( - "CREATE TABLE {} ( \ - txid TEXT PRIMARY KEY NOT NULL, \ - raw_tx BLOB, \ - last_seen INTEGER \ - ) STRICT", - Self::TXS_TABLE_NAME, - ), - // floating txouts - &format!( - "CREATE TABLE {} ( \ - txid TEXT NOT NULL, \ - vout INTEGER NOT NULL, \ - value INTEGER NOT NULL, \ - script BLOB NOT NULL, \ - PRIMARY KEY (txid, vout) \ - ) STRICT", - Self::TXOUTS_TABLE_NAME, - ), - // anchors - &format!( - "CREATE TABLE {} ( \ - txid TEXT NOT NULL REFERENCES {} (txid), \ - block_height INTEGER NOT NULL, \ - block_hash TEXT NOT NULL, \ - anchor BLOB NOT NULL, \ - PRIMARY KEY (txid, block_height, block_hash) \ - ) STRICT", - Self::ANCHORS_TABLE_NAME, - Self::TXS_TABLE_NAME, - ), - ]; - crate::sqlite::migrate_schema(db_tx, Self::SCHEMA_NAME, &[schema_v0]) - } - - /// Construct a [`TxGraph`] from an sqlite database. - pub fn from_sqlite(db_tx: &rusqlite::Transaction) -> rusqlite::Result { - Self::init_sqlite_tables(db_tx)?; - use crate::sqlite::Sql; - - let mut changeset = Self::default(); - - let mut statement = db_tx.prepare(&format!( - "SELECT txid, raw_tx, last_seen FROM {}", - Self::TXS_TABLE_NAME, - ))?; - let row_iter = statement.query_map([], |row| { - Ok(( - row.get::<_, Sql>("txid")?, - row.get::<_, Option>>("raw_tx")?, - row.get::<_, Option>("last_seen")?, - )) - })?; - for row in row_iter { - let (Sql(txid), tx, last_seen) = row?; - if let Some(Sql(tx)) = tx { - changeset.txs.insert(Arc::new(tx)); - } - if let Some(last_seen) = last_seen { - changeset.last_seen.insert(txid, last_seen); - } - } - - let mut statement = db_tx.prepare(&format!( - "SELECT txid, vout, value, script FROM {}", - Self::TXOUTS_TABLE_NAME, - ))?; - let row_iter = statement.query_map([], |row| { - Ok(( - row.get::<_, Sql>("txid")?, - row.get::<_, u32>("vout")?, - row.get::<_, Sql>("value")?, - row.get::<_, Sql>("script")?, - )) - })?; - for row in row_iter { - let (Sql(txid), vout, Sql(value), Sql(script_pubkey)) = row?; - changeset.txouts.insert( - OutPoint { txid, vout }, - TxOut { - value, - script_pubkey, - }, - ); - } - - let mut statement = db_tx.prepare(&format!( - "SELECT json(anchor), txid FROM {}", - Self::ANCHORS_TABLE_NAME, - ))?; - let row_iter = statement.query_map([], |row| { - Ok(( - row.get::<_, Sql>("json(anchor)")?, - row.get::<_, Sql>("txid")?, - )) - })?; - for row in row_iter { - let (Sql(anchor), Sql(txid)) = row?; - changeset.anchors.insert((anchor, txid)); - } - - Ok(changeset) - } - - /// Persist `changeset` to the sqlite database. - pub fn persist_to_sqlite(&self, db_tx: &rusqlite::Transaction) -> rusqlite::Result<()> { - Self::init_sqlite_tables(db_tx)?; - use crate::rusqlite::named_params; - use crate::sqlite::Sql; - - let mut statement = db_tx.prepare_cached(&format!( - "INSERT INTO {}(txid, raw_tx) VALUES(:txid, :raw_tx) ON CONFLICT(txid) DO UPDATE SET raw_tx=:raw_tx", - Self::TXS_TABLE_NAME, - ))?; - for tx in &self.txs { - statement.execute(named_params! { - ":txid": Sql(tx.compute_txid()), - ":raw_tx": Sql(tx.as_ref().clone()), - })?; - } - - let mut statement = db_tx - .prepare_cached(&format!( - "INSERT INTO {}(txid, last_seen) VALUES(:txid, :last_seen) ON CONFLICT(txid) DO UPDATE SET last_seen=:last_seen", - Self::TXS_TABLE_NAME, - ))?; - for (&txid, &last_seen) in &self.last_seen { - statement.execute(named_params! { - ":txid": Sql(txid), - ":last_seen": Some(last_seen), - })?; - } - - let mut statement = db_tx.prepare_cached(&format!( - "REPLACE INTO {}(txid, vout, value, script) VALUES(:txid, :vout, :value, :script)", - Self::TXOUTS_TABLE_NAME, - ))?; - for (op, txo) in &self.txouts { - statement.execute(named_params! { - ":txid": Sql(op.txid), - ":vout": op.vout, - ":value": Sql(txo.value), - ":script": Sql(txo.script_pubkey.clone()), - })?; - } - - let mut statement = db_tx.prepare_cached(&format!( - "REPLACE INTO {}(txid, block_height, block_hash, anchor) VALUES(:txid, :block_height, :block_hash, jsonb(:anchor))", - Self::ANCHORS_TABLE_NAME, - ))?; - for (anchor, txid) in &self.anchors { - let anchor_block = anchor.anchor_block(); - statement.execute(named_params! { - ":txid": Sql(*txid), - ":block_height": anchor_block.height, - ":block_hash": Sql(anchor_block.hash), - ":anchor": Sql(anchor.clone()), - })?; - } - - Ok(()) - } -} - impl Merge for ChangeSet { fn merge(&mut self, other: Self) { // We use `extend` instead of `BTreeMap::append` due to performance issues with `append`. diff --git a/crates/wallet/Cargo.toml b/crates/wallet/Cargo.toml index d7c2c75a..c1931d90 100644 --- a/crates/wallet/Cargo.toml +++ b/crates/wallet/Cargo.toml @@ -30,15 +30,15 @@ std = ["bitcoin/std", "bitcoin/rand-std", "miniscript/std", "bdk_chain/std"] compiler = ["miniscript/compiler"] all-keys = ["keys-bip39"] keys-bip39 = ["bip39"] -sqlite = ["bdk_chain/sqlite"] +rusqlite = ["bdk_chain/rusqlite"] file_store = ["bdk_file_store"] [dev-dependencies] lazy_static = "1.4" assert_matches = "1.5.0" tempfile = "3" -bdk_chain = { path = "../chain", features = ["sqlite"] } -bdk_wallet = { path = ".", features = ["sqlite", "file_store"] } +bdk_chain = { path = "../chain", features = ["rusqlite"] } +bdk_wallet = { path = ".", features = ["rusqlite", "file_store"] } bdk_file_store = { path = "../file_store" } anyhow = "1" rand = "^0.8" diff --git a/crates/wallet/src/lib.rs b/crates/wallet/src/lib.rs index a4abe5f1..40167a39 100644 --- a/crates/wallet/src/lib.rs +++ b/crates/wallet/src/lib.rs @@ -32,10 +32,10 @@ mod types; mod wallet; pub(crate) use bdk_chain::collections; -#[cfg(feature = "sqlite")] +#[cfg(feature = "rusqlite")] pub use bdk_chain::rusqlite; -#[cfg(feature = "sqlite")] -pub use bdk_chain::sqlite; +#[cfg(feature = "rusqlite")] +pub use bdk_chain::rusqlite_impl; pub use descriptor::template; pub use descriptor::HdKeyPaths; pub use signer; diff --git a/crates/wallet/src/wallet/changeset.rs b/crates/wallet/src/wallet/changeset.rs index 0b160295..d499ee6f 100644 --- a/crates/wallet/src/wallet/changeset.rs +++ b/crates/wallet/src/wallet/changeset.rs @@ -64,7 +64,7 @@ impl Merge for ChangeSet { } } -#[cfg(feature = "sqlite")] +#[cfg(feature = "rusqlite")] impl ChangeSet { /// Schema name for wallet. pub const WALLET_SCHEMA_NAME: &'static str = "bdk_wallet"; @@ -84,14 +84,14 @@ impl ChangeSet { ) STRICT;", Self::WALLET_TABLE_NAME, )]; - crate::sqlite::migrate_schema(db_tx, Self::WALLET_SCHEMA_NAME, &[schema_v0]) + crate::rusqlite_impl::migrate_schema(db_tx, Self::WALLET_SCHEMA_NAME, &[schema_v0]) } /// Recover a [`ChangeSet`] from sqlite database. pub fn from_sqlite(db_tx: &chain::rusqlite::Transaction) -> chain::rusqlite::Result { Self::init_wallet_sqlite_tables(db_tx)?; - use crate::sqlite::Sql; use chain::rusqlite::OptionalExtension; + use chain::Impl; use miniscript::{Descriptor, DescriptorPublicKey}; let mut changeset = Self::default(); @@ -103,13 +103,13 @@ impl ChangeSet { let row = wallet_statement .query_row([], |row| { Ok(( - row.get::<_, Sql>>("descriptor")?, - row.get::<_, Sql>>("change_descriptor")?, - row.get::<_, Sql>("network")?, + row.get::<_, Impl>>("descriptor")?, + row.get::<_, Impl>>("change_descriptor")?, + row.get::<_, Impl>("network")?, )) }) .optional()?; - if let Some((Sql(desc), Sql(change_desc), Sql(network))) = row { + if let Some((Impl(desc), Impl(change_desc), Impl(network))) = row { changeset.descriptor = Some(desc); changeset.change_descriptor = Some(change_desc); changeset.network = Some(network); @@ -129,7 +129,7 @@ impl ChangeSet { ) -> chain::rusqlite::Result<()> { Self::init_wallet_sqlite_tables(db_tx)?; use chain::rusqlite::named_params; - use chain::sqlite::Sql; + use chain::Impl; let mut descriptor_statement = db_tx.prepare_cached(&format!( "INSERT INTO {}(id, descriptor) VALUES(:id, :descriptor) ON CONFLICT(id) DO UPDATE SET descriptor=:descriptor", @@ -138,7 +138,7 @@ impl ChangeSet { if let Some(descriptor) = &self.descriptor { descriptor_statement.execute(named_params! { ":id": 0, - ":descriptor": Sql(descriptor.clone()), + ":descriptor": Impl(descriptor.clone()), })?; } @@ -149,7 +149,7 @@ impl ChangeSet { if let Some(change_descriptor) = &self.change_descriptor { change_descriptor_statement.execute(named_params! { ":id": 0, - ":change_descriptor": Sql(change_descriptor.clone()), + ":change_descriptor": Impl(change_descriptor.clone()), })?; } @@ -160,7 +160,7 @@ impl ChangeSet { if let Some(network) = self.network { network_statement.execute(named_params! { ":id": 0, - ":network": Sql(network), + ":network": Impl(network), })?; } diff --git a/crates/wallet/src/wallet/mod.rs b/crates/wallet/src/wallet/mod.rs index 84fe5289..514cec2e 100644 --- a/crates/wallet/src/wallet/mod.rs +++ b/crates/wallet/src/wallet/mod.rs @@ -586,7 +586,7 @@ impl Wallet { /// /// ```rust,no_run /// # use bdk_wallet::{LoadParams, ChangeSet, KeychainKind}; - /// use bdk_chain::sqlite::Connection; + /// use bdk_chain::rusqlite::Connection; /// let mut conn = Connection::open_in_memory().expect("must open connection"); /// let mut wallet = LoadParams::new() /// .load_wallet(&mut conn) diff --git a/crates/wallet/src/wallet/persisted.rs b/crates/wallet/src/wallet/persisted.rs index 5dfea3f2..3ba62cd6 100644 --- a/crates/wallet/src/wallet/persisted.rs +++ b/crates/wallet/src/wallet/persisted.rs @@ -5,8 +5,8 @@ use crate::{descriptor::DescriptorError, Wallet}; /// Represents a persisted wallet. pub type PersistedWallet = bdk_chain::Persisted; -#[cfg(feature = "sqlite")] -impl<'c> chain::PersistWith> for Wallet { +#[cfg(feature = "rusqlite")] +impl<'c> chain::PersistWith> for Wallet { type CreateParams = crate::CreateParams; type LoadParams = crate::LoadParams; @@ -15,7 +15,7 @@ impl<'c> chain::PersistWith> for Wallet { type PersistError = bdk_chain::rusqlite::Error; fn create( - db: &mut bdk_chain::sqlite::Transaction<'c>, + db: &mut bdk_chain::rusqlite::Transaction<'c>, params: Self::CreateParams, ) -> Result { let mut wallet = @@ -29,7 +29,7 @@ impl<'c> chain::PersistWith> for Wallet { } fn load( - conn: &mut bdk_chain::sqlite::Transaction<'c>, + conn: &mut bdk_chain::rusqlite::Transaction<'c>, params: Self::LoadParams, ) -> Result, Self::LoadError> { let changeset = @@ -41,15 +41,15 @@ impl<'c> chain::PersistWith> for Wallet { } fn persist( - db: &mut bdk_chain::sqlite::Transaction<'c>, + db: &mut bdk_chain::rusqlite::Transaction<'c>, changeset: &::ChangeSet, ) -> Result<(), Self::PersistError> { changeset.persist_to_sqlite(db) } } -#[cfg(feature = "sqlite")] -impl chain::PersistWith for Wallet { +#[cfg(feature = "rusqlite")] +impl chain::PersistWith for Wallet { type CreateParams = crate::CreateParams; type LoadParams = crate::LoadParams; @@ -58,7 +58,7 @@ impl chain::PersistWith for Wallet { type PersistError = bdk_chain::rusqlite::Error; fn create( - db: &mut bdk_chain::sqlite::Connection, + db: &mut bdk_chain::rusqlite::Connection, params: Self::CreateParams, ) -> Result { let mut db_tx = db.transaction().map_err(CreateWithPersistError::Persist)?; @@ -68,7 +68,7 @@ impl chain::PersistWith for Wallet { } fn load( - db: &mut bdk_chain::sqlite::Connection, + db: &mut bdk_chain::rusqlite::Connection, params: Self::LoadParams, ) -> Result, Self::LoadError> { let mut db_tx = db.transaction().map_err(LoadWithPersistError::Persist)?; @@ -78,7 +78,7 @@ impl chain::PersistWith for Wallet { } fn persist( - db: &mut bdk_chain::sqlite::Connection, + db: &mut bdk_chain::rusqlite::Connection, changeset: &::ChangeSet, ) -> Result<(), Self::PersistError> { let db_tx = db.transaction()?; diff --git a/crates/wallet/tests/wallet.rs b/crates/wallet/tests/wallet.rs index 5a709f1c..0c4fde79 100644 --- a/crates/wallet/tests/wallet.rs +++ b/crates/wallet/tests/wallet.rs @@ -169,10 +169,10 @@ fn wallet_is_persisted() -> anyhow::Result<()> { |path| Ok(bdk_file_store::Store::create_new(DB_MAGIC, path)?), |path| Ok(bdk_file_store::Store::open(DB_MAGIC, path)?), )?; - run::( + run::( "store.sqlite", - |path| Ok(bdk_chain::sqlite::Connection::open(path)?), - |path| Ok(bdk_chain::sqlite::Connection::open(path)?), + |path| Ok(bdk_chain::rusqlite::Connection::open(path)?), + |path| Ok(bdk_chain::rusqlite::Connection::open(path)?), )?; Ok(()) @@ -258,8 +258,8 @@ fn wallet_load_checks() -> anyhow::Result<()> { )?; run( "store.sqlite", - |path| Ok(bdk_chain::sqlite::Connection::open(path)?), - |path| Ok(bdk_chain::sqlite::Connection::open(path)?), + |path| Ok(bdk_chain::rusqlite::Connection::open(path)?), + |path| Ok(bdk_chain::rusqlite::Connection::open(path)?), )?; Ok(()) diff --git a/example-crates/wallet_esplora_async/Cargo.toml b/example-crates/wallet_esplora_async/Cargo.toml index 31bf39aa..aa18a5e9 100644 --- a/example-crates/wallet_esplora_async/Cargo.toml +++ b/example-crates/wallet_esplora_async/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -bdk_wallet = { path = "../../crates/wallet", features = ["sqlite"] } +bdk_wallet = { path = "../../crates/wallet", features = ["rusqlite"] } bdk_esplora = { path = "../../crates/esplora", features = ["async-https"] } tokio = { version = "1", features = ["rt", "rt-multi-thread", "macros"] } anyhow = "1"