Merge #19046: Replace CWallet::Set* functions that use memonly with Add/Load variants

3a9aba21a49a6d80bd187940d5e26893937b6832 Split SetWalletFlags into Add/LoadWalletFlags (Andrew Chow)
d9cd095b5965fc20c09f401370e7ba99446663e3 Split SetActiveScriptPubKeyMan into Add/LoadActiveScriptPubKeyMan (Andrew Chow)
0122fbab4c340b23ae56173de6c5ab866ba25ab8 Split SetHDChain into AddHDChain and LoadHDChain (Andrew Chow)

Pull request description:

  `SetHDChaiin`, `SetActiveScriptPubKeyMan`, and `SetWalletFlags` have a `memonly` argument which is kind of confusing, as noted in https://github.com/bitcoin/bitcoin/pull/17681#discussion_r427633081. This PR replaces those functions with `Add*` and `Load*` variants so that they follow the pattern used elsewhere in the wallet.

  `AddHDChain`, `AddActiveScriptPubKeyMan`, and `AddWalletFlags` both set their respective variables in `CWallet` and writes them to disk. These functions are used by the actions which modify the wallet such as `sethdseed`, `importdescriptors`, and creating a new wallet.

  `LoadHDChain`, `LoadActiveScriptPubKeyMan`, and `LoadWalletFlags` just set the `CWallet` variables. These functions are used by `LoadWallet` when loading the wallet from disk.

ACKs for top commit:
  jnewbery:
    Code review ACK 3a9aba21a49a6d80bd187940d5e26893937b6832
  ryanofsky:
    Code review ACK 3a9aba21a49a6d80bd187940d5e26893937b6832. Only changes since last review tweaks making m_wallet_flags updates more safe
  meshcollider:
    utACK 3a9aba21a49a6d80bd187940d5e26893937b6832

Tree-SHA512: 365aeaafc5ba42879c0eb797ec3beb29ab70e27f917dc880763f743420b3be6ddf797240996beed8a9ad70fb212c2590253c6b44c9dc244529c3939d9538983f
This commit is contained in:
Samuel Dobson 2020-07-11 22:58:28 +12:00
commit 89899a3448
No known key found for this signature in database
GPG Key ID: D300116E1C875A3D
6 changed files with 61 additions and 38 deletions

View File

@ -1547,7 +1547,7 @@ static UniValue ProcessDescriptorImport(CWallet * const pwallet, const UniValue&
if (!w_desc.descriptor->GetOutputType()) { if (!w_desc.descriptor->GetOutputType()) {
warnings.push_back("Unknown output type, cannot set descriptor to active."); warnings.push_back("Unknown output type, cannot set descriptor to active.");
} else { } else {
pwallet->SetActiveScriptPubKeyMan(spk_manager->GetID(), *w_desc.descriptor->GetOutputType(), internal); pwallet->AddActiveScriptPubKeyMan(spk_manager->GetID(), *w_desc.descriptor->GetOutputType(), internal);
} }
} }

View File

