From e4dcc8d8c66c3242d29bc4209f87e4679872e21c Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Tue, 5 Jun 2018 16:02:51 +0200 Subject: [PATCH] zcash overwinter support --- trezorlib/client.py | 6 +++- trezorlib/messages/SignTx.py | 9 +++-- trezorlib/messages/SimpleSignTx.py | 8 ++++- trezorlib/messages/TransactionType.py | 6 ++-- .../device_tests/test_msg_signtx_zcash.py | 36 +++++++------------ ...e4cf1539c5172684721e38e69f4ef634d75dc.json | 1 + trezorlib/tx_api.py | 4 ++- vendor/trezor-common | 2 +- 8 files changed, 38 insertions(+), 34 deletions(-) create mode 100644 trezorlib/tests/txcache/insight_zcash_testnet_tx_aaf51e4606c264e47e5c42c958fe4cf1539c5172684721e38e69f4ef634d75dc.json diff --git a/trezorlib/client.py b/trezorlib/client.py index a654c25a1..57920eb57 100644 --- a/trezorlib/client.py +++ b/trezorlib/client.py @@ -778,7 +778,7 @@ class ProtocolMixin(object): return txes @session - def sign_tx(self, coin_name, inputs, outputs, version=None, lock_time=None, debug_processor=None): + def sign_tx(self, coin_name, inputs, outputs, version=None, lock_time=None, expiry=None, overwintered=None, debug_processor=None): # start = time.time() txes = self._prepare_sign_tx(inputs, outputs) @@ -792,6 +792,10 @@ class ProtocolMixin(object): tx.version = version if lock_time is not None: tx.lock_time = lock_time + if expiry is not None: + tx.expiry = expiry + if overwintered is not None: + tx.overwintered = overwintered res = self.call(tx) # Prepare structure for signatures diff --git a/trezorlib/messages/SignTx.py b/trezorlib/messages/SignTx.py index b6cf04474..070769a44 100644 --- a/trezorlib/messages/SignTx.py +++ b/trezorlib/messages/SignTx.py @@ -10,7 +10,8 @@ class SignTx(p.MessageType): 3: ('coin_name', p.UnicodeType, 0), # default='Bitcoin' 4: ('version', p.UVarintType, 0), # default=1 5: ('lock_time', p.UVarintType, 0), # default=0 - 6: ('decred_expiry', p.UVarintType, 0), + 6: ('expiry', p.UVarintType, 0), + 7: ('overwintered', p.BoolType, 0), } def __init__( @@ -20,11 +21,13 @@ class SignTx(p.MessageType): coin_name: str = None, version: int = None, lock_time: int = None, - decred_expiry: int = None + expiry: int = None, + overwintered: bool = None ) -> None: self.outputs_count = outputs_count self.inputs_count = inputs_count self.coin_name = coin_name self.version = version self.lock_time = lock_time - self.decred_expiry = decred_expiry + self.expiry = expiry + self.overwintered = overwintered diff --git a/trezorlib/messages/SimpleSignTx.py b/trezorlib/messages/SimpleSignTx.py index c66bfc0b9..33c4b70be 100644 --- a/trezorlib/messages/SimpleSignTx.py +++ b/trezorlib/messages/SimpleSignTx.py @@ -19,6 +19,8 @@ class SimpleSignTx(p.MessageType): 4: ('coin_name', p.UnicodeType, 0), # default='Bitcoin' 5: ('version', p.UVarintType, 0), # default=1 6: ('lock_time', p.UVarintType, 0), # default=0 + 7: ('expiry', p.UVarintType, 0), + 8: ('overwintered', p.BoolType, 0), } def __init__( @@ -28,7 +30,9 @@ class SimpleSignTx(p.MessageType): transactions: List[TransactionType] = None, coin_name: str = None, version: int = None, - lock_time: int = None + lock_time: int = None, + expiry: int = None, + overwintered: bool = None ) -> None: self.inputs = inputs if inputs is not None else [] self.outputs = outputs if outputs is not None else [] @@ -36,3 +40,5 @@ class SimpleSignTx(p.MessageType): self.coin_name = coin_name self.version = version self.lock_time = lock_time + self.expiry = expiry + self.overwintered = overwintered diff --git a/trezorlib/messages/TransactionType.py b/trezorlib/messages/TransactionType.py index 2d9d20b60..1b78bf2d0 100644 --- a/trezorlib/messages/TransactionType.py +++ b/trezorlib/messages/TransactionType.py @@ -21,7 +21,7 @@ class TransactionType(p.MessageType): 7: ('outputs_cnt', p.UVarintType, 0), 8: ('extra_data', p.BytesType, 0), 9: ('extra_data_len', p.UVarintType, 0), - 10: ('decred_expiry', p.UVarintType, 0), + 10: ('expiry', p.UVarintType, 0), 11: ('overwintered', p.BoolType, 0), } @@ -36,7 +36,7 @@ class TransactionType(p.MessageType): outputs_cnt: int = None, extra_data: bytes = None, extra_data_len: int = None, - decred_expiry: int = None, + expiry: int = None, overwintered: bool = None ) -> None: self.version = version @@ -48,5 +48,5 @@ class TransactionType(p.MessageType): self.outputs_cnt = outputs_cnt self.extra_data = extra_data self.extra_data_len = extra_data_len - self.decred_expiry = decred_expiry + self.expiry = expiry self.overwintered = overwintered diff --git a/trezorlib/tests/device_tests/test_msg_signtx_zcash.py b/trezorlib/tests/device_tests/test_msg_signtx_zcash.py index 7a437f4c4..eb3f45f95 100644 --- a/trezorlib/tests/device_tests/test_msg_signtx_zcash.py +++ b/trezorlib/tests/device_tests/test_msg_signtx_zcash.py @@ -24,58 +24,46 @@ from trezorlib import coins from trezorlib import messages as proto from trezorlib.tools import parse_path -TxApiZcash = coins.tx_api["Zcash"] +TxApiZcashTestnet = coins.tx_api['Zcash Testnet'] +TXHASH_aaf51e = unhexlify('aaf51e4606c264e47e5c42c958fe4cf1539c5172684721e38e69f4ef634d75dc') -TXHASH_93373e = unhexlify('93373e63cc626c4a7d049ad775d6511bb5eba985f142db660c9b9f955c722f5c') - -# Zcash reset their testnet, which broke our test because it was not properly cached. -# Then when we tried to revive it, Overwinter happened and now Trezor is incapable of -# processing v3 transactions. So it's difficult to fix the test until we support v3. @pytest.mark.zcash -@pytest.mark.xfail(reason="Zcash support is botched due to Overwinter") class TestMsgSigntxZcash(TrezorTest): def test_one_one_fee(self): self.setup_mnemonic_allallall() - # tx: 93373e63cc626c4a7d049ad775d6511bb5eba985f142db660c9b9f955c722f5c - # input 0: 1.234567 TAZ + # tx: aaf51e4606c264e47e5c42c958fe4cf1539c5172684721e38e69f4ef634d75dc + # input 1: 3.0 TAZ inp1 = proto.TxInputType( address_n=parse_path("m/Zcash Testnet/0h/0/0"), # tmQoJ3PTXgQLaRRZZYT6xk8XtjRbr2kCqwu - # amount=123456700, - prev_hash=TXHASH_93373e, - prev_index=0, + amount=300000000, + prev_hash=TXHASH_aaf51e, + prev_index=1, ) out1 = proto.TxOutputType( address='tmJ1xYxP8XNTtCoDgvdmQPSrxh5qZJgy65Z', - amount=123456700 - 1940, + amount=300000000 - 1940, script_type=proto.OutputScriptType.PAYTOADDRESS, ) with self.client: - self.client.set_tx_api(TxApiZcash) + self.client.set_tx_api(TxApiZcashTestnet) 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, ]) + (signatures, serialized_tx) = self.client.sign_tx('Zcash Testnet', [inp1, ], [out1, ], version=3, overwintered=True) - # Accepted by network: tx dcc2a10894e0e8a785c2afd4de2d958207329b9acc2b987fd768a09c5efc4547 - assert hexlify(serialized_tx) == b'01000000015c2f725c959f9b0c66db42f185a9ebb51b51d675d79a047d4a6c62cc633e3793000000006a4730440220670b2b63d749a7038f9aea6ddf0302fe63bdcad93dafa4a89a1f0e7300ae2484022002c50af43fd867490cea0c527273c5828ff1b9a5115678f155a1830737cf29390121030e669acac1f280d1ddf441cd2ba5e97417bf2689e4bbec86df4f831bf9f7ffd0ffffffff0128c55b07000000001976a9145b157a678a10021243307e4bb58f36375aa80e1088ac00000000' + # Accepted by network: tx TODO + assert hexlify(serialized_tx) == b'030000807082c40301dc754d63eff4698ee321476872519c53f14cfe58c9425c7ee464c206461ef5aa010000006a473044022039e3814541d8b9fcd09a43e9320514a327c79ce9473f679857afaee12ec7ba3d02207b00fad860dba848f280674129b347c7ffebeede8c85cf742ed854b0347af3600121030e669acac1f280d1ddf441cd2ba5e97417bf2689e4bbec86df4f831bf9f7ffd0ffffffff016c9be111000000001976a9145b157a678a10021243307e4bb58f36375aa80e1088ac0000000000000000' diff --git a/trezorlib/tests/txcache/insight_zcash_testnet_tx_aaf51e4606c264e47e5c42c958fe4cf1539c5172684721e38e69f4ef634d75dc.json b/trezorlib/tests/txcache/insight_zcash_testnet_tx_aaf51e4606c264e47e5c42c958fe4cf1539c5172684721e38e69f4ef634d75dc.json new file mode 100644 index 000000000..66dd082c2 --- /dev/null +++ b/trezorlib/tests/txcache/insight_zcash_testnet_tx_aaf51e4606c264e47e5c42c958fe4cf1539c5172684721e38e69f4ef634d75dc.json @@ -0,0 +1 @@ +{"txid": "aaf51e4606c264e47e5c42c958fe4cf1539c5172684721e38e69f4ef634d75dc", "version": 3, "locktime": 234321, "vin": [{"txid": "01d175a5421206439525542f83d168577e92d59e8283e8862e236a1461d5938a", "vout": 2, "sequence": 4294967294, "n": 0, "scriptSig": {"hex": "473044022053a63f730e449f2d6c687ac53e9be627c4241614c041f458da2c4f91143179c802206ade1de030fc5fc77c4a88ccc79daedd28a79bfaf9e24533727a6fb81cbe4bd801210201d494a45f36f545443bafd1a9050b02f448dd236bb4ce2602f83978980b98f2", "asm": "3044022053a63f730e449f2d6c687ac53e9be627c4241614c041f458da2c4f91143179c802206ade1de030fc5fc77c4a88ccc79daedd28a79bfaf9e24533727a6fb81cbe4bd801 0201d494a45f36f545443bafd1a9050b02f448dd236bb4ce2602f83978980b98f2"}, "addr": "tmKBPqa8qqKA7vrGq1AaXHSAr9vqa3GczzK", "valueSat": 717937236, "value": "7.17937236", "doubleSpentTxID": null}], "vout": [{"value": "4.17937001", "n": 0, "scriptPubKey": {"hex": "76a914f5ea91f798002a6520f19da514f354b1c37b30d188ac", "asm": "OP_DUP OP_HASH160 f5ea91f798002a6520f19da514f354b1c37b30d1 OP_EQUALVERIFY OP_CHECKSIG", "addresses": ["tmY8dtPhaCuUy8nDABhtTzUnuxA5HQSQopq"], "type": "pubkeyhash"}, "spentTxId": "facc6ca0a5ac80ec9ce375aa2bb0e36be9c60eb38ae8a42f9c3582afbc196446", "spentIndex": 0, "spentHeight": 234335}, {"value": "3.00000000", "n": 1, "scriptPubKey": {"hex": "76a914a579388225827d9f2fe9014add644487808c695d88ac", "asm": "OP_DUP OP_HASH160 a579388225827d9f2fe9014add644487808c695d OP_EQUALVERIFY OP_CHECKSIG", "addresses": ["tmQoJ3PTXgQLaRRZZYT6xk8XtjRbr2kCqwu"], "type": "pubkeyhash"}, "spentTxId": null, "spentIndex": null, "spentHeight": null}], "vjoinsplit": [], "blockhash": "007886949ef185d5917522ae403d2ee884fc8f1b9b61f6802e6289cb65840480", "blockheight": 234332, "confirmations": 12968, "time": 1525885273, "blocktime": 1525885273, "valueOut": "7.17937001", "size": 234, "valueIn": "7.17937236", "fees": "0.00000235", "fOverwintered": true, "nVersionGroupId": 63210096, "nExpiryHeight": 234352} \ No newline at end of file diff --git a/trezorlib/tx_api.py b/trezorlib/tx_api.py index e7e8a02d0..0fd5da8a6 100644 --- a/trezorlib/tx_api.py +++ b/trezorlib/tx_api.py @@ -99,7 +99,9 @@ class TxApiInsight(TxApi): o.script_pubkey = binascii.unhexlify(vout['scriptPubKey']['hex']) if self.zcash: - if t.version == 2: + t.overwintered = data.get('fOverwintered', False) + t.expiry = data.get('nExpiryHeight', False) + if t.version >= 2: joinsplit_cnt = len(data['vjoinsplit']) if joinsplit_cnt == 0: t.extra_data = b'\x00' diff --git a/vendor/trezor-common b/vendor/trezor-common index aed1d7632..6d87bdcd5 160000 --- a/vendor/trezor-common +++ b/vendor/trezor-common @@ -1 +1 @@ -Subproject commit aed1d7632f5ad309db8a10f9c8f597f320e83aa5 +Subproject commit 6d87bdcd579d53adc17e1ec67199434645e5a0aa