Example #1
0
    def test_attack_change_input(self, client):
        """
        In Phases 1 and 2 the attacker replaces a non-multisig input
        `input_real` with a multisig input `input_fake`, which allows the
        attacker to provide a 1-of-2 multisig change address. When `input_real`
        is provided in the signing phase, an error must occur.
        """
        address_n = parse_path("48'/1'/0'/0/0")
        attacker_multisig_public_key = bytes.fromhex(
            "03653a148b68584acb97947344a7d4fd6a6f8b8485cad12987ff8edac874268088"
        )

        input_real = proto.TxInputType(
            address_n=address_n,
            prev_hash=TXHASH_fbbff7,
            prev_index=1,
            script_type=proto.InputScriptType.SPENDP2SHWITNESS,
            amount=1000000,
        )

        multisig_fake = proto.MultisigRedeemScriptType(
            m=1,
            nodes=[
                btc.get_public_node(client, address_n, coin_name="Testnet").node,
                proto.HDNodeType(
                    depth=0,
                    fingerprint=0,
                    child_num=0,
                    chain_code=bytes(32),
                    public_key=attacker_multisig_public_key,
                ),
            ],
            address_n=[],
        )

        input_fake = proto.TxInputType(
            address_n=address_n,
            prev_hash=input_real.prev_hash,
            prev_index=input_real.prev_index,
            script_type=input_real.script_type,
            multisig=multisig_fake,
            amount=input_real.amount,
        )

        output_payee = proto.TxOutputType(
            address="n2eMqTT929pb1RDNuqEnxdaLau1rxy3efi",
            amount=1000,
            script_type=proto.OutputScriptType.PAYTOADDRESS,
        )

        output_change = proto.TxOutputType(
            address_n=address_n,
            amount=input_real.amount - output_payee.amount - 1000,
            script_type=proto.OutputScriptType.PAYTOP2SHWITNESS,
            multisig=multisig_fake,
        )

        attack_count = 2

        def attack_processor(msg):
            nonlocal attack_count
            # replace the first input_real with input_fake
            if attack_count > 0 and msg.tx.inputs and msg.tx.inputs[0] == input_real:
                msg.tx.inputs[0] = input_fake
                attack_count -= 1
            return msg

        client.set_filter(proto.TxAck, attack_processor)
        with client:
            client.set_expected_responses(
                [
                    request_input(0),
                    request_output(0),
                    proto.ButtonRequest(code=B.ConfirmOutput),
                    request_output(1),
                    proto.ButtonRequest(code=B.SignTx),
                    request_input(0),
                    request_output(0),
                    request_output(1),
                    request_input(0),
                    proto.Failure(code=proto.FailureType.ProcessError),
                ]
            )

            with pytest.raises(TrezorFailure) as exc:
                btc.sign_tx(
                    client, "Testnet", [input_real], [output_payee, output_change]
                )
                # must not produce this tx:
                # 01000000000101396e2c107427f9eaece56a37539983adb8efd52b067c3d4567805fc8f3f7bffb01000000171600147a876a07b366f79000b441335f2907f777a0280bffffffff02e8030000000000001976a914e7c1345fc8f87c68170b3aa798a956c2fe6a9eff88ac703a0f000000000017a914a1261837f1b40e84346b1504ffe294e402965f2687024830450221009ff835e861be4e36ca1f2b6224aee2f253dfb9f456b13e4b1724bb4aaff4c9c802205e10679c2ead85743119f468cba5661f68b7da84dd2d477a7215fef98516f1f9012102af12ddd0d55e4fa2fcd084148eaf5b0b641320d0431d63d1e9a90f3cbd0d540700000000

            assert exc.value.code == proto.FailureType.ProcessError
            if client.features.model == "1":
                assert exc.value.message.endswith("Failed to compile input")
            else:
                assert exc.value.message.endswith(
                    "Transaction has changed during signing"
                )
        def test_multisig(index):
            address_n, multisig = create_multisig(index, "m/0/0", signatures[0])
            inp1 = proto.TxInputType(
                address_n=address_n,
                # TchpthUkRys1VQWgnQyLJNaA4MLBjVmRL2c
                multisig=multisig,
                prev_hash=TXHASH_3f7c39,
                prev_index=1,
                script_type=proto.InputScriptType.SPENDMULTISIG,
                decred_tree=0,
            )

            address_n, multisig = create_multisig(index, "m/0/1", signatures[1])
            inp2 = proto.TxInputType(
                address_n=address_n,
                # TcnfDEfMhkM3oLWqiq9v9GmYgLK7qfjitKG
                multisig=multisig,
                prev_hash=TXHASH_16da18,
                prev_index=0,
                script_type=proto.InputScriptType.SPENDMULTISIG,
                decred_tree=0,
            )

            address_n, multisig = create_multisig(index, "m/1/0")
            out1 = proto.TxOutputType(
                address_n=address_n,
                # TcrrURA3Bzj4isGU48PdSP9SDoU5oCpjEcb
                multisig=multisig,
                amount=99900000,
                script_type=proto.OutputScriptType.PAYTOMULTISIG,
                decred_script_version=0,
            )

            out2 = proto.TxOutputType(
                address="TsWjioPrP8E1TuTMmTrVMM2BA4iPrjQXBpR",
                amount=300000000,
                script_type=proto.OutputScriptType.PAYTOADDRESS,
                decred_script_version=0,
            )

            with self.client:
                self.client.set_expected_responses(
                    [
                        proto.TxRequest(
                            request_type=proto.RequestType.TXINPUT,
                            details=proto.TxRequestDetailsType(request_index=0),
                        ),
                        proto.TxRequest(
                            request_type=proto.RequestType.TXMETA,
                            details=proto.TxRequestDetailsType(tx_hash=TXHASH_3f7c39),
                        ),
                        proto.TxRequest(
                            request_type=proto.RequestType.TXINPUT,
                            details=proto.TxRequestDetailsType(
                                tx_hash=TXHASH_3f7c39, request_index=0
                            ),
                        ),
                        proto.TxRequest(
                            request_type=proto.RequestType.TXOUTPUT,
                            details=proto.TxRequestDetailsType(
                                tx_hash=TXHASH_3f7c39, request_index=0
                            ),
                        ),
                        proto.TxRequest(
                            request_type=proto.RequestType.TXOUTPUT,
                            details=proto.TxRequestDetailsType(
                                tx_hash=TXHASH_3f7c39, request_index=1
                            ),
                        ),
                        proto.TxRequest(
                            request_type=proto.RequestType.TXINPUT,
                            details=proto.TxRequestDetailsType(request_index=1),
                        ),
                        proto.TxRequest(
                            request_type=proto.RequestType.TXMETA,
                            details=proto.TxRequestDetailsType(tx_hash=TXHASH_16da18),
                        ),
                        proto.TxRequest(
                            request_type=proto.RequestType.TXINPUT,
                            details=proto.TxRequestDetailsType(
                                tx_hash=TXHASH_16da18, request_index=0
                            ),
                        ),
                        proto.TxRequest(
                            request_type=proto.RequestType.TXOUTPUT,
                            details=proto.TxRequestDetailsType(
                                tx_hash=TXHASH_16da18, request_index=0
                            ),
                        ),
                        proto.TxRequest(
                            request_type=proto.RequestType.TXOUTPUT,
                            details=proto.TxRequestDetailsType(
                                tx_hash=TXHASH_16da18, request_index=1
                            ),
                        ),
                        proto.TxRequest(
                            request_type=proto.RequestType.TXOUTPUT,
                            details=proto.TxRequestDetailsType(request_index=0),
                        ),
                        proto.TxRequest(
                            request_type=proto.RequestType.TXOUTPUT,
                            details=proto.TxRequestDetailsType(request_index=1),
                        ),
                        proto.ButtonRequest(code=proto.ButtonRequestType.ConfirmOutput),
                        proto.ButtonRequest(code=proto.ButtonRequestType.SignTx),
                        proto.TxRequest(
                            request_type=proto.RequestType.TXINPUT,
                            details=proto.TxRequestDetailsType(request_index=0),
                        ),
                        proto.TxRequest(
                            request_type=proto.RequestType.TXINPUT,
                            details=proto.TxRequestDetailsType(request_index=1),
                        ),
                        proto.TxRequest(request_type=proto.RequestType.TXFINISHED),
                    ]
                )
                (signature, serialized_tx) = btc.sign_tx(
                    self.client, "Decred Testnet", [inp1, inp2], [out1, out2]
                )

            signatures[0][index] = signature[0]
            signatures[1][index] = signature[1]
            return serialized_tx
    def test_one_one_fee(self):
        self.setup_mnemonic_allallall()

        # tx: 93373e63cc626c4a7d049ad775d6511bb5eba985f142db660c9b9f955c722f5c
        # input 0: 1.234567 TAZ

        inp1 = proto.TxInputType(
            address_n=parse_path("m/Zcash Testnet/0h/0/0"
                                 ),  # tmQoJ3PTXgQLaRRZZYT6xk8XtjRbr2kCqwu
            # amount=123456700,
            prev_hash=TXHASH_93373e,
            prev_index=0,
        )

        out1 = proto.TxOutputType(
            address='tmJ1xYxP8XNTtCoDgvdmQPSrxh5qZJgy65Z',
            amount=123456700 - 1940,
            script_type=proto.OutputScriptType.PAYTOADDRESS,
        )

        with self.client:
            self.client.set_tx_api(TxApiZcash)
            self.client.set_expected_responses([
                proto.TxRequest(
                    request_type=proto.RequestType.TXINPUT,
                    details=proto.TxRequestDetailsType(request_index=0)),
                proto.TxRequest(
                    request_type=proto.RequestType.TXMETA,
                    details=proto.TxRequestDetailsType(tx_hash=TXHASH_93373e)),
                proto.TxRequest(request_type=proto.RequestType.TXOUTPUT,
                                details=proto.TxRequestDetailsType(
                                    request_index=0, tx_hash=TXHASH_93373e)),
                proto.TxRequest(request_type=proto.RequestType.TXEXTRADATA,
                                details=proto.TxRequestDetailsType(
                                    tx_hash=TXHASH_93373e,
                                    extra_data_offset=0,
                                    extra_data_len=1024)),
                proto.TxRequest(request_type=proto.RequestType.TXEXTRADATA,
                                details=proto.TxRequestDetailsType(
                                    tx_hash=TXHASH_93373e,
                                    extra_data_offset=1024,
                                    extra_data_len=1024)),
                proto.TxRequest(request_type=proto.RequestType.TXEXTRADATA,
                                details=proto.TxRequestDetailsType(
                                    tx_hash=TXHASH_93373e,
                                    extra_data_offset=2048,
                                    extra_data_len=1024)),
                proto.TxRequest(request_type=proto.RequestType.TXEXTRADATA,
                                details=proto.TxRequestDetailsType(
                                    tx_hash=TXHASH_93373e,
                                    extra_data_offset=3072,
                                    extra_data_len=629)),
                proto.TxRequest(
                    request_type=proto.RequestType.TXOUTPUT,
                    details=proto.TxRequestDetailsType(request_index=0)),
                proto.ButtonRequest(
                    code=proto.ButtonRequestType.ConfirmOutput),
                proto.ButtonRequest(code=proto.ButtonRequestType.SignTx),
                proto.TxRequest(
                    request_type=proto.RequestType.TXINPUT,
                    details=proto.TxRequestDetailsType(request_index=0)),
                proto.TxRequest(
                    request_type=proto.RequestType.TXOUTPUT,
                    details=proto.TxRequestDetailsType(request_index=0)),
                proto.TxRequest(
                    request_type=proto.RequestType.TXOUTPUT,
                    details=proto.TxRequestDetailsType(request_index=0)),
                proto.TxRequest(request_type=proto.RequestType.TXFINISHED),
            ])

            (signatures,
             serialized_tx) = self.client.sign_tx('Zcash', [
                 inp1,
             ], [
                 out1,
             ])

        # Accepted by network: tx dcc2a10894e0e8a785c2afd4de2d958207329b9acc2b987fd768a09c5efc4547
        assert hexlify(
            serialized_tx
        ) == b'01000000015c2f725c959f9b0c66db42f185a9ebb51b51d675d79a047d4a6c62cc633e3793000000006a4730440220670b2b63d749a7038f9aea6ddf0302fe63bdcad93dafa4a89a1f0e7300ae2484022002c50af43fd867490cea0c527273c5828ff1b9a5115678f155a1830737cf29390121030e669acac1f280d1ddf441cd2ba5e97417bf2689e4bbec86df4f831bf9f7ffd0ffffffff0128c55b07000000001976a9145b157a678a10021243307e4bb58f36375aa80e1088ac00000000'
    def test_send_multisig_3_change(self):
        self.setup_mnemonic_allallall()
        nodes = [
            btc.get_public_node(self.client, parse_path("84'/1'/%d'" % index))
            for index in range(1, 4)
        ]
        multisig = proto.MultisigRedeemScriptType(
            nodes=[deserialize(n.xpub) for n in nodes],
            address_n=[1, 0],
            signatures=[b"", b"", b""],
            m=2,
        )
        multisig2 = proto.MultisigRedeemScriptType(
            nodes=[deserialize(n.xpub) for n in nodes],
            address_n=[1, 1],
            signatures=[b"", b"", b""],
            m=2,
        )

        inp1 = proto.TxInputType(
            address_n=parse_path("84'/1'/1'/1/0"),
            prev_hash=bytes.fromhex(
                "c9348040bbc2024e12dcb4a0b4806b0398646b91acf314da028c3f03dd0179fc"
            ),
            prev_index=0,
            script_type=proto.InputScriptType.SPENDWITNESS,
            multisig=multisig,
            amount=1604000,
        )

        out1 = proto.TxOutputType(
            address_n=parse_path("84'/1'/1'/1/1"),
            amount=1603000,
            multisig=multisig2,
            script_type=proto.OutputScriptType.PAYTOP2SHWITNESS,
        )

        with self.client:
            self.client.set_expected_responses([
                proto.TxRequest(
                    request_type=proto.RequestType.TXINPUT,
                    details=proto.TxRequestDetailsType(request_index=0),
                ),
                proto.TxRequest(
                    request_type=proto.RequestType.TXOUTPUT,
                    details=proto.TxRequestDetailsType(request_index=0),
                ),
                proto.ButtonRequest(code=proto.ButtonRequestType.SignTx),
                proto.TxRequest(
                    request_type=proto.RequestType.TXINPUT,
                    details=proto.TxRequestDetailsType(request_index=0),
                ),
                proto.TxRequest(
                    request_type=proto.RequestType.TXOUTPUT,
                    details=proto.TxRequestDetailsType(request_index=0),
                ),
                proto.TxRequest(
                    request_type=proto.RequestType.TXINPUT,
                    details=proto.TxRequestDetailsType(request_index=0),
                ),
                proto.TxRequest(request_type=proto.RequestType.TXFINISHED),
            ])
            signatures, _ = btc.sign_tx(self.client,
                                        "Testnet", [inp1], [out1],
                                        prev_txes=TX_API)
            # store signature
            inp1.multisig.signatures[0] = signatures[0]
            # sign with third key
            inp1.address_n[2] = H_(3)
            out1.address_n[2] = H_(3)
            self.client.set_expected_responses([
                proto.TxRequest(
                    request_type=proto.RequestType.TXINPUT,
                    details=proto.TxRequestDetailsType(request_index=0),
                ),
                proto.TxRequest(
                    request_type=proto.RequestType.TXOUTPUT,
                    details=proto.TxRequestDetailsType(request_index=0),
                ),
                proto.ButtonRequest(code=proto.ButtonRequestType.SignTx),
                proto.TxRequest(
                    request_type=proto.RequestType.TXINPUT,
                    details=proto.TxRequestDetailsType(request_index=0),
                ),
                proto.TxRequest(
                    request_type=proto.RequestType.TXOUTPUT,
                    details=proto.TxRequestDetailsType(request_index=0),
                ),
                proto.TxRequest(
                    request_type=proto.RequestType.TXINPUT,
                    details=proto.TxRequestDetailsType(request_index=0),
                ),
                proto.TxRequest(request_type=proto.RequestType.TXFINISHED),
            ])
            _, serialized_tx = btc.sign_tx(self.client,
                                           "Testnet", [inp1], [out1],
                                           prev_txes=TX_API)

        assert (
            serialized_tx.hex() ==
            "01000000000101fc7901dd033f8c02da14f3ac916b6498036b80b4a0b4dc124e02c2bb408034c90000000000ffffffff01b87518000000000017a914536250d41937e5b641082447580ff6a8e46c122a870400473044022003c26107a5a47f1f900ef8aa758977530cd13ea37a33971abae8d75cac2f9f34022039e2b8c2c1d0c24ff4fc026652e1f27ad8e3ed6c9bf485f61d9aa691cb57830801483045022100963b0dc0ab46e963a66ab6e69e5e41bac6c4fedc127cac12c560b029d54fe87402205b3bcdcf313dccd78e5dce0540e7d3c8cc1bf83f13c1f9f01811eb791fd35c8101695221039dba3a72f5dc3cad17aa924b5a03c34561465f997d0cb15993f2ca2c0be771c42103cd39f3f08bbd508dce4d307d57d0c70c258c285878bfda579fa260acc738c25d2102cd631ba95beca1d64766f5540885092d0bb384a3c13b6c3a5334d0ebacf51b9553ae00000000"
        )
    def test_send_p2sh_change(self):
        self.setup_mnemonic_allallall()
        inp1 = proto.TxInputType(
            address_n=parse_path("49'/1'/0'/1/0"),
            # 2N1LGaGg836mqSQqiuUBLfcyGBhyZbremDX
            amount=123456789,
            prev_hash=bytes.fromhex(
                "20912f98ea3ed849042efed0fdac8cb4fc301961c5988cba56902d8ffb61c337"
            ),
            prev_index=0,
            script_type=proto.InputScriptType.SPENDP2SHWITNESS,
        )
        out1 = proto.TxOutputType(
            address="tb1qqzv60m9ajw8drqulta4ld4gfx0rdh82un5s65s",
            amount=12300000,
            script_type=proto.OutputScriptType.PAYTOADDRESS,
        )
        out2 = proto.TxOutputType(
            address_n=parse_path("49'/1'/0'/1/0"),
            script_type=proto.OutputScriptType.PAYTOP2SHWITNESS,
            amount=123456789 - 11000 - 12300000,
        )
        with self.client:
            self.client.set_expected_responses([
                proto.TxRequest(
                    request_type=proto.RequestType.TXINPUT,
                    details=proto.TxRequestDetailsType(request_index=0),
                ),
                proto.TxRequest(
                    request_type=proto.RequestType.TXOUTPUT,
                    details=proto.TxRequestDetailsType(request_index=0),
                ),
                proto.ButtonRequest(
                    code=proto.ButtonRequestType.ConfirmOutput),
                proto.TxRequest(
                    request_type=proto.RequestType.TXOUTPUT,
                    details=proto.TxRequestDetailsType(request_index=1),
                ),
                proto.ButtonRequest(code=proto.ButtonRequestType.SignTx),
                proto.TxRequest(
                    request_type=proto.RequestType.TXINPUT,
                    details=proto.TxRequestDetailsType(request_index=0),
                ),
                proto.TxRequest(
                    request_type=proto.RequestType.TXOUTPUT,
                    details=proto.TxRequestDetailsType(request_index=0),
                ),
                proto.TxRequest(
                    request_type=proto.RequestType.TXOUTPUT,
                    details=proto.TxRequestDetailsType(request_index=1),
                ),
                proto.TxRequest(
                    request_type=proto.RequestType.TXINPUT,
                    details=proto.TxRequestDetailsType(request_index=0),
                ),
                proto.TxRequest(request_type=proto.RequestType.TXFINISHED),
            ])
            _, serialized_tx = btc.sign_tx(self.client,
                                           "Testnet", [inp1], [out1, out2],
                                           prev_txes=TX_API)

        assert (
            serialized_tx.hex() ==
            "0100000000010137c361fb8f2d9056ba8c98c5611930fcb48cacfdd0fe2e0449d83eea982f91200000000017160014d16b8c0680c61fc6ed2e407455715055e41052f5ffffffff02e0aebb00000000001600140099a7ecbd938ed1839f5f6bf6d50933c6db9d5c3df39f060000000017a91458b53ea7f832e8f096e896b8713a8c6df0e892ca8702483045022100bd3d8b8ad35c094e01f6282277300e575f1021678fc63ec3f9945d6e35670da3022052e26ef0dd5f3741c9d5939d1dec5464c15ab5f2c85245e70a622df250d4eb7c012103e7bfe10708f715e8538c92d46ca50db6f657bbc455b7494e6a0303ccdb868b7900000000"
        )
    def test_send_native_change(self):
        self.setup_mnemonic_allallall()
        inp1 = proto.TxInputType(
            address_n=parse_path("84'/1'/0'/0/0"),
            amount=12300000,
            prev_hash=bytes.fromhex(
                "09144602765ce3dd8f4329445b20e3684e948709c5cdcaf12da3bb079c99448a"
            ),
            prev_index=0,
            script_type=proto.InputScriptType.SPENDWITNESS,
        )
        out1 = proto.TxOutputType(
            address="2N4Q5FhU2497BryFfUgbqkAJE87aKHUhXMp",
            amount=5000000,
            script_type=proto.OutputScriptType.PAYTOADDRESS,
        )
        out2 = proto.TxOutputType(
            address_n=parse_path("84'/1'/0'/1/0"),
            script_type=proto.OutputScriptType.PAYTOWITNESS,
            amount=12300000 - 11000 - 5000000,
        )
        with self.client:
            self.client.set_expected_responses([
                proto.TxRequest(
                    request_type=proto.RequestType.TXINPUT,
                    details=proto.TxRequestDetailsType(request_index=0),
                ),
                proto.TxRequest(
                    request_type=proto.RequestType.TXOUTPUT,
                    details=proto.TxRequestDetailsType(request_index=0),
                ),
                proto.ButtonRequest(
                    code=proto.ButtonRequestType.ConfirmOutput),
                proto.TxRequest(
                    request_type=proto.RequestType.TXOUTPUT,
                    details=proto.TxRequestDetailsType(request_index=1),
                ),
                proto.ButtonRequest(code=proto.ButtonRequestType.SignTx),
                proto.TxRequest(
                    request_type=proto.RequestType.TXINPUT,
                    details=proto.TxRequestDetailsType(request_index=0),
                ),
                proto.TxRequest(
                    request_type=proto.RequestType.TXOUTPUT,
                    details=proto.TxRequestDetailsType(request_index=0),
                ),
                proto.TxRequest(
                    request_type=proto.RequestType.TXOUTPUT,
                    details=proto.TxRequestDetailsType(request_index=1),
                ),
                proto.TxRequest(
                    request_type=proto.RequestType.TXINPUT,
                    details=proto.TxRequestDetailsType(request_index=0),
                ),
                proto.TxRequest(request_type=proto.RequestType.TXFINISHED),
            ])
            _, serialized_tx = btc.sign_tx(self.client,
                                           "Testnet", [inp1], [out1, out2],
                                           prev_txes=TX_API)

        assert (
            serialized_tx.hex() ==
            "010000000001018a44999c07bba32df1cacdc50987944e68e3205b4429438fdde35c76024614090000000000ffffffff02404b4c000000000017a9147a55d61848e77ca266e79a39bfc85c580a6426c987a8386f0000000000160014cc8067093f6f843d6d3e22004a4290cd0c0f336b024730440220067675423ca6a0be3ddd5e13da00a9433775041e5cebc838873d2686f1d2840102201a5819e0312e6451d6b6180689101bce995685a51524cc4c3a5383f7bdab979a012103adc58245cf28406af0ef5cc24b8afba7f1be6c72f279b642d85c48798685f86200000000"
        )
    def test_send_multisig_1(self):
        self.setup_mnemonic_allallall()
        nodes = [
            btc.get_public_node(self.client, parse_path("49'/1'/%d'" % index))
            for index in range(1, 4)
        ]
        multisig = proto.MultisigRedeemScriptType(
            nodes=[deserialize(n.xpub) for n in nodes],
            address_n=[0, 0],
            signatures=[b"", b"", b""],
            m=2,
        )

        inp1 = proto.TxInputType(
            address_n=parse_path("49'/1'/1'/0/0"),
            prev_hash=bytes.fromhex(
                "9c31922be756c06d02167656465c8dc83bb553bf386a3f478ae65b5c021002be"
            ),
            prev_index=1,
            script_type=proto.InputScriptType.SPENDP2SHWITNESS,
            multisig=multisig,
            amount=1610436,
        )

        out1 = proto.TxOutputType(
            address=
            "tb1qch62pf820spe9mlq49ns5uexfnl6jzcezp7d328fw58lj0rhlhasge9hzy",
            amount=1605000,
            script_type=proto.OutputScriptType.PAYTOADDRESS,
        )

        with self.client:
            self.client.set_expected_responses([
                proto.TxRequest(
                    request_type=proto.RequestType.TXINPUT,
                    details=proto.TxRequestDetailsType(request_index=0),
                ),
                proto.TxRequest(
                    request_type=proto.RequestType.TXOUTPUT,
                    details=proto.TxRequestDetailsType(request_index=0),
                ),
                proto.ButtonRequest(
                    code=proto.ButtonRequestType.ConfirmOutput),
                proto.ButtonRequest(code=proto.ButtonRequestType.SignTx),
                proto.TxRequest(
                    request_type=proto.RequestType.TXINPUT,
                    details=proto.TxRequestDetailsType(request_index=0),
                ),
                proto.TxRequest(
                    request_type=proto.RequestType.TXOUTPUT,
                    details=proto.TxRequestDetailsType(request_index=0),
                ),
                proto.TxRequest(
                    request_type=proto.RequestType.TXINPUT,
                    details=proto.TxRequestDetailsType(request_index=0),
                ),
                proto.TxRequest(request_type=proto.RequestType.TXFINISHED),
            ])
            signatures, _ = btc.sign_tx(self.client,
                                        "Testnet", [inp1], [out1],
                                        prev_txes=TX_API)
            # store signature
            inp1.multisig.signatures[0] = signatures[0]
            # sign with third key
            inp1.address_n[2] = H_(3)
            self.client.set_expected_responses([
                proto.TxRequest(
                    request_type=proto.RequestType.TXINPUT,
                    details=proto.TxRequestDetailsType(request_index=0),
                ),
                proto.TxRequest(
                    request_type=proto.RequestType.TXOUTPUT,
                    details=proto.TxRequestDetailsType(request_index=0),
                ),
                proto.ButtonRequest(
                    code=proto.ButtonRequestType.ConfirmOutput),
                proto.ButtonRequest(code=proto.ButtonRequestType.SignTx),
                proto.TxRequest(
                    request_type=proto.RequestType.TXINPUT,
                    details=proto.TxRequestDetailsType(request_index=0),
                ),
                proto.TxRequest(
                    request_type=proto.RequestType.TXOUTPUT,
                    details=proto.TxRequestDetailsType(request_index=0),
                ),
                proto.TxRequest(
                    request_type=proto.RequestType.TXINPUT,
                    details=proto.TxRequestDetailsType(request_index=0),
                ),
                proto.TxRequest(request_type=proto.RequestType.TXFINISHED),
            ])
            _, serialized_tx = btc.sign_tx(self.client,
                                           "Testnet", [inp1], [out1],
                                           prev_txes=TX_API)

        assert (
            serialized_tx.hex() ==
            "01000000000101be0210025c5be68a473f6a38bf53b53bc88d5c46567616026dc056e72b92319c01000000232200208d398cfb58a1d9cdb59ccbce81559c095e8c6f4a3e64966ca385078d9879f95effffffff01887d180000000000220020c5f4a0a4ea7c0392efe0a9670a73264cffa90b19107cd8a8e9750ff93c77fdfb0400483045022100dd6342c65197af27d7894d8b8b88b16b568ee3b5ebfdc55fdfb7caa9650e3b4c02200c7074a5bcb0068f63d9014c7cd2b0490aba75822d315d41aad444e9b86adf5201483045022100e7e6c2d21109512ba0609e93903e84bfb7731ac3962ee2c1cad54a7a30ff99a20220421497930226c39fc3834e8d6da3fc876516239518b0e82e2dc1e3c46271a17c01695221021630971f20fa349ba940a6ba3706884c41579cd760c89901374358db5dd545b92102f2ff4b353702d2bb03d4c494be19d77d0ab53d16161b53fbcaf1afeef4ad0cb52103e9b6b1c691a12ce448f1aedbbd588e064869c79fbd760eae3b8cd8a5f1a224db53ae00000000"
        )
