Skip to content

Commit 74fede3

Browse files
committed
wallet: Upgrade existing descriptor caches
Add functions to upgrade existing descriptor caches to support the use of last hardened xpub caching.
1 parent 432ba9e commit 74fede3

File tree

6 files changed

+62
-0
lines changed

6 files changed

+62
-0
lines changed

src/wallet/scriptpubkeyman.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2278,3 +2278,32 @@ bool DescriptorScriptPubKeyMan::GetDescriptorString(std::string& out, bool priv)
22782278

22792279
return m_wallet_descriptor.descriptor->ToNormalizedString(provider, out, priv);
22802280
}
2281+
2282+
void DescriptorScriptPubKeyMan::UpgradeDescriptorCache()
2283+
{
2284+
LOCK(cs_desc_man);
2285+
if (m_storage.IsLocked() || m_storage.IsWalletFlagSet(WALLET_FLAG_LAST_HARDENED_XPUB_CACHED)) {
2286+
return;
2287+
}
2288+
2289+
// Skip if we have the last hardened xpub cache
2290+
if (m_wallet_descriptor.cache.GetCachedLastHardenedExtPubKeys().size() > 0) {
2291+
return;
2292+
}
2293+
2294+
// Expand the descriptor
2295+
FlatSigningProvider provider;
2296+
provider.keys = GetKeys();
2297+
FlatSigningProvider out_keys;
2298+
std::vector<CScript> scripts_temp;
2299+
DescriptorCache temp_cache;
2300+
if (!m_wallet_descriptor.descriptor->Expand(0, provider, scripts_temp, out_keys, &temp_cache)){
2301+
throw std::runtime_error("Unable to expand descriptor");
2302+
}
2303+
2304+
// Cache the last hardened xpubs
2305+
DescriptorCache diff = m_wallet_descriptor.cache.MergeAndDiff(temp_cache);
2306+
if (!WalletBatch(m_storage.GetDatabase()).WriteDescriptorCacheItems(GetID(), diff)) {
2307+
throw std::runtime_error(std::string(__func__) + ": writing cache items failed");
2308+
}
2309+
}

src/wallet/scriptpubkeyman.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -631,6 +631,8 @@ class DescriptorScriptPubKeyMan : public ScriptPubKeyMan
631631
const std::vector<CScript> GetScriptPubKeys() const;
632632

633633
bool GetDescriptorString(std::string& out, bool priv) const;
634+
635+
void UpgradeDescriptorCache();
634636
};
635637

636638
#endif // BITCOIN_WALLET_SCRIPTPUBKEYMAN_H

src/wallet/wallet.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,19 @@ void CWallet::UpgradeKeyMetadata()
374374
SetWalletFlag(WALLET_FLAG_KEY_ORIGIN_METADATA);
375375
}
376376

377+
void CWallet::UpgradeDescriptorCache()
378+
{
379+
if (!IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS) || IsLocked() || IsWalletFlagSet(WALLET_FLAG_LAST_HARDENED_XPUB_CACHED)) {
380+
return;
381+
}
382+
383+
for (ScriptPubKeyMan* spkm : GetAllScriptPubKeyMans()) {
384+
DescriptorScriptPubKeyMan* desc_spkm = dynamic_cast<DescriptorScriptPubKeyMan*>(spkm);
385+
desc_spkm->UpgradeDescriptorCache();
386+
}
387+
SetWalletFlag(WALLET_FLAG_LAST_HARDENED_XPUB_CACHED);
388+
}
389+
377390
bool CWallet::Unlock(const SecureString& strWalletPassphrase, bool accept_no_keys)
378391
{
379392
CCrypter crypter;
@@ -390,6 +403,8 @@ bool CWallet::Unlock(const SecureString& strWalletPassphrase, bool accept_no_key
390403
if (Unlock(_vMasterKey, accept_no_keys)) {
391404
// Now that we've unlocked, upgrade the key metadata
392405
UpgradeKeyMetadata();
406+
// Now that we've unlocked, upgrade the descriptor cache
407+
UpgradeDescriptorCache();
393408
return true;
394409
}
395410
}

src/wallet/wallet.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ static constexpr uint64_t KNOWN_WALLET_FLAGS =
117117
WALLET_FLAG_AVOID_REUSE
118118
| WALLET_FLAG_BLANK_WALLET
119119
| WALLET_FLAG_KEY_ORIGIN_METADATA
120+
| WALLET_FLAG_LAST_HARDENED_XPUB_CACHED
120121
| WALLET_FLAG_DISABLE_PRIVATE_KEYS
121122
| WALLET_FLAG_DESCRIPTORS
122123
| WALLET_FLAG_EXTERNAL_SIGNER;
@@ -128,6 +129,7 @@ static const std::map<std::string,WalletFlags> WALLET_FLAG_MAP{
128129
{"avoid_reuse", WALLET_FLAG_AVOID_REUSE},
129130
{"blank", WALLET_FLAG_BLANK_WALLET},
130131
{"key_origin_metadata", WALLET_FLAG_KEY_ORIGIN_METADATA},
132+
{"last_hardened_xpub_cached", WALLET_FLAG_LAST_HARDENED_XPUB_CACHED},
131133
{"disable_private_keys", WALLET_FLAG_DISABLE_PRIVATE_KEYS},
132134
{"descriptor_wallet", WALLET_FLAG_DESCRIPTORS},
133135
{"external_signer", WALLET_FLAG_EXTERNAL_SIGNER}
@@ -476,6 +478,9 @@ class CWallet final : public WalletStorage, public interfaces::Chain::Notificati
476478
//! Upgrade stored CKeyMetadata objects to store key origin info as KeyOriginInfo
477479
void UpgradeKeyMetadata() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
478480

481+
//! Upgrade DescriptorCaches
482+
void UpgradeDescriptorCache() EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
483+
479484
bool LoadMinVersion(int nVersion) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet) { AssertLockHeld(cs_wallet); nWalletVersion = nVersion; return true; }
480485

481486
//! Adds a destination data tuple to the store, without saving it to disk

src/wallet/walletdb.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -884,6 +884,14 @@ DBErrors WalletBatch::LoadWallet(CWallet* pwallet)
884884
result = DBErrors::CORRUPT;
885885
}
886886

887+
// Upgrade all of the descriptor caches to cache the last hardened xpub
888+
// This operation is not atomic, but if it fails, only new entries are added so it is backwards compatible
889+
try {
890+
pwallet->UpgradeDescriptorCache();
891+
} catch (...) {
892+
result = DBErrors::CORRUPT;
893+
}
894+
887895
// Set the inactive chain
888896
if (wss.m_hd_chains.size() > 0) {
889897
LegacyScriptPubKeyMan* legacy_spkm = pwallet->GetLegacyScriptPubKeyMan();

src/wallet/walletutil.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,9 @@ enum WalletFlags : uint64_t {
4343
// Indicates that the metadata has already been upgraded to contain key origins
4444
WALLET_FLAG_KEY_ORIGIN_METADATA = (1ULL << 1),
4545

46+
// Indicates that the descriptor cache has been upgraded to cache last hardened xpubs
47+
WALLET_FLAG_LAST_HARDENED_XPUB_CACHED = (1ULL << 2),
48+
4649
// will enforce the rule that the wallet can't contain any private keys (only watch-only/pubkeys)
4750
WALLET_FLAG_DISABLE_PRIVATE_KEYS = (1ULL << 32),
4851

0 commit comments

Comments
 (0)