Exemplo n.º 1
0
    def prepare_wallets(self, wallet_basename, encrypt=False):
        self.nodes[0].createwallet(wallet_name=f"{wallet_basename}_base",
                                   descriptors=False,
                                   blank=True)
        self.nodes[0].createwallet(wallet_name=f"{wallet_basename}_test",
                                   descriptors=False,
                                   blank=True)
        base_wallet = self.nodes[0].get_wallet_rpc(f"{wallet_basename}_base")
        test_wallet = self.nodes[0].get_wallet_rpc(f"{wallet_basename}_test")

        # Setup both wallets with the same HD seed
        seed = get_generate_key()
        base_wallet.sethdseed(True, seed.privkey)
        test_wallet.sethdseed(True, seed.privkey)

        if encrypt:
            # Encrypting will generate a new HD seed and flush the keypool
            test_wallet.encryptwallet("pass")
        else:
            # Generate a new HD seed on the test wallet
            test_wallet.sethdseed()

        return base_wallet, test_wallet
Exemplo n.º 2
0
    def test_without_upgraded_keymeta(self):
        # Test that it is possible to top up inactive hd chains even if there is no key origin
        # in CKeyMetadata. This tests for the segfault reported in
        # https://github.com/bitcoin/bitcoin/issues/21605
        self.log.info(
            "Test that topping up inactive HD chains does not need upgraded key origin"
        )

        self.nodes[0].createwallet(wallet_name="keymeta_base",
                                   descriptors=False,
                                   blank=True)
        # Createwallet is overridden in the test framework so that the descriptor option can be filled
        # depending on the test's cli args. However we don't want to do that when using old nodes that
        # do not support descriptors. So we use the createwallet_passthrough function.
        self.nodes[1].createwallet_passthrough(wallet_name="keymeta_test")
        base_wallet = self.nodes[0].get_wallet_rpc("keymeta_base")
        test_wallet = self.nodes[1].get_wallet_rpc("keymeta_test")

        # Setup both wallets with the same HD seed
        seed = get_generate_key()
        base_wallet.sethdseed(True, seed.privkey)
        test_wallet.sethdseed(True, seed.privkey)

        # Encrypting will generate a new HD seed and flush the keypool
        test_wallet.encryptwallet("pass")

        # Copy test wallet to node 0
        test_wallet.unloadwallet()
        test_wallet_dir = os.path.join(self.nodes[1].datadir,
                                       "regtest/wallets/keymeta_test")
        new_test_wallet_dir = os.path.join(self.nodes[0].datadir,
                                           "regtest/wallets/keymeta_test")
        shutil.copytree(test_wallet_dir, new_test_wallet_dir)
        self.nodes[0].loadwallet("keymeta_test")
        test_wallet = self.nodes[0].get_wallet_rpc("keymeta_test")

        self.do_inactive_test(base_wallet, test_wallet, encrypt=True)
    def run_test(self):
        self.log.info('Setting up wallets')
        self.nodes[0].createwallet(wallet_name='w0',
                                   disable_private_keys=False,
                                   descriptors=True)
        w0 = self.nodes[0].get_wallet_rpc('w0')

        self.nodes[1].createwallet(wallet_name='w1',
                                   disable_private_keys=True,
                                   blank=True,
                                   descriptors=True)
        w1 = self.nodes[1].get_wallet_rpc('w1')
        assert_equal(w1.getwalletinfo()['keypoolsize'], 0)

        self.nodes[1].createwallet(wallet_name="wpriv",
                                   disable_private_keys=False,
                                   blank=True,
                                   descriptors=True)
        wpriv = self.nodes[1].get_wallet_rpc("wpriv")
        assert_equal(wpriv.getwalletinfo()['keypoolsize'], 0)

        self.log.info('Mining coins')
        w0.generatetoaddress(101, w0.getnewaddress())

        # RPC importdescriptors -----------------------------------------------

        # # Test import fails if no descriptor present
        key = get_generate_key()
        self.log.info("Import should fail if a descriptor is not provided")
        self.test_importdesc({"timestamp": "now"},
                             success=False,
                             error_code=-8,
                             error_message='Descriptor not found.')

        # # Test importing of a P2PKH descriptor
        key = get_generate_key()
        self.log.info("Should import a p2pkh descriptor")
        self.test_importdesc(
            {
                "desc": descsum_create("pkh(" + key.pubkey + ")"),
                "timestamp": "now",
                "label": "Descriptor import test"
            },
            success=True)
        test_address(w1,
                     key.p2pkh_addr,
                     solvable=True,
                     ismine=True,
                     labels=["Descriptor import test"])
        assert_equal(w1.getwalletinfo()['keypoolsize'], 0)

        self.log.info("Internal addresses cannot have labels")
        self.test_importdesc(
            {
                "desc": descsum_create("pkh(" + key.pubkey + ")"),
                "timestamp": "now",
                "internal": True,
                "label": "Descriptor import test"
            },
            success=False,
            error_code=-8,
            error_message="Internal addresses should not have a label")

        self.log.info("Internal addresses should be detected as such")
        key = get_generate_key()
        addr = key_to_p2pkh(key.pubkey)
        self.test_importdesc(
            {
                "desc": descsum_create("pkh(" + key.pubkey + ")"),
                "timestamp": "now",
                "internal": True
            },
            success=True)
        info = w1.getaddressinfo(addr)
        assert_equal(info["ismine"], True)
        assert_equal(info["ischange"], True)

        # # Test importing of a P2SH-P2WPKH descriptor
        key = get_generate_key()
        self.log.info(
            "Should not import a p2sh-p2wpkh descriptor without checksum")
        self.test_importdesc(
            {
                "desc": "sh(wpkh(" + key.pubkey + "))",
                "timestamp": "now"
            },
            success=False,
            error_code=-5,
            error_message="Missing checksum")

        self.log.info(
            "Should not import a p2sh-p2wpkh descriptor that has range specified"
        )
        self.test_importdesc(
            {
                "desc": descsum_create("sh(wpkh(" + key.pubkey + "))"),
                "timestamp": "now",
                "range": 1,
            },
            success=False,
            error_code=-8,
            error_message=
            "Range should not be specified for an un-ranged descriptor")

        self.log.info(
            "Should not import a p2sh-p2wpkh descriptor and have it set to active"
        )
        self.test_importdesc(
            {
                "desc": descsum_create("sh(wpkh(" + key.pubkey + "))"),
                "timestamp": "now",
                "active": True,
            },
            success=False,
            error_code=-8,
            error_message="Active descriptors must be ranged")

        self.log.info("Should import a (non-active) p2sh-p2wpkh descriptor")
        self.test_importdesc(
            {
                "desc": descsum_create("sh(wpkh(" + key.pubkey + "))"),
                "timestamp": "now",
                "active": False,
            },
            success=True)
        assert_equal(w1.getwalletinfo()['keypoolsize'], 0)

        test_address(w1, key.p2sh_p2wpkh_addr, ismine=True, solvable=True)

        # Check persistence of data and that loading works correctly
        w1.unloadwallet()
        self.nodes[1].loadwallet('w1')
        test_address(w1, key.p2sh_p2wpkh_addr, ismine=True, solvable=True)

        # # Test importing of a multisig descriptor
        key1 = get_generate_key()
        key2 = get_generate_key()
        self.log.info("Should import a 1-of-2 bare multisig from descriptor")
        self.test_importdesc(
            {
                "desc":
                descsum_create("multi(1," + key1.pubkey + "," + key2.pubkey +
                               ")"),
                "timestamp":
                "now"
            },
            success=True)
        self.log.info(
            "Should not treat individual keys from the imported bare multisig as watchonly"
        )
        test_address(w1, key1.p2pkh_addr, ismine=False)

        # # Test ranged descriptors
        xpriv = "tprv8ZgxMBicQKsPeuVhWwi6wuMQGfPKi9Li5GtX35jVNknACgqe3CY4g5xgkfDDJcmtF7o1QnxWDRYw4H5P26PXq7sbcUkEqeR4fg3Kxp2tigg"
        xpub = "tpubD6NzVbkrYhZ4YNXVQbNhMK1WqguFsUXceaVJKbmno2aZ3B6QfbMeraaYvnBSGpV3vxLyTTK9DYT1yoEck4XUScMzXoQ2U2oSmE2JyMedq3H"
        addresses = [
            "2N7yv4p8G8yEaPddJxY41kPihnWvs39qCMf",
            "2MsHxyb2JS3pAySeNUsJ7mNnurtpeenDzLA"
        ]  # hdkeypath=m/0'/0'/0' and 1'
        addresses += [
            "bcrt1qrd3n235cj2czsfmsuvqqpr3lu6lg0ju7scl8gn",
            "bcrt1qfqeppuvj0ww98r6qghmdkj70tv8qpchehegrg8"
        ]  # wpkh subscripts corresponding to the above addresses
        desc = "sh(wpkh(" + xpub + "/0/0/*" + "))"

        self.log.info("Ranged descriptors cannot have labels")
        self.test_importdesc(
            {
                "desc": descsum_create(desc),
                "timestamp": "now",
                "range": [0, 100],
                "label": "test"
            },
            success=False,
            error_code=-8,
            error_message='Ranged descriptors should not have a label')

        self.log.info("Private keys required for private keys enabled wallet")
        self.test_importdesc(
            {
                "desc": descsum_create(desc),
                "timestamp": "now",
                "range": [0, 100]
            },
            success=False,
            error_code=-4,
            error_message=
            'Cannot import descriptor without private keys to a wallet with private keys enabled',
            wallet=wpriv)

        self.log.info(
            "Ranged descriptor import should warn without a specified range")
        self.test_importdesc(
            {
                "desc": descsum_create(desc),
                "timestamp": "now"
            },
            success=True,
            warnings=['Range not given, using default keypool range'])
        assert_equal(w1.getwalletinfo()['keypoolsize'], 0)

        # # Test importing of a ranged descriptor with xpriv
        self.log.info(
            "Should not import a ranged descriptor that includes xpriv into a watch-only wallet"
        )
        desc = "sh(wpkh(" + xpriv + "/0'/0'/*'" + "))"
        self.test_importdesc(
            {
                "desc": descsum_create(desc),
                "timestamp": "now",
                "range": 1
            },
            success=False,
            error_code=-4,
            error_message=
            'Cannot import private keys to a wallet with private keys disabled'
        )

        self.log.info(
            "Should not import a descriptor with hardened derivations when private keys are disabled"
        )
        self.test_importdesc(
            {
                "desc": descsum_create("wpkh(" + xpub + "/1h/*)"),
                "timestamp": "now",
                "range": 1
            },
            success=False,
            error_code=-4,
            error_message=
            'Cannot expand descriptor. Probably because of hardened derivations without private keys provided'
        )

        for address in addresses:
            test_address(w1, address, ismine=False, solvable=False)

        self.test_importdesc(
            {
                "desc": descsum_create(desc),
                "timestamp": "now",
                "range": -1
            },
            success=False,
            error_code=-8,
            error_message='End of range is too high')

        self.test_importdesc(
            {
                "desc": descsum_create(desc),
                "timestamp": "now",
                "range": [-1, 10]
            },
            success=False,
            error_code=-8,
            error_message='Range should be greater or equal than 0')

        self.test_importdesc(
            {
                "desc": descsum_create(desc),
                "timestamp": "now",
                "range": [(2 << 31 + 1) - 1000000, (2 << 31 + 1)]
            },
            success=False,
            error_code=-8,
            error_message='End of range is too high')

        self.test_importdesc(
            {
                "desc": descsum_create(desc),
                "timestamp": "now",
                "range": [2, 1]
            },
            success=False,
            error_code=-8,
            error_message=
            'Range specified as [begin,end] must not have begin after end')

        self.test_importdesc(
            {
                "desc": descsum_create(desc),
                "timestamp": "now",
                "range": [0, 1000001]
            },
            success=False,
            error_code=-8,
            error_message='Range is too large')

        # Make sure ranged imports import keys in order
        w1 = self.nodes[1].get_wallet_rpc('w1')
        self.log.info('Key ranges should be imported in order')
        xpub = "tpubDAXcJ7s7ZwicqjprRaEWdPoHKrCS215qxGYxpusRLLmJuT69ZSicuGdSfyvyKpvUNYBW1s2U3NSrT6vrCYB9e6nZUEvrqnwXPF8ArTCRXMY"
        addresses = [
            'bcrt1qtmp74ayg7p24uslctssvjm06q5phz4yrxucgnv',  # m/0'/0'/0
            'bcrt1q8vprchan07gzagd5e6v9wd7azyucksq2xc76k8',  # m/0'/0'/1
            'bcrt1qtuqdtha7zmqgcrr26n2rqxztv5y8rafjp9lulu',  # m/0'/0'/2
            'bcrt1qau64272ymawq26t90md6an0ps99qkrse58m640',  # m/0'/0'/3
            'bcrt1qsg97266hrh6cpmutqen8s4s962aryy77jp0fg0',  # m/0'/0'/4
        ]

        self.test_importdesc(
            {
                'desc': descsum_create('wpkh([80002067/0h/0h]' + xpub + '/*)'),
                'active': True,
                'range': [0, 2],
                'timestamp': 'now'
            },
            success=True)
        self.test_importdesc(
            {
                'desc':
                descsum_create('sh(wpkh([abcdef12/0h/0h]' + xpub + '/*))'),
                'active': True,
                'range': [0, 2],
                'timestamp': 'now'
            },
            success=True)
        self.test_importdesc(
            {
                'desc': descsum_create('pkh([12345678/0h/0h]' + xpub + '/*)'),
                'active': True,
                'range': [0, 2],
                'timestamp': 'now'
            },
            success=True)

        assert_equal(w1.getwalletinfo()['keypoolsize'], 5 * 3)
        for i, expected_addr in enumerate(addresses):
            received_addr = w1.getnewaddress('', 'bech32')
            assert_raises_rpc_error(-4, 'This wallet has no available keys',
                                    w1.getrawchangeaddress, 'bech32')
            assert_equal(received_addr, expected_addr)
            bech32_addr_info = w1.getaddressinfo(received_addr)
            assert_equal(bech32_addr_info['desc'][:23],
                         'wpkh([80002067/0\'/0\'/{}]'.format(i))

            shwpkh_addr = w1.getnewaddress('', 'p2sh-segwit')
            shwpkh_addr_info = w1.getaddressinfo(shwpkh_addr)
            assert_equal(shwpkh_addr_info['desc'][:26],
                         'sh(wpkh([abcdef12/0\'/0\'/{}]'.format(i))

            pkh_addr = w1.getnewaddress('', 'legacy')
            pkh_addr_info = w1.getaddressinfo(pkh_addr)
            assert_equal(pkh_addr_info['desc'][:22],
                         'pkh([12345678/0\'/0\'/{}]'.format(i))

            assert_equal(
                w1.getwalletinfo()['keypoolsize'], 4 * 3
            )  # After retrieving a key, we don't refill the keypool again, so it's one less for each address type
        w1.keypoolrefill()
        assert_equal(w1.getwalletinfo()['keypoolsize'], 5 * 3)

        # Check active=False default
        self.log.info('Check imported descriptors are not active by default')
        self.test_importdesc(
            {
                'desc': descsum_create('pkh([12345678/0h/0h]' + xpub + '/*)'),
                'range': [0, 2],
                'timestamp': 'now',
                'internal': True
            },
            success=True)
        assert_raises_rpc_error(-4, 'This wallet has no available keys',
                                w1.getrawchangeaddress, 'legacy')

        # # Test importing a descriptor containing a WIF private key
        wif_priv = "cTe1f5rdT8A8DFgVWTjyPwACsDPJM9ff4QngFxUixCSvvbg1x6sh"
        address = "2MuhcG52uHPknxDgmGPsV18jSHFBnnRgjPg"
        desc = "sh(wpkh(" + wif_priv + "))"
        self.log.info(
            "Should import a descriptor with a WIF private key as spendable")
        self.test_importdesc({
            "desc": descsum_create(desc),
            "timestamp": "now"
        },
                             success=True,
                             wallet=wpriv)
        test_address(wpriv, address, solvable=True, ismine=True)
        txid = w0.sendtoaddress(address, 49.99995540)
        w0.generatetoaddress(6, w0.getnewaddress())
        self.sync_blocks()
        tx = wpriv.createrawtransaction([{
            "txid": txid,
            "vout": 0
        }], {w0.getnewaddress(): 49.999})
        signed_tx = wpriv.signrawtransactionwithwallet(tx)
        w1.sendrawtransaction(signed_tx['hex'])

        # Make sure that we can use import and use multisig as addresses
        self.log.info(
            'Test that multisigs can be imported, signed for, and getnewaddress\'d'
        )
        self.nodes[1].createwallet(wallet_name="wmulti_priv",
                                   disable_private_keys=False,
                                   blank=True,
                                   descriptors=True)
        wmulti_priv = self.nodes[1].get_wallet_rpc("wmulti_priv")
        assert_equal(wmulti_priv.getwalletinfo()['keypoolsize'], 0)

        self.test_importdesc(
            {
                "desc":
                "wsh(multi(2,tprv8ZgxMBicQKsPevADjDCWsa6DfhkVXicu8NQUzfibwX2MexVwW4tCec5mXdCW8kJwkzBRRmAay1KZya4WsehVvjTGVW6JLqiqd8DdZ4xSg52/84h/0h/0h/*,tprv8ZgxMBicQKsPdSNWUhDiwTScDr6JfkZuLshTRwzvZGnMSnGikV6jxpmdDkC3YRc4T3GD6Nvg9uv6hQg73RVv1EiTXDZwxVbsLugVHU8B1aq/84h/0h/0h/*,tprv8ZgxMBicQKsPeonDt8Ka2mrQmHa61hQ5FQCsvWBTpSNzBFgM58cV2EuXNAHF14VawVpznnme3SuTbA62sGriwWyKifJmXntfNeK7zeqMCj1/84h/0h/0h/*))#m2sr93jn",
                "active": True,
                "range": 1000,
                "next_index": 0,
                "timestamp": "now"
            },
            success=True,
            wallet=wmulti_priv)
        self.test_importdesc(
            {
                "desc":
                "wsh(multi(2,tprv8ZgxMBicQKsPevADjDCWsa6DfhkVXicu8NQUzfibwX2MexVwW4tCec5mXdCW8kJwkzBRRmAay1KZya4WsehVvjTGVW6JLqiqd8DdZ4xSg52/84h/1h/0h/*,tprv8ZgxMBicQKsPdSNWUhDiwTScDr6JfkZuLshTRwzvZGnMSnGikV6jxpmdDkC3YRc4T3GD6Nvg9uv6hQg73RVv1EiTXDZwxVbsLugVHU8B1aq/84h/1h/0h/*,tprv8ZgxMBicQKsPeonDt8Ka2mrQmHa61hQ5FQCsvWBTpSNzBFgM58cV2EuXNAHF14VawVpznnme3SuTbA62sGriwWyKifJmXntfNeK7zeqMCj1/84h/1h/0h/*))#q3sztvx5",
                "active": True,
                "internal": True,
                "range": 1000,
                "next_index": 0,
                "timestamp": "now"
            },
            success=True,
            wallet=wmulti_priv)

        assert_equal(
            wmulti_priv.getwalletinfo()['keypoolsize'],
            1001)  # Range end (1000) is inclusive, so 1001 addresses generated
        addr = wmulti_priv.getnewaddress('', 'bech32')
        assert_equal(
            addr,
            'bcrt1qdt0qy5p7dzhxzmegnn4ulzhard33s2809arjqgjndx87rv5vd0fq2czhy8'
        )  # Derived at m/84'/0'/0'/0
        change_addr = wmulti_priv.getrawchangeaddress('bech32')
        assert_equal(
            change_addr,
            'bcrt1qt9uhe3a9hnq7vajl7a094z4s3crm9ttf8zw3f5v9gr2nyd7e3lnsy44n8e')
        assert_equal(wmulti_priv.getwalletinfo()['keypoolsize'], 1000)
        txid = w0.sendtoaddress(addr, 10)
        self.nodes[0].generate(6)
        self.sync_all()
        send_txid = wmulti_priv.sendtoaddress(w0.getnewaddress(), 8)
        decoded = wmulti_priv.decoderawtransaction(
            wmulti_priv.gettransaction(send_txid)['hex'])
        assert_equal(len(decoded['vin'][0]['txinwitness']), 4)
        self.nodes[0].generate(6)
        self.sync_all()

        self.nodes[1].createwallet(wallet_name="wmulti_pub",
                                   disable_private_keys=True,
                                   blank=True,
                                   descriptors=True)
        wmulti_pub = self.nodes[1].get_wallet_rpc("wmulti_pub")
        assert_equal(wmulti_pub.getwalletinfo()['keypoolsize'], 0)

        self.test_importdesc(
            {
                "desc":
                "wsh(multi(2,[7b2d0242/84h/0h/0h]tpubDCJtdt5dgJpdhW4MtaVYDhG4T4tF6jcLR1PxL43q9pq1mxvXgMS9Mzw1HnXG15vxUGQJMMSqCQHMTy3F1eW5VkgVroWzchsPD5BUojrcWs8/*,[59b09cd6/84h/0h/0h]tpubDDBF2BTR6s8drwrfDei8WxtckGuSm1cyoKxYY1QaKSBFbHBYQArWhHPA6eJrzZej6nfHGLSURYSLHr7GuYch8aY5n61tGqgn8b4cXrMuoPH/*,[e81a0532/84h/0h/0h]tpubDCsWoW1kuQB9kG5MXewHqkbjPtqPueRnXju7uM2NK7y3JYb2ajAZ9EiuZXNNuE4661RAfriBWhL8UsnAPpk8zrKKnZw1Ug7X4oHgMdZiU4E/*))#tsry0s5e",
                "active": True,
                "range": 1000,
                "next_index": 0,
                "timestamp": "now"
            },
            success=True,
            wallet=wmulti_pub)
        self.test_importdesc(
            {
                "desc":
                "wsh(multi(2,[7b2d0242/84h/1h/0h]tpubDCXqdwWZcszwqYJSnZp8eARkxGJfHAk23KDxbztV4BbschfaTfYLTcSkSJ3TN64dRqwa1rnFUScsYormKkGqNbbPwkorQimVevXjxzUV9Gf/*,[59b09cd6/84h/1h/0h]tpubDCYfZY2ceyHzYzMMVPt9MNeiqtQ2T7Uyp9QSFwYXh8Vi9iJFYXcuphJaGXfF3jUQJi5Y3GMNXvM11gaL4txzZgNGK22BFAwMXynnzv4z2Jh/*,[e81a0532/84h/1h/0h]tpubDC6UGqnsQStngYuGD4MKsMy7eD1Yg9NTJfPdvjdG2JE5oZ7EsSL3WHg4Gsw2pR5K39ZwJ46M1wZayhedVdQtMGaUhq5S23PH6fnENK3V1sb/*))#c08a2rzv",
                "active": True,
                "internal": True,
                "range": 1000,
                "next_index": 0,
                "timestamp": "now"
            },
            success=True,
            wallet=wmulti_pub)

        assert_equal(
            wmulti_pub.getwalletinfo()['keypoolsize'], 1000
        )  # The first one was already consumed by previous import and is detected as used
        addr = wmulti_pub.getnewaddress('', 'bech32')
        assert_equal(
            addr,
            'bcrt1qp8s25ckjl7gr6x2q3dx3tn2pytwp05upkjztk6ey857tt50r5aeqn6mvr9'
        )  # Derived at m/84'/0'/0'/1
        change_addr = wmulti_pub.getrawchangeaddress('bech32')
        assert_equal(
            change_addr,
            'bcrt1qt9uhe3a9hnq7vajl7a094z4s3crm9ttf8zw3f5v9gr2nyd7e3lnsy44n8e')
        assert_equal(wmulti_pub.getwalletinfo()['keypoolsize'], 999)
        txid = w0.sendtoaddress(addr, 10)
        vout = find_vout_for_address(self.nodes[0], txid, addr)
        self.nodes[0].generate(6)
        self.sync_all()
        assert_equal(wmulti_pub.getbalance(), wmulti_priv.getbalance())

        # Make sure that descriptor wallets containing multiple xpubs in a single descriptor load correctly
        wmulti_pub.unloadwallet()
        self.nodes[1].loadwallet('wmulti_pub')

        self.log.info("Multisig with distributed keys")
        self.nodes[1].createwallet(wallet_name="wmulti_priv1",
                                   descriptors=True)
        wmulti_priv1 = self.nodes[1].get_wallet_rpc("wmulti_priv1")
        res = wmulti_priv1.importdescriptors([{
            "desc":
            descsum_create(
                "wsh(multi(2,tprv8ZgxMBicQKsPevADjDCWsa6DfhkVXicu8NQUzfibwX2MexVwW4tCec5mXdCW8kJwkzBRRmAay1KZya4WsehVvjTGVW6JLqiqd8DdZ4xSg52/84h/0h/0h/*,[59b09cd6/84h/0h/0h]tpubDDBF2BTR6s8drwrfDei8WxtckGuSm1cyoKxYY1QaKSBFbHBYQArWhHPA6eJrzZej6nfHGLSURYSLHr7GuYch8aY5n61tGqgn8b4cXrMuoPH/*,[e81a0532/84h/0h/0h]tpubDCsWoW1kuQB9kG5MXewHqkbjPtqPueRnXju7uM2NK7y3JYb2ajAZ9EiuZXNNuE4661RAfriBWhL8UsnAPpk8zrKKnZw1Ug7X4oHgMdZiU4E/*))"
            ),
            "active":
            True,
            "range":
            1000,
            "next_index":
            0,
            "timestamp":
            "now"
        }, {
            "desc":
            descsum_create(
                "wsh(multi(2,tprv8ZgxMBicQKsPevADjDCWsa6DfhkVXicu8NQUzfibwX2MexVwW4tCec5mXdCW8kJwkzBRRmAay1KZya4WsehVvjTGVW6JLqiqd8DdZ4xSg52/84h/1h/0h/*,[59b09cd6/84h/1h/0h]tpubDCYfZY2ceyHzYzMMVPt9MNeiqtQ2T7Uyp9QSFwYXh8Vi9iJFYXcuphJaGXfF3jUQJi5Y3GMNXvM11gaL4txzZgNGK22BFAwMXynnzv4z2Jh/*,[e81a0532/84h/1h/0h]tpubDC6UGqnsQStngYuGD4MKsMy7eD1Yg9NTJfPdvjdG2JE5oZ7EsSL3WHg4Gsw2pR5K39ZwJ46M1wZayhedVdQtMGaUhq5S23PH6fnENK3V1sb/*))"
            ),
            "active":
            True,
            "internal":
            True,
            "range":
            1000,
            "next_index":
            0,
            "timestamp":
            "now"
        }])
        assert_equal(res[0]['success'], True)
        assert_equal(
            res[0]['warnings'][0],
            'Not all private keys provided. Some wallet functionality may return unexpected errors'
        )
        assert_equal(res[1]['success'], True)
        assert_equal(
            res[1]['warnings'][0],
            'Not all private keys provided. Some wallet functionality may return unexpected errors'
        )

        self.nodes[1].createwallet(wallet_name='wmulti_priv2',
                                   blank=True,
                                   descriptors=True)
        wmulti_priv2 = self.nodes[1].get_wallet_rpc('wmulti_priv2')
        res = wmulti_priv2.importdescriptors([{
            "desc":
            descsum_create(
                "wsh(multi(2,[7b2d0242/84h/0h/0h]tpubDCJtdt5dgJpdhW4MtaVYDhG4T4tF6jcLR1PxL43q9pq1mxvXgMS9Mzw1HnXG15vxUGQJMMSqCQHMTy3F1eW5VkgVroWzchsPD5BUojrcWs8/*,tprv8ZgxMBicQKsPdSNWUhDiwTScDr6JfkZuLshTRwzvZGnMSnGikV6jxpmdDkC3YRc4T3GD6Nvg9uv6hQg73RVv1EiTXDZwxVbsLugVHU8B1aq/84h/0h/0h/*,[e81a0532/84h/0h/0h]tpubDCsWoW1kuQB9kG5MXewHqkbjPtqPueRnXju7uM2NK7y3JYb2ajAZ9EiuZXNNuE4661RAfriBWhL8UsnAPpk8zrKKnZw1Ug7X4oHgMdZiU4E/*))"
            ),
            "active":
            True,
            "range":
            1000,
            "next_index":
            0,
            "timestamp":
            "now"
        }, {
            "desc":
            descsum_create(
                "wsh(multi(2,[7b2d0242/84h/1h/0h]tpubDCXqdwWZcszwqYJSnZp8eARkxGJfHAk23KDxbztV4BbschfaTfYLTcSkSJ3TN64dRqwa1rnFUScsYormKkGqNbbPwkorQimVevXjxzUV9Gf/*,tprv8ZgxMBicQKsPdSNWUhDiwTScDr6JfkZuLshTRwzvZGnMSnGikV6jxpmdDkC3YRc4T3GD6Nvg9uv6hQg73RVv1EiTXDZwxVbsLugVHU8B1aq/84h/1h/0h/*,[e81a0532/84h/1h/0h]tpubDC6UGqnsQStngYuGD4MKsMy7eD1Yg9NTJfPdvjdG2JE5oZ7EsSL3WHg4Gsw2pR5K39ZwJ46M1wZayhedVdQtMGaUhq5S23PH6fnENK3V1sb/*))"
            ),
            "active":
            True,
            "internal":
            True,
            "range":
            1000,
            "next_index":
            0,
            "timestamp":
            "now"
        }])
        assert_equal(res[0]['success'], True)
        assert_equal(
            res[0]['warnings'][0],
            'Not all private keys provided. Some wallet functionality may return unexpected errors'
        )
        assert_equal(res[1]['success'], True)
        assert_equal(
            res[1]['warnings'][0],
            'Not all private keys provided. Some wallet functionality may return unexpected errors'
        )

        rawtx = self.nodes[1].createrawtransaction([{
            'txid': txid,
            'vout': vout
        }], {w0.getnewaddress(): 9.999})
        tx_signed_1 = wmulti_priv1.signrawtransactionwithwallet(rawtx)
        assert_equal(tx_signed_1['complete'], False)
        tx_signed_2 = wmulti_priv2.signrawtransactionwithwallet(
            tx_signed_1['hex'])
        assert_equal(tx_signed_2['complete'], True)
        self.nodes[1].sendrawtransaction(tx_signed_2['hex'])

        self.log.info("We can create and use a huge multisig under P2WSH")
        self.nodes[1].createwallet(wallet_name='wmulti_priv_big',
                                   blank=True,
                                   descriptors=True)
        wmulti_priv_big = self.nodes[1].get_wallet_rpc('wmulti_priv_big')
        xkey = "tprv8ZgxMBicQKsPeZSeYx7VXDDTs3XrTcmZQpRLbAeSQFCQGgKwR4gKpcxHaKdoTNHniv4EPDJNdzA3KxRrrBHcAgth8fU5X4oCndkkxk39iAt/*"
        xkey_int = "tprv8ZgxMBicQKsPeZSeYx7VXDDTs3XrTcmZQpRLbAeSQFCQGgKwR4gKpcxHaKdoTNHniv4EPDJNdzA3KxRrrBHcAgth8fU5X4oCndkkxk39iAt/1/*"
        res = wmulti_priv_big.importdescriptors([{
            "desc":
            descsum_create(f"wsh(sortedmulti(20,{(xkey + ',') * 19}{xkey}))"),
            "active":
            True,
            "range":
            1000,
            "next_index":
            0,
            "timestamp":
            "now"
        }, {
            "desc":
            descsum_create(
                f"wsh(sortedmulti(20,{(xkey_int + ',') * 19}{xkey_int}))"),
            "active":
            True,
            "internal":
            True,
            "range":
            1000,
            "next_index":
            0,
            "timestamp":
            "now"
        }])
        assert_equal(res[0]['success'], True)
        assert_equal(res[1]['success'], True)

        addr = wmulti_priv_big.getnewaddress()
        w0.sendtoaddress(addr, 10)
        self.nodes[0].generate(1)
        self.sync_all()
        # It is standard and would relay.
        txid = wmulti_priv_big.sendtoaddress(w0.getnewaddress(), 9.999)
        decoded = wmulti_priv_big.decoderawtransaction(
            wmulti_priv_big.gettransaction(txid)['hex'])
        # 20 sigs + dummy + witness script
        assert_equal(len(decoded['vin'][0]['txinwitness']), 22)

        self.log.info("Under P2SH, multisig are standard with up to 15 "
                      "compressed keys")
        self.nodes[1].createwallet(wallet_name='multi_priv_big_legacy',
                                   blank=True,
                                   descriptors=True)
        multi_priv_big = self.nodes[1].get_wallet_rpc('multi_priv_big_legacy')
        res = multi_priv_big.importdescriptors([{
            "desc":
            descsum_create(f"sh(multi(15,{(xkey + ',') * 14}{xkey}))"),
            "active":
            True,
            "range":
            1000,
            "next_index":
            0,
            "timestamp":
            "now"
        }, {
            "desc":
            descsum_create(f"sh(multi(15,{(xkey_int + ',') * 14}{xkey_int}))"),
            "active":
            True,
            "internal":
            True,
            "range":
            1000,
            "next_index":
            0,
            "timestamp":
            "now"
        }])
        assert_equal(res[0]['success'], True)
        assert_equal(res[1]['success'], True)

        addr = multi_priv_big.getnewaddress("", "legacy")
        w0.sendtoaddress(addr, 10)
        self.nodes[0].generate(6)
        self.sync_all()
        # It is standard and would relay.
        txid = multi_priv_big.sendtoaddress(w0.getnewaddress(), 10, "", "",
                                            True)
        decoded = multi_priv_big.decoderawtransaction(
            multi_priv_big.gettransaction(txid)['hex'])

        self.log.info("Combo descriptors cannot be active")
        self.test_importdesc(
            {
                "desc":
                descsum_create(
                    "combo(tpubDCJtdt5dgJpdhW4MtaVYDhG4T4tF6jcLR1PxL43q9pq1mxvXgMS9Mzw1HnXG15vxUGQJMMSqCQHMTy3F1eW5VkgVroWzchsPD5BUojrcWs8/*)"
                ),
                "active":
                True,
                "range":
                1,
                "timestamp":
                "now"
            },
            success=False,
            error_code=-4,
            error_message="Combo descriptors cannot be set to active")

        self.log.info("Descriptors with no type cannot be active")
        self.test_importdesc(
            {
                "desc":
                descsum_create(
                    "pk(tpubDCJtdt5dgJpdhW4MtaVYDhG4T4tF6jcLR1PxL43q9pq1mxvXgMS9Mzw1HnXG15vxUGQJMMSqCQHMTy3F1eW5VkgVroWzchsPD5BUojrcWs8/*)"
                ),
                "active":
                True,
                "range":
                1,
                "timestamp":
                "now"
            },
            success=True,
            warnings=["Unknown output type, cannot set descriptor to active."])
