Skip to content

Commit ce0a17e

Browse files
committed
docs(wallet): for electrum, esplora examples use sqlite+testnet, print mempool.space URLs
For rpc example also add justfile to help testing with regtest bitcoind.
1 parent cd29221 commit ce0a17e

File tree

10 files changed

+202
-76
lines changed

10 files changed

+202
-76
lines changed

examples/example_wallet_electrum/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,6 @@ version = "0.2.0"
44
edition = "2021"
55

66
[dependencies]
7-
bdk_wallet = { path = "../../wallet", features = ["file_store"] }
7+
bdk_wallet = { path = "../../wallet", features = ["rusqlite"] }
88
bdk_electrum = { version = "0.23.0" }
99
anyhow = "1"

examples/example_wallet_electrum/src/main.rs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
use bdk_wallet::bitcoin::FeeRate;
2-
use bdk_wallet::file_store::Store;
32
use bdk_wallet::psbt::PsbtUtils;
43
use bdk_wallet::Wallet;
54
use std::io::Write;
@@ -9,23 +8,21 @@ use bdk_electrum::BdkElectrumClient;
98
use bdk_wallet::bitcoin::Amount;
109
use bdk_wallet::bitcoin::Network;
1110
use bdk_wallet::chain::collections::HashSet;
11+
use bdk_wallet::rusqlite::Connection;
1212
use bdk_wallet::{KeychainKind, SignOptions};
1313

14-
const DB_MAGIC: &str = "bdk_wallet_electrum_example";
1514
const SEND_AMOUNT: Amount = Amount::from_sat(5000);
1615
const STOP_GAP: usize = 50;
1716
const BATCH_SIZE: usize = 5;
1817

18+
const DB_PATH: &str = "bdk-example-electrum.sqlite";
1919
const NETWORK: Network = Network::Testnet;
2020
const EXTERNAL_DESC: &str = "wpkh(tprv8ZgxMBicQKsPdy6LMhUtFHAgpocR8GC6QmwMSFpZs7h6Eziw3SpThFfczTDh5rW2krkqffa11UpX3XkeTTB2FvzZKWXqPY54Y6Rq4AQ5R8L/84'/1'/0'/0/*)";
2121
const INTERNAL_DESC: &str = "wpkh(tprv8ZgxMBicQKsPdy6LMhUtFHAgpocR8GC6QmwMSFpZs7h6Eziw3SpThFfczTDh5rW2krkqffa11UpX3XkeTTB2FvzZKWXqPY54Y6Rq4AQ5R8L/84'/1'/0'/1/*)";
2222
const ELECTRUM_URL: &str = "ssl://electrum.blockstream.info:60002";
2323

