From 19cc7e1676345e9222a35e39849f62c5e2ff2ba2 Mon Sep 17 00:00:00 2001 From: Alexander Koeberl Date: Mon, 15 Feb 2021 14:48:25 +0100 Subject: [PATCH] Support chain_id=None for backward compatibility (prevent EIP-155 additions). --- README.md | 1 + blocksec2go_ethereum/_signer.py | 4 ++-- blocksec2go_ethereum/_utils.py | 7 +++++-- tests/test_utils.py | 6 ++++++ 4 files changed, 14 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index d51a238..68325bc 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,7 @@ pip install blocksec2go-ethereum After creating an instance of `Blocksec2Go` you can use it to generate signatures for transaction dicts. When passed raw tx, `sign_transaction()` will return a hex string of RLP-encoded signed transaction that can be directly consumed by `web3.eth.sendRawTransaction()`. +The replay attack protection introduced with [EIP-155](https://eips.ethereum.org/EIPS/eip-155) is used by default. Set `chain_id=None` to force the legacy behaviour for backward compatibility. ### Transfer Ether Below you will find an example of signing a simple Ether transfer: diff --git a/blocksec2go_ethereum/_signer.py b/blocksec2go_ethereum/_signer.py index 11062d6..467a3dd 100644 --- a/blocksec2go_ethereum/_signer.py +++ b/blocksec2go_ethereum/_signer.py @@ -1,6 +1,6 @@ import logging import time -from typing import Tuple +from typing import Tuple, Optional import blocksec2go from blocksec2go.comm.pyscard import open_pyscard @@ -18,7 +18,7 @@ class Blocksec2GoSigner: - def __init__(self, key_id: int = 1, chain_id: int = 1, connect_retry_count: int = 5): + def __init__(self, key_id: int = 1, chain_id: Optional[int] = 1, connect_retry_count: int = 5): self._key_id = key_id self._chain_id = chain_id self._connect_retry_count = connect_retry_count diff --git a/blocksec2go_ethereum/_utils.py b/blocksec2go_ethereum/_utils.py index 104becf..449e77f 100644 --- a/blocksec2go_ethereum/_utils.py +++ b/blocksec2go_ethereum/_utils.py @@ -1,4 +1,4 @@ -from typing import Tuple +from typing import Tuple, Optional import ecdsa from eth_typing import ChecksumAddress @@ -34,6 +34,9 @@ def address_from_public_key(public_key: bytes) -> ChecksumAddress: return Web3.toChecksumAddress(address) -def get_v(sig: UnrecoverableSignature, tx_hash: bytes, pub_key: bytes, chain_id: int) -> int: +def get_v(sig: UnrecoverableSignature, tx_hash: bytes, pub_key: bytes, chain_id: Optional[int]) -> int: recovery_id = find_recovery_id(sig, tx_hash, pub_key) + + if not chain_id: + return 27 + recovery_id return 35 + recovery_id + (chain_id * 2) diff --git a/tests/test_utils.py b/tests/test_utils.py index 8863da7..49d80c4 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -28,3 +28,9 @@ def test_address_from_public_key(): def test_get_v(): returned_v = get_v(test_unrecoverable_signature, test_tx_hash, test_pub_key, test_chain_id) assert test_signature[0] == returned_v + + +def test_get_v_legacy(): + returned_v = get_v(test_unrecoverable_signature, test_tx_hash, test_pub_key, None) + legacy_v = test_signature[0] - (2 * test_chain_id) - 35 + 27 + assert legacy_v == returned_v