diff --git a/doc/release-notes.md b/doc/release-notes.md --- a/doc/release-notes.md +++ b/doc/release-notes.md @@ -36,6 +36,13 @@ command line arguments. - The `hdmasterkeyid` return field has been removed from `getaddressinfo` and `getwalletinfo`. Use `hdseedid` instead. +- Descriptors with key origin information imported through `importmulti` will + have their key origin information stored in the wallet for use with creating + PSBTs. +- If `bip32derivs` of both `walletprocesspsbt` and `walletcreatefundedpsbt` is + set to true but the key metadata for a public key has not been updated yet, + then that key will have a derivation path as if it were just an independent + key (i.e. no derivation path and its master fingerprint is itself) RPC importprivkey: new label behavior ------------------------------------- @@ -77,3 +84,10 @@ ------------ - `deriveaddresses` returns one or more addresses corresponding to an [output descriptor](/doc/descriptors.md). + +Miscellaneous Wallet changes +---------------------------- + +- The key metadata will need to be upgraded the first time that the HD seed is + available. For unencrypted wallets this will occur on wallet loading. For + encrypted wallets this will occur the first time the wallet is unlocked. diff --git a/test/functional/wallet_importmulti.py b/test/functional/wallet_importmulti.py --- a/test/functional/wallet_importmulti.py +++ b/test/functional/wallet_importmulti.py @@ -514,6 +514,72 @@ ismine=False, iswatchonly=False) + # Import pubkeys with key origin info + self.log.info( + "Addresses should have hd keypath and master key id after import with key origin") + pub_addr = self.nodes[1].getnewaddress() + pub_addr = self.nodes[1].getnewaddress() + info = self.nodes[1].getaddressinfo(pub_addr) + pub = info['pubkey'] + pub_keypath = info['hdkeypath'] + pub_fpr = info['hdmasterfingerprint'] + result = self.nodes[0].importmulti( + [{ + 'desc': "pkh([" + pub_fpr + pub_keypath[1:] + "]" + pub + ")", + "timestamp": "now", + }] + ) + assert result[0]['success'] + pub_import_info = self.nodes[0].getaddressinfo(pub_addr) + assert_equal(pub_import_info['hdmasterfingerprint'], pub_fpr) + assert_equal(pub_import_info['pubkey'], pub) + assert_equal(pub_import_info['hdkeypath'], pub_keypath) + + # Import privkeys with key origin info + priv_addr = self.nodes[1].getnewaddress() + info = self.nodes[1].getaddressinfo(priv_addr) + priv = self.nodes[1].dumpprivkey(priv_addr) + priv_keypath = info['hdkeypath'] + priv_fpr = info['hdmasterfingerprint'] + result = self.nodes[0].importmulti( + [{ + 'desc': "pkh([" + priv_fpr + priv_keypath[1:] + "]" + priv + ")", + "timestamp": "now", + }] + ) + assert result[0]['success'] + priv_import_info = self.nodes[0].getaddressinfo(priv_addr) + assert_equal(priv_import_info['hdmasterfingerprint'], priv_fpr) + assert_equal(priv_import_info['hdkeypath'], priv_keypath) + + # Make sure the key origin info are still there after a restart + self.stop_nodes() + self.start_nodes() + import_info = self.nodes[0].getaddressinfo(pub_addr) + assert_equal(import_info['hdmasterfingerprint'], pub_fpr) + assert_equal(import_info['hdkeypath'], pub_keypath) + import_info = self.nodes[0].getaddressinfo(priv_addr) + assert_equal(import_info['hdmasterfingerprint'], priv_fpr) + assert_equal(import_info['hdkeypath'], priv_keypath) + + # Check legacy import does not import key origin info + self.log.info("Legacy imports don't have key origin info") + pub_addr = self.nodes[1].getnewaddress() + info = self.nodes[1].getaddressinfo(pub_addr) + pub = info['pubkey'] + result = self.nodes[0].importmulti( + [{ + 'scriptPubKey': {'address': pub_addr}, + 'pubkeys': [pub], + "timestamp": "now", + }] + ) + assert result[0]['success'] + pub_import_info = self.nodes[0].getaddressinfo(pub_addr) + assert_equal(pub_import_info['pubkey'], pub) + assert 'hdmasterfingerprint' not in pub_import_info + assert 'hdkeypath' not in pub_import_info + if __name__ == '__main__': ImportMultiTest().main()