Skip to content

Commit d5155a5

Browse files
committed
Merge #71: Add key-value-db and sqlite-db features, separate wallet directories
00454be Update CHANGELOG with new db features and wallet data directories (Steve Myers) 14106eb Prevent building with more than one database feature enabled (Steve Myers) fac465e Fix clippy warning (Steve Myers) d7471f6 Add key-value-db and sqlite-db features, separate wallet directories (Steve Myers) Pull request description: ### Description - Add distinct `key-value-db` and `sqlite-db` features, keep default as `key-value-db` - Put cached wallet data in separate directories: `~/.bdk-bitcoin/<wallet_name>` - Put compact filter data in `<wallet_name>/compact_filters` - Depending on the db used put cached wallet data in: `<wallet_name>/wallet.sled/` or `<wallet_name>/wallet.sqlite` ### Notes to the reviewers This change will help test BDK with different databases, in particular for manually testing DB migrations such as in bitcoindevkit/bdk#502. ### Checklists #### All Submissions: * [x] I've signed all my commits * [x] I followed the [contribution guidelines](https://github.com/bitcoindevkit/bdk-cli/blob/master/CONTRIBUTING.md) * [x] I ran `cargo fmt` and `cargo clippy` before committing #### New Features: * [ ] I've added tests for the new feature * [x] I've added docs for the new feature * [x] I've updated `CHANGELOG.md` Top commit has no ACKs. Tree-SHA512: a2610448295b39674706ab48f36e4ccb92f7065489bca2b7e0be81a6bbc063844ce7ea3728bd1fffde97938a8ef84234ba5a6cee56aa0deca267bbd671ae692a
2 parents 28f1318 + 00454be commit d5155a5

File tree

5 files changed

+164
-21
lines changed

5 files changed

+164
-21
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1212
- Make `regtest` the default network.
1313
- Add experimental `regtest-*` features to automatically deploy local regtest nodes
1414
(bitcoind, and electrs) while running cli commands.
15+
- Put cached wallet data in separate directories: ~/.bdk-bitcoin/<wallet_name>
16+
- Add distinct `key-value-db` and `sqlite-db` features, keep default as `key-value-db`
1517

1618
## [0.4.0]
1719

Cargo.lock

Lines changed: 68 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,11 @@ bdk-reserves = { version = "0.18", optional = true}
3131
electrsd = { version= "0.12", features = ["trigger", "bitcoind_22_0"], optional = true}
3232

3333
[features]
34-
default = ["cli", "repl"]
35-
cli = ["bdk/key-value-db", "clap", "dirs-next", "env_logger"]
34+
default = ["cli", "repl", "key-value-db"]
35+
cli = ["clap", "dirs-next", "env_logger"]
3636
repl = ["regex", "rustyline", "fd-lock"]
37+
key-value-db = ["bdk/key-value-db"]
38+
sqlite-db = ["bdk/sqlite"]
3739
electrum = ["bdk/electrum"]
3840
esplora = []
3941
esplora-ureq = ["esplora", "bdk/use-esplora-ureq"]

build.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,21 @@ fn main() {
1515
if blockchain_features.len() > 1 {
1616
panic!("At most one blockchain client feature can be enabled but these features were enabled: {:?}", blockchain_features)
1717
}
18+
19+
let key_value_db =
20+
env::var_os("CARGO_FEATURE_KEY_VALUE_DB").map(|_| "key-value-db".to_string());
21+
let sqlite_db = env::var_os("CARGO_FEATURE_SQLITE_DB").map(|_| "sqlite-db".to_string());
22+
23+
let database_features: Vec<String> = vec![key_value_db, sqlite_db]
24+
.iter()
25+
.map(|f| f.to_owned())
26+
.flatten()
27+
.collect();
28+
29+
if database_features.len() > 1 {
30+
panic!(
31+
"At most one database feature can be enabled but these features were enabled: {:?}",
32+
database_features
33+
)
34+
}
1835
}

src/bdk_cli.rs

