Beispiel #1
0
 def test_send_segwit_p2sh(self, client):
     inp1 = proto.TxInputType(
         # 2N1LGaGg836mqSQqiuUBLfcyGBhyZYBtBZ7
         address_n=parse_path("49'/1'/0'/1/0"),
         amount=123456789,
         prev_hash=TXHASH_09a48b,
         prev_index=0,
         script_type=proto.InputScriptType.SPENDP2SHWITNESS,
         sequence=0xFFFFFFFE,
     )
     out1 = proto.TxOutputType(
         address="mvbu1Gdy8SUjTenqerxUaZyYjmvedc787y",
         amount=12300000,
         script_type=proto.OutputScriptType.PAYTOADDRESS,
     )
     out2 = proto.TxOutputType(
         address="2N1LGaGg836mqSQqiuUBLfcyGBhyZYBtBZ7",
         amount=123456789 - 11000 - 12300000,
         script_type=proto.OutputScriptType.PAYTOADDRESS,
     )
     details = proto.SignTx(lock_time=650756)
     _, serialized_tx = btc.sign_tx(
         client, "Groestlcoin Testnet", [inp1], [out1, out2], details=details
     )
     assert (
         serialized_tx.hex()
         == "01000000000101cf60ded29a2bd7ebf93453feace8551889d0321beab90c4f6e5c9d2fce8ba4090000000017160014d16b8c0680c61fc6ed2e407455715055e41052f5feffffff02e0aebb00000000001976a914a579388225827d9f2fe9014add644487808c695d88ac3df39f060000000017a91458b53ea7f832e8f096e896b8713a8c6df0e892ca8702483045022100b7ce2972bcbc3a661fe320ba901e680913b2753fcb47055c9c6ba632fc4acf81022001c3cfd6c2fe92eb60f5176ce0f43707114dd7223da19c56f2df89c13c2fef80012103e7bfe10708f715e8538c92d46ca50db6f657bbc455b7494e6a0303ccdb868b7904ee0900"
     )
Beispiel #2
0
 def test_send_segwit_native_change(self):
     # https://blockbook-test.groestlcoin.org/tx/9b5c4859a8a31e69788cb4402812bb28f14ad71cbd8c60b09903478bc56f79a3
     self.setup_mnemonic_allallall()
     inp1 = proto.TxInputType(
         address_n=parse_path("84'/1'/0'/0/0"),
         amount=12300000,
         prev_hash=bytes.fromhex(
             "4f2f857f39ed1afe05542d058fb0be865a387446e32fc876d086203f483f61d1"
         ),
         prev_index=0,
         script_type=proto.InputScriptType.SPENDWITNESS,
         sequence=0xFFFFFFFE,
     )
     out1 = proto.TxOutputType(
         address="2N4Q5FhU2497BryFfUgbqkAJE87aKDv3V3e",
         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,
     )
     details = proto.SignTx(lock_time=650713)
     _, serialized_tx = btc.sign_tx(
         self.client, "Groestlcoin Testnet", [inp1], [out1, out2], details=details
     )
     assert (
         serialized_tx.hex()
         == "01000000000101d1613f483f2086d076c82fe34674385a86beb08f052d5405fe1aed397f852f4f0000000000feffffff02404b4c000000000017a9147a55d61848e77ca266e79a39bfc85c580a6426c987a8386f0000000000160014cc8067093f6f843d6d3e22004a4290cd0c0f336b02483045022100ea8780bc1e60e14e945a80654a41748bbf1aa7d6f2e40a88d91dfc2de1f34bd10220181a474a3420444bd188501d8d270736e1e9fe379da9970de992ff445b0972e3012103adc58245cf28406af0ef5cc24b8afba7f1be6c72f279b642d85c48798685f862d9ed0900"
     )
Beispiel #3
0
 def test_send_segwit_native_change(self, client):
     inp1 = proto.TxInputType(
         address_n=parse_path("84'/1'/0'/0/0"),
         amount=12300000,
         prev_hash=TXHASH_4f2f85,
         prev_index=0,
         script_type=proto.InputScriptType.SPENDWITNESS,
         sequence=0xFFFFFFFE,
     )
     out1 = proto.TxOutputType(
         address="2N4Q5FhU2497BryFfUgbqkAJE87aKDv3V3e",
         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,
     )
     details = proto.SignTx(lock_time=650713)
     _, serialized_tx = btc.sign_tx(
         client, "Groestlcoin Testnet", [inp1], [out1, out2], details=details
     )
     assert (
         serialized_tx.hex()
         == "01000000000101d1613f483f2086d076c82fe34674385a86beb08f052d5405fe1aed397f852f4f0000000000feffffff02404b4c000000000017a9147a55d61848e77ca266e79a39bfc85c580a6426c987a8386f0000000000160014cc8067093f6f843d6d3e22004a4290cd0c0f336b02483045022100ea8780bc1e60e14e945a80654a41748bbf1aa7d6f2e40a88d91dfc2de1f34bd10220181a474a3420444bd188501d8d270736e1e9fe379da9970de992ff445b0972e3012103adc58245cf28406af0ef5cc24b8afba7f1be6c72f279b642d85c48798685f862d9ed0900"
     )
Beispiel #4
0
    def test_version_group_id_missing(self, client):
        inp1 = proto.TxInputType(
            # tmQoJ3PTXgQLaRRZZYT6xk8XtjRbr2kCqwu
            address_n=parse_path("m/44h/1h/0h/0/0"),
            amount=300000000,
            prev_hash=TXHASH_e38206,
            prev_index=0,
        )
        out1 = proto.TxOutputType(
            address="tmJ1xYxP8XNTtCoDgvdmQPSrxh5qZJgy65Z",
            amount=300000000 - 1940,
            script_type=proto.OutputScriptType.PAYTOADDRESS,
        )

        details = proto.SignTx(version=4)
        with pytest.raises(TrezorFailure,
                           match="Version group ID must be set."):
            btc.sign_tx(
                client,
                "Zcash Testnet",
                [inp1],
                [out1],
                details=details,
                prev_txes=TX_API,
            )
