Skip to content

Commit c4e1139

Browse files
thunderbiscuit110CodingPValuedMammal
committed
docs: add KeyRing based examples
Also fixed original examples. Co-authored-by: codingp110 <codingp110@gmail.com> Co-authored-by: valued mammal <valuedmammal@protonmail.com>
1 parent 90b6971 commit c4e1139

12 files changed

Lines changed: 950 additions & 275 deletions

File tree

Cargo.toml

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,3 +74,23 @@ name = "esplora_blocking"
7474

7575
[[example]]
7676
name = "bitcoind_rpc"
77+
78+
[[example]]
79+
name = "multi_keychain_address_generation"
80+
path = "examples/multi_keychain/address_generation.rs"
81+
82+
[[example]]
83+
name = "multi_keychain_wallet"
84+
path = "examples/multi_keychain/wallet.rs"
85+
86+
[[example]]
87+
name = "multi_keychain_balance_tracking"
88+
path = "examples/multi_keychain/balance_tracking.rs"
89+
90+
[[example]]
91+
name = "multi_keychain_migration_guide"
92+
path = "examples/multi_keychain/migration_guide.rs"
93+
94+
[[example]]
95+
name = "multi_keychain_persistence"
96+
path = "examples/multi_keychain/persistence.rs"

examples/bitcoind_rpc.rs

