Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -429,9 +429,12 @@ class NethermindExceptionMapper(ExceptionMapper):
}
mapping_regex = {
# In-range r that is not an x-coordinate on the curve leaves the
# transaction without a recovered sender.
# transaction without a recovered sender. Nethermind decodes a legacy
# v as a 64-bit integer, so a v past that fails RLP decoding.
TransactionException.INVALID_SIGNATURE_VRS: (
r"failed with error sender not specified"
r"|Transaction \d+ is not valid: "
r"Unexpected length of integer value"
),
TransactionException.INSUFFICIENT_ACCOUNT_FUNDS: (
r"insufficient sender balance|"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,11 @@ class NimbusExceptionMapper(ExceptionMapper):
TransactionException.INITCODE_SIZE_EXCEEDED: (
"max initcode size exceeded"
),
# Nimbus decodes a legacy v as a 64-bit integer, so a v past that
# fails decoding the payload.
TransactionException.INVALID_SIGNATURE_VRS: (
"Failed to decode block in payload: integer out of bounds"
),
BlockException.RLP_BLOCK_LIMIT_EXCEEDED: (
# TODO:
"ExceededBlockSizeLimit: Exceeded block size limit"
Expand Down
5 changes: 4 additions & 1 deletion src/ethereum/forks/amsterdam/transactions.py
Original file line number Diff line number Diff line change
Expand Up @@ -871,7 +871,10 @@ def chain_id(tx: Transaction) -> None | U64:
if tx.v < U256(35):
raise InvalidSignatureError("bad v")

return U64((tx.v - U256(35)) >> U256(1))
tx_chain_id = (tx.v - U256(35)) >> U256(1)
if tx_chain_id > U256(U64.MAX_VALUE):
raise InvalidSignatureError("bad v")
return U64(tx_chain_id)
else:
return tx.chain_id

Expand Down
5 changes: 4 additions & 1 deletion src/ethereum/forks/arrow_glacier/transactions.py
Original file line number Diff line number Diff line change
Expand Up @@ -397,7 +397,10 @@ def chain_id(tx: Transaction) -> None | U64:
if tx.v < U256(35):
raise InvalidSignatureError("bad v")

return U64((tx.v - U256(35)) >> U256(1))
tx_chain_id = (tx.v - U256(35)) >> U256(1)
if tx_chain_id > U256(U64.MAX_VALUE):
raise InvalidSignatureError("bad v")
return U64(tx_chain_id)
else:
return tx.chain_id

Expand Down
5 changes: 4 additions & 1 deletion src/ethereum/forks/berlin/transactions.py
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,10 @@ def chain_id(tx: Transaction) -> None | U64:
if tx.v < U256(35):
raise InvalidSignatureError("bad v")

return U64((tx.v - U256(35)) >> U256(1))
tx_chain_id = (tx.v - U256(35)) >> U256(1)
if tx_chain_id > U256(U64.MAX_VALUE):
raise InvalidSignatureError("bad v")
return U64(tx_chain_id)
else:
return tx.chain_id

Expand Down
5 changes: 4 additions & 1 deletion src/ethereum/forks/bogota/transactions.py
Original file line number Diff line number Diff line change
Expand Up @@ -871,7 +871,10 @@ def chain_id(tx: Transaction) -> None | U64:
if tx.v < U256(35):
raise InvalidSignatureError("bad v")

return U64((tx.v - U256(35)) >> U256(1))
tx_chain_id = (tx.v - U256(35)) >> U256(1)
if tx_chain_id > U256(U64.MAX_VALUE):
raise InvalidSignatureError("bad v")
return U64(tx_chain_id)
else:
return tx.chain_id

Expand Down
5 changes: 4 additions & 1 deletion src/ethereum/forks/bpo1/transactions.py
Original file line number Diff line number Diff line change
Expand Up @@ -674,7 +674,10 @@ def chain_id(tx: Transaction) -> None | U64:
if tx.v < U256(35):
raise InvalidSignatureError("bad v")

return U64((tx.v - U256(35)) >> U256(1))
tx_chain_id = (tx.v - U256(35)) >> U256(1)
if tx_chain_id > U256(U64.MAX_VALUE):
raise InvalidSignatureError("bad v")
return U64(tx_chain_id)
else:
return tx.chain_id

Expand Down
5 changes: 4 additions & 1 deletion src/ethereum/forks/bpo2/transactions.py
Original file line number Diff line number Diff line change
Expand Up @@ -674,7 +674,10 @@ def chain_id(tx: Transaction) -> None | U64:
if tx.v < U256(35):
raise InvalidSignatureError("bad v")

return U64((tx.v - U256(35)) >> U256(1))
tx_chain_id = (tx.v - U256(35)) >> U256(1)
if tx_chain_id > U256(U64.MAX_VALUE):
raise InvalidSignatureError("bad v")
return U64(tx_chain_id)
else:
return tx.chain_id

Expand Down
5 changes: 4 additions & 1 deletion src/ethereum/forks/bpo3/transactions.py
Original file line number Diff line number Diff line change
Expand Up @@ -674,7 +674,10 @@ def chain_id(tx: Transaction) -> None | U64:
if tx.v < U256(35):
raise InvalidSignatureError("bad v")

return U64((tx.v - U256(35)) >> U256(1))
tx_chain_id = (tx.v - U256(35)) >> U256(1)
if tx_chain_id > U256(U64.MAX_VALUE):
raise InvalidSignatureError("bad v")
return U64(tx_chain_id)
else:
return tx.chain_id

Expand Down
5 changes: 4 additions & 1 deletion src/ethereum/forks/bpo4/transactions.py
Original file line number Diff line number Diff line change
Expand Up @@ -674,7 +674,10 @@ def chain_id(tx: Transaction) -> None | U64:
if tx.v < U256(35):
raise InvalidSignatureError("bad v")

return U64((tx.v - U256(35)) >> U256(1))
tx_chain_id = (tx.v - U256(35)) >> U256(1)
if tx_chain_id > U256(U64.MAX_VALUE):
raise InvalidSignatureError("bad v")
return U64(tx_chain_id)
else:
return tx.chain_id

Expand Down
5 changes: 4 additions & 1 deletion src/ethereum/forks/bpo5/transactions.py
Original file line number Diff line number Diff line change
Expand Up @@ -674,7 +674,10 @@ def chain_id(tx: Transaction) -> None | U64:
if tx.v < U256(35):
raise InvalidSignatureError("bad v")

return U64((tx.v - U256(35)) >> U256(1))
tx_chain_id = (tx.v - U256(35)) >> U256(1)
if tx_chain_id > U256(U64.MAX_VALUE):
raise InvalidSignatureError("bad v")
return U64(tx_chain_id)
else:
return tx.chain_id

Expand Down
5 changes: 4 additions & 1 deletion src/ethereum/forks/byzantium/transactions.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,10 @@ def chain_id(tx: Transaction) -> None | U64:
return None
if tx.v < U256(35):
raise InvalidSignatureError("bad v")
return U64((tx.v - U256(35)) >> U256(1))
tx_chain_id = (tx.v - U256(35)) >> U256(1)
if tx_chain_id > U256(U64.MAX_VALUE):
raise InvalidSignatureError("bad v")
return U64(tx_chain_id)


def recover_sender(tx: Transaction) -> Address:
Expand Down
5 changes: 4 additions & 1 deletion src/ethereum/forks/cancun/transactions.py
Original file line number Diff line number Diff line change
Expand Up @@ -524,7 +524,10 @@ def chain_id(tx: Transaction) -> None | U64:
if tx.v < U256(35):
raise InvalidSignatureError("bad v")

return U64((tx.v - U256(35)) >> U256(1))
tx_chain_id = (tx.v - U256(35)) >> U256(1)
if tx_chain_id > U256(U64.MAX_VALUE):
raise InvalidSignatureError("bad v")
return U64(tx_chain_id)
else:
return tx.chain_id

Expand Down
5 changes: 4 additions & 1 deletion src/ethereum/forks/constantinople/transactions.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,10 @@ def chain_id(tx: Transaction) -> None | U64:
return None
if tx.v < U256(35):
raise InvalidSignatureError("bad v")
return U64((tx.v - U256(35)) >> U256(1))
tx_chain_id = (tx.v - U256(35)) >> U256(1)
if tx_chain_id > U256(U64.MAX_VALUE):
raise InvalidSignatureError("bad v")
return U64(tx_chain_id)


def recover_sender(tx: Transaction) -> Address:
Expand Down
5 changes: 4 additions & 1 deletion src/ethereum/forks/gray_glacier/transactions.py
Original file line number Diff line number Diff line change
Expand Up @@ -397,7 +397,10 @@ def chain_id(tx: Transaction) -> None | U64:
if tx.v < U256(35):
raise InvalidSignatureError("bad v")

return U64((tx.v - U256(35)) >> U256(1))
tx_chain_id = (tx.v - U256(35)) >> U256(1)
if tx_chain_id > U256(U64.MAX_VALUE):
raise InvalidSignatureError("bad v")
return U64(tx_chain_id)
else:
return tx.chain_id

Expand Down
5 changes: 4 additions & 1 deletion src/ethereum/forks/istanbul/transactions.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,10 @@ def chain_id(tx: Transaction) -> None | U64:
return None
if tx.v < U256(35):
raise InvalidSignatureError("bad v")
return U64((tx.v - U256(35)) >> U256(1))
tx_chain_id = (tx.v - U256(35)) >> U256(1)
if tx_chain_id > U256(U64.MAX_VALUE):
raise InvalidSignatureError("bad v")
return U64(tx_chain_id)


def recover_sender(tx: Transaction) -> Address:
Expand Down
5 changes: 4 additions & 1 deletion src/ethereum/forks/london/transactions.py
Original file line number Diff line number Diff line change
Expand Up @@ -397,7 +397,10 @@ def chain_id(tx: Transaction) -> None | U64:
if tx.v < U256(35):
raise InvalidSignatureError("bad v")

return U64((tx.v - U256(35)) >> U256(1))
tx_chain_id = (tx.v - U256(35)) >> U256(1)
if tx_chain_id > U256(U64.MAX_VALUE):
raise InvalidSignatureError("bad v")
return U64(tx_chain_id)
else:
return tx.chain_id

Expand Down
5 changes: 4 additions & 1 deletion src/ethereum/forks/muir_glacier/transactions.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,10 @@ def chain_id(tx: Transaction) -> None | U64:
return None
if tx.v < U256(35):
raise InvalidSignatureError("bad v")
return U64((tx.v - U256(35)) >> U256(1))
tx_chain_id = (tx.v - U256(35)) >> U256(1)
if tx_chain_id > U256(U64.MAX_VALUE):
raise InvalidSignatureError("bad v")
return U64(tx_chain_id)


def recover_sender(tx: Transaction) -> Address:
Expand Down
5 changes: 4 additions & 1 deletion src/ethereum/forks/osaka/transactions.py
Original file line number Diff line number Diff line change
Expand Up @@ -674,7 +674,10 @@ def chain_id(tx: Transaction) -> None | U64:
if tx.v < U256(35):
raise InvalidSignatureError("bad v")

return U64((tx.v - U256(35)) >> U256(1))
tx_chain_id = (tx.v - U256(35)) >> U256(1)
if tx_chain_id > U256(U64.MAX_VALUE):
raise InvalidSignatureError("bad v")
return U64(tx_chain_id)
else:
return tx.chain_id

Expand Down
5 changes: 4 additions & 1 deletion src/ethereum/forks/paris/transactions.py
Original file line number Diff line number Diff line change
Expand Up @@ -397,7 +397,10 @@ def chain_id(tx: Transaction) -> None | U64:
if tx.v < U256(35):
raise InvalidSignatureError("bad v")

return U64((tx.v - U256(35)) >> U256(1))
tx_chain_id = (tx.v - U256(35)) >> U256(1)
if tx_chain_id > U256(U64.MAX_VALUE):
raise InvalidSignatureError("bad v")
return U64(tx_chain_id)
else:
return tx.chain_id

Expand Down
5 changes: 4 additions & 1 deletion src/ethereum/forks/prague/transactions.py
Original file line number Diff line number Diff line change
Expand Up @@ -670,7 +670,10 @@ def chain_id(tx: Transaction) -> None | U64:
if tx.v < U256(35):
raise InvalidSignatureError("bad v")

return U64((tx.v - U256(35)) >> U256(1))
tx_chain_id = (tx.v - U256(35)) >> U256(1)
if tx_chain_id > U256(U64.MAX_VALUE):
raise InvalidSignatureError("bad v")
return U64(tx_chain_id)
else:
return tx.chain_id

Expand Down
5 changes: 4 additions & 1 deletion src/ethereum/forks/shanghai/transactions.py
Original file line number Diff line number Diff line change
Expand Up @@ -410,7 +410,10 @@ def chain_id(tx: Transaction) -> None | U64:
if tx.v < U256(35):
raise InvalidSignatureError("bad v")

return U64((tx.v - U256(35)) >> U256(1))
tx_chain_id = (tx.v - U256(35)) >> U256(1)
if tx_chain_id > U256(U64.MAX_VALUE):
raise InvalidSignatureError("bad v")
return U64(tx_chain_id)
else:
return tx.chain_id

Expand Down
5 changes: 4 additions & 1 deletion src/ethereum/forks/spurious_dragon/transactions.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,10 @@ def chain_id(tx: Transaction) -> None | U64:
return None
if tx.v < U256(35):
raise InvalidSignatureError("bad v")
return U64((tx.v - U256(35)) >> U256(1))
tx_chain_id = (tx.v - U256(35)) >> U256(1)
if tx_chain_id > U256(U64.MAX_VALUE):
raise InvalidSignatureError("bad v")
return U64(tx_chain_id)


def recover_sender(tx: Transaction) -> Address:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
"""
Tests for [EIP-155: Simple replay attack
protection](https://eips.ethereum.org/EIPS/eip-155).
"""
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
"""Defines EIP-155 specification constants and functions."""

from dataclasses import dataclass


@dataclass(frozen=True)
class ReferenceSpec:
"""Defines the reference spec version and git path."""

git_path: str
version: str


ref_spec_155 = ReferenceSpec(
"EIPS/eip-155.md", "17024fa653e75d93f895632e96b20766569cebbd"
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
"""Tests for the chain ID a legacy transaction encodes in its v value."""

import pytest
from execution_testing import (
Account,
Alloc,
ChainConfig,
Fork,
StateTestFiller,
Transaction,
TransactionException,
)

from .spec import ref_spec_155

REFERENCE_SPEC_GIT_PATH = ref_spec_155.git_path
REFERENCE_SPEC_VERSION = ref_spec_155.version


@pytest.mark.inclusion_test
@pytest.mark.valid_from("SpuriousDragon")
@pytest.mark.exception_test
@pytest.mark.eels_base_coverage
@pytest.mark.parametrize(
"case",
[
"largest_64_bit_chain_id",
"smallest_65_bit_chain_id",
"chain_id_plus_2_64",
],
)
def test_legacy_chain_id_over_64_bits(
state_test: StateTestFiller,
pre: Alloc,
fork: Fork,
chain_config: ChainConfig,
case: str,
) -> None:
"""
A legacy transaction whose v encodes a chain ID too large for 64 bits has
an invalid v, while one that fits is only a chain ID mismatch.
"""
if case == "largest_64_bit_chain_id":
signed_for = encoded_in_v = 2**64 - 1
error = TransactionException.INVALID_CHAINID
elif case == "smallest_65_bit_chain_id":
signed_for = encoded_in_v = 2**64
error = TransactionException.INVALID_SIGNATURE_VRS
elif case == "chain_id_plus_2_64":
signed_for = chain_config.chain_id
encoded_in_v = chain_config.chain_id + 2**64
error = TransactionException.INVALID_SIGNATURE_VRS
else:
raise ValueError(f"Unknown case: {case}")

to = pre.fund_eoa(0xDEADBEEE)
tx = Transaction(
sender=pre.fund_eoa(),
to=to,
value=1,
chain_id=signed_for,
# Signing up front needs the final gas limit.
gas_limit=fork.transaction_intrinsic_cost_calculator()(),
).with_signature_and_sender()
tx = tx.copy(
# EIP-155: v = 35 + 2 * chain_id + parity.
v=tx.v + 2 * (encoded_in_v - signed_for),
error=error,
)

state_test(
pre=pre,
post={to: Account(balance=0xDEADBEEE)},
tx=tx,
)
Loading