예제 #1
0
def start_bitcoind(bitcoind_path):
    datadir = tempfile.mkdtemp()
    bitcoind_proc = subprocess.Popen([bitcoind_path, '-regtest', '-datadir=' + datadir, '-noprinttoconsole', '-fallbackfee=0.0002', '-keypool=1'])

    def cleanup_bitcoind():
        bitcoind_proc.kill()
        shutil.rmtree(datadir)
    atexit.register(cleanup_bitcoind)
    # Wait for cookie file to be created
    while not os.path.exists(datadir + '/regtest/.cookie'):
        time.sleep(0.5)
    # Read .cookie file to get user and pass
    with open(datadir + '/regtest/.cookie') as f:
        userpass = f.readline().lstrip().rstrip()
    rpc = AuthServiceProxy('http://{}@127.0.0.1:18443'.format(userpass))

    # Wait for bitcoind to be ready
    ready = False
    while not ready:
        try:
            rpc.getblockchaininfo()
            ready = True
        except JSONRPCException:
            time.sleep(0.5)
            pass

    # Make sure there are blocks and coins available
    rpc.createwallet(wallet_name="supply")
    wrpc = AuthServiceProxy('http://{}@127.0.0.1:18443/wallet/supply'.format(userpass))
    wrpc.generatetoaddress(101, wrpc.getnewaddress())
    return (rpc, userpass)
