aboutsummaryrefslogtreecommitdiff
path: root/src/wallet/wallet.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/wallet/wallet.cpp')
-rw-r--r--src/wallet/wallet.cpp268
1 files changed, 152 insertions, 116 deletions
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index 4b6630de3c..e6227048d2 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -8,6 +8,7 @@
#include <chain.h>
#include <consensus/consensus.h>
#include <consensus/validation.h>
+#include <external_signer.h>
#include <fs.h>
#include <interfaces/chain.h>
#include <interfaces/wallet.h>
@@ -93,6 +94,16 @@ static void UpdateWalletSetting(interfaces::Chain& chain,
}
}
+/**
+ * Refresh mempool status so the wallet is in an internally consistent state and
+ * immediately knows the transaction's status: Whether it can be considered
+ * trusted and is eligible to be abandoned ...
+ */
+static void RefreshMempoolStatus(CWalletTx& tx, interfaces::Chain& chain)
+{
+ tx.fInMempool = chain.isInMempool(tx.GetHash());
+}
+
bool AddWallet(const std::shared_ptr<CWallet>& wallet)
{
LOCK(cs_wallets);
@@ -373,6 +384,19 @@ void CWallet::UpgradeKeyMetadata()
SetWalletFlag(WALLET_FLAG_KEY_ORIGIN_METADATA);
}
+void CWallet::UpgradeDescriptorCache()
+{
+ if (!IsWalletFlagSet(WALLET_FLAG_DESCRIPTORS) || IsLocked() || IsWalletFlagSet(WALLET_FLAG_LAST_HARDENED_XPUB_CACHED)) {
+ return;
+ }
+
+ for (ScriptPubKeyMan* spkm : GetAllScriptPubKeyMans()) {
+ DescriptorScriptPubKeyMan* desc_spkm = dynamic_cast<DescriptorScriptPubKeyMan*>(spkm);
+ desc_spkm->UpgradeDescriptorCache();
+ }
+ SetWalletFlag(WALLET_FLAG_LAST_HARDENED_XPUB_CACHED);
+}
+
bool CWallet::Unlock(const SecureString& strWalletPassphrase, bool accept_no_keys)
{
CCrypter crypter;
@@ -389,6 +413,8 @@ bool CWallet::Unlock(const SecureString& strWalletPassphrase, bool accept_no_key
if (Unlock(_vMasterKey, accept_no_keys)) {
// Now that we've unlocked, upgrade the key metadata
UpgradeKeyMetadata();
+ // Now that we've unlocked, upgrade the descriptor cache
+ UpgradeDescriptorCache();
return true;
}
}
@@ -787,10 +813,7 @@ bool CWallet::MarkReplaced(const uint256& originalHash, const uint256& newHash)
wtx.mapValue["replaced_by_txid"] = newHash.ToString();
// Refresh mempool status without waiting for transactionRemovedFromMempool
- // notification so the wallet is in an internally consistent state and
- // immediately knows the old transaction should not be considered trusted
- // and is eligible to be abandoned
- wtx.fInMempool = chain().isInMempool(originalHash);
+ RefreshMempoolStatus(wtx, chain());
WalletBatch batch(GetDatabase());
@@ -800,7 +823,7 @@ bool CWallet::MarkReplaced(const uint256& originalHash, const uint256& newHash)
success = false;
}
- NotifyTransactionChanged(this, originalHash, CT_UPDATED);
+ NotifyTransactionChanged(originalHash, CT_UPDATED);
return success;
}
@@ -929,7 +952,7 @@ CWalletTx* CWallet::AddToWallet(CTransactionRef tx, const CWalletTx::Confirmatio
wtx.MarkDirty();
// Notify UI of new or updated transaction
- NotifyTransactionChanged(this, hash, fInsertedNew ? CT_NEW : CT_UPDATED);
+ NotifyTransactionChanged(hash, fInsertedNew ? CT_NEW : CT_UPDATED);
#if HAVE_SYSTEM
// notify an external script when a wallet transaction comes in or is updated
@@ -1103,7 +1126,7 @@ bool CWallet::AbandonTransaction(const uint256& hashTx)
wtx.setAbandoned();
wtx.MarkDirty();
batch.WriteTx(wtx);
- NotifyTransactionChanged(this, wtx.GetHash(), CT_UPDATED);
+ NotifyTransactionChanged(wtx.GetHash(), CT_UPDATED);
// Iterate over all its outputs, and mark transactions in the wallet that spend them abandoned too
TxSpends::const_iterator iter = mapTxSpends.lower_bound(COutPoint(now, 0));
while (iter != mapTxSpends.end() && iter->first.hash == now) {
@@ -1190,7 +1213,7 @@ void CWallet::transactionAddedToMempool(const CTransactionRef& tx, uint64_t memp
auto it = mapWallet.find(tx->GetHash());
if (it != mapWallet.end()) {
- it->second.fInMempool = true;
+ RefreshMempoolStatus(it->second, chain());
}
}
@@ -1198,7 +1221,7 @@ void CWallet::transactionRemovedFromMempool(const CTransactionRef& tx, MemPoolRe
LOCK(cs_wallet);
auto it = mapWallet.find(tx->GetHash());
if (it != mapWallet.end()) {
- it->second.fInMempool = false;
+ RefreshMempoolStatus(it->second, chain());
}
// Handle transactions that were removed from the mempool because they
// conflict with transactions in a newly connected block.
@@ -1806,11 +1829,11 @@ bool CWallet::SignTransaction(CMutableTransaction& tx) const
const CWalletTx& wtx = mi->second;
coins[input.prevout] = Coin(wtx.tx->vout[input.prevout.n], wtx.m_confirm.block_height, wtx.IsCoinBase());
}
- std::map<int, std::string> input_errors;
- return SignTransaction(tx, coins, SIGHASH_ALL, input_errors);
+ std::map<int, bilingual_str> input_errors;
+ return SignTransaction(tx, coins, SIGHASH_DEFAULT, input_errors);
}
-bool CWallet::SignTransaction(CMutableTransaction& tx, const std::map<COutPoint, Coin>& coins, int sighash, std::map<int, std::string>& input_errors) const
+bool CWallet::SignTransaction(CMutableTransaction& tx, const std::map<COutPoint, Coin>& coins, int sighash, std::map<int, bilingual_str>& input_errors) const
{
// Try to sign with all ScriptPubKeyMans
for (ScriptPubKeyMan* spk_man : GetAllScriptPubKeyMans()) {
@@ -1830,6 +1853,7 @@ TransactionError CWallet::FillPSBT(PartiallySignedTransaction& psbtx, bool& comp
if (n_signed) {
*n_signed = 0;
}
+ const PrecomputedTransactionData txdata = PrecomputePSBTData(psbtx);
LOCK(cs_wallet);
// Get all of the previous transactions
for (unsigned int i = 0; i < psbtx.tx->vin.size(); ++i) {
@@ -1856,7 +1880,7 @@ TransactionError CWallet::FillPSBT(PartiallySignedTransaction& psbtx, bool& comp
// Fill in information from ScriptPubKeyMans
for (ScriptPubKeyMan* spk_man : GetAllScriptPubKeyMans()) {
int n_signed_this_spkm = 0;
- TransactionError res = spk_man->FillPSBT(psbtx, sighash_type, sign, bip32derivs, &n_signed_this_spkm);
+ TransactionError res = spk_man->FillPSBT(psbtx, txdata, sighash_type, sign, bip32derivs, &n_signed_this_spkm);
if (res != TransactionError::OK) {
return res;
}
@@ -1907,7 +1931,13 @@ OutputType CWallet::TransactionChangeType(const std::optional<OutputType>& chang
int witnessversion = 0;
std::vector<unsigned char> witnessprogram;
if (recipient.scriptPubKey.IsWitnessProgram(witnessversion, witnessprogram)) {
- return OutputType::BECH32;
+ if (GetScriptPubKeyMan(OutputType::BECH32M, true)) {
+ return OutputType::BECH32M;
+ } else if (GetScriptPubKeyMan(OutputType::BECH32, true)) {
+ return OutputType::BECH32;
+ } else {
+ return m_default_address_type;
+ }
}
}
@@ -1936,7 +1966,7 @@ void CWallet::CommitTransaction(CTransactionRef tx, mapValue_t mapValue, std::ve
for (const CTxIn& txin : tx->vin) {
CWalletTx &coin = mapWallet.at(txin.prevout.hash);
coin.MarkDirty();
- NotifyTransactionChanged(this, coin.GetHash(), CT_UPDATED);
+ NotifyTransactionChanged(coin.GetHash(), CT_UPDATED);
}
// Get the inserted-CWalletTx from mapWallet so that the
@@ -1991,7 +2021,7 @@ DBErrors CWallet::ZapSelectTx(std::vector<uint256>& vHashIn, std::vector<uint256
for (const auto& txin : it->second.tx->vin)
mapTxSpends.erase(txin.prevout);
mapWallet.erase(it);
- NotifyTransactionChanged(this, hash, CT_DELETED);
+ NotifyTransactionChanged(hash, CT_DELETED);
}
if (nZapSelectTxRet == DBErrors::NEED_REWRITE)
@@ -2025,8 +2055,8 @@ bool CWallet::SetAddressBookWithDB(WalletBatch& batch, const CTxDestination& add
m_address_book[address].purpose = strPurpose;
is_mine = IsMine(address) != ISMINE_NO;
}
- NotifyAddressBookChanged(this, address, strName, is_mine,
- strPurpose, (fUpdated ? CT_UPDATED : CT_NEW) );
+ NotifyAddressBookChanged(address, strName, is_mine,
+ strPurpose, (fUpdated ? CT_UPDATED : CT_NEW));
if (!strPurpose.empty() && !batch.WritePurpose(EncodeDestination(address), strPurpose))
return false;
return batch.WriteName(EncodeDestination(address), strName);
@@ -2061,7 +2091,7 @@ bool CWallet::DelAddressBook(const CTxDestination& address)
is_mine = IsMine(address) != ISMINE_NO;
}
- NotifyAddressBookChanged(this, address, "", is_mine, "", CT_DELETED);
+ NotifyAddressBookChanged(address, "", is_mine, "", CT_DELETED);
batch.ErasePurpose(EncodeDestination(address));
return batch.EraseName(EncodeDestination(address));
@@ -2071,9 +2101,14 @@ size_t CWallet::KeypoolCountExternalKeys() const
{
AssertLockHeld(cs_wallet);
+ auto legacy_spk_man = GetLegacyScriptPubKeyMan();
+ if (legacy_spk_man) {
+ return legacy_spk_man->KeypoolCountExternalKeys();
+ }
+
unsigned int count = 0;
- for (auto spk_man : GetActiveScriptPubKeyMans()) {
- count += spk_man->KeypoolCountExternalKeys();
+ for (auto spk_man : m_external_spk_managers) {
+ count += spk_man.second->GetKeyPoolSize();
}
return count;
@@ -2100,7 +2135,7 @@ bool CWallet::TopUpKeyPool(unsigned int kpSize)
return res;
}
-bool CWallet::GetNewDestination(const OutputType type, const std::string label, CTxDestination& dest, std::string& error)
+bool CWallet::GetNewDestination(const OutputType type, const std::string label, CTxDestination& dest, bilingual_str& error)
{
LOCK(cs_wallet);
error.clear();
@@ -2110,7 +2145,7 @@ bool CWallet::GetNewDestination(const OutputType type, const std::string label,
spk_man->TopUp();
result = spk_man->GetNewDestination(type, dest, error);
} else {
- error = strprintf("Error: No %s addresses available.", FormatOutputType(type));
+ error = strprintf(_("Error: No %s addresses available."), FormatOutputType(type));
}
if (result) {
SetAddressBook(dest, label, "receive");
@@ -2119,14 +2154,13 @@ bool CWallet::GetNewDestination(const OutputType type, const std::string label,
return result;
}
-bool CWallet::GetNewChangeDestination(const OutputType type, CTxDestination& dest, std::string& error)
+bool CWallet::GetNewChangeDestination(const OutputType type, CTxDestination& dest, bilingual_str& error)
{
LOCK(cs_wallet);
error.clear();
ReserveDestination reservedest(this, type);
- if (!reservedest.GetReservedDestination(dest, true)) {
- error = _("Error: Keypool ran out, please call keypoolrefill first").translated;
+ if (!reservedest.GetReservedDestination(dest, true, error)) {
return false;
}
@@ -2173,10 +2207,11 @@ std::set<CTxDestination> CWallet::GetLabelAddresses(const std::string& label) co
return result;
}
-bool ReserveDestination::GetReservedDestination(CTxDestination& dest, bool internal)
+bool ReserveDestination::GetReservedDestination(CTxDestination& dest, bool internal, bilingual_str& error)
{
m_spk_man = pwallet->GetScriptPubKeyMan(type, internal);
if (!m_spk_man) {
+ error = strprintf(_("Error: No %s addresses available."), FormatOutputType(type));
return false;
}
@@ -2186,7 +2221,7 @@ bool ReserveDestination::GetReservedDestination(CTxDestination& dest, bool inter
m_spk_man->TopUp();
CKeyPool keypool;
- if (!m_spk_man->GetReservedDestination(type, internal, address, nIndex, keypool)) {
+ if (!m_spk_man->GetReservedDestination(type, internal, address, nIndex, keypool, error)) {
return false;
}
fInternal = keypool.fInternal;
@@ -2215,7 +2250,6 @@ void ReserveDestination::ReturnDestination()
bool CWallet::DisplayAddress(const CTxDestination& dest)
{
-#ifdef ENABLE_EXTERNAL_SIGNER
CScript scriptPubKey = GetScriptForDestination(dest);
const auto spk_man = GetScriptPubKeyMan(scriptPubKey);
if (spk_man == nullptr) {
@@ -2227,9 +2261,6 @@ bool CWallet::DisplayAddress(const CTxDestination& dest)
}
ExternalSigner signer = ExternalSignerScriptPubKeyMan::GetExternalSigner();
return signer_spk_man->DisplayAddress(scriptPubKey, signer);
-#else
- return false;
-#endif
}
void CWallet::LockCoin(const COutPoint& output)
@@ -2274,44 +2305,48 @@ void CWallet::GetKeyBirthTimes(std::map<CKeyID, int64_t>& mapKeyBirth) const {
AssertLockHeld(cs_wallet);
mapKeyBirth.clear();
- LegacyScriptPubKeyMan* spk_man = GetLegacyScriptPubKeyMan();
- assert(spk_man != nullptr);
- LOCK(spk_man->cs_KeyStore);
-
- // get birth times for keys with metadata
- for (const auto& entry : spk_man->mapKeyMetadata) {
- if (entry.second.nCreateTime) {
- mapKeyBirth[entry.first] = entry.second.nCreateTime;
- }
- }
-
// map in which we'll infer heights of other keys
std::map<CKeyID, const CWalletTx::Confirmation*> mapKeyFirstBlock;
CWalletTx::Confirmation max_confirm;
max_confirm.block_height = GetLastBlockHeight() > 144 ? GetLastBlockHeight() - 144 : 0; // the tip can be reorganized; use a 144-block safety margin
CHECK_NONFATAL(chain().findAncestorByHeight(GetLastBlockHash(), max_confirm.block_height, FoundBlock().hash(max_confirm.hashBlock)));
- for (const CKeyID &keyid : spk_man->GetKeys()) {
- if (mapKeyBirth.count(keyid) == 0)
- mapKeyFirstBlock[keyid] = &max_confirm;
- }
- // if there are no such keys, we're done
- if (mapKeyFirstBlock.empty())
- return;
+ {
+ LegacyScriptPubKeyMan* spk_man = GetLegacyScriptPubKeyMan();
+ assert(spk_man != nullptr);
+ LOCK(spk_man->cs_KeyStore);
+
+ // get birth times for keys with metadata
+ for (const auto& entry : spk_man->mapKeyMetadata) {
+ if (entry.second.nCreateTime) {
+ mapKeyBirth[entry.first] = entry.second.nCreateTime;
+ }
+ }
+
+ // Prepare to infer birth heights for keys without metadata
+ for (const CKeyID &keyid : spk_man->GetKeys()) {
+ if (mapKeyBirth.count(keyid) == 0)
+ mapKeyFirstBlock[keyid] = &max_confirm;
+ }
+
+ // if there are no such keys, we're done
+ if (mapKeyFirstBlock.empty())
+ return;
- // find first block that affects those keys, if there are any left
- for (const auto& entry : mapWallet) {
- // iterate over all wallet transactions...
- const CWalletTx &wtx = entry.second;
- if (wtx.m_confirm.status == CWalletTx::CONFIRMED) {
- // ... which are already in a block
- for (const CTxOut &txout : wtx.tx->vout) {
- // iterate over all their outputs
- for (const auto &keyid : GetAffectedKeys(txout.scriptPubKey, *spk_man)) {
- // ... and all their affected keys
- auto rit = mapKeyFirstBlock.find(keyid);
- if (rit != mapKeyFirstBlock.end() && wtx.m_confirm.block_height < rit->second->block_height) {
- rit->second = &wtx.m_confirm;
+ // find first block that affects those keys, if there are any left
+ for (const auto& entry : mapWallet) {
+ // iterate over all wallet transactions...
+ const CWalletTx &wtx = entry.second;
+ if (wtx.m_confirm.status == CWalletTx::CONFIRMED) {
+ // ... which are already in a block
+ for (const CTxOut &txout : wtx.tx->vout) {
+ // iterate over all their outputs
+ for (const auto &keyid : GetAffectedKeys(txout.scriptPubKey, *spk_man)) {
+ // ... and all their affected keys
+ auto rit = mapKeyFirstBlock.find(keyid);
+ if (rit != mapKeyFirstBlock.end() && wtx.m_confirm.block_height < rit->second->block_height) {
+ rit->second = &wtx.m_confirm;
+ }
}
}
}
@@ -2558,19 +2593,21 @@ std::shared_ptr<CWallet> CWallet::Create(interfaces::Chain* chain, const std::st
}
if (!gArgs.GetArg("-addresstype", "").empty()) {
- if (!ParseOutputType(gArgs.GetArg("-addresstype", ""), walletInstance->m_default_address_type)) {
+ std::optional<OutputType> parsed = ParseOutputType(gArgs.GetArg("-addresstype", ""));
+ if (!parsed) {
error = strprintf(_("Unknown address type '%s'"), gArgs.GetArg("-addresstype", ""));
return nullptr;
}
+ walletInstance->m_default_address_type = parsed.value();
}
if (!gArgs.GetArg("-changetype", "").empty()) {
- OutputType out_type;
- if (!ParseOutputType(gArgs.GetArg("-changetype", ""), out_type)) {
+ std::optional<OutputType> parsed = ParseOutputType(gArgs.GetArg("-changetype", ""));
+ if (!parsed) {
error = strprintf(_("Unknown change type '%s'"), gArgs.GetArg("-changetype", ""));
return nullptr;
}
- walletInstance->m_default_change_type = out_type;
+ walletInstance->m_default_change_type = parsed.value();
}
if (gArgs.IsArgSet("-mintxfee")) {
@@ -2958,7 +2995,6 @@ ScriptPubKeyMan* CWallet::GetScriptPubKeyMan(const OutputType& type, bool intern
const std::map<OutputType, ScriptPubKeyMan*>& spk_managers = internal ? m_internal_spk_managers : m_external_spk_managers;
std::map<OutputType, ScriptPubKeyMan*>::const_iterator it = spk_managers.find(type);
if (it == spk_managers.end()) {
- WalletLogPrintf("%s scriptPubKey Manager for output type %d does not exist\n", internal ? "Internal" : "External", static_cast<int>(type));
return nullptr;
}
return it->second;
@@ -3035,7 +3071,7 @@ void CWallet::SetupLegacyScriptPubKeyMan()
}
auto spk_manager = std::unique_ptr<ScriptPubKeyMan>(new LegacyScriptPubKeyMan(*this));
- for (const auto& type : OUTPUT_TYPES) {
+ for (const auto& type : LEGACY_OUTPUT_TYPES) {
m_internal_spk_managers[type] = spk_manager.get();
m_external_spk_managers[type] = spk_manager.get();
}
@@ -3063,12 +3099,8 @@ void CWallet::ConnectScriptPubKeyManNotifiers()
void CWallet::LoadDescriptorScriptPubKeyMan(uint256 id, WalletDescriptor& desc)
{
if (IsWalletFlagSet(WALLET_FLAG_EXTERNAL_SIGNER)) {
-#ifdef ENABLE_EXTERNAL_SIGNER
auto spk_manager = std::unique_ptr<ScriptPubKeyMan>(new ExternalSignerScriptPubKeyMan(*this, desc));
m_spk_managers[id] = std::move(spk_manager);
-#else
- throw std::runtime_error(std::string(__func__) + ": Compiled without external signing support (required for external signing)");
-#endif
} else {
auto spk_manager = std::unique_ptr<ScriptPubKeyMan>(new DescriptorScriptPubKeyMan(*this, desc));
m_spk_managers[id] = std::move(spk_manager);
@@ -3092,7 +3124,12 @@ void CWallet::SetupDescriptorScriptPubKeyMans()
for (bool internal : {false, true}) {
for (OutputType t : OUTPUT_TYPES) {
- auto spk_manager = std::unique_ptr<DescriptorScriptPubKeyMan>(new DescriptorScriptPubKeyMan(*this, internal));
+ if (t == OutputType::BECH32M) {
+ // Skip taproot (bech32m) for now
+ // TODO: Setup taproot (bech32m) descriptors by default
+ continue;
+ }
+ auto spk_manager = std::unique_ptr<DescriptorScriptPubKeyMan>(new DescriptorScriptPubKeyMan(*this));
if (IsCrypted()) {
if (IsLocked()) {
throw std::runtime_error(std::string(__func__) + ": Wallet is locked, cannot setup new descriptors");
@@ -3101,14 +3138,13 @@ void CWallet::SetupDescriptorScriptPubKeyMans()
throw std::runtime_error(std::string(__func__) + ": Could not encrypt new descriptors");
}
}
- spk_manager->SetupDescriptorGeneration(master_key, t);
+ spk_manager->SetupDescriptorGeneration(master_key, t, internal);
uint256 id = spk_manager->GetID();
m_spk_managers[id] = std::move(spk_manager);
AddActiveScriptPubKeyMan(id, t, internal);
}
}
} else {
-#ifdef ENABLE_EXTERNAL_SIGNER
ExternalSigner signer = ExternalSignerScriptPubKeyMan::GetExternalSigner();
// TODO: add account parameter
@@ -3128,16 +3164,13 @@ void CWallet::SetupDescriptorScriptPubKeyMans()
continue;
}
OutputType t = *desc->GetOutputType();
- auto spk_manager = std::unique_ptr<ExternalSignerScriptPubKeyMan>(new ExternalSignerScriptPubKeyMan(*this, internal));
+ auto spk_manager = std::unique_ptr<ExternalSignerScriptPubKeyMan>(new ExternalSignerScriptPubKeyMan(*this));
spk_manager->SetupDescriptor(std::move(desc));
uint256 id = spk_manager->GetID();
m_spk_managers[id] = std::move(spk_manager);
AddActiveScriptPubKeyMan(id, t, internal);
}
}
-#else
- throw std::runtime_error(std::string(__func__) + ": Compiled without external signing support (required for external signing)");
-#endif // ENABLE_EXTERNAL_SIGNER
}
}
@@ -3152,12 +3185,37 @@ void CWallet::AddActiveScriptPubKeyMan(uint256 id, OutputType type, bool interna
void CWallet::LoadActiveScriptPubKeyMan(uint256 id, OutputType type, bool 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 = %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_other = internal ? m_external_spk_managers : m_internal_spk_managers;
auto spk_man = m_spk_managers.at(id).get();
- spk_man->SetInternal(internal);
spk_mans[type] = spk_man;
+ if (spk_mans_other[type] == spk_man) {
+ spk_mans_other.erase(type);
+ }
+
+ NotifyCanGetAddressesChanged();
+}
+
+void CWallet::DeactivateScriptPubKeyMan(uint256 id, OutputType type, bool internal)
+{
+ auto spk_man = GetScriptPubKeyMan(type, internal);
+ if (spk_man != nullptr && spk_man->GetID() == id) {
+ WalletLogPrintf("Deactivate spkMan: id = %s, type = %d, internal = %d\n", id.ToString(), static_cast<int>(type), static_cast<int>(internal));
+ WalletBatch batch(GetDatabase());
+ if (!batch.EraseActiveScriptPubKeyMan(static_cast<uint8_t>(type), internal)) {
+ throw std::runtime_error(std::string(__func__) + ": erasing active ScriptPubKeyMan id failed");
+ }
+
+ auto& spk_mans = internal ? m_internal_spk_managers : m_external_spk_managers;
+ spk_mans.erase(type);
+ }
+
NotifyCanGetAddressesChanged();
}
@@ -3191,44 +3249,26 @@ ScriptPubKeyMan* CWallet::AddWalletDescriptor(WalletDescriptor& desc, const Flat
}
LOCK(cs_wallet);
- auto new_spk_man = std::unique_ptr<DescriptorScriptPubKeyMan>(new DescriptorScriptPubKeyMan(*this, desc));
-
- // If we already have this descriptor, remove it from the maps but add the existing cache to desc
- auto old_spk_man = GetDescriptorScriptPubKeyMan(desc);
- if (old_spk_man) {
+ auto spk_man = GetDescriptorScriptPubKeyMan(desc);
+ if (spk_man) {
WalletLogPrintf("Update existing descriptor: %s\n", desc.descriptor->ToString());
+ spk_man->UpdateWalletDescriptor(desc);
+ } else {
+ auto new_spk_man = std::unique_ptr<DescriptorScriptPubKeyMan>(new DescriptorScriptPubKeyMan(*this, desc));
+ spk_man = new_spk_man.get();
- {
- LOCK(old_spk_man->cs_desc_man);
- new_spk_man->SetCache(old_spk_man->GetWalletDescriptor().cache);
- }
-
- // Remove from maps of active spkMans
- auto old_spk_man_id = old_spk_man->GetID();
- for (bool internal : {false, true}) {
- for (OutputType t : OUTPUT_TYPES) {
- auto active_spk_man = GetScriptPubKeyMan(t, internal);
- if (active_spk_man && active_spk_man->GetID() == old_spk_man_id) {
- if (internal) {
- m_internal_spk_managers.erase(t);
- } else {
- m_external_spk_managers.erase(t);
- }
- break;
- }
- }
- }
- m_spk_managers.erase(old_spk_man_id);
+ // Save the descriptor to memory
+ m_spk_managers[new_spk_man->GetID()] = std::move(new_spk_man);
}
// Add the private keys to the descriptor
for (const auto& entry : signing_provider.keys) {
const CKey& key = entry.second;
- new_spk_man->AddDescriptorKey(key, key.GetPubKey());
+ spk_man->AddDescriptorKey(key, key.GetPubKey());
}
// Top up key pool, the manager will generate new scriptPubKeys internally
- if (!new_spk_man->TopUp()) {
+ if (!spk_man->TopUp()) {
WalletLogPrintf("Could not top up scriptPubKeys\n");
return nullptr;
}
@@ -3236,7 +3276,7 @@ ScriptPubKeyMan* CWallet::AddWalletDescriptor(WalletDescriptor& desc, const Flat
// Apply the label if necessary
// Note: we disable labels for ranged descriptors
if (!desc.descriptor->IsRange()) {
- auto script_pub_keys = new_spk_man->GetScriptPubKeys();
+ auto script_pub_keys = spk_man->GetScriptPubKeys();
if (script_pub_keys.empty()) {
WalletLogPrintf("Could not generate scriptPubKeys (cache is empty)\n");
return nullptr;
@@ -3248,12 +3288,8 @@ ScriptPubKeyMan* CWallet::AddWalletDescriptor(WalletDescriptor& desc, const Flat
}
}
- // Save the descriptor to memory
- auto ret = new_spk_man.get();
- m_spk_managers[new_spk_man->GetID()] = std::move(new_spk_man);
-
// Save the descriptor to DB
- ret->WriteDescriptor();
+ spk_man->WriteDescriptor();
- return ret;
+ return spk_man;
}