Beispiel #5
0
def test_timestamp_included(client):
    # tx: 3bf506c81ce84eda891679ddc797d162c17c60b15d6c0ac23be5e31369e7235f
    # input 0: 0.01 CPC
    # tx: f3a6e6411f1b2dffd76d2729bae8e056f8f9ecf8996d3f428e75a6f23f2c5e8c
    # input 0: 0.02 CPC

    inp1 = messages.TxInputType(address_n=parse_path("m/44'/289'/0'/0/0"),
                                prev_hash=TXHASH_3bf506,
                                prev_index=0)

    inp2 = messages.TxInputType(address_n=parse_path("m/44'/289'/0'/0/0"),
                                prev_hash=TXHASH_f3a6e6,
                                prev_index=1)

    out1 = messages.TxOutputType(
        address="CUGi8RGPWxbHM6FxF4eMEfqmQ6Bs5VjCdr",
        amount=3000000 - 20000,
        script_type=messages.OutputScriptType.PAYTOADDRESS,
    )

    with client:
        details = messages.SignTx(version=1, timestamp=0x5BCF5C66)
        _, timestamp_tx = btc.sign_tx(
            client,
            "Capricoin",
            [inp1, inp2],
            [out1],
            details=details,
            prev_txes=tx_cache("Capricoin"),
        )

    # Accepted by network https://insight.capricoin.org/tx/1bf227e6e24fe1f8ac98849fe06a2c5b77762e906fcf7e82787675f7f3a10bb8
    accepted_txhex = "01000000665ccf5b025f23e76913e3e53bc20a6c5db1607cc162d197c7dd791689da4ee81cc806f53b000000006b483045022100fce7ccbeb9524f36d118ebcfebcb133a05c236c4478e2051cfd5c9632920aee602206921b7be1a81f30cce3d8e7dba4597fc16a2761c42321c49d65eeacdfe3781250121021fcf98aee04939ec7df5762f426dc2d1db8026e3a73c3bbe44749dacfbb61230ffffffff8c5e2c3ff2a6758e423f6d99f8ecf9f856e0e8ba29276dd7ff2d1b1f41e6a6f3010000006a473044022015d967166fe9f89fbed8747328b1c4658aa1d7163e731c5fd5908feafe08e9a6022028af30801098418bd298cc60b143c52c48466f5791256721304b6eba4fdf0b3c0121021fcf98aee04939ec7df5762f426dc2d1db8026e3a73c3bbe44749dacfbb61230ffffffff01a0782d00000000001976a914818437acfd15780debd31f3fd21d4ca678bb36d188ac00000000"
    assert timestamp_tx.hex() == accepted_txhex
Beispiel #6
0
    def test_v3_not_supported(self, client):
        # prevout: aaf51e4606c264e47e5c42c958fe4cf1539c5172684721e38e69f4ef634d75dc:1
        # input 1: 3.0 TAZ

        inp1 = proto.TxInputType(
            # tmQoJ3PTXgQLaRRZZYT6xk8XtjRbr2kCqwu
            address_n=parse_path("m/44h/1h/0h/0/0"),
            amount=300000000,
            prev_hash=TXHASH_aaf51e,
            prev_index=1,
        )

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

        with client:
            details = proto.SignTx(
                version=3,
                version_group_id=0x03C48270,
                branch_id=0x5BA81B19,
            )
            with pytest.raises(TrezorFailure, match="DataError"):
                _, serialized_tx = btc.sign_tx(
                    client,
                    "Zcash Testnet",
                    [inp1],
                    [out1],
                    details=details,
                    prev_txes=TX_API,
                )
def test_timestamp_included(client):
    # tx: 41b29ad615d8eea40a4654a052d18bb10cd08f203c351f4d241f88b031357d3d
    # input 0: 0.1 PPC

    inp1 = messages.TxInputType(
        address_n=parse_path("m/44'/6'/0'/0/0"),
        amount=100000,
        prev_hash=TXHASH_41b29a,
        prev_index=0,
    )

    out1 = messages.TxOutputType(
        address="PXtfyTjzgXSgTwK5AbszdHQSSxyQN3BLM5",
        amount=100000 - 10000,
        script_type=messages.OutputScriptType.PAYTOADDRESS,
    )

    details = messages.SignTx(version=1, timestamp=0x5DC5448A)
    _, timestamp_tx = btc.sign_tx(
        client,
        "Peercoin",
        [inp1],
        [out1],
        details=details,
        prev_txes=TX_CACHE,
    )

    # Accepted by network https://explorer.peercoin.net/api/getrawtransaction?txid=f7e3624c143b6a170cc44f9337d0fa8ea8564a211de9c077c6889d8c78f80909&decrypt=1
    accepted_txhex = "010000008a44c55d013d7d3531b0881f244d1f353c208fd00cb18bd152a054460aa4eed815d69ab241000000006a473044022025c0ea702390c702c7ae8b5ea469820bea8d942c8c16439f8f0ba2e91e699efc02200db9b0a48fa2861695fa91df4831a4c7306587e5d2dc85419647f462717bc8f001210274cb0ee652d9457fbb0f3872d43155a6bc16f77bd5749d8826b53db443b1b278ffffffff01905f0100000000001976a914ff9a05654150fdc92b1655f49d7f2a8aaf6a3a2a88ac00000000"
    assert timestamp_tx.hex() == accepted_txhex
Beispiel #8
0
 def test_send_segwit_p2sh(self):
     # https://blockbook-test.groestlcoin.org/tx/4ce0220004bdfe14e3dd49fd8636bcb770a400c0c9e9bff670b6a13bb8f15c72
     self.setup_mnemonic_allallall()
     inp1 = proto.TxInputType(
         address_n=parse_path(
             "49'/1'/0'/1/0"
         ),  # 2N1LGaGg836mqSQqiuUBLfcyGBhyZYBtBZ7
         amount=123456789,
         prev_hash=bytes.fromhex(
             "09a48bce2f9d5c6e4f0cb9ea1b32d0891855e8acfe5334f9ebd72b9ad2de60cf"
         ),
         prev_index=0,
         script_type=proto.InputScriptType.SPENDP2SHWITNESS,
         sequence=0xFFFFFFFE,
     )
     out1 = proto.TxOutputType(
         address="mvbu1Gdy8SUjTenqerxUaZyYjmvedc787y",
         amount=12300000,
         script_type=proto.OutputScriptType.PAYTOADDRESS,
     )
     out2 = proto.TxOutputType(
         address="2N1LGaGg836mqSQqiuUBLfcyGBhyZYBtBZ7",
         amount=123456789 - 11000 - 12300000,
         script_type=proto.OutputScriptType.PAYTOADDRESS,
     )
     details = proto.SignTx(lock_time=650756)
     _, serialized_tx = btc.sign_tx(
         self.client, "Groestlcoin Testnet", [inp1], [out1, out2], details=details
     )
     assert (
         serialized_tx.hex()
         == "01000000000101cf60ded29a2bd7ebf93453feace8551889d0321beab90c4f6e5c9d2fce8ba4090000000017160014d16b8c0680c61fc6ed2e407455715055e41052f5feffffff02e0aebb00000000001976a914a579388225827d9f2fe9014add644487808c695d88ac3df39f060000000017a91458b53ea7f832e8f096e896b8713a8c6df0e892ca8702483045022100b7ce2972bcbc3a661fe320ba901e680913b2753fcb47055c9c6ba632fc4acf81022001c3cfd6c2fe92eb60f5176ce0f43707114dd7223da19c56f2df89c13c2fef80012103e7bfe10708f715e8538c92d46ca50db6f657bbc455b7494e6a0303ccdb868b7904ee0900"
     )
