Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 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 @@ -7,6 +7,7 @@

from execution_testing.base_types import Address, Alloc, Hash
from execution_testing.forks import Fork
from execution_testing.logging import get_logger
from execution_testing.rpc import (
EngineRPC,
EthRPC,
Expand All @@ -19,6 +20,8 @@

from .base import BaseExecute

logger = get_logger(__name__)


class TransactionPost(BaseExecute):
"""
Expand Down Expand Up @@ -86,8 +89,17 @@ def execute(
eth_rpc.send_wait_transaction(transaction)
all_tx_hashes.append(transaction.hash)
else:
with pytest.raises(SendTransactionExceptionError):
logger.info(
f"Sending transaction expecting rejection "
f"(expected error: {transaction.error})..."
)
with pytest.raises(
SendTransactionExceptionError
) as exc_info:
eth_rpc.send_transaction(transaction)
logger.info(
f"Transaction rejected as expected: {exc_info.value}"
)
else:
eth_rpc.send_wait_transactions(signed_txs)
all_tx_hashes.extend([tx.hash for tx in signed_txs])
Expand Down
10 changes: 9 additions & 1 deletion tests/byzantium/eip198_modexp_precompile/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,10 +155,18 @@ class ModExpOutput(TestParameterGroup):
call_success (bool): The return_code from CALL, 0 indicates
unsuccessful call (out-of-gas), 1 indicates call
succeeded.
returned_data(str): The output returnData is the expected
returned_data (Bytes): The output returnData is the expected
output of the call.

"""

call_success: bool = True
returned_data: Bytes

def __len__(self) -> int:
"""Return the length of the returned data."""
return len(self.returned_data)

def __bytes__(self) -> bytes:
"""Return the returned data as bytes."""
return bytes(self.returned_data)
1 change: 1 addition & 0 deletions tests/osaka/eip7823_modexp_upper_bounds/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,7 @@ def tx(
) -> Transaction:
"""Transaction to measure gas consumption of the ModExp precompile."""
return Transaction(
ty=0x02,
sender=pre.fund_eoa(),
to=gas_measure_contract,
data=bytes(modexp_input),
Expand Down
96 changes: 96 additions & 0 deletions tests/osaka/eip7823_modexp_upper_bounds/test_eip_mainnet.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
"""
Mainnet marked execute checklist tests for
[EIP-7823: ModExp Upper Bound](https://eips.ethereum.org/EIPS/eip-7823).
"""

from typing import Dict

import pytest
from execution_testing import (
Alloc,
StateTestFiller,
Transaction,
)

from ...byzantium.eip198_modexp_precompile.helpers import (
ModExpInput,
ModExpOutput,
)
from ..eip7883_modexp_gas_increase.spec import Spec
from .spec import ref_spec_7823

REFERENCE_SPEC_GIT_PATH = ref_spec_7823.git_path
REFERENCE_SPEC_VERSION = ref_spec_7823.version

pytestmark = [pytest.mark.valid_at("Osaka"), pytest.mark.mainnet]


@pytest.fixture
def call_succeeds(modexp_expected: ModExpOutput) -> bool:
"""Override `call_succeeds` to use the parametrized ModExpOutput value."""
return modexp_expected.call_success


@pytest.mark.parametrize(
"modexp_input,modexp_expected",
[
pytest.param(
ModExpInput(
base=b"\x01" * Spec.MAX_LENGTH_BYTES,
exponent=b"\x00",
modulus=b"\x02",
),
ModExpOutput(
call_success=True,
returned_data="0x01",
),
id="base-boundary-1024-bytes",
),
],
)
def test_modexp_boundary(
state_test: StateTestFiller,
pre: Alloc,
tx: Transaction,
post: Dict,
) -> None:
"""
Mainnet test at the 1024-byte boundary.

Tests that the ModExp precompile correctly handles input at the maximum
allowed length (1024 bytes) per EIP-7823.
"""
state_test(pre=pre, tx=tx, post=post)


@pytest.mark.parametrize(
"modexp_input,modexp_expected",
[
pytest.param(
ModExpInput(
base=b"\x01" * (Spec.MAX_LENGTH_BYTES + 1),
exponent=b"\x00",
modulus=b"\x02",
),
ModExpOutput(
call_success=False,
returned_data="",
),
id="base-over-boundary-1025-bytes",
),
],
)
def test_modexp_over_boundary(
state_test: StateTestFiller,
pre: Alloc,
tx: Transaction,
post: Dict,
) -> None:
"""
Mainnet test exceeding the 1024-byte boundary.

Tests that the ModExp precompile correctly rejects input exceeding the
maximum allowed length (1024 bytes) per EIP-7823. This proves the EIP
is correctly activated.
"""
state_test(pre=pre, tx=tx, post=post)
67 changes: 67 additions & 0 deletions tests/osaka/eip7825_transaction_gas_limit_cap/test_eip_mainnet.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
"""
Mainnet marked execute checklist tests for
[EIP-7825: Transaction Gas Limit Cap](https://eips.ethereum.org/EIPS/eip-7825).
"""

import pytest
from execution_testing import (
Account,
Alloc,
Op,
StateTestFiller,
Storage,
Transaction,
TransactionException,
)

from .spec import Spec, ref_spec_7825

REFERENCE_SPEC_GIT_PATH = ref_spec_7825.git_path
REFERENCE_SPEC_VERSION = ref_spec_7825.version

pytestmark = [pytest.mark.valid_at("Osaka"), pytest.mark.mainnet]


def test_tx_gas_limit_cap_at_maximum(
state_test: StateTestFiller,
pre: Alloc,
) -> None:
"""Test transaction at exactly the gas limit cap (2^24)."""
storage = Storage()
contract_address = pre.deploy_contract(
code=Op.SSTORE(storage.store_next(1), 1) + Op.STOP,
)

tx = Transaction(
ty=0x02,
to=contract_address,
sender=pre.fund_eoa(),
gas_limit=Spec.tx_gas_limit_cap,
)

post = {
contract_address: Account(storage=storage),
}

state_test(pre=pre, post=post, tx=tx)


@pytest.mark.exception_test
def test_tx_gas_limit_cap_exceeded(
state_test: StateTestFiller,
pre: Alloc,
) -> None:
"""Test transaction exceeding the gas limit cap (2^24 + 1)."""
contract_address = pre.deploy_contract(
code=Op.SSTORE(0, 1) + Op.STOP,
)

tx = Transaction(
ty=0x02,
to=contract_address,
sender=pre.fund_eoa(),
gas_limit=Spec.tx_gas_limit_cap + 1,
error=TransactionException.GAS_LIMIT_EXCEEDS_MAXIMUM,
)

state_test(pre=pre, post={}, tx=tx)
1 change: 1 addition & 0 deletions tests/osaka/eip7883_modexp_gas_increase/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,7 @@ def tx(
) -> Transaction:
"""Transaction to measure gas consumption of the ModExp precompile."""
return Transaction(
ty=0x02,
sender=pre.fund_eoa(),
to=gas_measure_contract,
data=bytes(modexp_input),
Expand Down
51 changes: 33 additions & 18 deletions tests/osaka/eip7883_modexp_gas_increase/test_eip_mainnet.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
"""
Mainnet marked tests for EIP-7883 ModExp gas cost increase.

Tests for ModExp gas cost increase in
Mainnet marked execute checklist tests for
[EIP-7883: ModExp Gas Cost Increase](https://eips.ethereum.org/EIPS/eip-7883).
"""

Expand All @@ -14,7 +12,10 @@
Transaction,
)

from ...byzantium.eip198_modexp_precompile.helpers import ModExpInput
from ...byzantium.eip198_modexp_precompile.helpers import (
ModExpInput,
ModExpOutput,
)
from .spec import Spec, ref_spec_7883

REFERENCE_SPEC_GIT_PATH = ref_spec_7883.git_path
Expand All @@ -23,6 +24,12 @@
pytestmark = [pytest.mark.valid_at("Osaka"), pytest.mark.mainnet]


@pytest.fixture
def call_succeeds(modexp_expected: ModExpOutput) -> bool:
"""Override `call_succeeds` to use the parametrized ModExpOutput value."""
return modexp_expected.call_success


@pytest.mark.parametrize(
"modexp_input,modexp_expected",
[
Expand All @@ -35,8 +42,10 @@
declared_exponent_length=1,
declared_modulus_length=1,
),
# expected result:
bytes.fromhex("04"),
ModExpOutput(
call_success=True,
returned_data="0x04",
),
id="32-bytes-long-base",
),
pytest.param(
Expand All @@ -48,8 +57,10 @@
declared_exponent_length=1,
declared_modulus_length=1,
),
# expected result:
bytes.fromhex("01"),
ModExpOutput(
call_success=True,
returned_data="0x01",
),
id="33-bytes-long-base", # higher cost than 32 bytes
),
pytest.param(
Expand All @@ -61,8 +72,10 @@
declared_exponent_length=1024,
declared_modulus_length=1,
),
# expected result:
bytes.fromhex("02"),
ModExpOutput(
call_success=True,
returned_data="0x02",
),
id="1024-bytes-long-exp",
),
pytest.param(
Expand All @@ -74,9 +87,11 @@
declared_exponent_length=3,
declared_modulus_length=64,
),
# expected result:
bytes.fromhex(
"c36d804180c35d4426b57b50c5bfcca5c01856d104564cd513b461d3c8b8409128a5573e416d0ebe38f5f736766d9dc27143e4da981dfa4d67f7dc474cbee6d2"
ModExpOutput(
call_success=True,
returned_data=(
"0xc36d804180c35d4426b57b50c5bfcca5c01856d104564cd513b461d3c8b8409128a5573e416d0ebe38f5f736766d9dc27143e4da981dfa4d67f7dc474cbee6d2"
),
),
id="nagydani-1-pow0x10001",
),
Expand All @@ -89,9 +104,11 @@
declared_exponent_length=64,
declared_modulus_length=32,
),
# expected result:
bytes.fromhex(
"0000000000000000000000000000000000000000000000000000000000000001"
ModExpOutput(
call_success=True,
returned_data=(
"0x0000000000000000000000000000000000000000000000000000000000000001"
),
),
id="zero-exponent-64bytes",
),
Expand All @@ -102,8 +119,6 @@ def test_modexp_different_base_lengths(
pre: Alloc,
tx: Transaction,
post: Dict,
modexp_input: ModExpInput,
modexp_expected: ModExpInput,
) -> None:
"""Mainnet test for triggering gas cost increase."""
state_test(pre=pre, tx=tx, post=post)
Loading
Loading