Lines changed: 135 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ use bdk_bitcoind_rpc::{
66
use bdk_wallet::rusqlite::Connection;
77
use bdk_wallet::{
88
bitcoin::{Block, Network},
9-
KeychainKind, Wallet,
9+
keyring::KeyRing,
10+
KeychainKind, LoadParams, PersistedWallet, Wallet,
1011
};
1112
use clap::{self, Parser};
1213
use std::{
@@ -85,125 +86,139 @@ enum Emission {
8586
}
8687

8788
fn main() -> anyhow::Result<()> {
88-
// let args = Args::parse();
89-
90-
// let rpc_client = Arc::new(args.client()?);
91-
// println!(
92-
// "Connected to Bitcoin Core RPC at {:?}",
93-
// rpc_client.get_blockchain_info().unwrap()
94-
// );
95-
96-
// let start_load_wallet = Instant::now();
97-
// let mut db = Connection::open(args.db_path)?;
98-
// let wallet_opt = Wallet::load()
99-
// .descriptor(KeychainKind::External, Some(args.descriptor.clone()))
100-
// .descriptor(KeychainKind::Internal, args.change_descriptor.clone())
101-
// .extract_keys()
102-
// .check_network(args.network)
103-
// .load_wallet(&mut db)?;
104-
// let mut wallet = match wallet_opt {
105-
// Some(wallet) => wallet,
106-
// None => match &args.change_descriptor {
107-
// Some(change_desc) => Wallet::create(args.descriptor.clone(), change_desc.clone())
108-
// .network(args.network)
109-
// .create_wallet(&mut db)?,
110-
// None => Wallet::create_single(args.descriptor.clone())
111-
// .network(args.network)
112-
// .create_wallet(&mut db)?,
113-
// },
114-
// };
115-
// println!(
116-
// "Loaded wallet in {}s",
117-
// start_load_wallet.elapsed().as_secs_f32()
118-
// );
119-
120-
// let address = wallet.reveal_next_address(KeychainKind::External).address;
121-
// println!("Wallet address: {address}");
122-
123-
// let balance = wallet.balance();
124-
// println!("Wallet balance before syncing: {}", balance.total());
125-
126-
// let wallet_tip = wallet.latest_checkpoint();
127-
// println!(
128-
// "Wallet tip: {} at height {}",
129-
// wallet_tip.hash(),
130-
// wallet_tip.height()
131-
// );
132-
133-
// let (sender, receiver) = sync_channel::<Emission>(21);
134-
135-
// let signal_sender = sender.clone();
136-
// let _ = ctrlc::set_handler(move || {
137-
// signal_sender
138-
// .send(Emission::SigTerm)
139-
// .expect("failed to send sigterm")
140-
// });
141-
142-
// let mut emitter = Emitter::new(
143-
// rpc_client,
144-
// wallet_tip,
145-
// args.start_height,
146-
// wallet
147-
// .transactions()
148-
// .filter(|tx| tx.chain_position.is_unconfirmed()),
149-
// );
150-
// spawn(move || -> Result<(), anyhow::Error> {
151-
// while let Some(emission) = emitter.next_block()? {
152-
// sender.send(Emission::Block(emission))?;
153-
// }
154-
// sender.send(Emission::Mempool(emitter.mempool()?))?;
155-
// Ok(())
156-
// });
157-
158-
// let mut blocks_received = 0_usize;
159-
// for emission in receiver {
160-
// match emission {
161-
// Emission::SigTerm => {
162-
// println!("Sigterm received, exiting...");
163-
// break;
164-
// }
165-
// Emission::Block(block_emission) => {
166-
// blocks_received += 1;
167-
// let height = block_emission.block_height();
168-
// let hash = block_emission.block_hash();
169-
// let connected_to = block_emission.connected_to();
170-
// let start_apply_block = Instant::now();
171-
// wallet.apply_block_connected_to(&block_emission.block, height, connected_to)?;
172-
// wallet.persist(&mut db)?;
173-
// let elapsed = start_apply_block.elapsed().as_secs_f32();
174-
// println!("Applied block {hash} at height {height} in {elapsed}s");
175-
// }
176-
// Emission::Mempool(event) => {
177-
// let start_apply_mempool = Instant::now();
178-
// wallet.apply_evicted_txs(event.evicted);
179-
// wallet.apply_unconfirmed_txs(event.update);
180-
// wallet.persist(&mut db)?;
181-
// println!(
182-
// "Applied unconfirmed transactions in {}s",
183-
// start_apply_mempool.elapsed().as_secs_f32()
184-
// );
185-
// break;
186-
// }
187-
// }
188-
// }
189-
// let wallet_tip_end = wallet.latest_checkpoint();
190-
// let balance = wallet.balance();
191-
// println!(
192-
// "Synced {} blocks in {}s",
193-
// blocks_received,
194-
// start_load_wallet.elapsed().as_secs_f32(),
195-
// );
196-
// println!(
197-
// "Wallet tip is '{}:{}'",
198-
// wallet_tip_end.height(),
199-
// wallet_tip_end.hash()
200-
// );
201-
// println!("Wallet balance is {}", balance.total());
202-
// println!(
203-
// "Wallet has {} transactions and {} utxos",
204-
// wallet.transactions().count(),
205-
// wallet.list_unspent().count()
206-
// );
89+
let args = Args::parse();
90+
91+
let rpc_client = Arc::new(args.client()?);
92+
println!(
93+
"Connected to Bitcoin Core RPC at {:?}",
94+
rpc_client.get_blockchain_info().unwrap()
95+
);
96+
97+
let start_load_wallet = Instant::now();
98+
let mut db = Connection::open(args.db_path)?;
99+
100+
let mut params = LoadParams::new()
101+
.check_descriptor(KeychainKind::External, Some(args.descriptor.clone()))
102+
.check_genesis_hash(bitcoin::constants::genesis_block(args.network).block_hash())
103+
.check_network(args.network);
104+
105+
if let Some(desc) = &args.change_descriptor {
106+
params = params.check_descriptor(KeychainKind::Internal, Some(desc.clone()));
107+
}
108+
109+
let mut wallet = match params.load_wallet(&mut db).unwrap() {
110+
Some(wallet) => wallet,
111+
None => {
112+
let mut keyring: KeyRing<KeychainKind> = KeyRing::new(
113+
args.network,
114+
KeychainKind::External,
115+
args.descriptor.clone(),
116+
)
117+
.unwrap();
118+
if let Some(desc) = &args.change_descriptor {
119+
keyring
120+
.add_descriptor(KeychainKind::Internal, desc.clone())
121+
.unwrap();
122+
}
123+
Wallet::create(keyring).create_wallet(&mut db)?
124+
}
125+
};
126+
127+
println!(
128+
"Loaded wallet in {}s",
129+
start_load_wallet.elapsed().as_secs_f32()
130+
);
131+
132+
let address = wallet
133+
.next_unused_address(KeychainKind::External)
134+
.unwrap()
135+
.address;
136+
println!("Wallet address: {address}");
137+
138+
let balance = wallet.balance();
139+
println!("Wallet balance before syncing: {}", balance.total());
140+
141+
let wallet_tip = wallet.latest_checkpoint();
142+
println!(
143+
"Wallet tip: {} at height {}",
144+
wallet_tip.hash(),
145+
wallet_tip.height()
146+
);
147+
148+
let (sender, receiver) = sync_channel::<Emission>(21);
149+
150+
let signal_sender = sender.clone();
151+
let _ = ctrlc::set_handler(move || {
152+
signal_sender
153+
.send(Emission::SigTerm)
154+
.expect("failed to send sigterm")
155+
});
156+
157+
let mut emitter = Emitter::new(
158+
rpc_client,
159+
wallet_tip,
160+
args.start_height,
161+
wallet
162+
.transactions()
163+
.filter(|tx| tx.chain_position.is_unconfirmed()),
164+
);
165+
spawn(move || -> Result<(), anyhow::Error> {
166+
while let Some(emission) = emitter.next_block()? {
167+
sender.send(Emission::Block(emission))?;
168+
}
169+
sender.send(Emission::Mempool(emitter.mempool()?))?;
170+
Ok(())
171+
});
172+
173+
let mut blocks_received = 0_usize;
174+
for emission in receiver {
175+
match emission {
176+
Emission::SigTerm => {
177+
println!("Sigterm received, exiting...");
178+
break;
179+
}
180+
Emission::Block(block_emission) => {
181+
blocks_received += 1;
182+
let height = block_emission.block_height();
183+
let hash = block_emission.block_hash();
184+
let connected_to = block_emission.connected_to();
185+
let start_apply_block = Instant::now();
186+
wallet.apply_block_connected_to(&block_emission.block, height, connected_to)?;
187+
wallet.persist(&mut db)?;
188+
let elapsed = start_apply_block.elapsed().as_secs_f32();
189+
println!("Applied block {hash} at height {height} in {elapsed}s");
190+
}
191+
Emission::Mempool(event) => {
192+
let start_apply_mempool = Instant::now();
193+
wallet.apply_evicted_txs(event.evicted);
194+
wallet.apply_unconfirmed_txs(event.update);
195+
wallet.persist(&mut db)?;
196+
println!(
197+
"Applied unconfirmed transactions in {}s",
198+
start_apply_mempool.elapsed().as_secs_f32()
199+
);
200+
break;
201+
}
202+
}
203+
}
204+
let wallet_tip_end = wallet.latest_checkpoint();
205+
let balance = wallet.balance();
206+
println!(
207+
"Synced {} blocks in {}s",
208+
blocks_received,
209+
start_load_wallet.elapsed().as_secs_f32(),
210+
);
211+
println!(
212+
"Wallet tip is '{}:{}'",
213+
wallet_tip_end.height(),
214+
wallet_tip_end.hash()
215+
);
216+
println!("Wallet balance is {}", balance.total());
217+
println!(
218+
"Wallet has {} transactions and {} utxos",
219+
wallet.transactions().count(),
220+
wallet.list_unspent().count()
221+
);
207222

208223
Ok(())
209224
}

0 commit comments

Comments
 (0)