Example #8
0
def test_p2wpkh_in_p2sh_remove_change(client):
    # Test fee bump with change-output removal. Originally fee was 3780, now 98060.

    inp1 = messages.TxInputType(
        address_n=parse_path("49h/1h/0h/0/4"),
        amount=100000,
        script_type=messages.InputScriptType.SPENDP2SHWITNESS,
        prev_hash=TXHASH_5e7667,
        prev_index=1,
        orig_hash=TXHASH_334cd7,
        orig_index=0,
    )

    inp2 = messages.TxInputType(
        address_n=parse_path("49h/1h/0h/0/3"),
        amount=998060,
        script_type=messages.InputScriptType.SPENDP2SHWITNESS,
        prev_hash=TXHASH_efaa41,
        prev_index=0,
        orig_hash=TXHASH_334cd7,
        orig_index=1,
    )

    out1 = messages.TxOutputType(
        # Actually m/49'/1'/0'/0/5.
        address="2MvUUSiQZDSqyeSdofKX9KrSCio1nANPDTe",
        amount=1000000,
        orig_hash=TXHASH_334cd7,
        orig_index=0,
    )

    with client:
        client.set_expected_responses(
            [
                request_input(0),
                request_meta(TXHASH_334cd7),
                request_orig_input(0, TXHASH_334cd7),
                request_input(1),
                request_orig_input(1, TXHASH_334cd7),
                messages.ButtonRequest(code=B.SignTx),
                request_output(0),
                request_orig_output(0, TXHASH_334cd7),
                request_orig_output(1, TXHASH_334cd7),
                messages.ButtonRequest(code=B.SignTx),
                request_input(0),
                request_meta(TXHASH_5e7667),
                request_input(0, TXHASH_5e7667),
                request_output(0, TXHASH_5e7667),
                request_output(1, TXHASH_5e7667),
                request_input(1),
                request_meta(TXHASH_efaa41),
                request_input(0, TXHASH_efaa41),
                request_output(0, TXHASH_efaa41),
                request_input(0),
                request_input(1),
                request_output(0),
                request_input(0),
                request_input(1),
                request_finished(),
            ]
        )
        _, serialized_tx = btc.sign_tx(
            client,
            "Testnet",
            [inp1, inp2],
            [out1],
            prev_txes=TX_CACHE_TESTNET,
        )

    assert (
        serialized_tx.hex()
        == "01000000000102d64ae26dceee1e309bed0821f39275b5f6e65d0072f8e23747ae76006967765e0100000017160014039ba06270e6c6c1ad4e6940515aa5cdbad33f9effffffff35ac1adc9e0cf408013090c52527d3cf9468d51e1a6c8408f5ed673eff41aaef0000000017160014209297fb46272a0b7e05139440dbd39daea3e25affffffff0140420f000000000017a9142369da13fee80c9d7fd8043bf1275c04deb360e68702483045022100c28eceaade3d0bc82e4b634d2c6d06feed4afe37c77b04b379eaf8c058b7190702202b7a369dd6104c13c60821c1ad4e7c2d8d37cf1962a9b3f5d70717709c021d63012103bb0e339d7495b1f355c49d385b79343e52e68d99de2fe1f7f476c465c9ccd16702483045022100f6a447b7f95fb067c87453c408aa648262adaf2472a7ccc754518cd06353b87502202e00359dd663eda24d381e070b92a5e41f1d047d276f685ff549a03659842b1b012103c2c2e65556ca4b7371549324b99390725493c8a6792e093a0bdcbb3e2d7df4ab00000000"
    )
