Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 34 additions & 2 deletions crates/core/src/spk_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -383,14 +383,46 @@ impl<I, D> SyncRequest<I, D> {
SyncIter::<I, D, SpkWithExpectedTxids>::new(self)
}

/// Drain and iterate over [`Txid`]s contained in this request, consuming them.
pub fn drain_txids(&mut self) -> impl ExactSizeIterator<Item = Txid> + '_ {
SyncIter::<I, D, Txid>::new(self)
}

/// Drain and iterate over [`OutPoint`]s contained in this request, consuming them.
pub fn drain_outpoints(&mut self) -> impl ExactSizeIterator<Item = OutPoint> + '_ {
SyncIter::<I, D, OutPoint>::new(self)
}

/// Iterate over [`Txid`]s contained in this request.
#[deprecated(
note = "use `drain_txids` for consuming iteration or `txids` for read-only iteration"
)]
pub fn iter_txids(&mut self) -> impl ExactSizeIterator<Item = Txid> + '_ {
SyncIter::<I, D, Txid>::new(self)
self.drain_txids()
}

/// Iterate over [`OutPoint`]s contained in this request.
#[deprecated(
note = "use `drain_outpoints` for consuming iteration or `outpoints` for read-only iteration"
)]
pub fn iter_outpoints(&mut self) -> impl ExactSizeIterator<Item = OutPoint> + '_ {
SyncIter::<I, D, OutPoint>::new(self)
self.drain_outpoints()
}

/// Iterate over script pubkeys (with indexes) contained in this request, without
/// consuming them.
pub fn spks(&self) -> impl ExactSizeIterator<Item = &(I, ScriptBuf)> + '_ {
self.spks.iter()
}

/// Iterate over [`Txid`]s contained in this request, without consuming them.
pub fn txids(&self) -> impl ExactSizeIterator<Item = &Txid> + '_ {
self.txids.iter()
}

/// Iterate over [`OutPoint`]s contained in this request, without consuming them.
pub fn outpoints(&self) -> impl ExactSizeIterator<Item = &OutPoint> + '_ {
self.outpoints.iter()
}

fn _call_inspect(&mut self, item: SyncItem<I>) {
Expand Down
56 changes: 55 additions & 1 deletion crates/core/tests/test_spk_client.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
use bdk_core::spk_client::{FullScanResponse, SyncResponse};
use bdk_core::bitcoin::hashes::Hash;
use bdk_core::bitcoin::{BlockHash, OutPoint, Txid};
use bdk_core::spk_client::{FullScanResponse, SyncRequest, SyncResponse};

#[test]
fn test_empty() {
Expand All @@ -11,3 +13,55 @@ fn test_empty() {
"Default `SyncResponse` must be empty"
);
}

#[test]
fn test_spks_does_not_consume() {
let spk1 = bitcoin::ScriptBuf::new();
let spk2 = bitcoin::ScriptBuf::new();

let request: SyncRequest<u32, BlockHash> = SyncRequest::builder()
.spks_with_indexes(vec![(0u32, spk1), (1u32, spk2)])
.build();

assert_eq!(request.spks().count(), 2);
assert_eq!(request.spks().count(), 2, "must not consume");
}

#[test]
fn test_txids_does_not_consume() {
let txid1 = Txid::from_byte_array([0x01; 32]);

let request: SyncRequest<(), BlockHash> = SyncRequest::builder().txids(vec![txid1]).build();

assert_eq!(request.txids().count(), 1);
assert_eq!(request.txids().count(), 1, "must not consume");
}

#[test]
fn test_outpoints_does_not_consume() {
let outpoint1 = OutPoint::null();

let request: SyncRequest<(), BlockHash> =
SyncRequest::builder().outpoints(vec![outpoint1]).build();

assert_eq!(request.outpoints().count(), 1);
assert_eq!(request.outpoints().count(), 1, "must not consume");
}

#[test]
fn test_drain_txids_still_consumes_all_items() {
let txid1 = Txid::from_byte_array([0x01; 32]);
let txid2 = Txid::from_byte_array([0x02; 32]);

let mut request: SyncRequest<(), BlockHash> =
SyncRequest::builder().txids(vec![txid1, txid2]).build();

assert_eq!(request.txids().count(), 2);

let consumed: Vec<_> = request.drain_txids().collect();
assert_eq!(
consumed.len(),
2,
"drain_txids must still consume all items"
);
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These tests don't earn their keep imo. It's apparent from the method's signature.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the feedback! I removed those tests since the non-consuming behavior is already apparent from the method signatures. I've updated the PR accordingly. PTAL when you have a chance.

4 changes: 2 additions & 2 deletions crates/electrum/src/bdk_electrum_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -238,13 +238,13 @@ impl<E: ElectrumApi> BdkElectrumClient<E> {
self.populate_with_txids(
start_time,
&mut tx_update,
request.iter_txids(),
request.drain_txids(),
&mut pending_anchors,
)?;
self.populate_with_outpoints(
start_time,
&mut tx_update,
request.iter_outpoints(),
request.drain_outpoints(),
&mut pending_anchors,
)?;

Expand Down
4 changes: 2 additions & 2 deletions crates/esplora/src/async_ext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ where
self,
start_time,
&mut inserted_txs,
request.iter_txids(),
request.drain_txids(),
parallel_requests,
)
.await?,
Expand All @@ -155,7 +155,7 @@ where
self,
start_time,
&mut inserted_txs,
request.iter_outpoints(),
request.drain_outpoints(),
parallel_requests,
)
.await?,
Expand Down
4 changes: 2 additions & 2 deletions crates/esplora/src/blocking_ext.rs
Original file line number Diff line number Diff line change
Expand Up @@ -133,14 +133,14 @@ impl EsploraExt for esplora_client::BlockingClient {
self,
start_time,
&mut inserted_txs,
request.iter_txids(),
request.drain_txids(),
parallel_requests,
)?);
tx_update.extend(fetch_txs_with_outpoints(
self,
start_time,
&mut inserted_txs,
request.iter_outpoints(),
request.drain_outpoints(),
parallel_requests,
)?);

Expand Down