]> Untitled Git - bdk/commitdiff
refactor(chain,wallet)!: move rusqlite things into it's own file
author志宇 <hello@evanlinjin.me>
Fri, 19 Jul 2024 11:20:34 +0000 (11:20 +0000)
committer志宇 <hello@evanlinjin.me>
Fri, 19 Jul 2024 11:25:11 +0000 (11:25 +0000)
Also fix imports and rename `sqlite` module to `rusqlite_impl`.

14 files changed:
crates/chain/Cargo.toml
crates/chain/src/indexer/keychain_txout.rs
crates/chain/src/lib.rs
crates/chain/src/local_chain.rs
crates/chain/src/rusqlite_impl.rs [new file with mode: 0644]
crates/chain/src/sqlite.rs [deleted file]
crates/chain/src/tx_graph.rs
crates/wallet/Cargo.toml
crates/wallet/src/lib.rs
crates/wallet/src/wallet/changeset.rs
crates/wallet/src/wallet/mod.rs
crates/wallet/src/wallet/persisted.rs
crates/wallet/tests/wallet.rs
example-crates/wallet_esplora_async/Cargo.toml

index 2e704b1de4e4efc9f2b1071302b42b10ba4de041..19874301a2edbbde83c77ad7f263239d4ac6f46e 100644 (file)
@@ -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"]
index 4b81304f7bf984cb9700477090ee9ded795c32f5..86bd18e2a80e2ff8d52d15a7e548b51ab7b6552f 100644 (file)
@@ -783,74 +783,6 @@ impl<K: Clone + Ord + Debug> KeychainTxOutIndex<K> {
     }
 }
 
