wallet: Introduce a callback called after TopUp completes

After TopUp completes, the wallet containing each SPKM will want to know
what new scriptPubKeys were generated. In order for all TopUp calls
(including ones internal the the SPKM), we use a callback function in
the WalletStorage interface.
This commit is contained in:
Ava Chow 2024-02-02 14:16:46 -05:00
parent b276825932
commit 99a0cddbc0
4 changed files with 28 additions and 0 deletions

View file

@ -1290,6 +1290,9 @@ bool LegacyScriptPubKeyMan::TopUp(unsigned int kpSize)
}
if (!batch.TxnCommit()) throw std::runtime_error(strprintf("Error during keypool top up. Cannot commit changes for wallet %s", m_storage.GetDisplayName()));
NotifyCanGetAddressesChanged();
// Note: Unlike with DescriptorSPKM, LegacySPKM does not need to call
// m_storage.TopUpCallback() as we do not know what new scripts the LegacySPKM is
// watching for. CWallet's scriptPubKey cache is not used for LegacySPKMs.
return true;
}
@ -2154,6 +2157,7 @@ bool DescriptorScriptPubKeyMan::TopUp(unsigned int size)
bool DescriptorScriptPubKeyMan::TopUpWithDB(WalletBatch& batch, unsigned int size)
{
LOCK(cs_desc_man);
std::set<CScript> new_spks;
unsigned int target_size;
if (size > 0) {
target_size = size;
@ -2184,6 +2188,7 @@ bool DescriptorScriptPubKeyMan::TopUpWithDB(WalletBatch& batch, unsigned int siz
if (!m_wallet_descriptor.descriptor->Expand(i, provider, scripts_temp, out_keys, &temp_cache)) return false;
}
// Add all of the scriptPubKeys to the scriptPubKey set
new_spks.insert(scripts_temp.begin(), scripts_temp.end());
for (const CScript& script : scripts_temp) {
m_map_script_pub_keys[script] = i;
}
@ -2209,6 +2214,7 @@ bool DescriptorScriptPubKeyMan::TopUpWithDB(WalletBatch& batch, unsigned int siz
// By this point, the cache size should be the size of the entire range
assert(m_wallet_descriptor.range_end - 1 == m_max_cached_index);
m_storage.TopUpCallback(new_spks, this);
NotifyCanGetAddressesChanged();
return true;
}
@ -2624,6 +2630,7 @@ uint256 DescriptorScriptPubKeyMan::GetID() const
void DescriptorScriptPubKeyMan::SetCache(const DescriptorCache& cache)
{
LOCK(cs_desc_man);
std::set<CScript> new_spks;
m_wallet_descriptor.cache = cache;
for (int32_t i = m_wallet_descriptor.range_start; i < m_wallet_descriptor.range_end; ++i) {
FlatSigningProvider out_keys;
@ -2632,6 +2639,7 @@ void DescriptorScriptPubKeyMan::SetCache(const DescriptorCache& cache)
throw std::runtime_error("Error: Unable to expand wallet descriptor from cache");
}
// Add all of the scriptPubKeys to the scriptPubKey set
new_spks.insert(scripts_temp.begin(), scripts_temp.end());
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]));
@ -2649,6 +2657,8 @@ void DescriptorScriptPubKeyMan::SetCache(const DescriptorCache& cache)
}
m_max_cached_index++;
}
// Make sure the wallet knows about our new spks
m_storage.TopUpCallback(new_spks, this);
}
bool DescriptorScriptPubKeyMan::AddKey(const CKeyID& key_id, const CKey& key)

View file

@ -31,6 +31,7 @@ struct bilingual_str;
namespace wallet {
struct MigrationData;
class ScriptPubKeyMan;
// Wallet storage things that ScriptPubKeyMans need in order to be able to store things to the wallet database.
// It provides access to things that are part of the entire wallet and not specific to a ScriptPubKeyMan such as
@ -51,6 +52,8 @@ public:
virtual bool WithEncryptionKey(std::function<bool (const CKeyingMaterial&)> cb) const = 0;
virtual bool HasEncryptionKeys() const = 0;
virtual bool IsLocked() const = 0;
//! Callback function for after TopUp completes containining any scripts that were added by a SPKMan
virtual void TopUpCallback(const std::set<CScript>&, ScriptPubKeyMan*) = 0;
};
//! Constant representing an unknown spkm creation time

View file

@ -4334,4 +4334,14 @@ util::Result<MigrationResult> MigrateLegacyToDescriptor(const std::string& walle
}
return res;
}
void CWallet::CacheNewScriptPubKeys(const std::set<CScript>& spks, ScriptPubKeyMan* spkm)
{
}
void CWallet::TopUpCallback(const std::set<CScript>& spks, ScriptPubKeyMan* spkm)
{
// Update scriptPubKey cache
CacheNewScriptPubKeys(spks, spkm);
}
} // namespace wallet

View file

@ -1042,6 +1042,11 @@ public:
//! Whether the (external) signer performs R-value signature grinding
bool CanGrindR() const;
//! Add scriptPubKeys for this ScriptPubKeyMan into the scriptPubKey cache
void CacheNewScriptPubKeys(const std::set<CScript>& spks, ScriptPubKeyMan* spkm);
void TopUpCallback(const std::set<CScript>& spks, ScriptPubKeyMan* spkm) override;
};
/**