bdk/examples/esplora.rs
LLFourn aab2b12f7a
bdk_core integration initial commit 🔥
We prepare the BDK repo for a major restructuring.

- database modules removed
- blockchain module removed
- minimal API changes.
- Many macros removed.
- no longer applicable examples removed.
- Much conditional compilation removed. Can compile with --all-features.
- delete verify module
2023-03-02 10:55:07 +01:00

113 lines
4.1 KiB
Rust

use bdk::{
blockchain::esplora::{esplora_client, BlockingClientExt},
wallet::AddressIndex,
Wallet,
};
use bdk_test_client::{RpcApi, TestClient};
use bitcoin::{Amount, Network};
use rand::Rng;
use std::error::Error;
fn main() -> Result<(), Box<dyn Error>> {
let _ = env_logger::init();
const DESCRIPTOR: &'static str ="tr([73c5da0a/86'/0'/0']tprv8cSrHfiTQQWzKVejDHvBcvW4pdLEDLMvtVdbUXFfceQ4kbZKMsuFWbd3LUN3omNrQfafQaPwXUFXtcofkE9UjFZ3i9deezBHQTGvYV2xUzz/0/*)";
const CHANGE_DESCRIPTOR: &'static str = "tr(tprv8ZgxMBicQKsPeQe98SGJ53vEJ7MNEFkQ4CkZmrr6PNom3vn6GqxuyoE78smkzpuP347zR9MXPg38PoZ8tbxLqSx4CufufHAGbQ9Hf7yTTwn/44'/0'/0'/1/*)#pxy2d75a";
let mut test_client = TestClient::default();
let esplora_url = format!(
"http://{}",
test_client.electrsd.esplora_url.as_ref().unwrap()
);
let client = esplora_client::Builder::new(&esplora_url).build_blocking()?;
let wallet = Wallet::new(DESCRIPTOR, Some(CHANGE_DESCRIPTOR), Network::Regtest)
.expect("parsing descriptors failed");
// note we don't *need* the Mutex for this example but it helps to show when the wallet does and
// doesn't need to be mutablek
let wallet = std::sync::Mutex::new(wallet);
let n_initial_transactions = 10;
let addresses = {
// we need it to be mutable to get a new address.
// This incremenents the derivatoin index of the keychain.
let mut wallet = wallet.lock().unwrap();
core::iter::repeat_with(|| wallet.get_address(AddressIndex::New))
.filter(|_| rand::thread_rng().gen_bool(0.5))
.take(n_initial_transactions)
.collect::<Vec<_>>()
};
// get some coins for the internal node
test_client.generate(100, None);
for address in addresses {
let exp_txid = test_client
.send_to_address(
&address,
Amount::from_sat(10_000),
None,
None,
None,
None,
None,
None,
)
.expect("tx should send");
eprintln!(
"💸 sending some coins to: {} (index {}) in tx {}",
address, address.index, exp_txid
);
// sometimes generate a block after we send coins to the address
if rand::thread_rng().gen_bool(0.3) {
let height = test_client.generate(1, None);
eprintln!("📦 created a block at height {}", height);
}
}
let wait_for_esplora_sync = std::time::Duration::from_secs(5);
println!("⏳ waiting {}s for esplora to catch up..", wait_for_esplora_sync.as_secs());
std::thread::sleep(wait_for_esplora_sync);
let wallet_scan_input = {
let wallet = wallet.lock().unwrap();
wallet.start_wallet_scan()
};
let start = std::time::Instant::now();
let stop_gap = 5;
eprintln!(
"🔎 startig scanning all keychains with stop gap of {}",
stop_gap
);
let wallet_scan = client.wallet_scan(wallet_scan_input, stop_gap, &Default::default(), 5)?;
// we've got an update so briefly take a lock the wallet to apply it
{
let mut wallet = wallet.lock().unwrap();
match wallet.apply_wallet_scan(wallet_scan) {
Ok(changes) => {
eprintln!("🎉 success! ({}ms)", start.elapsed().as_millis());
eprintln!("wallet balance after: {:?}", wallet.get_balance());
//XXX: esplora is not indexing mempool transactions right now (or not doing it fast enough)
eprintln!(
"wallet found {} new transactions",
changes.tx_additions().count(),
);
if changes.tx_additions().count() != n_initial_transactions {
eprintln!(
"(it should have found {} but maybe stop gap wasn't large enough?)",
n_initial_transactions
);
}
}
Err(reason) => {
eprintln!("❌ esplora produced invalid wallet scan {}", reason);
}
}
}
Ok(())
}