Exemple #1
0
    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'])
            self.assertTrue(sign_res["signed"])
            self.assertTrue(finalize_res["complete"])
        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] = KeyOriginInfo(b"\x00\x00\x00\x01", path.path)
                for pubkey, (leaves, origin) in psbt_input.tap_bip32_paths.items():
                    psbt_input.tap_bip32_paths[pubkey] = (leaves, KeyOriginInfo(b"\x00\x00\x00\x01", origin.path))
            for pubkey, path in second_psbt.inputs[0].hd_keypaths.items():
                second_psbt.inputs[0].hd_keypaths[pubkey] = KeyOriginInfo(b"\x00\x00\x00\x01", path.path)
            for pubkey, (leaves, origin) in second_psbt.inputs[0].tap_bip32_paths.items():
                second_psbt.inputs[0].tap_bip32_paths[pubkey] = (leaves, KeyOriginInfo(b"\x00\x00\x00\x01", origin.path))

            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(first_sign_res["signed"])
            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:
                if single_input:
                    self.assertFalse(second_sign_res["signed"])
                else:
                    self.assertTrue(second_sign_res["signed"])
                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']
Exemple #2
0
    def _make_multisig(self, addrtype):
        if addrtype == "legacy":
            coin_type = 0
            desc_prefix = "sh("
            desc_suffix = ")"
        elif addrtype == "p2sh-segwit":
            coin_type = 1 if self.emulator.strict_bip48 else 0
            desc_prefix = "sh(wsh("
            desc_suffix = "))"
        elif addrtype == "bech32":
            coin_type = 2 if self.emulator.strict_bip48 else 0
            desc_prefix = "wsh("
            desc_suffix = ")"
        else:
            self.fail(f"Unknown address type {addrtype}")

        desc_pubkeys = []
        xpubs: Dict[bytes, KeyOriginInfo] = {}
        for account in range(0, 3 if self.emulator.supports_device_multiple_multisig else 1):
            path = f"/48h/1h/{account}h/{coin_type}h"
            origin = '{}{}'.format(self.emulator.fingerprint, path)
            xpub = self.do_command(self.dev_args + ["getxpub", "m{}".format(path)])
            desc_pubkeys.append("[{}]{}/0/0".format(origin, xpub["xpub"]))
            if self.emulator.include_xpubs:
                extkey = ExtendedKey.deserialize(xpub["xpub"])
                xpubs[extkey.serialize()] = KeyOriginInfo.from_string(origin)

        if not self.emulator.supports_device_multiple_multisig:
            # If the device does not support itself in the multisig more than once,
            # we need to fetch a key from Core, and use another key that will not be signed with
            counter_descs = self.wpk_rpc.listdescriptors()["descriptors"]
            desc = parse_descriptor(counter_descs[0]["desc"])
            pubkey_prov = None
            while pubkey_prov is None:
                if len(desc.pubkeys) > 0:
                    pubkey_prov = desc.pubkeys[0]
                else:
                    desc = desc.subdescriptors[0]
            assert pubkey_prov.extkey is not None
            assert pubkey_prov.origin is not None
            pubkey_prov.deriv_path = "/0/0"
            desc_pubkeys.append(pubkey_prov.to_string())
            if self.emulator.include_xpubs:
                xpubs[pubkey_prov.extkey.serialize()] = pubkey_prov.origin

            # A fixed key
            fixed_extkey = ExtendedKey.deserialize("tpubDCBWBScQPGv4Xk3JSbhw6wYYpayMjb2eAYyArpbSqQTbLDpphHGAetB6VQgVeftLML8vDSUEWcC2xDi3qJJ3YCDChJDvqVzpgoYSuT52MhJ")
            fixed_origin = KeyOriginInfo(b"\xde\xad\xbe\xef", [0x80000000])
            desc_pubkeys.append(PubkeyProvider(fixed_origin, fixed_extkey.to_string(), "/0/0").to_string())
            if self.emulator.include_xpubs:
                xpubs[fixed_extkey.serialize()] = fixed_origin

        desc = AddChecksum(f"{desc_prefix}sortedmulti(2,{desc_pubkeys[0]},{desc_pubkeys[1]},{desc_pubkeys[2]}){desc_suffix}")

        return desc, self.rpc.deriveaddresses(desc)[0], xpubs