Skip to content

Commit f60708b

Browse files
committed
docs: add example for EsploraClient with timeout configuration
Add a new example demonstrating how to configure EsploraClient with custom timeout and retry settings. This is useful for developers working with slow or unreliable network connections. The example shows: - Setting socket timeout using Builder::timeout() - Configuring max retries using Builder::max_retries() - Handling timeout-related errors gracefully Closes #260 Signed-off-by: Eeshu-Yadav <eeshuyadav123@gmail.com>
1 parent bec219a commit f60708b

File tree

3 files changed

+113
-0
lines changed

3 files changed

+113
-0
lines changed

Cargo.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,5 +72,8 @@ name = "esplora_async"
7272
[[example]]
7373
name = "esplora_blocking"
7474

75+
[[example]]
76+
name = "esplora_with_timeout"
77+
7578
[[example]]
7679
name = "bitcoind_rpc"

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ that the `Wallet` can use to update its view of the chain.
6363

6464
* [`examples/esplora_async`](https://github.com/bitcoindevkit/bdk_wallet/tree/master/examples/esplora_async)
6565
* [`examples/esplora_blocking`](https://github.com/bitcoindevkit/bdk_wallet/tree/master/examples/esplora_blocking)
66+
* [`examples/esplora_with_timeout`](https://github.com/bitcoindevkit/bdk_wallet/tree/master/examples/esplora_with_timeout)
6667
* [`examples/electrum`](https://github.com/bitcoindevkit/bdk_wallet/tree/master/examples/electrum)
6768
* [`examples/bitcoind_rpc`](https://github.com/bitcoindevkit/bdk_wallet/tree/master/examples/bitcoind_rpc)
6869

examples/esplora_with_timeout.rs

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
//! Example demonstrating how to configure EsploraClient with custom timeout settings.
2+
3+
use bdk_esplora::{esplora_client, EsploraExt};
4+
use bdk_wallet::{bitcoin::Network, rusqlite::Connection, KeychainKind, Wallet};
5+
use std::{collections::BTreeSet, io::Write};
6+
7+
const STOP_GAP: usize = 5;
8+
const PARALLEL_REQUESTS: usize = 5;
9+
10+
const DB_PATH: &str = "bdk-example-esplora-timeout.sqlite";
11+
const NETWORK: Network = Network::Testnet4;
12+
const EXTERNAL_DESC: &str = "wpkh(tprv8ZgxMBicQKsPdy6LMhUtFHAgpocR8GC6QmwMSFpZs7h6Eziw3SpThFfczTDh5rW2krkqffa11UpX3XkeTTB2FvzZKWXqPY54Y6Rq4AQ5R8L/84'/1'/0'/0/*)";
13+
const INTERNAL_DESC: &str = "wpkh(tprv8ZgxMBicQKsPdy6LMhUtFHAgpocR8GC6QmwMSFpZs7h6Eziw3SpThFfczTDh5rW2krkqffa11UpX3XkeTTB2FvzZKWXqPY54Y6Rq4AQ5R8L/84'/1'/0'/1/*)";
14+
const ESPLORA_URL: &str = "https://mempool.space/testnet4/api";
15+
16+
const TIMEOUT_SECS: u64 = 30;
17+
const MAX_RETRIES: usize = 3;
18+
19+
fn main() -> Result<(), anyhow::Error> {
20+
let mut db = Connection::open(DB_PATH)?;
21+
let wallet_opt = Wallet::load()
22+
.descriptor(KeychainKind::External, Some(EXTERNAL_DESC))
23+
.descriptor(KeychainKind::Internal, Some(INTERNAL_DESC))
24+
.extract_keys()
25+
.check_network(NETWORK)
26+
.load_wallet(&mut db)?;
27+
let mut wallet = match wallet_opt {
28+
Some(wallet) => wallet,
29+
None => Wallet::create(EXTERNAL_DESC, INTERNAL_DESC)
30+
.network(NETWORK)
31+
.create_wallet(&mut db)?,
32+
};
33+
34+
let address = wallet.next_unused_address(KeychainKind::External);
35+
wallet.persist(&mut db)?;
36+
println!(
37+
"Next unused address: ({}) {}",
38+
address.index, address.address
39+
);
40+
41+
let balance = wallet.balance();
42+
println!("Wallet balance before syncing: {}", balance.total());
43+
44+
// Configure EsploraClient with custom timeout and retry settings.
45+
// Available builder options:
46+
// - timeout(secs): Socket timeout in seconds
47+
// - max_retries(count): Retries on HTTP codes 408, 425, 429, 500, 502, 503, 504
48+
// - proxy(url): Proxy server URL
49+
// - header(key, value): Custom HTTP header
50+
println!(
51+
"Creating Esplora client with {TIMEOUT_SECS}s timeout and {MAX_RETRIES} max retries..."
52+
);
53+
let client = esplora_client::Builder::new(ESPLORA_URL)
54+
.timeout(TIMEOUT_SECS)
55+
.max_retries(MAX_RETRIES)
56+
.build_blocking();
57+
58+
println!("Starting full sync...");
59+
let request = wallet.start_full_scan().inspect({
60+
let mut stdout = std::io::stdout();
61+
let mut once = BTreeSet::<KeychainKind>::new();
62+
move |keychain, spk_i, _| {
63+
if once.insert(keychain) {
64+
print!("\nScanning keychain [{keychain:?}] ");
65+
}
66+
print!(" {spk_i:<3}");
67+
stdout.flush().expect("must flush")
68+
}
69+
});
70+
71+
match client.full_scan(request, STOP_GAP, PARALLEL_REQUESTS) {
72+
Ok(update) => {
73+
wallet.apply_update(update)?;
74+
wallet.persist(&mut db)?;
75+
println!();
76+
77+
let balance = wallet.balance();
78+
println!("Wallet balance after syncing: {}", balance.total());
79+
}
80+
Err(e) => {
81+
eprintln!("\nSync failed: {e}");
82+
eprintln!(
83+
"Tips: increase timeout/max_retries, check connectivity, or try another server"
84+
);
85+
return Err(e.into());
86+
}
87+
}
88+
89+
println!("\nFetching current block height...");
90+
match client.get_height() {
91+
Ok(height) => println!("Current block height: {height}"),
92+
Err(e) => eprintln!("Failed to get block height: {e}"),
93+
}
94+
95+
println!("\nFetching fee estimates...");
96+
match client.get_fee_estimates() {
97+
Ok(estimates) => {
98+
println!("Fee estimates (sat/vB):");
99+
for (target, rate) in estimates.iter().take(5) {
100+
println!(" {} blocks: {:.1} sat/vB", target, rate);
101+
}
102+
}
103+
Err(e) => {
104+
eprintln!("Failed to get fee estimates: {e}");
105+
}
106+
}
107+
108+
Ok(())
109+
}

0 commit comments

Comments
 (0)