예제 #2
0
파일: test_device.py 프로젝트: nopara73/HWI
class TestSignTx(DeviceTestCase):
    def setUp(self):
        self.rpc = AuthServiceProxy('http://{}@127.0.0.1:18443'.format(self.rpc_userpass))
        if '{}_test'.format(self.full_type) not in self.rpc.listwallets():
            self.rpc.createwallet('{}_test'.format(self.full_type), True)
        self.wrpc = AuthServiceProxy('http://{}@127.0.0.1:18443/wallet/{}_test'.format(self.rpc_userpass, self.full_type))
        self.wpk_rpc = AuthServiceProxy('http://{}@127.0.0.1:18443/wallet/'.format(self.rpc_userpass))
        if '--testnet' not in self.dev_args:
            self.dev_args.append('--testnet')
        self.emulator.start()

    def tearDown(self):
        self.emulator.stop()

    def _generate_and_finalize(self, unknown_inputs, psbt):
        if not unknown_inputs:
            # Just do the normal signing process to test "all inputs" case
            sign_res = self.do_command(self.dev_args + ['signtx', psbt['psbt']])
            finalize_res = self.wrpc.finalizepsbt(sign_res['psbt'])
        else:
            # Sign only input one on first pass
            # then rest on second pass to test ability to successfully
            # ignore inputs that are not its own. Then combine both
            # signing passes to ensure they are actually properly being
            # partially signed at each step.
            first_psbt = PSBT()
            first_psbt.deserialize(psbt['psbt'])
            second_psbt = PSBT()
            second_psbt.deserialize(psbt['psbt'])

            # Blank master fingerprint to make hww fail to sign
            # Single input PSBTs will be fully signed by first signer
            for psbt_input in first_psbt.inputs[1:]:
                for pubkey, path in psbt_input.hd_keypaths.items():
                    psbt_input.hd_keypaths[pubkey] = (0,) + path[1:]
            for pubkey, path in second_psbt.inputs[0].hd_keypaths.items():
                second_psbt.inputs[0].hd_keypaths[pubkey] = (0,) + path[1:]

            single_input = len(first_psbt.inputs) == 1

            # Process the psbts
            first_psbt = first_psbt.serialize()
            second_psbt = second_psbt.serialize()

            # First will always have something to sign
            first_sign_res = self.do_command(self.dev_args + ['signtx', first_psbt])
            self.assertTrue(single_input == self.wrpc.finalizepsbt(first_sign_res['psbt'])['complete'])
            # Second may have nothing to sign (1 input case)
            # and also may throw an error(e.g., ColdCard)
            second_sign_res = self.do_command(self.dev_args + ['signtx', second_psbt])
            if 'psbt' in second_sign_res:
                self.assertTrue(not self.wrpc.finalizepsbt(second_sign_res['psbt'])['complete'])
                combined_psbt = self.wrpc.combinepsbt([first_sign_res['psbt'], second_sign_res['psbt']])

            else:
                self.assertTrue('error' in second_sign_res)
                combined_psbt = first_sign_res['psbt']

            finalize_res = self.wrpc.finalizepsbt(combined_psbt)
            self.assertTrue(finalize_res['complete'])
            self.assertTrue(self.wrpc.testmempoolaccept([finalize_res['hex']])[0]["allowed"])
        return finalize_res['hex']

    def _test_signtx(self, input_type, multisig, external):
        # Import some keys to the watch only wallet and send coins to them
        keypool_desc = self.do_command(self.dev_args + ['getkeypool', '--sh_wpkh', '30', '40'])
        import_result = self.wrpc.importmulti(keypool_desc)
        self.assertTrue(import_result[0]['success'])
        keypool_desc = self.do_command(self.dev_args + ['getkeypool', '--sh_wpkh', '--internal', '30', '40'])
        import_result = self.wrpc.importmulti(keypool_desc)
        self.assertTrue(import_result[0]['success'])
        sh_wpkh_addr = self.wrpc.getnewaddress('', 'p2sh-segwit')
        wpkh_addr = self.wrpc.getnewaddress('', 'bech32')
        pkh_addr = self.wrpc.getnewaddress('', 'legacy')
        self.wrpc.importaddress(wpkh_addr)
        self.wrpc.importaddress(pkh_addr)

        # pubkeys to construct 2-of-3 multisig descriptors for import
        sh_wpkh_info = self.wrpc.getaddressinfo(sh_wpkh_addr)
        wpkh_info = self.wrpc.getaddressinfo(wpkh_addr)
        pkh_info = self.wrpc.getaddressinfo(pkh_addr)

        # Get origin info/key pair so wallet doesn't forget how to
        # sign with keys post-import
        pubkeys = [sh_wpkh_info['desc'][8:-11],
                   wpkh_info['desc'][5:-10],
                   pkh_info['desc'][4:-10]]

        # Get the descriptors with their checksums
        sh_multi_desc = self.wrpc.getdescriptorinfo('sh(sortedmulti(2,' + pubkeys[0] + ',' + pubkeys[1] + ',' + pubkeys[2] + '))')['descriptor']
        sh_wsh_multi_desc = self.wrpc.getdescriptorinfo('sh(wsh(sortedmulti(2,' + pubkeys[0] + ',' + pubkeys[1] + ',' + pubkeys[2] + ')))')['descriptor']
        wsh_multi_desc = self.wrpc.getdescriptorinfo('wsh(sortedmulti(2,' + pubkeys[2] + ',' + pubkeys[1] + ',' + pubkeys[0] + '))')['descriptor']

        sh_multi_import = {'desc': sh_multi_desc, "timestamp": "now", "label": "shmulti"}
        sh_wsh_multi_import = {'desc': sh_wsh_multi_desc, "timestamp": "now", "label": "shwshmulti"}
        # re-order pubkeys to allow import without "already have private keys" error
        wsh_multi_import = {'desc': wsh_multi_desc, "timestamp": "now", "label": "wshmulti"}
        multi_result = self.wrpc.importmulti([sh_multi_import, sh_wsh_multi_import, wsh_multi_import])
        self.assertTrue(multi_result[0]['success'])
        self.assertTrue(multi_result[1]['success'])
        self.assertTrue(multi_result[2]['success'])

        sh_multi_addr = self.wrpc.getaddressesbylabel("shmulti").popitem()[0]
        sh_wsh_multi_addr = self.wrpc.getaddressesbylabel("shwshmulti").popitem()[0]
        wsh_multi_addr = self.wrpc.getaddressesbylabel("wshmulti").popitem()[0]

        in_amt = 3
        out_amt = in_amt // 3
        number_inputs = 0
        # Single-sig
        if input_type == 'segwit' or input_type == 'all':
            self.wpk_rpc.sendtoaddress(sh_wpkh_addr, in_amt)
            self.wpk_rpc.sendtoaddress(wpkh_addr, in_amt)
            number_inputs += 2
        if input_type == 'legacy' or input_type == 'all':
            self.wpk_rpc.sendtoaddress(pkh_addr, in_amt)
            number_inputs += 1
        # Now do segwit/legacy multisig
        if multisig:
            if input_type == 'legacy' or input_type == 'all':
                self.wpk_rpc.sendtoaddress(sh_multi_addr, in_amt)
                number_inputs += 1
            if input_type == 'segwit' or input_type == 'all':
                self.wpk_rpc.sendtoaddress(wsh_multi_addr, in_amt)
                self.wpk_rpc.sendtoaddress(sh_wsh_multi_addr, in_amt)
                number_inputs += 2

        self.wpk_rpc.generatetoaddress(6, self.wpk_rpc.getnewaddress())

        # Spend different amounts, requiring 1 to 3 inputs
        for i in range(number_inputs):
            # Create a psbt spending the above
            if i == number_inputs - 1:
                self.assertTrue((i + 1) * in_amt == self.wrpc.getbalance("*", 0, True))
            psbt = self.wrpc.walletcreatefundedpsbt([], [{self.wpk_rpc.getnewaddress('', 'legacy'): (i + 1) * out_amt}, {self.wpk_rpc.getnewaddress('', 'p2sh-segwit'): (i + 1) * out_amt}, {self.wpk_rpc.getnewaddress('', 'bech32'): (i + 1) * out_amt}], 0, {'includeWatching': True, 'subtractFeeFromOutputs': [0, 1, 2]}, True)

            if external:
                # Sign with unknown inputs in two steps
                self._generate_and_finalize(True, psbt)
            # Sign all inputs all at once
            final_tx = self._generate_and_finalize(False, psbt)

        # Send off final tx to sweep the wallet
        self.wrpc.sendrawtransaction(final_tx)

    # Test wrapper to avoid mixed-inputs signing for Ledger
    def test_signtx(self):
        supports_mixed = {'coldcard', 'trezor_1', 'digitalbitbox', 'keepkey'}
        supports_multisig = {'ledger', 'trezor_1', 'digitalbitbox', 'keepkey', 'coldcard', 'trezor_t'}
        supports_external = {'ledger', 'trezor_1', 'digitalbitbox', 'keepkey', 'coldcard'}
        if self.full_type not in supports_mixed:
            self._test_signtx("legacy", self.full_type in supports_multisig, self.full_type in supports_external)
            self._test_signtx("segwit", self.full_type in supports_multisig, self.full_type in supports_external)
        else:
            self._test_signtx("all", self.full_type in supports_multisig, self.full_type in supports_external)

    # Make a huge transaction which might cause some problems with different interfaces
    def test_big_tx(self):
        # make a huge transaction that is unrelated to the hardware wallet
        outputs = []
        num_inputs = 60
        for i in range(0, num_inputs):
            outputs.append({self.wpk_rpc.getnewaddress('', 'legacy'): 0.001})
        psbt = self.wpk_rpc.walletcreatefundedpsbt([], outputs, 0, {}, True)['psbt']
        psbt = self.wpk_rpc.walletprocesspsbt(psbt)['psbt']
        tx = self.wpk_rpc.finalizepsbt(psbt)['hex']
        txid = self.wpk_rpc.sendrawtransaction(tx)
        inputs = []
        for i in range(0, num_inputs):
            inputs.append({'txid': txid, 'vout': i})
        psbt = self.wpk_rpc.walletcreatefundedpsbt(inputs, [{self.wpk_rpc.getnewaddress('', 'legacy'): 0.001 * num_inputs}], 0, {'subtractFeeFromOutputs': [0]}, True)['psbt']
        # For cli, this should throw an exception
        try:
            result = self.do_command(self.dev_args + ['signtx', psbt])
            if self.interface == 'cli':
                self.fail('Big tx did not cause CLI to error')
            if self.type == 'coldcard':
                self.assertEqual(result['code'], -7)
            else:
                self.assertNotIn('code', result)
                self.assertNotIn('error', result)
        except OSError:
            if self.interface == 'cli':
                pass
