rpc_createmultisig.py
1 #!/usr/bin/env python3 2 # Copyright (c) 2015-present The Bitcoin Core developers 3 # Distributed under the MIT software license, see the accompanying 4 # file COPYING or http://www.opensource.org/licenses/mit-license.php. 5 """Test multisig RPCs""" 6 import decimal 7 import itertools 8 import json 9 import os 10 11 from test_framework.address import address_to_scriptpubkey 12 from test_framework.descriptors import descsum_create 13 from test_framework.key import ECPubKey 14 from test_framework.messages import COIN 15 from test_framework.script_util import keys_to_multisig_script 16 from test_framework.test_framework import BitcoinTestFramework 17 from test_framework.util import ( 18 assert_raises_rpc_error, 19 assert_equal, 20 ) 21 from test_framework.wallet_util import generate_keypair 22 from test_framework.wallet import ( 23 MiniWallet, 24 getnewdestination, 25 ) 26 27 class RpcCreateMultiSigTest(BitcoinTestFramework): 28 def set_test_params(self): 29 self.setup_clean_chain = True 30 self.num_nodes = 3 31 32 def create_keys(self, num_keys): 33 self.pub = [] 34 self.priv = [] 35 for _ in range(num_keys): 36 privkey, pubkey = generate_keypair(wif=True) 37 self.pub.append(pubkey.hex()) 38 self.priv.append(privkey) 39 40 def run_test(self): 41 node0, node1, _node2 = self.nodes 42 self.wallet = MiniWallet(test_node=node0) 43 44 self.log.info('Generating blocks ...') 45 self.generate(self.wallet, 149) 46 47 self.create_keys(21) # max number of allowed keys + 1 48 m_of_n = [(2, 3), (3, 3), (2, 5), (3, 5), (10, 15), (15, 15)] 49 for (sigs, keys) in m_of_n: 50 for output_type in ["bech32", "p2sh-segwit", "legacy"]: 51 self.do_multisig(keys, sigs, output_type) 52 53 self.test_multisig_script_limit() 54 self.test_mixing_uncompressed_and_compressed_keys(node0) 55 self.test_sortedmulti_descriptors_bip67() 56 57 # Check that bech32m is currently not allowed 58 assert_raises_rpc_error(-5, "createmultisig cannot create bech32m multisig addresses", self.nodes[0].createmultisig, 2, self.pub, "bech32m") 59 60 self.log.info('Check correct encoding of multisig script for all n (1..20)') 61 for nkeys in range(1, 20+1): 62 keys = [self.pub[0]]*nkeys 63 expected_ms_script = keys_to_multisig_script(keys, k=nkeys) # simply use n-of-n 64 # note that the 'legacy' address type fails for n values larger than 15 65 # due to exceeding the P2SH size limit (520 bytes), so we use 'bech32' instead 66 # (for the purpose of this encoding test, we don't care about the resulting address) 67 res = self.nodes[0].createmultisig(nrequired=nkeys, keys=keys, address_type='bech32') 68 assert_equal(res['redeemScript'], expected_ms_script.hex()) 69 70 def test_multisig_script_limit(self): 71 node1 = self.nodes[1] 72 pubkeys = self.pub[0:20] 73 74 self.log.info('Test legacy redeem script max size limit') 75 assert_raises_rpc_error(-8, "redeemScript exceeds size limit: 684 > 520", node1.createmultisig, 16, pubkeys, 'legacy') 76 77 self.log.info('Test valid 16-20 multisig p2sh-legacy and bech32 (no wallet)') 78 self.do_multisig(nkeys=20, nsigs=16, output_type="p2sh-segwit") 79 self.do_multisig(nkeys=20, nsigs=16, output_type="bech32") 80 81 self.log.info('Test invalid 16-21 multisig p2sh-legacy and bech32 (no wallet)') 82 assert_raises_rpc_error(-8, "Number of keys involved in the multisignature address creation > 20", node1.createmultisig, 16, self.pub, 'p2sh-segwit') 83 assert_raises_rpc_error(-8, "Number of keys involved in the multisignature address creation > 20", node1.createmultisig, 16, self.pub, 'bech32') 84 85 def do_multisig(self, nkeys, nsigs, output_type): 86 node0, _node1, node2 = self.nodes 87 pub_keys = self.pub[0: nkeys] 88 priv_keys = self.priv[0: nkeys] 89 90 # Construct the expected descriptor 91 desc = 'multi({},{})'.format(nsigs, ','.join(pub_keys)) 92 if output_type == 'legacy': 93 desc = 'sh({})'.format(desc) 94 elif output_type == 'p2sh-segwit': 95 desc = 'sh(wsh({}))'.format(desc) 96 elif output_type == 'bech32': 97 desc = 'wsh({})'.format(desc) 98 desc = descsum_create(desc) 99 100 msig = node2.createmultisig(nsigs, pub_keys, output_type) 101 assert 'warnings' not in msig 102 madd = msig["address"] 103 mredeem = msig["redeemScript"] 104 assert_equal(desc, msig['descriptor']) 105 if output_type == 'bech32': 106 assert madd[0:4] == "bcrt" # actually a bech32 address 107 108 spk = address_to_scriptpubkey(madd) 109 value = decimal.Decimal("0.00004000") 110 tx = self.wallet.send_to(from_node=self.nodes[0], scriptPubKey=spk, amount=int(value * COIN)) 111 prevtxs = [{"txid": tx["txid"], "vout": tx["sent_vout"], "scriptPubKey": spk.hex(), "redeemScript": mredeem, "amount": value}] 112 113 self.generate(node0, 1) 114 115 outval = value - decimal.Decimal("0.00002000") # deduce fee (must be higher than the min relay fee) 116 out_addr = getnewdestination('bech32')[2] 117 rawtx = node2.createrawtransaction([{"txid": tx["txid"], "vout": tx["sent_vout"]}], [{out_addr: outval}]) 118 119 prevtx_err = dict(prevtxs[0]) 120 del prevtx_err["redeemScript"] 121 122 assert_raises_rpc_error(-8, "Missing redeemScript/witnessScript", node2.signrawtransactionwithkey, rawtx, priv_keys[0:nsigs-1], [prevtx_err]) 123 124 # if witnessScript specified, all ok 125 prevtx_err["witnessScript"] = prevtxs[0]["redeemScript"] 126 node2.signrawtransactionwithkey(rawtx, priv_keys[0:nsigs-1], [prevtx_err]) 127 128 # both specified, also ok 129 prevtx_err["redeemScript"] = prevtxs[0]["redeemScript"] 130 node2.signrawtransactionwithkey(rawtx, priv_keys[0:nsigs-1], [prevtx_err]) 131 132 # redeemScript mismatch to witnessScript 133 prevtx_err["redeemScript"] = "6a" # OP_RETURN 134 assert_raises_rpc_error(-8, "redeemScript does not correspond to witnessScript", node2.signrawtransactionwithkey, rawtx, priv_keys[0:nsigs-1], [prevtx_err]) 135 136 # redeemScript does not match scriptPubKey 137 del prevtx_err["witnessScript"] 138 assert_raises_rpc_error(-8, "redeemScript/witnessScript does not match scriptPubKey", node2.signrawtransactionwithkey, rawtx, priv_keys[0:nsigs-1], [prevtx_err]) 139 140 # witnessScript does not match scriptPubKey 141 prevtx_err["witnessScript"] = prevtx_err["redeemScript"] 142 del prevtx_err["redeemScript"] 143 assert_raises_rpc_error(-8, "redeemScript/witnessScript does not match scriptPubKey", node2.signrawtransactionwithkey, rawtx, priv_keys[0:nsigs-1], [prevtx_err]) 144 145 rawtx2 = node2.signrawtransactionwithkey(rawtx, priv_keys[0:nsigs - 1], prevtxs) 146 assert_equal(rawtx2["complete"], False) 147 rawtx3 = node2.signrawtransactionwithkey(rawtx, [priv_keys[-1]], prevtxs) 148 assert_equal(rawtx3["complete"], False) 149 assert_raises_rpc_error(-22, "TX decode failed", node2.combinerawtransaction, [rawtx2['hex'], rawtx3['hex'] + "00"]) 150 assert_raises_rpc_error(-22, "Missing transactions", node2.combinerawtransaction, []) 151 combined_rawtx = node2.combinerawtransaction([rawtx2["hex"], rawtx3["hex"]]) 152 153 tx = node0.sendrawtransaction(combined_rawtx, 0) 154 blk = self.generate(node0, 1)[0] 155 assert tx in node0.getblock(blk)["tx"] 156 157 assert_raises_rpc_error(-25, "Input not found or already spent", node2.combinerawtransaction, [rawtx2['hex'], rawtx3['hex']]) 158 159 txinfo = node0.getrawtransaction(tx, True, blk) 160 self.log.info("n/m=%d/%d %s size=%d vsize=%d weight=%d" % (nsigs, nkeys, output_type, txinfo["size"], txinfo["vsize"], txinfo["weight"])) 161 162 def test_mixing_uncompressed_and_compressed_keys(self, node): 163 self.log.info('Mixed compressed and uncompressed multisigs are not allowed') 164 pk0, pk1, pk2 = [getnewdestination('bech32')[0].hex() for _ in range(3)] 165 166 # decompress pk2 167 pk_obj = ECPubKey() 168 pk_obj.set(bytes.fromhex(pk2)) 169 pk_obj.compressed = False 170 pk2 = pk_obj.get_bytes().hex() 171 172 # Check all permutations of keys because order matters apparently 173 for keys in itertools.permutations([pk0, pk1, pk2]): 174 # Results should be the same as this legacy one 175 legacy_addr = node.createmultisig(2, keys, 'legacy')['address'] 176 177 # Generate addresses with the segwit types. These should all make legacy addresses 178 err_msg = ["Unable to make chosen address type, please ensure no uncompressed public keys are present."] 179 180 for addr_type in ['bech32', 'p2sh-segwit']: 181 result = self.nodes[0].createmultisig(nrequired=2, keys=keys, address_type=addr_type) 182 assert_equal(legacy_addr, result['address']) 183 assert_equal(result['warnings'], err_msg) 184 185 def test_sortedmulti_descriptors_bip67(self): 186 self.log.info('Testing sortedmulti descriptors with BIP 67 test vectors') 187 with open(os.path.join(os.path.dirname(os.path.realpath(__file__)), 'data/rpc_bip67.json')) as f: 188 vectors = json.load(f) 189 190 for t in vectors: 191 key_str = ','.join(t['keys']) 192 desc = descsum_create('sh(sortedmulti(2,{}))'.format(key_str)) 193 assert_equal(self.nodes[0].deriveaddresses(desc)[0], t['address']) 194 sorted_key_str = ','.join(t['sorted_keys']) 195 sorted_key_desc = descsum_create('sh(multi(2,{}))'.format(sorted_key_str)) 196 assert_equal(self.nodes[0].deriveaddresses(sorted_key_desc)[0], t['address']) 197 198 199 if __name__ == '__main__': 200 RpcCreateMultiSigTest(__file__).main()