Beispiel #9
0
def sign_interactive():
    coin = prompt("Coin name", default="Bitcoin")
    blockbook_host = prompt("Blockbook server", default="btc1.trezor.io")

    if not requests.get(f"https://{blockbook_host}/api").ok:
        raise click.ClickException("Could not connect to blockbook")

    blockbook_url = f"https://{blockbook_host}/api/tx-specific/"

    inputs, txes = _get_inputs_interactive(blockbook_url)
    outputs = _get_outputs_interactive()

    signtx = messages.SignTx()
    signtx.version = prompt("Transaction version", type=int, default=2)
    signtx.lock_time = prompt("Transaction locktime", type=int, default=0)

    result = {
        "coin_name": coin,
        "inputs": [to_dict(i, hexlify_bytes=True) for i in inputs],
        "outputs": [to_dict(o, hexlify_bytes=True) for o in outputs],
        "details": to_dict(signtx, hexlify_bytes=True),
        "prev_txes": {
            txhash: to_dict(txdata, hexlify_bytes=True)
            for txhash, txdata in txes.items()
        },
    }

    print(json.dumps(result, sort_keys=True, indent=2))
    def test_one_one_fee_sapling(self):
        self.setup_mnemonic_allallall()

        # prevout:  339c3e78610e229f65ebc3fa722016fcb9fbde7bc196d2d876604f5257ada19c:0
        # input 1: 2.9999 KMD

        inp1 = proto.TxInputType(
            address_n=parse_path(
                "m/Komodo/0h/0/0"),  # RDvyC66RQf7HKkUB5zyLKJhitV4ibzkKF5
            amount=299990000,
            prev_hash=TXHASH_339c3e,
            prev_index=0,
        )

        out1 = proto.TxOutputType(
            address="RDvyC66RQf7HKkUB5zyLKJhitV4ibzkKF5",
            amount=299990000 - 10000,
            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.TXFINISHED),
            ])

            details = proto.SignTx(
                version=4,
                overwintered=True,
                version_group_id=0x892F2085,
                branch_id=0x76B809BB,
            )
            _, serialized_tx = btc.sign_tx(self.client,
                                           "Komodo", [inp1], [out1],
                                           details=details,
                                           prev_txes=TX_API)

        # Accepted by network: tx 92b45f54cb7c3cdfc4a88dbf088dfcc7c1417ad0955f02712e136da7fd5343d6
        assert (
            serialized_tx.hex() ==
            "0400008085202f89019ca1ad57524f6076d8d296c17bdefbb9fc162072fac3eb659f220e61783e9c33000000006a47304402206972af8ff4dec4074da9edb1a741114bebda9e686bb411dd6f388aafd81f0af2022060a05d0ea66d5b8632868b6a6d377ad1a8941385d628be4631b31cc246014b8501210235ad92bb4efda1e6794890f248fa26aab75906bd496c07a6a8532b62a5bd80f7ffffffff01e054e111000000001976a91433058d6bb20e9297fc0a518e2e0262e854496a6c88ac6be15c5c000000000000000000000000000000"
        )
Beispiel #11
0
    def test_spend_old_versions(self, client):
        # inputs are NOT OWNED by this seed
        input_v1 = proto.TxInputType(
            address_n=parse_path("m/44h/1h/0h/0/0"),
            amount=123000000,
            prev_hash=TXHASH_v1,
            prev_index=0,
        )
        input_v2 = proto.TxInputType(
            address_n=parse_path("m/44h/1h/0h/0/1"),
            amount=49990000,
            prev_hash=TXHASH_v2,
            prev_index=0,
        )
        input_v3 = proto.TxInputType(
            address_n=parse_path("m/44h/1h/0h/0/2"),
            amount=300000000,
            prev_hash=TXHASH_v3,
            prev_index=1,
        )
        input_v4 = proto.TxInputType(
            address_n=parse_path("m/44h/1h/0h/0/3"),
            amount=100000,
            prev_hash=TXHASH_v4,
            prev_index=0,
        )

        inputs = [input_v1, input_v2, input_v3, input_v4]

        for i, txi in enumerate(inputs, 1):
            txdata = TX_API[txi.prev_hash]
            assert txdata.version == i

        output = proto.TxOutputType(
            address="tmNvfeKR5PkcQazLEqddTskFr6Ev9tsovfQ",
            amount=sum(txi.amount for txi in inputs),
            script_type=proto.OutputScriptType.PAYTOADDRESS,
        )

        details = proto.SignTx(
            version=4,
            version_group_id=0x892F2085,
            branch_id=0x76B809BB,
        )

        with client:
            _, serialized_tx = btc.sign_tx(
                client,
                "Zcash Testnet",
                inputs,
                [output],
                details=details,
                prev_txes=TX_API,
            )

        assert (
            serialized_tx.hex() ==
            "0400008085202f890446828054c6c81a8c370c47dc1cfd6f1b200af5623ac3d5b62501121b74ae91fb000000006b483045022100d40e85efbadd378fc603dc8b11c70774086de631fe5b1418ac2b95a478f86507022072e999d8ddd75a0b33bd2adcc88e7234e6251b9e73c9223e7c59e0d1f8d1ff220121030e669acac1f280d1ddf441cd2ba5e97417bf2689e4bbec86df4f831bf9f7ffd0ffffffffef42e249deb8e7bc1d5ec7c4590c70c5b89734b2b896c72ad6469d95190ed303000000006b483045022100917d96445d64c80f9569cb9ca45c04c9b6d7b0fda6b9fd0b1d311837366c699202202cd6140489cf38b5d97ed271ba28603f4693c2a36113cc6ec423301f077c5a8e01210294e3e5e77e22eea0e4c0d30d89beb4db7f69b4bf1ae709e411d6a06618b8f852ffffffff6cb78ae689ae1334f4b03c6f613b280c70088b963f1c965f814081d1298841f9010000006a473044022058768c74c9b1698070636388d7d2ae8223748f13b0a5f402716e4d49fc5bc5f30220658d1e6095dcfbe66669b4141d23af28c9ed5bae73480889429b41742be85f32012103f5008445568548bd745a3dedccc6048969436bf1a49411f60938ff1938941f14ffffffff0f9c2ee92a378e5399a6f2c41dce2b4af5a7119ae1bee3c8ec8eb06472e68d5d000000006b483045022100e64853d86bed039c4edce4abaf80d41486cd21c63bec79c0308ea05a351663e302206732aa22a5dee7bd7f3cc8268faebe31a08abadb4b7e3a4257509bc7baa052b60121029ad0b9519779c540b34fa8d11d24d14a5475546bfa28c7de50573d22a503ce21ffffffff01d0c7321c000000001976a91490ede9de4bed6e39008375eace793949de9a533288ac00000000000000000000000000000000000000"
        )
