Skip to content

Commit bf68ebc

Browse files
committed
wallet: allow to import same descriptor twice
1 parent 8cdf917 commit bf68ebc

File tree

5 files changed

+122
-51
lines changed

5 files changed

+122
-51
lines changed

src/wallet/rpcdump.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1566,9 +1566,8 @@ static UniValue ProcessDescriptorImport(CWallet& wallet, const UniValue& data, c
15661566
// Check if the wallet already contains the descriptor
15671567
auto existing_spk_manager = wallet.GetDescriptorScriptPubKeyMan(w_desc);
15681568
if (existing_spk_manager) {
1569-
LOCK(existing_spk_manager->cs_desc_man);
1570-
if (range_start > existing_spk_manager->GetWalletDescriptor().range_start) {
1571-
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));
1569+
if (!existing_spk_manager->CanUpdateToWalletDescriptor(w_desc, error)) {
1570+
throw JSONRPCError(RPC_INVALID_PARAMETER, error);
15721571
}
15731572
}
15741573

src/wallet/scriptpubkeyman.cpp

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1875,6 +1875,12 @@ bool DescriptorScriptPubKeyMan::AddDescriptorKeyWithDB(WalletBatch& batch, const
18751875
AssertLockHeld(cs_desc_man);
18761876
assert(!m_storage.IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS));
18771877