예제 #3
0
파일: test_device.py 프로젝트: nopara73/HWI
class TestGetKeypool(DeviceTestCase):
    def setUp(self):
        self.rpc = AuthServiceProxy('http://{}@127.0.0.1:18443'.format(self.rpc_userpass))
        if '{}_test'.format(self.full_type) not in self.rpc.listwallets():
            self.rpc.createwallet('{}_test'.format(self.full_type), True)
        self.wrpc = AuthServiceProxy('http://{}@127.0.0.1:18443/wallet/{}_test'.format(self.rpc_userpass, self.full_type))
        self.wpk_rpc = AuthServiceProxy('http://{}@127.0.0.1:18443/wallet/'.format(self.rpc_userpass))
        if '--testnet' not in self.dev_args:
            self.dev_args.append('--testnet')
        self.emulator.start()

    def tearDown(self):
        self.emulator.stop()

    def test_getkeypool_bad_args(self):
        result = self.do_command(self.dev_args + ['getkeypool', '--sh_wpkh', '--wpkh', '0', '20'])
        self.assertIn('error', result)
        self.assertIn('code', result)
        self.assertEqual(result['code'], -7)

    def test_getkeypool(self):
        non_keypool_desc = self.do_command(self.dev_args + ['getkeypool', '--nokeypool', '0', '20'])
        import_result = self.wpk_rpc.importmulti(non_keypool_desc)
        self.assertTrue(import_result[0]['success'])

        keypool_desc = self.do_command(self.dev_args + ['getkeypool', '0', '20'])
        import_result = self.wpk_rpc.importmulti(keypool_desc)
        self.assertFalse(import_result[0]['success'])

        import_result = self.wrpc.importmulti(keypool_desc)
        self.assertTrue(import_result[0]['success'])
        for i in range(0, 21):
            addr_info = self.wrpc.getaddressinfo(self.wrpc.getnewaddress())
            self.assertEqual(addr_info['hdkeypath'], "m/44'/1'/0'/0/{}".format(i))
            addr_info = self.wrpc.getaddressinfo(self.wrpc.getrawchangeaddress())
            self.assertEqual(addr_info['hdkeypath'], "m/44'/1'/0'/1/{}".format(i))

        keypool_desc = self.do_command(self.dev_args + ['getkeypool', '--sh_wpkh', '0', '20'])
        import_result = self.wrpc.importmulti(keypool_desc)
        self.assertTrue(import_result[0]['success'])
        for i in range(0, 21):
            addr_info = self.wrpc.getaddressinfo(self.wrpc.getnewaddress())
            self.assertEqual(addr_info['hdkeypath'], "m/49'/1'/0'/0/{}".format(i))
            addr_info = self.wrpc.getaddressinfo(self.wrpc.getrawchangeaddress())
            self.assertEqual(addr_info['hdkeypath'], "m/49'/1'/0'/1/{}".format(i))

        keypool_desc = self.do_command(self.dev_args + ['getkeypool', '--wpkh', '0', '20'])
        import_result = self.wrpc.importmulti(keypool_desc)
        self.assertTrue(import_result[0]['success'])
        for i in range(0, 21):
            addr_info = self.wrpc.getaddressinfo(self.wrpc.getnewaddress())
            self.assertEqual(addr_info['hdkeypath'], "m/84'/1'/0'/0/{}".format(i))
            addr_info = self.wrpc.getaddressinfo(self.wrpc.getrawchangeaddress())
            self.assertEqual(addr_info['hdkeypath'], "m/84'/1'/0'/1/{}".format(i))

        keypool_desc = self.do_command(self.dev_args + ['getkeypool', '--sh_wpkh', '--account', '3', '0', '20'])
        import_result = self.wrpc.importmulti(keypool_desc)
        self.assertTrue(import_result[0]['success'])
        for i in range(0, 21):
            addr_info = self.wrpc.getaddressinfo(self.wrpc.getnewaddress())
            self.assertEqual(addr_info['hdkeypath'], "m/49'/1'/3'/0/{}".format(i))
            addr_info = self.wrpc.getaddressinfo(self.wrpc.getrawchangeaddress())
            self.assertEqual(addr_info['hdkeypath'], "m/49'/1'/3'/1/{}".format(i))
        keypool_desc = self.do_command(self.dev_args + ['getkeypool', '--wpkh', '--account', '3', '0', '20'])
        import_result = self.wrpc.importmulti(keypool_desc)
        self.assertTrue(import_result[0]['success'])
        for i in range(0, 21):
            addr_info = self.wrpc.getaddressinfo(self.wrpc.getnewaddress())
            self.assertEqual(addr_info['hdkeypath'], "m/84'/1'/3'/0/{}".format(i))
            addr_info = self.wrpc.getaddressinfo(self.wrpc.getrawchangeaddress())
            self.assertEqual(addr_info['hdkeypath'], "m/84'/1'/3'/1/{}".format(i))

        keypool_desc = self.do_command(self.dev_args + ['getkeypool', '--path', 'm/0h/0h/4h/*', '0', '20'])
        import_result = self.wrpc.importmulti(keypool_desc)
        self.assertTrue(import_result[0]['success'])
        for i in range(0, 21):
            addr_info = self.wrpc.getaddressinfo(self.wrpc.getnewaddress())
            self.assertEqual(addr_info['hdkeypath'], "m/0'/0'/4'/{}".format(i))

        keypool_desc = self.do_command(self.dev_args + ['getkeypool', '--path', '/0h/0h/4h/*', '0', '20'])
        self.assertEqual(keypool_desc['error'], 'Path must start with m/')
        self.assertEqual(keypool_desc['code'], -7)
        keypool_desc = self.do_command(self.dev_args + ['getkeypool', '--path', 'm/0h/0h/4h/', '0', '20'])
        self.assertEqual(keypool_desc['error'], 'Path must end with /*')
        self.assertEqual(keypool_desc['code'], -7)
