Skip to content

Commit

Permalink
refactor(chain,wallet)!: move rusqlite things into it's own file
Browse files Browse the repository at this point in the history
Also fix imports and rename `sqlite` module to `rusqlite_impl`.
  • Loading branch information
evanlinjin committed Jul 19, 2024
1 parent 93f9b83 commit 2cf07d6
Show file tree
Hide file tree
Showing 14 changed files with 587 additions and 602 deletions.
4 changes: 2 additions & 2 deletions crates/chain/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand All @@ -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"]
68 changes: 0 additions & 68 deletions crates/chain/src/indexer/keychain_txout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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> {
Expand Down
26 changes: 21 additions & 5 deletions crates/chain/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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
}
}
77 changes: 0 additions & 77 deletions crates/chain/src/local_chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Loading

0 comments on commit 2cf07d6

Please sign in to comment.