Skip to content

Commit f484619

Browse files
committed
Introduce DatabaseFactory trait
This is part of #486 to add multi-descriptor wallet support to BDK.
1 parent 1fd62a7 commit f484619

File tree

5 files changed

+160
-1
lines changed

5 files changed

+160
-1
lines changed

src/database/any.rs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -425,3 +425,43 @@ impl ConfigurableDatabase for AnyDatabase {
425425
impl_from!((), AnyDatabaseConfig, Memory,);
426426
impl_from!(SledDbConfiguration, AnyDatabaseConfig, Sled, #[cfg(feature = "key-value-db")]);
427427
impl_from!(SqliteDbConfiguration, AnyDatabaseConfig, Sqlite, #[cfg(feature = "sqlite")]);
428+
429+
/// Type that implements [`DatabaseFactory`] that builds [`AnyDatabase`].
430+
pub enum AnyDatabaseFactory {
431+
/// Memory database factory
432+
Memory(memory::MemoryDatabaseFactory),
433+
#[cfg(feature = "key-value-db")]
434+
#[cfg_attr(docsrs, doc(cfg(feature = "key-value-db")))]
435+
/// Key-value database factory
436+
Sled(sled::Db),
437+
#[cfg(feature = "sqlite")]
438+
#[cfg_attr(docsrs, doc(cfg(feature = "sqlite")))]
439+
/// Sqlite databae factory
440+
Sqlite(sqlite::SqliteDatabaseFactory),
441+
}
442+
443+
impl DatabaseFactory for AnyDatabaseFactory {
444+
type Inner = AnyDatabase;
445+
446+
fn build_with_change(
447+
&self,
448+
descriptor: ExtendedDescriptor,
449+
change_descriptor: Option<ExtendedDescriptor>,
450+
network: Network,
451+
secp: &SecpCtx,
452+
) -> Result<Self::Inner, Error> {
453+
match self {
454+
AnyDatabaseFactory::Memory(f) => f
455+
.build_with_change(descriptor, change_descriptor, network, secp)
456+
.map(Self::Inner::Memory),
457+
#[cfg(feature = "key-value-db")]
458+
AnyDatabaseFactory::Sled(f) => f
459+
.build_with_change(descriptor, change_descriptor, network, secp)
460+
.map(Self::Inner::Sled),
461+
#[cfg(feature = "sqlite")]
462+
AnyDatabaseFactory::Sqlite(f) => f
463+
.build_with_change(descriptor, change_descriptor, network, secp)
464+
.map(Self::Inner::Sqlite),
465+
}
466+
}
467+
}

src/database/keyvalue.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ use crate::database::memory::MapKey;
2121
use crate::database::{BatchDatabase, BatchOperations, Database, SyncTime};
2222
use crate::error::Error;
2323
use crate::types::*;
24+
use crate::wallet::wallet_name_from_descriptor;
25+
26+
use super::DatabaseFactory;
2427

2528
macro_rules! impl_batch_operations {
2629
( { $($after_insert:tt)* }, $process_delete:ident ) => {
@@ -402,6 +405,28 @@ impl BatchDatabase for Tree {
402405
}
403406
}
404407

408+
/// A [`DatabaseFactory`] implementation that builds [`Tree`]
409+
impl DatabaseFactory for sled::Db {
410+
type Inner = sled::Tree;
411+
412+
// type Config = String;
413+
414+
// fn from_config(config: &Self::Config) -> Result<Self, Error> {
415+
// sled::open(config).map_err(Error::Sled)
416+
// }
417+
418+
fn build_with_change(
419+
&self,
420+
descriptor: crate::descriptor::ExtendedDescriptor,
421+
change_descriptor: Option<crate::descriptor::ExtendedDescriptor>,
422+
network: bitcoin::Network,
423+
secp: &crate::wallet::utils::SecpCtx,
424+
) -> Result<Self::Inner, Error> {
425+
let name = wallet_name_from_descriptor(descriptor, change_descriptor, network, secp)?;
426+
self.open_tree(&name).map_err(Error::Sled)
427+
}
428+
}
429+
405430
#[cfg(test)]
406431
mod test {
407432
use lazy_static::lazy_static;

src/database/memory.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ use crate::database::{BatchDatabase, BatchOperations, ConfigurableDatabase, Data
2626
use crate::error::Error;
2727
use crate::types::*;
2828

29+
use super::DatabaseFactory;
30+
2931
// path -> script p{i,e}<path> -> script
3032
// script -> path s<script> -> {i,e}<path>
3133
// outpoint u<outpoint> -> txout
@@ -475,6 +477,31 @@ impl ConfigurableDatabase for MemoryDatabase {
475477
}
476478
}
477479

480+
/// A [`DatabaseFactory`] implementation that builds [`MemoryDatabase`].
481+
#[derive(Debug, Default)]
482+
pub struct MemoryDatabaseFactory;
483+
484+
impl DatabaseFactory for MemoryDatabaseFactory {
485+
type Inner = MemoryDatabase;
486+
// type Config = ();
487+
488+
// fn from_config(_: &Self::Config) -> Result<Self, Error> {
489+
// Ok(MemoryDatabaseFactory::default())
490+
// }
491+
492+
fn build_with_change(
493+
&self,
494+
_descriptor: crate::descriptor::ExtendedDescriptor,
495+
_change_descriptor: Option<crate::descriptor::ExtendedDescriptor>,
496+
_network: bitcoin::Network,
497+
_secp: &crate::wallet::utils::SecpCtx,
498+
) -> Result<Self::Inner, Error> {
499+
Ok(MemoryDatabase::default())
500+
}
501+
}
502+
503+
// impl DatabaseFactory for
504+
478505
#[macro_export]
479506
#[doc(hidden)]
480507
/// Artificially insert a tx in the database, as if we had found it with a `sync`. This is a hidden

src/database/mod.rs

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,12 @@
2727
use serde::{Deserialize, Serialize};
2828

2929
use bitcoin::hash_types::Txid;
30-
use bitcoin::{OutPoint, Script, Transaction, TxOut};
30+
use bitcoin::{Network, OutPoint, Script, Transaction, TxOut};
3131

32+
use crate::descriptor::ExtendedDescriptor;
3233
use crate::error::Error;
3334
use crate::types::*;
35+
use crate::wallet::utils::SecpCtx;
3436

3537
pub mod any;
3638
pub use any::{AnyDatabase, AnyDatabaseConfig};
@@ -212,6 +214,31 @@ pub(crate) trait DatabaseUtils: Database {
212214

213215
impl<T: Database> DatabaseUtils for T {}
214216

217+
/// Trait for a factory that build databases, sharing the underlying configurations or storage path.
218+
pub trait DatabaseFactory: Sized {
219+
/// Inner type to build
220+
type Inner: Database;
221+
222+
/// Builds the defined [`DatabaseFactory::Inner`] type.
223+
fn build(
224+
&self,
225+
descriptor: ExtendedDescriptor,
226+
network: Network,
227+
secp: &SecpCtx,
228+
) -> Result<Self::Inner, Error> {
229+
self.build_with_change(descriptor, None, network, secp)
230+
}
231+
232+
/// Builds the defined [`DatabaseFactory::Inner`] type with the addition of a change descriptor.
233+
fn build_with_change(
234+
&self,
235+
descriptor: ExtendedDescriptor,
236+
change_descriptor: Option<ExtendedDescriptor>,
237+
network: Network,
238+
secp: &SecpCtx,
239+
) -> Result<Self::Inner, Error>;
240+
}
241+
215242
#[cfg(test)]
216243
pub mod test {
217244
use std::str::FromStr;

src/database/sqlite.rs

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,12 @@ use bitcoin::{OutPoint, Script, Transaction, TxOut};
1616
use crate::database::{BatchDatabase, BatchOperations, Database, SyncTime};
1717
use crate::error::Error;
1818
use crate::types::*;
19+
use crate::wallet::wallet_name_from_descriptor;
1920

2021
use rusqlite::{named_params, Connection};
2122

23+
use super::DatabaseFactory;
24+
2225
static MIGRATIONS: &[&str] = &[
2326
"CREATE TABLE version (version INTEGER)",
2427
"INSERT INTO version VALUES (1)",
@@ -970,6 +973,43 @@ pub fn migrate(conn: &Connection) -> rusqlite::Result<()> {
970973
Ok(())
971974
}
972975

976+
/// A [`DatabaseFactory`] implementation that builds [`SqliteDatabase`].
977+
///
978+
/// Each built database is stored in path of format: `<path_root>_<hash>.<path_ext>`
979+
/// Where `hash` contains identifying data derived with inputs provided by
980+
/// [`DatabaseFactory::build`] or [`DatabaseFactory::build_with_change`] calls.
981+
pub struct SqliteDatabaseFactory {
982+
pub path_root: String,
983+
pub path_ext: String,
984+
}
985+
986+
impl DatabaseFactory for SqliteDatabaseFactory {
987+
type Inner = SqliteDatabase;
988+
989+
// /// Configuration of format `(path_root, path_ext)`.
990+
// type Config = (String, String);
991+
992+
// fn from_config(config: &Self::Config) -> Result<Self, Error> {
993+
// let (path_root, path_ext) = config.to_owned();
994+
// Ok(Self {
995+
// path_root,
996+
// path_ext,
997+
// })
998+
// }
999+
1000+
fn build_with_change(
1001+
&self,
1002+
descriptor: crate::descriptor::ExtendedDescriptor,
1003+
change_descriptor: Option<crate::descriptor::ExtendedDescriptor>,
1004+
network: bitcoin::Network,
1005+
secp: &crate::wallet::utils::SecpCtx,
1006+
) -> Result<Self::Inner, Error> {
1007+
let name = wallet_name_from_descriptor(descriptor, change_descriptor, network, secp)?;
1008+
let path = format!("{}_{}.{}", self.path_root, name, self.path_ext);
1009+
Ok(Self::Inner::new(path))
1010+
}
1011+
}
1012+
9731013
#[cfg(test)]
9741014
pub mod test {
9751015
use crate::database::SqliteDatabase;

0 commit comments

Comments
 (0)