Ethereum: EIP-155 replay protection

Added chain_id parameter to sign tx (and updated protobuf).
Added a unit test with chain_id for Ropsten testnet.
trezorctl:
 - Fixed compatibility with new ethjsonrpc
 - added chain_id parameter
pull/25/head
Jochen Hoenicke 7 years ago committed by Pavol Rusnak
parent 4b98513ff7
commit 607893f9ac

@ -153,5 +153,32 @@ class TestMsgEthereumSigntx(common.TrezorTest):
to=binascii.unhexlify('1d1c328764a41bda0492b66baa30c4a339ff85ef'),
value=12345678901234567890)
def test_ethereum_signtx_nodata_eip155(self):
self.setup_mnemonic_allallall()
sig_v, sig_r, sig_s = self.client.ethereum_sign_tx(
n=[0x80000000 | 44, 0x80000000 | 1, 0x80000000, 0, 0],
nonce=0,
gas_price=20000000000,
gas_limit=21000,
to=binascii.unhexlify('8ea7a3fccc211ed48b763b4164884ddbcf3b0a98'),
value=100000000000000000,
chain_id=3)
self.assertEqual(sig_v, 41)
self.assertEqual(binascii.hexlify(sig_r), 'a90d0bc4f8d63be69453dd62f2bb5fff53c610000abf956672564d8a654d401a')
self.assertEqual(binascii.hexlify(sig_s), '544a2e57bc8b4da18660a1e6036967ea581cc635f5137e3ba97a750867c27cf2')
sig_v, sig_r, sig_s = self.client.ethereum_sign_tx(
n=[0x80000000 | 44, 0x80000000 | 1, 0x80000000, 0, 0],
nonce=1,
gas_price=20000000000,
gas_limit=21000,
to=binascii.unhexlify('8ea7a3fccc211ed48b763b4164884ddbcf3b0a98'),
value=100000000000000000,
chain_id=3)
self.assertEqual(sig_v, 42)
self.assertEqual(binascii.hexlify(sig_r), '699428a6950e23c6843f1bf3754f847e64e047e829978df80d55187d19a401ce')
self.assertEqual(binascii.hexlify(sig_s), '087343d0a3a2f10842218ffccb146b59a8431b6245ab389fde22dc833f171e6e')
if __name__ == '__main__':
unittest.main()

@ -182,6 +182,8 @@ class Commands(object):
host, port = args.host.split(':')
eth = EthJsonRpc(host, int(port))
if not args.data:
args.gata = ''
if args.data.startswith('0x'):
args.data = args.data[2:]
data = binascii.unhexlify(args.data)
@ -189,12 +191,12 @@ class Commands(object):
if not gas_price:
gas_price = eth.eth_gasPrice()
if args.data:
gas_limit = hex_to_dec(eth.eth_estimateGas(
if not gas_limit:
gas_limit = eth.eth_estimateGas(
to_address=args.to,
from_address=address,
value=value,
data="0x"+args.data))
value=("0x%x" % value),
data="0x"+args.data)
if not nonce:
nonce = eth.eth_getTransactionCount(address)
@ -206,7 +208,8 @@ class Commands(object):
gas_limit=gas_limit,
to=to_address,
value=value,
data=data)
data=data,
chain_id=args.chain_id)
transaction = rlp.encode(
(nonce, gas_price, gas_limit, to_address, value, data) + sig)
@ -411,6 +414,7 @@ class Commands(object):
ethereum_sign_tx.arguments = (
(('-a', '--host'), {'type': str, 'default': 'localhost:8545'}),
(('-c', '--chain-id'), {'type' : int, 'help': 'EIP-155 chain id (replay protection)', 'default': None}),
(('-n', '-address'), {'type': str}),
(('-v', '--value'), {'type': str, 'default': "0"}),
(('-g', '--gas'), {'type': int, 'help': 'Required for offline signing'}),

@ -503,7 +503,7 @@ class ProtocolMixin(object):
return self.call(proto.EthereumGetAddress(address_n=n, show_display=show_display))
@session
def ethereum_sign_tx(self, n, nonce, gas_price, gas_limit, to, value, data=None):
def ethereum_sign_tx(self, n, nonce, gas_price, gas_limit, to, value, data=None, chain_id=None):
def int_to_big_endian(value):
import rlp.utils
if value == 0:
@ -527,6 +527,9 @@ class ProtocolMixin(object):
data, chunk = data[1024:], data[:1024]
msg.data_initial_chunk = chunk
if chain_id:
msg.chain_id = chain_id
response = self.call(msg)
while response.HasField('data_length'):

Loading…
Cancel
Save