Beispiel #12
0
    def test_one_one_fee_sapling(self, client):
        # prevout: e3820602226974b1dd87b7113cc8aea8c63e5ae29293991e7bfa80c126930368:0
        # input 1: 3.0 TAZ

        inp1 = proto.TxInputType(
            # tmQoJ3PTXgQLaRRZZYT6xk8XtjRbr2kCqwu
            address_n=parse_path("m/44h/1h/0h/0/0"),
            amount=300000000,
            prev_hash=TXHASH_e38206,
            prev_index=0,
        )

        out1 = proto.TxOutputType(
            address="tmJ1xYxP8XNTtCoDgvdmQPSrxh5qZJgy65Z",
            amount=300000000 - 1940,
            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_meta(TXHASH_e38206),
                request_input(0, TXHASH_e38206),
                request_input(1, TXHASH_e38206),
                request_output(0, TXHASH_e38206),
                request_output(1, TXHASH_e38206),
                request_extra_data(0, 1, TXHASH_e38206),
                request_input(0),
                request_output(0),
                request_finished(),
            ])

            details = proto.SignTx(
                version=4,
                version_group_id=0x892F2085,
                branch_id=0x76B809BB,
            )
            _, serialized_tx = btc.sign_tx(
                client,
                "Zcash Testnet",
                [inp1],
                [out1],
                details=details,
                prev_txes=TX_API,
            )

        # Accepted by network: tx 0cef132c1d6d67f11cfa48f7fca3209da29cf872ac782354bedb686e61a17a78
        assert (
            serialized_tx.hex() ==
            "0400008085202f890168039326c180fa7b1e999392e25a3ec6a8aec83c11b787ddb1746922020682e3000000006b483045022100f28298891f48706697a6f898ac18e39ce2c7cebe547b585d51cc22d80b1b21a602201a807b8a18544832d95d1e3ada82c0617bc6d97d3f24d1fb4801ac396647aa880121030e669acac1f280d1ddf441cd2ba5e97417bf2689e4bbec86df4f831bf9f7ffd0ffffffff016c9be111000000001976a9145b157a678a10021243307e4bb58f36375aa80e1088ac00000000000000000000000000000000000000"
        )
Beispiel #13
0
    def test_one_one_fee_overwinter(self, client):
        # prevout: aaf51e4606c264e47e5c42c958fe4cf1539c5172684721e38e69f4ef634d75dc:1
        # input 1: 3.0 TAZ

        inp1 = proto.TxInputType(
            # tmQoJ3PTXgQLaRRZZYT6xk8XtjRbr2kCqwu
            address_n=parse_path("m/44h/1h/0h/0/0"),
            amount=300000000,
            prev_hash=TXHASH_aaf51e,
            prev_index=1,
        )

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

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

            details = proto.SignTx(
                version=3,
                version_group_id=0x03C48270,
                branch_id=0x5BA81B19,
            )
            _, serialized_tx = btc.sign_tx(
                client,
                "Zcash Testnet",
                [inp1],
                [out1],
                details=details,
                prev_txes=TX_API,
            )

        # Accepted by network: tx eda9b772c47f0c29310759960e0081c98707aa67a0a2738bcc71439fcf360675
        assert (
            serialized_tx.hex() ==
            "030000807082c40301dc754d63eff4698ee321476872519c53f14cfe58c9425c7ee464c206461ef5aa010000006a47304402207e45f303b4e42be824513855eb21653e1d2749cd94dcd0f0613d3f85d4efd1e20220699ffbdbcad889af7ede5ce9febf7a5ef8f5619b2464824529974c400cffaebc0121030e669acac1f280d1ddf441cd2ba5e97417bf2689e4bbec86df4f831bf9f7ffd0ffffffff016c9be111000000001976a9145b157a678a10021243307e4bb58f36375aa80e1088ac000000000000000000"
        )
Beispiel #14
0
    def test_one_one_fee_sapling(self, client):
        # prevout: 2807c5b126ec8e2b078cab0f12e4c8b4ce1d7724905f8ebef8dca26b0c8e0f1d:0
        # input 1: 10.9998 KMD

        inp1 = proto.TxInputType(
            # R9HgJZo6JBKmPvhm7whLSR8wiHyZrEDVRi
            address_n=parse_path("44'/141'/0'/0/0"),
            amount=1099980000,
            prev_hash=TXHASH_2807c,
            prev_index=0,
        )

        out1 = proto.TxOutputType(
            address="R9HgJZo6JBKmPvhm7whLSR8wiHyZrEDVRi",
            amount=1099980000 - 10000,
            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),
                proto.ButtonRequest(code=B.SignTx),
                request_input(0),
                request_meta(TXHASH_2807c),
                request_input(0, TXHASH_2807c),
                request_output(0, TXHASH_2807c),
                request_extra_data(0, 11, TXHASH_2807c),
                request_input(0),
                request_output(0),
                request_finished(),
            ])

            details = proto.SignTx(
                version=4,
                version_group_id=0x892F2085,
                branch_id=0x76B809BB,
                lock_time=0x5D2A30B8,
            )
            _, serialized_tx = btc.sign_tx(client,
                                           "Komodo", [inp1], [out1],
                                           details=details,
                                           prev_txes=TX_API)

        # Accepted by network: tx 7b28bd91119e9776f0d4ebd80e570165818a829bbf4477cd1afe5149dbcd34b1
        assert (
            serialized_tx.hex() ==
            "0400008085202f89011d0f8e0c6ba2dcf8be8e5f9024771dceb4c8e4120fab8c072b8eec26b1c50728000000006a4730440220158c970ca2fc6bcc33026eb5366f0342f63b35d178f7efb334b1df78fe90b67202207bc4ff69f67cf843b08564a5adc77bf5593e28ab4d5104911824ac13fe885d8f012102a87aef7b1a8f676e452d6240767699719cd58b0261c822472c25df146938bca5ffffffff01d0359041000000001976a91400178fa0b6fc253a3a402ee2cadd8a7bfec08f6388acb8302a5d000000000000000000000000000000"
        )
