aboutsummaryrefslogtreecommitdiff
path: root/src/wallet
diff options
context:
space:
mode:
authorS3RK <1466284+S3RK@users.noreply.github.com>2021-06-28 21:37:37 +0200
committerS3RK <1466284+S3RK@users.noreply.github.com>2021-06-28 21:37:37 +0200
commitbf68ebc1cd555f791103f81adc9111e0e55c8003 (patch)
treeafbc1236be46e64d0cbaf91df75e14d5445f5397 /src/wallet
parent8cdf91735f2bdc55577d84a9915f5920ce23b00a (diff)
downloadbitcoin-bf68ebc1cd555f791103f81adc9111e0e55c8003.tar.xz
wallet: allow to import same descriptor twice
Diffstat (limited to 'src/wallet')
-rw-r--r--src/wallet/rpcdump.cpp5
-rw-r--r--src/wallet/scriptpubkeyman.cpp40
-rw-r--r--src/wallet/scriptpubkeyman.h2
-rw-r--r--src/wallet/wallet.cpp48
4 files changed, 57 insertions, 38 deletions
diff --git a/src/wallet/rpcdump.cpp b/src/wallet/rpcdump.cpp
index 35649ab02c..3ae36131cc 100644
--- a/src/wallet/rpcdump.cpp
+++ b/src/wallet/rpcdump.cpp
@@ -1566,9 +1566,8 @@ static UniValue ProcessDescriptorImport(CWallet& wallet, const UniValue& data, c
// Check if the wallet already contains the descriptor
auto existing_spk_manager = wallet.GetDescriptorScriptPubKeyMan(w_desc);
if (existing_spk_manager) {
- LOCK(existing_spk_manager->cs_desc_man);
- if (range_start > existing_spk_manager->GetWalletDescriptor().range_start) {
- throw JSONRPCError(RPC_INVALID_PARAMS, strprintf("range_start can only decrease; current range = [%d,%d]", existing_spk_manager->GetWalletDescriptor().range_start, existing_spk_manager->GetWalletDescriptor().range_end));
+ if (!existing_spk_manager->CanUpdateToWalletDescriptor(w_desc, error)) {
+ throw JSONRPCError(RPC_INVALID_PARAMETER, error);
}
}
diff --git a/src/wallet/scriptpubkeyman.cpp b/src/wallet/scriptpubkeyman.cpp
index 44c3912544..8b397fa1f3 100644
--- a/src/wallet/scriptpubkeyman.cpp
+++ b/src/wallet/scriptpubkeyman.cpp
@@ -1875,6 +1875,12 @@ bool DescriptorScriptPubKeyMan::AddDescriptorKeyWithDB(WalletBatch& batch, const
AssertLockHeld(cs_desc_man);
assert(!m_storage.IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS));
+ // Check if provided key already exists
+ if (m_map_keys.find(pubkey.GetID()) != m_map_keys.end() ||
+ m_map_crypted_keys.find(pubkey.GetID()) != m_map_crypted_keys.end()) {
+ return true;
+ }
+
if (m_storage.HasEncryptionKeys()) {
if (m_storage.IsLocked()) {
return false;
@@ -2302,3 +2308,37 @@ bool DescriptorScriptPubKeyMan::GetDescriptorString(std::string& out, bool priv)
return m_wallet_descriptor.descriptor->ToNormalizedString(provider, out, priv);
}
+
+void DescriptorScriptPubKeyMan::UpdateWalletDescriptor(WalletDescriptor& descriptor)
+{
+ LOCK(cs_desc_man);
+ std::string error;
+ if (!CanUpdateToWalletDescriptor(descriptor, error)) {
+ throw std::runtime_error(std::string(__func__) + ": " + error);
+ }
+
+ m_map_pubkeys.clear();
+ m_map_script_pub_keys.clear();
+ m_max_cached_index = -1;
+ m_wallet_descriptor = descriptor;
+}
+
+bool DescriptorScriptPubKeyMan::CanUpdateToWalletDescriptor(const WalletDescriptor& descriptor, std::string& error)
+{
+ LOCK(cs_desc_man);
+ if (!HasWalletDescriptor(descriptor)) {
+ error = "can only update matching descriptor";
+ return false;
+ }
+
+ if (descriptor.range_start > m_wallet_descriptor.range_start ||
+ descriptor.range_end < m_wallet_descriptor.range_end) {
+ // Use inclusive range for error
+ error = strprintf("new range must include current range = [%d,%d]",
+ m_wallet_descriptor.range_start,
+ m_wallet_descriptor.range_end - 1);
+ return false;
+ }
+
+ return true;
+}
diff --git a/src/wallet/scriptpubkeyman.h b/src/wallet/scriptpubkeyman.h
index b2ca354b0a..f2d1d87d55 100644
--- a/src/wallet/scriptpubkeyman.h
+++ b/src/wallet/scriptpubkeyman.h
@@ -624,6 +624,8 @@ public:
bool AddCryptedKey(const CKeyID& key_id, const CPubKey& pubkey, const std::vector<unsigned char>& crypted_key);
bool HasWalletDescriptor(const WalletDescriptor& desc) const;
+ void UpdateWalletDescriptor(WalletDescriptor& descriptor);
+ bool CanUpdateToWalletDescriptor(const WalletDescriptor& descriptor, std::string& error);
void AddDescriptorKey(const CKey& key, const CPubKey &pubkey);
void WriteDescriptor();
diff --git a/src/wallet/wallet.cpp b/src/wallet/wallet.cpp
index c2586b60b8..8750f508a7 100644
--- a/src/wallet/wallet.cpp
+++ b/src/wallet/wallet.cpp
@@ -3192,44 +3192,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;
}
@@ -3237,7 +3219,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;
@@ -3249,12 +3231,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;
}