Skip to content
Open
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -74,3 +74,6 @@ name = "esplora_blocking"

[[example]]
name = "bitcoind_rpc"

[[example]]
name = "simple_keyring"
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ To persist `Wallet` state use a data storage crate that reads and writes [`Chang
* [`bdk_file_store`]: Stores wallet changes in a simple flat file.
* `rusqlite`: Stores wallet changes in a SQLite database.

**Example**
<!-- **Example**

```rust,no_run
use bdk_wallet::rusqlite;
Expand Down Expand Up @@ -110,7 +110,7 @@ wallet.persist(&mut conn)?;

println!("Next receive address: {}", address_info.address);
Ok::<_, anyhow::Error>(())
```
``` -->

## Minimum Supported Rust Version (MSRV)

Expand Down
221 changes: 111 additions & 110 deletions examples/bitcoind_rpc.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#![allow(unused)]
use bdk_bitcoind_rpc::{
bitcoincore_rpc::{Auth, Client, RpcApi},
Emitter, MempoolEvent,
Expand Down Expand Up @@ -84,125 +85,125 @@ enum Emission {
}

fn main() -> anyhow::Result<()> {
let args = Args::parse();
// let args = Args::parse();

let rpc_client = Arc::new(args.client()?);
println!(
"Connected to Bitcoin Core RPC at {:?}",
rpc_client.get_blockchain_info().unwrap()
);
// let rpc_client = Arc::new(args.client()?);
// println!(
// "Connected to Bitcoin Core RPC at {:?}",
// rpc_client.get_blockchain_info().unwrap()
// );

let start_load_wallet = Instant::now();
let mut db = Connection::open(args.db_path)?;
let wallet_opt = Wallet::load()
.descriptor(KeychainKind::External, Some(args.descriptor.clone()))
.descriptor(KeychainKind::Internal, args.change_descriptor.clone())
.extract_keys()
.check_network(args.network)
.load_wallet(&mut db)?;
let mut wallet = match wallet_opt {
Some(wallet) => wallet,
None => match &args.change_descriptor {
Some(change_desc) => Wallet::create(args.descriptor.clone(), change_desc.clone())
.network(args.network)
.create_wallet(&mut db)?,
None => Wallet::create_single(args.descriptor.clone())
.network(args.network)
.create_wallet(&mut db)?,
},
};
println!(
"Loaded wallet in {}s",
start_load_wallet.elapsed().as_secs_f32()
);
// let start_load_wallet = Instant::now();
// let mut db = Connection::open(args.db_path)?;
// let wallet_opt = Wallet::load()
// .descriptor(KeychainKind::External, Some(args.descriptor.clone()))
// .descriptor(KeychainKind::Internal, args.change_descriptor.clone())
// .extract_keys()
// .check_network(args.network)
// .load_wallet(&mut db)?;
// let mut wallet = match wallet_opt {
// Some(wallet) => wallet,
// None => match &args.change_descriptor {
// Some(change_desc) => Wallet::create(args.descriptor.clone(), change_desc.clone())
// .network(args.network)
// .create_wallet(&mut db)?,
// None => Wallet::create_single(args.descriptor.clone())
// .network(args.network)
// .create_wallet(&mut db)?,
// },
// };
// println!(
// "Loaded wallet in {}s",
// start_load_wallet.elapsed().as_secs_f32()
// );

let address = wallet.reveal_next_address(KeychainKind::External).address;
println!("Wallet address: {address}");
// let address = wallet.reveal_next_address(KeychainKind::External).address;
// println!("Wallet address: {address}");

let balance = wallet.balance();
println!("Wallet balance before syncing: {}", balance.total());
// let balance = wallet.balance();
// println!("Wallet balance before syncing: {}", balance.total());

let wallet_tip = wallet.latest_checkpoint();
println!(
"Wallet tip: {} at height {}",
wallet_tip.hash(),
wallet_tip.height()
);
// let wallet_tip = wallet.latest_checkpoint();
// println!(
// "Wallet tip: {} at height {}",
// wallet_tip.hash(),
// wallet_tip.height()
// );

let (sender, receiver) = sync_channel::<Emission>(21);
// let (sender, receiver) = sync_channel::<Emission>(21);

let signal_sender = sender.clone();
let _ = ctrlc::set_handler(move || {
signal_sender
.send(Emission::SigTerm)
.expect("failed to send sigterm")
});
// let signal_sender = sender.clone();
// let _ = ctrlc::set_handler(move || {
// signal_sender
// .send(Emission::SigTerm)
// .expect("failed to send sigterm")
// });

let mut emitter = Emitter::new(
rpc_client,
wallet_tip,
args.start_height,
wallet
.transactions()
.filter(|tx| tx.chain_position.is_unconfirmed()),
);
spawn(move || -> Result<(), anyhow::Error> {
while let Some(emission) = emitter.next_block()? {
sender.send(Emission::Block(emission))?;
}
sender.send(Emission::Mempool(emitter.mempool()?))?;
Ok(())
});
// let mut emitter = Emitter::new(
// rpc_client,
// wallet_tip,
// args.start_height,
// wallet
// .transactions()
// .filter(|tx| tx.chain_position.is_unconfirmed()),
// );
// spawn(move || -> Result<(), anyhow::Error> {
// while let Some(emission) = emitter.next_block()? {
// sender.send(Emission::Block(emission))?;
// }
// sender.send(Emission::Mempool(emitter.mempool()?))?;
// Ok(())
// });

let mut blocks_received = 0_usize;
for emission in receiver {
match emission {
Emission::SigTerm => {
println!("Sigterm received, exiting...");
break;
}
Emission::Block(block_emission) => {
blocks_received += 1;
let height = block_emission.block_height();
let hash = block_emission.block_hash();
let connected_to = block_emission.connected_to();
let start_apply_block = Instant::now();
wallet.apply_block_connected_to(&block_emission.block, height, connected_to)?;
wallet.persist(&mut db)?;
let elapsed = start_apply_block.elapsed().as_secs_f32();
println!("Applied block {hash} at height {height} in {elapsed}s");
}
Emission::Mempool(event) => {
let start_apply_mempool = Instant::now();
wallet.apply_evicted_txs(event.evicted);
wallet.apply_unconfirmed_txs(event.update);
wallet.persist(&mut db)?;
println!(
"Applied unconfirmed transactions in {}s",
start_apply_mempool.elapsed().as_secs_f32()
);
break;
}
}
}
let wallet_tip_end = wallet.latest_checkpoint();
let balance = wallet.balance();
println!(
"Synced {} blocks in {}s",
blocks_received,
start_load_wallet.elapsed().as_secs_f32(),
);
println!(
"Wallet tip is '{}:{}'",
wallet_tip_end.height(),
wallet_tip_end.hash()
);
println!("Wallet balance is {}", balance.total());
println!(
"Wallet has {} transactions and {} utxos",
wallet.transactions().count(),
wallet.list_unspent().count()
);
// let mut blocks_received = 0_usize;
// for emission in receiver {
// match emission {
// Emission::SigTerm => {
// println!("Sigterm received, exiting...");
// break;
// }
// Emission::Block(block_emission) => {
// blocks_received += 1;
// let height = block_emission.block_height();
// let hash = block_emission.block_hash();
// let connected_to = block_emission.connected_to();
// let start_apply_block = Instant::now();
// wallet.apply_block_connected_to(&block_emission.block, height, connected_to)?;
// wallet.persist(&mut db)?;
// let elapsed = start_apply_block.elapsed().as_secs_f32();
// println!("Applied block {hash} at height {height} in {elapsed}s");
// }
// Emission::Mempool(event) => {
// let start_apply_mempool = Instant::now();
// wallet.apply_evicted_txs(event.evicted);
// wallet.apply_unconfirmed_txs(event.update);
// wallet.persist(&mut db)?;
// println!(
// "Applied unconfirmed transactions in {}s",
// start_apply_mempool.elapsed().as_secs_f32()
// );
// break;
// }
// }
// }
// let wallet_tip_end = wallet.latest_checkpoint();
// let balance = wallet.balance();
// println!(
// "Synced {} blocks in {}s",
// blocks_received,
// start_load_wallet.elapsed().as_secs_f32(),
// );
// println!(
// "Wallet tip is '{}:{}'",
// wallet_tip_end.height(),
// wallet_tip_end.hash()
// );
// println!("Wallet balance is {}", balance.total());
// println!(
// "Wallet has {} transactions and {} utxos",
// wallet.transactions().count(),
// wallet.list_unspent().count()
// );

Ok(())
}
81 changes: 43 additions & 38 deletions examples/compiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
// You may not use this file except in accordance with one or both of these
// licenses.

#![allow(unused)]
extern crate bdk_wallet;
extern crate bitcoin;
extern crate miniscript;
extern crate serde_json;
// extern crate bitcoin;
// extern crate miniscript;
// extern crate serde_json;

use std::error::Error;
use std::str::FromStr;
Expand All @@ -32,47 +32,52 @@ use bdk_wallet::{KeychainKind, Wallet};
/// This example demonstrates the interaction between a bdk wallet and miniscript policy.
#[allow(clippy::print_stdout)]
fn main() -> Result<(), Box<dyn Error>> {
// We start with a miniscript policy string
let policy_str = "or(
10@thresh(4,
pk(029ffbe722b147f3035c87cb1c60b9a5947dd49c774cc31e94773478711a929ac0),pk(025f05815e3a1a8a83bfbb03ce016c9a2ee31066b98f567f6227df1d76ec4bd143),pk(025625f41e4a065efc06d5019cbbd56fe8c07595af1231e7cbc03fafb87ebb71ec),pk(02a27c8b850a00f67da3499b60562673dcf5fdfb82b7e17652a7ac54416812aefd),pk(03e618ec5f384d6e19ca9ebdb8e2119e5bef978285076828ce054e55c4daf473e2)
),1@and(
older(4209713),
thresh(2,
pk(03deae92101c790b12653231439f27b8897264125ecb2f46f48278603102573165),pk(033841045a531e1adf9910a6ec279589a90b3b8a904ee64ffd692bd08a8996c1aa),pk(02aebf2d10b040eb936a6f02f44ee82f8b34f5c1ccb20ff3949c2b28206b7c1068)
)
)
)"
.replace(&[' ', '\n', '\t'][..], "");
// // We start with a miniscript policy string
// let policy_str = "or(
// 10@thresh(4,
// pk(029ffbe722b147f3035c87cb1c60b9a5947dd49c774cc31e94773478711a929ac0),
// pk(025f05815e3a1a8a83bfbb03ce016c9a2ee31066b98f567f6227df1d76ec4bd143),
// pk(025625f41e4a065efc06d5019cbbd56fe8c07595af1231e7cbc03fafb87ebb71ec),
// pk(02a27c8b850a00f67da3499b60562673dcf5fdfb82b7e17652a7ac54416812aefd),
// pk(03e618ec5f384d6e19ca9ebdb8e2119e5bef978285076828ce054e55c4daf473e2) ),1@and(
// older(4209713),
// thresh(2,
//
// pk(03deae92101c790b12653231439f27b8897264125ecb2f46f48278603102573165),
// pk(033841045a531e1adf9910a6ec279589a90b3b8a904ee64ffd692bd08a8996c1aa),
// pk(02aebf2d10b040eb936a6f02f44ee82f8b34f5c1ccb20ff3949c2b28206b7c1068) )
// )
// )"
// .replace(&[' ', '\n', '\t'][..], "");

println!("Compiling policy: \n{policy_str}");
// println!("Compiling policy: \n{policy_str}");

// Parse the string as a [`Concrete`] type miniscript policy.
let policy = Concrete::<String>::from_str(&policy_str)?;
// // Parse the string as a [`Concrete`] type miniscript policy.
// let policy = Concrete::<String>::from_str(&policy_str)?;

// Create a `wsh` type descriptor from the policy.
// `policy.compile()` returns the resulting miniscript from the policy.
let descriptor = Descriptor::new_wsh(policy.compile()?)?.to_string();
// // Create a `wsh` type descriptor from the policy.
// // `policy.compile()` returns the resulting miniscript from the policy.
// let descriptor = Descriptor::new_wsh(policy.compile()?)?.to_string();

println!("Compiled into Descriptor: \n{descriptor}");
// println!("Compiled into Descriptor: \n{descriptor}");

// Create a new wallet from descriptors
let mut wallet = Wallet::create_single(descriptor)
.network(Network::Regtest)
.create_wallet_no_persist()?;
// // Create a new wallet from descriptors
// let mut wallet = Wallet::create_single(descriptor)
// .network(Network::Regtest)
// .create_wallet_no_persist()?;

println!(
"First derived address from the descriptor: \n{}",
wallet.next_unused_address(KeychainKind::External),
);
// println!(
// "First derived address from the descriptor: \n{}",
// wallet.next_unused_address(KeychainKind::External),
// );

// BDK also has it's own `Policy` structure to represent the spending condition in a more
// human readable json format.
let spending_policy = wallet.policies(KeychainKind::External)?;
println!(
"The BDK spending policy: \n{}",
serde_json::to_string_pretty(&spending_policy)?
);
// // BDK also has it's own `Policy` structure to represent the spending condition in a more
// // human readable json format.
// let spending_policy = wallet.policies(KeychainKind::External)?;
// println!(
// "The BDK spending policy: \n{}",
// serde_json::to_string_pretty(&spending_policy)?
// );

Ok(())
}
Loading