Beispiel #15
0
    def test_lock_time(self, client, lock_time, sequence):
        # tx: d5f65ee80147b4bcc70b75e4bbf2d7382021b871bd8867ef8fa525ef50864882
        # input 0: 0.0039 BTC

        inp1 = messages.TxInputType(
            address_n=parse_path("44h/0h/0h/0/0"),
            amount=390000,
            prev_hash=TXHASH_d5f65e,
            prev_index=0,
            sequence=sequence,
        )

        out1 = messages.TxOutputType(
            address="1MJ2tj2ThBE62zXbBYA5ZaN3fdve5CPAz1",
            amount=390000 - 10000,
            script_type=messages.OutputScriptType.PAYTOADDRESS,
        )

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

            details = messages.SignTx(lock_time=lock_time)
            btc.sign_tx(
                client,
                "Bitcoin",
                [inp1],
                [out1],
                details=details,
                prev_txes=TX_CACHE_MAINNET,
            )
def sign_interactive():
    coin = prompt("Coin name", default="Bitcoin")
    if coin in coins.tx_api:
        coin_data = coins.by_name[coin]
        txapi = coins.tx_api[coin]
    else:
        echo('Coin "%s" is not recognized.' % coin, err=True)
        echo("Supported coin types: %s" % ", ".join(coins.tx_api.keys()), err=True)
        sys.exit(1)

    inputs, txes = _get_inputs_interactive(coin_data, txapi)
    outputs = _get_outputs_interactive()

    if coin_data["bip115"]:
        current_block_height = txapi.current_height()
        # Zencash recommendation for the better protection
        block_height = current_block_height - 300
        block_hash = txapi.get_block_hash(block_height)
        # Blockhash passed in reverse order
        block_hash = block_hash[::-1]

        for output in outputs:
            output.block_hash_bip115 = block_hash
            output.block_height_bip115 = block_height

    signtx = messages.SignTx()
    signtx.version = prompt("Transaction version", type=int, default=2)
    signtx.lock_time = prompt("Transaction locktime", type=int, default=0)
    if coin == "Capricoin":
        signtx.timestamp = prompt("Transaction timestamp", type=int)

    result = {
        "coin_name": coin,
        "inputs": [to_dict(i, hexlify_bytes=True) for i in inputs],
        "outputs": [to_dict(o, hexlify_bytes=True) for o in outputs],
        "details": to_dict(signtx, hexlify_bytes=True),
        "prev_txes": {
            txhash.hex(): to_dict(txdata, hexlify_bytes=True)
            for txhash, txdata in txes.items()
        },
    }

    print(json.dumps(result, sort_keys=True, indent=2))
Beispiel #17
0
    def test_signtx_forbidden_fields(self, client, field, value):
        inp0 = messages.TxInputType(address_n=parse_path("44h/0h/0h/0/0"),
                                    prev_hash=TXHASH_157041,
                                    prev_index=0)
        out1 = messages.TxOutputType(
            address="1MJ2tj2ThBE62zXbBYA5ZaN3fdve5CPAz1",
            amount=1000,
            script_type=messages.OutputScriptType.PAYTOADDRESS,
        )

        details = messages.SignTx()
        setattr(details, field, value)
        name = field.replace("_", " ")
        with pytest.raises(
                TrezorFailure,
                match=r"(?i){} not enabled on this coin".format(name)):
            btc.sign_tx(client,
                        "Bitcoin", [inp0], [out1],
                        details,
                        prev_txes=TX_CACHE_MAINNET)
Beispiel #18
0
    def test_signtx_forbidden_fields(self, client, field, value):
        cache = TxCache("Bitcoin")
        inp0 = proto.TxInputType(address_n=[0],
                                 prev_hash=TXHASH_157041,
                                 prev_index=0)
        out1 = proto.TxOutputType(
            address="1MJ2tj2ThBE62zXbBYA5ZaN3fdve5CPAz1",
            amount=1000,
            script_type=proto.OutputScriptType.PAYTOADDRESS,
        )

        details = proto.SignTx()
        setattr(details, field, value)
        name = field.replace("_", " ")
        with pytest.raises(
                TrezorFailure,
                match=r"(?i){} not enabled on this coin".format(name)):
            btc.sign_tx(client,
                        "Bitcoin", [inp0], [out1],
                        details,
                        prev_txes=cache)
def test_timestamp_missing_prevtx(client):
    inp1 = messages.TxInputType(
        address_n=parse_path("m/44'/6'/0'/0/0"),
        amount=100000,
        prev_hash=TXHASH_41b29a,
        prev_index=0,
    )
    out1 = messages.TxOutputType(
        address="PXtfyTjzgXSgTwK5AbszdHQSSxyQN3BLM5",
        amount=100000 - 10000,
        script_type=messages.OutputScriptType.PAYTOADDRESS,
    )
    details = messages.SignTx(version=1, timestamp=0x5DC5448A)

    prevtx = TX_CACHE[TXHASH_41b29a]
    prevtx.timestamp = 0

    with pytest.raises(TrezorFailure, match="Timestamp must be set."):
        btc.sign_tx(
            client,
            "Peercoin",
            [inp1],
            [out1],
            details=details,
            prev_txes={TXHASH_41b29a: prevtx},
        )

    prevtx.timestamp = None
    with pytest.raises(TrezorFailure, match="Timestamp must be set."):
        btc.sign_tx(
            client,
            "Peercoin",
            [inp1],
            [out1],
            details=details,
            prev_txes={TXHASH_41b29a: prevtx},
        )
