|
5 | 5 |
|
6 | 6 | #include <wallet/wallet.h>
|
7 | 7 |
|
| 8 | +#include <blockfilter.h> |
8 | 9 | #include <chain.h>
|
9 | 10 | #include <consensus/amount.h>
|
10 | 11 | #include <consensus/consensus.h>
|
@@ -261,6 +262,64 @@ std::shared_ptr<CWallet> LoadWalletInternal(WalletContext& context, const std::s
|
261 | 262 | return nullptr;
|
262 | 263 | }
|
263 | 264 | }
|
| 265 | + |
| 266 | +class FastWalletRescanFilter |
| 267 | +{ |
| 268 | +public: |
| 269 | + FastWalletRescanFilter(const CWallet& wallet) : m_wallet(wallet) |
| 270 | + { |
| 271 | + // fast rescanning via block filters is only supported by descriptor wallets right now |
| 272 | + assert(!m_wallet.IsLegacy()); |
| 273 | + |
| 274 | + // create initial filter with scripts from all ScriptPubKeyMans |
| 275 | + for (auto spkm : m_wallet.GetAllScriptPubKeyMans()) { |
| 276 | + auto desc_spkm{dynamic_cast<DescriptorScriptPubKeyMan*>(spkm)}; |
| 277 | + assert(desc_spkm != nullptr); |
| 278 | + AddScriptPubKeys(desc_spkm); |
| 279 | + // save each range descriptor's end for possible future filter updates |
| 280 | + if (desc_spkm->IsHDEnabled()) { |
| 281 | + m_last_range_ends.emplace(desc_spkm->GetID(), desc_spkm->GetEndRange()); |
| 282 | + } |
| 283 | + } |
| 284 | + } |
| 285 | + |
| 286 | + void UpdateIfNeeded() |
| 287 | + { |
| 288 | + // repopulate filter with new scripts if top-up has happened since last iteration |
| 289 | + for (const auto& [desc_spkm_id, last_range_end] : m_last_range_ends) { |
| 290 | + auto desc_spkm{dynamic_cast<DescriptorScriptPubKeyMan*>(m_wallet.GetScriptPubKeyMan(desc_spkm_id))}; |
| 291 | + assert(desc_spkm != nullptr); |
| 292 | + int32_t current_range_end{desc_spkm->GetEndRange()}; |
| 293 | + if (current_range_end > last_range_end) { |
| 294 | + AddScriptPubKeys(desc_spkm, last_range_end); |
| 295 | + m_last_range_ends.at(desc_spkm->GetID()) = current_range_end; |
| 296 | + } |
| 297 | + } |
| 298 | + } |
| 299 | + |
| 300 | + std::optional<bool> MatchesBlock(const uint256& block_hash) const |
| 301 | + { |
| 302 | + return m_wallet.chain().blockFilterMatchesAny(BlockFilterType::BASIC, block_hash, m_filter_set); |
| 303 | + } |
| 304 | + |
| 305 | +private: |
| 306 | + const CWallet& m_wallet; |
| 307 | + /** Map for keeping track of each range descriptor's last seen end range. |
| 308 | + * This information is used to detect whether new addresses were derived |
| 309 | + * (that is, if the current end range is larger than the saved end range) |
| 310 | + * after processing a block and hence a filter set update is needed to |
| 311 | + * take possible keypool top-ups into account. |
| 312 | + */ |
| 313 | + std::map<uint256, int32_t> m_last_range_ends; |
| 314 | + GCSFilter::ElementSet m_filter_set; |
| 315 | + |
| 316 | + void AddScriptPubKeys(const DescriptorScriptPubKeyMan* desc_spkm, int32_t last_range_end = 0) |
| 317 | + { |
| 318 | + for (const auto& script_pub_key : desc_spkm->GetScriptPubKeys(last_range_end)) { |
| 319 | + m_filter_set.emplace(script_pub_key.begin(), script_pub_key.end()); |
| 320 | + } |
| 321 | + } |
| 322 | +}; |
264 | 323 | } // namespace
|
265 | 324 |
|
266 | 325 | 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)
|
|
0 commit comments