wallet, rpc: Disallow import of unused() if key already exists

This commit is contained in:
Ava Chow 2024-01-04 13:50:35 -05:00
parent 9e70f515a0
commit 09e5a684fe
2 changed files with 34 additions and 0 deletions

View file

@ -1573,6 +1573,23 @@ static UniValue ProcessDescriptorImport(CWallet& wallet, const UniValue& data, c
}
}
// If this is an unused(KEY) descriptor, check that the wallet doesn't already have other descriptors with this key
if (!parsed_desc->HasScripts()) {
// Unused descriptors must contain a single key.
// Earlier checks will have enforced that this key is either a private key when private keys are enabled,
// or that this key is a public key when private keys are disabled.
// If we can retrieve the corresponding private key from the wallet, then this key is already in the wallet
// and we should not import it.
std::set<CPubKey> pubkeys;
std::set<CExtPubKey> extpubs;
parsed_desc->GetPubKeys(pubkeys, extpubs);
std::transform(extpubs.begin(), extpubs.end(), std::inserter(pubkeys, pubkeys.begin()), [](const CExtPubKey& xpub) { return xpub.pubkey; });
CHECK_NONFATAL(pubkeys.size() == 1);
if (wallet.GetKey(pubkeys.begin()->GetID())) {
throw JSONRPCError(RPC_WALLET_ERROR, "Cannot import an unused() descriptor when its private key is already in the wallet");
}
}
WalletDescriptor w_desc(std::move(parsed_desc), timestamp, range_start, range_end, next_index);
// Check if the wallet already contains the descriptor

View file

@ -83,6 +83,22 @@ class ImportDescriptorsTest(BitcoinTestFramework):
assert_equal(hdkeys[0]["xpub"], xpub)
wallet.unloadwallet()
def test_import_unused_key_existing(self):
self.log.info("Test import of unused(KEY) with existing KEY")
self.nodes[0].createwallet(wallet_name="import_existing_unused")
wallet = self.nodes[0].get_wallet_rpc("import_existing_unused")
hdkeys = wallet.gethdkeys(private=True)
assert_equal(len(hdkeys), 1)
xprv = hdkeys[0]["xprv"]
self.test_importdesc({"timestamp": "now", "desc": descsum_create(f"unused({xprv})")},
success=False,
error_code=-4,
error_message="Cannot import an unused() descriptor when its private key is already in the wallet",
wallet=wallet)
wallet.unloadwallet()
def run_test(self):
self.log.info('Setting up wallets')
self.nodes[0].createwallet(wallet_name='w0', disable_private_keys=False, descriptors=True)
@ -791,6 +807,7 @@ class ImportDescriptorsTest(BitcoinTestFramework):
assert_equal(sorted(w_multipath.listdescriptors()["descriptors"], key=lambda x: x["desc"]), sorted(w_multisplit.listdescriptors()["descriptors"], key=lambda x: x["desc"]))
self.test_import_unused_key()
self.test_import_unused_key_existing()
if __name__ == '__main__':
ImportDescriptorsTest(__file__).main()