Beispiel #20
0
    def sign_tx(self, required_data):
        signing_inputs = required_data['signing_inputs']
        transaction_outputs = required_data['transaction_outputs']
        signing_transactions = required_data['signing_transactions']
        signing_address_types = required_data['signing_address_types']

        scripts = []
        for in_ in signing_inputs:
            service_xpub = deserialize(in_['service_xpub'])
            user_xpub = deserialize(self.as_xpub(in_['user_path'][:-1]))
            pointer = in_['pointer']
            redeem_script = proto.MultisigRedeemScriptType(
                nodes=[user_xpub, service_xpub],
                address_n=[pointer],
                signatures=[b'', b''],
                m=2,
                csv=in_['subtype'])
            scripts.append(redeem_script)

        ins = []
        for i, txin in enumerate(signing_inputs):
            in_ = proto.TxInputType(
                address_n=txin['user_path'],
                prev_hash=h2b(txin['txhash']),
                prev_index=txin['pt_idx'],
                script_type=proto.InputScriptType.SPENDP2SHWITNESS,
                multisig=scripts[i],
                amount=txin['satoshi'],
                sequence=txin['sequence'])
            in_.confidential = proto.TxConfidentialAsset(
                asset=h2b(txin['asset_id'])[::-1],
                amount_blind=h2b(txin['vbf']),
                asset_blind=h2b(txin['abf']))
            ins.append(in_)

        values = []
        in_vbfs = []
        in_abfs = []
        for txin in signing_inputs:
            in_vbfs.append(h2b(txin['vbf']))
            in_abfs.append(h2b(txin['abf']))
            values.append(txin['satoshi'])

        out_vbfs = []
        out_abfs = []
        for i, txout in enumerate(transaction_outputs):
            if txout['is_fee']:
                continue
            out_vbfs.append(
                os.urandom(32))  # TODO: check if HW is going to generate these
            out_abfs.append(
                os.urandom(32))  # TODO: check if HW is going to generate these
            values.append(txout['satoshi'])

        abfs = in_abfs + out_abfs
        vbfs = in_vbfs + out_vbfs[:-1]
        final_vbf = wally.asset_final_vbf(values, len(signing_inputs),
                                          b''.join(abfs), b''.join(vbfs))
        out_vbfs[-1] = final_vbf

        outs = []
        for i, txout in enumerate(transaction_outputs):
            if txout['is_fee']:
                out = proto.TxOutputType(address='', amount=txout['satoshi'])
                out.confidential = proto.TxConfidentialAsset(
                    asset=h2b(txout['asset_id'])[::-1])
            else:
                out = proto.TxOutputType(
                    address=txout['address'],
                    amount=txout['satoshi'],
                    script_type=proto.OutputScriptType.PAYTOADDRESS)
                out.confidential = proto.TxConfidentialAsset(
                    asset=h2b(txout['asset_id'])[::-1],
                    amount_blind=out_vbfs[i],
                    asset_blind=out_abfs[i],
                    nonce_privkey=h2b(txout['eph_keypair_sec']))
            outs.append(out)

        signatures, serialized_tx = btc.sign_tx(
            self.client,
            'Elements',
            ins,
            outs,
            prev_txes=None,
            details=proto.SignTx(version=2,
                                 lock_time=required_data['transaction']
                                 ['transaction_locktime']))

        # with open('tx.txt', 'w') as f:
        #    f.write(serialized_tx.hex())

        asset_commitments = []
        value_commitments = []

        tx = wally.tx_from_bytes(
            serialized_tx,
            wally.WALLY_TX_FLAG_USE_WITNESS | wally.WALLY_TX_FLAG_USE_ELEMENTS)
        for i in range(wally.tx_get_num_outputs(tx)):
            asset_commitments.append(wally.tx_get_output_asset(tx, i))
            value_commitments.append(wally.tx_get_output_value(tx, i))

        out_abfs.append(b'\x00' *
                        32)  # FIXME: GDK enforcing blinding factors for fee
        out_vbfs.append(b'\x00' * 32)

        return json.dumps({
            'signatures': [sig.hex() + '01' for sig in signatures],
            'vbfs': [vbf.hex() for vbf in out_vbfs],
            'abfs': [abf.hex() for abf in out_abfs],
            'asset_commitments':
            [commitment.hex() for commitment in asset_commitments],
            'value_commitments':
            [commitment.hex() for commitment in value_commitments]
        })
Beispiel #21
0
def make_signing_details(tx) -> m.SignTx:
    details_dict = {
        "version": tx.version,
        "lock_time": tx.lock_time,
    }
    return m.SignTx(**details_dict)
    def test_one_one_rewards_claim(self, client):
        # prevout: 7b28bd91119e9776f0d4ebd80e570165818a829bbf4477cd1afe5149dbcd34b1:0
        # input 1: 10.9997 KMD

        inp1 = proto.TxInputType(
            address_n=parse_path(
                "44'/141'/0'/0/0"
            ),  # R9HgJZo6JBKmPvhm7whLSR8wiHyZrEDVRi
            amount=1099970000,
            prev_hash=TXHASH_7b28bd,
            prev_index=0,
        )

        out1 = proto.TxOutputType(
            address="R9HgJZo6JBKmPvhm7whLSR8wiHyZrEDVRi",
            amount=1099970000 - 10000,
            script_type=proto.OutputScriptType.PAYTOADDRESS,
        )

        # kmd interest, vout sum > vin sum
        out2 = proto.TxOutputType(
            address="R9HgJZo6JBKmPvhm7whLSR8wiHyZrEDVRi",
            amount=79605,
            script_type=proto.OutputScriptType.PAYTOADDRESS,
        )

        with client:
            er = [
                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),
            ]
            if client.features.model != "1":  # extra screen for lock_time
                er += [proto.ButtonRequest(code=proto.ButtonRequestType.SignTx)]
            er += [
                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),
            ]
            client.set_expected_responses(er)

            details = proto.SignTx(
                version=4,
                version_group_id=0x892F2085,
                branch_id=0x76B809BB,
                lock_time=0x5D2AF1F2,
            )
            _, serialized_tx = btc.sign_tx(
                client,
                "Komodo",
                [inp1],
                [out1, out2],
                details=details,
                prev_txes=TX_API,
            )

        # Accepted by network: tx c775678ceb18277729b427c7acf2f8ce63ac02fc2366f47ce08a3f443ff0e059
        assert (
            serialized_tx.hex()
            == "0400008085202f8901b134cddb4951fe1acd7744bf9b828a816501570ed8ebd4f076979e1191bd287b000000006a4730440220483a58f5be3a147c773c663008c992a7fcea4d03bdf4c1d4bc0535c0d98ddf0602207b19d69140dd00c7a94f048c712aeaed55dfd27f581c7212d9cc5e476fe1dc9f012102a87aef7b1a8f676e452d6240767699719cd58b0261c822472c25df146938bca5ffffffff02c00e9041000000001976a91400178fa0b6fc253a3a402ee2cadd8a7bfec08f6388acf5360100000000001976a91400178fa0b6fc253a3a402ee2cadd8a7bfec08f6388acf2f12a5d000000000000000000000000000000"
        )
    def test_external_presigned(self, client):
        inp1 = proto.TxInputType(
            # tmQoJ3PTXgQLaRRZZYT6xk8XtjRbr2kCqwu
            address_n=parse_path("m/44h/1h/0h/0/0"),
            amount=300000000,
            prev_hash=TXHASH_e38206,
            prev_index=0,
        )

        inp2 = proto.TxInputType(
            # tmQoJ3PTXgQLaRRZZYT6xk8XtjRbr2kCqwu
            # address_n=parse_path("m/44h/1h/0h/0/0"),
            amount=300000000,
            prev_hash=TXHASH_aaf51e,
            prev_index=1,
            script_type=proto.InputScriptType.EXTERNAL,
            script_sig=bytes.fromhex(
                "47304402202495a38e5b368569a1a0c9fc95aa7e57a0dd5ae43f51300d7222dc139015233d022047833eaa571578f72c8468c8b537b36410388b7eb5001d75d1f4b954e1997d590121030e669acac1f280d1ddf441cd2ba5e97417bf2689e4bbec86df4f831bf9f7ffd0"
            ),
        )

        out1 = proto.TxOutputType(
            address="tmJ1xYxP8XNTtCoDgvdmQPSrxh5qZJgy65Z",
            amount=300000000 + 300000000 - 1940,
            script_type=proto.OutputScriptType.PAYTOADDRESS,
        )

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

            details = proto.SignTx(
                version=4,
                version_group_id=0x892F2085,
                branch_id=0x76B809BB,
            )
            _, serialized_tx = btc.sign_tx(
                client,
                "Zcash Testnet",
                [inp1, inp2],
                [out1],
                details=details,
                prev_txes=TX_API,
            )

        assert (
            serialized_tx.hex() ==
            "0400008085202f890268039326c180fa7b1e999392e25a3ec6a8aec83c11b787ddb1746922020682e3000000006a473044022007efbf539f8d612d8e140c6af2289b447c34e3d36edd75d539f269fe5526878302206830f6b0398494bca09afdd967fedcd016f49468711cfcd7aafd9a128ee568d20121030e669acac1f280d1ddf441cd2ba5e97417bf2689e4bbec86df4f831bf9f7ffd0ffffffffdc754d63eff4698ee321476872519c53f14cfe58c9425c7ee464c206461ef5aa010000006a47304402202495a38e5b368569a1a0c9fc95aa7e57a0dd5ae43f51300d7222dc139015233d022047833eaa571578f72c8468c8b537b36410388b7eb5001d75d1f4b954e1997d590121030e669acac1f280d1ddf441cd2ba5e97417bf2689e4bbec86df4f831bf9f7ffd0ffffffff016c3ec323000000001976a9145b157a678a10021243307e4bb58f36375aa80e1088ac00000000000000000000000000000000000000"
        )
