mirror of
https://github.com/bitcoin/bitcoin.git
synced 2024-11-19 18:09:47 +01:00
wallet: add FastWalletRescanFilter
class for speeding up rescans
This only supports wallet descriptors right now.
This commit is contained in:
parent
c051026586
commit
70b3513904
@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
#include <wallet/wallet.h>
|
#include <wallet/wallet.h>
|
||||||
|
|
||||||
|
#include <blockfilter.h>
|
||||||
#include <chain.h>
|
#include <chain.h>
|
||||||
#include <consensus/amount.h>
|
#include <consensus/amount.h>
|
||||||
#include <consensus/consensus.h>
|
#include <consensus/consensus.h>
|
||||||
@ -261,6 +262,64 @@ std::shared_ptr<CWallet> LoadWalletInternal(WalletContext& context, const std::s
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class FastWalletRescanFilter
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
FastWalletRescanFilter(const CWallet& wallet) : m_wallet(wallet)
|
||||||
|
{
|
||||||
|
// fast rescanning via block filters is only supported by descriptor wallets right now
|
||||||
|
assert(!m_wallet.IsLegacy());
|
||||||
|
|
||||||
|
// create initial filter with scripts from all ScriptPubKeyMans
|
||||||
|
for (auto spkm : m_wallet.GetAllScriptPubKeyMans()) {
|
||||||
|
auto desc_spkm{dynamic_cast<DescriptorScriptPubKeyMan*>(spkm)};
|
||||||
|
assert(desc_spkm != nullptr);
|
||||||
|
AddScriptPubKeys(desc_spkm);
|
||||||
|
// save each range descriptor's end for possible future filter updates
|
||||||
|
if (desc_spkm->IsHDEnabled()) {
|
||||||
|
m_last_range_ends.emplace(desc_spkm->GetID(), desc_spkm->GetEndRange());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateIfNeeded()
|
||||||
|
{
|
||||||
|
// repopulate filter with new scripts if top-up has happened since last iteration
|
||||||
|
for (const auto& [desc_spkm_id, last_range_end] : m_last_range_ends) {
|
||||||
|
auto desc_spkm{dynamic_cast<DescriptorScriptPubKeyMan*>(m_wallet.GetScriptPubKeyMan(desc_spkm_id))};
|
||||||
|
assert(desc_spkm != nullptr);
|
||||||
|
int32_t current_range_end{desc_spkm->GetEndRange()};
|
||||||
|
if (current_range_end > last_range_end) {
|
||||||
|
AddScriptPubKeys(desc_spkm, last_range_end);
|
||||||
|
m_last_range_ends.at(desc_spkm->GetID()) = current_range_end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::optional<bool> MatchesBlock(const uint256& block_hash) const
|
||||||
|
{
|
||||||
|
return m_wallet.chain().blockFilterMatchesAny(BlockFilterType::BASIC, block_hash, m_filter_set);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
const CWallet& m_wallet;
|
||||||
|
/** Map for keeping track of each range descriptor's last seen end range.
|
||||||
|
* This information is used to detect whether new addresses were derived
|
||||||
|
* (that is, if the current end range is larger than the saved end range)
|
||||||
|
* after processing a block and hence a filter set update is needed to
|
||||||
|
* take possible keypool top-ups into account.
|
||||||
|
*/
|
||||||
|
std::map<uint256, int32_t> m_last_range_ends;
|
||||||
|
GCSFilter::ElementSet m_filter_set;
|
||||||
|
|
||||||
|
void AddScriptPubKeys(const DescriptorScriptPubKeyMan* desc_spkm, int32_t last_range_end = 0)
|
||||||
|
{
|
||||||
|
for (const auto& script_pub_key : desc_spkm->GetScriptPubKeys(last_range_end)) {
|
||||||
|
m_filter_set.emplace(script_pub_key.begin(), script_pub_key.end());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
std::shared_ptr<CWallet> LoadWallet(WalletContext& context, const std::string& name, std::optional<bool> load_on_start, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error, std::vector<bilingual_str>& warnings)
|
std::shared_ptr<CWallet> LoadWallet(WalletContext& context, const std::string& name, std::optional<bool> load_on_start, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error, std::vector<bilingual_str>& warnings)
|
||||||
|
Loading…
Reference in New Issue
Block a user