Example #9
0
def test_p2wpkh_in_p2sh_fee_bump_from_external(client):
    # Use the change output and an external output to bump the fee.
    # Originally fee was 3780, now 108060 (94280 from change and 10000 from external).

    inp1 = messages.TxInputType(
        address_n=parse_path("49h/1h/0h/0/4"),
        amount=100000,
        script_type=messages.InputScriptType.SPENDP2SHWITNESS,
        prev_hash=TXHASH_5e7667,
        prev_index=1,
        orig_hash=TXHASH_334cd7,
        orig_index=0,
    )

    inp2 = messages.TxInputType(
        address_n=parse_path("49h/1h/0h/0/3"),
        amount=998060,
        script_type=messages.InputScriptType.SPENDP2SHWITNESS,
        prev_hash=TXHASH_efaa41,
        prev_index=0,
        orig_hash=TXHASH_334cd7,
        orig_index=1,
    )

    out1 = messages.TxOutputType(
        # Actually m/49'/1'/0'/0/5.
        address="2MvUUSiQZDSqyeSdofKX9KrSCio1nANPDTe",
        amount=990000,
        orig_hash=TXHASH_334cd7,
        orig_index=0,
    )

    with client:
        client.set_expected_responses(
            [
                request_input(0),
                request_meta(TXHASH_334cd7),
                request_orig_input(0, TXHASH_334cd7),
                request_input(1),
                request_orig_input(1, TXHASH_334cd7),
                messages.ButtonRequest(code=B.SignTx),
                request_output(0),
                request_orig_output(0, TXHASH_334cd7),
                messages.ButtonRequest(code=B.ConfirmOutput),
                (
                    client.features.model == "1",
                    messages.ButtonRequest(code=B.ConfirmOutput),
                ),
                request_orig_output(1, TXHASH_334cd7),
                messages.ButtonRequest(code=B.SignTx),
                request_input(0),
                request_meta(TXHASH_5e7667),
                request_input(0, TXHASH_5e7667),
                request_output(0, TXHASH_5e7667),
                request_output(1, TXHASH_5e7667),
                request_input(1),
                request_meta(TXHASH_efaa41),
                request_input(0, TXHASH_efaa41),
                request_output(0, TXHASH_efaa41),
                request_input(0),
                request_input(1),
                request_output(0),
                request_input(0),
                request_input(1),
                request_finished(),
            ]
        )
        _, serialized_tx = btc.sign_tx(
            client,
            "Testnet",
            [inp1, inp2],
            [out1],
            prev_txes=TX_CACHE_TESTNET,
        )

    assert (
        serialized_tx.hex()
        == "01000000000102d64ae26dceee1e309bed0821f39275b5f6e65d0072f8e23747ae76006967765e0100000017160014039ba06270e6c6c1ad4e6940515aa5cdbad33f9effffffff35ac1adc9e0cf408013090c52527d3cf9468d51e1a6c8408f5ed673eff41aaef0000000017160014209297fb46272a0b7e05139440dbd39daea3e25affffffff01301b0f000000000017a9142369da13fee80c9d7fd8043bf1275c04deb360e68702483045022100bd303aa0d923e73300e37971d43b9cd134230f8287e0e3b702aacd19ba8ef97b02202b4368b3e9d7478b8529ea2aeea23f6612ec05854510794958d6ce58c19082ad012103bb0e339d7495b1f355c49d385b79343e52e68d99de2fe1f7f476c465c9ccd1670247304402204869b27aa926d98bfd36912f71e335c1d6afb2c1a28102407066db5257e1b8810220197bcac3c85a721547974bd7309a6ea2b809810a595cbdca2da9599af4038ba2012103c2c2e65556ca4b7371549324b99390725493c8a6792e093a0bdcbb3e2d7df4ab00000000"
    )
Example #10
0
def test_p2wpkh_finalize(client):
    # Original input with disabled RBF opt-in, i.e. we finalize the transaction.
    inp1 = messages.TxInputType(
        address_n=parse_path("84h/1h/0h/0/2"),
        amount=20000000,
        script_type=messages.InputScriptType.SPENDWITNESS,
        prev_hash=TXHASH_43d273,
        prev_index=1,
        orig_hash=TXHASH_70f987,
        orig_index=0,
        sequence=4294967294,
    )

    # Original external output (actually 84h/1h/0h/0/0).
    out1 = messages.TxOutputType(
        address="tb1qkvwu9g3k2pdxewfqr7syz89r3gj557l3uuf9r9",
        amount=100000,
        script_type=messages.OutputScriptType.PAYTOWITNESS,
        orig_hash=TXHASH_70f987,
        orig_index=0,
    )

    # Change output. We bump the fee from 141 to 200.
    out2 = messages.TxOutputType(
        address_n=parse_path("84h/1h/0h/1/1"),
        amount=20000000 - 100000 - 200,
        script_type=messages.OutputScriptType.PAYTOWITNESS,
        orig_hash=TXHASH_70f987,
        orig_index=1,
    )

    with client:
        client.set_expected_responses(
            [
                request_input(0),
                request_meta(TXHASH_70f987),
                request_orig_input(0, TXHASH_70f987),
                messages.ButtonRequest(code=B.SignTx),
                request_output(0),
                request_orig_output(0, TXHASH_70f987),
                request_output(1),
                request_orig_output(1, TXHASH_70f987),
                messages.ButtonRequest(code=B.SignTx),
                request_input(0),
                request_meta(TXHASH_43d273),
                request_input(0, TXHASH_43d273),
                request_output(0, TXHASH_43d273),
                request_output(1, TXHASH_43d273),
                request_output(2, TXHASH_43d273),
                request_input(0),
                request_output(0),
                request_output(1),
                request_input(0),
                request_finished(),
            ]
        )
        _, serialized_tx = btc.sign_tx(
            client,
            "Testnet",
            [inp1],
            [out1, out2],
            lock_time=1348713,
            prev_txes=TX_CACHE_TESTNET,
        )

    assert (
        serialized_tx.hex()
        == "0100000000010106fcd13aab9f1eb618d0351196ecf20ff8fb60f9743484ad5917f4cad373d2430100000000feffffff02a086010000000000160014b31dc2a236505a6cb9201fa0411ca38a254a7bf198a52f0100000000160014167dae080bca35c9ea49c0c8335dcc4b252a1d700247304402201ee1828ab0ca7f8113989399edda8394c65e5c3c9fe597a78890c5d2c9bd2aeb022010e76ad6abe171e5cded6b374a344ee18a51d38477b76a4b6fb30289ed24beff01210357cb3a5918d15d224f14a89f0eb54478272108f6cbb9c473c1565e55260f6e9369941400"
    )
Example #11
0
def test_p2wpkh_payjoin(
    client, out1_amount, out2_amount, copayer_witness, fee_confirm, expected_tx
):
    # Original input.
    inp1 = messages.TxInputType(
        address_n=parse_path("84h/1h/0h/0/0"),
        amount=100000,
        script_type=messages.InputScriptType.SPENDWITNESS,
        prev_hash=TXHASH_e4b5b2,
        prev_index=0,
        orig_hash=TXHASH_65b768,
        orig_index=0,
        sequence=1516634,
    )

    # New presigned external input. (Actually 84h/1h/0h/1/1, making it easier to generate witnesses.)
    inp2 = messages.TxInputType(
        amount=19899859,
        script_type=messages.InputScriptType.EXTERNAL,
        prev_hash=TXHASH_70f987,
        prev_index=1,
        witness=bytes.fromhex(copayer_witness),
    )

    # PayJoined output.
    out1 = messages.TxOutputType(
        address="tb1qldlynaqp0hy4zc2aag3pkenzvxy65saesxw3wd",
        # Originally payment was 10000, now we add receiver's inp2.
        amount=out1_amount,
        script_type=messages.OutputScriptType.PAYTOWITNESS,
        orig_hash=TXHASH_65b768,
        orig_index=0,
    )

    # Original change.
    out2 = messages.TxOutputType(
        address_n=parse_path("84h/1h/0h/1/2"),
        amount=out2_amount,
        script_type=messages.OutputScriptType.PAYTOWITNESS,
        orig_hash=TXHASH_65b768,
        orig_index=1,
    )

    with client:
        client.set_expected_responses(
            [
                request_input(0),
                request_meta(TXHASH_65b768),
                request_orig_input(0, TXHASH_65b768),
                request_input(1),
                messages.ButtonRequest(code=B.SignTx),
                request_output(0),
                request_orig_output(0, TXHASH_65b768),
                request_output(1),
                request_orig_output(1, TXHASH_65b768),
                (fee_confirm, messages.ButtonRequest(code=B.SignTx)),
                request_input(0),
                request_meta(TXHASH_e4b5b2),
                request_input(0, TXHASH_e4b5b2),
                request_output(0, TXHASH_e4b5b2),
                request_output(1, TXHASH_e4b5b2),
                request_input(1),
                request_meta(TXHASH_70f987),
                request_input(0, TXHASH_70f987),
                request_output(0, TXHASH_70f987),
                request_output(1, TXHASH_70f987),
                request_input(0),
                request_input(1),
                request_output(0),
                request_output(1),
                request_input(0),
                request_input(1),
                request_finished(),
            ]
        )
        _, serialized_tx = btc.sign_tx(
            client,
            "Testnet",
            [inp1, inp2],
            [out1, out2],
            lock_time=1516634,
            prev_txes=TX_CACHE_TESTNET,
        )

    assert serialized_tx.hex() == expected_tx
    def test_send_multisig_1(self, client):
        nodes = [
            btc.get_public_node(client,
                                parse_path(f"49'/156'/{i}'"),
                                coin_name="Bgold").node for i in range(1, 4)
        ]
        multisig = proto.MultisigRedeemScriptType(nodes=nodes,
                                                  address_n=[1, 0],
                                                  signatures=[b"", b"", b""],
                                                  m=2)

        inp1 = proto.TxInputType(
            address_n=parse_path("49'/156'/1'/1/0"),
            prev_hash=TXHASH_25526b,
            prev_index=1,
            script_type=proto.InputScriptType.SPENDP2SHWITNESS,
            multisig=multisig,
            amount=1610436,
        )

        out1 = proto.TxOutputType(
            address="GfDB1tvjfm3bukeoBTtfNqrJVFohS2kCTe",
            amount=1605000,
            script_type=proto.OutputScriptType.PAYTOADDRESS,
        )

        with client:
            client.set_expected_responses([
                request_input(0),
                request_output(0),
                proto.ButtonRequest(code=B.ConfirmOutput),
                proto.ButtonRequest(code=B.SignTx),
                request_input(0),
                request_output(0),
                request_input(0),
                request_finished(),
            ])
            signatures, _ = btc.sign_tx(client,
                                        "Bgold", [inp1], [out1],
                                        prev_txes=TX_API)
            # store signature
            inp1.multisig.signatures[0] = signatures[0]
            # sign with third key
            inp1.address_n[2] = H_(3)
            client.set_expected_responses([
                request_input(0),
                request_output(0),
                proto.ButtonRequest(code=B.ConfirmOutput),
                proto.ButtonRequest(code=B.SignTx),
                request_input(0),
                request_output(0),
                request_input(0),
                request_finished(),
            ])
            _, serialized_tx = btc.sign_tx(client,
                                           "Bgold", [inp1], [out1],
                                           prev_txes=TX_API)

        assert (
            serialized_tx.hex() ==
            "0100000000010185c9dd4ae1071affd77d90b9d03c1b5fdd7c62cf30a9bb8230ad766cf06b52250100000023220020ea9ec48498c451286c2ebaf9e19255e2873b0fb517d67b2f2005298c7e437829ffffffff01887d1800000000001976a914ea5f904d195079a350b534db4446433b3cec222e88ac0400473044022077cb8b2a534f79328810ca8c330539ae9ffa086c359ddb7da11026557b04eef202201d95be0dd1da0aa01720953e52d5dabffd19a998d1490c13a21b8e52e4ead2e041483045022100e41cbd6a501ba8fe6f65554420e23e950d35af0da9b052da54a087463b0717ca02206c695c8d1f74f9535b5d89a2fd1f9326a0ef20e5400137f1e1daeee992b62b594169522103279aea0b253b144d1b2bb8532280001a996dcddd04f86e5e13df1355032cbc1321032c6465c956c0879663fa8be974c912d229c179a5cdedeb29611a1bec1f951eb22103494480a4b72101cbd2eadac8e18c7a3a7589a7f576bf46b8971c38c51e5eceeb53ae00000000"
        )
    def test_send_btg_multisig_change(self, client):
        nodes = [
            btc.get_public_node(client,
                                parse_path(f"48'/156'/{i}'"),
                                coin_name="Bgold").node for i in range(1, 4)
        ]

        def getmultisig(chain, nr, signatures=[b"", b"", b""], nodes=nodes):
            return proto.MultisigRedeemScriptType(nodes=nodes,
                                                  address_n=[chain, nr],
                                                  signatures=signatures,
                                                  m=2)

        inp1 = proto.TxInputType(
            address_n=parse_path("48'/156'/3'/0/0"),
            multisig=getmultisig(0, 0),
            # 33Ju286QvonBz5N1V754ZekQv4GLJqcc5R
            amount=48490,
            prev_hash=TXHASH_25526b,
            prev_index=0,
            script_type=proto.InputScriptType.SPENDMULTISIG,
        )
        out1 = proto.TxOutputType(
            address="GfDB1tvjfm3bukeoBTtfNqrJVFohS2kCTe",
            amount=24000,
            script_type=proto.OutputScriptType.PAYTOADDRESS,
        )
        out2 = proto.TxOutputType(
            address_n=parse_path("48'/156'/3'/1/0"),
            multisig=getmultisig(1, 0),
            script_type=proto.OutputScriptType.PAYTOMULTISIG,
            amount=24000,
        )
        with client:
            client.set_expected_responses([
                request_input(0),
                request_output(0),
                proto.ButtonRequest(code=B.ConfirmOutput),
                request_output(1),
                proto.ButtonRequest(code=B.SignTx),
                request_input(0),
                request_output(0),
                request_output(1),
                request_finished(),
            ])
            signatures, serialized_tx = btc.sign_tx(client,
                                                    "Bgold", [inp1],
                                                    [out1, out2],
                                                    prev_txes=TX_API)

        assert (
            signatures[0].hex() ==
            "3045022100d954f341ddd3ec96e4bc6cdb90f2df9b2032723f85e4a0187346dd743130bfca0220105ce08b795c70dc09a55569d7874bff684a877219ec2fc37c88cdffe12f332c"
        )

        inp1 = proto.TxInputType(
            address_n=parse_path("48'/156'/1'/0/0"),
            multisig=getmultisig(0, 0, [b"", b"", signatures[0]]),
            amount=48490,
            prev_hash=TXHASH_25526b,
            prev_index=0,
            script_type=proto.InputScriptType.SPENDMULTISIG,
        )
        out2.address_n[2] = H_(1)

        with client:
            client.set_expected_responses([
                request_input(0),
                request_output(0),
                proto.ButtonRequest(code=B.ConfirmOutput),
                request_output(1),
                proto.ButtonRequest(code=B.SignTx),
                request_input(0),
                request_output(0),
                request_output(1),
                request_finished(),
            ])
            signatures, serialized_tx = btc.sign_tx(client,
                                                    "Bgold", [inp1],
                                                    [out1, out2],
                                                    prev_txes=TX_API)

        assert (
            signatures[0].hex() ==
            "30440220614f9a18695365a2edba0d930404a77cae970d3430ad86c5b5239a96fd54bf84022030bc76a322e3b2b1c987622b5eb6da23ac1e6c905ee9b3b6405a4e4edd5bbb87"
        )
        assert (
            serialized_tx.hex() ==
            "010000000185c9dd4ae1071affd77d90b9d03c1b5fdd7c62cf30a9bb8230ad766cf06b522500000000fdfd00004730440220614f9a18695365a2edba0d930404a77cae970d3430ad86c5b5239a96fd54bf84022030bc76a322e3b2b1c987622b5eb6da23ac1e6c905ee9b3b6405a4e4edd5bbb8741483045022100d954f341ddd3ec96e4bc6cdb90f2df9b2032723f85e4a0187346dd743130bfca0220105ce08b795c70dc09a55569d7874bff684a877219ec2fc37c88cdffe12f332c414c695221035a8db79c0ef57a202664a3da60ca41e8865c6d86ed0aafc03f8e75173341b58021037fba152d8fca660cc49973d8bc9421ff49a75b44ea200873d70d3990f763ed4c210348cbcbd93e069416e0d5db93e86b5698852d9fd54502ad0bed9722fa83f90e4b53aeffffffff02c05d0000000000001976a914ea5f904d195079a350b534db4446433b3cec222e88acc05d00000000000017a914623c803f7fb654dac8dda7786fbf9bc38cd867f48700000000"
        )