Beispiel #24
0
    def sign_tx(self, tx):

        # Get this devices master key fingerprint
        master_key = btc.get_public_node(self.client, [0])
        master_fp = get_xpub_fingerprint(master_key.xpub)

        # Do multiple passes for multisig
        passes = 1
        p = 0

        while p < passes:
            # Prepare inputs
            inputs = []
            to_ignore = [
            ]  # Note down which inputs whose signatures we're going to ignore
            for input_num, (psbt_in, txin) in py_enumerate(
                    list(zip(tx.inputs, tx.tx.vin))):
                txinputtype = proto.TxInputType()

                # Set the input stuff
                txinputtype.prev_hash = ser_uint256(txin.prevout.hash)[::-1]
                txinputtype.prev_index = txin.prevout.n
                txinputtype.sequence = txin.nSequence

                # Detrermine spend type
                scriptcode = b''
                if psbt_in.non_witness_utxo:
                    utxo = psbt_in.non_witness_utxo.vout[txin.prevout.n]
                    txinputtype.script_type = proto.InputScriptType.SPENDADDRESS
                    scriptcode = utxo.scriptPubKey
                    txinputtype.amount = psbt_in.non_witness_utxo.vout[
                        txin.prevout.n].nValue
                elif psbt_in.witness_utxo:
                    utxo = psbt_in.witness_utxo
                    # Check if the output is p2sh
                    if psbt_in.witness_utxo.is_p2sh():
                        txinputtype.script_type = proto.InputScriptType.SPENDP2SHWITNESS
                    else:
                        txinputtype.script_type = proto.InputScriptType.SPENDWITNESS
                    scriptcode = psbt_in.witness_utxo.scriptPubKey
                    txinputtype.amount = psbt_in.witness_utxo.nValue

                # Set the script
                if psbt_in.witness_script:
                    scriptcode = psbt_in.witness_script
                elif psbt_in.redeem_script:
                    scriptcode = psbt_in.redeem_script

                def ignore_input():
                    txinputtype.address_n = [0x80000000]
                    inputs.append(txinputtype)
                    to_ignore.append(input_num)

                # Check for multisig
                is_ms, multisig = parse_multisig(scriptcode)
                if is_ms:
                    # Add to txinputtype
                    txinputtype.multisig = multisig
                    if psbt_in.non_witness_utxo:
                        if utxo.is_p2sh:
                            txinputtype.script_type = proto.InputScriptType.SPENDMULTISIG
                        else:
                            # Cannot sign bare multisig, ignore it
                            ignore_input()
                            continue
                elif not is_ms and psbt_in.non_witness_utxo and not utxo.is_p2pkh:
                    # Cannot sign unknown spk, ignore it
                    ignore_input()
                    continue
                elif not is_ms and psbt_in.witness_utxo and psbt_in.witness_script:
                    # Cannot sign unknown witness script, ignore it
                    ignore_input()
                    continue

                # Find key to sign with
                found = False
                our_keys = 0
                for key in psbt_in.hd_keypaths.keys():
                    keypath = psbt_in.hd_keypaths[key]
                    if keypath[
                            0] == master_fp and key not in psbt_in.partial_sigs:
                        if not found:
                            txinputtype.address_n = keypath[1:]
                            found = True
                        our_keys += 1

                # Determine if we need to do more passes to sign everything
                if our_keys > passes:
                    passes = our_keys

                if not found:
                    # This input is not one of ours
                    ignore_input()
                    continue

                # append to inputs
                inputs.append(txinputtype)

            # address version byte
            if self.is_testnet:
                p2pkh_version = b'\x6f'
                p2sh_version = b'\xc4'
                bech32_hrp = 'tb'
            else:
                p2pkh_version = b'\x00'
                p2sh_version = b'\x05'
                bech32_hrp = 'bc'

            # prepare outputs
            outputs = []
            for out in tx.tx.vout:
                txoutput = proto.TxOutputType()
                txoutput.amount = out.nValue
                txoutput.script_type = proto.OutputScriptType.PAYTOADDRESS
                if out.is_p2pkh():
                    txoutput.address = to_address(out.scriptPubKey[3:23],
                                                  p2pkh_version)
                elif out.is_p2sh():
                    txoutput.address = to_address(out.scriptPubKey[2:22],
                                                  p2sh_version)
                else:
                    wit, ver, prog = out.is_witness()
                    if wit:
                        txoutput.address = bech32.encode(bech32_hrp, ver, prog)
                    else:
                        raise TypeError("Output is not an address")

                # append to outputs
                outputs.append(txoutput)

            # Prepare prev txs
            prevtxs = {}
            for psbt_in in tx.inputs:
                if psbt_in.non_witness_utxo:
                    prev = psbt_in.non_witness_utxo

                    t = proto.TransactionType()
                    t.version = prev.nVersion
                    t.lock_time = prev.nLockTime

                    for vin in prev.vin:
                        i = proto.TxInputType()
                        i.prev_hash = ser_uint256(vin.prevout.hash)[::-1]
                        i.prev_index = vin.prevout.n
                        i.script_sig = vin.scriptSig
                        i.sequence = vin.nSequence
                        t.inputs.append(i)

                    for vout in prev.vout:
                        o = proto.TxOutputBinType()
                        o.amount = vout.nValue
                        o.script_pubkey = vout.scriptPubKey
                        t.bin_outputs.append(o)
                    logging.debug(psbt_in.non_witness_utxo.hash)
                    prevtxs[ser_uint256(
                        psbt_in.non_witness_utxo.sha256)[::-1]] = t

            # Sign the transaction
            tx_details = proto.SignTx()
            tx_details.version = tx.tx.nVersion
            tx_details.lock_time = tx.tx.nLockTime
            if self.is_testnet:
                signed_tx = btc.sign_tx(self.client, "Testnet", inputs,
                                        outputs, tx_details, prevtxs)
            else:
                signed_tx = btc.sign_tx(self.client, "Bitcoin", inputs,
                                        outputs, tx_details, prevtxs)

            # Each input has one signature
            for input_num, (psbt_in, sig) in py_enumerate(
                    list(zip(tx.inputs, signed_tx[0]))):
                if input_num in to_ignore:
                    continue
                for pubkey in psbt_in.hd_keypaths.keys():
                    fp = psbt_in.hd_keypaths[pubkey][0]
                    if fp == master_fp and pubkey not in psbt_in.partial_sigs:
                        psbt_in.partial_sigs[pubkey] = sig + b'\x01'
                        break

            p += 1

        return {'psbt': tx.serialize()}