예제 #4
0
class Bitcoind():
    def __init__(self, bitcoind_path):
        self.bitcoind_path = bitcoind_path
        self.datadir = tempfile.mkdtemp()
        self.rpc = None
        self.bitcoind_proc = None
        self.userpass = None

    def start(self):
        def get_free_port():
            s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            s.bind(("", 0))
            s.listen(1)
            port = s.getsockname()[1]
            s.close()
            return port

        self.p2p_port = get_free_port()
        self.rpc_port = get_free_port()

        self.bitcoind_proc = subprocess.Popen([
            self.bitcoind_path, "-regtest", f"-datadir={self.datadir}",
            "-noprinttoconsole", "-fallbackfee=0.0002", "-keypool=1",
            f"-port={self.p2p_port}", f"-rpcport={self.rpc_port}"
        ])

        atexit.register(self.cleanup)

        # Wait for cookie file to be created
        cookie_path = os.path.join(self.datadir, "regtest", ".cookie")
        while not os.path.exists(cookie_path):
            time.sleep(0.5)
        # Read .cookie file to get user and pass
        with open(cookie_path) as f:
            self.userpass = f.readline().lstrip().rstrip()
        self.rpc_url = f"http://{self.userpass}@127.0.0.1:{self.rpc_port}"
        self.rpc = AuthServiceProxy(self.rpc_url)

        # Wait for bitcoind to be ready
        ready = False
        while not ready:
            try:
                self.rpc.getblockchaininfo()
                ready = True
            except JSONRPCException:
                time.sleep(0.5)
                pass

        # Make sure there are blocks and coins available
        self.rpc.createwallet(wallet_name="supply")
        self.wrpc = self.get_wallet_rpc("supply")
        self.wrpc.generatetoaddress(101, self.wrpc.getnewaddress())

    def get_wallet_rpc(self, wallet):
        url = self.rpc_url + f"/wallet/{wallet}"
        return AuthServiceProxy(url)

    def cleanup(self):
        if self.bitcoind_proc is not None and self.bitcoind_proc.poll(
        ) is None:
            self.bitcoind_proc.kill()
        shutil.rmtree(self.datadir)

    @staticmethod
    def create(*args, **kwargs):
        c = Bitcoind(*args, **kwargs)
        c.start()
        return c
