Skip to content

Commit

Permalink
wip: update example to use sqlite
Browse files Browse the repository at this point in the history
Requires a patch to bdk release/0.29 to update
rusqlite dependency to 0.31
  • Loading branch information
ValuedMammal committed Oct 22, 2024
1 parent eb7328f commit 8756a9f
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 45 deletions.
5 changes: 4 additions & 1 deletion example-crates/example_migrate_wallet/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ version = "0.1.0"
edition = "2021"

[dependencies]
bdk = { version = "0.29" }
anyhow = "1"
# TODO: We should be able to patch bdk v0.29 to depend on rusqlite v0.31
#bdk = { version = "0.30", features = ["sqlite"] }
bdk = { git = "https://github.com/ValuedMammal/bdk", branch = "release/0.29-deps-rusqlite", features = ["sqlite"] }
bdk_wallet = { path = "../../crates/wallet", features = ["rusqlite"] }
bdk_electrum = { path = "../../crates/electrum" }
82 changes: 38 additions & 44 deletions example-crates/example_migrate_wallet/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,42 +2,37 @@ use std::collections::HashSet;
use std::io::Write;

use bdk::bitcoin::Network;
use bdk::sled;
use bdk::database::SqliteDatabase;
use bdk::wallet::{AddressIndex, Wallet};

use bdk_electrum::{electrum_client, BdkElectrumClient};
use bdk_wallet::rusqlite;

const DESC: &str = "tr([83737d5e/86'/1'/0']tpubDDR5GgtoxS8fJyjjvdahN4VzV5DV6jtbcyvVXhEKq2XtpxjxBXmxH3r8QrNbQqHg4bJM1EGkxi7Pjfkgnui9jQWqS7kxHvX6rhUeriLDKxz/0/*)";
const CHANGE_DESC: &str = "tr([83737d5e/86'/1'/0']tpubDDR5GgtoxS8fJyjjvdahN4VzV5DV6jtbcyvVXhEKq2XtpxjxBXmxH3r8QrNbQqHg4bJM1EGkxi7Pjfkgnui9jQWqS7kxHvX6rhUeriLDKxz/1/*)";
const DESC: &str = "wpkh(tprv8ZgxMBicQKsPdy6LMhUtFHAgpocR8GC6QmwMSFpZs7h6Eziw3SpThFfczTDh5rW2krkqffa11UpX3XkeTTB2FvzZKWXqPY54Y6Rq4AQ5R8L/84'/1'/0'/0/*)";
const CHANGE_DESC: &str = "wpkh(tprv8ZgxMBicQKsPdy6LMhUtFHAgpocR8GC6QmwMSFpZs7h6Eziw3SpThFfczTDh5rW2krkqffa11UpX3XkeTTB2FvzZKWXqPY54Y6Rq4AQ5R8L/84'/1'/0'/1/*)";
const ELECTRUM_URL: &str = "ssl://mempool.space:60602";
const NETWORK: Network = Network::Signet;

// Steps for migrating wallet details from bdk v0.29 to bdk_wallet v1.0. For this example we assume
// the previous wallet was backed by `sled` and the new wallet will use sqlite. (steps will be
// similar if coming from sqlite, but we can't easily depend on multiple versions of rusqlite
// in the same project).
const BDK_DB_PATH: &str = "example-bdk.sqlite";
const BDK_WALLET_DB_PATH: &str = "example-bdk-wallet.sqlite";

// Run this with `cargo run` and optionally providing a path and tree name
// for an existing sled db
// Steps for migrating wallet details from bdk v0.29 to bdk_wallet v1.0. These steps
// are applicable to wallets backed by a SQLite database.

// Usage: `cargo run -- [db_path tree_name]`
// May be run with no arguments or optionally providing a path to an existing sqlite db
// e.g. `cargo run --bin example_migrate_wallet -- <path-to-bdk-database>`

