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

3a9aba21a4 Split SetWalletFlags into Add/LoadWalletFlags (Andrew Chow)
d9cd095b59 Split SetActiveScriptPubKeyMan into Add/LoadActiveScriptPubKeyMan (Andrew Chow)
0122fbab4c 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 3a9aba21a4
  ryanofsky:
    Code review ACK 3a9aba21a4. Only changes since last review tweaks making m_wallet_flags updates more safe
  meshcollider:
    utACK 3a9aba21a4

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()) {
warnings.push_back("Unknown output type, cannot set descriptor to active.");
} 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);
}
void LegacyScriptPubKeyMan::SetHDChain(const CHDChain& chain, bool memonly)
void LegacyScriptPubKeyMan::LoadHDChain(const CHDChain& chain)
{
LOCK(cs_KeyStore);
// memonly == true means we are loading the wallet file
// memonly == false means that the chain is actually being changed
if (!memonly) {
// Store the new chain
if (!WalletBatch(m_storage.GetDatabase()).WriteHDChain(chain)) {
throw std::runtime_error(std::string(__func__) + ": writing chain failed");
}
// 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;
}
void LegacyScriptPubKeyMan::AddHDChain(const CHDChain& chain)
{
LOCK(cs_KeyStore);
// Store the new chain
if (!WalletBatch(m_storage.GetDatabase()).WriteHDChain(chain)) {
throw std::runtime_error(std::string(__func__) + ": writing chain failed");
}
// 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;
@ -1172,7 +1174,7 @@ void LegacyScriptPubKeyMan::SetHDSeed(const CPubKey& seed)
CHDChain newHdChain;
newHdChain.nVersion = m_storage.CanSupportFeature(FEATURE_HD_SPLIT) ? CHDChain::VERSION_HD_CHAIN_SPLIT : CHDChain::VERSION_HD_BASE;
newHdChain.seed_id = seed.GetID();
SetHDChain(newHdChain, false);
AddHDChain(newHdChain);
NotifyCanGetAddressesChanged();
WalletBatch batch(m_storage.GetDatabase());
m_storage.UnsetBlankWalletFlag(batch);

View file

@ -422,8 +422,10 @@ public:
//! Generate a new key
CPubKey GenerateNewKey(WalletBatch& batch, CHDChain& hd_chain, bool internal = false) EXCLUSIVE_LOCKS_REQUIRED(cs_KeyStore);
/* Set the HD chain model (chain child index counters) */
void SetHDChain(const CHDChain& chain, bool memonly);
/* Set the HD chain model (chain child index counters) and writes it to the database */
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; }
void AddInactiveHDChain(const CHDChain& chain);

View file

@ -1422,19 +1422,28 @@ bool CWallet::IsWalletFlagSet(uint64_t flag) const
return (m_wallet_flags & flag);
}
bool CWallet::SetWalletFlags(uint64_t overwriteFlags, bool memonly)
bool CWallet::LoadWalletFlags(uint64_t flags)
{
LOCK(cs_wallet);
m_wallet_flags = overwriteFlags;
if (((overwriteFlags & KNOWN_WALLET_FLAGS) >> 32) ^ (overwriteFlags >> 32)) {
if (((flags & KNOWN_WALLET_FLAGS) >> 32) ^ (flags >> 32)) {
// contains unknown non-tolerable wallet flags
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");
}
return true;
return LoadWalletFlags(flags);
}
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
walletInstance->SetMinVersion(FEATURE_LATEST);
walletInstance->SetWalletFlags(wallet_creation_flags, false);
walletInstance->AddWalletFlags(wallet_creation_flags);
// Only create LegacyScriptPubKeyMan when not descriptor wallet
if (!walletInstance->IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS)) {
@ -4419,12 +4428,21 @@ void CWallet::SetupDescriptorScriptPubKeyMans()
spk_manager->SetupDescriptorGeneration(master_key, t);
uint256 id = spk_manager->GetID();
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));
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_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();
}

View file

@ -1176,7 +1176,9 @@ public:
/** overwrite all flags by the given uint64_t
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 */
bool IsLegacy() const;
@ -1254,12 +1256,17 @@ public:
//! Instantiate a descriptor ScriptPubKeyMan from the WalletDescriptor and load it
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] type The OutputType this ScriptPubKeyMan provides addresses for
//! @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 SetActiveScriptPubKeyMan(uint256 id, OutputType type, bool internal, bool memonly = false);
void AddActiveScriptPubKeyMan(uint256 id, OutputType type, bool internal);
//! 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
void SetupDescriptorScriptPubKeyMans();

View file

@ -539,11 +539,11 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
} else if (strType == DBKeys::HDCHAIN) {
CHDChain chain;
ssValue >> chain;
pwallet->GetOrCreateLegacyScriptPubKeyMan()->SetHDChain(chain, true);
pwallet->GetOrCreateLegacyScriptPubKeyMan()->LoadHDChain(chain);
} else if (strType == DBKeys::FLAGS) {
uint64_t flags;
ssValue >> flags;
if (!pwallet->SetWalletFlags(flags, true)) {
if (!pwallet->LoadWalletFlags(flags)) {
strErr = "Error reading wallet database: Unknown non-tolerable wallet flags found";
return false;
}
@ -752,10 +752,10 @@ DBErrors WalletBatch::LoadWallet(CWallet* pwallet)
// Set the active ScriptPubKeyMans
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) {
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