Repository: bitcoin/bitcoin
File: test/functional/rpc_createmultisig.py (Python)

Code before:

        self.log.info('Generating blocks ...')
        self.generate(self.wallet, 149)

        self.moved = 0
        for self.nkeys in [3, 5]:
            for self.nsigs in [2, 3]:
                for self.output_type in ["bech32", "p2sh-segwit", "legacy"]:
                    self.get_keys()
                    self.do_multisig()
        if self.is_bdb_compiled():
            self.checkbalances()

        # Test mixed compressed and uncompressed pubkeys
        self.log.info('Mixed compressed and uncompressed multisigs are not allowed')
        pk0, pk1, pk2 = [getnewdestination('bech32')[0].hex() for _ in range(3)]

        # decompress pk2
        pk_obj = ECPubKey()
        pk_obj.set(bytes.fromhex(pk2))
        pk_obj.compressed = False
        pk2 = pk_obj.get_bytes().hex()

        if self.is_bdb_compiled():
            node0.createwallet(wallet_name='wmulti0', disable_private_keys=True)
            wmulti0 = node0.get_wallet_rpc('wmulti0')

        # Check all permutations of keys because order matters apparently
        for keys in itertools.permutations([pk0, pk1, pk2]):
            # Results should be the same as this legacy one
            legacy_addr = node0.createmultisig(2, keys, 'legacy')['address']

            if self.is_bdb_compiled():
                result = wmulti0.addmultisigaddress(2, keys, '', 'legacy')
                assert_equal(legacy_addr, result['address'])
                assert 'warnings' not in result

            # Generate addresses with the segwit types. These should all make legacy addresses
            err_msg = ["Unable to make chosen address type, please ensure no uncompressed public keys are present."]

            for addr_type in ['bech32', 'p2sh-segwit']:
                result = self.nodes[0].createmultisig(nrequired=2, keys=keys, address_type=addr_type)
                assert_equal(legacy_addr, result['address'])
                assert_equal(result['warnings'], err_msg)

                if self.is_bdb_compiled():
                    result = wmulti0.addmultisigaddress(nrequired=2, keys=keys, address_type=addr_type)
                    assert_equal(legacy_addr, result['address'])
                    assert_equal(result['warnings'], err_msg)

        self.log.info('Testing sortedmulti descriptors with BIP 67 test vectors')

Review comment (suggestion):
Since > 20 keys are not allowed when creating a multisig address, recommend adding a test case to check this.

Something like:
```diff
diff --git a/test/functional/rpc_createmultisig.py b/test/functional/rpc_createmultisig.py
index 4bbd2a526d..88f4e44a65 100755
--- a/test/functional/rpc_createmultisig.py
+++ b/test/functional/rpc_createmultisig.py
@@ -129,6 +129,9 @@ class RpcCreateMultiSigTest(BitcoinTestFramework):
             res = self.nodes[0].createmultisig(nrequired=nkeys, keys=keys, address_type='bech32')
             assert_equal(res['redeemScript'], expected_ms_script.hex())
 
+        self.log.info('Check that number of keys greater than 20 is not allowed')
+        assert_raises_rpc_error(-8, "Number of keys involved in the multisignature address creation > 20", self.nodes[0].createmultisig, 20, [self.pub[0]]*21, "bech32")
+
     def check_addmultisigaddress_errors(self):
         if self.options.descriptors:
             return

```

Code after:
        self.generate(self.wallet, 149)

        wallet_multi = self.create_wallet(node1, 'wmulti') if self._requires_wallet else None
        self.create_keys(21)  # max number of allowed keys + 1
        m_of_n = [(2, 3), (3, 3), (2, 5), (3, 5), (10, 15), (15, 15)]
        for (sigs, keys) in m_of_n:
            for output_type in ["bech32", "p2sh-segwit", "legacy"]:
                self.do_multisig(keys, sigs, output_type, wallet_multi)

        self.test_multisig_script_limit(wallet_multi)
        self.test_mixing_uncompressed_and_compressed_keys(node0, wallet_multi)
        self.test_sortedmulti_descriptors_bip67()

        # Check that bech32m is currently not allowed
        assert_raises_rpc_error(-5, "createmultisig cannot create bech32m multisig addresses", self.nodes[0].createmultisig, 2, self.pub, "bech32m")

        self.log.info('Check correct encoding of multisig script for all n (1..20)')
        for nkeys in range(1, 20+1):
            keys = [self.pub[0]]*nkeys
            expected_ms_script = keys_to_multisig_script(keys, k=nkeys)  # simply use n-of-n
            # note that the 'legacy' address type fails for n values larger than 15
            # due to exceeding the P2SH size limit (520 bytes), so we use 'bech32' instead
            # (for the purpose of this encoding test, we don't care about the resulting address)
            res = self.nodes[0].createmultisig(nrequired=nkeys, keys=keys, address_type='bech32')
            assert_equal(res['redeemScript'], expected_ms_script.hex())

    def check_addmultisigaddress_errors(self):
        if self.options.descriptors:
            return
        self.log.info('Check that addmultisigaddress fails when the private keys are missing')
        addresses = [self.nodes[1].getnewaddress(address_type='legacy') for _ in range(2)]
        assert_raises_rpc_error(-5, 'no full public key for address', lambda: self.nodes[0].addmultisigaddress(nrequired=1, keys=addresses))
        for a in addresses:
            # Importing all addresses should not change the result
            self.nodes[0].importaddress(a)
        assert_raises_rpc_error(-5, 'no full public key for address', lambda: self.nodes[0].addmultisigaddress(nrequired=1, keys=addresses))

        # Bech32m address type is disallowed for legacy wallets
        pubs = [self.nodes[1].getaddressinfo(addr)["pubkey"] for addr in addresses]
        assert_raises_rpc_error(-5, "Bech32m multisig addresses cannot be created with legacy wallets", self.nodes[0].addmultisigaddress, 2, pubs, "", "bech32m")

    def test_multisig_script_limit(self, wallet_multi):
        node1 = self.nodes[1]
        pubkeys = self.pub[0:20]

        self.log.info('Test legacy redeem script max size limit')
        assert_raises_rpc_error(-8, "redeemScript exceeds size limit: 684 > 520", node1.createmultisig, 16, pubkeys, 'legacy')

        self.log.info('Test valid 16-20 multisig p2sh-legacy and bech32 (no wallet)')
        self.do_multisig(nkeys=20, nsigs=16, output_type="p2sh-segwit", wallet_multi=None)
        self.do_multisig(nkeys=20, nsigs=16, output_type="bech32", wallet_multi=None)