refactor(esplora_ext): rename scan_txs to sync and scan_txs_with_keychains to full_scan

removed txids and outpoints params from full_scan
This commit is contained in:
Steve Myers 2023-12-06 21:21:02 -06:00
parent 95d34854f4
commit de54e710ed
No known key found for this signature in database
GPG Key ID: 8105A46B22C2D051
9 changed files with 124 additions and 147 deletions

View File

@ -1,4 +1,4 @@
//! This crate is a collection of core structures for [Bitcoin Dev Kit] (alpha release). //! This crate is a collection of core structures for [Bitcoin Dev Kit].
//! //!
//! The goal of this crate is to give wallets the mechanisms needed to: //! The goal of this crate is to give wallets the mechanisms needed to:
//! //!

View File

@ -36,58 +36,45 @@ pub trait EsploraAsyncExt {
request_heights: impl IntoIterator<IntoIter = impl Iterator<Item = u32> + Send> + Send, request_heights: impl IntoIterator<IntoIter = impl Iterator<Item = u32> + Send> + Send,
) -> Result<local_chain::Update, Error>; ) -> Result<local_chain::Update, Error>;
/// Scan Esplora for the data specified and return a [`TxGraph`] and a map of last active /// Full scan the keychain scripts specified with the blockchain (via an Esplora client) and
/// indices. /// returns a [`TxGraph`] and a map of last active indices.
/// ///
/// * `keychain_spks`: keychains that we want to scan transactions for /// * `keychain_spks`: keychains that we want to scan transactions for
/// * `txids`: transactions for which we want updated [`ConfirmationTimeHeightAnchor`]s
/// * `outpoints`: transactions associated with these outpoints (residing, spending) that we
/// want to include in the update
/// ///
/// The scan for each keychain stops after a gap of `stop_gap` script pubkeys with no associated /// The full scan for each keychain stops after a gap of `stop_gap` script pubkeys with no associated
/// transactions. `parallel_requests` specifies the max number of HTTP requests to make in /// transactions. `parallel_requests` specifies the max number of HTTP requests to make in
/// parallel. /// parallel.
#[allow(clippy::result_large_err)] #[allow(clippy::result_large_err)]
async fn scan_txs_with_keychains<K: Ord + Clone + Send>( async fn full_scan<K: Ord + Clone + Send>(
&self, &self,
keychain_spks: BTreeMap< keychain_spks: BTreeMap<
K, K,
impl IntoIterator<IntoIter = impl Iterator<Item = (u32, ScriptBuf)> + Send> + Send, impl IntoIterator<IntoIter = impl Iterator<Item = (u32, ScriptBuf)> + Send> + Send,
>, >,
txids: impl IntoIterator<IntoIter = impl Iterator<Item = Txid> + Send> + Send,
outpoints: impl IntoIterator<IntoIter = impl Iterator<Item = OutPoint> + Send> + Send,
stop_gap: usize, stop_gap: usize,
parallel_requests: usize, parallel_requests: usize,
) -> Result<(TxGraph<ConfirmationTimeHeightAnchor>, BTreeMap<K, u32>), Error>; ) -> Result<(TxGraph<ConfirmationTimeHeightAnchor>, BTreeMap<K, u32>), Error>;
/// Convenience method to call [`scan_txs_with_keychains`] without requiring a keychain. /// Sync a set of scripts with the blockchain (via an Esplora client) for the data
/// specified and return a [`TxGraph`].
/// ///
/// [`scan_txs_with_keychains`]: EsploraAsyncExt::scan_txs_with_keychains /// * `misc_spks`: scripts that we want to sync transactions for
/// * `txids`: transactions for which we want updated [`ConfirmationTimeHeightAnchor`]s
/// * `outpoints`: transactions associated with these outpoints (residing, spending) that we
/// want to include in the update
///
/// If the scripts to sync are unknown, such as when restoring or importing a keychain that
/// may include scripts that have been used, use [`full_scan`] with the keychain.
///
/// [`full_scan`]: EsploraAsyncExt::full_scan
#[allow(clippy::result_large_err)] #[allow(clippy::result_large_err)]
async fn scan_txs( async fn sync(
&self, &self,
misc_spks: impl IntoIterator<IntoIter = impl Iterator<Item = ScriptBuf> + Send> + Send, misc_spks: impl IntoIterator<IntoIter = impl Iterator<Item = ScriptBuf> + Send> + Send,
txids: impl IntoIterator<IntoIter = impl Iterator<Item = Txid> + Send> + Send, txids: impl IntoIterator<IntoIter = impl Iterator<Item = Txid> + Send> + Send,
outpoints: impl IntoIterator<IntoIter = impl Iterator<Item = OutPoint> + Send> + Send, outpoints: impl IntoIterator<IntoIter = impl Iterator<Item = OutPoint> + Send> + Send,
parallel_requests: usize, parallel_requests: usize,
) -> Result<TxGraph<ConfirmationTimeHeightAnchor>, Error> { ) -> Result<TxGraph<ConfirmationTimeHeightAnchor>, Error>;
self.scan_txs_with_keychains(
[(
(),
misc_spks
.into_iter()
.enumerate()
.map(|(i, spk)| (i as u32, spk)),
)]
.into(),
txids,
outpoints,
usize::MAX,
parallel_requests,
)
.await
.map(|(g, _)| g)
}
} }
#[cfg_attr(target_arch = "wasm32", async_trait(?Send))] #[cfg_attr(target_arch = "wasm32", async_trait(?Send))]
@ -199,14 +186,12 @@ impl EsploraAsyncExt for esplora_client::AsyncClient {
}) })
} }
async fn scan_txs_with_keychains<K: Ord + Clone + Send>( async fn full_scan<K: Ord + Clone + Send>(
&self, &self,
keychain_spks: BTreeMap< keychain_spks: BTreeMap<
K, K,
impl IntoIterator<IntoIter = impl Iterator<Item = (u32, ScriptBuf)> + Send> + Send, impl IntoIterator<IntoIter = impl Iterator<Item = (u32, ScriptBuf)> + Send> + Send,
>, >,
txids: impl IntoIterator<IntoIter = impl Iterator<Item = Txid> + Send> + Send,
outpoints: impl IntoIterator<IntoIter = impl Iterator<Item = OutPoint> + Send> + Send,
stop_gap: usize, stop_gap: usize,
parallel_requests: usize, parallel_requests: usize,
) -> Result<(TxGraph<ConfirmationTimeHeightAnchor>, BTreeMap<K, u32>), Error> { ) -> Result<(TxGraph<ConfirmationTimeHeightAnchor>, BTreeMap<K, u32>), Error> {
@ -275,6 +260,32 @@ impl EsploraAsyncExt for esplora_client::AsyncClient {
} }
} }
Ok((graph, last_active_indexes))
}
async fn sync(
&self,
misc_spks: impl IntoIterator<IntoIter = impl Iterator<Item = ScriptBuf> + Send> + Send,
txids: impl IntoIterator<IntoIter = impl Iterator<Item = Txid> + Send> + Send,
outpoints: impl IntoIterator<IntoIter = impl Iterator<Item = OutPoint> + Send> + Send,
parallel_requests: usize,
) -> Result<TxGraph<ConfirmationTimeHeightAnchor>, Error> {
let mut graph = self
.full_scan(
[(
(),
misc_spks
.into_iter()
.enumerate()
.map(|(i, spk)| (i as u32, spk)),
)]
.into(),
usize::MAX,
parallel_requests,
)
.await
.map(|(g, _)| g)?;
let mut txids = txids.into_iter(); let mut txids = txids.into_iter();
loop { loop {
let handles = txids let handles = txids
@ -323,7 +334,6 @@ impl EsploraAsyncExt for esplora_client::AsyncClient {
} }
} }
} }
Ok(graph)
Ok((graph, last_active_indexes))
} }
} }