-#[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> {
-        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<DescriptorId>>("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<K> {
index 0070c89b8bebde15824b04e4bf9b47fea774764b..77759676c646f679ff97cfde684007ff78bcfa84 100644 (file)
@@ -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<T> = (u32, T);
 /// A tuple of keychain `K`, derivation index (`u32`) and a `T` associated with them.
 pub type KeychainIndexed<K, T> = ((K, u32), T);
+
+/// A wrapper that we use to impl remote traits for types in our crate or dependency crates.
+pub struct Impl<T>(pub T);
+
+impl<T> From<T> for Impl<T> {
+    fn from(value: T) -> Self {
+        Self(value)
+    }
+}
+
+impl<T> core::ops::Deref for Impl<T> {
+    type Target = T;
+
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
index 32394bc58121f590b1d66349c8efc4df8070e260..9fcd7a70691c7000623f5c76eaa258e73ce0fc61 100644 (file)
@@ -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> {
-        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<BlockHash>>("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 (file)
index 0000000..0ce919d
--- /dev/null
@@ -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<Option<u32>> {
+    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<bitcoin::Txid> {
+    fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
+        bitcoin::Txid::from_str(value.as_str()?)
+            .map(Self)
+            .map_err(from_sql_error)
+    }
+}
+
+impl ToSql for Impl<bitcoin::Txid> {
+    fn to_sql(&self) -> rusqlite::Result<ToSqlOutput<'_>> {
+        Ok(self.to_string().into())
+    }
+}
+
+impl FromSql for Impl<bitcoin::BlockHash> {
+    fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
+        bitcoin::BlockHash::from_str(value.as_str()?)
+            .map(Self)
+            .map_err(from_sql_error)
+    }
+}
+
+impl ToSql for Impl<bitcoin::BlockHash> {
+    fn to_sql(&self) -> rusqlite::Result<ToSqlOutput<'_>> {
+        Ok(self.to_string().into())
+    }
+}
+
+#[cfg(feature = "miniscript")]
+impl FromSql for Impl<DescriptorId> {
+    fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
+        DescriptorId::from_str(value.as_str()?)
+            .map(Self)
+            .map_err(from_sql_error)
+    }
+}
+
+#[cfg(feature = "miniscript")]
+impl ToSql for Impl<DescriptorId> {
+    fn to_sql(&self) -> rusqlite::Result<ToSqlOutput<'_>> {
+        Ok(self.to_string().into())
+    }
+}
+
+impl FromSql for Impl<bitcoin::Transaction> {
+    fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
+        bitcoin::Transaction::consensus_decode_from_finite_reader(&mut value.as_bytes()?)
+            .map(Self)
+            .map_err(from_sql_error)
+    }
+}
+
+impl ToSql for Impl<bitcoin::Transaction> {
+    fn to_sql(&self) -> rusqlite::Result<ToSqlOutput<'_>> {
+        let mut bytes = Vec::<u8>::new();
+        self.consensus_encode(&mut bytes).map_err(to_sql_error)?;
+        Ok(bytes.into())
+    }
+}
+
+impl FromSql for Impl<bitcoin::ScriptBuf> {
+    fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
+        Ok(bitcoin::Script::from_bytes(value.as_bytes()?)
+            .to_owned()
+            .into())
+    }
+}
+
+impl ToSql for Impl<bitcoin::ScriptBuf> {
+    fn to_sql(&self) -> rusqlite::Result<ToSqlOutput<'_>> {
+        Ok(self.as_bytes().into())
+    }
+}
+
+impl FromSql for Impl<bitcoin::Amount> {
+    fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
+        Ok(bitcoin::Amount::from_sat(value.as_i64()?.try_into().map_err(from_sql_error)?).into())
+    }
+}
+
+impl ToSql for Impl<bitcoin::Amount> {
+    fn to_sql(&self) -> rusqlite::Result<ToSqlOutput<'_>> {
+        let amount: i64 = self.to_sat().try_into().map_err(to_sql_error)?;
+        Ok(amount.into())
+    }
+}
+
+impl<A: Anchor + serde_crate::de::DeserializeOwned> FromSql for Impl<A> {
+    fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
+        serde_json::from_str(value.as_str()?)
+            .map(Impl)
+            .map_err(from_sql_error)
+    }
+}
+
+impl<A: Anchor + serde_crate::Serialize> ToSql for Impl<A> {
+    fn to_sql(&self) -> rusqlite::Result<ToSqlOutput<'_>> {
+        serde_json::to_string(&self.0)
+            .map(Into::into)
+            .map_err(to_sql_error)
+    }
+}
+
+#[cfg(feature = "miniscript")]
+impl FromSql for Impl<miniscript::Descriptor<miniscript::DescriptorPublicKey>> {
+    fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
+        miniscript::Descriptor::from_str(value.as_str()?)
+            .map(Self)
+            .map_err(from_sql_error)
+    }
+}
+
+#[cfg(feature = "miniscript")]
+impl ToSql for Impl<miniscript::Descriptor<miniscript::DescriptorPublicKey>> {
+    fn to_sql(&self) -> rusqlite::Result<ToSqlOutput<'_>> {
+        Ok(self.to_string().into())
+    }
+}
+
+impl FromSql for Impl<bitcoin::Network> {
+    fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
+        bitcoin::Network::from_str(value.as_str()?)
+            .map(Self)
+            .map_err(from_sql_error)
+    }
+}
+
+impl ToSql for Impl<bitcoin::Network> {
+    fn to_sql(&self) -> rusqlite::Result<ToSqlOutput<'_>> {
+        Ok(self.to_string().into())
+    }
+}
+
+fn from_sql_error<E: std::error::Error + Send + Sync + 'static>(err: E) -> FromSqlError {
+    FromSqlError::Other(Box::new(err))
+}
+
+fn to_sql_error<E: std::error::Error + Send + Sync + 'static>(err: E) -> rusqlite::Error {
+    rusqlite::Error::ToSqlConversionFailure(Box::new(err))
+}
+
+impl<A> tx_graph::ChangeSet<A>
+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> {
+        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<bitcoin::Txid>>("txid")?,
+                row.get::<_, Option<Impl<bitcoin::Transaction>>>("raw_tx")?,
+                row.get::<_, Option<u64>>("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<bitcoin::Txid>>("txid")?,
+                row.get::<_, u32>("vout")?,
+                row.get::<_, Impl<bitcoin::Amount>>("value")?,
+                row.get::<_, Impl<bitcoin::ScriptBuf>>("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<A>>("json(anchor)")?,
+                row.get::<_, Impl<bitcoin::Txid>>("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> {
+        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<bitcoin::BlockHash>>("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> {
+        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<DescriptorId>>("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 (file)
index 23dccf1..0000000
+++ /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<Option<u32>> {
-    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<T>(pub T);
-
-impl<T> From<T> for Sql<T> {
-    fn from(value: T) -> Self {
-        Self(value)
-    }
-}
-
-impl<T> Deref for Sql<T> {
-    type Target = T;
-
-    fn deref(&self) -> &Self::Target {
-        &self.0
-    }
-}
-
-impl FromSql for Sql<bitcoin::Txid> {
-    fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
-        bitcoin::Txid::from_str(value.as_str()?)
-            .map(Self)
-            .map_err(from_sql_error)
-    }
-}
-
-impl ToSql for Sql<bitcoin::Txid> {
-    fn to_sql(&self) -> rusqlite::Result<ToSqlOutput<'_>> {
-        Ok(self.to_string().into())
-    }
-}
-
-impl FromSql for Sql<bitcoin::BlockHash> {
-    fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
-        bitcoin::BlockHash::from_str(value.as_str()?)
-            .map(Self)
-            .map_err(from_sql_error)
-    }
-}
-
-impl ToSql for Sql<bitcoin::BlockHash> {
-    fn to_sql(&self) -> rusqlite::Result<ToSqlOutput<'_>> {
-        Ok(self.to_string().into())
-    }
-}
-
-#[cfg(feature = "miniscript")]
-impl FromSql for Sql<crate::DescriptorId> {
-    fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
-        crate::DescriptorId::from_str(value.as_str()?)
-            .map(Self)
-            .map_err(from_sql_error)
-    }
-}
-
-#[cfg(feature = "miniscript")]
-impl ToSql for Sql<crate::DescriptorId> {
-    fn to_sql(&self) -> rusqlite::Result<ToSqlOutput<'_>> {
-        Ok(self.to_string().into())
-    }
-}
-
-impl FromSql for Sql<bitcoin::Transaction> {
-    fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
-        bitcoin::Transaction::consensus_decode_from_finite_reader(&mut value.as_bytes()?)
-            .map(Self)
-            .map_err(from_sql_error)
-    }
-}
-
-impl ToSql for Sql<bitcoin::Transaction> {
-    fn to_sql(&self) -> rusqlite::Result<ToSqlOutput<'_>> {
-        let mut bytes = Vec::<u8>::new();
-        self.consensus_encode(&mut bytes).map_err(to_sql_error)?;
-        Ok(bytes.into())
-    }
-}
-
-impl FromSql for Sql<bitcoin::ScriptBuf> {
-    fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
-        Ok(bitcoin::Script::from_bytes(value.as_bytes()?)
-            .to_owned()
-            .into())
-    }
-}
-
-impl ToSql for Sql<bitcoin::ScriptBuf> {
-    fn to_sql(&self) -> rusqlite::Result<ToSqlOutput<'_>> {
-        Ok(self.as_bytes().into())
-    }
-}
-
-impl FromSql for Sql<bitcoin::Amount> {
-    fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
-        Ok(bitcoin::Amount::from_sat(value.as_i64()?.try_into().map_err(from_sql_error)?).into())
-    }
-}
-
-impl ToSql for Sql<bitcoin::Amount> {
-    fn to_sql(&self) -> rusqlite::Result<ToSqlOutput<'_>> {
-        let amount: i64 = self.to_sat().try_into().map_err(to_sql_error)?;
-        Ok(amount.into())
-    }
-}
-
-impl<A: Anchor + serde_crate::de::DeserializeOwned> FromSql for Sql<A> {
-    fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
-        serde_json::from_str(value.as_str()?)
-            .map(Sql)
-            .map_err(from_sql_error)
-    }
-}
-
-impl<A: Anchor + serde_crate::Serialize> ToSql for Sql<A> {
-    fn to_sql(&self) -> rusqlite::Result<ToSqlOutput<'_>> {
-        serde_json::to_string(&self.0)
-            .map(Into::into)
-            .map_err(to_sql_error)
-    }
-}
-
-#[cfg(feature = "miniscript")]
-impl FromSql for Sql<miniscript::Descriptor<miniscript::DescriptorPublicKey>> {
-    fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
-        miniscript::Descriptor::from_str(value.as_str()?)
-            .map(Self)
-            .map_err(from_sql_error)
-    }
-}
-
-#[cfg(feature = "miniscript")]
-impl ToSql for Sql<miniscript::Descriptor<miniscript::DescriptorPublicKey>> {
-    fn to_sql(&self) -> rusqlite::Result<ToSqlOutput<'_>> {
-        Ok(self.to_string().into())
-    }
-}
-
-impl FromSql for Sql<bitcoin::Network> {
-    fn column_result(value: ValueRef<'_>) -> FromSqlResult<Self> {
-        bitcoin::Network::from_str(value.as_str()?)
-            .map(Self)
-            .map_err(from_sql_error)
-    }
-}
-
-impl ToSql for Sql<bitcoin::Network> {
-    fn to_sql(&self) -> rusqlite::Result<ToSqlOutput<'_>> {
-        Ok(self.to_string().into())
-    }
-}
-
-fn from_sql_error<E: std::error::Error + Send + Sync + 'static>(err: E) -> FromSqlError {
-    FromSqlError::Other(Box::new(err))
-}
-
-fn to_sql_error<E: std::error::Error + Send + Sync + 'static>(err: E) -> rusqlite::Error {
-    rusqlite::Error::ToSqlConversionFailure(Box::new(err))
-}
index 67f6307afd91b8d70570b81272b680783797018b..8c11e737a41a03dee8738194fee8cd681875db2c 100644 (file)
@@ -1293,188 +1293,6 @@ impl<A> ChangeSet<A> {
     }
 }
 