Example #14
0
    def test_2_of_3(self, client):
        nodes = [
            btc.get_public_node(client, parse_path("48'/0'/%d'" % index)).node
            for index in range(1, 4)
        ]

        multisig = proto.MultisigRedeemScriptType(
            nodes=nodes, address_n=[0, 0], signatures=[b"", b"", b""], m=2
        )
        # Let's go to sign with key 1
        inp1 = proto.TxInputType(
            address_n=parse_path("48'/0'/1'/0/0"),
            prev_hash=TXHASH_c6091a,
            prev_index=1,
            script_type=proto.InputScriptType.SPENDMULTISIG,
            multisig=multisig,
        )

        out1 = proto.TxOutputType(
            address="12iyMbUb4R2K3gre4dHSrbu5azG5KaqVss",
            amount=100000,
            script_type=proto.OutputScriptType.PAYTOADDRESS,
        )

        with client:
            client.set_expected_responses(
                [
                    request_input(0),
                    request_meta(TXHASH_c6091a),
                    request_input(0, TXHASH_c6091a),
                    request_output(0, TXHASH_c6091a),
                    request_output(1, TXHASH_c6091a),
                    request_output(0),
                    proto.ButtonRequest(code=B.ConfirmOutput),
                    proto.ButtonRequest(code=B.SignTx),
                    request_input(0),
                    request_output(0),
                    request_output(0),
                    request_finished(),
                ]
            )

            # Now we have first signature
            signatures1, _ = btc.sign_tx(
                client, "Bitcoin", [inp1], [out1], prev_txes=TX_API
            )

        assert (
            signatures1[0].hex()
            == "3044022052f4a3dc5ca3e86ed66abb1e2b4d9b9ace7d96f5615944beea19e58280847c2902201bd3ff32a38366a4eed0373e27da26ebc0d2a4c2bbeffd83e8a60e313d95b9e3"
        )

        # ---------------------------------------
        # Let's do second signature using 3rd key

        multisig = proto.MultisigRedeemScriptType(
            nodes=nodes,
            address_n=[0, 0],
            signatures=[
                signatures1[0],
                b"",
                b"",
            ],  # Fill signature from previous signing process
            m=2,
        )

        # Let's do a second signature with key 3
        inp3 = proto.TxInputType(
            address_n=parse_path("48'/0'/3'/0/0"),
            prev_hash=TXHASH_c6091a,
            prev_index=1,
            script_type=proto.InputScriptType.SPENDMULTISIG,
            multisig=multisig,
        )

        with client:
            client.set_expected_responses(
                [
                    request_input(0),
                    request_meta(TXHASH_c6091a),
                    request_input(0, TXHASH_c6091a),
                    request_output(0, TXHASH_c6091a),
                    request_output(1, TXHASH_c6091a),
                    request_output(0),
                    proto.ButtonRequest(code=B.ConfirmOutput),
                    proto.ButtonRequest(code=B.SignTx),
                    request_input(0),
                    request_output(0),
                    request_output(0),
                    request_finished(),
                ]
            )
            signatures2, serialized_tx = btc.sign_tx(
                client, "Bitcoin", [inp3], [out1], prev_txes=TX_API
            )

        assert (
            signatures2[0].hex()
            == "304402203828fd48540811be6a1b12967e7012587c46e6f05c78d42471e7b25c06bc7afc0220749274bc1aa698335b00400c5ba946a70b6b46c711324fbc4989279737a57f49"
        )

        assert (
            serialized_tx.hex()
            == "010000000152ba4dfcde9c4bed88f55479cdea03e711ae586e9a89352a98230c4cdf1a09c601000000fc00473044022052f4a3dc5ca3e86ed66abb1e2b4d9b9ace7d96f5615944beea19e58280847c2902201bd3ff32a38366a4eed0373e27da26ebc0d2a4c2bbeffd83e8a60e313d95b9e30147304402203828fd48540811be6a1b12967e7012587c46e6f05c78d42471e7b25c06bc7afc0220749274bc1aa698335b00400c5ba946a70b6b46c711324fbc4989279737a57f49014c6952210203ed6187880ae932660086e55d4561a57952dd200aa3ed2aa66b73e5723a0ce7210360e7f32fd3c8dee27a166f6614c598929699ee66acdcbda5fb24571bf2ae1ca021037c4c7e5d3293ab0f97771dcfdf83caadab341f427f54713da8b2c590a834f03b53aeffffffff01a0860100000000001976a91412e8391ad256dcdc023365978418d658dfecba1c88ac00000000"
        )
    def test_attack_script_type(self, client):
        # Scenario: The attacker falsely claims that the transaction is Taproot-only to avoid prev
        # tx streaming and gives a lower amount for one of the inputs. The correct input types and
        # amounts are revelaled only in step6_sign_segwit_inputs() to get a valid signature. This
        # results in a transaction which pays a fee much larger than what the user confirmed.

        inp1 = messages.TxInputType(
            address_n=parse_path("84'/1'/0'/1/0"),
            amount=7289000,
            prev_hash=TXHASH_65b811,
            prev_index=1,
            script_type=messages.InputScriptType.SPENDWITNESS,
        )
        inp2 = messages.TxInputType(
            address_n=parse_path("84'/1'/1'/0/0"),
            amount=12300000,
            prev_hash=TXHASH_091446,
            prev_index=0,
            script_type=messages.InputScriptType.SPENDWITNESS,
        )

        out1 = messages.TxOutputType(
            address="tb1q694ccp5qcc0udmfwgp692u2s2hjpq5h407urtu",
            script_type=messages.OutputScriptType.PAYTOADDRESS,
            amount=7289000 + 10000 - 1000,
        )

        attack_count = 5

        def attack_processor(msg):
            nonlocal attack_count

            if attack_count > 0 and msg.tx.inputs:
                attack_count -= 1
                if msg.tx.inputs[0] == inp2:
                    msg.tx.inputs[0].amount = 10000
                msg.tx.inputs[0].address_n[0] = H_(86)
                msg.tx.inputs[
                    0].script_type = messages.InputScriptType.SPENDTAPROOT

            return msg

        with client:
            client.set_filter(messages.TxAck, attack_processor)
            client.set_expected_responses([
                request_input(0),
                request_input(1),
                request_output(0),
                messages.ButtonRequest(code=B.ConfirmOutput),
                messages.ButtonRequest(code=B.SignTx),
                request_input(0),
                request_input(1),
                request_output(0),
                request_input(0),
                request_input(1),
                messages.Failure(code=messages.FailureType.ProcessError),
            ])
            with pytest.raises(TrezorFailure) as exc:
                btc.sign_tx(client,
                            "Testnet", [inp1, inp2], [out1],
                            prev_txes=TX_API)
            assert exc.value.code == messages.FailureType.ProcessError
            assert exc.value.message.endswith(
                "Transaction has changed during signing")
