/ test / functional / rpc_createmultisig.py
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()