Also fix imports and rename `sqlite` module to `rusqlite_impl`.
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]
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"]
}
}
-#[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> {
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;
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
+ }
+}
}
}
-#[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;
--- /dev/null
+//! 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(())
+ }
+}
+++ /dev/null
-//! 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))
-}
}
}
-#[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`.
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"
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;
}
}
-#[cfg(feature = "sqlite")]
+#[cfg(feature = "rusqlite")]
impl ChangeSet {
/// Schema name for wallet.
pub const WALLET_SCHEMA_NAME: &'static str = "bdk_wallet";
) 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();
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);
) -> 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",
if let Some(descriptor) = &self.descriptor {
descriptor_statement.execute(named_params! {
":id": 0,
- ":descriptor": Sql(descriptor.clone()),
+ ":descriptor": Impl(descriptor.clone()),
})?;
}
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()),
})?;
}
if let Some(network) = self.network {
network_statement.execute(named_params! {
":id": 0,
- ":network": Sql(network),
+ ":network": Impl(network),
})?;
}
///
/// ```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)
/// 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;
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 =
}
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 =
}
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;
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)?;
}
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)?;
}
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()?;
|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(())
)?;
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(())
# 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"