diff --git a/src/wallet/scriptpubkeyman.h b/src/wallet/scriptpubkeyman.h --- a/src/wallet/scriptpubkeyman.h +++ b/src/wallet/scriptpubkeyman.h @@ -692,6 +692,8 @@ uint256 GetID() const override; void SetType(OutputType type, bool internal) override; + + void SetCache(const DescriptorCache &cache); }; #endif // BITCOIN_WALLET_SCRIPTPUBKEYMAN_H diff --git a/src/wallet/scriptpubkeyman.cpp b/src/wallet/scriptpubkeyman.cpp --- a/src/wallet/scriptpubkeyman.cpp +++ b/src/wallet/scriptpubkeyman.cpp @@ -1646,3 +1646,28 @@ this->m_address_type = type; this->m_internal = internal; } + +void DescriptorScriptPubKeyMan::SetCache(const DescriptorCache &cache) { + LOCK(cs_desc_man); + m_wallet_descriptor.cache = cache; + for (int32_t i = m_wallet_descriptor.range_start; + i < m_wallet_descriptor.range_end; ++i) { + FlatSigningProvider out_keys; + std::vector scripts_temp; + if (!m_wallet_descriptor.descriptor->ExpandFromCache( + i, m_wallet_descriptor.cache, scripts_temp, out_keys)) { + throw std::runtime_error( + "Error: Unable to expand wallet descriptor from cache"); + } + // Add all of the scriptPubKeys to the scriptPubKey set + for (const CScript &script : scripts_temp) { + if (m_map_script_pub_keys.count(script) != 0) { + throw std::runtime_error( + strprintf("Error: Already loaded script at index %d as " + "being at index %d", + i, m_map_script_pub_keys[script])); + } + m_map_script_pub_keys[script] = i; + } + } +} diff --git a/src/wallet/walletdb.cpp b/src/wallet/walletdb.cpp --- a/src/wallet/walletdb.cpp +++ b/src/wallet/walletdb.cpp @@ -43,6 +43,7 @@ const std::string TX{"tx"}; const std::string VERSION{"version"}; const std::string WALLETDESCRIPTOR{"walletdescriptor"}; +const std::string WALLETDESCRIPTORCACHE{"walletdescriptorcache"}; const std::string WATCHMETA{"watchmeta"}; const std::string WATCHS{"watchs"}; } // namespace DBKeys @@ -214,6 +215,7 @@ std::vector vWalletUpgrade; std::map m_active_external_spks; std::map m_active_internal_spks; + std::map m_descriptor_caches; CWalletScanState() {} }; @@ -469,7 +471,39 @@ ssKey >> id; WalletDescriptor desc; ssValue >> desc; + if (wss.m_descriptor_caches.count(id) == 0) { + wss.m_descriptor_caches[id] = DescriptorCache(); + } pwallet->LoadDescriptorScriptPubKeyMan(id, desc); + } else if (strType == DBKeys::WALLETDESCRIPTORCACHE) { + bool parent = true; + uint256 desc_id; + uint32_t key_exp_index; + uint32_t der_index; + ssKey >> desc_id; + ssKey >> key_exp_index; + + // if the der_index exists, it's a derived xpub + try { + ssKey >> der_index; + parent = false; + } catch (...) { + } + + std::vector ser_xpub(BIP32_EXTKEY_SIZE); + ssValue >> ser_xpub; + CExtPubKey xpub; + xpub.Decode(ser_xpub.data()); + if (wss.m_descriptor_caches.count(desc_id)) { + wss.m_descriptor_caches[desc_id] = DescriptorCache(); + } + if (parent) { + wss.m_descriptor_caches[desc_id].CacheParentExtPubKey( + key_exp_index, xpub); + } else { + wss.m_descriptor_caches[desc_id].CacheDerivedExtPubKey( + key_exp_index, der_index, xpub); + } } else if (strType != DBKeys::BESTBLOCK && strType != DBKeys::BESTBLOCK_NOMERKLE && strType != DBKeys::MINVERSION && @@ -578,6 +612,14 @@ /* memonly */ true); } + // Set the descriptor caches + for (auto desc_cache_pair : wss.m_descriptor_caches) { + auto spk_man = pwallet->GetScriptPubKeyMan(desc_cache_pair.first); + assert(spk_man); + ((DescriptorScriptPubKeyMan *)spk_man) + ->SetCache(desc_cache_pair.second); + } + if (fNoncriticalErrors && result == DBErrors::LOAD_OK) { result = DBErrors::NONCRITICAL_ERROR; }