Example #16
0
def test_tx_meld(client):
    # Meld two original transactions into one, joining the change-outputs into a different one.

    inp1 = messages.TxInputType(
        address_n=parse_path("49h/1h/0h/0/4"),
        amount=100000,
        script_type=messages.InputScriptType.SPENDP2SHWITNESS,
        prev_hash=TXHASH_5e7667,
        prev_index=1,
        orig_hash=TXHASH_334cd7,
        orig_index=0,
    )

    inp2 = messages.TxInputType(
        address_n=parse_path("49h/1h/0h/0/8"),
        amount=4973340,
        script_type=messages.InputScriptType.SPENDP2SHWITNESS,
        prev_hash=TXHASH_6673b7,
        prev_index=0,
        orig_hash=TXHASH_ed89ac,
        orig_index=0,
    )

    inp3 = messages.TxInputType(
        address_n=parse_path("49h/1h/0h/0/3"),
        amount=998060,
        script_type=messages.InputScriptType.SPENDP2SHWITNESS,
        prev_hash=TXHASH_efaa41,
        prev_index=0,
        orig_hash=TXHASH_334cd7,
        orig_index=1,
    )

    inp4 = messages.TxInputType(
        address_n=parse_path("49h/1h/0h/0/9"),
        amount=839318869,
        script_type=messages.InputScriptType.SPENDP2SHWITNESS,
        prev_hash=TXHASH_927784,
        prev_index=0,
        orig_hash=TXHASH_ed89ac,
        orig_index=1,
    )

    out1 = messages.TxOutputType(
        address="moE1dVYvebvtaMuNdXQKvu4UxUftLmS1Gt",
        amount=100000000,
        orig_hash=TXHASH_ed89ac,
        orig_index=1,
    )

    out2 = messages.TxOutputType(
        # Actually m/49'/1'/0'/0/5.
        address="2MvUUSiQZDSqyeSdofKX9KrSCio1nANPDTe",
        amount=1000000,
        orig_hash=TXHASH_334cd7,
        orig_index=0,
    )

    # Change-output. Original fees were 3780 + 90720 = 94500.
    out3 = messages.TxOutputType(
        address_n=parse_path("49h/1h/0h/1/0"),
        amount=100000 + 4973340 + 998060 + 839318869 - 100000000 - 1000000 - 94500,
        script_type=messages.OutputScriptType.PAYTOP2SHWITNESS,
    )

    with client:
        client.set_expected_responses(
            [
                request_input(0),
                request_meta(TXHASH_334cd7),
                request_orig_input(0, TXHASH_334cd7),
                request_input(1),
                request_meta(TXHASH_ed89ac),
                request_orig_input(0, TXHASH_ed89ac),
                request_input(2),
                request_orig_input(1, TXHASH_334cd7),
                request_input(3),
                request_orig_input(1, TXHASH_ed89ac),
                messages.ButtonRequest(code=B.SignTx),
                messages.ButtonRequest(code=B.SignTx),
                request_output(0),
                request_orig_output(0, TXHASH_ed89ac),
                request_orig_output(1, TXHASH_ed89ac),
                request_output(1),
                request_orig_output(0, TXHASH_334cd7),
                request_output(2),
                request_orig_output(1, TXHASH_334cd7),
                messages.ButtonRequest(code=B.SignTx),
                request_input(0),
                request_meta(TXHASH_5e7667),
                request_input(0, TXHASH_5e7667),
                request_output(0, TXHASH_5e7667),
                request_output(1, TXHASH_5e7667),
                request_input(1),
                request_meta(TXHASH_6673b7),
                request_input(0, TXHASH_6673b7),
                request_input(1, TXHASH_6673b7),
                request_input(2, TXHASH_6673b7),
                request_input(3, TXHASH_6673b7),
                request_input(4, TXHASH_6673b7),
                request_output(0, TXHASH_6673b7),
                request_input(2),
                request_meta(TXHASH_efaa41),
                request_input(0, TXHASH_efaa41),
                request_output(0, TXHASH_efaa41),
                request_input(3),
                request_meta(TXHASH_927784),
                request_input(0, TXHASH_927784),
                request_input(1, TXHASH_927784),
                request_input(2, TXHASH_927784),
                request_output(0, TXHASH_927784),
                request_input(0),
                request_input(1),
                request_input(2),
                request_input(3),
                request_output(0),
                request_output(1),
                request_output(2),
                request_input(0),
                request_input(1),
                request_input(2),
                request_input(3),
                request_finished(),
            ]
        )
        _, serialized_tx = btc.sign_tx(
            client,
            "Testnet",
            [inp1, inp2, inp3, inp4],
            [out1, out2, out3],
            prev_txes=TX_CACHE_TESTNET,
        )

    assert (
        serialized_tx.hex()
        == "01000000000104d64ae26dceee1e309bed0821f39275b5f6e65d0072f8e23747ae76006967765e0100000017160014039ba06270e6c6c1ad4e6940515aa5cdbad33f9effffffff57b4cb6156c63a8d6b834e236a21edf9d0f11fdd2fd0f9b28248328e24b773660000000017160014adbbadefe594e9e4bfccb9c699ae5d4f18716772ffffffff35ac1adc9e0cf408013090c52527d3cf9468d51e1a6c8408f5ed673eff41aaef0000000017160014209297fb46272a0b7e05139440dbd39daea3e25affffffff0b03833dd525dae7f7ed1455f386fc7899737a1cc3f538c7c4efbc7be08477920000000017160014681ea49259abb892460bf3373e8a0b43d877fa18ffffffff0300e1f505000000001976a914548cb80e45b1d36312fe0cb075e5e337e3c54cef88ac40420f000000000017a9142369da13fee80c9d7fd8043bf1275c04deb360e687590d5d2c0000000017a91458b53ea7f832e8f096e896b8713a8c6df0e892ca870247304402205b4b304cb5a23cd3b73aa586c983cbadefc3fcbcb8fb33684037b17a818726c002202a3f529183eebf2f06d041b18d379579c22d908be31060752179f01d125ff020012103bb0e339d7495b1f355c49d385b79343e52e68d99de2fe1f7f476c465c9ccd167024730440220666ebf2c146d4a369971ec1d5b69fce2f3b8e2c0ba689e6077ebed513f91dd760220200e203355156e23abf5b536ac174df4109985feddf86ab065c12f0da8339d6a012102a52d8cf5a89c284bacff90a3d7c30a0166e0074ca3fc385f3efce638c50493b30247304402207d6331026626fc133813ea672147c95feac29a3d7deefb49ef1d0194e061d53802207e4c3a3b8f3c2e11845684d74a5f1d8395da0a8e65e18c7f72155aac82be648e012103c2c2e65556ca4b7371549324b99390725493c8a6792e093a0bdcbb3e2d7df4ab02473044022047f95a95ea8cac78f057e15e37ac5cebd6abcf50d87e5509d30c730cb0f7e89f02201d861acb267c0bc100cac99cad42b067a39614602eef5f9f791c1875f24dd0de0121028cbc37e1816a23086fa738c8415def477e813e20f484dbbd6f5a33a37c32225100000000"
    )
    def test_send_native(self):
        self.setup_mnemonic_allallall()
        inp1 = proto.TxInputType(
            address_n=parse_path("84'/1'/0'/0/0"),
            amount=12300000,
            prev_hash=bytes.fromhex(
                "09144602765ce3dd8f4329445b20e3684e948709c5cdcaf12da3bb079c99448a"
            ),
            prev_index=0,
            script_type=proto.InputScriptType.SPENDWITNESS,
        )
        out1 = proto.TxOutputType(
            address="2N4Q5FhU2497BryFfUgbqkAJE87aKHUhXMp",
            amount=5000000,
            script_type=proto.OutputScriptType.PAYTOADDRESS,
        )
        out2 = proto.TxOutputType(
            address="tb1q694ccp5qcc0udmfwgp692u2s2hjpq5h407urtu",
            script_type=proto.OutputScriptType.PAYTOADDRESS,
            amount=12300000 - 11000 - 5000000,
        )
        with self.client:
            self.client.set_expected_responses([
                proto.TxRequest(
                    request_type=proto.RequestType.TXINPUT,
                    details=proto.TxRequestDetailsType(request_index=0),
                ),
                proto.TxRequest(
                    request_type=proto.RequestType.TXOUTPUT,
                    details=proto.TxRequestDetailsType(request_index=0),
                ),
                proto.ButtonRequest(
                    code=proto.ButtonRequestType.ConfirmOutput),
                proto.TxRequest(
                    request_type=proto.RequestType.TXOUTPUT,
                    details=proto.TxRequestDetailsType(request_index=1),
                ),
                proto.ButtonRequest(
                    code=proto.ButtonRequestType.ConfirmOutput),
                proto.ButtonRequest(code=proto.ButtonRequestType.SignTx),
                proto.TxRequest(
                    request_type=proto.RequestType.TXINPUT,
                    details=proto.TxRequestDetailsType(request_index=0),
                ),
                proto.TxRequest(
                    request_type=proto.RequestType.TXOUTPUT,
                    details=proto.TxRequestDetailsType(request_index=0),
                ),
                proto.TxRequest(
                    request_type=proto.RequestType.TXOUTPUT,
                    details=proto.TxRequestDetailsType(request_index=1),
                ),
                proto.TxRequest(
                    request_type=proto.RequestType.TXINPUT,
                    details=proto.TxRequestDetailsType(request_index=0),
                ),
                proto.TxRequest(request_type=proto.RequestType.TXFINISHED),
            ])
            _, serialized_tx = btc.sign_tx(self.client,
                                           "Testnet", [inp1], [out1, out2],
                                           prev_txes=TX_API)

        assert (
            serialized_tx.hex() ==
            "010000000001018a44999c07bba32df1cacdc50987944e68e3205b4429438fdde35c76024614090000000000ffffffff02404b4c000000000017a9147a55d61848e77ca266e79a39bfc85c580a6426c987a8386f0000000000160014d16b8c0680c61fc6ed2e407455715055e41052f502473044022073ce72dcf2f6e42eeb44adbe7d5038cf3763f168d1c04bd8b873a19b53331f51022016b051725731e7f53a567021bcd9c370727f551c81e857ebae7c128472119652012103adc58245cf28406af0ef5cc24b8afba7f1be6c72f279b642d85c48798685f86200000000"
        )
Example #18
0
def test_attack_steal_change(client):
    # Attempt to steal amount equivalent to the change in the original transaction by
    # hiding the fact that an output in the original transaction is a change-output.

    # Original input.
    inp1 = messages.TxInputType(
        address_n=parse_path("84h/1h/0h/0/0"),
        amount=100000,
        script_type=messages.InputScriptType.SPENDWITNESS,
        prev_hash=TXHASH_e4b5b2,
        prev_index=0,
        orig_hash=TXHASH_65b768,
        orig_index=0,
        sequence=1516634,
    )

    # New input for the attacker to steal from.
    inp2 = messages.TxInputType(
        address_n=parse_path("84h/1h/0h/1/1"),
        amount=19899859,
        script_type=messages.InputScriptType.SPENDWITNESS,
        prev_hash=TXHASH_70f987,
        prev_index=1,
    )

    # Original output.
    out1 = messages.TxOutputType(
        address="tb1qldlynaqp0hy4zc2aag3pkenzvxy65saesxw3wd",
        amount=10000,
        script_type=messages.OutputScriptType.PAYTOWITNESS,
        orig_hash=TXHASH_65b768,
        orig_index=0,
    )

    # Original change was 89859. We bump the fee from 141 to 200 and
    # attacker gives back what he can't steal.
    out2 = messages.TxOutputType(
        address_n=parse_path("84h/1h/0h/1/2"),
        amount=100000 - 10000 - 200 + (19899859 - 89859),
        script_type=messages.OutputScriptType.PAYTOWITNESS,
        orig_hash=TXHASH_65b768,
        orig_index=1,
    )

    # Attacker's new output.
    out3 = messages.TxOutputType(
        address="tb1q694ccp5qcc0udmfwgp692u2s2hjpq5h407urtu",
        amount=89859,
    )

    # Attacker hides the fact that second output of 65b768 is a change-output.
    prev_tx_attack = TX_CACHE_TESTNET[TXHASH_65b768]
    prev_tx_attack.outputs[1].address_n = None
    prev_tx_attack.outputs[1].address = "tb1qr5p6f5sk09sms57ket074vywfymuthlgud7xyx"
    prev_tx_attack.outputs[1].script_type = messages.OutputScriptType.PAYTOADDRESS
    prev_txes = {TXHASH_65b768: prev_tx_attack}

    with pytest.raises(
        TrezorFailure, match="Original output is missing change-output parameters"
    ):
        btc.sign_tx(
            client,
            "Testnet",
            [inp1, inp2],
            [out1, out2, out3],
            lock_time=1516634,
            prev_txes=prev_txes,
        )
    def test_send_both(self):
        self.setup_mnemonic_allallall()
        inp1 = proto.TxInputType(
            address_n=parse_path("49'/1'/0'/1/0"),
            # 2N1LGaGg836mqSQqiuUBLfcyGBhyZbremDX
            amount=111145789,
            prev_hash=bytes.fromhex(
                "09144602765ce3dd8f4329445b20e3684e948709c5cdcaf12da3bb079c99448a"
            ),
            prev_index=1,
            script_type=proto.InputScriptType.SPENDP2SHWITNESS,
        )
        inp2 = proto.TxInputType(
            address_n=parse_path("84'/1'/0'/1/0"),
            amount=7289000,
            prev_hash=bytes.fromhex(
                "65b811d3eca0fe6915d9f2d77c86c5a7f19bf66b1b1253c2c51cb4ae5f0c017b"
            ),
            prev_index=1,
            script_type=proto.InputScriptType.SPENDWITNESS,
        )
        out1 = proto.TxOutputType(
            address="tb1q54un3q39sf7e7tlfq99d6ezys7qgc62a6rxllc",
            amount=12300000,
            script_type=proto.OutputScriptType.PAYTOADDRESS,
        )
        out2 = proto.TxOutputType(
            # address_n=parse_path("44'/1'/0'/0/0"),
            # script_type=proto.OutputScriptType.PAYTOP2SHWITNESS,
            address="2N6UeBoqYEEnybg4cReFYDammpsyDw8R2Mc",
            script_type=proto.OutputScriptType.PAYTOADDRESS,
            amount=45600000,
        )
        out3 = proto.TxOutputType(
            address="mvbu1Gdy8SUjTenqerxUaZyYjmveZvt33q",
            amount=111145789 + 7289000 - 11000 - 12300000 - 45600000,
            script_type=proto.OutputScriptType.PAYTOADDRESS,
        )

        with self.client:
            self.client.set_expected_responses([
                proto.TxRequest(
                    request_type=proto.RequestType.TXINPUT,
                    details=proto.TxRequestDetailsType(request_index=0),
                ),
                proto.TxRequest(
                    request_type=proto.RequestType.TXINPUT,
                    details=proto.TxRequestDetailsType(request_index=1),
                ),
                proto.TxRequest(
                    request_type=proto.RequestType.TXOUTPUT,
                    details=proto.TxRequestDetailsType(request_index=0),
                ),
                proto.ButtonRequest(
                    code=proto.ButtonRequestType.ConfirmOutput),
                proto.TxRequest(
                    request_type=proto.RequestType.TXOUTPUT,
                    details=proto.TxRequestDetailsType(request_index=1),
                ),
                proto.ButtonRequest(
                    code=proto.ButtonRequestType.ConfirmOutput),
                proto.TxRequest(
                    request_type=proto.RequestType.TXOUTPUT,
                    details=proto.TxRequestDetailsType(request_index=2),
                ),
                proto.ButtonRequest(
                    code=proto.ButtonRequestType.ConfirmOutput),
                proto.ButtonRequest(code=proto.ButtonRequestType.SignTx),
                proto.TxRequest(
                    request_type=proto.RequestType.TXINPUT,
                    details=proto.TxRequestDetailsType(request_index=0),
                ),
                proto.TxRequest(
                    request_type=proto.RequestType.TXINPUT,
                    details=proto.TxRequestDetailsType(request_index=1),
                ),
                proto.TxRequest(
                    request_type=proto.RequestType.TXOUTPUT,
                    details=proto.TxRequestDetailsType(request_index=0),
                ),
                proto.TxRequest(
                    request_type=proto.RequestType.TXOUTPUT,
                    details=proto.TxRequestDetailsType(request_index=1),
                ),
                proto.TxRequest(
                    request_type=proto.RequestType.TXOUTPUT,
                    details=proto.TxRequestDetailsType(request_index=2),
                ),
                proto.TxRequest(
                    request_type=proto.RequestType.TXINPUT,
                    details=proto.TxRequestDetailsType(request_index=0),
                ),
                proto.TxRequest(
                    request_type=proto.RequestType.TXINPUT,
                    details=proto.TxRequestDetailsType(request_index=1),
                ),
                proto.TxRequest(request_type=proto.RequestType.TXFINISHED),
            ])
            _, serialized_tx = btc.sign_tx(
                self.client,
                "Testnet",
                [inp1, inp2],
                [out1, out2, out3],
                prev_txes=TX_API,
            )

        assert (
            serialized_tx.hex() ==
            "010000000001028a44999c07bba32df1cacdc50987944e68e3205b4429438fdde35c76024614090100000017160014d16b8c0680c61fc6ed2e407455715055e41052f5ffffffff7b010c5faeb41cc5c253121b6bf69bf1a7c5867cd7f2d91569fea0ecd311b8650100000000ffffffff03e0aebb0000000000160014a579388225827d9f2fe9014add644487808c695d00cdb7020000000017a91491233e24a9bf8dbb19c1187ad876a9380c12e787870d859b03000000001976a914a579388225827d9f2fe9014add644487808c695d88ac02483045022100ead79ee134f25bb585b48aee6284a4bb14e07f03cc130253e83450d095515e5202201e161e9402c8b26b666f2b67e5b668a404ef7e57858ae9a6a68c3837e65fdc69012103e7bfe10708f715e8538c92d46ca50db6f657bbc455b7494e6a0303ccdb868b7902463043021f585c54a84dc7326fa60e22729accd41153c7dd4725bd4c8f751aa3a8cd8d6a0220631bfd83fc312cc6d5d129572a25178696d81eaf50c8c3f16c6121be4f4c029d012103505647c017ff2156eb6da20fae72173d3b681a1d0a629f95f49e884db300689f00000000"
        )
