Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions src/wallet/rpc/backup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1783,7 +1783,7 @@ static UniValue ProcessDescriptorImport(CWallet& wallet, const UniValue& data, c
if (!w_desc.descriptor->GetOutputType()) {
warnings.push_back("Unknown output type, cannot set descriptor to active.");
} else {
wallet.AddActiveScriptPubKeyMan(spk_manager->GetID(), internal);
wallet.AddActiveScriptPubKeyMan(spk_manager->GetID(), internal ? InternalKey::Internal : InternalKey::External);
}
} else {
if (w_desc.descriptor->GetOutputType()) {
Expand Down Expand Up @@ -1976,6 +1976,7 @@ RPCHelpMan listdescriptors()
{RPCResult::Type::NUM, "timestamp", "The creation time of the descriptor"},
{RPCResult::Type::BOOL, "active", "Whether this descriptor is currently used to generate new addresses"},
{RPCResult::Type::BOOL, "internal", /*optional=*/true, "True if this descriptor is used to generate change addresses. False if this descriptor is used to generate receiving addresses; defined only for active descriptors"},
{RPCResult::Type::BOOL, "coinjoin", /*optional=*/true, "True if this descriptor is used to generate CoinJoin addresses. False if this descriptor is used to generate receiving addresses; defined only for active descriptors"},
{RPCResult::Type::ARR_FIXED, "range", /*optional=*/true, "Defined only for ranged descriptors", {
{RPCResult::Type::NUM, "", "Range start inclusive"},
{RPCResult::Type::NUM, "", "Range end inclusive"},
Expand Down Expand Up @@ -2034,7 +2035,10 @@ RPCHelpMan listdescriptors()
spk.pushKV("active", active);
const auto& type = wallet_descriptor.descriptor->GetOutputType();
if (active && type != std::nullopt) {
spk.pushKV("internal", wallet->GetScriptPubKeyMan(true) == desc_spk_man);
spk.pushKV("internal", wallet->GetScriptPubKeyMan(InternalKey::Internal) == desc_spk_man);
}
if (active && type != std::nullopt) {
spk.pushKV("coinjoin", wallet->GetScriptPubKeyMan(InternalKey::CoinJoin) == desc_spk_man);
}
if (wallet_descriptor.descriptor->IsRange()) {
UniValue range(UniValue::VARR);
Expand Down
2 changes: 1 addition & 1 deletion src/wallet/rpc/wallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,7 @@ static RPCHelpMan getwalletinfo()
{RPCResult::Type::NUM_TIME, "timefirstkey", "the " + UNIX_EPOCH_TIME + " of the oldest known key in the wallet"},
{RPCResult::Type::NUM_TIME, "keypoololdest", /* optional */ true, "the " + UNIX_EPOCH_TIME + " of the oldest pre-generated key in the key pool. Legacy wallets only"},
{RPCResult::Type::NUM, "keypoolsize", "how many new keys are pre-generated (only counts external keys)"},
{RPCResult::Type::NUM, "keypoolsize_hd_internal", /* optional */ true, "how many new keys are pre-generated for internal use (used for change outputs, only appears if the wallet is using this feature, otherwise external keys are used)"},
{RPCResult::Type::NUM, "keypoolsize_hd_internal", /* optional */ true, "how many new keys are pre-generated for internal use (used for change outputs and mobile coinjoin, only appears if the wallet is using this feature, otherwise external keys are used)"},
{RPCResult::Type::NUM, "keys_left", "how many new keys are left since last automatic backup"},
{RPCResult::Type::NUM_TIME, "unlocked_until", /* optional */ true, "the " + UNIX_EPOCH_TIME + " until which the wallet is unlocked for transfers, or 0 if the wallet is locked (only present for passphrase-encrypted wallets)"},
{RPCResult::Type::STR_AMOUNT, "paytxfee", "the transaction fee configuration, set in " + CURRENCY_UNIT + "/kB"},
Expand Down
6 changes: 3 additions & 3 deletions src/wallet/scriptpubkeyman.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2074,7 +2074,7 @@ bool DescriptorScriptPubKeyMan::AddDescriptorKeyWithDB(WalletBatch& batch, const
}
}

bool DescriptorScriptPubKeyMan::SetupDescriptorGeneration(const CExtKey& master_key, const SecureString& secure_mnemonic, const SecureString& secure_mnemonic_passphrase, bool internal)
bool DescriptorScriptPubKeyMan::SetupDescriptorGeneration(const CExtKey& master_key, const SecureString& secure_mnemonic, const SecureString& secure_mnemonic_passphrase, InternalKey internal)
{
LOCK(cs_desc_man);
assert(m_storage.IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS));
Expand All @@ -2099,10 +2099,10 @@ bool DescriptorScriptPubKeyMan::SetupDescriptorGeneration(const CExtKey& master_
std::string xpub = EncodeExtPubKey(master_key.Neuter());

// Build descriptor string
std::string desc_prefix = strprintf("pkh(%s/44'/%d'", xpub, Params().ExtCoinType());
std::string desc_prefix = strprintf("pkh(%s/%d'/%d'", xpub, internal == InternalKey::CoinJoin ? 9 : 44, Params().ExtCoinType());
std::string desc_suffix = "/*)";

std::string internal_path = internal ? "/1" : "/0";
std::string internal_path = (internal == InternalKey::Internal) ? "/1" : "/0";
std::string desc_str = desc_prefix + "/0'" + internal_path + desc_suffix;

// Make the descriptor
Expand Down
9 changes: 8 additions & 1 deletion src/wallet/scriptpubkeyman.h
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,13 @@ class CKeyPool
}
};

enum class InternalKey
{
External,
Internal,
CoinJoin,
};

/*
* A class implementing ScriptPubKeyMan manages some (or all) scriptPubKeys used in a wallet.
* It contains the scripts and keys related to the scriptPubKeys it manages.
Expand Down Expand Up @@ -575,7 +582,7 @@ class DescriptorScriptPubKeyMan : public ScriptPubKeyMan
bool IsHDEnabled() const override;

//! Setup descriptors based on the given CExtkey
bool SetupDescriptorGeneration(const CExtKey& master_key, const SecureString& secure_mnemonic, const SecureString& secure_mnemonic_passphrase, bool internal);
bool SetupDescriptorGeneration(const CExtKey& master_key, const SecureString& secure_mnemonic, const SecureString& secure_mnemonic_passphrase, InternalKey internal);

bool HavePrivateKeys() const override;

Expand Down
64 changes: 44 additions & 20 deletions src/wallet/wallet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1477,7 +1477,7 @@ bool CWallet::CanGetAddresses(bool internal) const
{
LOCK(cs_wallet);
if (m_spk_managers.empty()) return false;
auto spk_man = GetScriptPubKeyMan(internal);
auto spk_man = GetScriptPubKeyMan(internal ? InternalKey::Internal : InternalKey::External);
if (spk_man && spk_man->CanGetAddresses(internal)) {
return true;
}
Expand Down Expand Up @@ -2354,7 +2354,7 @@ bool CWallet::TopUpKeyPool(unsigned int kpSize)
util::Result<CTxDestination> CWallet::GetNewDestination(const std::string label)
{
LOCK(cs_wallet);
auto spk_man = GetScriptPubKeyMan(false /* internal */);
auto spk_man = GetScriptPubKeyMan(InternalKey::External);
if (!spk_man) {
return util::Error{_("Error: No addresses available.")};
}
Expand Down Expand Up @@ -2447,7 +2447,7 @@ std::set<std::string> CWallet::ListAddrBookLabels(const std::string& purpose) co

util::Result<CTxDestination> ReserveDestination::GetReservedDestination(bool fInternalIn)
{
m_spk_man = pwallet->GetScriptPubKeyMan(fInternalIn);
m_spk_man = pwallet->GetScriptPubKeyMan(fInternalIn ? InternalKey::Internal : InternalKey::External);
if (!m_spk_man) {
return util::Error{_("Error: No addresses available.")};
}
Expand Down Expand Up @@ -3638,7 +3638,7 @@ bool CWallet::Unlock(const CKeyingMaterial& vMasterKeyIn, bool fForMixingOnly, b
std::set<ScriptPubKeyMan*> CWallet::GetActiveScriptPubKeyMans() const
{
std::set<ScriptPubKeyMan*> spk_mans;
for (bool internal : {false, true}) {
for (auto internal : {InternalKey::Internal, InternalKey::External, InternalKey::CoinJoin}) {
auto spk_man = GetScriptPubKeyMan(internal);
if (spk_man) {
spk_mans.insert(spk_man);
Expand All @@ -3656,13 +3656,18 @@ std::set<ScriptPubKeyMan*> CWallet::GetAllScriptPubKeyMans() const
return spk_mans;
}

ScriptPubKeyMan* CWallet::GetScriptPubKeyMan(bool internal) const
ScriptPubKeyMan* CWallet::GetScriptPubKeyMan(InternalKey internal) const
{
const auto spk_manager = internal ? m_internal_spk_managers : m_external_spk_managers;
if (spk_manager == nullptr) {
return nullptr;
}
return spk_manager;
switch (internal)
{
case InternalKey::Internal:
return m_internal_spk_managers;
case InternalKey::External:
return m_external_spk_managers;
case InternalKey::CoinJoin:
return m_coinjoin_spk_managers;
} // no default to let compiler warn us
return nullptr;
}

std::set<ScriptPubKeyMan*> CWallet::GetScriptPubKeyMans(const CScript& script, SignatureData& sigdata) const
Expand Down Expand Up @@ -3787,7 +3792,7 @@ void CWallet::SetupDescriptorScriptPubKeyMans(const SecureString& mnemonic_arg,
CExtKey master_key;
master_key.SetSeed(MakeByteSpan(seed_key));

for (bool internal : {false, true}) {
for (auto internal : {InternalKey::External, InternalKey::Internal, InternalKey::CoinJoin}) {
{ // OUTPUT_TYPE is only one: LEGACY
auto spk_manager = std::unique_ptr<DescriptorScriptPubKeyMan>(new DescriptorScriptPubKeyMan(*this));
if (IsCrypted()) {
Expand All @@ -3806,7 +3811,7 @@ void CWallet::SetupDescriptorScriptPubKeyMans(const SecureString& mnemonic_arg,
}
}

void CWallet::AddActiveScriptPubKeyMan(uint256 id, bool internal)
void CWallet::AddActiveScriptPubKeyMan(uint256 id, InternalKey internal)
{
WalletBatch batch(GetDatabase());
if (!batch.WriteActiveScriptPubKeyMan(id, internal)) {
Expand All @@ -3815,29 +3820,48 @@ void CWallet::AddActiveScriptPubKeyMan(uint256 id, bool internal)
LoadActiveScriptPubKeyMan(id, internal);
}

void CWallet::LoadActiveScriptPubKeyMan(uint256 id, bool internal)
void CWallet::LoadActiveScriptPubKeyMan(uint256 id, InternalKey internal)
{
// Activating ScriptPubKeyManager for a given output and change type is incompatible with legacy wallets.
// Legacy wallets have only one ScriptPubKeyManager and it's active for all output and change types.
Assert(IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS));

WalletLogPrintf("Setting spkMan to active: id = %s, type = %s, internal = %s\n", id.ToString(), FormatOutputType(OutputType::LEGACY), internal ? "true" : "false");
auto& spk_mans = internal ? m_internal_spk_managers : m_external_spk_managers;
auto& spk_mans_other = internal ? m_external_spk_managers : m_internal_spk_managers;
WalletLogPrintf("Setting spkMan to active: id = %s, type = %s, internal = %s\n", id.ToString(), FormatOutputType(OutputType::LEGACY), internal == InternalKey::Internal ? "true" : "false");

auto spk_man = m_spk_managers.at(id).get();
spk_mans = spk_man;
switch (internal) {
case InternalKey::Internal:
m_internal_spk_managers = spk_man;
break;

if (spk_mans_other == spk_man) {
spk_mans_other = nullptr;
case InternalKey::External:
m_external_spk_managers = spk_man;
break;
case InternalKey::CoinJoin:
m_coinjoin_spk_managers = spk_man;
break;
}

// no default case to let compiler hint it
if (internal != InternalKey::Internal && m_internal_spk_managers == spk_man) {
m_internal_spk_managers = nullptr;
}

if (internal != InternalKey::External && m_external_spk_managers == spk_man) {
m_external_spk_managers = nullptr;
}
if (internal != InternalKey::CoinJoin && m_coinjoin_spk_managers == spk_man) {
m_coinjoin_spk_managers = nullptr;
}

NotifyCanGetAddressesChanged();

}

// TODO: probably need to support InternalKey here
void CWallet::DeactivateScriptPubKeyMan(uint256 id, bool internal)
{
auto spk_man = GetScriptPubKeyMan(internal);
auto spk_man = GetScriptPubKeyMan(internal ? InternalKey::Internal : InternalKey::External);
if (spk_man != nullptr && spk_man->GetID() == id) {
WalletLogPrintf("Deactivate spkMan: id = %s, type = %s, internal = %s\n", id.ToString(), FormatOutputType(OutputType::LEGACY), internal ? "true" : "false");
WalletBatch batch(GetDatabase());
Expand Down
7 changes: 4 additions & 3 deletions src/wallet/wallet.h
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,7 @@ class CWallet final : public WalletStorage, public interfaces::Chain::Notificati

ScriptPubKeyMan* m_external_spk_managers{nullptr};
ScriptPubKeyMan* m_internal_spk_managers{nullptr};
ScriptPubKeyMan* m_coinjoin_spk_managers{nullptr};

// Indexed by a unique identifier produced by each ScriptPubKeyMan using
// ScriptPubKeyMan::GetID. In many cases it will be the hash of an internal structure
Expand Down Expand Up @@ -984,7 +985,7 @@ class CWallet final : public WalletStorage, public interfaces::Chain::Notificati
std::set<ScriptPubKeyMan*> GetAllScriptPubKeyMans() const;

//! Get the ScriptPubKeyMan for internal/external chain.
ScriptPubKeyMan* GetScriptPubKeyMan(bool internal) const;
ScriptPubKeyMan* GetScriptPubKeyMan(InternalKey internal) const;

//! Get the ScriptPubKeyMan for a script
ScriptPubKeyMan* GetScriptPubKeyMan(const CScript& script) const;
Expand Down Expand Up @@ -1039,12 +1040,12 @@ class CWallet final : public WalletStorage, public interfaces::Chain::Notificati
//! 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] internal Whether this ScriptPubKeyMan provides change addresses
void AddActiveScriptPubKeyMan(uint256 id, bool internal);
void AddActiveScriptPubKeyMan(uint256 id, InternalKey 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] internal Whether this ScriptPubKeyMan provides change addresses
void LoadActiveScriptPubKeyMan(uint256 id, bool internal);
void LoadActiveScriptPubKeyMan(uint256 id, InternalKey internal);

//! Remove specified ScriptPubKeyMan from set of active SPK managers. Writes the change to the wallet file.
//! @param[in] id The unique id for the ScriptPubKeyMan
Expand Down
32 changes: 26 additions & 6 deletions src/wallet/walletdb.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ namespace DBKeys {
const std::string ACENTRY{"acentry"};
const std::string ACTIVEEXTERNALSPK{"activeexternalspk"};
const std::string ACTIVEINTERNALSPK{"activeinternalspk"};
const std::string ACTIVECOINJOINSPK{"activecoinjoinspk"};
const std::string BESTBLOCK_NOMERKLE{"bestblock_nomerkle"};
const std::string BESTBLOCK{"bestblock"};
const std::string CRYPTED_KEY{"ckey"};
Expand Down Expand Up @@ -230,9 +231,23 @@ bool WalletBatch::WriteGovernanceObject(const Governance::Object& obj)
return WriteIC(std::make_pair(DBKeys::G_OBJECT, obj.GetHash()), obj, false);
}

bool WalletBatch::WriteActiveScriptPubKeyMan(const uint256& id, bool internal)
bool WalletBatch::WriteActiveScriptPubKeyMan(const uint256& id, InternalKey internal)
{
std::string key = internal ? DBKeys::ACTIVEINTERNALSPK : DBKeys::ACTIVEEXTERNALSPK;
std::string key;
switch (internal) {
case InternalKey::Internal:
key = DBKeys::ACTIVEINTERNALSPK;
break;
case InternalKey::External:
key = DBKeys::ACTIVEEXTERNALSPK;
break;
case InternalKey::CoinJoin:
key = DBKeys::ACTIVECOINJOINSPK;
break;
}
// no default to get a hint from a compiler
assert(!key.empty());

return WriteIC(key, id);
}

Expand Down Expand Up @@ -333,6 +348,7 @@ class CWalletScanState {
std::vector<uint256> vWalletUpgrade;
std::map<OutputType, uint256> m_active_external_spks;
std::map<OutputType, uint256> m_active_internal_spks;
std::map<OutputType, uint256> m_active_coinjoin_spks;
std::map<uint256, DescriptorCache> m_descriptor_caches;
std::map<std::pair<uint256, CKeyID>, CKey> m_descriptor_keys;
std::map<std::pair<uint256, CKeyID>, std::pair<CPubKey, std::vector<unsigned char>>> m_descriptor_crypt_keys;
Expand Down Expand Up @@ -614,12 +630,13 @@ ReadKeyValue(CWallet* pwallet, CDataStream& ssKey, CDataStream& ssValue,
} else if (strType == DBKeys::OLD_KEY) {
strErr = "Found unsupported 'wkey' record, try loading with version 0.17";
return false;
} else if (strType == DBKeys::ACTIVEEXTERNALSPK || strType == DBKeys::ACTIVEINTERNALSPK) {
} else if (strType == DBKeys::ACTIVEEXTERNALSPK || strType == DBKeys::ACTIVEINTERNALSPK || strType == DBKeys::ACTIVEEXTERNALSPK) {
uint256 id;
ssValue >> id;

bool internal = strType == DBKeys::ACTIVEINTERNALSPK;
auto& spk_mans = internal ? wss.m_active_internal_spks : wss.m_active_external_spks;
bool coinjoin = strType == DBKeys::ACTIVECOINJOINSPK;
auto& spk_mans = internal ? wss.m_active_internal_spks : (coinjoin ? wss.m_active_coinjoin_spks : wss.m_active_external_spks);
const OutputType type = OutputType::LEGACY;
if (spk_mans.count(static_cast<OutputType>(type)) > 0) {
strErr = "Multiple ScriptPubKeyMans specified for a single type";
Expand Down Expand Up @@ -878,10 +895,13 @@ DBErrors WalletBatch::LoadWallet(CWallet* pwallet)

// Set the active ScriptPubKeyMans
for (auto spk_man : wss.m_active_external_spks) {
pwallet->LoadActiveScriptPubKeyMan(spk_man.second, /* internal */ false);
pwallet->LoadActiveScriptPubKeyMan(spk_man.second, InternalKey::External);
}
for (auto spk_man : wss.m_active_internal_spks) {
pwallet->LoadActiveScriptPubKeyMan(spk_man.second, /* internal */ true);
pwallet->LoadActiveScriptPubKeyMan(spk_man.second, InternalKey::Internal);
}
for (auto spk_man : wss.m_active_coinjoin_spks) {
pwallet->LoadActiveScriptPubKeyMan(spk_man.second, InternalKey::CoinJoin);
}

// Set the descriptor caches
Expand Down
5 changes: 3 additions & 2 deletions src/wallet/walletdb.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ class CMasterKey;
class CWallet;
class CWalletTx;
struct WalletContext;

enum class InternalKey;
/**
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

Forward-declared scoped enum used by value — specify underlying type or include the definition.

enum class InternalKey; is incomplete here and is used by value in a function declaration below; this can fail to compile unless the underlying type is known. Add : int (matches the default for scoped enums) or include the defining header.

-enum class InternalKey;
+enum class InternalKey : int;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
enum class InternalKey;
/**
enum class InternalKey : int;
/**
🤖 Prompt for AI Agents
In src/wallet/walletdb.h around lines 34-35, the forward declaration "enum class
InternalKey;" is insufficient because the scoped enum is used by value later;
either change the forward declaration to specify the underlying type (e.g.,
"enum class InternalKey : int;") so the size is known, or replace the forward
declaration by including the header that defines InternalKey; update the line
accordingly and ensure any include guards/imports remain correct.

* Overview of wallet database classes:
*
Expand Down Expand Up @@ -61,6 +61,7 @@ namespace DBKeys {
extern const std::string ACENTRY;
extern const std::string ACTIVEEXTERNALSPK;
extern const std::string ACTIVEINTERNALSPK;
extern const std::string ACTIVECOINJOINSPK;
extern const std::string BESTBLOCK;
extern const std::string BESTBLOCK_NOMERKLE;
extern const std::string CRYPTED_HDCHAIN;
Expand Down Expand Up @@ -229,7 +230,7 @@ class WalletBatch
/// Erase destination data tuple from wallet database
bool EraseDestData(const std::string &address, const std::string &key);

bool WriteActiveScriptPubKeyMan(const uint256& id, bool internal);
bool WriteActiveScriptPubKeyMan(const uint256& id, InternalKey internal);
bool EraseActiveScriptPubKeyMan(bool internal);

Comment on lines 233 to 235
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

API inconsistency: EraseActiveScriptPubKeyMan still takes bool; cannot target CoinJoin.

Write-path now supports External/Internal/CoinJoin, but erase-path can only address a boolean (internal/external). This risks leaving stale ACTIVECOINJOINSPK entries.

-    bool WriteActiveScriptPubKeyMan(const uint256& id, InternalKey internal);
-    bool EraseActiveScriptPubKeyMan(bool internal);
+    bool WriteActiveScriptPubKeyMan(const uint256& id, InternalKey internal);
+    bool EraseActiveScriptPubKeyMan(InternalKey internal);

Outside this file (walletdb.cpp), mirror the switch used in WriteActiveScriptPubKeyMan:

bool WalletBatch::EraseActiveScriptPubKeyMan(InternalKey internal)
{
    std::string key;
    switch (internal) {
    case InternalKey::Internal: key = DBKeys::ACTIVEINTERNALSPK; break;
    case InternalKey::External: key = DBKeys::ACTIVEEXTERNALSPK; break;
    case InternalKey::CoinJoin: key = DBKeys::ACTIVECOINJOINSPK; break;
    }
    assert(!key.empty());
    return EraseIC(key);
}

🏁 Script executed:

#!/bin/bash
# Find erase callsites and confirm no assumptions on bool survive.
rg -n "EraseActiveScriptPubKeyMan\\(" -g src/wallet
rg -n "ACTIVECOINJOINSPK" -g src/wallet

Length of output: 390


🏁 Script executed:

#!/bin/bash
# Search for EraseActiveScriptPubKeyMan definitions and callsites across the repo
rg -n "EraseActiveScriptPubKeyMan\(" -C3 .

# Search for WriteActiveScriptPubKeyMan definitions and callsites across the repo
rg -n "WriteActiveScriptPubKeyMan\(" -C3 .

# Search for the CoinJoin key usage
rg -n "ACTIVECOINJOINSPK" -C3 .

Length of output: 5259


Refactor EraseActiveScriptPubKeyMan to use InternalKey
Signature in src/wallet/walletdb.h (line 234) and definition in src/wallet/walletdb.cpp (line 254) must accept InternalKey internal instead of bool internal; replicate the switch(internal) from WriteActiveScriptPubKeyMan to handle InternalKey::CoinJoin (DBKeys::ACTIVECOINJOINSPK) as well as External/Internal. Update the callsite in src/wallet/wallet.cpp (around line 3855) to pass the enum value rather than a bool, ensuring proper removal of coinjoin entries.

🤖 Prompt for AI Agents
In src/wallet/walletdb.h around lines 233-235, change the prototype of
EraseActiveScriptPubKeyMan to accept InternalKey internal (not bool) so it
matches the implementation; in src/wallet/walletdb.cpp around line 254, update
the function to switch(on internal) like WriteActiveScriptPubKeyMan and handle
InternalKey::CoinJoin by erasing DBKeys::ACTIVECOINJOINSPK in addition to
External/Internal keys; then update the callsite in src/wallet/wallet.cpp near
line 3855 to pass the appropriate InternalKey enum value instead of a bool so
CoinJoin entries are removed correctly (also ensure any needed includes or
forward declarations for InternalKey are present).

DBErrors LoadWallet(CWallet* pwallet);
Expand Down
3 changes: 2 additions & 1 deletion test/functional/tool_wallet.py
Original file line number Diff line number Diff line change
Expand Up @@ -266,7 +266,8 @@ def test_tool_wallet_create_on_existing_wallet(self):
shasum_before = self.wallet_shasum()
timestamp_before = self.wallet_timestamp()
self.log.debug('Wallet file timestamp before calling create: {}'.format(timestamp_before))
out = "Topping up keypool...\n" + self.get_expected_info_output(name="foo", keypool=2000)
keypool_size = 3000 if self.options.descriptors else 2000
out = "Topping up keypool...\n" + self.get_expected_info_output(name="foo", keypool=keypool_size)
self.assert_tool_output(out, '-wallet=foo', 'create')
shasum_after = self.wallet_shasum()
timestamp_after = self.wallet_timestamp()
Expand Down
3 changes: 2 additions & 1 deletion test/functional/wallet_createwallet.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,9 +152,10 @@ def run_test(self):
# There should only be 1 key for legacy, 1 for descriptors (dash has only one type of addresses)
walletinfo = w6.getwalletinfo()
keys = 1 if self.options.descriptors else 1
cj_keys = 1 if self.options.descriptors else 0
assert_equal(walletinfo['keypoolsize'], keys)
# hd_internals are not refilled by default for descriptor wallets atm
assert_equal(walletinfo['keypoolsize_hd_internal'], keys)
assert_equal(walletinfo['keypoolsize_hd_internal'], keys + cj_keys)
# Allow empty passphrase, but there should be a warning
resp = self.nodes[0].createwallet(wallet_name='w7', disable_private_keys=False, blank=False, passphrase='')
assert 'Empty string given as passphrase, wallet will not be encrypted.' in resp['warning']
Expand Down
Loading
Loading