/// `request` provides the data required to perform a script-pubkey-based full scan
/// (see [`FullScanRequest`]). The full scan for each keychain (`K`) stops after a gap of
/// `stop_gap` script pubkeys with no associated transactions. `parallel_requests` specifies
- /// the maximum number of HTTP requests to make in parallel.
+ /// the maximum number of HTTP requests to make in parallel. A `parallel_requests` of 0 is
+ /// treated as 1.
///
/// Refer to [crate-level docs](crate) for more.
async fn full_scan<K: Ord + Clone + Send, R: Into<FullScanRequest<K>> + Send>(
///
/// `request` provides the data required to perform a script-pubkey-based sync (see
/// [`SyncRequest`]). `parallel_requests` specifies the maximum number of HTTP requests to make
- /// in parallel.
+ /// in parallel. A `parallel_requests` of 0 is treated as 1.
///
/// Refer to [crate-level docs](crate) for more.
async fn sync<I: Send, R: Into<SyncRequest<I>> + Send>(
let mut consecutive_unused = 0usize;
// Treat stop_gap = 0 as 1 while preserving original semantics for other values.
let gap_limit = stop_gap.max(1);
+ let parallel_requests = parallel_requests.max(1);
loop {
let handles = keychain_spks
.filter(|txid| !inserted_txs.contains(txid))
.collect::<Vec<Txid>>()
.into_iter();
+ let parallel_requests = parallel_requests.max(1);
loop {
let handles = txids
.by_ref()
I::IntoIter: Send,
S: Sleeper + Clone + Send + Sync,
{
+ let parallel_requests = parallel_requests.max(1);
let outpoints = outpoints.into_iter().collect::<Vec<_>>();
let mut update = TxUpdate::<ConfirmationBlockTime>::default();
/// `request` provides the data required to perform a script-pubkey-based full scan
/// (see [`FullScanRequest`]). The full scan for each keychain (`K`) stops after a gap of
/// `stop_gap` script pubkeys with no associated transactions. `parallel_requests` specifies
- /// the maximum number of HTTP requests to make in parallel.
+ /// the maximum number of HTTP requests to make in parallel. A `parallel_requests` of 0 is
+ /// treated as 1.
///
/// Refer to [crate-level docs](crate) for more.
fn full_scan<K: Ord + Clone, R: Into<FullScanRequest<K>>>(
///
/// `request` provides the data required to perform a script-pubkey-based sync (see
/// [`SyncRequest`]). `parallel_requests` specifies the maximum number of HTTP requests to make
- /// in parallel.
+ /// in parallel. A `parallel_requests` of 0 is treated as 1.
///
/// Refer to [crate-level docs](crate) for more.
fn sync<I: 'static, R: Into<SyncRequest<I>>>(
let mut consecutive_unused = 0usize;
// Treat stop_gap = 0 as 1 while preserving original semantics for other values.
let gap_limit = stop_gap.max(1);
+ let parallel_requests = parallel_requests.max(1);
loop {
let handles = keychain_spks
.filter(|txid| !inserted_txs.contains(txid))
.collect::<Vec<Txid>>()
.into_iter();
+ let parallel_requests = parallel_requests.max(1);
loop {
let handles = txids
.by_ref()
outpoints: I,
parallel_requests: usize,
) -> Result<TxUpdate<ConfirmationBlockTime>, Error> {
+ let parallel_requests = parallel_requests.max(1);
let outpoints = outpoints.into_iter().collect::<Vec<_>>();
let mut update = TxUpdate::<ConfirmationBlockTime>::default();
-use bdk_chain::bitcoin::{Address, Amount};
+use bdk_chain::bitcoin::{hashes::Hash, Address, Amount, OutPoint, ScriptBuf, Txid};
use bdk_chain::local_chain::LocalChain;
use bdk_chain::spk_client::{FullScanRequest, SyncRequest};
use bdk_chain::spk_txout::SpkTxOutIndex;
"`sync` must reject a page that does not advance the cursor"
);
}
+
+/// A `parallel_requests` of 0 must not make `full_scan` skip its scripts.
+///
+/// The client points at a closed port, so a scan that actually requests something returns an
+/// error. If no request is made, the scan returns an empty `Ok`.
+#[tokio::test]
+pub async fn test_full_scan_with_zero_parallel_requests() -> anyhow::Result<()> {
+ let client = Builder::new("http://127.0.0.1:1").build_async()?;
+ let request = FullScanRequest::builder().spks_for_keychain(0u32, [(0, ScriptBuf::new())]);
+
+ let response = client.full_scan(request, 3, 0).await;
+ assert!(
+ response.is_err(),
+ "scan skipped its script and returned {response:?}"
+ );
+ Ok(())
+}
+
+/// A `parallel_requests` of 0 must not make `sync` skip its spks, txids or outpoints (each goes
+/// through a different fetch loop).
+#[tokio::test]
+pub async fn test_sync_with_zero_parallel_requests() -> anyhow::Result<()> {
+ let client = Builder::new("http://127.0.0.1:1").build_async()?;
+ let requests = [
+ ("spks", SyncRequest::builder().spks([ScriptBuf::new()])),
+ ("txids", SyncRequest::builder().txids([Txid::all_zeros()])),
+ (
+ "outpoints",
+ SyncRequest::builder().outpoints([OutPoint::new(Txid::all_zeros(), 0)]),
+ ),
+ ];
+ for (kind, request) in requests {
+ let response = client.sync(request, 0).await;
+ assert!(
+ response.is_err(),
+ "sync skipped its {kind} and returned {response:?}"
+ );
+ }
+ Ok(())
+}
-use bdk_chain::bitcoin::{Address, Amount};
+use bdk_chain::bitcoin::{hashes::Hash, Address, Amount, OutPoint, ScriptBuf, Txid};
use bdk_chain::local_chain::LocalChain;
use bdk_chain::spk_client::{FullScanRequest, SyncRequest};
use bdk_chain::spk_txout::SpkTxOutIndex;
"`sync` must reject a page that does not advance the cursor"
);
}
+
+/// A `parallel_requests` of 0 must not make `full_scan` skip its scripts.
+///
+/// The client points at a closed port, so a scan that actually requests something returns an
+/// error. If no request is made, the scan returns an empty `Ok`.
+#[test]
+pub fn test_full_scan_with_zero_parallel_requests() {
+ let client = Builder::new("http://127.0.0.1:1").build_blocking();
+ let request = FullScanRequest::builder().spks_for_keychain(0u32, [(0, ScriptBuf::new())]);
+
+ let response = client.full_scan(request, 3, 0);
+ assert!(
+ response.is_err(),
+ "scan skipped its script and returned {response:?}"
+ );
+}
+
+/// A `parallel_requests` of 0 must not make `sync` skip its spks, txids or outpoints (each goes
+/// through a different fetch loop).
+#[test]
+pub fn test_sync_with_zero_parallel_requests() {
+ let client = Builder::new("http://127.0.0.1:1").build_blocking();
+ let requests = [
+ ("spks", SyncRequest::builder().spks([ScriptBuf::new()])),
+ ("txids", SyncRequest::builder().txids([Txid::all_zeros()])),
+ (
+ "outpoints",
+ SyncRequest::builder().outpoints([OutPoint::new(Txid::all_zeros(), 0)]),
+ ),
+ ];
+ for (kind, request) in requests {
+ let response = client.sync(request, 0);
+ assert!(
+ response.is_err(),
+ "sync skipped its {kind} and returned {response:?}"
+ );
+ }
+}