Skip to content

Commit 90a0018

Browse files
committed
feat(electrum): batch transaction.get_merkle calls via batch_call
1 parent d574431 commit 90a0018

2 files changed

Lines changed: 46 additions & 42 deletions

File tree

crates/electrum/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ workspace = true
1515
[dependencies]
1616
bdk_core = { path = "../core", version = "0.5.0" }
1717
electrum-client = { version = "0.23.1", features = [ "proxy" ], default-features = false }
18+
serde_json = "1.0"
1819

1920
[dev-dependencies]
2021
bdk_testenv = { path = "../testenv" }

crates/electrum/src/bdk_electrum_client.rs

Lines changed: 45 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,6 @@ use std::sync::{Arc, Mutex};
1212
/// We include a chain suffix of a certain length for the purpose of robustness.
1313
const CHAIN_SUFFIX_LENGTH: u32 = 8;
1414

15-
/// Maximum batch size for proof validation requests
16-
const MAX_BATCH_SIZE: usize = 100;
17-
1815
/// Wrapper around an [`electrum_client::ElectrumApi`] which includes an internal in-memory
1916
/// transaction cache to avoid re-fetching already downloaded transactions.
2017
#[derive(Debug)]
@@ -502,51 +499,57 @@ impl<E: ElectrumApi> BdkElectrumClient<E> {
502499
}
503500
}
504501

505-
// Fetch missing proofs in batches
506-
for chunk in to_fetch.chunks(MAX_BATCH_SIZE) {
507-
for &(txid, height, hash) in chunk {
508-
// Fetch the raw proof.
509-
let proof = self.inner.transaction_get_merkle(&txid, height)?;
502+
// Batch all get_merkle calls.
503+
let mut batch = electrum_client::Batch::default();
504+
for &(txid, height, _) in &to_fetch {
505+
batch.raw(
506+
"blockchain.transaction.get_merkle".into(),
507+
vec![
508+
electrum_client::Param::String(format!("{:x}", txid)),
509+
electrum_client::Param::Usize(height),
510+
],
511+
);
512+
}
513+
let resps = self.inner.batch_call(&batch)?;
510514

511-
// Validate against header, retrying once on stale header.
512-
let mut header = {
513-
let cache = self.block_header_cache.lock().unwrap();
514-
cache[&(height as u32)]
515-
};
516-
let mut valid = electrum_client::utils::validate_merkle_proof(
515+
// Validate each proof, retrying once for each stale header.
516+
for ((txid, height, hash), resp) in to_fetch.into_iter().zip(resps.into_iter()) {
517+
let proof: electrum_client::GetMerkleRes = serde_json::from_value(resp)?;
518+
519+
let mut header = {
520+
let cache = self.block_header_cache.lock().unwrap();
521+
cache[&(height as u32)]
522+
};
523+
let mut valid =
524+
electrum_client::utils::validate_merkle_proof(&txid, &header.merkle_root, &proof);
525+
if !valid {
526+
let new_header = self.inner.block_header(height)?;
527+
self.block_header_cache
528+
.lock()
529+
.unwrap()
530+
.insert(height as u32, new_header);
531+
header = new_header;
532+
valid = electrum_client::utils::validate_merkle_proof(
517533
&txid,
518534
&header.merkle_root,
519535
&proof,
520536
);
521-
if !valid {
522-
let new_header = self.inner.block_header(height)?;
523-
self.block_header_cache
524-
.lock()
525-
.unwrap()
526-
.insert(height as u32, new_header);
527-
header = new_header;
528-
valid = electrum_client::utils::validate_merkle_proof(
529-
&txid,
530-
&header.merkle_root,
531-
&proof,
532-
);
533-
}
537+
}
534538

535-
// Build and cache the anchor if merkle proof is valid.
536-
if valid {
537-
let anchor = ConfirmationBlockTime {
538-
confirmation_time: header.time as u64,
539-
block_id: BlockId {
540-
height: height as u32,
541-
hash: header.block_hash(),
542-
},
543-
};
544-
self.anchor_cache
545-
.lock()
546-
.unwrap()
547-
.insert((txid, hash), anchor);
548-
results.push((txid, anchor));
549-
}
539+
// Build and cache the anchor if merkle proof is valid.
540+
if valid {
541+
let anchor = ConfirmationBlockTime {
542+
confirmation_time: header.time as u64,
543+
block_id: BlockId {
544+
height: height as u32,
545+
hash: header.block_hash(),
546+
},
547+
};
548+
self.anchor_cache
549+
.lock()
550+
.unwrap()
551+
.insert((txid, hash), anchor);
552+
results.push((txid, anchor));
550553
}
551554
}
552555

0 commit comments

Comments
 (0)