Lines changed: 73 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -43,9 +43,11 @@ use bdk::blockchain::{AnyBlockchain, AnyBlockchainConfig, ConfigurableBlockchain
4343
#[cfg(feature = "rpc")]
4444
use bdk::blockchain::rpc::{Auth, RpcConfig};
4545

46-
use bdk::database::BatchDatabase;
47-
use bdk::sled;
48-
use bdk::sled::Tree;
46+
#[cfg(feature = "key-value-db")]
47+
use bdk::database::any::SledDbConfiguration;
48+
#[cfg(feature = "sqlite-db")]
49+
use bdk::database::any::SqliteDbConfiguration;
50+
use bdk::database::{AnyDatabase, AnyDatabaseConfig, BatchDatabase, ConfigurableDatabase};
4951
use bdk::wallet::wallet_name_from_descriptor;
5052
use bdk::Wallet;
5153
use bdk::{bitcoin, Error};
@@ -88,7 +90,8 @@ enum ReplSubCommand {
8890
Exit,
8991
}
9092

91-
fn prepare_home_dir() -> Result<PathBuf, Error> {
93+
/// prepare bdk_cli home and wallet directory
94+
fn prepare_home_wallet_dir(wallet_name: &str) -> Result<PathBuf, Error> {
9295
let mut dir = PathBuf::new();
9396
dir.push(
9497
&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> {
100103
fs::create_dir(&dir).map_err(|e| Error::Generic(e.to_string()))?;
101104
}
102105

103-
#[cfg(not(feature = "compact_filters"))]
104-
dir.push("database.sled");
106+
dir.push(wallet_name);
107+
108+
if !dir.exists() {
109+
info!("Creating wallet directory {}", dir.as_path().display());
110+
fs::create_dir(&dir).map_err(|e| Error::Generic(e.to_string()))?;
111+
}
105112

106-
#[cfg(feature = "compact_filters")]
107-
dir.push("compact_filters");
108113
Ok(dir)
109114
}
110115

111-
fn open_database(wallet_opts: &WalletOpts) -> Result<Tree, Error> {
112-
let mut database_path = prepare_home_dir()?;
113-
let wallet_name = wallet_opts
114-
.wallet
115-
.as_deref()
116-
.expect("We should always have a wallet name at this point");
117-
database_path.push(wallet_name);
118-
let database = sled::open(database_path)?;
119-
let tree = database.open_tree(&wallet_name)?;
116+
/// Prepare wallet database directory
117+
fn prepare_wallet_db_dir(wallet_name: &str) -> Result<PathBuf, Error> {
118+
let mut db_dir = prepare_home_wallet_dir(wallet_name)?;
119+
120+
#[cfg(feature = "key-value-db")]
121+
db_dir.push("wallet.sled");
122+
123+
#[cfg(feature = "sqlite-db")]
124+
db_dir.push("wallet.sqlite");
125+
126+
#[cfg(not(feature = "sqlite-db"))]
127+
if !db_dir.exists() {
128+
info!("Creating database directory {}", db_dir.as_path().display());
129+
fs::create_dir(&db_dir).map_err(|e| Error::Generic(e.to_string()))?;
130+
}
131+
132+
Ok(db_dir)
133+
}
134+
135+
/// Prepare blockchain data directory (for compact filters)
136+
#[cfg(feature = "compact_filters")]
137+
fn prepare_bc_dir(wallet_name: &str) -> Result<PathBuf, Error> {
138+
let mut bc_dir = prepare_home_wallet_dir(wallet_name)?;
139+
140+
bc_dir.push("compact_filters");
141+
142+
if !bc_dir.exists() {
143+
info!(
144+
"Creating blockchain directory {}",
145+
bc_dir.as_path().display()
146+
);
147+
fs::create_dir(&bc_dir).map_err(|e| Error::Generic(e.to_string()))?;
148+
}
149+
150+
Ok(bc_dir)
151+
}
152+
153+
fn open_database(wallet_opts: &WalletOpts) -> Result<AnyDatabase, Error> {
154+
let wallet_name = wallet_opts.wallet.as_ref().expect("wallet name");
155+
let database_path = prepare_wallet_db_dir(wallet_name)?;
156+
157+
#[cfg(feature = "key-value-db")]
158+
let config = AnyDatabaseConfig::Sled(SledDbConfiguration {
159+
path: database_path
160+
.into_os_string()
161+
.into_string()
162+
.expect("path string"),
163+
tree_name: wallet_name.to_string(),
164+
});
165+
#[cfg(feature = "sqlite-db")]
166+
let config = AnyDatabaseConfig::Sqlite(SqliteDbConfiguration {
167+
path: database_path
168+
.into_os_string()
169+
.into_string()
170+
.expect("path string"),
171+
});
172+
let database = AnyDatabase::from_config(&config)?;
120173
debug!("database opened successfully");
121-
Ok(tree)
174+
Ok(database)
122175
}
123176

124177
#[allow(dead_code)]
@@ -180,10 +233,11 @@ fn new_blockchain(
180233
}
181234
}
182235

236+
let wallet_name = wallet_opts.wallet.as_ref().expect("wallet name");
183237
AnyBlockchainConfig::CompactFilters(CompactFiltersBlockchainConfig {
184238
peers,
185239
network: _network,
186-
storage_dir: prepare_home_dir()?
240+
storage_dir: prepare_bc_dir(wallet_name)?
187241
.into_os_string()
188242
.into_string()
189243
.map_err(|_| Error::Generic("Internal OS_String conversion error".to_string()))?,

0 commit comments

Comments
 (0)