2424
fn main() -> Result<(), anyhow::Error> {
25-
let db_path = "bdk-electrum-example.db";
26-
27-
let (mut db, _) = Store::<bdk_wallet::ChangeSet>::load_or_create(DB_MAGIC.as_bytes(), db_path)?;
28-
25+
let mut db = Connection::open(DB_PATH)?;
2926
let wallet_opt = Wallet::load()
3027
.descriptor(KeychainKind::External, Some(EXTERNAL_DESC))
3128
.descriptor(KeychainKind::Internal, Some(INTERNAL_DESC))
@@ -97,7 +94,7 @@ fn main() -> Result<(), anyhow::Error> {
9794
let tx = psbt.extract_tx()?;
9895
client.transaction_broadcast(&tx)?;
9996
let txid = tx.compute_txid();
100-
println!("Tx broadcasted! Txid: {txid}");
97+
println!("Tx broadcasted! Txid: https://mempool.space/testnet/tx/{txid}");
10198

10299
println!("Partial Sync...");
103100
print!("SCANNING: ");
@@ -120,8 +117,8 @@ fn main() -> Result<(), anyhow::Error> {
120117
wallet.apply_update(sync_update)?;
121118
wallet.persist(&mut db)?;
122119

123-
// bump fee tx
124-
let feerate = FeeRate::from_sat_per_kwu(tx_feerate.to_sat_per_kwu() + 250);
120+
// bump fee rate for tx by at least 1 sat per vbyte
121+
let feerate = FeeRate::from_sat_per_vb(tx_feerate.to_sat_per_vb_ceil() + 1).unwrap();
125122
let mut builder = wallet.build_fee_bump(txid).expect("failed to bump tx");
126123
builder.fee_rate(feerate);
127124
let mut bumped_psbt = builder.finish().unwrap();
@@ -146,7 +143,10 @@ fn main() -> Result<(), anyhow::Error> {
146143
original_fee
147144
);
148145
client.transaction_broadcast(&bumped_tx)?;
149-
println!("Broadcasted bumped tx. Txid: {}", bumped_tx.compute_txid());
146+
println!(
147+
"Broadcasted bumped tx. Txid: https://mempool.space/testnet/tx/{}",
148+
bumped_tx.compute_txid()
149+
);
150150

151151
print!("Syncing after bumped tx broadcast...");
152152
let sync_request = wallet.start_sync_with_revealed_spks().inspect(|_, _| {});

examples/example_wallet_esplora_async/src/main.rs

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -13,29 +13,29 @@ const STOP_GAP: usize = 5;
1313
const PARALLEL_REQUESTS: usize = 5;
1414

1515
const DB_PATH: &str = "bdk-example-esplora-async.sqlite";
16-
const NETWORK: Network = Network::Signet;
16+
const NETWORK: Network = Network::Testnet;
1717
const EXTERNAL_DESC: &str = "wpkh(tprv8ZgxMBicQKsPdy6LMhUtFHAgpocR8GC6QmwMSFpZs7h6Eziw3SpThFfczTDh5rW2krkqffa11UpX3XkeTTB2FvzZKWXqPY54Y6Rq4AQ5R8L/84'/1'/0'/0/*)";
1818
const INTERNAL_DESC: &str = "wpkh(tprv8ZgxMBicQKsPdy6LMhUtFHAgpocR8GC6QmwMSFpZs7h6Eziw3SpThFfczTDh5rW2krkqffa11UpX3XkeTTB2FvzZKWXqPY54Y6Rq4AQ5R8L/84'/1'/0'/1/*)";
19-
const ESPLORA_URL: &str = "http://signet.bitcoindevkit.net";
19+
const ESPLORA_URL: &str = "https://blockstream.info/testnet/api";
2020

2121
#[tokio::main]
2222
async fn main() -> Result<(), anyhow::Error> {
23-
let mut conn = Connection::open(DB_PATH)?;
23+
let mut db = Connection::open(DB_PATH)?;
2424
let wallet_opt = Wallet::load()
2525
.descriptor(KeychainKind::External, Some(EXTERNAL_DESC))
2626
.descriptor(KeychainKind::Internal, Some(INTERNAL_DESC))
2727
.extract_keys()
2828
.check_network(NETWORK)
29-
.load_wallet(&mut conn)?;
29+
.load_wallet(&mut db)?;
3030
let mut wallet = match wallet_opt {
3131
Some(wallet) => wallet,
3232
None => Wallet::create(EXTERNAL_DESC, INTERNAL_DESC)
3333
.network(NETWORK)
34-
.create_wallet(&mut conn)?,
34+
.create_wallet(&mut db)?,
3535
};
3636

3737
let address = wallet.next_unused_address(KeychainKind::External);
38-
wallet.persist(&mut conn)?;
38+
wallet.persist(&mut db)?;
3939
println!("Next unused address: ({}) {address}", address.index);
4040

4141
let balance = wallet.balance();
@@ -63,7 +63,7 @@ async fn main() -> Result<(), anyhow::Error> {
6363
.await?;
6464

6565
wallet.apply_update(update)?;
66-
wallet.persist(&mut conn)?;
66+
wallet.persist(&mut db)?;
6767
println!();
6868

6969
let balance = wallet.balance();
@@ -78,8 +78,15 @@ async fn main() -> Result<(), anyhow::Error> {
7878
println!("Please send at least {SEND_AMOUNT} to the receiving address");
7979
std::process::exit(0);
8080
}
81+
82+
// set fee rate for inclusion in 3 blocks so we can bump it later
83+
let fee_rate_estimates = client.get_fee_estimates().await?;
84+
let target_fee_rate =
85+
FeeRate::from_sat_per_vb(fee_rate_estimates.get(&3).unwrap().round() as u64).unwrap();
86+
8187
let mut tx_builder = wallet.build_tx();
8288
tx_builder.add_recipient(address.script_pubkey(), SEND_AMOUNT);
89+
tx_builder.fee_rate(target_fee_rate);
8390

8491
let mut psbt = tx_builder.finish()?;
8592
let finalized = wallet.sign(&mut psbt, SignOptions::default())?;
@@ -89,7 +96,7 @@ async fn main() -> Result<(), anyhow::Error> {
8996
let tx = psbt.extract_tx()?;
9097
client.broadcast(&tx).await?;
9198
let txid = tx.compute_txid();
92-
println!("Tx broadcasted! Txid: {txid}");
99+
println!("Tx broadcasted! Txid: https://mempool.space/testnet/tx/{txid}");
93100

94101
println!("Partial Sync...");
95102
print!("SCANNING: ");
@@ -109,9 +116,10 @@ async fn main() -> Result<(), anyhow::Error> {
109116
let sync_update = client.sync(sync_request, PARALLEL_REQUESTS).await?;
110117
println!();
111118
wallet.apply_update(sync_update)?;
112-
wallet.persist(&mut conn)?;
119+
wallet.persist(&mut db)?;
113120

114-
let feerate = FeeRate::from_sat_per_kwu(tx_feerate.to_sat_per_kwu() + 250);
121+
// bump fee rate for tx by at least 1 sat per vbyte
122+
let feerate = FeeRate::from_sat_per_vb(tx_feerate.to_sat_per_vb_ceil() + 1).unwrap();
115123
let mut builder = wallet.build_fee_bump(txid).expect("failed to bump tx");
116124
builder.fee_rate(feerate);
117125
let mut bumped_psbt = builder.finish().unwrap();
@@ -134,7 +142,10 @@ async fn main() -> Result<(), anyhow::Error> {
134142
"New fee ({new_fee}) should be higher than original ({original_fee})",
135143
);
136144
client.broadcast(&bumped_tx).await?;
137-
println!("Broadcasted bumped tx. Txid: {}", bumped_tx.compute_txid());
145+
println!(
146+
"Broadcasted bumped tx. Txid: https://mempool.space/testnet/tx/{}",
147+
bumped_tx.compute_txid()
148+
);
138149

139150
println!("syncing after broadcasting bumped tx...");
140151
print!("SCANNING: ");
@@ -174,7 +185,7 @@ async fn main() -> Result<(), anyhow::Error> {
174185
}
175186

176187
wallet.apply_update(sync_update)?;
177-
wallet.persist(&mut conn)?;
188+
wallet.persist(&mut db)?;
178189

179190
let balance_after_sync = wallet.balance();
180191
println!("Wallet balance after sync: {}", balance_after_sync.total());

examples/example_wallet_esplora_blocking/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,6 @@ publish = false
77
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
88

99
[dependencies]
10-
bdk_wallet = { path = "../../wallet", features = ["file_store"] }
10+
bdk_wallet = { path = "../../wallet", features = ["rusqlite"] }
1111
bdk_esplora = { version = "0.22.0", features = ["blocking"] }
1212
anyhow = "1"

examples/example_wallet_esplora_blocking/src/main.rs

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,24 @@
11
use bdk_esplora::{esplora_client, EsploraExt};
2+
use bdk_wallet::rusqlite::Connection;
23
use bdk_wallet::{
34
bitcoin::{Amount, FeeRate, Network},
4-
file_store::Store,
55
psbt::PsbtUtils,
66
KeychainKind, SignOptions, Wallet,
77
};
88
use std::{collections::BTreeSet, io::Write};
99

10-
const DB_MAGIC: &str = "bdk_wallet_esplora_example";
11-
const DB_PATH: &str = "bdk-example-esplora-blocking.db";
1210
const SEND_AMOUNT: Amount = Amount::from_sat(5000);
1311
const STOP_GAP: usize = 5;
1412
const PARALLEL_REQUESTS: usize = 5;
1513

16-
const NETWORK: Network = Network::Signet;
14+
const DB_PATH: &str = "bdk-example-esplora-blocking.sqlite";
15+
const NETWORK: Network = Network::Testnet;
1716
const EXTERNAL_DESC: &str = "wpkh(tprv8ZgxMBicQKsPdy6LMhUtFHAgpocR8GC6QmwMSFpZs7h6Eziw3SpThFfczTDh5rW2krkqffa11UpX3XkeTTB2FvzZKWXqPY54Y6Rq4AQ5R8L/84'/1'/0'/0/*)";
1817
const INTERNAL_DESC: &str = "wpkh(tprv8ZgxMBicQKsPdy6LMhUtFHAgpocR8GC6QmwMSFpZs7h6Eziw3SpThFfczTDh5rW2krkqffa11UpX3XkeTTB2FvzZKWXqPY54Y6Rq4AQ5R8L/84'/1'/0'/1/*)";
19-
const ESPLORA_URL: &str = "http://signet.bitcoindevkit.net";
18+
const ESPLORA_URL: &str = "https://blockstream.info/testnet/api";
2019

2120
fn main() -> Result<(), anyhow::Error> {
22-
let (mut db, _) = Store::<bdk_wallet::ChangeSet>::load_or_create(DB_MAGIC.as_bytes(), DB_PATH)?;
23-
21+
let mut db = Connection::open(DB_PATH)?;
2422
let wallet_opt = Wallet::load()
2523
.descriptor(KeychainKind::External, Some(EXTERNAL_DESC))
2624
.descriptor(KeychainKind::Internal, Some(INTERNAL_DESC))
@@ -74,8 +72,14 @@ fn main() -> Result<(), anyhow::Error> {
7472
std::process::exit(0);
7573
}
7674

75+
// set fee rate for inclusion in 3 blocks so we can bump it later
76+
let fee_rate_estimates = client.get_fee_estimates()?;
77+
let target_fee_rate =
78+
FeeRate::from_sat_per_vb(fee_rate_estimates.get(&3).unwrap().round() as u64).unwrap();
79+
7780
let mut tx_builder = wallet.build_tx();
7881
tx_builder.add_recipient(address.script_pubkey(), SEND_AMOUNT);
82+
tx_builder.fee_rate(target_fee_rate);
7983

8084
let mut psbt = tx_builder.finish()?;
8185
let finalized = wallet.sign(&mut psbt, SignOptions::default())?;
@@ -85,7 +89,7 @@ fn main() -> Result<(), anyhow::Error> {
8589
let tx = psbt.extract_tx()?;
8690
client.broadcast(&tx)?;
8791
let txid = tx.compute_txid();
88-
println!("Tx broadcasted! Txid: {txid}");
92+
println!("Tx broadcasted! Txid: https://mempool.space/testnet/tx/{txid}");
8993

9094
println!("Partial Sync...");
9195
print!("SCANNING: ");
@@ -108,7 +112,8 @@ fn main() -> Result<(), anyhow::Error> {
108112
wallet.persist(&mut db)?;
109113
println!();
110114

111-
let feerate = FeeRate::from_sat_per_kwu(tx_feerate.to_sat_per_kwu() + 200);
115+
// bump fee rate for tx by at least 1 sat per vbyte
116+
let feerate = FeeRate::from_sat_per_vb(tx_feerate.to_sat_per_vb_ceil() + 1).unwrap();
112117
let mut builder = wallet.build_fee_bump(txid).unwrap();
113118
builder.fee_rate(feerate);
114119
let mut new_psbt = builder.finish().unwrap();
@@ -132,7 +137,7 @@ fn main() -> Result<(), anyhow::Error> {
132137
);
133138
client.broadcast(&bumped_tx)?;
134139
println!(
135-
"Broadcast replacement transaction. Txid: {}",
140+
"Broadcast replacement transaction. Txid: https://mempool.space/testnet/tx/{}",
136141
bumped_tx.compute_txid()
137142
);
138143

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
test_data/

examples/example_wallet_rpc/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ edition = "2021"
66
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
77

88
[dependencies]
9-
bdk_wallet = { path = "../../wallet", features = ["file_store"] }
9+
bdk_wallet = { path = "../../wallet", features = ["rusqlite"] }
1010
bdk_bitcoind_rpc = { version = "0.20.0" }
1111

1212
anyhow = "1"

examples/example_wallet_rpc/README.md

Lines changed: 31 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,34 @@
11
# Wallet RPC Example
22

3-
```
4-
$ cargo run --bin example_wallet_rpc -- --help
5-
6-
Bitcoind RPC example using `bdk_wallet::Wallet`
7-
8-
Usage: example_wallet_rpc [OPTIONS] <DESCRIPTOR> [CHANGE_DESCRIPTOR]
9-
10-
Arguments:
11-
<DESCRIPTOR> Wallet descriptor [env: DESCRIPTOR=]
12-
[CHANGE_DESCRIPTOR] Wallet change descriptor [env: CHANGE_DESCRIPTOR=]
13-
14-
Options:
15-
--start-height <START_HEIGHT> Earliest block height to start sync from [env: START_HEIGHT=] [default: 0]
16-
17-
--network <NETWORK> Bitcoin network to connect to [env: BITCOIN_NETWORK=] [default: regtest]
18-
19-
--db-path <DB_PATH> Where to store wallet data [env: BDK_DB_PATH=] [default: .bdk_wallet_rpc_example.db]
20-
21-
--url <URL> RPC URL [env: RPC_URL=] [default: 127.0.0.1:18443]
22-
23-
--rpc-cookie <RPC_COOKIE> RPC auth cookie file [env: RPC_COOKIE=]
24-
25-
--rpc-user <RPC_USER> RPC auth username [env: RPC_USER=]
26-
27-
--rpc-pass <RPC_PASS> RPC auth password [env: RPC_PASS=]
28-
29-
-h, --help Print help
30-
31-
-V, --version Print version
32-
33-
```
3+
1. Install bitcoind
4+
2. Start bitcoind in regtest mode.
5+
```
6+
just start
7+
```
8+
3. Create test bitcoind wallet and generate regtest blocks.
9+
```
10+
just create
11+
just generate 110 $(just address)
12+
```
13+
4. Run the example and note the wallet's address and balance.
14+
```
15+
just run
16+
```
17+
5. Send regtest coins to the wallet address.
18+
```
19+
just send 10 <wallet address>
20+
just generate 6 $(just address)
21+
```
22+
6. Re-run example and note the new balance.
23+
```
24+
just run
25+
```
26+
7. Kill the regtest bitcoind.
27+
```
28+
just kill
29+
```
30+
8. Cleanup test data (optional).
31+
```
32+
just clean
33+
```
3434

0 commit comments

Comments
 (0)