View File

@ -19,8 +19,8 @@ use crate::{anchor_from_status, ASSUME_FINAL_DEPTH};
pub trait EsploraExt { pub trait EsploraExt {
/// Prepare an [`LocalChain`] update with blocks fetched from Esplora. /// Prepare an [`LocalChain`] update with blocks fetched from Esplora.
/// ///
/// * `prev_tip` is the previous tip of [`LocalChain::tip`]. /// * `local_tip` is the previous tip of [`LocalChain::tip`].
/// * `get_heights` is the block heights that we are interested in fetching from Esplora. /// * `request_heights` is the block heights that we are interested in fetching from Esplora.
/// ///
/// The result of this method can be applied to [`LocalChain::apply_update`]. /// The result of this method can be applied to [`LocalChain::apply_update`].
/// ///
@ -34,54 +34,42 @@ pub trait EsploraExt {
request_heights: impl IntoIterator<Item = u32>, request_heights: impl IntoIterator<Item = u32>,
) -> Result<local_chain::Update, Error>; ) -> Result<local_chain::Update, Error>;
/// Scan Esplora for the data specified and return a [`TxGraph`] and a map of last active /// Full scan the keychain scripts specified with the blockchain (via an Esplora client) and
/// indices. /// returns a [`TxGraph`] and a map of last active indices.
/// ///
/// * `keychain_spks`: keychains that we want to scan transactions for /// * `keychain_spks`: keychains that we want to scan transactions for
/// * `txids`: transactions for which we want updated [`ConfirmationTimeHeightAnchor`]s
/// * `outpoints`: transactions associated with these outpoints (residing, spending) that we
/// want to include in the update
/// ///
/// The scan for each keychain stops after a gap of `stop_gap` script pubkeys with no associated /// The full scan for each keychain stops after a gap of `stop_gap` script pubkeys with no associated
/// transactions. `parallel_requests` specifies the max number of HTTP requests to make in /// transactions. `parallel_requests` specifies the max number of HTTP requests to make in
/// parallel. /// parallel.
#[allow(clippy::result_large_err)] #[allow(clippy::result_large_err)]
fn scan_txs_with_keychains<K: Ord + Clone>( fn full_scan<K: Ord + Clone>(
&self, &self,
keychain_spks: BTreeMap<K, impl IntoIterator<Item = (u32, ScriptBuf)>>, keychain_spks: BTreeMap<K, impl IntoIterator<Item = (u32, ScriptBuf)>>,
txids: impl IntoIterator<Item = Txid>,
outpoints: impl IntoIterator<Item = OutPoint>,
stop_gap: usize, stop_gap: usize,
parallel_requests: usize, parallel_requests: usize,
) -> Result<(TxGraph<ConfirmationTimeHeightAnchor>, BTreeMap<K, u32>), Error>; ) -> Result<(TxGraph<ConfirmationTimeHeightAnchor>, BTreeMap<K, u32>), Error>;
/// Convenience method to call [`scan_txs_with_keychains`] without requiring a keychain. /// Sync a set of scripts with the blockchain (via an Esplora client) for the data
/// specified and return a [`TxGraph`].
/// ///
/// [`scan_txs_with_keychains`]: EsploraExt::scan_txs_with_keychains /// * `misc_spks`: scripts that we want to sync transactions for
/// * `txids`: transactions for which we want updated [`ConfirmationTimeHeightAnchor`]s
/// * `outpoints`: transactions associated with these outpoints (residing, spending) that we
/// want to include in the update
///
/// If the scripts to sync are unknown, such as when restoring or importing a keychain that
/// may include scripts that have been used, use [`full_scan`] with the keychain.
///
/// [`full_scan`]: EsploraExt::full_scan
#[allow(clippy::result_large_err)] #[allow(clippy::result_large_err)]
fn scan_txs( fn sync(
&self, &self,
misc_spks: impl IntoIterator<Item = ScriptBuf>, misc_spks: impl IntoIterator<Item = ScriptBuf>,
txids: impl IntoIterator<Item = Txid>, txids: impl IntoIterator<Item = Txid>,
outpoints: impl IntoIterator<Item = OutPoint>, outpoints: impl IntoIterator<Item = OutPoint>,
parallel_requests: usize, parallel_requests: usize,
) -> Result<TxGraph<ConfirmationTimeHeightAnchor>, Error> { ) -> Result<TxGraph<ConfirmationTimeHeightAnchor>, Error>;
self.scan_txs_with_keychains(
[(
(),
misc_spks
.into_iter()
.enumerate()
.map(|(i, spk)| (i as u32, spk)),
)]
.into(),
txids,
outpoints,
usize::MAX,
parallel_requests,
)
.map(|(g, _)| g)
}
} }
impl EsploraExt for esplora_client::BlockingClient { impl EsploraExt for esplora_client::BlockingClient {
@ -190,11 +178,9 @@ impl EsploraExt for esplora_client::BlockingClient {
}) })
} }
fn scan_txs_with_keychains<K: Ord + Clone>( fn full_scan<K: Ord + Clone>(
&self, &self,
keychain_spks: BTreeMap<K, impl IntoIterator<Item = (u32, ScriptBuf)>>, keychain_spks: BTreeMap<K, impl IntoIterator<Item = (u32, ScriptBuf)>>,
txids: impl IntoIterator<Item = Txid>,
outpoints: impl IntoIterator<Item = OutPoint>,
stop_gap: usize, stop_gap: usize,
parallel_requests: usize, parallel_requests: usize,
) -> Result<(TxGraph<ConfirmationTimeHeightAnchor>, BTreeMap<K, u32>), Error> { ) -> Result<(TxGraph<ConfirmationTimeHeightAnchor>, BTreeMap<K, u32>), Error> {
@ -266,6 +252,31 @@ impl EsploraExt for esplora_client::BlockingClient {
} }
} }
Ok((graph, last_active_indexes))
}
fn sync(
&self,
misc_spks: impl IntoIterator<Item = ScriptBuf>,
txids: impl IntoIterator<Item = Txid>,
outpoints: impl IntoIterator<Item = OutPoint>,
parallel_requests: usize,
) -> Result<TxGraph<ConfirmationTimeHeightAnchor>, Error> {
let mut graph = self
.full_scan(
[(
(),
misc_spks
.into_iter()
.enumerate()
.map(|(i, spk)| (i as u32, spk)),
)]
.into(),
usize::MAX,
parallel_requests,
)
.map(|(g, _)| g)?;
let mut txids = txids.into_iter(); let mut txids = txids.into_iter();
loop { loop {
let handles = txids let handles = txids
@ -292,7 +303,7 @@ impl EsploraExt for esplora_client::BlockingClient {
} }
} }
for op in outpoints.into_iter() { for op in outpoints {
if graph.get_tx(op.txid).is_none() { if graph.get_tx(op.txid).is_none() {
if let Some(tx) = self.get_tx(&op.txid)? { if let Some(tx) = self.get_tx(&op.txid)? {
let _ = graph.insert_tx(tx); let _ = graph.insert_tx(tx);
@ -317,7 +328,6 @@ impl EsploraExt for esplora_client::BlockingClient {
} }
} }
} }
Ok(graph)
Ok((graph, last_active_indexes))
} }
} }