@ -905,20 +905,22 @@ bool LegacyScriptPubKeyMan::AddWatchOnly(const CScript& dest, int64_t nCreateTim
return AddWatchOnly(dest); return AddWatchOnly(dest);
} }
void LegacyScriptPubKeyMan::SetHDChain(const CHDChain& chain, bool memonly) void LegacyScriptPubKeyMan::LoadHDChain(const CHDChain& chain)
{ {
LOCK(cs_KeyStore); LOCK(cs_KeyStore);
// memonly == true means we are loading the wallet file m_hd_chain = chain;
// memonly == false means that the chain is actually being changed }
if (!memonly) {
// Store the new chain void LegacyScriptPubKeyMan::AddHDChain(const CHDChain& chain)
if (!WalletBatch(m_storage.GetDatabase()).WriteHDChain(chain)) { {
throw std::runtime_error(std::string(__func__) + ": writing chain failed"); LOCK(cs_KeyStore);
} // Store the new chain
// When there's an old chain, add it as an inactive chain as we are now rotating hd chains if (!WalletBatch(m_storage.GetDatabase()).WriteHDChain(chain)) {
if (!m_hd_chain.seed_id.IsNull()) { throw std::runtime_error(std::string(__func__) + ": writing chain failed");
AddInactiveHDChain(m_hd_chain); }
} // When there's an old chain, add it as an inactive chain as we are now rotating hd chains
if (!m_hd_chain.seed_id.IsNull()) {
AddInactiveHDChain(m_hd_chain);
} }
m_hd_chain = chain; m_hd_chain = chain;
@ -1172,7 +1174,7 @@ void LegacyScriptPubKeyMan::SetHDSeed(const CPubKey& seed)
CHDChain newHdChain; CHDChain newHdChain;
newHdChain.nVersion = m_storage.CanSupportFeature(FEATURE_HD_SPLIT) ? CHDChain::VERSION_HD_CHAIN_SPLIT : CHDChain::VERSION_HD_BASE; newHdChain.nVersion = m_storage.CanSupportFeature(FEATURE_HD_SPLIT) ? CHDChain::VERSION_HD_CHAIN_SPLIT : CHDChain::VERSION_HD_BASE;
newHdChain.seed_id = seed.GetID(); newHdChain.seed_id = seed.GetID();
SetHDChain(newHdChain, false); AddHDChain(newHdChain);
NotifyCanGetAddressesChanged(); NotifyCanGetAddressesChanged();
WalletBatch batch(m_storage.GetDatabase()); WalletBatch batch(m_storage.GetDatabase());
m_storage.UnsetBlankWalletFlag(batch); m_storage.UnsetBlankWalletFlag(batch);

View File

@ -422,8 +422,10 @@ public:
//! Generate a new key //! Generate a new key
CPubKey GenerateNewKey(WalletBatch& batch, CHDChain& hd_chain, bool internal = false) EXCLUSIVE_LOCKS_REQUIRED(cs_KeyStore); CPubKey GenerateNewKey(WalletBatch& batch, CHDChain& hd_chain, bool internal = false) EXCLUSIVE_LOCKS_REQUIRED(cs_KeyStore);
/* Set the HD chain model (chain child index counters) */ /* Set the HD chain model (chain child index counters) and writes it to the database */
void SetHDChain(const CHDChain& chain, bool memonly); void AddHDChain(const CHDChain& chain);
//! Load a HD chain model (used by LoadWallet)
void LoadHDChain(const CHDChain& chain);
const CHDChain& GetHDChain() const { return m_hd_chain; } const CHDChain& GetHDChain() const { return m_hd_chain; }
void AddInactiveHDChain(const CHDChain& chain); void AddInactiveHDChain(const CHDChain& chain);

View File

@ -1422,19 +1422,28 @@ bool CWallet::IsWalletFlagSet(uint64_t flag) const
return (m_wallet_flags & flag); return (m_wallet_flags & flag);
} }
bool CWallet::SetWalletFlags(uint64_t overwriteFlags, bool memonly) bool CWallet::LoadWalletFlags(uint64_t flags)
{ {
LOCK(cs_wallet); LOCK(cs_wallet);
m_wallet_flags = overwriteFlags; if (((flags & KNOWN_WALLET_FLAGS) >> 32) ^ (flags >> 32)) {
if (((overwriteFlags & KNOWN_WALLET_FLAGS) >> 32) ^ (overwriteFlags >> 32)) {
// contains unknown non-tolerable wallet flags // contains unknown non-tolerable wallet flags
return false; return false;
} }
if (!memonly && !WalletBatch(*database).WriteWalletFlags(m_wallet_flags)) { m_wallet_flags = flags;
return true;
}
bool CWallet::AddWalletFlags(uint64_t flags)
{
LOCK(cs_wallet);
// We should never be writing unknown onon-tolerable wallet flags
assert(!(((flags & KNOWN_WALLET_FLAGS) >> 32) ^ (flags >> 32)));
if (!WalletBatch(*database).WriteWalletFlags(flags)) {
throw std::runtime_error(std::string(__func__) + ": writing wallet flags failed"); throw std::runtime_error(std::string(__func__) + ": writing wallet flags failed");
} }
return true; return LoadWalletFlags(flags);
} }
int64_t CWalletTx::GetTxTime() const int64_t CWalletTx::GetTxTime() const
@ -3798,7 +3807,7 @@ std::shared_ptr<CWallet> CWallet::CreateWalletFromFile(interfaces::Chain& chain,
// ensure this wallet.dat can only be opened by clients supporting HD with chain split and expects no default key // ensure this wallet.dat can only be opened by clients supporting HD with chain split and expects no default key
walletInstance->SetMinVersion(FEATURE_LATEST); walletInstance->SetMinVersion(FEATURE_LATEST);
walletInstance->SetWalletFlags(wallet_creation_flags, false); walletInstance->AddWalletFlags(wallet_creation_flags);
// Only create LegacyScriptPubKeyMan when not descriptor wallet // Only create LegacyScriptPubKeyMan when not descriptor wallet
if (!walletInstance->IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS)) { if (!walletInstance->IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS)) {
@ -4419,12 +4428,21 @@ void CWallet::SetupDescriptorScriptPubKeyMans()
spk_manager->SetupDescriptorGeneration(master_key, t); spk_manager->SetupDescriptorGeneration(master_key, t);
uint256 id = spk_manager->GetID(); uint256 id = spk_manager->GetID();
m_spk_managers[id] = std::move(spk_manager); m_spk_managers[id] = std::move(spk_manager);
SetActiveScriptPubKeyMan(id, t, internal); AddActiveScriptPubKeyMan(id, t, internal);
} }
} }
} }
void CWallet::SetActiveScriptPubKeyMan(uint256 id, OutputType type, bool internal, bool memonly) void CWallet::AddActiveScriptPubKeyMan(uint256 id, OutputType type, bool internal)
{
WalletBatch batch(*database);
if (!batch.WriteActiveScriptPubKeyMan(static_cast<uint8_t>(type), id, internal)) {
throw std::runtime_error(std::string(__func__) + ": writing active ScriptPubKeyMan id failed");
}
LoadActiveScriptPubKeyMan(id, type, internal);
}
void CWallet::LoadActiveScriptPubKeyMan(uint256 id, OutputType type, bool internal)
{ {
WalletLogPrintf("Setting spkMan to active: id = %s, type = %d, internal = %d\n", id.ToString(), static_cast<int>(type), static_cast<int>(internal)); WalletLogPrintf("Setting spkMan to active: id = %s, type = %d, internal = %d\n", id.ToString(), static_cast<int>(type), static_cast<int>(internal));
auto& spk_mans = internal ? m_internal_spk_managers : m_external_spk_managers; auto& spk_mans = internal ? m_internal_spk_managers : m_external_spk_managers;
@ -4432,12 +4450,6 @@ void CWallet::SetActiveScriptPubKeyMan(uint256 id, OutputType type, bool interna
spk_man->SetInternal(internal); spk_man->SetInternal(internal);
spk_mans[type] = spk_man; spk_mans[type] = spk_man;
if (!memonly) {
WalletBatch batch(*database);
if (!batch.WriteActiveScriptPubKeyMan(static_cast<uint8_t>(type), id, internal)) {
throw std::runtime_error(std::string(__func__) + ": writing active ScriptPubKeyMan id failed");
}
}
NotifyCanGetAddressesChanged(); NotifyCanGetAddressesChanged();
} }

View File

@ -1176,7 +1176,9 @@ public:
/** overwrite all flags by the given uint64_t /** overwrite all flags by the given uint64_t
returns false if unknown, non-tolerable flags are present */ returns false if unknown, non-tolerable flags are present */
bool SetWalletFlags(uint64_t overwriteFlags, bool memOnly); bool AddWalletFlags(uint64_t flags);
/** Loads the flags into the wallet. (used by LoadWallet) */
bool LoadWalletFlags(uint64_t flags);
/** Determine if we are a legacy wallet */ /** Determine if we are a legacy wallet */
bool IsLegacy() const; bool IsLegacy() const;
@ -1254,12 +1256,17 @@ public:
//! Instantiate a descriptor ScriptPubKeyMan from the WalletDescriptor and load it //! Instantiate a descriptor ScriptPubKeyMan from the WalletDescriptor and load it
void LoadDescriptorScriptPubKeyMan(uint256 id, WalletDescriptor& desc); void LoadDescriptorScriptPubKeyMan(uint256 id, WalletDescriptor& desc);
//! Sets the active ScriptPubKeyMan for the specified type and internal //! Adds the active ScriptPubKeyMan for the specified type and internal. Writes it to the wallet file
//! @param[in] id The unique id for the ScriptPubKeyMan //! @param[in] id The unique id for the ScriptPubKeyMan
//! @param[in] type The OutputType this ScriptPubKeyMan provides addresses for //! @param[in] type The OutputType this ScriptPubKeyMan provides addresses for
//! @param[in] internal Whether this ScriptPubKeyMan provides change addresses //! @param[in] internal Whether this ScriptPubKeyMan provides change addresses
//! @param[in] memonly Whether to record this update to the database. Set to true for wallet loading, normally false when actually updating the wallet. void AddActiveScriptPubKeyMan(uint256 id, OutputType type, bool internal);
void SetActiveScriptPubKeyMan(uint256 id, OutputType type, bool internal, bool memonly = false);
//! Loads an active ScriptPubKeyMan for the specified type and internal. (used by LoadWallet)
//! @param[in] id The unique id for the ScriptPubKeyMan
//! @param[in] type The OutputType this ScriptPubKeyMan provides addresses for
//! @param[in] internal Whether this ScriptPubKeyMan provides change addresses
void LoadActiveScriptPubKeyMan(uint256 id, OutputType type, bool internal);
//! Create new DescriptorScriptPubKeyMans and add them to the wallet //! Create new DescriptorScriptPubKeyMans and add them to the wallet
void SetupDescriptorScriptPubKeyMans(); void SetupDescriptorScriptPubKeyMans();

View File

@ -539,11 +539,11 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
} else if (strType == DBKeys::HDCHAIN) { } else if (strType == DBKeys::HDCHAIN) {
CHDChain chain; CHDChain chain;
ssValue >> chain; ssValue >> chain;
pwallet->GetOrCreateLegacyScriptPubKeyMan()->SetHDChain(chain, true); pwallet->GetOrCreateLegacyScriptPubKeyMan()->LoadHDChain(chain);
} else if (strType == DBKeys::FLAGS) { } else if (strType == DBKeys::FLAGS) {
uint64_t flags; uint64_t flags;
ssValue >> flags; ssValue >> flags;
if (!pwallet->SetWalletFlags(flags, true)) { if (!pwallet->LoadWalletFlags(flags)) {
strErr = "Error reading wallet database: Unknown non-tolerable wallet flags found"; strErr = "Error reading wallet database: Unknown non-tolerable wallet flags found";
return false; return false;
} }
@ -752,10 +752,10 @@ DBErrors WalletBatch::LoadWallet(CWallet* pwallet)
// Set the active ScriptPubKeyMans // Set the active ScriptPubKeyMans
for (auto spk_man_pair : wss.m_active_external_spks) { for (auto spk_man_pair : wss.m_active_external_spks) {
pwallet->SetActiveScriptPubKeyMan(spk_man_pair.second, spk_man_pair.first, /* internal */ false, /* memonly */ true); pwallet->LoadActiveScriptPubKeyMan(spk_man_pair.second, spk_man_pair.first, /* internal */ false);
} }
for (auto spk_man_pair : wss.m_active_internal_spks) { for (auto spk_man_pair : wss.m_active_internal_spks) {
pwallet->SetActiveScriptPubKeyMan(spk_man_pair.second, spk_man_pair.first, /* internal */ true, /* memonly */ true); pwallet->LoadActiveScriptPubKeyMan(spk_man_pair.second, spk_man_pair.first, /* internal */ true);
} }
// Set the descriptor caches // Set the descriptor caches