Beispiel #25
0
def sign_tx(sig_percent,
            client,
            coin_name,
            inputs,
            outputs,
            details=None,
            prev_txes=None):
    # set up a transactions dict
    txes = {None: trezor_proto.TransactionType(inputs=inputs, outputs=outputs)}
    # preload all relevant transactions ahead of time
    for inp in inputs:
        if inp.script_type not in (
                trezor_proto.InputScriptType.SPENDP2SHWITNESS,
                trezor_proto.InputScriptType.SPENDWITNESS,
                trezor_proto.InputScriptType.EXTERNAL,
        ):
            try:
                prev_tx = prev_txes[inp.prev_hash]
            except Exception as e:
                raise ValueError("Could not retrieve prev_tx") from e
            if not isinstance(prev_tx, trezor_proto.TransactionType):
                raise ValueError("Invalid value for prev_tx") from None
            txes[inp.prev_hash] = prev_tx

    if details is None:
        signtx = trezor_proto.SignTx()
    else:
        signtx = details

    signtx.coin_name = coin_name
    signtx.inputs_count = len(inputs)
    signtx.outputs_count = len(outputs)

    res = client.call(signtx)

    # Prepare structure for signatures
    signatures = [None] * len(inputs)
    serialized_tx = b""

    def copy_tx_meta(tx):
        tx_copy = trezor_proto.TransactionType(**tx)
        # clear fields
        tx_copy.inputs_cnt = len(tx.inputs)
        tx_copy.inputs = []
        tx_copy.outputs_cnt = len(tx.bin_outputs or tx.outputs)
        tx_copy.outputs = []
        tx_copy.bin_outputs = []
        tx_copy.extra_data_len = len(tx.extra_data or b"")
        tx_copy.extra_data = None
        return tx_copy

    R = trezor_proto.RequestType

    percent = 0  # Used for signaling progress. 1-10 for inputs/outputs, 10-100 for sigs.
    sig_percent.emit(percent)
    while isinstance(res, trezor_proto.TxRequest):
        # If there's some part of signed transaction, let's add it
        if res.serialized:
            if res.serialized.serialized_tx:
                serialized_tx += res.serialized.serialized_tx

            if res.serialized.signature_index is not None:
                idx = res.serialized.signature_index
                sig = res.serialized.signature
                if signatures[idx] is not None:
                    raise ValueError("Signature for index %d already filled" %
                                     idx)
                signatures[idx] = sig
                # emit completion percent
                percent = 10 + int(90 * (idx + 1) / len(signatures))
                sig_percent.emit(percent)

        if res.request_type == R.TXFINISHED:
            break

        # Device asked for one more information, let's process it.
        current_tx = txes[res.details.tx_hash]

        if res.request_type == R.TXMETA:
            msg = copy_tx_meta(current_tx)
            res = client.call(trezor_proto.TxAck(tx=msg))

        elif res.request_type == R.TXINPUT:
            if percent == 0 or (res.details.request_index > 0
                                and percent < 10):
                percent = 1 + int(
                    8 * (res.details.request_index + 1) / len(inputs))
                sig_percent.emit(percent)
            msg = trezor_proto.TransactionType()
            msg.inputs = [current_tx.inputs[res.details.request_index]]
            res = client.call(trezor_proto.TxAck(tx=msg))

        elif res.request_type == R.TXOUTPUT:
            # Update just one percent then display additional waiting message (emitting -1)
            if percent == 9:
                percent += 1
                sig_percent.emit(percent)
                sig_percent.emit(-1)

            msg = trezor_proto.TransactionType()
            if res.details.tx_hash:
                msg.bin_outputs = [
                    current_tx.bin_outputs[res.details.request_index]
                ]
            else:
                msg.outputs = [current_tx.outputs[res.details.request_index]]

            res = client.call(trezor_proto.TxAck(tx=msg))

        elif res.request_type == R.TXEXTRADATA:
            o, l = res.details.extra_data_offset, res.details.extra_data_len
            msg = trezor_proto.TransactionType()
            msg.extra_data = current_tx.extra_data[o:o + l]
            res = client.call(trezor_proto.TxAck(tx=msg))

    if isinstance(res, trezor_proto.Failure):
        raise Exception("Signing failed")

    if not isinstance(res, trezor_proto.TxRequest):
        raise Exception("Unexpected message")

    if None in signatures:
        raise RuntimeError("Some signatures are missing!")

    return signatures, serialized_tx
Beispiel #26
0
in1_prev_hash_b = bytes.fromhex(in1_prev_hash)
device = get_transport()
client = TrezorClient(transport=device, ui=ui.ClickUI())

fw = client.features
fw_min = min_version[fw.model]
py_min = (3, 6, 0)
tl_min = [0, 12, 0]
if (fw_min > (fw.major_version, fw.minor_version, fw.patch_version)
        or tl_min > [int(i) for i in lib_version.split('.')]
        or py_min > py_ver):
    m = "Requires at least Python rev {}, trezorlib rev {}, and FW rev {}"
    print(m.format(py_min, tl_min, fw_min))
    exit(1)

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.SPENDWITNESS,
                      sequence=sequence)
]
outs = [
    proto.TxOutputType(address=out1_address,
                       amount=out1_amount,
                       script_type=proto.OutputScriptType.PAYTOADDRESS)
]