View File

@ -1,4 +1,21 @@
#![doc = include_str!("../README.md")] #![doc = include_str!("../README.md")]
//! This crate is used for updating structures of [`bdk_chain`] with data from an Esplora server.
//!
//! The two primary methods are [`EsploraExt::sync`] and [`EsploraExt::full_scan`]. In most cases
//! [`EsploraExt::sync`] is used to sync the transaction histories of scripts that the application
//! cares about, for example the scripts for all the receive addresses of a Wallet's keychain that it
//! has shown a user. [`EsploraExt::full_scan`] is meant to be used when importing or restoring a
//! keychain where the range of possibly used scripts is not known. In this case it is necessary to
//! scan all keychain scripts until a number (the "stop gap") of unused scripts is discovered. For a
//! sync or full scan the user receives relevant blockchain data and output updates for [`bdk_chain`]
//! via a new [`TxGraph`] to be appended to any existing [`TxGraph`] data.
//!
//! Refer to [`example_esplora`] for a complete example.
//!
//! [`TxGraph`]: bdk_chain::tx_graph::TxGraph
//! [`example_esplora`]: https://github.com/bitcoindevkit/bdk/tree/master/example-crates/example_esplora
use bdk_chain::{BlockId, ConfirmationTimeHeightAnchor}; use bdk_chain::{BlockId, ConfirmationTimeHeightAnchor};
use esplora_client::TxStatus; use esplora_client::TxStatus;

