Skip to content

Commit be62903

Browse files
committed
Make descriptor checksums mandatory in deriveaddresses and importmulti
1 parent b52cb63 commit be62903

File tree

4 files changed

+45
-31
lines changed

4 files changed

+45
-31
lines changed

src/rpc/misc.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ UniValue deriveaddresses(const JSONRPCRequest& request)
207207
},
208208
RPCExamples{
209209
"First three native segwit receive addresses\n" +
210-
HelpExampleCli("deriveaddresses", "\"wpkh([d34db33f/84h/0h/0h]xpub6DJ2dNUysrn5Vt36jH2KLBT2i1auw1tTSSomg8PhqNiUtx8QX2SvC9nrHu81fT41fvDUnhMjEzQgXnQjKEu3oaqMSzhSrHMxyyoEAmUHQbY/0/*)\" 0 2")
210+
HelpExampleCli("deriveaddresses", "\"wpkh([d34db33f/84h/0h/0h]xpub6DJ2dNUysrn5Vt36jH2KLBT2i1auw1tTSSomg8PhqNiUtx8QX2SvC9nrHu81fT41fvDUnhMjEzQgXnQjKEu3oaqMSzhSrHMxyyoEAmUHQbY/0/*)#trd0mf0l\" 0 2")
211211
}}.ToString()
212212
);
213213
}
@@ -233,7 +233,7 @@ UniValue deriveaddresses(const JSONRPCRequest& request)
233233
}
234234

235235
FlatSigningProvider provider;
236-
auto desc = Parse(desc_str, provider);
236+
auto desc = Parse(desc_str, provider, /* require_checksum = */ true);
237237
if (!desc) {
238238
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, strprintf("Invalid descriptor"));
239239
}

