Skip to content

Commit

Permalink
fix(tests): EIP-7623 update due to spec change (#1071)
Browse files Browse the repository at this point in the history
* fix(tests): EIP-7623 update due to spec change

* Add comments
  • Loading branch information
marioevz authored Jan 23, 2025
1 parent 4891ac7 commit 4a77afb
Show file tree
Hide file tree
Showing 4 changed files with 340 additions and 169 deletions.
2 changes: 1 addition & 1 deletion docs/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ Release tarball changes:
-[EIP-7702](https://eips.ethereum.org/EIPS/eip-7702) set code of non-empty-storage account test ([#948](https://github.com/ethereum/execution-spec-tests/pull/948))
-[EIP-7702](https://eips.ethereum.org/EIPS/eip-7702) Remove delegation behavior of EXTCODE* ([#984](https://github.com/ethereum/execution-spec-tests/pull/984))
-[EIP-7702](https://eips.ethereum.org/EIPS/eip-7702) implement 7702 test ideas ([#981](https://github.com/ethereum/execution-spec-tests/pull/981))
-[EIP-7623](https://eips.ethereum.org/EIPS/eip-7623) Increase calldata cost ([#1004](https://github.com/ethereum/execution-spec-tests/pull/1004))
-[EIP-7623](https://eips.ethereum.org/EIPS/eip-7623) Increase calldata cost ([#1004](https://github.com/ethereum/execution-spec-tests/pull/1004), [#1071](https://github.com/ethereum/execution-spec-tests/pull/1071))
- ✨ Add generic precompile-absence test ([#1036](https://github.com/ethereum/execution-spec-tests/pull/1036))
- ✨ Add test for [EIP-2537](https://eips.ethereum.org/EIPS/eip-2537) which uses the full discount table of G2 MSM ([#1038](https://github.com/ethereum/execution-spec-tests/pull/1038))
- 🔀 Update EIP-7251 according to [spec updates](https://github.com/ethereum/EIPs/pull/9127) ([#1024](https://github.com/ethereum/execution-spec-tests/pull/1024)).
Expand Down
33 changes: 29 additions & 4 deletions tests/prague/eip7623_increase_calldata_cost/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,30 @@ def tx_gas_delta() -> int:


@pytest.fixture
def tx_intrinsic_gas_cost(
def tx_intrinsic_gas_cost_before_execution(
fork: Fork,
tx_data: Bytes,
access_list: List[AccessList] | None,
authorization_list: List[AuthorizationTuple] | None,
contract_creating_tx: bool,
) -> int:
"""
Return the intrinsic gas cost that is applied before the execution start.
This value never includes the floor data gas cost.
"""
intrinsic_gas_cost_calculator = fork.transaction_intrinsic_cost_calculator()
return intrinsic_gas_cost_calculator(
calldata=tx_data,
contract_creation=contract_creating_tx,
access_list=access_list,
authorization_list_or_count=authorization_list,
return_cost_deducted_prior_execution=True,
)


@pytest.fixture
def tx_intrinsic_gas_cost_including_floor_data_cost(
fork: Fork,
tx_data: Bytes,
access_list: List[AccessList] | None,
Expand All @@ -242,7 +265,9 @@ def tx_intrinsic_gas_cost(
Transaction intrinsic gas cost.
The calculated value takes into account the normal intrinsic gas cost and the floor data gas
cost.
cost if it is greater than the intrinsic gas cost.
In other words, this is the value that is required for the transaction to be valid.
"""
intrinsic_gas_cost_calculator = fork.transaction_intrinsic_cost_calculator()
return intrinsic_gas_cost_calculator(
Expand All @@ -265,15 +290,15 @@ def tx_floor_data_cost(

@pytest.fixture
def tx_gas_limit(
tx_intrinsic_gas_cost: int,
tx_intrinsic_gas_cost_including_floor_data_cost: int,
tx_gas_delta: int,
) -> int:
"""
Gas limit for the transaction.
The gas delta is added to the intrinsic gas cost to generate different test scenarios.
"""
return tx_intrinsic_gas_cost + tx_gas_delta
return tx_intrinsic_gas_cost_including_floor_data_cost + tx_gas_delta


@pytest.fixture
Expand Down
178 changes: 14 additions & 164 deletions tests/prague/eip7623_increase_calldata_cost/test_execution_gas.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,98 +38,8 @@ def data_test_type() -> DataTestType:

@pytest.fixture
def authorization_refund() -> bool:
"""
Force the authority of the authorization tuple to be an existing authority in order
to produce a refund.
"""
return True


class TestGasRefunds:
"""Test gas refunds with EIP-7623 active."""

@pytest.fixture
def intrinsic_gas_data_floor_minimum_delta(self) -> int:
"""
In this test we reset a storage key to zero to induce a refund,
but we need to make sure that the floor is higher than the gas
used during execution in order for the refund to be applied to
the floor.
"""
return 50_000

@pytest.fixture
def to(
self,
pre: Alloc,
) -> Address | None:
"""Return a contract that when executed results in refunds due to storage clearing."""
return pre.deploy_contract(Op.SSTORE(0, 0) + Op.STOP, storage={0: 1})

@pytest.fixture
def refund(self, fork: Fork, ty: int) -> int:
"""Return the refund gas of the transaction."""
gas_costs = fork.gas_costs()
refund = gas_costs.R_STORAGE_CLEAR
if ty == 4:
refund += gas_costs.R_AUTHORIZATION_EXISTING_AUTHORITY
return refund

@pytest.mark.parametrize(
"ty,protected,authorization_list",
[
pytest.param(0, False, None, id="type_0_unprotected"),
pytest.param(0, True, None, id="type_0_protected"),
pytest.param(1, True, None, id="type_1"),
pytest.param(2, True, None, id="type_2"),
pytest.param(
3,
True,
None,
id="type_3",
),
pytest.param(
4,
True,
[Address(1)],
id="type_4_with_authorization_refund",
),
],
indirect=["authorization_list"],
)
@pytest.mark.parametrize(
"tx_gas_delta",
[
# Test with exact gas and extra gas, to verify that the refund is correctly applied up
# to the floor data cost.
pytest.param(1, id="extra_gas"),
pytest.param(0, id="exact_gas"),
],
)
def test_gas_refunds_from_data_floor(
self,
state_test: StateTestFiller,
pre: Alloc,
tx: Transaction,
tx_floor_data_cost: int,
refund: int,
) -> None:
"""
Test gas refunds deducted from the data floor.
I.e. the used gas by the intrinsic gas cost plus the execution cost is less than the data
floor, hence data floor is used, and then the gas refunds are applied to the data floor.
"""
tx.expected_receipt = TransactionReceipt(gas_used=tx_floor_data_cost - refund)
state_test(
pre=pre,
post={
tx.to: {
"storage": {0: 0}, # Verify storage was cleared
}
},
tx=tx,
)
"""Disable the refunds on these tests (see ./test_refunds.py)."""
return False


class TestGasConsumption:
Expand All @@ -148,47 +58,22 @@ def to(
"""Return a contract that consumes all gas when executed by calling an invalid opcode."""
return pre.deploy_contract(Op.INVALID)

@pytest.fixture
def refund(
self,
fork: Fork,
ty: int,
authorization_refund: bool,
) -> int:
"""Return the refund gas of the transaction."""
gas_costs = fork.gas_costs()
refund = 0
if ty == 4 and authorization_refund:
refund += gas_costs.R_AUTHORIZATION_EXISTING_AUTHORITY
return refund

@pytest.mark.parametrize(
"ty,protected,authorization_list",
[
pytest.param(0, False, None, id="type_0_unprotected"),
pytest.param(0, True, None, id="type_0_protected"),
pytest.param(1, True, None, id="type_1"),
pytest.param(2, True, None, id="type_2"),
pytest.param(
3,
True,
None,
id="type_3",
),
pytest.param(
4,
True,
[Address(1)],
id="type_4_with_authorization_refund",
),
pytest.param(3, True, None, id="type_3"),
pytest.param(4, True, [Address(1)], id="type_4"),
],
indirect=["authorization_list"],
)
@pytest.mark.parametrize(
"tx_gas_delta",
[
# Test with exact gas and extra gas, to verify that the refund is correctly applied
# to the full consumed execution gas.
# Test with exact gas and extra gas.
pytest.param(1, id="extra_gas"),
pytest.param(0, id="exact_gas"),
],
Expand All @@ -198,10 +83,9 @@ def test_full_gas_consumption(
state_test: StateTestFiller,
pre: Alloc,
tx: Transaction,
refund: int,
) -> None:
"""Test executing a transaction that fully consumes its execution gas allocation."""
tx.expected_receipt = TransactionReceipt(gas_used=tx.gas_limit - refund)
tx.expected_receipt = TransactionReceipt(gas_used=tx.gas_limit)
state_test(
pre=pre,
post={},
Expand All @@ -217,20 +101,6 @@ def contract_creating_tx(self) -> bool:
"""Use a constant in order to avoid circular fixture dependencies."""
return False

@pytest.fixture
def refund(
self,
fork: Fork,
ty: int,
authorization_refund: bool,
) -> int:
"""Return the refund gas of the transaction."""
gas_costs = fork.gas_costs()
refund = 0
if ty == 4 and authorization_refund:
refund += gas_costs.R_AUTHORIZATION_EXISTING_AUTHORITY
return refund

@pytest.fixture
def to(
self,
Expand Down Expand Up @@ -258,33 +128,14 @@ def to(
return pre.deploy_contract((Op.JUMPDEST * (execution_gas - 1)) + Op.STOP)

@pytest.mark.parametrize(
"ty,protected,authorization_list,authorization_refund",
"ty,protected,authorization_list",
[
pytest.param(0, False, None, False, id="type_0_unprotected"),
pytest.param(0, True, None, False, id="type_0_protected"),
pytest.param(1, True, None, False, id="type_1"),
pytest.param(2, True, None, False, id="type_2"),
pytest.param(
3,
True,
None,
False,
id="type_3",
),
pytest.param(
4,
True,
[Address(1)],
False,
id="type_4",
),
pytest.param(
4,
True,
[Address(1)],
True,
id="type_4_with_authorization_refund",
),
pytest.param(0, False, None, id="type_0_unprotected"),
pytest.param(0, True, None, id="type_0_protected"),
pytest.param(1, True, None, id="type_1"),
pytest.param(2, True, None, id="type_2"),
pytest.param(3, True, None, id="type_3"),
pytest.param(4, True, [Address(1)], id="type_4"),
],
indirect=["authorization_list"],
)
Expand All @@ -302,10 +153,9 @@ def test_gas_consumption_below_data_floor(
pre: Alloc,
tx: Transaction,
tx_floor_data_cost: int,
refund: int,
) -> None:
"""Test executing a transaction that almost consumes the floor data cost."""
tx.expected_receipt = TransactionReceipt(gas_used=tx_floor_data_cost - refund)
tx.expected_receipt = TransactionReceipt(gas_used=tx_floor_data_cost)
state_test(
pre=pre,
post={},
Expand Down
Loading

0 comments on commit 4a77afb

Please sign in to comment.