]> Untitled Git - bdk-cli/commitdiff
Add key-value-db and sqlite-db features, separate wallet directories
authorSteve Myers <steve@notmandatory.org>
Fri, 18 Feb 2022 20:57:14 +0000 (12:57 -0800)
committerSteve Myers <steve@notmandatory.org>
Fri, 6 May 2022 18:28:46 +0000 (11:28 -0700)
Cargo.lock
Cargo.toml
src/bdk_cli.rs

index 6616d691fcd43a9c7603a1b0621e8ec2c28ba0e7..1c5573ba91e23d871f3540d447717fb1c18d5924 100644 (file)
@@ -8,6 +8,17 @@ version = "1.0.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe"
 
+[[package]]
+name = "ahash"
+version = "0.7.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "43bb833f0bf979d8475d38fbf09ed3b8a55e1885fe93ad3f93239fc6a4f17b98"
+dependencies = [
+ "getrandom 0.2.6",
+ "once_cell",
+ "version_check",
+]
+
 [[package]]
 name = "aho-corasick"
 version = "0.7.18"
@@ -96,6 +107,7 @@ version = "0.17.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "00fa2bcfe9debe57f32285ef56cb218b2e0dbf91e476ad22f61a745d4c032a18"
 dependencies = [
+ "ahash",
  "async-trait",
  "bdk-macros",
  "bip39",
@@ -112,6 +124,7 @@ dependencies = [
  "rand",
  "reqwest",
  "rocksdb",
+ "rusqlite",
  "serde",
  "serde_json",
  "sled",
@@ -568,6 +581,18 @@ dependencies = [
  "str-buf",
 ]
 
+[[package]]
+name = "fallible-iterator"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7"
+
+[[package]]
+name = "fallible-streaming-iterator"
+version = "0.1.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a"
+
 [[package]]
 name = "fastrand"
 version = "1.7.0"
@@ -790,6 +815,18 @@ name = "hashbrown"
 version = "0.11.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
+dependencies = [
+ "ahash",
+]
+
+[[package]]
+name = "hashlink"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7249a3129cbc1ffccd74857f81464a323a152173cdb134e0fd81bc803b29facf"
+dependencies = [
+ "hashbrown",
+]
 
 [[package]]
 name = "heck"
@@ -997,6 +1034,16 @@ dependencies = [
  "libc",
 ]
 
+[[package]]
+name = "libsqlite3-sys"
+version = "0.22.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "290b64917f8b0cb885d9de0f9959fe1f775d7fa12f1da2db9001c1c8ab60f89d"
+dependencies = [
+ "pkg-config",
+ "vcpkg",
+]
+
 [[package]]
 name = "lock_api"
 version = "0.4.7"
@@ -1442,6 +1489,21 @@ dependencies = [
  "librocksdb-sys",
 ]
 
+[[package]]
+name = "rusqlite"
+version = "0.25.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c4b1eaf239b47034fb450ee9cdedd7d0226571689d8823030c4b6c2cb407152"
+dependencies = [
+ "bitflags",
+ "fallible-iterator",
+ "fallible-streaming-iterator",
+ "hashlink",
+ "libsqlite3-sys",
+ "memchr",
+ "smallvec 1.8.0",
+]
+
 [[package]]
 name = "rustc-hash"
 version = "1.1.0"
@@ -2077,6 +2139,12 @@ version = "0.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "936e4b492acfd135421d8dca4b1aa80a7bfc26e702ef3af710e0752684df5372"
 
+[[package]]
+name = "vcpkg"
+version = "0.2.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
+
 [[package]]
 name = "vec_map"
 version = "0.8.2"
index af87bad765c6a7ebd367c53c16e244fff111e0c9..87133d98e92d0062e578edb8f7b081eb9efef43c 100644 (file)
@@ -31,9 +31,11 @@ bdk-reserves = { version = "0.17", optional = true}
 electrsd = { version= "0.12", features = ["trigger", "bitcoind_22_0"], optional = true}
 
 [features]
-default = ["cli", "repl"]
-cli = ["bdk/key-value-db", "clap", "dirs-next", "env_logger"]
+default = ["cli", "repl", "key-value-db"]
+cli = ["clap", "dirs-next", "env_logger"]
 repl = ["regex", "rustyline", "fd-lock"]
+key-value-db = ["bdk/key-value-db"]
+sqlite-db = ["bdk/sqlite"]
 electrum = ["bdk/electrum"]
 esplora = []
 esplora-ureq = ["esplora", "bdk/use-esplora-ureq"]
index 24ee81bc787490947ad9d340ba351ac74f0ad8e8..1e0ee1a3df7fee8de95d686f52510591b8d08ea8 100644 (file)
@@ -43,9 +43,11 @@ use bdk::blockchain::{AnyBlockchain, AnyBlockchainConfig, ConfigurableBlockchain
 #[cfg(feature = "rpc")]
 use bdk::blockchain::rpc::{Auth, RpcConfig};
 
-use bdk::database::BatchDatabase;
-use bdk::sled;
-use bdk::sled::Tree;
+#[cfg(feature = "key-value-db")]
+use bdk::database::any::SledDbConfiguration;
+#[cfg(feature = "sqlite-db")]
+use bdk::database::any::SqliteDbConfiguration;
+use bdk::database::{AnyDatabase, AnyDatabaseConfig, BatchDatabase, ConfigurableDatabase};
 use bdk::wallet::wallet_name_from_descriptor;
 use bdk::Wallet;
 use bdk::{bitcoin, Error};
@@ -88,7 +90,8 @@ enum ReplSubCommand {
     Exit,
 }
 
-fn prepare_home_dir() -> Result<PathBuf, Error> {
+/// prepare bdk_cli home and wallet directory
+fn prepare_home_wallet_dir(wallet_name: &String) -> Result<PathBuf, Error> {
     let mut dir = PathBuf::new();
     dir.push(
         &dirs_next::home_dir().ok_or_else(|| Error::Generic("home dir not found".to_string()))?,
@@ -100,25 +103,75 @@ fn prepare_home_dir() -> Result<PathBuf, Error> {
         fs::create_dir(&dir).map_err(|e| Error::Generic(e.to_string()))?;
     }
 
-    #[cfg(not(feature = "compact_filters"))]
-    dir.push("database.sled");
+    dir.push(wallet_name);
+
+    if !dir.exists() {
+        info!("Creating wallet directory {}", dir.as_path().display());
+        fs::create_dir(&dir).map_err(|e| Error::Generic(e.to_string()))?;
+    }
 
-    #[cfg(feature = "compact_filters")]
-    dir.push("compact_filters");
     Ok(dir)
 }
 
-fn open_database(wallet_opts: &WalletOpts) -> Result<Tree, Error> {
-    let mut database_path = prepare_home_dir()?;
-    let wallet_name = wallet_opts
-        .wallet
-        .as_deref()
-        .expect("We should always have a wallet name at this point");
-    database_path.push(wallet_name);
-    let database = sled::open(database_path)?;
-    let tree = database.open_tree(&wallet_name)?;
+/// Prepare wallet database directory
+fn prepare_wallet_db_dir(wallet_name: &String) -> Result<PathBuf, Error> {
+    let mut db_dir = prepare_home_wallet_dir(wallet_name)?;
+
+    #[cfg(feature = "key-value-db")]
+    db_dir.push("wallet.sled");
+
+    #[cfg(feature = "sqlite-db")]
+    db_dir.push("wallet.sqlite");
+
+    #[cfg(not(feature = "sqlite-db"))]
+    if !db_dir.exists() {
+        info!("Creating database directory {}", db_dir.as_path().display());
+        fs::create_dir(&db_dir).map_err(|e| Error::Generic(e.to_string()))?;
+    }
+
+    Ok(db_dir)
+}
+
+/// Prepare blockchain data directory (for compact filters)
+#[cfg(feature = "compact_filters")]
+fn prepare_bc_dir(wallet_name: &String) -> Result<PathBuf, Error> {
+    let mut bc_dir = prepare_home_wallet_dir(wallet_name)?;
+
+    bc_dir.push("compact_filters");
+
+    if !bc_dir.exists() {
+        info!(
+            "Creating blockchain directory {}",
+            bc_dir.as_path().display()
+        );
+        fs::create_dir(&bc_dir).map_err(|e| Error::Generic(e.to_string()))?;
+    }
+
+    Ok(bc_dir)
+}
+
+fn open_database(wallet_opts: &WalletOpts) -> Result<AnyDatabase, Error> {
+    let wallet_name = wallet_opts.wallet.as_ref().expect("wallet name");
+    let database_path = prepare_wallet_db_dir(wallet_name)?;
+
+    #[cfg(feature = "key-value-db")]
+    let config = AnyDatabaseConfig::Sled(SledDbConfiguration {
+        path: database_path
+            .into_os_string()
+            .into_string()
+            .expect("path string"),
+        tree_name: wallet_name.to_string(),
+    });
+    #[cfg(feature = "sqlite-db")]
+    let config = AnyDatabaseConfig::Sqlite(SqliteDbConfiguration {
+        path: database_path
+            .into_os_string()
+            .into_string()
+            .expect("path string"),
+    });
+    let database = AnyDatabase::from_config(&config)?;
     debug!("database opened successfully");
-    Ok(tree)
+    Ok(database)
 }
 
 #[allow(dead_code)]
@@ -180,10 +233,11 @@ fn new_blockchain(
             }
         }
 
+        let wallet_name = wallet_opts.wallet.as_ref().expect("wallet name");
         AnyBlockchainConfig::CompactFilters(CompactFiltersBlockchainConfig {
             peers,
             network: _network,
-            storage_dir: prepare_home_dir()?
+            storage_dir: prepare_bc_dir(wallet_name)?
                 .into_os_string()
                 .into_string()
                 .map_err(|_| Error::Generic("Internal OS_String conversion error".to_string()))?,