src/wallet/rpcdump.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1117,7 +1117,7 @@ static UniValue ProcessImportDescriptor(ImportData& import_data, std::map<CKeyID
11171117

11181118
const std::string& descriptor = data["desc"].get_str();
11191119
FlatSigningProvider keys;
1120-
auto parsed_desc = Parse(descriptor, keys);
1120+
auto parsed_desc = Parse(descriptor, keys, /* require_checksum = */ true);
11211121
if (!parsed_desc) {
11221122
throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Descriptor is invalid");
11231123
}

test/functional/rpc_deriveaddresses.py

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
55
"""Test the deriveaddresses rpc call."""
66
from test_framework.test_framework import BitcoinTestFramework
7+
from test_framework.descriptors import descsum_create
78
from test_framework.util import assert_equal, assert_raises_rpc_error
89

910
class DeriveaddressesTest(BitcoinTestFramework):
@@ -14,36 +15,37 @@ def set_test_params(self):
1415
def run_test(self):
1516
assert_raises_rpc_error(-5, "Invalid descriptor", self.nodes[0].deriveaddresses, "a")
1617

17-
descriptor = "wpkh(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/0)"
18+
descriptor = "wpkh(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/0)#t6wfjs64"
1819
address = "bcrt1qjqmxmkpmxt80xz4y3746zgt0q3u3ferr34acd5"
19-
2020
assert_equal(self.nodes[0].deriveaddresses(descriptor), [address])
2121

22-
descriptor_pubkey = "wpkh(tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/1/1/0)"
23-
address = "bcrt1qjqmxmkpmxt80xz4y3746zgt0q3u3ferr34acd5"
22+
descriptor = descriptor[:-9]
23+
assert_raises_rpc_error(-5, "Invalid descriptor", self.nodes[0].deriveaddresses, descriptor)
2424

25+
descriptor_pubkey = "wpkh(tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/1/1/0)#s9ga3alw"
26+
address = "bcrt1qjqmxmkpmxt80xz4y3746zgt0q3u3ferr34acd5"
2527
assert_equal(self.nodes[0].deriveaddresses(descriptor_pubkey), [address])
2628

27-
ranged_descriptor = "wpkh(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/*)"
29+
ranged_descriptor = "wpkh(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/*)#kft60nuy"
2830
assert_equal(self.nodes[0].deriveaddresses(ranged_descriptor, 0, 2), [address, "bcrt1qhku5rq7jz8ulufe2y6fkcpnlvpsta7rq4442dy", "bcrt1qpgptk2gvshyl0s9lqshsmx932l9ccsv265tvaq"])
2931

30-
assert_raises_rpc_error(-8, "Range should not be specified for an un-ranged descriptor", self.nodes[0].deriveaddresses, "wpkh(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/0)", 0, 2)
32+
assert_raises_rpc_error(-8, "Range should not be specified for an un-ranged descriptor", self.nodes[0].deriveaddresses, descsum_create("wpkh(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/0)"), 0, 2)
3133

32-
assert_raises_rpc_error(-8, "Range must be specified for a ranged descriptor", self.nodes[0].deriveaddresses, "wpkh(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/*)")
34+
assert_raises_rpc_error(-8, "Range must be specified for a ranged descriptor", self.nodes[0].deriveaddresses, descsum_create("wpkh(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/*)"))
3335

34-
assert_raises_rpc_error(-8, "Missing range end parameter", self.nodes[0].deriveaddresses, "wpkh(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/*)", 0)
36+
assert_raises_rpc_error(-8, "Missing range end parameter", self.nodes[0].deriveaddresses, descsum_create("wpkh(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/*)"), 0)
3537

36-
assert_raises_rpc_error(-8, "Range end should be equal to or greater than begin", self.nodes[0].deriveaddresses, "wpkh(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/*)", 2, 0)
38+
assert_raises_rpc_error(-8, "Range end should be equal to or greater than begin", self.nodes[0].deriveaddresses, descsum_create("wpkh(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/*)"), 2, 0)
3739

38-
assert_raises_rpc_error(-8, "Range should be greater or equal than 0", self.nodes[0].deriveaddresses, "wpkh(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/*)", -1, 0)
40+
assert_raises_rpc_error(-8, "Range should be greater or equal than 0", self.nodes[0].deriveaddresses, descsum_create("wpkh(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/*)"), -1, 0)
3941

40-
combo_descriptor = "combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/0)"
42+
combo_descriptor = descsum_create("combo(tprv8ZgxMBicQKsPd7Uf69XL1XwhmjHopUGep8GuEiJDZmbQz6o58LninorQAfcKZWARbtRtfnLcJ5MQ2AtHcQJCCRUcMRvmDUjyEmNUWwx8UbK/1/1/0)")
4143
assert_equal(self.nodes[0].deriveaddresses(combo_descriptor), ["mtfUoUax9L4tzXARpw1oTGxWyoogp52KhJ", "mtfUoUax9L4tzXARpw1oTGxWyoogp52KhJ", address, "2NDvEwGfpEqJWfybzpKPHF2XH3jwoQV3D7x"])
4244

43-
hardened_without_privkey_descriptor = "wpkh(tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/1'/1/0)"
45+
hardened_without_privkey_descriptor = descsum_create("wpkh(tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/1'/1/0)")
4446
assert_raises_rpc_error(-5, "Cannot derive script without private keys", self.nodes[0].deriveaddresses, hardened_without_privkey_descriptor)
4547

46-
bare_multisig_descriptor = "multi(1, tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/1/1/0, tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/1/1/1)"
48+
bare_multisig_descriptor = descsum_create("multi(1,tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/1/1/0,tpubD6NzVbkrYhZ4WaWSyoBvQwbpLkojyoTZPRsgXELWz3Popb3qkjcJyJUGLnL4qHHoQvao8ESaAstxYSnhyswJ76uZPStJRJCTKvosUCJZL5B/1/1/1)")
4749
assert_raises_rpc_error(-5, "Descriptor does not have a corresponding address", self.nodes[0].deriveaddresses, bare_multisig_descriptor)
4850

4951
if __name__ == '__main__':

test/functional/wallet_importmulti.py

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
OP_NOP,
2121
)
2222
from test_framework.test_framework import BitcoinTestFramework
23+
from test_framework.descriptors import descsum_create
2324
from test_framework.util import (
2425
assert_equal,
2526
assert_greater_than,
@@ -545,11 +546,22 @@ def run_test(self):
545546

546547
# Test importing of a P2SH-P2WPKH address via descriptor + private key
547548
key = get_key(self.nodes[0])
548-
self.log.info("Should import a p2sh-p2wpkh address from descriptor and private key")
549+
self.log.info("Should not import a p2sh-p2wpkh address from descriptor without checksum and private key")
549550
self.test_importmulti({"desc": "sh(wpkh(" + key.pubkey + "))",
550551
"timestamp": "now",
551552
"label": "Descriptor import test",
552553
"keys": [key.privkey]},
554+
success=False,
555+
error_code=-5,
556+
error_message="Descriptor is invalid")
557+
558+
# Test importing of a P2SH-P2WPKH address via descriptor + private key
559+
key = get_key(self.nodes[0])
560+
self.log.info("Should import a p2sh-p2wpkh address from descriptor and private key")
561+
self.test_importmulti({"desc": descsum_create("sh(wpkh(" + key.pubkey + "))"),
562+
"timestamp": "now",
563+
"label": "Descriptor import test",
564+
"keys": [key.privkey]},
553565
success=True)
554566
test_address(self.nodes[1],
555567
key.p2sh_p2wpkh_addr,
@@ -562,15 +574,15 @@ def run_test(self):
562574
addresses = ["2N7yv4p8G8yEaPddJxY41kPihnWvs39qCMf", "2MsHxyb2JS3pAySeNUsJ7mNnurtpeenDzLA"] # hdkeypath=m/0'/0'/0' and 1'
563575
desc = "sh(wpkh(" + xpriv + "/0'/0'/*'" + "))"
564576
self.log.info("Ranged descriptor import should fail without a specified range")
565-
self.test_importmulti({"desc": desc,
577+
self.test_importmulti({"desc": descsum_create(desc),
566578
"timestamp": "now"},
567579
success=False,
568580
error_code=-8,
569581
error_message='Descriptor is ranged, please specify the range')
570582

571583
# Test importing of a ranged descriptor without keys
572584
self.log.info("Should import the ranged descriptor with specified range as solvable")
573-
self.test_importmulti({"desc": desc,
585+
self.test_importmulti({"desc": descsum_create(desc),
574586
"timestamp": "now",
575587
"range": {"end": 1}},
576588
success=True,
@@ -583,7 +595,7 @@ def run_test(self):
583595
# Test importing of a P2PKH address via descriptor
584596
key = get_key(self.nodes[0])
585597
self.log.info("Should import a p2pkh address from descriptor")
586-
self.test_importmulti({"desc": "pkh(" + key.pubkey + ")",
598+
self.test_importmulti({"desc": descsum_create("pkh(" + key.pubkey + ")"),
587599
"timestamp": "now",
588600
"label": "Descriptor import test"},
589601
True,
@@ -597,7 +609,7 @@ def run_test(self):
597609
# Test import fails if both desc and scriptPubKey are provided
598610
key = get_key(self.nodes[0])
599611
self.log.info("Import should fail if both scriptPubKey and desc are provided")
600-
self.test_importmulti({"desc": "pkh(" + key.pubkey + ")",
612+
self.test_importmulti({"desc": descsum_create("pkh(" + key.pubkey + ")"),
601613
"scriptPubKey": {"address": key.p2pkh_addr},
602614
"timestamp": "now"},
603615
success=False,
@@ -616,7 +628,7 @@ def run_test(self):
616628
key1 = get_key(self.nodes[0])
617629
key2 = get_key(self.nodes[0])
618630
self.log.info("Should import a 1-of-2 bare multisig from descriptor")
619-
self.test_importmulti({"desc": "multi(1," + key1.pubkey + "," + key2.pubkey + ")",
631+
self.test_importmulti({"desc": descsum_create("multi(1," + key1.pubkey + "," + key2.pubkey + ")"),
620632
"timestamp": "now"},
621633
success=True)
622634
self.log.info("Should not treat individual keys from the imported bare multisig as watchonly")
@@ -635,7 +647,7 @@ def run_test(self):
635647
pub_fpr = info['hdmasterfingerprint']
636648
result = self.nodes[0].importmulti(
637649
[{
638-
'desc' : "wpkh([" + pub_fpr + pub_keypath[1:] +"]" + pub + ")",
650+
'desc' : descsum_create("wpkh([" + pub_fpr + pub_keypath[1:] +"]" + pub + ")"),
639651
"timestamp": "now",
640652
}]
641653
)
@@ -653,7 +665,7 @@ def run_test(self):
653665
priv_fpr = info['hdmasterfingerprint']
654666
result = self.nodes[0].importmulti(
655667
[{
656-
'desc' : "wpkh([" + priv_fpr + priv_keypath[1:] + "]" + priv + ")",
668+
'desc' : descsum_create("wpkh([" + priv_fpr + priv_keypath[1:] + "]" + priv + ")"),
657669
"timestamp": "now",
658670
}]
659671
)
@@ -701,12 +713,12 @@ def run_test(self):
701713
pub2 = self.nodes[0].getaddressinfo(addr2)['pubkey']
702714
result = wrpc.importmulti(
703715
[{
704-
'desc': 'wpkh(' + pub1 + ')',
716+
'desc': descsum_create('wpkh(' + pub1 + ')'),
705717
'keypool': True,
706718
"timestamp": "now",
707719
},
708720
{
709-
'desc': 'wpkh(' + pub2 + ')',
721+
'desc': descsum_create('wpkh(' + pub2 + ')'),
710722
'keypool': True,
711723
"timestamp": "now",
712724
}]
@@ -727,13 +739,13 @@ def run_test(self):
727739
pub2 = self.nodes[0].getaddressinfo(addr2)['pubkey']
728740
result = wrpc.importmulti(
729741
[{
730-
'desc': 'wpkh(' + pub1 + ')',
742+
'desc': descsum_create('wpkh(' + pub1 + ')'),
731743
'keypool': True,
732744
'internal': True,
733745
"timestamp": "now",
734746
},
735747
{
736-
'desc': 'wpkh(' + pub2 + ')',
748+
'desc': descsum_create('wpkh(' + pub2 + ')'),
737749
'keypool': True,
738750
'internal': True,
739751
"timestamp": "now",
@@ -755,7 +767,7 @@ def run_test(self):
755767
pub2 = self.nodes[0].getaddressinfo(addr2)['pubkey']
756768
result = wrpc.importmulti(
757769
[{
758-
'desc': 'wsh(multi(2,' + pub1 + ',' + pub2 + '))',
770+
'desc': descsum_create('wsh(multi(2,' + pub1 + ',' + pub2 + '))'),
759771
'keypool': True,
760772
"timestamp": "now",
761773
}]
@@ -769,7 +781,7 @@ def run_test(self):
769781
assert wrpc.getwalletinfo()['private_keys_enabled']
770782
result = wrpc.importmulti(
771783
[{
772-
'desc': 'wpkh(' + pub1 + ')',
784+
'desc': descsum_create('wpkh(' + pub1 + ')'),
773785
'keypool': True,
774786
"timestamp": "now",
775787
}]
@@ -792,7 +804,7 @@ def run_test(self):
792804
]
793805
result = wrpc.importmulti(
794806
[{
795-
'desc': 'wpkh([80002067/0h/0h]' + xpub + '/*)',
807+
'desc': descsum_create('wpkh([80002067/0h/0h]' + xpub + '/*)'),
796808
'keypool': True,
797809
'timestamp': 'now',
798810
'range' : {'start': 0, 'end': 4}

0 commit comments

Comments
 (0)