1878+
// Check if provided key already exists
1879+
if (m_map_keys.find(pubkey.GetID()) != m_map_keys.end() ||
1880+
m_map_crypted_keys.find(pubkey.GetID()) != m_map_crypted_keys.end()) {
1881+
return true;
1882+
}
1883+
18781884
if (m_storage.HasEncryptionKeys()) {
18791885
if (m_storage.IsLocked()) {
18801886
return false;
@@ -2302,3 +2308,37 @@ bool DescriptorScriptPubKeyMan::GetDescriptorString(std::string& out, bool priv)
23022308

23032309
return m_wallet_descriptor.descriptor->ToNormalizedString(provider, out, priv);
23042310
}
2311+
2312+
void DescriptorScriptPubKeyMan::UpdateWalletDescriptor(WalletDescriptor& descriptor)
2313+
{
2314+
LOCK(cs_desc_man);
2315+
std::string error;
2316+
if (!CanUpdateToWalletDescriptor(descriptor, error)) {
2317+
throw std::runtime_error(std::string(__func__) + ": " + error);
2318+
}
2319+
2320+
m_map_pubkeys.clear();
2321+
m_map_script_pub_keys.clear();
2322+
m_max_cached_index = -1;
2323+
m_wallet_descriptor = descriptor;
2324+
}
2325+
2326+
bool DescriptorScriptPubKeyMan::CanUpdateToWalletDescriptor(const WalletDescriptor& descriptor, std::string& error)
2327+
{
2328+
LOCK(cs_desc_man);
2329+
if (!HasWalletDescriptor(descriptor)) {
2330+
error = "can only update matching descriptor";
2331+
return false;
2332+
}
2333+
2334+
if (descriptor.range_start > m_wallet_descriptor.range_start ||
2335+
descriptor.range_end < m_wallet_descriptor.range_end) {
2336+
// Use inclusive range for error
2337+
error = strprintf("new range must include current range = [%d,%d]",
2338+
m_wallet_descriptor.range_start,
2339+
m_wallet_descriptor.range_end - 1);
2340+
return false;
2341+
}
2342+
2343+
return true;
2344+
}

src/wallet/scriptpubkeyman.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -624,6 +624,8 @@ class DescriptorScriptPubKeyMan : public ScriptPubKeyMan
624624
bool AddCryptedKey(const CKeyID& key_id, const CPubKey& pubkey, const std::vector<unsigned char>& crypted_key);
625625

626626
bool HasWalletDescriptor(const WalletDescriptor& desc) const;
627+
void UpdateWalletDescriptor(WalletDescriptor& descriptor);
628+
bool CanUpdateToWalletDescriptor(const WalletDescriptor& descriptor, std::string& error);
627629
void AddDescriptorKey(const CKey& key, const CPubKey &pubkey);
628630
void WriteDescriptor();
629631

src/wallet/wallet.cpp

Lines changed: 13 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -3192,52 +3192,34 @@ ScriptPubKeyMan* CWallet::AddWalletDescriptor(WalletDescriptor& desc, const Flat
31923192
}
31933193

31943194
LOCK(cs_wallet);
3195-
auto new_spk_man = std::unique_ptr<DescriptorScriptPubKeyMan>(new DescriptorScriptPubKeyMan(*this, desc));
3196-
3197-
// If we already have this descriptor, remove it from the maps but add the existing cache to desc
3198-
auto old_spk_man = GetDescriptorScriptPubKeyMan(desc);
3199-
if (old_spk_man) {
3195+
auto spk_man = GetDescriptorScriptPubKeyMan(desc);
3196+
if (spk_man) {
32003197
WalletLogPrintf("Update existing descriptor: %s\n", desc.descriptor->ToString());
3198+
spk_man->UpdateWalletDescriptor(desc);
3199+
} else {
3200+
auto new_spk_man = std::unique_ptr<DescriptorScriptPubKeyMan>(new DescriptorScriptPubKeyMan(*this, desc));
3201+
spk_man = new_spk_man.get();
32013202

3202-
{
3203-
LOCK(old_spk_man->cs_desc_man);
3204-
new_spk_man->SetCache(old_spk_man->GetWalletDescriptor().cache);
3205-
}
3206-
3207-
// Remove from maps of active spkMans
3208-
auto old_spk_man_id = old_spk_man->GetID();
3209-
for (bool internal : {false, true}) {
3210-
for (OutputType t : OUTPUT_TYPES) {
3211-
auto active_spk_man = GetScriptPubKeyMan(t, internal);
3212-
if (active_spk_man && active_spk_man->GetID() == old_spk_man_id) {
3213-
if (internal) {
3214-
m_internal_spk_managers.erase(t);
3215-
} else {
3216-
m_external_spk_managers.erase(t);
3217-
}
3218-
break;
3219-
}
3220-
}
3221-
}
3222-
m_spk_managers.erase(old_spk_man_id);
3203+
// Save the descriptor to memory
3204+
m_spk_managers[new_spk_man->GetID()] = std::move(new_spk_man);
32233205
}
32243206

32253207
// Add the private keys to the descriptor
32263208
for (const auto& entry : signing_provider.keys) {
32273209
const CKey& key = entry.second;
3228-
new_spk_man->AddDescriptorKey(key, key.GetPubKey());
3210+
spk_man->AddDescriptorKey(key, key.GetPubKey());
32293211
}
32303212

32313213
// Top up key pool, the manager will generate new scriptPubKeys internally
3232-
if (!new_spk_man->TopUp()) {
3214+
if (!spk_man->TopUp()) {
32333215
WalletLogPrintf("Could not top up scriptPubKeys\n");
32343216
return nullptr;
32353217
}
32363218

32373219
// Apply the label if necessary
32383220
// Note: we disable labels for ranged descriptors
32393221
if (!desc.descriptor->IsRange()) {
3240-
auto script_pub_keys = new_spk_man->GetScriptPubKeys();
3222+
auto script_pub_keys = spk_man->GetScriptPubKeys();
32413223
if (script_pub_keys.empty()) {
32423224
WalletLogPrintf("Could not generate scriptPubKeys (cache is empty)\n");
32433225
return nullptr;
@@ -3249,12 +3231,8 @@ ScriptPubKeyMan* CWallet::AddWalletDescriptor(WalletDescriptor& desc, const Flat
32493231
}
32503232
}
32513233

3252-
// Save the descriptor to memory
3253-
auto ret = new_spk_man.get();
3254-
m_spk_managers[new_spk_man->GetID()] = std::move(new_spk_man);
3255-
32563234
// Save the descriptor to DB
3257-
ret->WriteDescriptor();
3235+
spk_man->WriteDescriptor();
32583236

3259-
return ret;
3237+
return spk_man;
32603238
}

test/functional/wallet_importdescriptors.py

Lines changed: 65 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -89,17 +89,20 @@ def run_test(self):
8989
# # Test importing of a P2PKH descriptor
9090
key = get_generate_key()
9191
self.log.info("Should import a p2pkh descriptor")
92-
self.test_importdesc({"desc": descsum_create("pkh(" + key.pubkey + ")"),
93-
"timestamp": "now",
94-
"label": "Descriptor import test"},
95-
success=True)
92+
import_request = {"desc": descsum_create("pkh(" + key.pubkey + ")"),
93+
"timestamp": "now",
94+
"label": "Descriptor import test"}
95+
self.test_importdesc(import_request, success=True)
9696
test_address(w1,
9797
key.p2pkh_addr,
9898
solvable=True,
9999
ismine=True,
100100
labels=["Descriptor import test"])
101101
assert_equal(w1.getwalletinfo()['keypoolsize'], 0)
102102

103+
self.log.info("Test can import same descriptor with public key twice")
104+
self.test_importdesc(import_request, success=True)
105+
103106
self.log.info("Internal addresses cannot have labels")
104107
self.test_importdesc({"desc": descsum_create("pkh(" + key.pubkey + ")"),
105108
"timestamp": "now",
@@ -305,7 +308,7 @@ def run_test(self):
305308

306309
# Check active=False default
307310
self.log.info('Check imported descriptors are not active by default')
308-
self.test_importdesc({'desc': descsum_create('pkh([12345678/0h/0h]' + xpub + '/*)'),
311+
self.test_importdesc({'desc': descsum_create('pkh([12345678/1h]' + xpub + '/*)'),
309312
'range' : [0, 2],
310313
'timestamp': 'now',
311314
'internal': True
@@ -322,6 +325,10 @@ def run_test(self):
322325
"timestamp": "now"},
323326
success=True,
324327
wallet=wpriv)
328+
329+
self.log.info('Test can import same descriptor with private key twice')
330+
self.test_importdesc({"desc": descsum_create(desc), "timestamp": "now"}, success=True, wallet=wpriv)
331+
325332
test_address(wpriv,
326333
address,
327334
solvable=True,
@@ -339,14 +346,25 @@ def run_test(self):
339346
wmulti_priv = self.nodes[1].get_wallet_rpc("wmulti_priv")
340347
assert_equal(wmulti_priv.getwalletinfo()['keypoolsize'], 0)
341348

342-
self.test_importdesc({"desc":"wsh(multi(2,tprv8ZgxMBicQKsPevADjDCWsa6DfhkVXicu8NQUzfibwX2MexVwW4tCec5mXdCW8kJwkzBRRmAay1KZya4WsehVvjTGVW6JLqiqd8DdZ4xSg52/84h/0h/0h/*,tprv8ZgxMBicQKsPdSNWUhDiwTScDr6JfkZuLshTRwzvZGnMSnGikV6jxpmdDkC3YRc4T3GD6Nvg9uv6hQg73RVv1EiTXDZwxVbsLugVHU8B1aq/84h/0h/0h/*,tprv8ZgxMBicQKsPeonDt8Ka2mrQmHa61hQ5FQCsvWBTpSNzBFgM58cV2EuXNAHF14VawVpznnme3SuTbA62sGriwWyKifJmXntfNeK7zeqMCj1/84h/0h/0h/*))#m2sr93jn",
349+
xprv1 = 'tprv8ZgxMBicQKsPevADjDCWsa6DfhkVXicu8NQUzfibwX2MexVwW4tCec5mXdCW8kJwkzBRRmAay1KZya4WsehVvjTGVW6JLqiqd8DdZ4xSg52'
350+
acc_xpub1 = 'tpubDCJtdt5dgJpdhW4MtaVYDhG4T4tF6jcLR1PxL43q9pq1mxvXgMS9Mzw1HnXG15vxUGQJMMSqCQHMTy3F1eW5VkgVroWzchsPD5BUojrcWs8' # /84'/0'/0'
351+
chg_xpub1 = 'tpubDCXqdwWZcszwqYJSnZp8eARkxGJfHAk23KDxbztV4BbschfaTfYLTcSkSJ3TN64dRqwa1rnFUScsYormKkGqNbbPwkorQimVevXjxzUV9Gf' # /84'/1'/0'
352+
xprv2 = 'tprv8ZgxMBicQKsPdSNWUhDiwTScDr6JfkZuLshTRwzvZGnMSnGikV6jxpmdDkC3YRc4T3GD6Nvg9uv6hQg73RVv1EiTXDZwxVbsLugVHU8B1aq'
353+
acc_xprv2 = 'tprv8gVCsmRAxVSxyUpsL13Y7ZEWBFPWbgS5E2MmFVNGuANrknvmmn2vWnmHvU8AwEFYzR2ji6EeZLSCLVacsYkvor3Pcb5JY5FGcevqTwYvdYx'
354+
acc_xpub2 = 'tpubDDBF2BTR6s8drwrfDei8WxtckGuSm1cyoKxYY1QaKSBFbHBYQArWhHPA6eJrzZej6nfHGLSURYSLHr7GuYch8aY5n61tGqgn8b4cXrMuoPH'
355+
chg_xpub2 = 'tpubDCYfZY2ceyHzYzMMVPt9MNeiqtQ2T7Uyp9QSFwYXh8Vi9iJFYXcuphJaGXfF3jUQJi5Y3GMNXvM11gaL4txzZgNGK22BFAwMXynnzv4z2Jh'
356+
xprv3 = 'tprv8ZgxMBicQKsPeonDt8Ka2mrQmHa61hQ5FQCsvWBTpSNzBFgM58cV2EuXNAHF14VawVpznnme3SuTbA62sGriwWyKifJmXntfNeK7zeqMCj1'
357+
acc_xpub3 = 'tpubDCsWoW1kuQB9kG5MXewHqkbjPtqPueRnXju7uM2NK7y3JYb2ajAZ9EiuZXNNuE4661RAfriBWhL8UsnAPpk8zrKKnZw1Ug7X4oHgMdZiU4E'
358+
chg_xpub3 = 'tpubDC6UGqnsQStngYuGD4MKsMy7eD1Yg9NTJfPdvjdG2JE5oZ7EsSL3WHg4Gsw2pR5K39ZwJ46M1wZayhedVdQtMGaUhq5S23PH6fnENK3V1sb'
359+
360+
self.test_importdesc({"desc":"wsh(multi(2," + xprv1 + "/84h/0h/0h/*," + xprv2 + "/84h/0h/0h/*," + xprv3 + "/84h/0h/0h/*))#m2sr93jn",
343361
"active": True,
344362
"range": 1000,
345363
"next_index": 0,
346364
"timestamp": "now"},
347365
success=True,
348366
wallet=wmulti_priv)
349-
self.test_importdesc({"desc":"wsh(multi(2,tprv8ZgxMBicQKsPevADjDCWsa6DfhkVXicu8NQUzfibwX2MexVwW4tCec5mXdCW8kJwkzBRRmAay1KZya4WsehVvjTGVW6JLqiqd8DdZ4xSg52/84h/1h/0h/*,tprv8ZgxMBicQKsPdSNWUhDiwTScDr6JfkZuLshTRwzvZGnMSnGikV6jxpmdDkC3YRc4T3GD6Nvg9uv6hQg73RVv1EiTXDZwxVbsLugVHU8B1aq/84h/1h/0h/*,tprv8ZgxMBicQKsPeonDt8Ka2mrQmHa61hQ5FQCsvWBTpSNzBFgM58cV2EuXNAHF14VawVpznnme3SuTbA62sGriwWyKifJmXntfNeK7zeqMCj1/84h/1h/0h/*))#q3sztvx5",
367+
self.test_importdesc({"desc":"wsh(multi(2," + xprv1 + "/84h/1h/0h/*," + xprv2 + "/84h/1h/0h/*," + xprv3 + "/84h/1h/0h/*))#q3sztvx5",
350368
"active": True,
351369
"internal" : True,
352370
"range": 1000,
@@ -374,14 +392,14 @@ def run_test(self):
374392
wmulti_pub = self.nodes[1].get_wallet_rpc("wmulti_pub")
375393
assert_equal(wmulti_pub.getwalletinfo()['keypoolsize'], 0)
376394

377-
self.test_importdesc({"desc":"wsh(multi(2,[7b2d0242/84h/0h/0h]tpubDCJtdt5dgJpdhW4MtaVYDhG4T4tF6jcLR1PxL43q9pq1mxvXgMS9Mzw1HnXG15vxUGQJMMSqCQHMTy3F1eW5VkgVroWzchsPD5BUojrcWs8/*,[59b09cd6/84h/0h/0h]tpubDDBF2BTR6s8drwrfDei8WxtckGuSm1cyoKxYY1QaKSBFbHBYQArWhHPA6eJrzZej6nfHGLSURYSLHr7GuYch8aY5n61tGqgn8b4cXrMuoPH/*,[e81a0532/84h/0h/0h]tpubDCsWoW1kuQB9kG5MXewHqkbjPtqPueRnXju7uM2NK7y3JYb2ajAZ9EiuZXNNuE4661RAfriBWhL8UsnAPpk8zrKKnZw1Ug7X4oHgMdZiU4E/*))#tsry0s5e",
395+
self.test_importdesc({"desc":"wsh(multi(2,[7b2d0242/84h/0h/0h]" + acc_xpub1 + "/*,[59b09cd6/84h/0h/0h]" + acc_xpub2 + "/*,[e81a0532/84h/0h/0h]" + acc_xpub3 +"/*))#tsry0s5e",
378396
"active": True,
379397
"range": 1000,
380398
"next_index": 0,
381399
"timestamp": "now"},
382400
success=True,
383401
wallet=wmulti_pub)
384-
self.test_importdesc({"desc":"wsh(multi(2,[7b2d0242/84h/1h/0h]tpubDCXqdwWZcszwqYJSnZp8eARkxGJfHAk23KDxbztV4BbschfaTfYLTcSkSJ3TN64dRqwa1rnFUScsYormKkGqNbbPwkorQimVevXjxzUV9Gf/*,[59b09cd6/84h/1h/0h]tpubDCYfZY2ceyHzYzMMVPt9MNeiqtQ2T7Uyp9QSFwYXh8Vi9iJFYXcuphJaGXfF3jUQJi5Y3GMNXvM11gaL4txzZgNGK22BFAwMXynnzv4z2Jh/*,[e81a0532/84h/1h/0h]tpubDC6UGqnsQStngYuGD4MKsMy7eD1Yg9NTJfPdvjdG2JE5oZ7EsSL3WHg4Gsw2pR5K39ZwJ46M1wZayhedVdQtMGaUhq5S23PH6fnENK3V1sb/*))#c08a2rzv",
402+
self.test_importdesc({"desc":"wsh(multi(2,[7b2d0242/84h/1h/0h]" + chg_xpub1 + "/*,[59b09cd6/84h/1h/0h]" + chg_xpub2 + "/*,[e81a0532/84h/1h/0h]" + chg_xpub3 + "/*))#c08a2rzv",
385403
"active": True,
386404
"internal" : True,
387405
"range": 1000,
@@ -396,8 +414,15 @@ def run_test(self):
396414
change_addr = wmulti_pub.getrawchangeaddress('bech32')
397415
assert_equal(change_addr, 'bcrt1qt9uhe3a9hnq7vajl7a094z4s3crm9ttf8zw3f5v9gr2nyd7e3lnsy44n8e')
398416
assert_equal(wmulti_pub.getwalletinfo()['keypoolsize'], 999)
417+
418+
# generate some utxos for next tests
399419
txid = w0.sendtoaddress(addr, 10)
400420
vout = find_vout_for_address(self.nodes[0], txid, addr)
421+
422+
addr2 = wmulti_pub.getnewaddress('', 'bech32')
423+
txid2 = w0.sendtoaddress(addr2, 10)
424+
vout2 = find_vout_for_address(self.nodes[0], txid2, addr2)
425+
401426
self.nodes[0].generate(6)
402427
self.sync_all()
403428
assert_equal(wmulti_pub.getbalance(), wmulti_priv.getbalance())
@@ -411,14 +436,14 @@ def run_test(self):
411436
wmulti_priv1 = self.nodes[1].get_wallet_rpc("wmulti_priv1")
412437
res = wmulti_priv1.importdescriptors([
413438
{
414-
"desc": descsum_create("wsh(multi(2,tprv8ZgxMBicQKsPevADjDCWsa6DfhkVXicu8NQUzfibwX2MexVwW4tCec5mXdCW8kJwkzBRRmAay1KZya4WsehVvjTGVW6JLqiqd8DdZ4xSg52/84h/0h/0h/*,[59b09cd6/84h/0h/0h]tpubDDBF2BTR6s8drwrfDei8WxtckGuSm1cyoKxYY1QaKSBFbHBYQArWhHPA6eJrzZej6nfHGLSURYSLHr7GuYch8aY5n61tGqgn8b4cXrMuoPH/*,[e81a0532/84h/0h/0h]tpubDCsWoW1kuQB9kG5MXewHqkbjPtqPueRnXju7uM2NK7y3JYb2ajAZ9EiuZXNNuE4661RAfriBWhL8UsnAPpk8zrKKnZw1Ug7X4oHgMdZiU4E/*))"),
439+
"desc": descsum_create("wsh(multi(2," + xprv1 + "/84h/0h/0h/*,[59b09cd6/84h/0h/0h]" + acc_xpub2 + "/*,[e81a0532/84h/0h/0h]" + acc_xpub3 + "/*))"),
415440
"active": True,
416441
"range": 1000,
417442
"next_index": 0,
418443
"timestamp": "now"
419444
},
420445
{
421-
"desc": descsum_create("wsh(multi(2,tprv8ZgxMBicQKsPevADjDCWsa6DfhkVXicu8NQUzfibwX2MexVwW4tCec5mXdCW8kJwkzBRRmAay1KZya4WsehVvjTGVW6JLqiqd8DdZ4xSg52/84h/1h/0h/*,[59b09cd6/84h/1h/0h]tpubDCYfZY2ceyHzYzMMVPt9MNeiqtQ2T7Uyp9QSFwYXh8Vi9iJFYXcuphJaGXfF3jUQJi5Y3GMNXvM11gaL4txzZgNGK22BFAwMXynnzv4z2Jh/*,[e81a0532/84h/1h/0h]tpubDC6UGqnsQStngYuGD4MKsMy7eD1Yg9NTJfPdvjdG2JE5oZ7EsSL3WHg4Gsw2pR5K39ZwJ46M1wZayhedVdQtMGaUhq5S23PH6fnENK3V1sb/*))"),
446+
"desc": descsum_create("wsh(multi(2," + xprv1 + "/84h/1h/0h/*,[59b09cd6/84h/1h/0h]" + chg_xpub2 + "/*,[e81a0532/84h/1h/0h]" + chg_xpub3 + "/*))"),
422447
"active": True,
423448
"internal" : True,
424449
"range": 1000,
@@ -434,14 +459,14 @@ def run_test(self):
434459
wmulti_priv2 = self.nodes[1].get_wallet_rpc('wmulti_priv2')
435460
res = wmulti_priv2.importdescriptors([
436461
{
437-
"desc": descsum_create("wsh(multi(2,[7b2d0242/84h/0h/0h]tpubDCJtdt5dgJpdhW4MtaVYDhG4T4tF6jcLR1PxL43q9pq1mxvXgMS9Mzw1HnXG15vxUGQJMMSqCQHMTy3F1eW5VkgVroWzchsPD5BUojrcWs8/*,tprv8ZgxMBicQKsPdSNWUhDiwTScDr6JfkZuLshTRwzvZGnMSnGikV6jxpmdDkC3YRc4T3GD6Nvg9uv6hQg73RVv1EiTXDZwxVbsLugVHU8B1aq/84h/0h/0h/*,[e81a0532/84h/0h/0h]tpubDCsWoW1kuQB9kG5MXewHqkbjPtqPueRnXju7uM2NK7y3JYb2ajAZ9EiuZXNNuE4661RAfriBWhL8UsnAPpk8zrKKnZw1Ug7X4oHgMdZiU4E/*))"),
462+
"desc": descsum_create("wsh(multi(2,[7b2d0242/84h/0h/0h]" + acc_xpub1 + "/*," + xprv2 + "/84h/0h/0h/*,[e81a0532/84h/0h/0h]" + acc_xpub3 + "/*))"),
438463
"active": True,
439464
"range": 1000,
440465
"next_index": 0,
441466
"timestamp": "now"
442467
},
443468
{
444-
"desc": descsum_create("wsh(multi(2,[7b2d0242/84h/1h/0h]tpubDCXqdwWZcszwqYJSnZp8eARkxGJfHAk23KDxbztV4BbschfaTfYLTcSkSJ3TN64dRqwa1rnFUScsYormKkGqNbbPwkorQimVevXjxzUV9Gf/*,tprv8ZgxMBicQKsPdSNWUhDiwTScDr6JfkZuLshTRwzvZGnMSnGikV6jxpmdDkC3YRc4T3GD6Nvg9uv6hQg73RVv1EiTXDZwxVbsLugVHU8B1aq/84h/1h/0h/*,[e81a0532/84h/1h/0h]tpubDC6UGqnsQStngYuGD4MKsMy7eD1Yg9NTJfPdvjdG2JE5oZ7EsSL3WHg4Gsw2pR5K39ZwJ46M1wZayhedVdQtMGaUhq5S23PH6fnENK3V1sb/*))"),
469+
"desc": descsum_create("wsh(multi(2,[7b2d0242/84h/1h/0h]" + chg_xpub1 + "/*," + xprv2 + "/84h/1h/0h/*,[e81a0532/84h/1h/0h]" + chg_xpub3 + "/*))"),
445470
"active": True,
446471
"internal" : True,
447472
"range": 1000,
@@ -531,6 +556,33 @@ def run_test(self):
531556
)
532557

533558

559+
self.log.info("Amending multisig with new private keys")
560+
self.nodes[1].createwallet(wallet_name="wmulti_priv3", descriptors=True)
561+
wmulti_priv3 = self.nodes[1].get_wallet_rpc("wmulti_priv3")
562+
res = wmulti_priv3.importdescriptors([
563+
{
564+
"desc": descsum_create("wsh(multi(2," + xprv1 + "/84h/0h/0h/*,[59b09cd6/84h/0h/0h]" + acc_xpub2 + "/*,[e81a0532/84h/0h/0h]" + acc_xpub3 + "/*))"),
565+
"active": True,
566+
"range": 1000,
567+
"next_index": 0,
568+
"timestamp": "now"
569+
}])
570+
assert_equal(res[0]['success'], True)
571+
res = wmulti_priv3.importdescriptors([
572+
{
573+
"desc": descsum_create("wsh(multi(2," + xprv1 + "/84h/0h/0h/*,[59b09cd6/84h/0h/0h]" + acc_xprv2 + "/*,[e81a0532/84h/0h/0h]" + acc_xpub3 + "/*))"),
574+
"active": True,
575+
"range": 1000,
576+
"next_index": 0,
577+
"timestamp": "now"
578+
}])
579+
assert_equal(res[0]['success'], True)
580+
581+
rawtx = self.nodes[1].createrawtransaction([{'txid': txid2, 'vout': vout2}], {w0.getnewaddress(): 9.999})
582+
tx = wmulti_priv3.signrawtransactionwithwallet(rawtx)
583+
assert_equal(tx['complete'], True)
584+
self.nodes[1].sendrawtransaction(tx['hex'])
585+
534586
self.log.info("Combo descriptors cannot be active")
535587
self.test_importdesc({"desc": descsum_create("combo(tpubDCJtdt5dgJpdhW4MtaVYDhG4T4tF6jcLR1PxL43q9pq1mxvXgMS9Mzw1HnXG15vxUGQJMMSqCQHMTy3F1eW5VkgVroWzchsPD5BUojrcWs8/*)"),
536588
"active": True,

0 commit comments

Comments
 (0)