Example #20
0
def test_p2pkh_fee_bump(client):
    inp1 = messages.TxInputType(
        address_n=parse_path("44h/0h/0h/0/4"),
        amount=174998,
        prev_hash=TXHASH_beafc7,
        prev_index=0,
        orig_hash=TXHASH_50f6f1,
        orig_index=0,
    )

    out1 = messages.TxOutputType(
        address_n=parse_path("44h/0h/0h/1/2"),
        amount=174998 - 50000 - 15000,  # Originally fee was 11300, now 15000.
        script_type=messages.OutputScriptType.PAYTOADDRESS,
        orig_hash=TXHASH_50f6f1,
        orig_index=0,
    )

    out2 = messages.TxOutputType(
        address="1GA9u9TfCG7SWmKCveBumdA1TZpfom6ZdJ",
        amount=50000,
        script_type=messages.OutputScriptType.PAYTOADDRESS,
        orig_hash=TXHASH_50f6f1,
        orig_index=1,
    )

    tt = client.features.model == "T"

    with client:
        client.set_expected_responses(
            [
                request_input(0),
                request_meta(TXHASH_50f6f1),
                request_orig_input(0, TXHASH_50f6f1),
                messages.ButtonRequest(code=B.SignTx),
                request_output(0),
                request_orig_output(0, TXHASH_50f6f1),
                request_output(1),
                request_orig_output(1, TXHASH_50f6f1),
                messages.ButtonRequest(code=B.SignTx),
                request_input(0),
                request_meta(TXHASH_beafc7),
                request_input(0, TXHASH_beafc7),
                request_output(0, TXHASH_beafc7),
                (tt, request_orig_input(0, TXHASH_50f6f1)),
                (tt, request_orig_output(0, TXHASH_50f6f1)),
                (tt, request_orig_output(1, TXHASH_50f6f1)),
                request_input(0),
                request_output(0),
                request_output(1),
                request_output(0),
                request_output(1),
                request_finished(),
            ]
        )
        _, serialized_tx = btc.sign_tx(
            client,
            "Bitcoin",
            [inp1],
            [out1, out2],
            prev_txes=TX_CACHE_MAINNET,
        )

    assert (
        serialized_tx.hex()
        == "01000000017a1ebb08f129fb1cc814b59d63284286d58a7602708ae8be6dd073d8cbc7afbe000000006b483045022100a8c1c118d61259f8df463deb538a10d9e9f42bbdfff28bb1337ee5426e5098f8022060e7464f7a63a83fd93dbd268f319133cb03452764afd601db063ff3eede9207012103f54094da6a0b2e0799286268bb59ca7c83538e81c78e64f6333f40f9e0e222c0ffffffff02aead0100000000001976a914902c642ba3a22f5c6cfa30a1790c133ddf15cc8888ac50c30000000000001976a914a6450f1945831a81912616691e721b787383f4ed88ac00000000"
    )
    def test_send_multisig_2(self):
        self.setup_mnemonic_allallall()
        nodes = [
            btc.get_public_node(self.client, parse_path("84'/1'/%d'" % index))
            for index in range(1, 4)
        ]
        multisig = proto.MultisigRedeemScriptType(
            nodes=[deserialize(n.xpub) for n in nodes],
            address_n=[0, 1],
            signatures=[b"", b"", b""],
            m=2,
        )

        inp1 = proto.TxInputType(
            address_n=parse_path("84'/1'/2'/0/1"),
            prev_hash=bytes.fromhex(
                "f41cbedd8becee05a830f418d13aa665125464547db5c7a6cd28f21639fe1228"
            ),
            prev_index=0,
            script_type=proto.InputScriptType.SPENDWITNESS,
            multisig=multisig,
            amount=1605000,
        )

        out1 = proto.TxOutputType(
            address=
            "tb1qr6xa5v60zyt3ry9nmfew2fk5g9y3gerkjeu6xxdz7qga5kknz2ssld9z2z",
            amount=1604000,
            script_type=proto.OutputScriptType.PAYTOADDRESS,
        )

        with self.client:
            self.client.set_expected_responses([
                proto.TxRequest(
                    request_type=proto.RequestType.TXINPUT,
                    details=proto.TxRequestDetailsType(request_index=0),
                ),
                proto.TxRequest(
                    request_type=proto.RequestType.TXOUTPUT,
                    details=proto.TxRequestDetailsType(request_index=0),
                ),
                proto.ButtonRequest(
                    code=proto.ButtonRequestType.ConfirmOutput),
                proto.ButtonRequest(code=proto.ButtonRequestType.SignTx),
                proto.TxRequest(
                    request_type=proto.RequestType.TXINPUT,
                    details=proto.TxRequestDetailsType(request_index=0),
                ),
                proto.TxRequest(
                    request_type=proto.RequestType.TXOUTPUT,
                    details=proto.TxRequestDetailsType(request_index=0),
                ),
                proto.TxRequest(
                    request_type=proto.RequestType.TXINPUT,
                    details=proto.TxRequestDetailsType(request_index=0),
                ),
                proto.TxRequest(request_type=proto.RequestType.TXFINISHED),
            ])
            signatures, _ = btc.sign_tx(self.client,
                                        "Testnet", [inp1], [out1],
                                        prev_txes=TX_API)
            # store signature
            inp1.multisig.signatures[1] = signatures[0]
            # sign with first key
            inp1.address_n[2] = H_(1)
            self.client.set_expected_responses([
                proto.TxRequest(
                    request_type=proto.RequestType.TXINPUT,
                    details=proto.TxRequestDetailsType(request_index=0),
                ),
                proto.TxRequest(
                    request_type=proto.RequestType.TXOUTPUT,
                    details=proto.TxRequestDetailsType(request_index=0),
                ),
                proto.ButtonRequest(
                    code=proto.ButtonRequestType.ConfirmOutput),
                proto.ButtonRequest(code=proto.ButtonRequestType.SignTx),
                proto.TxRequest(
                    request_type=proto.RequestType.TXINPUT,
                    details=proto.TxRequestDetailsType(request_index=0),
                ),
                proto.TxRequest(
                    request_type=proto.RequestType.TXOUTPUT,
                    details=proto.TxRequestDetailsType(request_index=0),
                ),
                proto.TxRequest(
                    request_type=proto.RequestType.TXINPUT,
                    details=proto.TxRequestDetailsType(request_index=0),
                ),
                proto.TxRequest(request_type=proto.RequestType.TXFINISHED),
            ])
            _, serialized_tx = btc.sign_tx(self.client,
                                           "Testnet", [inp1], [out1],
                                           prev_txes=TX_API)

        assert (
            serialized_tx.hex() ==
            "010000000001012812fe3916f228cda6c7b57d5464541265a63ad118f430a805eeec8bddbe1cf40000000000ffffffff01a0791800000000002200201e8dda334f11171190b3da72e526d441491464769679a319a2f011da5ad312a10400473044022001b7f4f21a8ddcd5e0faaaee3b95515bf8b84f2a7cbfdf66996c64123617a5cf02202fc6a776a7225420dbca759ad4ac83a61d15bf8d2883b6bf1aa31de7437f9b6e0147304402206c4125c1189a3b3e93a77cdf54c60c0538b80e5a03ec74e6ac776dfa77706ee4022035be14de76259b9d8a24863131a06a65b95df02f7d3ace90d52b37e8d94b167f0169522103bab8ecdd9ae2c51a0dc858f4c751b27533143bf6013ba1725ba8a4ecebe7de8c21027d5e55696c875308b03f2ca3d8637f51d3e35da9456a5187aa14b3de8a89534f2103b78eabaea8b3a4868be4f4bb96d6f66973f7081faa7f1cafba321444611c241e53ae00000000"
        )
Example #22
0
def test_attack_fake_ext_input_amount(client):
    # Give a fake input amount for an original external input while giving the correct
    # amount for the replacement input. If an attacker could decrease the amount of an
    # external input in the original transaction, then they could steal the fee from
    # the transaction without the user noticing.

    inp1 = messages.TxInputType(
        address_n=parse_path("49h/1h/0h/0/8"),
        amount=4973340,
        script_type=messages.InputScriptType.SPENDP2SHWITNESS,
        prev_hash=TXHASH_6673b7,
        prev_index=0,
        orig_hash=TXHASH_ed89ac,
        orig_index=0,
    )

    inp2 = messages.TxInputType(
        # Actually 49h/1h/0h/0/9, but we will make it look like it's external,
        # so that we can try out this scenario, i.e. not a part of the attack.
        amount=839318869,
        script_type=messages.InputScriptType.EXTERNAL,
        prev_hash=TXHASH_927784,
        prev_index=0,
        orig_hash=TXHASH_ed89ac,
        orig_index=1,
        script_sig=bytes.fromhex("160014681ea49259abb892460bf3373e8a0b43d877fa18"),
        witness=bytes.fromhex(
            "02483045022100d9c2d4364e104bf0d27886b4d7cd05f9a256bda8acbe84b7b2753f5c054b1a8602206a512575a89da5b5123e2769a5f73675b27b9f43d1a7b54bddeae039f6b83efa0121028cbc37e1816a23086fa738c8415def477e813e20f484dbbd6f5a33a37c322251"
        ),
    )

    # Attacker adds 30000, but it could even go to a new output.
    out1 = messages.TxOutputType(
        address="moE1dVYvebvtaMuNdXQKvu4UxUftLmS1Gt",
        amount=100000000 + 30000,
        orig_hash=TXHASH_ed89ac,
        orig_index=1,
    )

    # Change-output. Original fee was 90720, attacker steals 30000.
    out2 = messages.TxOutputType(
        address_n=parse_path("49h/1h/0h/1/6"),
        amount=4973340 + 839318869 - (100000000 + 30000) - 60720,
        script_type=messages.OutputScriptType.PAYTOP2SHWITNESS,
    )

    # Decrease the original amount of inp2 by 30000.
    # Also make the original inp2 look external (not a part of the attack).
    prev_tx_attack = TX_CACHE_TESTNET[TXHASH_ed89ac]
    prev_tx_attack.inputs[1].amount -= 30000
    prev_tx_attack.inputs[1].address_n = None
    prev_tx_attack.inputs[1].script_type = messages.InputScriptType.EXTERNAL
    prev_txes = {
        TXHASH_ed89ac: prev_tx_attack,
        TXHASH_6673b7: TX_CACHE_TESTNET[TXHASH_6673b7],
        TXHASH_927784: TX_CACHE_TESTNET[TXHASH_927784],
    }

    with pytest.raises(
        TrezorFailure, match="Original input does not match current input"
    ):
        btc.sign_tx(
            client,
            "Testnet",
            [inp1, inp2],
            [out1, out2],
            prev_txes=prev_txes,
        )
    def test_send_multisig_4_change(self):
        self.setup_mnemonic_allallall()
        nodes = [
            btc.get_public_node(self.client, parse_path("49'/1'/%d'" % index))
            for index in range(1, 4)
        ]
        multisig = proto.MultisigRedeemScriptType(
            nodes=[deserialize(n.xpub) for n in nodes],
            address_n=[1, 1],
            signatures=[b"", b"", b""],
            m=2,
        )
        multisig2 = proto.MultisigRedeemScriptType(
            nodes=[deserialize(n.xpub) for n in nodes],
            address_n=[1, 2],
            signatures=[b"", b"", b""],
            m=2,
        )

        inp1 = proto.TxInputType(
            address_n=parse_path("49'/1'/1'/1/1"),
            prev_hash=bytes.fromhex(
                "31bc1c88ce6ae337a6b3057a16d5bad0b561ad1dfc047d0a7fbb8814668f91e5"
            ),
            prev_index=0,
            script_type=proto.InputScriptType.SPENDP2SHWITNESS,
            multisig=multisig,
            amount=1603000,
        )

        out1 = proto.TxOutputType(
            address_n=parse_path("49'/1'/1'/1/2"),
            amount=1602000,
            multisig=multisig2,
            script_type=proto.OutputScriptType.PAYTOWITNESS,
        )

        with self.client:
            self.client.set_expected_responses([
                proto.TxRequest(
                    request_type=proto.RequestType.TXINPUT,
                    details=proto.TxRequestDetailsType(request_index=0),
                ),
                proto.TxRequest(
                    request_type=proto.RequestType.TXOUTPUT,
                    details=proto.TxRequestDetailsType(request_index=0),
                ),
                proto.ButtonRequest(code=proto.ButtonRequestType.SignTx),
                proto.TxRequest(
                    request_type=proto.RequestType.TXINPUT,
                    details=proto.TxRequestDetailsType(request_index=0),
                ),
                proto.TxRequest(
                    request_type=proto.RequestType.TXOUTPUT,
                    details=proto.TxRequestDetailsType(request_index=0),
                ),
                proto.TxRequest(
                    request_type=proto.RequestType.TXINPUT,
                    details=proto.TxRequestDetailsType(request_index=0),
                ),
                proto.TxRequest(request_type=proto.RequestType.TXFINISHED),
            ])
            signatures, _ = btc.sign_tx(self.client,
                                        "Testnet", [inp1], [out1],
                                        prev_txes=TX_API)
            # store signature
            inp1.multisig.signatures[0] = signatures[0]
            # sign with third key
            inp1.address_n[2] = H_(3)
            out1.address_n[2] = H_(3)
            self.client.set_expected_responses([
                proto.TxRequest(
                    request_type=proto.RequestType.TXINPUT,
                    details=proto.TxRequestDetailsType(request_index=0),
                ),
                proto.TxRequest(
                    request_type=proto.RequestType.TXOUTPUT,
                    details=proto.TxRequestDetailsType(request_index=0),
                ),
                proto.ButtonRequest(code=proto.ButtonRequestType.SignTx),
                proto.TxRequest(
                    request_type=proto.RequestType.TXINPUT,
                    details=proto.TxRequestDetailsType(request_index=0),
                ),
                proto.TxRequest(
                    request_type=proto.RequestType.TXOUTPUT,
                    details=proto.TxRequestDetailsType(request_index=0),
                ),
                proto.TxRequest(
                    request_type=proto.RequestType.TXINPUT,
                    details=proto.TxRequestDetailsType(request_index=0),
                ),
                proto.TxRequest(request_type=proto.RequestType.TXFINISHED),
            ])
            _, serialized_tx = btc.sign_tx(self.client,
                                           "Testnet", [inp1], [out1],
                                           prev_txes=TX_API)

        assert (
            serialized_tx.hex() ==
            "01000000000101e5918f661488bb7f0a7d04fc1dad61b5d0bad5167a05b3a637e36ace881cbc310000000023220020fa6c73de618ec134eeec0c16f6dd04d46d4347e9a4fd0a95fd7938403a4949f9ffffffff01d071180000000000220020bcea2324dacbcde5a9db90cc26b8df9cbc72010e05cb68cf034df6f0e05239a2040047304402206bbddb45f12e31e77610fd85b50a83bad4426433b1c4860b1c5ddc0a69f803720220087b0607daab14830f4b4941f16b953b38e606ad70029bac24af7267f93c4242014730440220551a0cb6b0d5b3fa0cfd0b07bb5d751494b827b1c6a08702186696cfbc18278302204f37c382876c4117cca656654599b508f2d55fc3b083dc938e3cd8491b29719601695221036a5ec3abd10501409092246fe59c6d7a15fff1a933479483c3ba98b866c5b9742103559be875179d44e438db2c74de26e0bc9842cbdefd16018eae8a2ed989e474722103067b56aad037cd8b5f569b21f9025b76470a72dc69457813d2b76e98dc0cd01a53ae00000000"
        )
Example #24
0
signtx = proto.SignTx(
    version = tx_version,
    lock_time = tx_locktime
)

ins = [proto.TxInputType(
    address_n=tools.parse_path(in1_addr_path),
    prev_hash=in1_prev_hash_b,
    prev_index=in1_prev_index,
    amount=in1_amount,
    script_type=proto.InputScriptType.SPENDADDRESS,
    sequence=sequence
)]
outs = [proto.TxOutputType(
    address=out1_address,
    amount=out1_amount,
    script_type=proto.OutputScriptType.PAYTOADDRESS
)]

txes = None
for i in ins:
    if i.script_type == proto.InputScriptType.SPENDADDRESS:
        tx = from_json(in1_prev_txn_j)
        txes = {in1_prev_hash_b: tx}
        break

_, serialized_tx = btc.sign_tx(client, coin, ins, outs, 
                               details=signtx, prev_txes=txes)
