30 ScanResult result =
Scan(start_block, start_height, {}, reserver,
false);
77class FastWalletRescanFilter
83 for (
auto spkm :
m_wallet.GetAllScriptPubKeyMans()) {
85 assert(desc_spkm !=
nullptr);
86 AddScriptPubKeys(desc_spkm);
88 if (desc_spkm->IsHDEnabled()) {
98 auto desc_spkm{
dynamic_cast<DescriptorScriptPubKeyMan*
>(
m_wallet.GetScriptPubKeyMan(desc_spkm_id))};
99 assert(desc_spkm !=
nullptr);
100 int32_t current_range_end{desc_spkm->GetEndRange()};
101 if (current_range_end > last_range_end) {
102 AddScriptPubKeys(desc_spkm, last_range_end);
108 std::optional<bool> MatchesBlock(
const uint256& block_hash)
const
124 void AddScriptPubKeys(
const DescriptorScriptPubKeyMan* desc_spkm, int32_t last_range_end = 0)
126 for (
const auto& script_pub_key : desc_spkm->GetScriptPubKeys(last_range_end)) {
127 m_filter_set.emplace(script_pub_key.begin(), script_pub_key.end());
132static bool ShouldFetchBlock(
const FastWalletRescanFilter& filter,
const uint256& block_hash,
int block_height) {
133 auto matches_block{filter.MatchesBlock(block_hash)};
134 if (matches_block.has_value()) {
135 if (*matches_block) {
142 LogDebug(
BCLog::SCAN,
"Fast rescan: inspect block %d [%s] (WARNING: block filter not found!)\n", block_height, block_hash.
ToString());
149 bool block_still_active =
false;
150 bool has_next_block =
false;
158 if (has_next_block && (!max_height || block_height < *max_height)) {
159 next_block = {{next_block_hash, block_height + 1}};
162 return block_still_active;
170 if (progress_diff <= 0.0)
return;
173 if (block_height % 100 == 0) {
193 if (save_progress) found_block.
locator(loc);
196 if (block.
IsNull())
return false;
202 for (
size_t posInBlock = 0; posInBlock < block.
vtx.size(); ++posInBlock) {
205 static_cast<int>(posInBlock)},
220 constexpr auto INTERVAL_TIME{60
s};
221 auto current_time{reserver.
now()};
222 auto start_time{reserver.
now()};
227 std::unique_ptr<FastWalletRescanFilter> fast_rescan_filter;
231 fast_rescan_filter ?
"fast variant using block filters" :
"slow variant inspecting all blocks");
240 if (max_height) chain.findAncestorByHeight(state.
tip_hash, *max_height,
FoundBlock().hash(end_hash));
241 state.
progress_begin = chain.guessVerificationProgress(start_block);
242 state.
progress_end = chain.guessVerificationProgress(end_hash);
244 std::optional<std::pair<uint256, int>> next_block = {{start_block, start_height}};
245 int block_height = start_height;
246 while (!
m_abort && !chain.shutdownRequested()) {
247 if (!next_block)
break;
249 const uint256 block_hash = next_block->first;
250 block_height = next_block->second;
255 const bool block_still_active =
QueueNextBlock(block_hash, block_height, next_block, max_height);
257 progress_current = chain.guessVerificationProgress(block_hash);
260 bool next_interval = reserver.
now() >= current_time + INTERVAL_TIME;
262 current_time = reserver.
now();
266 bool fetch_block{
true};
267 if (fast_rescan_filter) {
268 fast_rescan_filter->UpdateIfNeeded();
269 fetch_block = ShouldFetchBlock(*fast_rescan_filter, block_hash, block_height);
272 if (fetch_block && !block_still_active) {
283 if (!fetch_block ||
ScanBlock(block_hash, block_height, save_progress && next_interval)) {
315 }
else if (chain.shutdownRequested()) {
316 m_wallet.
WalletLogPrintf(
"Rescan interrupted by shutdown request at block %d. Progress=%f\n", block_height, progress_current);
constexpr int64_t TIMESTAMP_WINDOW
Timestamp window used as a grace period by code that compares external timestamps (such as timestamps...
#define CHECK_NONFATAL(condition)
Identity function.
std::vector< CTransactionRef > vtx
std::unordered_set< Element, ByteVectorHash > ElementSet
std::string ToString() const
virtual bool findFirstBlockWithTimeAndHeight(int64_t min_time, int min_height, const FoundBlock &block={})=0
Find first block in the chain with timestamp >= the given time and height >= than the given height,...
virtual bool findBlock(const uint256 &hash, const FoundBlock &block={})=0
Return whether node has the block and optionally return block metadata or contents.
virtual double guessVerificationProgress(const uint256 &block_hash)=0
Estimate fraction of total transactions verified if blocks up to the specified block hash are verifie...
Helper for findBlock to selectively return pieces of block data.
FoundBlock & locator(CBlockLocator &locator)
Return locator if block is in the active chain.
FoundBlock & data(CBlock &data)
Read block data from disk.
A CWallet maintains a set of transactions and balances, and provides the ability to create new transa...
int GetLastBlockHeight() const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
Get last block processed height.
interfaces::Chain & chain() const
Interface for accessing chain state.
void WalletLogPrintf(util::ConstevalFormatString< sizeof...(Params)> wallet_fmt, const Params &... params) const
Prepends the wallet name in logging output to ease debugging in multi-wallet use cases.
btcsignals::signal< void(const std::string &title, int nProgress)> ShowProgress
Show progress e.g.
WalletDatabase & GetDatabase() const override
std::string DisplayName() const
Return wallet name for display, like LogName() but translates "default wallet" string.
uint256 GetLastBlockHash() const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
RecursiveMutex cs_wallet
Main wallet lock.
std::atomic< SteadyClock::time_point > m_scanning_start
void UpdateProgress(const LoopState &state, double progress_current, int block_height)
std::atomic< double > m_scanning_progress
void UpdateTipIfChanged(LoopState &state)
bool QueueNextBlock(const uint256 &block_hash, int block_height, std::optional< std::pair< uint256, int > > &next_block, std::optional< int > max_height)
Locate block_hash in the chain, queueing its active-chain successor into next_block if it exists and ...
bool ScanBlock(const uint256 &block_hash, int block_height, bool save_progress)
bool TryReserve(bool with_passphrase=false)
int64_t ScanFromTime(int64_t startTime, const WalletRescanReserver &reserver)
Scan active chain for relevant transactions after importing keys.
ScanResult Scan(const uint256 &start_block, int start_height, std::optional< int > max_height, const WalletRescanReserver &reserver, bool save_progress)
Scan the block chain (starting in start_block) for transactions from or to us.
std::atomic< bool > m_scanning_with_passphrase
std::atomic< bool > m_scanning
std::atomic< bool > m_abort
Access to the wallet database.
bool WriteBestBlock(const CBlockLocator &locator)
RAII object to check and reserve a wallet rescan.
Clock::time_point now() const
bool reserve(bool with_passphrase=false)
bool SyncTransaction(const CTransactionRef &tx, const SyncTxState &state, bool rescanning_old_block=false) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet)
#define LogDebug(category,...)
GCSFilter::ElementSet m_filter_set
std::map< uint256, int32_t > m_last_range_ends
Map for keeping track of each range descriptor's last seen end range.
Describes a place in the block chain to another node such that if the other node doesn't have the sam...
Progress window and tip tracked across Scan loop iterations.
uint256 last_scanned_block
Hash and height of most recent block that was successfully scanned.
enum wallet::ScanResult::@19 status
std::optional< int > last_scanned_height
uint256 last_failed_block
Height of the most recent block that could not be scanned due to read errors or pruning.
State of transaction confirmed in a block.
#define WITH_LOCK(cs, code)
Run code while locking a mutex.
consteval auto _(util::TranslatedLiteral str)