View File

@ -101,7 +101,7 @@ pub async fn test_update_tx_graph_without_keychain() -> anyhow::Result<()> {
let graph_update = env let graph_update = env
.client .client
.scan_txs( .sync(
misc_spks.into_iter(), misc_spks.into_iter(),
vec![].into_iter(), vec![].into_iter(),
vec![].into_iter(), vec![].into_iter(),
@ -166,28 +166,10 @@ pub async fn test_async_update_tx_graph_gap_limit() -> anyhow::Result<()> {
// A scan with a gap limit of 2 won't find the transaction, but a scan with a gap limit of 3 // A scan with a gap limit of 2 won't find the transaction, but a scan with a gap limit of 3
// will. // will.
let (graph_update, active_indices) = env let (graph_update, active_indices) = env.client.full_scan(keychains.clone(), 2, 1).await?;
.client
.scan_txs_with_keychains(
keychains.clone(),
vec![].into_iter(),
vec![].into_iter(),
2,
1,
)
.await?;
assert!(graph_update.full_txs().next().is_none()); assert!(graph_update.full_txs().next().is_none());
assert!(active_indices.is_empty()); assert!(active_indices.is_empty());
let (graph_update, active_indices) = env let (graph_update, active_indices) = env.client.full_scan(keychains.clone(), 3, 1).await?;
.client
.scan_txs_with_keychains(
keychains.clone(),
vec![].into_iter(),
vec![].into_iter(),
3,
1,
)
.await?;
assert_eq!(graph_update.full_txs().next().unwrap().txid, txid_4th_addr); assert_eq!(graph_update.full_txs().next().unwrap().txid, txid_4th_addr);
assert_eq!(active_indices[&0], 3); assert_eq!(active_indices[&0], 3);
@ -209,24 +191,12 @@ pub async fn test_async_update_tx_graph_gap_limit() -> anyhow::Result<()> {
// A scan with gap limit 4 won't find the second transaction, but a scan with gap limit 5 will. // A scan with gap limit 4 won't find the second transaction, but a scan with gap limit 5 will.
// The last active indice won't be updated in the first case but will in the second one. // The last active indice won't be updated in the first case but will in the second one.
let (graph_update, active_indices) = env let (graph_update, active_indices) = env.client.full_scan(keychains.clone(), 4, 1).await?;
.client
.scan_txs_with_keychains(
keychains.clone(),
vec![].into_iter(),
vec![].into_iter(),
4,
1,
)
.await?;
let txs: HashSet<_> = graph_update.full_txs().map(|tx| tx.txid).collect(); let txs: HashSet<_> = graph_update.full_txs().map(|tx| tx.txid).collect();
assert_eq!(txs.len(), 1); assert_eq!(txs.len(), 1);
assert!(txs.contains(&txid_4th_addr)); assert!(txs.contains(&txid_4th_addr));
assert_eq!(active_indices[&0], 3); assert_eq!(active_indices[&0], 3);
let (graph_update, active_indices) = env let (graph_update, active_indices) = env.client.full_scan(keychains, 5, 1).await?;
.client
.scan_txs_with_keychains(keychains, vec![].into_iter(), vec![].into_iter(), 5, 1)
.await?;
let txs: HashSet<_> = graph_update.full_txs().map(|tx| tx.txid).collect(); let txs: HashSet<_> = graph_update.full_txs().map(|tx| tx.txid).collect();
assert_eq!(txs.len(), 2); assert_eq!(txs.len(), 2);
assert!(txs.contains(&txid_4th_addr) && txs.contains(&txid_last_addr)); assert!(txs.contains(&txid_4th_addr) && txs.contains(&txid_last_addr));

View File

@ -99,7 +99,7 @@ pub fn test_update_tx_graph_without_keychain() -> anyhow::Result<()> {
sleep(Duration::from_millis(10)) sleep(Duration::from_millis(10))
} }
let graph_update = env.client.scan_txs( let graph_update = env.client.sync(
misc_spks.into_iter(), misc_spks.into_iter(),
vec![].into_iter(), vec![].into_iter(),
vec![].into_iter(), vec![].into_iter(),
@ -164,22 +164,10 @@ pub fn test_update_tx_graph_gap_limit() -> anyhow::Result<()> {
// A scan with a gap limit of 2 won't find the transaction, but a scan with a gap limit of 3 // A scan with a gap limit of 2 won't find the transaction, but a scan with a gap limit of 3
// will. // will.
let (graph_update, active_indices) = env.client.scan_txs_with_keychains( let (graph_update, active_indices) = env.client.full_scan(keychains.clone(), 2, 1)?;
keychains.clone(),
vec![].into_iter(),
vec![].into_iter(),
2,
1,
)?;
assert!(graph_update.full_txs().next().is_none()); assert!(graph_update.full_txs().next().is_none());
assert!(active_indices.is_empty()); assert!(active_indices.is_empty());
let (graph_update, active_indices) = env.client.scan_txs_with_keychains( let (graph_update, active_indices) = env.client.full_scan(keychains.clone(), 3, 1)?;
keychains.clone(),
vec![].into_iter(),
vec![].into_iter(),
3,
1,
)?;
assert_eq!(graph_update.full_txs().next().unwrap().txid, txid_4th_addr); assert_eq!(graph_update.full_txs().next().unwrap().txid, txid_4th_addr);
assert_eq!(active_indices[&0], 3); assert_eq!(active_indices[&0], 3);
@ -201,24 +189,12 @@ pub fn test_update_tx_graph_gap_limit() -> anyhow::Result<()> {
// A scan with gap limit 4 won't find the second transaction, but a scan with gap limit 5 will. // A scan with gap limit 4 won't find the second transaction, but a scan with gap limit 5 will.
// The last active indice won't be updated in the first case but will in the second one. // The last active indice won't be updated in the first case but will in the second one.
let (graph_update, active_indices) = env.client.scan_txs_with_keychains( let (graph_update, active_indices) = env.client.full_scan(keychains.clone(), 4, 1)?;
keychains.clone(),
vec![].into_iter(),
vec![].into_iter(),
4,
1,
)?;
let txs: HashSet<_> = graph_update.full_txs().map(|tx| tx.txid).collect(); let txs: HashSet<_> = graph_update.full_txs().map(|tx| tx.txid).collect();
assert_eq!(txs.len(), 1); assert_eq!(txs.len(), 1);
assert!(txs.contains(&txid_4th_addr)); assert!(txs.contains(&txid_4th_addr));
assert_eq!(active_indices[&0], 3); assert_eq!(active_indices[&0], 3);
let (graph_update, active_indices) = env.client.scan_txs_with_keychains( let (graph_update, active_indices) = env.client.full_scan(keychains, 5, 1)?;
keychains,
vec![].into_iter(),
vec![].into_iter(),
5,
1,
)?;
let txs: HashSet<_> = graph_update.full_txs().map(|tx| tx.txid).collect(); let txs: HashSet<_> = graph_update.full_txs().map(|tx| tx.txid).collect();
assert_eq!(txs.len(), 2); assert_eq!(txs.len(), 2);
assert!(txs.contains(&txid_4th_addr) && txs.contains(&txid_last_addr)); assert!(txs.contains(&txid_4th_addr) && txs.contains(&txid_last_addr));

View File

@ -188,13 +188,7 @@ fn main() -> anyhow::Result<()> {
// represents the last active spk derivation indices of keychains // represents the last active spk derivation indices of keychains
// (`keychain_indices_update`). // (`keychain_indices_update`).
let (graph_update, last_active_indices) = client let (graph_update, last_active_indices) = client
.scan_txs_with_keychains( .full_scan(keychain_spks, *stop_gap, scan_options.parallel_requests)
keychain_spks,
core::iter::empty(),
core::iter::empty(),
*stop_gap,
scan_options.parallel_requests,
)
.context("scanning for transactions")?; .context("scanning for transactions")?;
let mut graph = graph.lock().expect("mutex must not be poisoned"); let mut graph = graph.lock().expect("mutex must not be poisoned");
@ -312,7 +306,7 @@ fn main() -> anyhow::Result<()> {
} }
let graph_update = let graph_update =
client.scan_txs(spks, txids, outpoints, scan_options.parallel_requests)?; client.sync(spks, txids, outpoints, scan_options.parallel_requests)?;
graph.lock().unwrap().apply_update(graph_update) graph.lock().unwrap().apply_update(graph_update)
} }

View File

@ -54,7 +54,7 @@ async fn main() -> Result<(), anyhow::Error> {
}) })
.collect(); .collect();
let (update_graph, last_active_indices) = client let (update_graph, last_active_indices) = client
.scan_txs_with_keychains(keychain_spks, None, None, STOP_GAP, PARALLEL_REQUESTS) .full_scan(keychain_spks, STOP_GAP, PARALLEL_REQUESTS)
.await?; .await?;
let missing_heights = update_graph.missing_heights(wallet.local_chain()); let missing_heights = update_graph.missing_heights(wallet.local_chain());
let chain_update = client.update_local_chain(prev_tip, missing_heights).await?; let chain_update = client.update_local_chain(prev_tip, missing_heights).await?;

View File

@ -54,7 +54,7 @@ fn main() -> Result<(), anyhow::Error> {
.collect(); .collect();
let (update_graph, last_active_indices) = let (update_graph, last_active_indices) =
client.scan_txs_with_keychains(keychain_spks, None, None, STOP_GAP, PARALLEL_REQUESTS)?; client.full_scan(keychain_spks, STOP_GAP, PARALLEL_REQUESTS)?;
let missing_heights = update_graph.missing_heights(wallet.local_chain()); let missing_heights = update_graph.missing_heights(wallet.local_chain());
let chain_update = client.update_local_chain(prev_tip, missing_heights)?; let chain_update = client.update_local_chain(prev_tip, missing_heights)?;
let update = Update { let update = Update {