client.close()
print(f'{{"hex": "{serialized_tx.hex()}"}}')
    def test_send_decred_change(self):
        self.setup_mnemonic_allallall()
        self.client.set_tx_api(TxApiDecredTestnet)

        inp1 = proto.TxInputType(
            # TscqTv1he8MZrV321SfRghw7LFBCJDKB3oz
            address_n=parse_path("m/44'/1'/0'/0/0"),
            prev_hash=TXHASH_5e6e35,
            prev_index=0,
            script_type=proto.InputScriptType.SPENDADDRESS,
            decred_tree=0,
        )

        inp2 = proto.TxInputType(
            # TscqTv1he8MZrV321SfRghw7LFBCJDKB3oz
            address_n=parse_path("m/44'/1'/0'/0/0"),
            prev_hash=TXHASH_ccf95b,
            prev_index=1,
            script_type=proto.InputScriptType.SPENDADDRESS,
            decred_tree=0,
        )

        inp3 = proto.TxInputType(
            # Tskt39YEvzoJ5KBDH4f1auNzG3jViVjZ2RV
            address_n=parse_path("m/44'/1'/0'/0/1"),
            prev_hash=TXHASH_f395ef,
            prev_index=0,
            script_type=proto.InputScriptType.SPENDADDRESS,
            decred_tree=0,
        )

        out1 = proto.TxOutputType(
            address="TsWjioPrP8E1TuTMmTrVMM2BA4iPrjQXBpR",
            amount=489975000,
            script_type=proto.OutputScriptType.PAYTOADDRESS,
            decred_script_version=0,
        )

        out2 = proto.TxOutputType(
            # TsaSFRwfN9muW5F6ZX36iSksc9hruiC5F97
            address_n=parse_path("m/44'/1'/0'/1/0"),
            amount=100000000,
            script_type=proto.OutputScriptType.PAYTOADDRESS,
            decred_script_version=0,
        )

        with self.client:
            self.client.set_expected_responses(
                [
                    proto.TxRequest(
                        request_type=proto.RequestType.TXINPUT,
                        details=proto.TxRequestDetailsType(request_index=0),
                    ),
                    proto.TxRequest(
                        request_type=proto.RequestType.TXMETA,
                        details=proto.TxRequestDetailsType(tx_hash=TXHASH_5e6e35),
                    ),
                    proto.TxRequest(
                        request_type=proto.RequestType.TXINPUT,
                        details=proto.TxRequestDetailsType(
                            tx_hash=TXHASH_5e6e35, request_index=0
                        ),
                    ),
                    proto.TxRequest(
                        request_type=proto.RequestType.TXOUTPUT,
                        details=proto.TxRequestDetailsType(
                            tx_hash=TXHASH_5e6e35, request_index=0
                        ),
                    ),
                    proto.TxRequest(
                        request_type=proto.RequestType.TXINPUT,
                        details=proto.TxRequestDetailsType(request_index=1),
                    ),
                    proto.TxRequest(
                        request_type=proto.RequestType.TXMETA,
                        details=proto.TxRequestDetailsType(tx_hash=TXHASH_ccf95b),
                    ),
                    proto.TxRequest(
                        request_type=proto.RequestType.TXINPUT,
                        details=proto.TxRequestDetailsType(
                            tx_hash=TXHASH_ccf95b, request_index=0
                        ),
                    ),
                    proto.TxRequest(
                        request_type=proto.RequestType.TXOUTPUT,
                        details=proto.TxRequestDetailsType(
                            tx_hash=TXHASH_ccf95b, request_index=0
                        ),
                    ),
                    proto.TxRequest(
                        request_type=proto.RequestType.TXOUTPUT,
                        details=proto.TxRequestDetailsType(
                            tx_hash=TXHASH_ccf95b, request_index=1
                        ),
                    ),
                    proto.TxRequest(
                        request_type=proto.RequestType.TXINPUT,
                        details=proto.TxRequestDetailsType(request_index=2),
                    ),
                    proto.TxRequest(
                        request_type=proto.RequestType.TXMETA,
                        details=proto.TxRequestDetailsType(tx_hash=TXHASH_f395ef),
                    ),
                    proto.TxRequest(
                        request_type=proto.RequestType.TXINPUT,
                        details=proto.TxRequestDetailsType(
                            tx_hash=TXHASH_f395ef, request_index=0
                        ),
                    ),
                    proto.TxRequest(
                        request_type=proto.RequestType.TXOUTPUT,
                        details=proto.TxRequestDetailsType(
                            tx_hash=TXHASH_f395ef, request_index=0
                        ),
                    ),
                    proto.TxRequest(
                        request_type=proto.RequestType.TXOUTPUT,
                        details=proto.TxRequestDetailsType(
                            tx_hash=TXHASH_f395ef, request_index=1
                        ),
                    ),
                    proto.TxRequest(
                        request_type=proto.RequestType.TXOUTPUT,
                        details=proto.TxRequestDetailsType(request_index=0),
                    ),
                    proto.ButtonRequest(code=proto.ButtonRequestType.ConfirmOutput),
                    proto.TxRequest(
                        request_type=proto.RequestType.TXOUTPUT,
                        details=proto.TxRequestDetailsType(request_index=1),
                    ),
                    proto.ButtonRequest(code=proto.ButtonRequestType.SignTx),
                    proto.TxRequest(
                        request_type=proto.RequestType.TXINPUT,
                        details=proto.TxRequestDetailsType(request_index=0),
                    ),
                    proto.TxRequest(
                        request_type=proto.RequestType.TXINPUT,
                        details=proto.TxRequestDetailsType(request_index=1),
                    ),
                    proto.TxRequest(
                        request_type=proto.RequestType.TXINPUT,
                        details=proto.TxRequestDetailsType(request_index=2),
                    ),
                    proto.TxRequest(request_type=proto.RequestType.TXFINISHED),
                ]
            )
            (signatures, serialized_tx) = btc.sign_tx(
                self.client, "Decred Testnet", [inp1, inp2, inp3], [out1, out2]
            )

        assert (
            serialized_tx.hex()
            == "010000000370b95980a47b9bcb4ec2c2b450888a53179b1a5fdb23f5023cc533a300356e5e0000000000ffffffff74bc93bcfce18aff2e522d6822817522e2815a00175b2eae59ef20d20f5bf9cc0100000000ffffffff13317ab453832deabd684d2302eed42580c28ba3e715db66a731a8723eef95f30000000000ffffffff02d86c341d0000000000001976a9143eb656115197956125365348c542e37b6d3d259988ac00e1f5050000000000001976a9143ee6f9d662e7be18373d80e5eb44627014c2bf6688ac000000000000000003000000000000000000000000ffffffff6a47304402200e50a6d43c462045917792e7d03b4354900c3baccb7abef66f556a32b12f2ca6022031ae94fdf2a41dd6ed2e081faf0f8f1c64411a1b46eb26f7f35d94402b2bde110121030e669acac1f280d1ddf441cd2ba5e97417bf2689e4bbec86df4f831bf9f7ffd0000000000000000000000000ffffffff6a47304402204894c2f8e76c4645d2df600cdd01443aeb48807b72150c4bc10eebd126529532022054cd37462a3f0ddb85c75b4e874ab0c2aad7eebcff3e6c1ac20e1c16babe36720121030e669acac1f280d1ddf441cd2ba5e97417bf2689e4bbec86df4f831bf9f7ffd0000000000000000000000000ffffffff6b4830450221009f1ba584023da8aafd57374e83be68f1a097b906967ec9e50736f31bfc7989f102204a190fc2885e394572b5c2ced046657b1dd07abdb19144e21e78987968c7f17601210294e3e5e77e22eea0e4c0d30d89beb4db7f69b4bf1ae709e411d6a06618b8f852"
        )
Example #26
0
    def prepare_transfer_tx_bulk(self,
                                 caller,
                                 rewardsArray,
                                 dest_address,
                                 tx_fee,
                                 useSwiftX=False,
                                 isTestnet=False):
        inputs = []
        outputs = []
        c_name = "PIVX"
        if isTestnet:
            c_name += " Testnet"
        coin = coins.by_name[c_name]
        with self.lock:
            self.amount = 0

            for mnode in rewardsArray:
                # Add proper HW path (for current device) on each utxo
                if isTestnet:
                    mnode['path'] = MPATH_TESTNET + mnode['path']
                else:
                    mnode['path'] = MPATH + mnode['path']

                # Create a TX input with each utxo
                for utxo in mnode['utxos']:
                    self.append_inputs_to_TX(utxo, mnode['path'], inputs)

            self.amount = int(self.amount)
            self.amount -= int(tx_fee)
            if self.amount < 0:
                raise Exception('Invalid TX: inputs + fee != outputs')

            outputs.append(
                trezor_proto.TxOutputType(
                    address=dest_address,
                    address_n=None,
                    amount=self.amount,
                    script_type=trezor_proto.OutputScriptType.PAYTOSCRIPTHASH))

            txes = self.load_prev_txes(rewardsArray)

            self.mBox2 = QMessageBox(caller)
            self.messageText = "<p>Signing transaction...</p>"
            # messageText += "From bip32_path: <b>%s</b><br><br>" % str(bip32_path)
            self.messageText += "<p>Payment to:<br><b>%s</b></p>" % dest_address
            self.messageText += "<p>Net amount:<br><b>%s</b> PIV</p>" % str(
                round(self.amount / 1e8, 8))
            if useSwiftX:
                self.messageText += "<p>Fees (SwiftX flat rate):<br><b>%s</b> PIV<p>" % str(
                    round(int(tx_fee) / 1e8, 8))
            else:
                self.messageText += "<p>Fees:<br><b>%s</b> PIV<p>" % str(
                    round(int(tx_fee) / 1e8, 8))
            messageText = self.messageText + "Signature Progress: 0 %"
            self.mBox2.setText(messageText)
            self.setBoxIcon(self.mBox2, caller)
            self.mBox2.setWindowTitle("CHECK YOUR TREZOR")
            self.mBox2.setStandardButtons(QMessageBox.NoButton)
            self.mBox2.setMaximumWidth(500)
            self.mBox2.show()

        ThreadFuns.runInThread(self.signTxSign,
                               (inputs, outputs, txes, isTestnet),
                               self.signTxFinish)
    def test_send_decred(self):
        self.setup_mnemonic_allallall()
        self.client.set_tx_api(TxApiDecredTestnet)

        inp1 = proto.TxInputType(
            # TscqTv1he8MZrV321SfRghw7LFBCJDKB3oz
            address_n=parse_path("m/44'/1'/0'/0/0"),
            prev_hash=TXHASH_e16248,
            prev_index=1,
            script_type=proto.InputScriptType.SPENDADDRESS,
            decred_tree=0,
        )

        out1 = proto.TxOutputType(
            address="TscqTv1he8MZrV321SfRghw7LFBCJDKB3oz",
            amount=190000000,
            script_type=proto.OutputScriptType.PAYTOADDRESS,
            decred_script_version=0,
        )

        with self.client:
            self.client.set_expected_responses(
                [
                    proto.TxRequest(
                        request_type=proto.RequestType.TXINPUT,
                        details=proto.TxRequestDetailsType(request_index=0),
                    ),
                    proto.TxRequest(
                        request_type=proto.RequestType.TXMETA,
                        details=proto.TxRequestDetailsType(tx_hash=TXHASH_e16248),
                    ),
                    proto.TxRequest(
                        request_type=proto.RequestType.TXINPUT,
                        details=proto.TxRequestDetailsType(
                            tx_hash=TXHASH_e16248, request_index=0
                        ),
                    ),
                    proto.TxRequest(
                        request_type=proto.RequestType.TXOUTPUT,
                        details=proto.TxRequestDetailsType(
                            tx_hash=TXHASH_e16248, request_index=0
                        ),
                    ),
                    proto.TxRequest(
                        request_type=proto.RequestType.TXOUTPUT,
                        details=proto.TxRequestDetailsType(
                            tx_hash=TXHASH_e16248, request_index=1
                        ),
                    ),
                    proto.TxRequest(
                        request_type=proto.RequestType.TXOUTPUT,
                        details=proto.TxRequestDetailsType(request_index=0),
                    ),
                    proto.ButtonRequest(code=proto.ButtonRequestType.ConfirmOutput),
                    proto.ButtonRequest(code=proto.ButtonRequestType.FeeOverThreshold),
                    proto.ButtonRequest(code=proto.ButtonRequestType.SignTx),
                    proto.TxRequest(
                        request_type=proto.RequestType.TXINPUT,
                        details=proto.TxRequestDetailsType(request_index=0),
                    ),
                    proto.TxRequest(request_type=proto.RequestType.TXFINISHED),
                ]
            )
            (signatures, serialized_tx) = btc.sign_tx(
                self.client, "Decred Testnet", [inp1], [out1]
            )

        assert (
            serialized_tx.hex()
            == "0100000001edd579e9462ee0e80127a817e0500d4f942a4cf8f2d6530e0c0a9ab3f04862e10100000000ffffffff01802b530b0000000000001976a914819d291a2f7fbf770e784bfd78b5ce92c58e95ea88ac000000000000000001000000000000000000000000ffffffff6a473044022009e394c7dec76ab6988270b467839b1462ad781556bce37383b76e026418ce6302204f7f6ef535d2986b095d7c96232a0990a0b9ce3004894b39c167bb18e5833ac30121030e669acac1f280d1ddf441cd2ba5e97417bf2689e4bbec86df4f831bf9f7ffd0"
        )
    def test_send_mixed(self, client):
        inp1 = messages.TxInputType(
            # 2MutHjgAXkqo3jxX2DZWorLAckAnwTxSM9V
            address_n=parse_path("49'/1'/1'/0/0"),
            amount=20000,
            prev_hash=TXHASH_8c3ea7,
            prev_index=0,
            script_type=messages.InputScriptType.SPENDP2SHWITNESS,
        )
        inp2 = messages.TxInputType(
            # tb1q7r9yvcdgcl6wmtta58yxf29a8kc96jkyxl7y88
            address_n=parse_path("84'/1'/1'/0/0"),
            amount=15000,
            prev_hash=TXHASH_7956f1,
            prev_index=0,
            script_type=messages.InputScriptType.SPENDWITNESS,
        )
        inp3 = messages.TxInputType(
            # tb1paxhjl357yzctuf3fe58fcdx6nul026hhh6kyldpfsf3tckj9a3wslqd7zd
            address_n=parse_path("86'/1'/1'/0/0"),
            amount=4450,
            prev_hash=TXHASH_901593,
            prev_index=0,
            script_type=messages.InputScriptType.SPENDTAPROOT,
        )
        inp4 = messages.TxInputType(
            # msUqRgCWS7ryuFcF34EaKTrsTe3xHra128
            address_n=parse_path("44'/1'/1'/0/0"),
            amount=10000,
            prev_hash=TXHASH_3ac32e,
            prev_index=2,
            script_type=messages.InputScriptType.SPENDADDRESS,
        )
        out1 = messages.TxOutputType(
            address="tb1q6xnnna3g7lk22h5tn8nlx2ezmndlvuk556w4w3",
            amount=25000,
            script_type=messages.OutputScriptType.PAYTOWITNESS,
        )
        out2 = messages.TxOutputType(
            address="mfnMbVFC1rH4p9GNbjkMfrAjyKRLycFAzA",
            script_type=messages.OutputScriptType.PAYTOADDRESS,
            amount=7000,
        )
        out3 = messages.TxOutputType(
            address="2MvAG8m2xSf83FgeR4ZpUtaubpLNjAMMoka",
            amount=6900,
            script_type=messages.OutputScriptType.PAYTOP2SHWITNESS,
        )
        out4 = messages.TxOutputType(
            op_return_data=b"test of op_return data",
            amount=0,
            script_type=messages.OutputScriptType.PAYTOOPRETURN,
        )
        out5 = messages.TxOutputType(
            address=
            "tb1ptgp9w0mm89ms43flw0gkrhyx75gyc6qjhtpf0jmt5sv0dufpnsrsyv9nsz",
            amount=10000,
            script_type=messages.OutputScriptType.PAYTOTAPROOT,
        )

        with client:
            client.set_expected_responses([
                # process inputs
                request_input(0),
                request_input(1),
                request_input(2),
                request_input(3),
                # approve outputs
                request_output(0),
                messages.ButtonRequest(code=B.ConfirmOutput),
                request_output(1),
                messages.ButtonRequest(code=B.ConfirmOutput),
                request_output(2),
                messages.ButtonRequest(code=B.ConfirmOutput),
                request_output(3),
                messages.ButtonRequest(code=B.ConfirmOutput),
                request_output(4),
                messages.ButtonRequest(code=B.ConfirmOutput),
                messages.ButtonRequest(code=B.SignTx),
                # verify inputs
                request_input(0),
                request_meta(TXHASH_8c3ea7),
                request_input(0, TXHASH_8c3ea7),
                request_output(0, TXHASH_8c3ea7),
                request_output(1, TXHASH_8c3ea7),
                request_input(1),
                request_meta(TXHASH_7956f1),
                request_input(0, TXHASH_7956f1),
                request_input(1, TXHASH_7956f1),
                request_output(0, TXHASH_7956f1),
                request_output(1, TXHASH_7956f1),
                request_input(2),
                request_meta(TXHASH_901593),
                request_input(0, TXHASH_901593),
                request_output(0, TXHASH_901593),
                request_input(3),
                request_meta(TXHASH_3ac32e),
                request_input(0, TXHASH_3ac32e),
                request_output(0, TXHASH_3ac32e),
                request_output(1, TXHASH_3ac32e),
                request_output(2, TXHASH_3ac32e),
                # serialize (segwit) inputs
                request_input(0),
                request_input(1),
                request_input(2),
                # serialize and sign legacy input
                request_input(0),
                request_input(1),
                request_input(2),
                request_input(3),
                request_output(0),
                request_output(1),
                request_output(2),
                request_output(3),
                request_output(4),
                # serialize outputs
                request_output(0),
                request_output(1),
                request_output(2),
                request_output(3),
                request_output(4),
                # sign segwit inputs
                request_input(0),
                request_input(1),
                request_input(2),
                (client.features.model == "1", request_input(3)),
                request_finished(),
            ])
            _, serialized_tx = btc.sign_tx(
                client,
                "Testnet",
                [inp1, inp2, inp3, inp4],
                [out1, out2, out3, out4, out5],
                prev_txes=TX_API,
            )

        assert (
            serialized_tx.hex() ==
            "010000000001045d77b6e482d770031ad3ce3423727cc1707bc2c82e729b1189d2b60aa1a73e8c0000000017160014a33c6e24c99e108b97bc411e7e9ef31e9d5d6164ffffffff7b350e3faca092f39883d7086cdd502c82b6f0314ab61541b062733edef156790000000000ffffffff852e125137abca2dd7a42837dccfc34edc358c72eefd62978d6747d3be9315900000000000ffffffff9b117a776a9aaf70d4c3ffe89f009dcd23210a03d649ee5e38791d83902ec33a020000006b483045022100f6bd64136839b49822cf7e2050bc5c91346fc18b5cf97a945d4fd6c502f712d002207d1859e66d218f705b704f3cfca0c75410349bb1f50623f4fc2d09d5d8df0a3f012103bae960983f83e28fcb8f0e5f3dc1f1297b9f9636612fd0835b768e1b7275fb9dffffffff05a861000000000000160014d1a739f628f7eca55e8b99e7f32b22dcdbf672d4581b0000000000001976a91402e9b094fd98e2a26e805894eb78f7ff3fef199b88acf41a00000000000017a9141ff816cbeb74817050de585ceb2c772ebf71147a870000000000000000186a1674657374206f66206f705f72657475726e206461746110270000000000002251205a02573f7b39770ac53f73d161dc86f5104c6812bac297cb6ba418f6f1219c070247304402205fae7fa2b5141548593d5623ce5bd82ee18dfc751c243526039c91848efd603702200febfbe3467a68c599245ff89055514f26e146c79b58d932ced2325e6dad1b1a0121021630971f20fa349ba940a6ba3706884c41579cd760c89901374358db5dd545b90247304402201b21212100c84207697cebb852374669c382ed97cbd08afbbdfe1b302802161602206b32b2140d094cf5b7e758135961c95478c8e82fea0df30f56ccee284b79eaea012103f6b2377d52960a6094ec158cf19dcf9e33b3da4798c2302aa5806483ed4187ae01404a81e4b7f55d6d4a26923c5e2daf3cc86ed6030f83ea6e7bb16d7b81b988b34585be21a64ab45ddcc2fb9f17be2dfeff6b22cf943bc3fc8f125a7f463af428ed0000000000"
        )