예제 #5
0
파일: test_device.py 프로젝트: shannona/HWI
class TestDisplayAddress(DeviceTestCase):
    def setUp(self):
        self.rpc = AuthServiceProxy('http://{}@127.0.0.1:18443'.format(
            self.rpc_userpass))
        if '{}_test'.format(self.full_type) not in self.rpc.listwallets():
            self.rpc.createwallet('{}_test'.format(self.full_type), True)
        self.wrpc = AuthServiceProxy(
            'http://{}@127.0.0.1:18443/wallet/{}_test'.format(
                self.rpc_userpass, self.full_type))
        self.wpk_rpc = AuthServiceProxy(
            'http://{}@127.0.0.1:18443/wallet/'.format(self.rpc_userpass))
        if '--testnet' not in self.dev_args:
            self.dev_args.append('--testnet')
        self.emulator.start()

    def test_display_address_bad_args(self):
        result = self.do_command(self.dev_args + [
            'displayaddress', '--sh_wpkh', '--wpkh', '--path',
            'm/49h/1h/0h/0/0'
        ])
        self.assertIn('error', result)
        self.assertIn('code', result)
        self.assertEqual(result['code'], -7)

    def test_display_address_path(self):
        result = self.do_command(
            self.dev_args + ['displayaddress', '--path', 'm/44h/1h/0h/0/0'])
        self.assertNotIn('error', result)
        self.assertNotIn('code', result)
        self.assertIn('address', result)

        result = self.do_command(
            self.dev_args +
            ['displayaddress', '--sh_wpkh', '--path', 'm/49h/1h/0h/0/0'])
        self.assertNotIn('error', result)
        self.assertNotIn('code', result)
        self.assertIn('address', result)

        result = self.do_command(
            self.dev_args +
            ['displayaddress', '--wpkh', '--path', 'm/84h/1h/0h/0/0'])
        self.assertNotIn('error', result)
        self.assertNotIn('code', result)
        self.assertIn('address', result)

    def test_display_address_bad_path(self):
        result = self.do_command(self.dev_args +
                                 ['displayaddress', '--path', 'f'])
        self.assertEquals(result['code'], -7)

    def test_display_address_descriptor(self):
        account_xpub = self.do_command(self.dev_args +
                                       ['getxpub', 'm/84h/1h/0h'])['xpub']
        p2sh_segwit_account_xpub = self.do_command(
            self.dev_args + ['getxpub', 'm/49h/1h/0h'])['xpub']
        legacy_account_xpub = self.do_command(
            self.dev_args + ['getxpub', 'm/44h/1h/0h'])['xpub']

        # Native SegWit address using xpub:
        result = self.do_command(self.dev_args + [
            'displayaddress', '--desc', 'wpkh([' + self.fingerprint +
            '/84h/1h/0h]' + account_xpub + '/0/0)'
        ])
        self.assertNotIn('error', result)
        self.assertNotIn('code', result)
        self.assertIn('address', result)

        # Native SegWit address using hex encoded pubkey:
        result = self.do_command(self.dev_args + [
            'displayaddress', '--desc', 'wpkh([' + self.fingerprint +
            '/84h/1h/0h]' + xpub_to_pub_hex(account_xpub) + '/0/0)'
        ])
        self.assertNotIn('error', result)
        self.assertNotIn('code', result)
        self.assertIn('address', result)

        # P2SH wrapped SegWit address using xpub:
        result = self.do_command(self.dev_args + [
            'displayaddress', '--desc', 'sh(wpkh([' + self.fingerprint +
            '/49h/1h/0h]' + p2sh_segwit_account_xpub + '/0/0))'
        ])
        self.assertNotIn('error', result)
        self.assertNotIn('code', result)
        self.assertIn('address', result)

        # Legacy address
        result = self.do_command(self.dev_args + [
            'displayaddress', '--desc', 'pkh([' + self.fingerprint +
            '/44h/1h/0h]' + legacy_account_xpub + '/0/0)'
        ])
        self.assertNotIn('error', result)
        self.assertNotIn('code', result)
        self.assertIn('address', result)

        # Should check xpub
        result = self.do_command(self.dev_args + [
            'displayaddress', '--desc', 'wpkh([' + self.fingerprint +
            '/84h/1h/0h]' + "not_and_xpub" + '/0/0)'
        ])
        self.assertIn('error', result)
        self.assertIn('code', result)
        self.assertEqual(result['code'], -7)

        # Should check hex pub
        result = self.do_command(self.dev_args + [
            'displayaddress', '--desc', 'wpkh([' + self.fingerprint +
            '/84h/1h/0h]' + "not_and_xpub" + '/0/0)'
        ])
        self.assertIn('error', result)
        self.assertIn('code', result)
        self.assertEqual(result['code'], -7)

        # Should check fingerprint
        self.do_command(self.dev_args + [
            'displayaddress', '--desc', 'wpkh([00000000/84h/1h/0h]' +
            account_xpub + '/0/0)'
        ])
        self.assertIn('error', result)
        self.assertIn('code', result)
        self.assertEqual(result['code'], -7)

    def test_display_address_multisig_path(self):
        supports_multisig = {'trezor_1', 'keepkey', 'coldcard', 'trezor_t'}
        if self.full_type not in supports_multisig:
            return
        # Import some keys to the watch only wallet and get multisig address
        keypool_desc = self.do_command(self.dev_args +
                                       ['getkeypool', '--sh_wpkh', '40', '50'])
        import_result = self.wrpc.importmulti(keypool_desc)
        self.assertTrue(import_result[0]['success'])
        keypool_desc = self.do_command(
            self.dev_args +
            ['getkeypool', '--sh_wpkh', '--internal', '40', '50'])
        import_result = self.wrpc.importmulti(keypool_desc)
        self.assertTrue(import_result[0]['success'])
        sh_wpkh_addr = self.wrpc.getnewaddress('', 'p2sh-segwit')
        wpkh_addr = self.wrpc.getnewaddress('', 'bech32')
        pkh_addr = self.wrpc.getnewaddress('', 'legacy')
        self.wrpc.importaddress(wpkh_addr)
        self.wrpc.importaddress(pkh_addr)

        # pubkeys to construct 2-of-3 multisig descriptors for import
        sh_wpkh_info = self.wrpc.getaddressinfo(sh_wpkh_addr)
        wpkh_info = self.wrpc.getaddressinfo(wpkh_addr)
        pkh_info = self.wrpc.getaddressinfo(pkh_addr)

        pubkeys = [
            sh_wpkh_info['desc'][8:-11], wpkh_info['desc'][5:-10],
            pkh_info['desc'][4:-10]
        ]

        # Get the descriptors with their checksums
        sh_multi_desc = self.wrpc.getdescriptorinfo('sh(sortedmulti(2,' +
                                                    pubkeys[0] + ',' +
                                                    pubkeys[1] + ',' +
                                                    pubkeys[2] +
                                                    '))')['descriptor']
        sh_wsh_multi_desc = self.wrpc.getdescriptorinfo(
            'sh(wsh(sortedmulti(2,' + pubkeys[0] + ',' + pubkeys[1] + ',' +
            pubkeys[2] + ')))')['descriptor']
        wsh_multi_desc = self.wrpc.getdescriptorinfo('wsh(sortedmulti(2,' +
                                                     pubkeys[2] + ',' +
                                                     pubkeys[1] + ',' +
                                                     pubkeys[0] +
                                                     '))')['descriptor']

        sh_multi_import = {
            'desc': sh_multi_desc,
            "timestamp": "now",
            "label": "shmulti-display"
        }
        sh_wsh_multi_import = {
            'desc': sh_wsh_multi_desc,
            "timestamp": "now",
            "label": "shwshmulti-display"
        }
        # re-order pubkeys to allow import without "already have private keys" error
        wsh_multi_import = {
            'desc': wsh_multi_desc,
            "timestamp": "now",
            "label": "wshmulti-display"
        }
        multi_result = self.wrpc.importmulti(
            [sh_multi_import, sh_wsh_multi_import, wsh_multi_import])
        self.assertTrue(multi_result[0]['success'])
        self.assertTrue(multi_result[1]['success'])
        self.assertTrue(multi_result[2]['success'])

        sh_multi_addr = self.wrpc.getaddressesbylabel(
            "shmulti-display").popitem()[0]
        sh_wsh_multi_addr = self.wrpc.getaddressesbylabel(
            "shwshmulti-display").popitem()[0]
        wsh_multi_addr = self.wrpc.getaddressesbylabel(
            "wshmulti-display").popitem()[0]

        sh_multi_addr_redeem_script = self.wrpc.getaddressinfo(
            sh_multi_addr)['hex']
        sh_wsh_multi_addr_redeem_script = self.wrpc.getaddressinfo(
            sh_multi_addr)['hex']
        wsh_multi_addr_redeem_script = self.wrpc.getaddressinfo(
            sh_multi_addr)['hex']

        path = pubkeys[2][1:24] + ',' + pubkeys[1][1:24] + ',' + pubkeys[0][
            1:24]
        # need to replace `'` with `h` for stdin option to work
        path = path.replace("'", "h")

        # legacy
        result = self.do_command(self.dev_args + [
            'displayaddress', '--path', path, '--redeem_script',
            sh_multi_addr_redeem_script
        ])
        self.assertNotIn('error', result)
        self.assertNotIn('code', result)
        self.assertIn('address', result)
        self.assertEqual(sh_multi_addr, result['address'])

        # wrapped segwit
        result = self.do_command(self.dev_args + [
            'displayaddress', '--sh_wpkh', '--path', path, '--redeem_script',
            sh_wsh_multi_addr_redeem_script
        ])
        self.assertNotIn('error', result)
        self.assertNotIn('code', result)
        self.assertIn('address', result)
        self.assertEqual(sh_wsh_multi_addr, result['address'])

        # native setwit
        result = self.do_command(self.dev_args + [
            'displayaddress', '--wpkh', '--path', path, '--redeem_script',
            wsh_multi_addr_redeem_script
        ])
        self.assertNotIn('error', result)
        self.assertNotIn('code', result)
        self.assertIn('address', result)
        # removes prefix and checksum since regtest gives
        # prefix `bcrt` on Bitcoin Core while wallets return testnet `tb` prefix
        self.assertEqual(wsh_multi_addr[4:58], result['address'][2:56])

    def test_display_address_multisig_descriptor(self):
        supports_multisig = {'trezor_1', 'keepkey', 'coldcard', 'trezor_t'}
        if self.full_type not in supports_multisig:
            return
        # Import some keys to the watch only wallet and get multisig address
        keypool_desc = self.do_command(self.dev_args +
                                       ['getkeypool', '--sh_wpkh', '50', '60'])
        import_result = self.wrpc.importmulti(keypool_desc)
        self.assertTrue(import_result[0]['success'])
        keypool_desc = self.do_command(
            self.dev_args +
            ['getkeypool', '--sh_wpkh', '--internal', '50', '60'])
        import_result = self.wrpc.importmulti(keypool_desc)
        self.assertTrue(import_result[0]['success'])
        sh_wpkh_addr = self.wrpc.getnewaddress('', 'p2sh-segwit')
        wpkh_addr = self.wrpc.getnewaddress('', 'bech32')
        pkh_addr = self.wrpc.getnewaddress('', 'legacy')
        self.wrpc.importaddress(wpkh_addr)
        self.wrpc.importaddress(pkh_addr)

        # pubkeys to construct 2-of-3 multisig descriptors for import
        sh_wpkh_info = self.wrpc.getaddressinfo(sh_wpkh_addr)
        wpkh_info = self.wrpc.getaddressinfo(wpkh_addr)
        pkh_info = self.wrpc.getaddressinfo(pkh_addr)

        pubkeys = [
            sh_wpkh_info['desc'][8:-11], wpkh_info['desc'][5:-10],
            pkh_info['desc'][4:-10]
        ]

        # Get the descriptors with their checksums
        sh_multi_desc = self.wrpc.getdescriptorinfo('sh(sortedmulti(2,' +
                                                    pubkeys[0] + ',' +
                                                    pubkeys[1] + ',' +
                                                    pubkeys[2] +
                                                    '))')['descriptor']
        sh_wsh_multi_desc = self.wrpc.getdescriptorinfo(
            'sh(wsh(sortedmulti(2,' + pubkeys[0] + ',' + pubkeys[1] + ',' +
            pubkeys[2] + ')))')['descriptor']
        wsh_multi_desc = self.wrpc.getdescriptorinfo('wsh(sortedmulti(2,' +
                                                     pubkeys[2] + ',' +
                                                     pubkeys[1] + ',' +
                                                     pubkeys[0] +
                                                     '))')['descriptor']

        sh_multi_import = {
            'desc': sh_multi_desc,
            "timestamp": "now",
            "label": "shmulti-display-desc"
        }
        sh_wsh_multi_import = {
            'desc': sh_wsh_multi_desc,
            "timestamp": "now",
            "label": "shwshmulti-display-desc"
        }
        # re-order pubkeys to allow import without "already have private keys" error
        wsh_multi_import = {
            'desc': wsh_multi_desc,
            "timestamp": "now",
            "label": "wshmulti-display-desc"
        }
        multi_result = self.wrpc.importmulti(
            [sh_multi_import, sh_wsh_multi_import, wsh_multi_import])
        self.assertTrue(multi_result[0]['success'])
        self.assertTrue(multi_result[1]['success'])
        self.assertTrue(multi_result[2]['success'])

        sh_multi_addr = self.wrpc.getaddressesbylabel(
            "shmulti-display-desc").popitem()[0]
        sh_wsh_multi_addr = self.wrpc.getaddressesbylabel(
            "shwshmulti-display-desc").popitem()[0]
        wsh_multi_addr = self.wrpc.getaddressesbylabel(
            "wshmulti-display-desc").popitem()[0]

        # need to replace `'` with `h` and to remove checksome for the stdin option to work
        sh_multi_desc = sh_multi_desc.replace("'", "h").split('#')[0]
        sh_wsh_multi_desc = sh_wsh_multi_desc.replace("'", "h").split('#')[0]
        wsh_multi_desc = wsh_multi_desc.replace("'", "h").split('#')[0]

        # legacy
        result = self.do_command(self.dev_args +
                                 ['displayaddress', '--desc', sh_multi_desc])
        self.assertNotIn('error', result)
        self.assertNotIn('code', result)
        self.assertIn('address', result)
        self.assertEqual(sh_multi_addr, result['address'])

        # wrapped segwit
        result = self.do_command(
            self.dev_args + ['displayaddress', '--desc', sh_wsh_multi_desc])
        self.assertNotIn('error', result)
        self.assertNotIn('code', result)
        self.assertIn('address', result)
        self.assertEqual(sh_wsh_multi_addr, result['address'])

        # native setwit
        result = self.do_command(self.dev_args +
                                 ['displayaddress', '--desc', wsh_multi_desc])
        self.assertNotIn('error', result)
        self.assertNotIn('code', result)
        self.assertIn('address', result)
        # removes prefix and checksum since regtest gives
        # prefix `bcrt` on Bitcoin Core while wallets return testnet `tb` prefix
        self.assertEqual(wsh_multi_addr[4:58], result['address'][2:56])
예제 #6
0
# Wait for bitcoind to be ready
ready: bool = False
while not ready:
    try:
        rpc.getblockchaininfo()
        ready = True
    except Exception:
        time.sleep(0.5)
        pass
print('bitcoind ready')

for item in rpc.listwalletdir()['wallets']:
    if 'big' == item['name']:
        break
else:
    rpc.createwallet('big')

if 'big' not in rpc.listwallets():
    rpc.loadwallet('big')

def_rpc = AuthServiceProxy(
    'http://{}@127.0.0.1:18443/wallet/'.format(userpass))
big_rpc = AuthServiceProxy(
    'http://{}@127.0.0.1:18443/wallet/big'.format(userpass))

print('mining')
gen_addr = big_rpc.getnewaddress()
if rpc.getblockcount() == 0:
    big_rpc.generatetoaddress(200, gen_addr)

self_addr = big_rpc.getnewaddress()