Exemplo n.º 4
0
    def run_test(self):
        self.generate(self.nodes[0], 161)  # block 161

        self.log.info("Verify sigops are counted in GBT with pre-BIP141 rules before the fork")
        txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1)
        tmpl = self.nodes[0].getblocktemplate({'rules': ['segwit']})
        assert_equal(tmpl['sizelimit'], 1000000)
        assert 'weightlimit' not in tmpl
        assert_equal(tmpl['sigoplimit'], 20000)
        assert_equal(tmpl['transactions'][0]['hash'], txid)
        assert_equal(tmpl['transactions'][0]['sigops'], 2)
        assert '!segwit' not in tmpl['rules']
        self.generate(self.nodes[0], 1)  # block 162

        balance_presetup = self.nodes[0].getbalance()
        self.pubkey = []
        p2sh_ids = []  # p2sh_ids[NODE][TYPE] is an array of txids that spend to P2WPKH (TYPE=0) or P2WSH (TYPE=1) scripts to an address for NODE embedded in p2sh
        wit_ids = []  # wit_ids[NODE][TYPE] is an array of txids that spend to P2WPKH (TYPE=0) or P2WSH (TYPE=1) scripts to an address for NODE via bare witness
        for i in range(3):
            key = get_generate_key()
            self.pubkey.append(key.pubkey)

            multiscript = keys_to_multisig_script([self.pubkey[-1]])
            p2sh_ms_addr = self.nodes[i].createmultisig(1, [self.pubkey[-1]], 'p2sh-segwit')['address']
            bip173_ms_addr = self.nodes[i].createmultisig(1, [self.pubkey[-1]], 'bech32')['address']
            assert_equal(p2sh_ms_addr, script_to_p2sh_p2wsh(multiscript))
            assert_equal(bip173_ms_addr, script_to_p2wsh(multiscript))

            p2sh_ms_desc = descsum_create(f"sh(wsh(multi(1,{key.privkey})))")
            bip173_ms_desc = descsum_create(f"wsh(multi(1,{key.privkey}))")
            assert_equal(self.nodes[i].deriveaddresses(p2sh_ms_desc)[0], p2sh_ms_addr)
            assert_equal(self.nodes[i].deriveaddresses(bip173_ms_desc)[0], bip173_ms_addr)

            sh_wpkh_desc = descsum_create(f"sh(wpkh({key.privkey}))")
            wpkh_desc = descsum_create(f"wpkh({key.privkey})")
            assert_equal(self.nodes[i].deriveaddresses(sh_wpkh_desc)[0], key.p2sh_p2wpkh_addr)
            assert_equal(self.nodes[i].deriveaddresses(wpkh_desc)[0], key.p2wpkh_addr)

            if self.options.descriptors:
                res = self.nodes[i].importdescriptors([
                {"desc": p2sh_ms_desc, "timestamp": "now"},
                {"desc": bip173_ms_desc, "timestamp": "now"},
                {"desc": sh_wpkh_desc, "timestamp": "now"},
                {"desc": wpkh_desc, "timestamp": "now"},
            ])
            else:
                # The nature of the legacy wallet is that this import results in also adding all of the necessary scripts
                res = self.nodes[i].importmulti([
                    {"desc": p2sh_ms_desc, "timestamp": "now"},
                ])
            assert all([r["success"] for r in res])

            p2sh_ids.append([])
            wit_ids.append([])
            for _ in range(2):
                p2sh_ids[i].append([])
                wit_ids[i].append([])

        for _ in range(5):
            for n in range(3):
                for v in range(2):
                    wit_ids[n][v].append(send_to_witness(v, self.nodes[0], find_spendable_utxo(self.nodes[0], 50), self.pubkey[n], False, Decimal("49.999")))
                    p2sh_ids[n][v].append(send_to_witness(v, self.nodes[0], find_spendable_utxo(self.nodes[0], 50), self.pubkey[n], True, Decimal("49.999")))

        self.generate(self.nodes[0], 1)  # block 163

        # Make sure all nodes recognize the transactions as theirs
        assert_equal(self.nodes[0].getbalance(), balance_presetup - 60 * 50 + 20 * Decimal("49.999") + 50)
        assert_equal(self.nodes[1].getbalance(), 20 * Decimal("49.999"))
        assert_equal(self.nodes[2].getbalance(), 20 * Decimal("49.999"))

        self.log.info("Verify unsigned p2sh witness txs without a redeem script are invalid")
        self.fail_accept(self.nodes[2], "mandatory-script-verify-flag-failed (Operation not valid with the current stack size)", p2sh_ids[NODE_2][P2WPKH][1], sign=False)
        self.fail_accept(self.nodes[2], "mandatory-script-verify-flag-failed (Operation not valid with the current stack size)", p2sh_ids[NODE_2][P2WSH][1], sign=False)

        self.generate(self.nodes[0], 1)  # block 164

        self.log.info("Verify witness txs are mined as soon as segwit activates")

        send_to_witness(1, self.nodes[2], getutxo(wit_ids[NODE_2][P2WPKH][0]), self.pubkey[0], encode_p2sh=False, amount=Decimal("49.998"), sign=True)
        send_to_witness(1, self.nodes[2], getutxo(wit_ids[NODE_2][P2WSH][0]), self.pubkey[0], encode_p2sh=False, amount=Decimal("49.998"), sign=True)
        send_to_witness(1, self.nodes[2], getutxo(p2sh_ids[NODE_2][P2WPKH][0]), self.pubkey[0], encode_p2sh=False, amount=Decimal("49.998"), sign=True)
        send_to_witness(1, self.nodes[2], getutxo(p2sh_ids[NODE_2][P2WSH][0]), self.pubkey[0], encode_p2sh=False, amount=Decimal("49.998"), sign=True)

        assert_equal(len(self.nodes[2].getrawmempool()), 4)
        blockhash = self.generate(self.nodes[2], 1)[0]  # block 165 (first block with new rules)
        assert_equal(len(self.nodes[2].getrawmempool()), 0)
        segwit_tx_list = self.nodes[2].getblock(blockhash)["tx"]
        assert_equal(len(segwit_tx_list), 5)

        self.log.info("Verify default node can't accept txs with missing witness")
        # unsigned, no scriptsig
        self.fail_accept(self.nodes[0], "non-mandatory-script-verify-flag (Witness program hash mismatch)", wit_ids[NODE_0][P2WPKH][0], sign=False)
        self.fail_accept(self.nodes[0], "non-mandatory-script-verify-flag (Witness program was passed an empty witness)", wit_ids[NODE_0][P2WSH][0], sign=False)
        self.fail_accept(self.nodes[0], "mandatory-script-verify-flag-failed (Operation not valid with the current stack size)", p2sh_ids[NODE_0][P2WPKH][0], sign=False)
        self.fail_accept(self.nodes[0], "mandatory-script-verify-flag-failed (Operation not valid with the current stack size)", p2sh_ids[NODE_0][P2WSH][0], sign=False)
        # unsigned with redeem script
        self.fail_accept(self.nodes[0], "non-mandatory-script-verify-flag (Witness program hash mismatch)", p2sh_ids[NODE_0][P2WPKH][0], sign=False, redeem_script=witness_script(False, self.pubkey[0]))
        self.fail_accept(self.nodes[0], "non-mandatory-script-verify-flag (Witness program was passed an empty witness)", p2sh_ids[NODE_0][P2WSH][0], sign=False, redeem_script=witness_script(True, self.pubkey[0]))

        self.log.info("Verify block and transaction serialization rpcs return differing serializations depending on rpc serialization flag")
        assert self.nodes[2].getblock(blockhash, False) != self.nodes[0].getblock(blockhash, False)
        assert self.nodes[1].getblock(blockhash, False) == self.nodes[2].getblock(blockhash, False)

        for tx_id in segwit_tx_list:
            tx = tx_from_hex(self.nodes[2].gettransaction(tx_id)["hex"])
            assert self.nodes[2].getrawtransaction(tx_id, False, blockhash) != self.nodes[0].getrawtransaction(tx_id, False, blockhash)
            assert self.nodes[1].getrawtransaction(tx_id, False, blockhash) == self.nodes[2].getrawtransaction(tx_id, False, blockhash)
            assert self.nodes[0].getrawtransaction(tx_id, False, blockhash) != self.nodes[2].gettransaction(tx_id)["hex"]
            assert self.nodes[1].getrawtransaction(tx_id, False, blockhash) == self.nodes[2].gettransaction(tx_id)["hex"]
            assert self.nodes[0].getrawtransaction(tx_id, False, blockhash) == tx.serialize_without_witness().hex()

        # Coinbase contains the witness commitment nonce, check that RPC shows us
        coinbase_txid = self.nodes[2].getblock(blockhash)['tx'][0]
        coinbase_tx = self.nodes[2].gettransaction(txid=coinbase_txid, verbose=True)
        witnesses = coinbase_tx["decoded"]["vin"][0]["txinwitness"]
        assert_equal(len(witnesses), 1)
        assert_is_hex_string(witnesses[0])
        assert_equal(witnesses[0], '00' * 32)

        self.log.info("Verify witness txs without witness data are invalid after the fork")
        self.fail_accept(self.nodes[2], 'non-mandatory-script-verify-flag (Witness program hash mismatch)', wit_ids[NODE_2][P2WPKH][2], sign=False)
        self.fail_accept(self.nodes[2], 'non-mandatory-script-verify-flag (Witness program was passed an empty witness)', wit_ids[NODE_2][P2WSH][2], sign=False)
        self.fail_accept(self.nodes[2], 'non-mandatory-script-verify-flag (Witness program hash mismatch)', p2sh_ids[NODE_2][P2WPKH][2], sign=False, redeem_script=witness_script(False, self.pubkey[2]))
        self.fail_accept(self.nodes[2], 'non-mandatory-script-verify-flag (Witness program was passed an empty witness)', p2sh_ids[NODE_2][P2WSH][2], sign=False, redeem_script=witness_script(True, self.pubkey[2]))

        self.log.info("Verify default node can now use witness txs")
        self.success_mine(self.nodes[0], wit_ids[NODE_0][P2WPKH][0], True)
        self.success_mine(self.nodes[0], wit_ids[NODE_0][P2WSH][0], True)
        self.success_mine(self.nodes[0], p2sh_ids[NODE_0][P2WPKH][0], True)
        self.success_mine(self.nodes[0], p2sh_ids[NODE_0][P2WSH][0], True)

        self.log.info("Verify sigops are counted in GBT with BIP141 rules after the fork")
        txid = self.nodes[0].sendtoaddress(self.nodes[0].getnewaddress(), 1)
        raw_tx = self.nodes[0].getrawtransaction(txid, True)
        tmpl = self.nodes[0].getblocktemplate({'rules': ['segwit']})
        assert_greater_than_or_equal(tmpl['sizelimit'], 3999577)  # actual maximum size is lower due to minimum mandatory non-witness data
        assert_equal(tmpl['weightlimit'], 4000000)
        assert_equal(tmpl['sigoplimit'], 80000)
        assert_equal(tmpl['transactions'][0]['txid'], txid)
        expected_sigops = 9 if 'txinwitness' in raw_tx["vin"][0] else 8
        assert_equal(tmpl['transactions'][0]['sigops'], expected_sigops)
        assert '!segwit' in tmpl['rules']

        self.generate(self.nodes[0], 1)  # Mine a block to clear the gbt cache

        self.log.info("Non-segwit miners are able to use GBT response after activation.")
        # Create a 3-tx chain: tx1 (non-segwit input, paying to a segwit output) ->
        #                      tx2 (segwit input, paying to a non-segwit output) ->
        #                      tx3 (non-segwit input, paying to a non-segwit output).
        # tx1 is allowed to appear in the block, but no others.
        txid1 = send_to_witness(1, self.nodes[0], find_spendable_utxo(self.nodes[0], 50), self.pubkey[0], False, Decimal("49.996"))
        hex_tx = self.nodes[0].gettransaction(txid)['hex']
        tx = tx_from_hex(hex_tx)
        assert tx.wit.is_null()  # This should not be a segwit input
        assert txid1 in self.nodes[0].getrawmempool()

        tx1_hex = self.nodes[0].gettransaction(txid1)['hex']
        tx1 = tx_from_hex(tx1_hex)

        # Check that wtxid is properly reported in mempool entry (txid1)
        assert_equal(int(self.nodes[0].getmempoolentry(txid1)["wtxid"], 16), tx1.calc_sha256(True))

        # Check that weight and vsize are properly reported in mempool entry (txid1)
        assert_equal(self.nodes[0].getmempoolentry(txid1)["vsize"], tx1.get_vsize())
        assert_equal(self.nodes[0].getmempoolentry(txid1)["weight"], tx1.get_weight())

        # Now create tx2, which will spend from txid1.
        tx = CTransaction()
        tx.vin.append(CTxIn(COutPoint(int(txid1, 16), 0), b''))
        tx.vout.append(CTxOut(int(49.99 * COIN), CScript([OP_TRUE, OP_DROP] * 15 + [OP_TRUE])))
        tx2_hex = self.nodes[0].signrawtransactionwithwallet(tx.serialize().hex())['hex']
        txid2 = self.nodes[0].sendrawtransaction(tx2_hex)
        tx = tx_from_hex(tx2_hex)
        assert not tx.wit.is_null()

        # Check that wtxid is properly reported in mempool entry (txid2)
        assert_equal(int(self.nodes[0].getmempoolentry(txid2)["wtxid"], 16), tx.calc_sha256(True))

        # Check that weight and vsize are properly reported in mempool entry (txid2)
        assert_equal(self.nodes[0].getmempoolentry(txid2)["vsize"], tx.get_vsize())
        assert_equal(self.nodes[0].getmempoolentry(txid2)["weight"], tx.get_weight())

        # Now create tx3, which will spend from txid2
        tx = CTransaction()
        tx.vin.append(CTxIn(COutPoint(int(txid2, 16), 0), b""))
        tx.vout.append(CTxOut(int(49.95 * COIN), CScript([OP_TRUE, OP_DROP] * 15 + [OP_TRUE])))  # Huge fee
        tx.calc_sha256()
        txid3 = self.nodes[0].sendrawtransaction(hexstring=tx.serialize().hex(), maxfeerate=0)
        assert tx.wit.is_null()
        assert txid3 in self.nodes[0].getrawmempool()

        # Check that getblocktemplate includes all transactions.
        template = self.nodes[0].getblocktemplate({"rules": ["segwit"]})
        template_txids = [t['txid'] for t in template['transactions']]
        assert txid1 in template_txids
        assert txid2 in template_txids
        assert txid3 in template_txids

        # Check that wtxid is properly reported in mempool entry (txid3)
        assert_equal(int(self.nodes[0].getmempoolentry(txid3)["wtxid"], 16), tx.calc_sha256(True))

        # Check that weight and vsize are properly reported in mempool entry (txid3)
        assert_equal(self.nodes[0].getmempoolentry(txid3)["vsize"], tx.get_vsize())
        assert_equal(self.nodes[0].getmempoolentry(txid3)["weight"], tx.get_weight())

        # Mine a block to clear the gbt cache again.
        self.generate(self.nodes[0], 1)

        if not self.options.descriptors:
            self.log.info("Verify behaviour of importaddress and listunspent")

            # Some public keys to be used later
            pubkeys = [
                "0363D44AABD0F1699138239DF2F042C3282C0671CC7A76826A55C8203D90E39242",  # cPiM8Ub4heR9NBYmgVzJQiUH1if44GSBGiqaeJySuL2BKxubvgwb
                "02D3E626B3E616FC8662B489C123349FECBFC611E778E5BE739B257EAE4721E5BF",  # cPpAdHaD6VoYbW78kveN2bsvb45Q7G5PhaPApVUGwvF8VQ9brD97
                "04A47F2CBCEFFA7B9BCDA184E7D5668D3DA6F9079AD41E422FA5FD7B2D458F2538A62F5BD8EC85C2477F39650BD391EA6250207065B2A81DA8B009FC891E898F0E",  # 91zqCU5B9sdWxzMt1ca3VzbtVm2YM6Hi5Rxn4UDtxEaN9C9nzXV
                "02A47F2CBCEFFA7B9BCDA184E7D5668D3DA6F9079AD41E422FA5FD7B2D458F2538",  # cPQFjcVRpAUBG8BA9hzr2yEzHwKoMgLkJZBBtK9vJnvGJgMjzTbd
                "036722F784214129FEB9E8129D626324F3F6716555B603FFE8300BBCB882151228",  # cQGtcm34xiLjB1v7bkRa4V3aAc9tS2UTuBZ1UnZGeSeNy627fN66
                "0266A8396EE936BF6D99D17920DB21C6C7B1AB14C639D5CD72B300297E416FD2EC",  # cTW5mR5M45vHxXkeChZdtSPozrFwFgmEvTNnanCW6wrqwaCZ1X7K
                "0450A38BD7F0AC212FEBA77354A9B036A32E0F7C81FC4E0C5ADCA7C549C4505D2522458C2D9AE3CEFD684E039194B72C8A10F9CB9D4764AB26FCC2718D421D3B84",  # 92h2XPssjBpsJN5CqSP7v9a7cf2kgDunBC6PDFwJHMACM1rrVBJ
            ]

            # Import a compressed key and an uncompressed key, generate some multisig addresses
            self.nodes[0].importprivkey("92e6XLo5jVAVwrQKPNTs93oQco8f8sDNBcpv73Dsrs397fQtFQn")
            uncompressed_spendable_address = ["mvozP4UwyGD2mGZU4D2eMvMLPB9WkMmMQu"]
            self.nodes[0].importprivkey("cNC8eQ5dg3mFAVePDX4ddmPYpPbw41r9bm2jd1nLJT77e6RrzTRR")
            compressed_spendable_address = ["mmWQubrDomqpgSYekvsU7HWEVjLFHAakLe"]
            assert not self.nodes[0].getaddressinfo(uncompressed_spendable_address[0])['iscompressed']
            assert self.nodes[0].getaddressinfo(compressed_spendable_address[0])['iscompressed']

            self.nodes[0].importpubkey(pubkeys[0])
            compressed_solvable_address = [key_to_p2pkh(pubkeys[0])]
            self.nodes[0].importpubkey(pubkeys[1])
            compressed_solvable_address.append(key_to_p2pkh(pubkeys[1]))
            self.nodes[0].importpubkey(pubkeys[2])
            uncompressed_solvable_address = [key_to_p2pkh(pubkeys[2])]

            spendable_anytime = []                      # These outputs should be seen anytime after importprivkey and addmultisigaddress
            spendable_after_importaddress = []          # These outputs should be seen after importaddress
            solvable_after_importaddress = []           # These outputs should be seen after importaddress but not spendable
            unsolvable_after_importaddress = []         # These outputs should be unsolvable after importaddress
            solvable_anytime = []                       # These outputs should be solvable after importpubkey
            unseen_anytime = []                         # These outputs should never be seen

            uncompressed_spendable_address.append(self.nodes[0].addmultisigaddress(2, [uncompressed_spendable_address[0], compressed_spendable_address[0]])['address'])
            uncompressed_spendable_address.append(self.nodes[0].addmultisigaddress(2, [uncompressed_spendable_address[0], uncompressed_spendable_address[0]])['address'])
            compressed_spendable_address.append(self.nodes[0].addmultisigaddress(2, [compressed_spendable_address[0], compressed_spendable_address[0]])['address'])
            uncompressed_solvable_address.append(self.nodes[0].addmultisigaddress(2, [compressed_spendable_address[0], uncompressed_solvable_address[0]])['address'])
            compressed_solvable_address.append(self.nodes[0].addmultisigaddress(2, [compressed_spendable_address[0], compressed_solvable_address[0]])['address'])
            compressed_solvable_address.append(self.nodes[0].addmultisigaddress(2, [compressed_solvable_address[0], compressed_solvable_address[1]])['address'])

            # Test multisig_without_privkey
            # We have 2 public keys without private keys, use addmultisigaddress to add to wallet.
            # Money sent to P2SH of multisig of this should only be seen after importaddress with the BASE58 P2SH address.

            multisig_without_privkey_address = self.nodes[0].addmultisigaddress(2, [pubkeys[3], pubkeys[4]])['address']
            script = keys_to_multisig_script([pubkeys[3], pubkeys[4]])
            solvable_after_importaddress.append(script_to_p2sh_script(script))

            for i in compressed_spendable_address:
                v = self.nodes[0].getaddressinfo(i)
                if v['isscript']:
                    [bare, p2sh, p2wsh, p2sh_p2wsh] = self.p2sh_address_to_script(v)
                    # p2sh multisig with compressed keys should always be spendable
                    spendable_anytime.extend([p2sh])
                    # bare multisig can be watched and signed, but is not treated as ours
                    solvable_after_importaddress.extend([bare])
                    # P2WSH and P2SH(P2WSH) multisig with compressed keys are spendable after direct importaddress
                    spendable_after_importaddress.extend([p2wsh, p2sh_p2wsh])
                else:
                    [p2wpkh, p2sh_p2wpkh, p2pk, p2pkh, p2sh_p2pk, p2sh_p2pkh, p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh] = self.p2pkh_address_to_script(v)
                    # normal P2PKH and P2PK with compressed keys should always be spendable
                    spendable_anytime.extend([p2pkh, p2pk])
                    # P2SH_P2PK, P2SH_P2PKH with compressed keys are spendable after direct importaddress
                    spendable_after_importaddress.extend([p2sh_p2pk, p2sh_p2pkh, p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh])
                    # P2WPKH and P2SH_P2WPKH with compressed keys should always be spendable
                    spendable_anytime.extend([p2wpkh, p2sh_p2wpkh])

            for i in uncompressed_spendable_address:
                v = self.nodes[0].getaddressinfo(i)
                if v['isscript']:
                    [bare, p2sh, p2wsh, p2sh_p2wsh] = self.p2sh_address_to_script(v)
                    # p2sh multisig with uncompressed keys should always be spendable
                    spendable_anytime.extend([p2sh])
                    # bare multisig can be watched and signed, but is not treated as ours
                    solvable_after_importaddress.extend([bare])
                    # P2WSH and P2SH(P2WSH) multisig with uncompressed keys are never seen
                    unseen_anytime.extend([p2wsh, p2sh_p2wsh])
                else:
                    [p2wpkh, p2sh_p2wpkh, p2pk, p2pkh, p2sh_p2pk, p2sh_p2pkh, p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh] = self.p2pkh_address_to_script(v)
                    # normal P2PKH and P2PK with uncompressed keys should always be spendable
                    spendable_anytime.extend([p2pkh, p2pk])
                    # P2SH_P2PK and P2SH_P2PKH are spendable after direct importaddress
                    spendable_after_importaddress.extend([p2sh_p2pk, p2sh_p2pkh])
                    # Witness output types with uncompressed keys are never seen
                    unseen_anytime.extend([p2wpkh, p2sh_p2wpkh, p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh])

            for i in compressed_solvable_address:
                v = self.nodes[0].getaddressinfo(i)
                if v['isscript']:
                    # Multisig without private is not seen after addmultisigaddress, but seen after importaddress
                    [bare, p2sh, p2wsh, p2sh_p2wsh] = self.p2sh_address_to_script(v)
                    solvable_after_importaddress.extend([bare, p2sh, p2wsh, p2sh_p2wsh])
                else:
                    [p2wpkh, p2sh_p2wpkh, p2pk, p2pkh, p2sh_p2pk, p2sh_p2pkh, p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh] = self.p2pkh_address_to_script(v)
                    # normal P2PKH, P2PK, P2WPKH and P2SH_P2WPKH with compressed keys should always be seen
                    solvable_anytime.extend([p2pkh, p2pk, p2wpkh, p2sh_p2wpkh])
                    # P2SH_P2PK, P2SH_P2PKH with compressed keys are seen after direct importaddress
                    solvable_after_importaddress.extend([p2sh_p2pk, p2sh_p2pkh, p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh])

            for i in uncompressed_solvable_address:
                v = self.nodes[0].getaddressinfo(i)
                if v['isscript']:
                    [bare, p2sh, p2wsh, p2sh_p2wsh] = self.p2sh_address_to_script(v)
                    # Base uncompressed multisig without private is not seen after addmultisigaddress, but seen after importaddress
                    solvable_after_importaddress.extend([bare, p2sh])
                    # P2WSH and P2SH(P2WSH) multisig with uncompressed keys are never seen
                    unseen_anytime.extend([p2wsh, p2sh_p2wsh])
                else:
                    [p2wpkh, p2sh_p2wpkh, p2pk, p2pkh, p2sh_p2pk, p2sh_p2pkh, p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh] = self.p2pkh_address_to_script(v)
                    # normal P2PKH and P2PK with uncompressed keys should always be seen
                    solvable_anytime.extend([p2pkh, p2pk])
                    # P2SH_P2PK, P2SH_P2PKH with uncompressed keys are seen after direct importaddress
                    solvable_after_importaddress.extend([p2sh_p2pk, p2sh_p2pkh])
                    # Witness output types with uncompressed keys are never seen
                    unseen_anytime.extend([p2wpkh, p2sh_p2wpkh, p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh])

            op1 = CScript([OP_1])
            op0 = CScript([OP_0])
            # 2N7MGY19ti4KDMSzRfPAssP6Pxyuxoi6jLe is the P2SH(P2PKH) version of mjoE3sSrb8ByYEvgnC3Aox86u1CHnfJA4V
            unsolvable_address_key = bytes.fromhex("02341AEC7587A51CDE5279E0630A531AEA2615A9F80B17E8D9376327BAEAA59E3D")
            unsolvablep2pkh = key_to_p2pkh_script(unsolvable_address_key)
            unsolvablep2wshp2pkh = script_to_p2wsh_script(unsolvablep2pkh)
            p2shop0 = script_to_p2sh_script(op0)
            p2wshop1 = script_to_p2wsh_script(op1)
            unsolvable_after_importaddress.append(unsolvablep2pkh)
            unsolvable_after_importaddress.append(unsolvablep2wshp2pkh)
            unsolvable_after_importaddress.append(op1)  # OP_1 will be imported as script
            unsolvable_after_importaddress.append(p2wshop1)
            unseen_anytime.append(op0)  # OP_0 will be imported as P2SH address with no script provided
            unsolvable_after_importaddress.append(p2shop0)

            spendable_txid = []
            solvable_txid = []
            spendable_txid.append(self.mine_and_test_listunspent(spendable_anytime, 2))
            solvable_txid.append(self.mine_and_test_listunspent(solvable_anytime, 1))
            self.mine_and_test_listunspent(spendable_after_importaddress + solvable_after_importaddress + unseen_anytime + unsolvable_after_importaddress, 0)

            importlist = []
            for i in compressed_spendable_address + uncompressed_spendable_address + compressed_solvable_address + uncompressed_solvable_address:
                v = self.nodes[0].getaddressinfo(i)
                if v['isscript']:
                    bare = bytes.fromhex(v['hex'])
                    importlist.append(bare.hex())
                    importlist.append(script_to_p2wsh_script(bare).hex())
                else:
                    pubkey = bytes.fromhex(v['pubkey'])
                    p2pk = key_to_p2pk_script(pubkey)
                    p2pkh = key_to_p2pkh_script(pubkey)
                    importlist.append(p2pk.hex())
                    importlist.append(p2pkh.hex())
                    importlist.append(key_to_p2wpkh_script(pubkey).hex())
                    importlist.append(script_to_p2wsh_script(p2pk).hex())
                    importlist.append(script_to_p2wsh_script(p2pkh).hex())

            importlist.append(unsolvablep2pkh.hex())
            importlist.append(unsolvablep2wshp2pkh.hex())
            importlist.append(op1.hex())
            importlist.append(p2wshop1.hex())

            for i in importlist:
                # import all generated addresses. The wallet already has the private keys for some of these, so catch JSON RPC
                # exceptions and continue.
                try_rpc(-4, "The wallet already contains the private key for this address or script", self.nodes[0].importaddress, i, "", False, True)

            self.nodes[0].importaddress(script_to_p2sh(op0))  # import OP_0 as address only
            self.nodes[0].importaddress(multisig_without_privkey_address)  # Test multisig_without_privkey

            spendable_txid.append(self.mine_and_test_listunspent(spendable_anytime + spendable_after_importaddress, 2))
            solvable_txid.append(self.mine_and_test_listunspent(solvable_anytime + solvable_after_importaddress, 1))
            self.mine_and_test_listunspent(unsolvable_after_importaddress, 1)
            self.mine_and_test_listunspent(unseen_anytime, 0)

            spendable_txid.append(self.mine_and_test_listunspent(spendable_anytime + spendable_after_importaddress, 2))
            solvable_txid.append(self.mine_and_test_listunspent(solvable_anytime + solvable_after_importaddress, 1))
            self.mine_and_test_listunspent(unsolvable_after_importaddress, 1)
            self.mine_and_test_listunspent(unseen_anytime, 0)

            # Repeat some tests. This time we don't add witness scripts with importaddress
            # Import a compressed key and an uncompressed key, generate some multisig addresses
            self.nodes[0].importprivkey("927pw6RW8ZekycnXqBQ2JS5nPyo1yRfGNN8oq74HeddWSpafDJH")
            uncompressed_spendable_address = ["mguN2vNSCEUh6rJaXoAVwY3YZwZvEmf5xi"]
            self.nodes[0].importprivkey("cMcrXaaUC48ZKpcyydfFo8PxHAjpsYLhdsp6nmtB3E2ER9UUHWnw")
            compressed_spendable_address = ["n1UNmpmbVUJ9ytXYXiurmGPQ3TRrXqPWKL"]

            self.nodes[0].importpubkey(pubkeys[5])
            compressed_solvable_address = [key_to_p2pkh(pubkeys[5])]
            self.nodes[0].importpubkey(pubkeys[6])
            uncompressed_solvable_address = [key_to_p2pkh(pubkeys[6])]

            unseen_anytime = []                         # These outputs should never be seen
            solvable_anytime = []                       # These outputs should be solvable after importpubkey
            unseen_anytime = []                         # These outputs should never be seen

            uncompressed_spendable_address.append(self.nodes[0].addmultisigaddress(2, [uncompressed_spendable_address[0], compressed_spendable_address[0]])['address'])
            uncompressed_spendable_address.append(self.nodes[0].addmultisigaddress(2, [uncompressed_spendable_address[0], uncompressed_spendable_address[0]])['address'])
            compressed_spendable_address.append(self.nodes[0].addmultisigaddress(2, [compressed_spendable_address[0], compressed_spendable_address[0]])['address'])
            uncompressed_solvable_address.append(self.nodes[0].addmultisigaddress(2, [compressed_solvable_address[0], uncompressed_solvable_address[0]])['address'])
            compressed_solvable_address.append(self.nodes[0].addmultisigaddress(2, [compressed_spendable_address[0], compressed_solvable_address[0]])['address'])

            premature_witaddress = []

            for i in compressed_spendable_address:
                v = self.nodes[0].getaddressinfo(i)
                if v['isscript']:
                    [bare, p2sh, p2wsh, p2sh_p2wsh] = self.p2sh_address_to_script(v)
                    premature_witaddress.append(script_to_p2sh(p2wsh))
                else:
                    [p2wpkh, p2sh_p2wpkh, p2pk, p2pkh, p2sh_p2pk, p2sh_p2pkh, p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh] = self.p2pkh_address_to_script(v)
                    # P2WPKH, P2SH_P2WPKH are always spendable
                    spendable_anytime.extend([p2wpkh, p2sh_p2wpkh])

            for i in uncompressed_spendable_address + uncompressed_solvable_address:
                v = self.nodes[0].getaddressinfo(i)
                if v['isscript']:
                    [bare, p2sh, p2wsh, p2sh_p2wsh] = self.p2sh_address_to_script(v)
                    # P2WSH and P2SH(P2WSH) multisig with uncompressed keys are never seen
                    unseen_anytime.extend([p2wsh, p2sh_p2wsh])
                else:
                    [p2wpkh, p2sh_p2wpkh, p2pk, p2pkh, p2sh_p2pk, p2sh_p2pkh, p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh] = self.p2pkh_address_to_script(v)
                    # P2WPKH, P2SH_P2WPKH with uncompressed keys are never seen
                    unseen_anytime.extend([p2wpkh, p2sh_p2wpkh])

            for i in compressed_solvable_address:
                v = self.nodes[0].getaddressinfo(i)
                if v['isscript']:
                    [bare, p2sh, p2wsh, p2sh_p2wsh] = self.p2sh_address_to_script(v)
                    premature_witaddress.append(script_to_p2sh(p2wsh))
                else:
                    [p2wpkh, p2sh_p2wpkh, p2pk, p2pkh, p2sh_p2pk, p2sh_p2pkh, p2wsh_p2pk, p2wsh_p2pkh, p2sh_p2wsh_p2pk, p2sh_p2wsh_p2pkh] = self.p2pkh_address_to_script(v)
                    # P2SH_P2PK, P2SH_P2PKH with compressed keys are always solvable
                    solvable_anytime.extend([p2wpkh, p2sh_p2wpkh])

            self.mine_and_test_listunspent(spendable_anytime, 2)
            self.mine_and_test_listunspent(solvable_anytime, 1)
            self.mine_and_test_listunspent(unseen_anytime, 0)

            # Check that createrawtransaction/decoderawtransaction with non-v0 Bech32 works
            v1_addr = program_to_witness(1, [3, 5])
            v1_tx = self.nodes[0].createrawtransaction([getutxo(spendable_txid[0])], {v1_addr: 1})
            v1_decoded = self.nodes[1].decoderawtransaction(v1_tx)
            assert_equal(v1_decoded['vout'][0]['scriptPubKey']['address'], v1_addr)
            assert_equal(v1_decoded['vout'][0]['scriptPubKey']['hex'], "51020305")

            # Check that spendable outputs are really spendable
            self.create_and_mine_tx_from_txids(spendable_txid)

            # import all the private keys so solvable addresses become spendable
            self.nodes[0].importprivkey("cPiM8Ub4heR9NBYmgVzJQiUH1if44GSBGiqaeJySuL2BKxubvgwb")
            self.nodes[0].importprivkey("cPpAdHaD6VoYbW78kveN2bsvb45Q7G5PhaPApVUGwvF8VQ9brD97")
            self.nodes[0].importprivkey("91zqCU5B9sdWxzMt1ca3VzbtVm2YM6Hi5Rxn4UDtxEaN9C9nzXV")
            self.nodes[0].importprivkey("cPQFjcVRpAUBG8BA9hzr2yEzHwKoMgLkJZBBtK9vJnvGJgMjzTbd")
            self.nodes[0].importprivkey("cQGtcm34xiLjB1v7bkRa4V3aAc9tS2UTuBZ1UnZGeSeNy627fN66")
            self.nodes[0].importprivkey("cTW5mR5M45vHxXkeChZdtSPozrFwFgmEvTNnanCW6wrqwaCZ1X7K")
            self.create_and_mine_tx_from_txids(solvable_txid)

            # Test that importing native P2WPKH/P2WSH scripts works
            for use_p2wsh in [False, True]:
                if use_p2wsh:
                    scriptPubKey = "00203a59f3f56b713fdcf5d1a57357f02c44342cbf306ffe0c4741046837bf90561a"
                    transaction = "01000000000100e1f505000000002200203a59f3f56b713fdcf5d1a57357f02c44342cbf306ffe0c4741046837bf90561a00000000"
                else:
                    scriptPubKey = "a9142f8c469c2f0084c48e11f998ffbe7efa7549f26d87"
                    transaction = "01000000000100e1f5050000000017a9142f8c469c2f0084c48e11f998ffbe7efa7549f26d8700000000"

                self.nodes[1].importaddress(scriptPubKey, "", False)
                rawtxfund = self.nodes[1].fundrawtransaction(transaction)['hex']
                rawtxfund = self.nodes[1].signrawtransactionwithwallet(rawtxfund)["hex"]
                txid = self.nodes[1].sendrawtransaction(rawtxfund)

                assert_equal(self.nodes[1].gettransaction(txid, True)["txid"], txid)
                assert_equal(self.nodes[1].listtransactions("*", 1, 0, True)[0]["txid"], txid)

                # Assert it is properly saved
                self.restart_node(1)
                assert_equal(self.nodes[1].gettransaction(txid, True)["txid"], txid)
                assert_equal(self.nodes[1].listtransactions("*", 1, 0, True)[0]["txid"], txid)

        self.log.info('Test negative and unknown rpcserialversion throw an init error')
        self.stop_node(0)
        self.nodes[0].assert_start_raises_init_error(["-rpcserialversion=-1"], "Error: rpcserialversion must be non-negative.")
        self.nodes[0].assert_start_raises_init_error(["-rpcserialversion=100"], "Error: Unknown rpcserialversion requested.")
    def run_test(self):
        self.log.info('Setting up wallets')
        self.nodes[0].createwallet(wallet_name='w0',
                                   disable_private_keys=False)
        w0 = self.nodes[0].get_wallet_rpc('w0')

        self.nodes[1].createwallet(wallet_name='w1',
                                   disable_private_keys=True,
                                   blank=True,
                                   descriptors=True)
        w1 = self.nodes[1].get_wallet_rpc('w1')
        assert_equal(w1.getwalletinfo()['keypoolsize'], 0)

        self.nodes[1].createwallet(wallet_name="wpriv",
                                   disable_private_keys=False,
                                   blank=True,
                                   descriptors=True)
        wpriv = self.nodes[1].get_wallet_rpc("wpriv")
        assert_equal(wpriv.getwalletinfo()['keypoolsize'], 0)

        self.log.info('Mining coins')
        w0.generatetoaddress(101, w0.getnewaddress())

        # RPC importdescriptors -----------------------------------------------

        # # Test import fails if no descriptor present
        key = get_generate_key()
        self.log.info("Import should fail if a descriptor is not provided")
        self.test_importdesc({"timestamp": "now"},
                             success=False,
                             error_code=-8,
                             error_message='Descriptor not found.')

        # # Test importing of a P2PKH descriptor
        key = get_generate_key()
        self.log.info("Should import a p2pkh descriptor")
        self.test_importdesc(
            {
                "desc": descsum_create("pkh(" + key.pubkey + ")"),
                "timestamp": "now",
                "label": "Descriptor import test"
            },
            success=True)
        test_address(w1,
                     key.p2pkh_addr,
                     solvable=True,
                     ismine=True,
                     labels=["Descriptor import test"])
        assert_equal(w1.getwalletinfo()['keypoolsize'], 0)

        self.log.info("Internal addresses cannot have labels")
        self.test_importdesc(
            {
                "desc": descsum_create("pkh(" + key.pubkey + ")"),
                "timestamp": "now",
                "internal": True,
                "label": "Descriptor import test"
            },
            success=False,
            error_code=-8,
            error_message="Internal addresses should not have a label")

        self.log.info("Internal addresses should be detected as such")
        key = get_generate_key()
        addr = key_to_p2pkh(key.pubkey)
        self.test_importdesc(
            {
                "desc": descsum_create("pkh(" + key.pubkey + ")"),
                "timestamp": "now",
                "internal": True
            },
            success=True)
        info = w1.getaddressinfo(addr)
        assert_equal(info["ismine"], True)
        assert_equal(info["ischange"], True)
        assert_equal(w1.getwalletinfo()['keypoolsize'], 0)

        test_address(w1, key.p2pkh_addr, ismine=True, solvable=True)

        # Check persistence of data and that loading works correctly
        w1.unloadwallet()
        self.nodes[1].loadwallet('w1')
        test_address(w1, key.p2pkh_addr, ismine=True, solvable=True)

        # # Test importing of a multisig descriptor
        key1 = get_generate_key()
        key2 = get_generate_key()
        self.log.info("Should import a 1-of-2 bare multisig from descriptor")
        self.test_importdesc(
            {
                "desc":
                descsum_create("multi(1," + key1.pubkey + "," + key2.pubkey +
                               ")"),
                "timestamp":
                "now"
            },
            success=True)
        self.log.info(
            "Should not treat individual keys from the imported bare multisig as watchonly"
        )
        test_address(w1, key1.p2pkh_addr, ismine=False)

        # # Test ranged descriptors
        xpriv = "tprv8ZgxMBicQKsPeuVhWwi6wuMQGfPKi9Li5GtX35jVNknACgqe3CY4g5xgkfDDJcmtF7o1QnxWDRYw4H5P26PXq7sbcUkEqeR4fg3Kxp2tigg"
        xpub = "tpubD6NzVbkrYhZ4YNXVQbNhMK1WqguFsUXceaVJKbmno2aZ3B6QfbMeraaYvnBSGpV3vxLyTTK9DYT1yoEck4XUScMzXoQ2U2oSmE2JyMedq3H"
        addresses = [
            "2N7yv4p8G8yEaPddJxY41kPihnWvs39qCMf",
            "2MsHxyb2JS3pAySeNUsJ7mNnurtpeenDzLA"
        ]  # hdkeypath=m/0'/0'/0' and 1'
        # wpkh subscripts corresponding to the above addresses
        addresses += [
            "ecregtest:prvn9ycvgr5atuyh49sua3mapskh2mnnzg7t9yp6dt",
            "ecregtest:pp3n087yx0njv2e5wcvltahfxqst7l66rutz8ceeat"
        ]
        desc = "sh(pkh(" + xpub + "/0/0/*" + "))"

        self.log.info("Ranged descriptors cannot have labels")
        self.test_importdesc(
            {
                "desc": descsum_create(desc),
                "timestamp": "now",
                "range": [0, 100],
                "label": "test"
            },
            success=False,
            error_code=-8,
            error_message='Ranged descriptors should not have a label')

        self.log.info("Private keys required for private keys enabled wallet")
        self.test_importdesc(
            {
                "desc": descsum_create(desc),
                "timestamp": "now",
                "range": [0, 100]
            },
            success=False,
            error_code=-4,
            error_message=
            'Cannot import descriptor without private keys to a wallet with private keys enabled',
            wallet=wpriv)

        self.log.info(
            "Ranged descriptor import should warn without a specified range")
        self.test_importdesc(
            {
                "desc": descsum_create(desc),
                "timestamp": "now"
            },
            success=True,
            warnings=['Range not given, using default keypool range'])
        assert_equal(w1.getwalletinfo()['keypoolsize'], 0)

        # # Test importing of a ranged descriptor with xpriv
        self.log.info(
            "Should not import a ranged descriptor that includes xpriv into a watch-only wallet"
        )
        desc = "sh(pkh(" + xpriv + "/0'/0'/*'" + "))"
        self.test_importdesc(
            {
                "desc": descsum_create(desc),
                "timestamp": "now",
                "range": 1
            },
            success=False,
            error_code=-4,
            error_message=
            'Cannot import private keys to a wallet with private keys disabled'
        )

        self.log.info("Should not import a descriptor with hardened "
                      "derivations when private keys are disabled")
        self.test_importdesc(
            {
                "desc": descsum_create("pkh(" + xpub + "/1h/*)"),
                "timestamp": "now",
                "range": 1
            },
            success=False,
            error_code=-4,
            error_message=
            'Cannot expand descriptor. Probably because of hardened derivations without private keys provided'
        )

        for address in addresses:
            test_address(w1, address, ismine=False, solvable=False)

        self.test_importdesc(
            {
                "desc": descsum_create(desc),
                "timestamp": "now",
                "range": -1
            },
            success=False,
            error_code=-8,
            error_message='End of range is too high')

        self.test_importdesc(
            {
                "desc": descsum_create(desc),
                "timestamp": "now",
                "range": [-1, 10]
            },
            success=False,
            error_code=-8,
            error_message='Range should be greater or equal than 0')

        self.test_importdesc(
            {
                "desc": descsum_create(desc),
                "timestamp": "now",
                "range": [(2 << 31 + 1) - 1000000, (2 << 31 + 1)]
            },
            success=False,
            error_code=-8,
            error_message='End of range is too high')

        self.test_importdesc(
            {
                "desc": descsum_create(desc),
                "timestamp": "now",
                "range": [2, 1]
            },
            success=False,
            error_code=-8,
            error_message=
            'Range specified as [begin,end] must not have begin after end')

        self.test_importdesc(
            {
                "desc": descsum_create(desc),
                "timestamp": "now",
                "range": [0, 1000001]
            },
            success=False,
            error_code=-8,
            error_message='Range is too large')

        # Make sure ranged imports import keys in order
        w1 = self.nodes[1].get_wallet_rpc('w1')
        self.log.info('Key ranges should be imported in order')
        xpub = "tpubDAXcJ7s7ZwicqjprRaEWdPoHKrCS215qxGYxpusRLLmJuT69ZSicuGdSfyvyKpvUNYBW1s2U3NSrT6vrCYB9e6nZUEvrqnwXPF8ArTCRXMY"
        addresses = [
            'ecregtest:qp0v86h53rc92hjrlpwzpjtdlgzsxu25svv6g40fpl',  # m/0'/0'/0
            'ecregtest:qqasy0zlkdleqt4pkn8fs4ehm5gnnz6qpgdcpt90fq',  # m/0'/0'/1
            'ecregtest:qp0sp4wlhctvprqvdt2dgvqcfdjssu04xgey0l3syw',  # m/0'/0'/2
            'ecregtest:qrhn24tegn04cptfv4ldhtkduxq55zcwrycjfdj9vr',  # m/0'/0'/3
            'ecregtest:qzpqhett2uwltq803vrxv7zkqhft5vsnmcjeh50v0p',  # m/0'/0'/4
        ]

        self.test_importdesc(
            {
                'desc':
                descsum_create('sh(pkh([abcdef12/0h/0h]' + xpub + '/*))'),
                'active': True,
                'range': [0, 2],
                'timestamp': 'now'
            },
            success=True)
        self.test_importdesc(
            {
                'desc': descsum_create('pkh([12345678/0h/0h]' + xpub + '/*)'),
                'active': True,
                'range': [0, 2],
                'timestamp': 'now'
            },
            success=True)

        assert_equal(w1.getwalletinfo()['keypoolsize'], 5)
        for i, expected_addr in enumerate(addresses):
            pkh_addr = w1.getnewaddress('')
            assert_raises_rpc_error(-4, 'This wallet has no available keys',
                                    w1.getrawchangeaddress)

            assert_equal(pkh_addr, expected_addr)
            pkh_addr_info = w1.getaddressinfo(pkh_addr)
            assert_equal(pkh_addr_info['desc'][:22],
                         'pkh([12345678/0\'/0\'/{}]'.format(i))

            # After retrieving a key, we don't refill the keypool again, so
            # it's one less for each address type
            assert_equal(w1.getwalletinfo()['keypoolsize'], 4)
        w1.keypoolrefill()
        assert_equal(w1.getwalletinfo()['keypoolsize'], 5)

        # Check active=False default
        self.log.info('Check imported descriptors are not active by default')
        self.test_importdesc(
            {
                'desc': descsum_create('pkh([12345678/0h/0h]' + xpub + '/*)'),
                'range': [0, 2],
                'timestamp': 'now',
                'internal': True
            },
            success=True)
        assert_raises_rpc_error(-4, 'This wallet has no available keys',
                                w1.getrawchangeaddress)

        # # Test importing a descriptor containing a WIF private key
        wif_priv = "cTe1f5rdT8A8DFgVWTjyPwACsDPJM9ff4QngFxUixCSvvbg1x6sh"
        address = "ecregtest:ppn85zpvym8cdccmgw8km6e48jfhnpa435h3hkyfd6"
        desc = "sh(pkh(" + wif_priv + "))"
        self.log.info(
            "Should import a descriptor with a WIF private key as spendable")
        self.test_importdesc({
            "desc": descsum_create(desc),
            "timestamp": "now"
        },
                             success=True,
                             wallet=wpriv)
        test_address(wpriv, address, solvable=True, ismine=True)
        txid = w0.sendtoaddress(address, 49999996.00)
        w0.generatetoaddress(6, w0.getnewaddress())
        self.sync_blocks()
        tx = wpriv.createrawtransaction([{
            "txid": txid,
            "vout": 0
        }], {w0.getnewaddress(): 49999000})
        signed_tx = wpriv.signrawtransactionwithwallet(tx)
        w1.sendrawtransaction(signed_tx['hex'])

        # Make sure that we can use import and use multisig as addresses
        self.log.info(
            'Test that multisigs can be imported, signed for, and getnewaddress\'d'
        )
        self.nodes[1].createwallet(wallet_name="wmulti_priv",
                                   disable_private_keys=False,
                                   blank=True,
                                   descriptors=True)
        wmulti_priv = self.nodes[1].get_wallet_rpc("wmulti_priv")
        assert_equal(wmulti_priv.getwalletinfo()['keypoolsize'], 0)

        self.test_importdesc(
            {
                "desc":
                "sh(multi(2,tprv8ZgxMBicQKsPevADjDCWsa6DfhkVXicu8NQUzfibwX2MexVwW4tCec5mXdCW8kJwkzBRRmAay1KZya4WsehVvjTGVW6JLqiqd8DdZ4xSg52/84h/0h/0h/*,tprv8ZgxMBicQKsPdSNWUhDiwTScDr6JfkZuLshTRwzvZGnMSnGikV6jxpmdDkC3YRc4T3GD6Nvg9uv6hQg73RVv1EiTXDZwxVbsLugVHU8B1aq/84h/0h/0h/*,tprv8ZgxMBicQKsPeonDt8Ka2mrQmHa61hQ5FQCsvWBTpSNzBFgM58cV2EuXNAHF14VawVpznnme3SuTbA62sGriwWyKifJmXntfNeK7zeqMCj1/84h/0h/0h/*))#f5nqn4ax",
                "active": True,
                "range": 1000,
                "next_index": 0,
                "timestamp": "now"
            },
            success=True,
            wallet=wmulti_priv)
        self.test_importdesc(
            {
                "desc":
                "sh(multi(2,tprv8ZgxMBicQKsPevADjDCWsa6DfhkVXicu8NQUzfibwX2MexVwW4tCec5mXdCW8kJwkzBRRmAay1KZya4WsehVvjTGVW6JLqiqd8DdZ4xSg52/84h/1h/0h/*,tprv8ZgxMBicQKsPdSNWUhDiwTScDr6JfkZuLshTRwzvZGnMSnGikV6jxpmdDkC3YRc4T3GD6Nvg9uv6hQg73RVv1EiTXDZwxVbsLugVHU8B1aq/84h/1h/0h/*,tprv8ZgxMBicQKsPeonDt8Ka2mrQmHa61hQ5FQCsvWBTpSNzBFgM58cV2EuXNAHF14VawVpznnme3SuTbA62sGriwWyKifJmXntfNeK7zeqMCj1/84h/1h/0h/*))#m4e4s5de",
                "active": True,
                "internal": True,
                "range": 1000,
                "next_index": 0,
                "timestamp": "now"
            },
            success=True,
            wallet=wmulti_priv)

        # Range end (1000) is inclusive, so 1001 addresses generated
        assert_equal(wmulti_priv.getwalletinfo()['keypoolsize'], 1001)
        addr = wmulti_priv.getnewaddress('')
        # Derived at m/84'/0'/0'/0
        assert_equal(addr,
                     'ecregtest:pzkcf26dw7np58jcspnpxaupgz9csnc3wsf5wdh2a3')
        change_addr = wmulti_priv.getrawchangeaddress()
        assert_equal(change_addr,
                     'ecregtest:prnkfg7pxe3kpyv3l4v00ft6q3sfseag7vnva0k49n')

        assert_equal(wmulti_priv.getwalletinfo()['keypoolsize'], 1000)
        txid = w0.sendtoaddress(addr, 10000000)
        self.nodes[0].generate(6)
        self.sync_all()

        self.nodes[1].createwallet(wallet_name="wmulti_pub",
                                   disable_private_keys=True,
                                   blank=True,
                                   descriptors=True)
        wmulti_pub = self.nodes[1].get_wallet_rpc("wmulti_pub")
        assert_equal(wmulti_pub.getwalletinfo()['keypoolsize'], 0)

        self.test_importdesc(
            {
                "desc":
                "sh(multi(2,[7b2d0242/84h/0h/0h]tpubDCJtdt5dgJpdhW4MtaVYDhG4T4tF6jcLR1PxL43q9pq1mxvXgMS9Mzw1HnXG15vxUGQJMMSqCQHMTy3F1eW5VkgVroWzchsPD5BUojrcWs8/*,[59b09cd6/84h/0h/0h]tpubDDBF2BTR6s8drwrfDei8WxtckGuSm1cyoKxYY1QaKSBFbHBYQArWhHPA6eJrzZej6nfHGLSURYSLHr7GuYch8aY5n61tGqgn8b4cXrMuoPH/*,[e81a0532/84h/0h/0h]tpubDCsWoW1kuQB9kG5MXewHqkbjPtqPueRnXju7uM2NK7y3JYb2ajAZ9EiuZXNNuE4661RAfriBWhL8UsnAPpk8zrKKnZw1Ug7X4oHgMdZiU4E/*))#x75vpsak",
                "active": True,
                "range": 1000,
                "next_index": 0,
                "timestamp": "now"
            },
            success=True,
            wallet=wmulti_pub)
        self.test_importdesc(
            {
                "desc":
                "sh(multi(2,[7b2d0242/84h/1h/0h]tpubDCXqdwWZcszwqYJSnZp8eARkxGJfHAk23KDxbztV4BbschfaTfYLTcSkSJ3TN64dRqwa1rnFUScsYormKkGqNbbPwkorQimVevXjxzUV9Gf/*,[59b09cd6/84h/1h/0h]tpubDCYfZY2ceyHzYzMMVPt9MNeiqtQ2T7Uyp9QSFwYXh8Vi9iJFYXcuphJaGXfF3jUQJi5Y3GMNXvM11gaL4txzZgNGK22BFAwMXynnzv4z2Jh/*,[e81a0532/84h/1h/0h]tpubDC6UGqnsQStngYuGD4MKsMy7eD1Yg9NTJfPdvjdG2JE5oZ7EsSL3WHg4Gsw2pR5K39ZwJ46M1wZayhedVdQtMGaUhq5S23PH6fnENK3V1sb/*))#v0t48ucu",
                "active": True,
                "internal": True,
                "range": 1000,
                "next_index": 0,
                "timestamp": "now"
            },
            success=True,
            wallet=wmulti_pub)

        # The first one was already consumed by previous import and is detected
        # as used
        assert_equal(wmulti_pub.getwalletinfo()['keypoolsize'], 1000)
        addr = wmulti_pub.getnewaddress('')
        # Derived at m/84'/0'/0'/1
        assert_equal(addr,
                     'ecregtest:pr5xql8r03jp5dvrep22dns59vf7hhykr5nmaucy2h')
        change_addr = wmulti_pub.getrawchangeaddress()
        assert_equal(change_addr,
                     'ecregtest:prnkfg7pxe3kpyv3l4v00ft6q3sfseag7vnva0k49n')

        assert_equal(wmulti_pub.getwalletinfo()['keypoolsize'], 999)
        txid = w0.sendtoaddress(addr, 10000000)
        vout = find_vout_for_address(self.nodes[0], txid, addr)
        self.nodes[0].generate(6)
        self.sync_all()
        assert_equal(wmulti_pub.getbalance(), wmulti_priv.getbalance())

        # Make sure that descriptor wallets containing multiple xpubs in a
        # single descriptor load correctly
        wmulti_pub.unloadwallet()
        self.nodes[1].loadwallet('wmulti_pub')

        self.log.info("Multisig with distributed keys")
        self.nodes[1].createwallet(wallet_name="wmulti_priv1",
                                   descriptors=True)
        wmulti_priv1 = self.nodes[1].get_wallet_rpc("wmulti_priv1")
        res = wmulti_priv1.importdescriptors([{
            "desc":
            descsum_create(
                "sh(multi(2,tprv8ZgxMBicQKsPevADjDCWsa6DfhkVXicu8NQUzfibwX2MexVwW4tCec5mXdCW8kJwkzBRRmAay1KZya4WsehVvjTGVW6JLqiqd8DdZ4xSg52/84h/0h/0h/*,[59b09cd6/84h/0h/0h]tpubDDBF2BTR6s8drwrfDei8WxtckGuSm1cyoKxYY1QaKSBFbHBYQArWhHPA6eJrzZej6nfHGLSURYSLHr7GuYch8aY5n61tGqgn8b4cXrMuoPH/*,[e81a0532/84h/0h/0h]tpubDCsWoW1kuQB9kG5MXewHqkbjPtqPueRnXju7uM2NK7y3JYb2ajAZ9EiuZXNNuE4661RAfriBWhL8UsnAPpk8zrKKnZw1Ug7X4oHgMdZiU4E/*))"
            ),
            "active":
            True,
            "range":
            1000,
            "next_index":
            0,
            "timestamp":
            "now"
        }, {
            "desc":
            descsum_create(
                "sh(multi(2,tprv8ZgxMBicQKsPevADjDCWsa6DfhkVXicu8NQUzfibwX2MexVwW4tCec5mXdCW8kJwkzBRRmAay1KZya4WsehVvjTGVW6JLqiqd8DdZ4xSg52/84h/1h/0h/*,[59b09cd6/84h/1h/0h]tpubDCYfZY2ceyHzYzMMVPt9MNeiqtQ2T7Uyp9QSFwYXh8Vi9iJFYXcuphJaGXfF3jUQJi5Y3GMNXvM11gaL4txzZgNGK22BFAwMXynnzv4z2Jh/*,[e81a0532/84h/1h/0h]tpubDC6UGqnsQStngYuGD4MKsMy7eD1Yg9NTJfPdvjdG2JE5oZ7EsSL3WHg4Gsw2pR5K39ZwJ46M1wZayhedVdQtMGaUhq5S23PH6fnENK3V1sb/*))"
            ),
            "active":
            True,
            "internal":
            True,
            "range":
            1000,
            "next_index":
            0,
            "timestamp":
            "now"
        }])
        assert_equal(res[0]['success'], True)
        assert_equal(
            res[0]['warnings'][0],
            'Not all private keys provided. Some wallet functionality may return unexpected errors'
        )
        assert_equal(res[1]['success'], True)
        assert_equal(
            res[1]['warnings'][0],
            'Not all private keys provided. Some wallet functionality may return unexpected errors'
        )

        self.nodes[1].createwallet(wallet_name='wmulti_priv2',
                                   blank=True,
                                   descriptors=True)
        wmulti_priv2 = self.nodes[1].get_wallet_rpc('wmulti_priv2')
        res = wmulti_priv2.importdescriptors([{
            "desc":
            descsum_create(
                "sh(multi(2,[7b2d0242/84h/0h/0h]tpubDCJtdt5dgJpdhW4MtaVYDhG4T4tF6jcLR1PxL43q9pq1mxvXgMS9Mzw1HnXG15vxUGQJMMSqCQHMTy3F1eW5VkgVroWzchsPD5BUojrcWs8/*,tprv8ZgxMBicQKsPdSNWUhDiwTScDr6JfkZuLshTRwzvZGnMSnGikV6jxpmdDkC3YRc4T3GD6Nvg9uv6hQg73RVv1EiTXDZwxVbsLugVHU8B1aq/84h/0h/0h/*,[e81a0532/84h/0h/0h]tpubDCsWoW1kuQB9kG5MXewHqkbjPtqPueRnXju7uM2NK7y3JYb2ajAZ9EiuZXNNuE4661RAfriBWhL8UsnAPpk8zrKKnZw1Ug7X4oHgMdZiU4E/*))"
            ),
            "active":
            True,
            "range":
            1000,
            "next_index":
            0,
            "timestamp":
            "now"
        }, {
            "desc":
            descsum_create(
                "sh(multi(2,[7b2d0242/84h/1h/0h]tpubDCXqdwWZcszwqYJSnZp8eARkxGJfHAk23KDxbztV4BbschfaTfYLTcSkSJ3TN64dRqwa1rnFUScsYormKkGqNbbPwkorQimVevXjxzUV9Gf/*,tprv8ZgxMBicQKsPdSNWUhDiwTScDr6JfkZuLshTRwzvZGnMSnGikV6jxpmdDkC3YRc4T3GD6Nvg9uv6hQg73RVv1EiTXDZwxVbsLugVHU8B1aq/84h/1h/0h/*,[e81a0532/84h/1h/0h]tpubDC6UGqnsQStngYuGD4MKsMy7eD1Yg9NTJfPdvjdG2JE5oZ7EsSL3WHg4Gsw2pR5K39ZwJ46M1wZayhedVdQtMGaUhq5S23PH6fnENK3V1sb/*))"
            ),
            "active":
            True,
            "internal":
            True,
            "range":
            1000,
            "next_index":
            0,
            "timestamp":
            "now"
        }])
        assert_equal(res[0]['success'], True)
        assert_equal(
            res[0]['warnings'][0],
            'Not all private keys provided. Some wallet functionality may return unexpected errors'
        )
        assert_equal(res[1]['success'], True)
        assert_equal(
            res[1]['warnings'][0],
            'Not all private keys provided. Some wallet functionality may return unexpected errors'
        )

        rawtx = self.nodes[1].createrawtransaction([{
            'txid': txid,
            'vout': vout
        }], {w0.getnewaddress(): 9999000})
        tx_signed_1 = wmulti_priv1.signrawtransactionwithwallet(rawtx)
        assert_equal(tx_signed_1['complete'], False)
        tx_signed_2 = wmulti_priv2.signrawtransactionwithwallet(
            tx_signed_1['hex'])
        assert_equal(tx_signed_2['complete'], True)
        self.nodes[1].sendrawtransaction(tx_signed_2['hex'])

        self.log.info("Combo descriptors cannot be active")
        self.test_importdesc(
            {
                "desc":
                descsum_create(
                    "combo(tpubDCJtdt5dgJpdhW4MtaVYDhG4T4tF6jcLR1PxL43q9pq1mxvXgMS9Mzw1HnXG15vxUGQJMMSqCQHMTy3F1eW5VkgVroWzchsPD5BUojrcWs8/*)"
                ),
                "active":
                True,
                "range":
                1,
                "timestamp":
                "now"
            },
            success=False,
            error_code=-4,
            error_message="Combo descriptors cannot be set to active")

        self.log.info("Descriptors with no type cannot be active")
        self.test_importdesc(
            {
                "desc":
                descsum_create(
                    "pk(tpubDCJtdt5dgJpdhW4MtaVYDhG4T4tF6jcLR1PxL43q9pq1mxvXgMS9Mzw1HnXG15vxUGQJMMSqCQHMTy3F1eW5VkgVroWzchsPD5BUojrcWs8/*)"
                ),
                "active":
                True,
                "range":
                1,
                "timestamp":
                "now"
            },
            success=True,
            warnings=["Unknown output type, cannot set descriptor to active."])