def sign_tx(hw_session: HwSessionInfo,
            utxos_to_spend: List[wallet_common.UtxoType],
            tx_outputs: List[wallet_common.TxOutputType], tx_fee):
    """
    Creates a signed transaction.
    :param hw_session:
    :param utxos_to_spend: list of utxos to send
    :param tx_outputs: list of transaction outputs
    :param tx_fee: transaction fee
    :return: tuple (serialized tx, total transaction amount in satoshis)
    """
    def load_prev_txes(tx_api, skip_cache: bool = False):
        txes = {}
        tx_api.skip_cache = skip_cache
        for utxo in utxos_to_spend:
            prev_hash = bytes.fromhex(utxo.txid)
            if prev_hash not in txes:
                tx = tx_api[prev_hash]
                txes[prev_hash] = tx
        return txes

    insight_network = 'insight_dash'
    if hw_session.app_config.is_testnet():
        insight_network += '_testnet'
    dash_network = hw_session.app_config.dash_network

    c_name = hw_session.app_config.hw_coin_name
    coin = coins.by_name[c_name]
    url = hw_session.app_config.get_tx_api_url()
    coin['bitcore'].clear()
    coin['bitcore'].append(url)

    tx_api = MyTxApiInsight(coin, '', hw_session.dashd_intf,
                            hw_session.app_config.tx_cache_dir)
    client = hw_session.hw_client
    inputs = []
    outputs = []
    inputs_amount = 0
    for utxo_index, utxo in enumerate(utxos_to_spend):
        if not utxo.bip32_path:
            raise Exception('No BIP32 path for UTXO ' + utxo.txid)

        address_n = dash_utils.bip32_path_string_to_n(utxo.bip32_path)
        it = trezor_proto.TxInputType(address_n=address_n,
                                      prev_hash=binascii.unhexlify(utxo.txid),
                                      prev_index=int(utxo.output_index))

        inputs.append(it)
        inputs_amount += utxo.satoshis

    outputs_amount = 0
    for out in tx_outputs:
        outputs_amount += out.satoshis
        if out.address[0] in dash_utils.get_chain_params(
                dash_network).B58_PREFIXES_SCRIPT_ADDRESS:
            stype = trezor_proto.OutputScriptType.PAYTOSCRIPTHASH
            logging.debug('Transaction type: PAYTOSCRIPTHASH' + str(stype))
        elif out.address[0] in dash_utils.get_chain_params(
                dash_network).B58_PREFIXES_PUBKEY_ADDRESS:
            stype = trezor_proto.OutputScriptType.PAYTOADDRESS
            logging.debug('Transaction type: PAYTOADDRESS ' + str(stype))
        else:
            raise Exception('Invalid prefix of the destination address.')
        if out.bip32_path:
            address_n = dash_utils.bip32_path_string_to_n(out.bip32_path)
        else:
            address_n = None

        ot = trezor_proto.TxOutputType(
            address=out.address if address_n is None else None,
            address_n=address_n,
            amount=out.satoshis,
            script_type=stype)
        outputs.append(ot)

    if outputs_amount + tx_fee != inputs_amount:
        raise Exception(
            'Transaction validation failure: inputs + fee != outputs')

    try:
        for skip_cache in (False, True):
            txes = load_prev_txes(tx_api, skip_cache)
            try:
                signed = btc.sign_tx(client,
                                     hw_session.app_config.hw_coin_name,
                                     inputs,
                                     outputs,
                                     prev_txes=txes)
                return signed[1], inputs_amount
            except exceptions.Cancelled:
                raise
            except Exception as e:
                if skip_cache:
                    raise
                log.exception(
                    'Exception occurred while signing transaction. Turning off the transaction cache '
                    'and retrying...')
        raise Exception('Internal error: transaction not signed')
    except exceptions.Cancelled:
        raise CancelException('Cancelled')
    def test_send_bch_multisig_change(self):
        self.setup_mnemonic_allallall()
        self.client.set_tx_api(TxApiBcash)
        xpubs = []
        for n in map(
                lambda index: self.client.get_public_node(
                    parse_path("44'/145'/" + str(index) + "'")), range(1, 4)):
            xpubs.append(n.xpub)

        def getmultisig(chain, nr, signatures=[b'', b'', b''], xpubs=xpubs):
            return proto.MultisigRedeemScriptType(
                pubkeys=list(
                    map(
                        lambda xpub: proto.HDNodePathType(
                            node=deserialize(xpub), address_n=[chain, nr]),
                        xpubs)),
                signatures=signatures,
                m=2,
            )

        inp1 = proto.TxInputType(
            address_n=parse_path("44'/145'/3'/0/0"),
            multisig=getmultisig(0, 0),
            # bitcoincash:pqguz4nqq64jhr5v3kvpq4dsjrkda75hwy86gq0qzw
            amount=48490,
            prev_hash=unhexlify(
                '8b6db9b8ba24235d86b053ea2ccb484fc32b96f89c3c39f98d86f90db16076a0'
            ),
            prev_index=0,
            script_type=proto.InputScriptType.SPENDMULTISIG,
        )
        out1 = proto.TxOutputType(
            address='bitcoincash:qqq8gx2j76nw4dfefumxmdwvtf2tpsjznusgsmzex9',
            amount=24000,
            script_type=proto.OutputScriptType.PAYTOADDRESS,
        )
        out2 = proto.TxOutputType(
            address_n=parse_path("44'/145'/3'/1/0"),
            multisig=getmultisig(1, 0),
            script_type=proto.OutputScriptType.PAYTOMULTISIG,
            amount=24000)
        with self.client:
            self.client.set_expected_responses([
                proto.TxRequest(
                    request_type=proto.RequestType.TXINPUT,
                    details=proto.TxRequestDetailsType(request_index=0)),
                proto.TxRequest(
                    request_type=proto.RequestType.TXOUTPUT,
                    details=proto.TxRequestDetailsType(request_index=0)),
                proto.ButtonRequest(
                    code=proto.ButtonRequestType.ConfirmOutput),
                proto.TxRequest(
                    request_type=proto.RequestType.TXOUTPUT,
                    details=proto.TxRequestDetailsType(request_index=1)),
                proto.ButtonRequest(code=proto.ButtonRequestType.SignTx),
                proto.TxRequest(
                    request_type=proto.RequestType.TXINPUT,
                    details=proto.TxRequestDetailsType(request_index=0)),
                proto.TxRequest(
                    request_type=proto.RequestType.TXOUTPUT,
                    details=proto.TxRequestDetailsType(request_index=0)),
                proto.TxRequest(
                    request_type=proto.RequestType.TXOUTPUT,
                    details=proto.TxRequestDetailsType(request_index=1)),
                proto.TxRequest(request_type=proto.RequestType.TXFINISHED),
            ])
            (signatures1,
             serialized_tx) = self.client.sign_tx('Bcash', [inp1],
                                                  [out1, out2])

        assert hexlify(
            signatures1[0]
        ) == b'3045022100bcb1a7134a13025a06052546ee1c6ac3640a0abd2d130190ed13ed7fcb43e9cd02207c381478e2ee123c850425bfbf6d3c691230eb37e333832cb32a1ed3f2cd9e85'

        inp1 = proto.TxInputType(
            address_n=parse_path("44'/145'/1'/0/0"),
            multisig=getmultisig(0, 0, [b'', b'', signatures1[0]]),
            # bitcoincash:pqguz4nqq64jhr5v3kvpq4dsjrkda75hwy86gq0qzw
            amount=48490,
            prev_hash=unhexlify(
                '8b6db9b8ba24235d86b053ea2ccb484fc32b96f89c3c39f98d86f90db16076a0'
            ),
            prev_index=0,
            script_type=proto.InputScriptType.SPENDMULTISIG,
        )
        out2.address_n[2] = 1 + 0x80000000

        with self.client:
            self.client.set_expected_responses([
                proto.TxRequest(
                    request_type=proto.RequestType.TXINPUT,
                    details=proto.TxRequestDetailsType(request_index=0)),
                proto.TxRequest(
                    request_type=proto.RequestType.TXOUTPUT,
                    details=proto.TxRequestDetailsType(request_index=0)),
                proto.ButtonRequest(
                    code=proto.ButtonRequestType.ConfirmOutput),
                proto.TxRequest(
                    request_type=proto.RequestType.TXOUTPUT,
                    details=proto.TxRequestDetailsType(request_index=1)),
                proto.ButtonRequest(code=proto.ButtonRequestType.SignTx),
                proto.TxRequest(
                    request_type=proto.RequestType.TXINPUT,
                    details=proto.TxRequestDetailsType(request_index=0)),
                proto.TxRequest(
                    request_type=proto.RequestType.TXOUTPUT,
                    details=proto.TxRequestDetailsType(request_index=0)),
                proto.TxRequest(
                    request_type=proto.RequestType.TXOUTPUT,
                    details=proto.TxRequestDetailsType(request_index=1)),
                proto.TxRequest(request_type=proto.RequestType.TXFINISHED),
            ])
            (signatures1,
             serialized_tx) = self.client.sign_tx('Bcash', [inp1],
                                                  [out1, out2])

        assert hexlify(
            signatures1[0]
        ) == b'3045022100f1153636371ba1f84389460e1265a8fa296569bc18e117c31f4e8f0fc0650c01022022932cc84766ff0c0f65ed9633ad311ae90d4c8fe71f5e1890b1e8f74dd516fa'
        assert hexlify(
            serialized_tx
        ) == b'0100000001a07660b10df9868df9393c9cf8962bc34f48cb2cea53b0865d2324bab8b96d8b00000000fdfe0000483045022100f1153636371ba1f84389460e1265a8fa296569bc18e117c31f4e8f0fc0650c01022022932cc84766ff0c0f65ed9633ad311ae90d4c8fe71f5e1890b1e8f74dd516fa41483045022100bcb1a7134a13025a06052546ee1c6ac3640a0abd2d130190ed13ed7fcb43e9cd02207c381478e2ee123c850425bfbf6d3c691230eb37e333832cb32a1ed3f2cd9e85414c69522102fcf63419c319ce1a42d69120a3599d6da8c5dd4caf2888220eccde5a1ff7c5d021036d7d5ef79370b7fabe2c058698a20219e97fc70868e65ecdd6b37cc18e8a88bd2103505dc649dab8cd1655a4c0daf0ec5f955881c9d7011478ea881fac11cab1e49953aeffffffff02c05d0000000000001976a91400741952f6a6eab5394f366db5cc5a54b0c2429f88acc05d00000000000017a914756c06d7e77de3950a6124f026d8e1a2464b3ecf8700000000'