-#[cfg(feature = "sqlite")]
-impl<A> ChangeSet<A>
-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> {
-        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>>("txid")?,
-                row.get::<_, Option<Sql<Transaction>>>("raw_tx")?,
-                row.get::<_, Option<u64>>("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>>("txid")?,
-                row.get::<_, u32>("vout")?,
-                row.get::<_, Sql<Amount>>("value")?,
-                row.get::<_, Sql<bitcoin::ScriptBuf>>("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<A>>("json(anchor)")?,
-                row.get::<_, Sql<Txid>>("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<A: Ord> Merge for ChangeSet<A> {
     fn merge(&mut self, other: Self) {
         // We use `extend` instead of `BTreeMap::append` due to performance issues with `append`.
index d7c2c75aca1bf4959fcb6409076a5dfcbf094fa5..c1931d90a6c19e9212f9ef5798f8e93423db3aa5 100644 (file)
@@ -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"
index a4abe5f1c3414a9e72c056b98ba49a4d8d0c829b..40167a39657f136b2aba236c6317d3cd7e3a9aff 100644 (file)
@@ -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;
index 0b1602953bf96ab704c461b7adb5ea789927046e..d499ee6fb7039557bb45d90d269ec70bcee9ebed 100644 (file)
@@ -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> {
         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<DescriptorPublicKey>>>("descriptor")?,
-                    row.get::<_, Sql<Descriptor<DescriptorPublicKey>>>("change_descriptor")?,
-                    row.get::<_, Sql<bitcoin::Network>>("network")?,
+                    row.get::<_, Impl<Descriptor<DescriptorPublicKey>>>("descriptor")?,
+                    row.get::<_, Impl<Descriptor<DescriptorPublicKey>>>("change_descriptor")?,
+                    row.get::<_, Impl<bitcoin::Network>>("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),
             })?;
         }
 
index 84fe52896b30d2242b92c43ef3d8917721a06932..514cec2ea04f8998db0d3a9cd69e7d881ec7e46c 100644 (file)
@@ -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)
index 5dfea3f2a3df3cd8cfcd54e939ebf8500cc7cac9..3ba62cd651b5e02839159edbae957331be681fe7 100644 (file)
@@ -5,8 +5,8 @@ use crate::{descriptor::DescriptorError, Wallet};
 /// Represents a persisted wallet.
 pub type PersistedWallet = bdk_chain::Persisted<Wallet>;
 
-#[cfg(feature = "sqlite")]
-impl<'c> chain::PersistWith<bdk_chain::sqlite::Transaction<'c>> for Wallet {
+#[cfg(feature = "rusqlite")]
+impl<'c> chain::PersistWith<bdk_chain::rusqlite::Transaction<'c>> for Wallet {
     type CreateParams = crate::CreateParams;
     type LoadParams = crate::LoadParams;
 
@@ -15,7 +15,7 @@ impl<'c> chain::PersistWith<bdk_chain::sqlite::Transaction<'c>> 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<Self, Self::CreateError> {
         let mut wallet =
@@ -29,7 +29,7 @@ impl<'c> chain::PersistWith<bdk_chain::sqlite::Transaction<'c>> for Wallet {
     }
 
     fn load(
-        conn: &mut bdk_chain::sqlite::Transaction<'c>,
+        conn: &mut bdk_chain::rusqlite::Transaction<'c>,
         params: Self::LoadParams,
     ) -> Result<Option<Self>, Self::LoadError> {
         let changeset =
@@ -41,15 +41,15 @@ impl<'c> chain::PersistWith<bdk_chain::sqlite::Transaction<'c>> for Wallet {
     }
 
     fn persist(
-        db: &mut bdk_chain::sqlite::Transaction<'c>,
+        db: &mut bdk_chain::rusqlite::Transaction<'c>,
         changeset: &<Self as chain::Staged>::ChangeSet,
     ) -> Result<(), Self::PersistError> {
         changeset.persist_to_sqlite(db)
     }
 }
 
-#[cfg(feature = "sqlite")]
-impl chain::PersistWith<bdk_chain::sqlite::Connection> for Wallet {
+#[cfg(feature = "rusqlite")]
+impl chain::PersistWith<bdk_chain::rusqlite::Connection> for Wallet {
     type CreateParams = crate::CreateParams;
     type LoadParams = crate::LoadParams;
 
@@ -58,7 +58,7 @@ impl chain::PersistWith<bdk_chain::sqlite::Connection> 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<Self, Self::CreateError> {
         let mut db_tx = db.transaction().map_err(CreateWithPersistError::Persist)?;
@@ -68,7 +68,7 @@ impl chain::PersistWith<bdk_chain::sqlite::Connection> for Wallet {
     }
 
     fn load(
-        db: &mut bdk_chain::sqlite::Connection,
+        db: &mut bdk_chain::rusqlite::Connection,
         params: Self::LoadParams,
     ) -> Result<Option<Self>, Self::LoadError> {
         let mut db_tx = db.transaction().map_err(LoadWithPersistError::Persist)?;
@@ -78,7 +78,7 @@ impl chain::PersistWith<bdk_chain::sqlite::Connection> for Wallet {
     }
 
     fn persist(
-        db: &mut bdk_chain::sqlite::Connection,
+        db: &mut bdk_chain::rusqlite::Connection,
         changeset: &<Self as chain::Staged>::ChangeSet,
     ) -> Result<(), Self::PersistError> {
         let db_tx = db.transaction()?;
index 5a709f1c6303110fae054e49a6634778ad8aa0e5..0c4fde7990f2a0a9310585f01b5be2a052b8c438 100644 (file)
@@ -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::<bdk_chain::sqlite::Connection, _, _>(
+    run::<bdk_chain::rusqlite::Connection, _, _>(
         "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(())
index 31bf39aa0b530179a0a6a2481aace5e0bdffade8..aa18a5e9db4f4289ff09001e4b10f014017d40df 100644 (file)
@@ -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"