fn main() -> Result<(), Box<dyn std::error::Error>> {
fn main() -> anyhow::Result<()> {
let cargo_dir = std::env::var("CARGO_MANIFEST_DIR")?;

// Accept a db config passed in via command line, or else create a new one for testing
let mut args = std::env::args();
_ = args.next();
let args: Vec<String> = args.collect();

let args: Vec<String> = std::env::args().collect();
let db = if args.len() < 2 {
let path = format!("{}/sled", cargo_dir);
sled::open(path)?.open_tree("wallet")?
let path = format!("{}/{}", cargo_dir, BDK_DB_PATH);
SqliteDatabase::new(path)
} else {
let path = args[0].to_string();
let tree_name = args[1].to_string();
sled::open(path)?.open_tree(tree_name)?
let path = args[1].to_string();
SqliteDatabase::new(path)
};

// Open wallet
Expand All @@ -46,39 +41,36 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
// Get last revealed addresses for each keychain
let addr = wallet.get_address(AddressIndex::LastUnused)?;
println!("Last revealed external {} {}", addr.index, addr.address);
let last_revealed_external = addr.index;
let external_derivation_index = addr.index;
let last_revealed_external = addr.address.to_string();

let addr = wallet.get_internal_address(AddressIndex::LastUnused)?;
println!("Last revealed internal {} {}", addr.index, addr.address);
let last_revealed_internal = addr.index;

// Get descriptors
// Or we can use the same `DESC` and `CHANGE_DESC` from above.
// let descriptor = wallet.public_descriptor(KeychainKind::External)?.unwrap().to_string();
// let change_descriptor = wallet.public_descriptor(KeychainKind::Internal)?.unwrap().to_string();

// Note:
// If wallet 1 was created with signing keys we could try to get the signers from it as well, however
// we'll get a compiler error if we try to pass these to wallet 2, as it is using a different version
// of rust-miniscript. Since the old bdk made you provide the descriptors at startup, we can assume
// they are also available when doing the migration, so private keys will carry over if desired.
// let signers_external = wallet.get_signers(KeychainKind::External).as_key_map(wallet.secp_ctx());
// let signers_internal = wallet.get_signers(KeychainKind::Internal).as_key_map(wallet.secp_ctx());
drop(wallet);
let internal_derivation_index = addr.index;
let last_revealed_internal = addr.address.to_string();

// Create new wallet
let new_db_path = format!("{}/wallet.sqlite", cargo_dir);
// For the new bdk wallet we pass in the same descriptors as before. If the given descriptors
// contain secret keys the wallet will be able to sign transactions as well.
let new_db_path = format!("{}/{}", cargo_dir, BDK_WALLET_DB_PATH);
let mut db = rusqlite::Connection::open(new_db_path)?;
let mut wallet = match bdk_wallet::Wallet::load().load_wallet(&mut db)? {
Some(wallet) => wallet,
None => bdk_wallet::Wallet::create(DESC, CHANGE_DESC)
.network(bdk_wallet::bitcoin::Network::Signet)
.create_wallet(&mut db)?,
let mut wallet = match bdk_wallet::Wallet::create(DESC, CHANGE_DESC)
.network(bdk_wallet::bitcoin::Network::Signet)
.create_wallet(&mut db)
{
Ok(wallet) => wallet,
Err(_) => anyhow::bail!("should not have existing db"),
};

// Retore revealed addresses
let _ = wallet.reveal_addresses_to(bdk_wallet::KeychainKind::External, last_revealed_external);
let _ = wallet.reveal_addresses_to(bdk_wallet::KeychainKind::Internal, last_revealed_internal);
let _ = wallet.reveal_addresses_to(
bdk_wallet::KeychainKind::External,
external_derivation_index,
);
let _ = wallet.reveal_addresses_to(
bdk_wallet::KeychainKind::Internal,
internal_derivation_index,
);

// Remember to persist the new wallet
wallet.persist(&mut db)?;
Expand All @@ -89,12 +81,14 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
.list_unused_addresses(bdk_wallet::KeychainKind::External)
.last()
.unwrap();
assert_eq!(addr.to_string(), last_revealed_external);
println!("Last revealed external {} {}", addr.index, addr.address);
let addr = wallet
.list_unused_addresses(bdk_wallet::KeychainKind::Internal)
.last()
.unwrap();
println!("Last revealed internal {} {}", addr.index, addr.address);
assert_eq!(addr.to_string(), last_revealed_internal);

// Now that we migrated the wallet details, you likely want to rescan the blockchain
// to restore transaction data for wallet 2. Here we're using the bdk_electrum client
Expand Down

0 comments on commit 8756a9f

Please sign in to comment.