From 5c940c33cb1f1a166c6e28e8bbfd9cdaef6c1ab6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=BF=97=E5=AE=87?= Date: Sun, 17 Jul 2022 21:02:19 +0800 Subject: [PATCH] Fix wallet sync not finding coins of addresses which are not cached Previously, electrum-based blockchain implementations only synced for `scriptPubKey`s that are already cached in `Database`. This PR introduces a feedback mechanism, that uses `stop_gap` and the difference between "current index" and "last active index" to determine whether we need to cache more `scriptPubKeys`. The `WalletSync::wallet_setup` trait now may return an `Error::MissingCachedScripts` error which contains the number of extra `scriptPubKey`s to cache, in order to satisfy `stop_gap` for the next call. `Wallet::sync` now calls `WalletSync` in a loop, cacheing inbetween subsequent calls (if needed). --- src/blockchain/esplora/reqwest.rs | 1 - src/blockchain/script_sync.rs | 102 +++++++++----- src/error.rs | 16 ++- src/testutils/blockchain_tests.rs | 1 - .../configurable_blockchain_tests.rs | 125 +++++++++++++++++- src/wallet/mod.rs | 58 ++++++-- 6 files changed, 254 insertions(+), 49 deletions(-) diff --git a/src/blockchain/esplora/reqwest.rs b/src/blockchain/esplora/reqwest.rs index 0d4050608..302e811fd 100644 --- a/src/blockchain/esplora/reqwest.rs +++ b/src/blockchain/esplora/reqwest.rs @@ -213,7 +213,6 @@ impl WalletSync for EsploraBlockchain { }; database.commit_batch(batch_update)?; - Ok(()) } } diff --git a/src/blockchain/script_sync.rs b/src/blockchain/script_sync.rs index 057527360..2c4b26cef 100644 --- a/src/blockchain/script_sync.rs +++ b/src/blockchain/script_sync.rs @@ -5,6 +5,7 @@ returns associated transactions i.e. electrum. #![allow(dead_code)] use crate::{ database::{BatchDatabase, BatchOperations, DatabaseUtils}, + error::MissingCachedScripts, wallet::time::Instant, BlockTime, Error, KeychainKind, LocalUtxo, TransactionDetails, }; @@ -34,11 +35,12 @@ pub fn start(db: &D, stop_gap: usize) -> Result let scripts_needed = db .iter_script_pubkeys(Some(keychain))? .into_iter() - .collect(); + .collect::>(); let state = State::new(db); Ok(Request::Script(ScriptReq { state, + initial_scripts_needed: scripts_needed.len(), scripts_needed, script_index: 0, stop_gap, @@ -50,6 +52,7 @@ pub fn start(db: &D, stop_gap: usize) -> Result pub struct ScriptReq<'a, D: BatchDatabase> { state: State<'a, D>, script_index: usize, + initial_scripts_needed: usize, // if this is 1, we assume the descriptor is not derivable scripts_needed: VecDeque