Skip to content

Commit 6431581

Browse files
committed
new(tests): EOF - EIP-7069 - expand ext*call gas testing
1 parent d3d3219 commit 6431581

File tree

4 files changed

+98
-33
lines changed

4 files changed

+98
-33
lines changed

tests/prague/eip7692_eof_v1/eip7069_extcall/helpers.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818
slot_calldata_2 = next(_slot)
1919
slot_cold_gas = next(_slot)
2020
slot_warm_gas = next(_slot)
21+
slot_oog_call_result = next(_slot)
22+
slot_sanity_call_result = next(_slot)
2123

2224
slot_last_slot = next(_slot)
2325

@@ -26,6 +28,8 @@
2628

2729
"""Storage values for common testing fields"""
2830
value_code_worked = 0x2015
31+
value_call_legacy_abort = 0
32+
value_call_legacy_success = 1
2933

3034
"""Memory and storage value for calldata"""
3135
value_calldata_1 = 0xC1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1C1

tests/prague/eip7692_eof_v1/eip7069_extcall/test_gas.py

Lines changed: 84 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,20 @@
66
import pytest
77

88
from ethereum_test_tools import Account, Alloc, Environment, StateTestFiller, Transaction
9-
from ethereum_test_tools.eof.v1 import Container, Section
9+
from ethereum_test_tools.eof.v1 import Container
1010
from ethereum_test_tools.vm.opcode import Opcodes as Op
1111
from ethereum_test_vm import Bytecode, EVMCodeType
1212

1313
from .. import EOF_FORK_NAME
1414
from . import REFERENCE_SPEC_GIT_PATH, REFERENCE_SPEC_VERSION
15-
from .helpers import slot_cold_gas, slot_warm_gas
15+
from .helpers import (
16+
slot_cold_gas,
17+
slot_oog_call_result,
18+
slot_sanity_call_result,
19+
slot_warm_gas,
20+
value_call_legacy_abort,
21+
value_call_legacy_success,
22+
)
1623

1724
REFERENCE_SPEC_GIT_PATH = REFERENCE_SPEC_GIT_PATH
1825
REFERENCE_SPEC_VERSION = REFERENCE_SPEC_VERSION
@@ -50,25 +57,29 @@ def gas_test(
5057

5158
sender = pre.fund_eoa(10**18)
5259

53-
address_baseline = pre.deploy_contract(setup_code + tear_down_code)
54-
address_subject = pre.deploy_contract(setup_code + subject_code + tear_down_code)
60+
address_baseline = pre.deploy_contract(Container.Code(setup_code + tear_down_code))
61+
address_subject = pre.deploy_contract(
62+
Container.Code(setup_code + subject_code + tear_down_code)
63+
)
64+
# GAS, POP, CALL, 7 times PUSH1 - instructions charged for at every gas run
65+
gas_single_gas_run = 2 + 2 + 100 + 7 * 3
5566
address_legacy_harness = pre.deploy_contract(
5667
code=(
5768
# warm subject and baseline without executing
5869
(Op.BALANCE(address_subject) + Op.POP + Op.BALANCE(address_baseline) + Op.POP)
59-
# cold gas run
70+
# Baseline gas run
6071
+ (
6172
Op.GAS
62-
+ Op.CALL(address=address_subject, gas=500_000)
73+
+ Op.CALL(address=address_baseline, gas=500_000)
6374
+ Op.POP
6475
+ Op.GAS
6576
+ Op.SWAP1
6677
+ Op.SUB
6778
)
68-
# Baseline gas run
79+
# cold gas run
6980
+ (
7081
Op.GAS
71-
+ Op.CALL(address=address_baseline, gas=500_000)
82+
+ Op.CALL(address=address_subject, gas=500_000)
7283
+ Op.POP
7384
+ Op.GAS
7485
+ Op.SWAP1
@@ -83,10 +94,30 @@ def gas_test(
8394
+ Op.SWAP1
8495
+ Op.SUB
8596
)
86-
# Store warm gas
87-
+ (Op.DUP2 + Op.SWAP1 + Op.SUB + Op.PUSH2(slot_warm_gas) + Op.SSTORE)
88-
# store cold gas
89-
+ (Op.SWAP1 + Op.SUB + Op.PUSH2(slot_cold_gas) + Op.SSTORE)
97+
# Store warm gas: DUP3 is the gas of the baseline gas run
98+
+ (Op.DUP3 + Op.SWAP1 + Op.SUB + Op.PUSH2(slot_warm_gas) + Op.SSTORE)
99+
# store cold gas: DUP2 is the gas of the baseline gas run
100+
+ (Op.DUP2 + Op.SWAP1 + Op.SUB + Op.PUSH2(slot_cold_gas) + Op.SSTORE)
101+
# oog gas run:
102+
# - DUP7 is the gas of the baseline gas run, after other CALL args were pushed
103+
# - subtract the gas charged by the harness
104+
# - add warm gas charged by the subject
105+
# - subtract 1 to cause OOG exception
106+
+ Op.SSTORE(
107+
slot_oog_call_result,
108+
Op.CALL(
109+
gas=Op.ADD(warm_gas - gas_single_gas_run - 1, Op.DUP7),
110+
address=address_subject,
111+
),
112+
)
113+
# sanity gas run: not subtracting 1 to see if enough gas makes the call succeed
114+
+ Op.SSTORE(
115+
slot_sanity_call_result,
116+
Op.CALL(
117+
gas=Op.ADD(warm_gas - gas_single_gas_run, Op.DUP7),
118+
address=address_subject,
119+
),
120+
)
90121
+ Op.STOP
91122
),
92123
evm_code_type=EVMCodeType.LEGACY, # Needs to be legacy to use GAS opcode
@@ -97,22 +128,46 @@ def gas_test(
97128
storage={
98129
slot_warm_gas: warm_gas,
99130
slot_cold_gas: cold_gas,
131+
slot_oog_call_result: value_call_legacy_abort,
132+
slot_sanity_call_result: value_call_legacy_success,
100133
},
101134
),
102135
}
103136

104-
tx = Transaction(to=address_legacy_harness, gas_limit=2_000_000, sender=sender)
137+
tx = Transaction(to=address_legacy_harness, gas_limit=20_000_000, sender=sender)
105138

106139
state_test(env=env, pre=pre, tx=tx, post=post)
107140

108141

109142
@pytest.mark.parametrize(
110-
["opcode", "pre_setup", "cold_gas", "warm_gas"],
143+
["opcode", "pre_setup", "cold_gas", "warm_gas", "new_account"],
111144
[
112-
pytest.param(Op.EXTCALL, Op.PUSH0, 2600, 100, id="EXTCALL"),
113-
pytest.param(Op.EXTCALL, Op.PUSH1(1), 2600 + 9000, 100 + 9000, id="EXTCALL_with_value"),
114-
pytest.param(Op.EXTDELEGATECALL, Op.NOOP, 2600, 100, id="EXTSTATICCALL"),
115-
pytest.param(Op.EXTSTATICCALL, Op.NOOP, 2600, 100, id="EXTDELEGATECALL"),
145+
pytest.param(Op.EXTCALL, Op.PUSH0, 2600, 100, False, id="EXTCALL"),
146+
pytest.param(
147+
Op.EXTCALL, Op.PUSH1(1), 2600 + 9000, 100 + 9000, False, id="EXTCALL_with_value"
148+
),
149+
pytest.param(Op.EXTDELEGATECALL, Op.NOOP, 2600, 100, False, id="EXTSTATICCALL"),
150+
pytest.param(Op.EXTSTATICCALL, Op.NOOP, 2600, 100, False, id="EXTDELEGATECALL"),
151+
pytest.param(Op.EXTCALL, Op.PUSH0, 2600, 100, True, id="EXTCALL_new_acc"),
152+
pytest.param(
153+
Op.EXTCALL,
154+
Op.PUSH1(1),
155+
2600 + 25000 + 9000,
156+
100 + 25000 + 9000,
157+
True,
158+
id="EXTCALL_with_value_new_acc",
159+
),
160+
pytest.param(Op.EXTDELEGATECALL, Op.NOOP, 2600, 100, True, id="EXTSTATICCALL_new_acc"),
161+
pytest.param(Op.EXTSTATICCALL, Op.NOOP, 2600, 100, True, id="EXTDELEGATECALL_new_acc"),
162+
],
163+
)
164+
@pytest.mark.parametrize(
165+
["mem_expansion_size", "mem_expansion_extra_gas"],
166+
[
167+
pytest.param(0, 0, id="no_mem_expansion"),
168+
pytest.param(1, 3, id="1byte_mem_expansion"),
169+
pytest.param(32, 3, id="1word_mem_expansion"),
170+
pytest.param(33, 6, id="33bytes_mem_expansion"),
116171
],
117172
)
118173
def test_ext_calls_gas(
@@ -122,18 +177,23 @@ def test_ext_calls_gas(
122177
opcode: Op,
123178
pre_setup: Op,
124179
cold_gas: int,
125-
warm_gas: int | None,
180+
warm_gas: int,
181+
new_account: bool,
182+
mem_expansion_size: int,
183+
mem_expansion_extra_gas: int,
126184
):
127-
"""Tests 4 variations of EXT*CALL gas, both warm and cold"""
128-
address_target = pre.deploy_contract(Container(sections=[Section.Code(code=Op.STOP)]))
185+
"""Tests variations of EXT*CALL gas, both warm and cold"""
186+
address_target = (
187+
pre.fund_eoa(0) if new_account else pre.deploy_contract(Container.Code(Op.STOP))
188+
)
129189

130190
gas_test(
131191
state_test,
132192
state_env,
133193
pre,
134-
setup_code=pre_setup + Op.PUSH0 + Op.PUSH0 + Op.PUSH20(address_target),
194+
setup_code=pre_setup + Op.PUSH1(mem_expansion_size) + Op.PUSH0 + Op.PUSH20(address_target),
135195
subject_code=opcode,
136196
tear_down_code=Op.STOP,
137-
cold_gas=cold_gas,
138-
warm_gas=warm_gas,
197+
cold_gas=cold_gas + mem_expansion_extra_gas,
198+
warm_gas=warm_gas + mem_expansion_extra_gas,
139199
)

tests/prague/eip7692_eof_v1/tracker.md

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -379,25 +379,25 @@
379379
- [x] EXTDELEGATECALL from EOF to legacy fails (evmone-tests: state_tests/state_transition/eof_calls/eof1_extdelegatecall_legacy.json)
380380
- [ ] EXTSTATICCALL forwards static mode (evmone-tests: state_tests/state_transition/eof_calls/extdelegatecall_static.json)
381381
- [x] EXTCALL with value success (evmone-tests: state_tests/state_transition/eof_calls/extcall_with_value.json)
382-
- [ ] EXTCALL with value from EXTSTATICCALL (evmone-tests: state_tests/state_transition/eof_calls/extcall_static_with_value.json)
382+
- [x] EXTCALL with value from EXTSTATICCALL (evmone-tests: state_tests/state_transition/eof_calls/extcall_static_with_value.json)
383383
- [x] EXTCALL with value, not enough balance (evmone-tests: state_tests/state_transition/eof_calls/extcall_failing_with_value_balance_check.json)
384-
- [ ] EXTCALL with value, check additional charge for value (evmone-tests: state_tests/state_transition/eof_calls/extcall_failing_with_value_additional_cost.json)
384+
- [x] EXTCALL with value, check additional charge for value (evmone-tests: state_tests/state_transition/eof_calls/extcall_failing_with_value_additional_cost.json)
385385
- [x] EXTCALL with gas not enough for callee to get 5000 gas (evmone-tests: state_tests/state_transition/eof_calls/extcall_min_callee_gas_failure_mode.json)
386386
- [x] RETURNDATA* after EXTCALL (evmone-tests: state_tests/state_transition/eof_calls/extcall_output.json)
387387
- [x] RETURNDATA* after EXTDELEGATECALL (evmone-tests: state_tests/state_transition/eof_calls/extdelegatecall_output.json state_tests/state_transition/eof_calls/extdelegatecall_returndatasize.json state_tests/state_transition/eof_calls/returndatacopy.json state_tests/state_transition/eof_calls/returndataload.json)
388388
- [x] RETURNDATA* after EXTSTATICCALL (evmone-tests: state_tests/state_transition/eof_calls/extstaticcall_output.json)
389389
- [x] RETURNDATA* after aborted EXT*CALL (evmone-tests: state_tests/state_transition/eof_calls/extdelegatecall_returndatasize_abort.json)
390390
- [x] Failed EXTCALL clears returndata from previous EXTCALL (evmone-tests: state_tests/state_transition/eof_calls/extcall_clears_returndata.json)
391-
- [ ] EXTCALL not enough gas for input memory charge (evmone-tests: state_tests/state_transition/eof_calls/extcall_memory.json)
392-
- [ ] EXTDELEGATECALL not enough gas for input memory charge (evmone-tests: state_tests/state_transition/eof_calls/extdelegatecall_memory.json)
393-
- [ ] EXTSTATICCALL not enough gas for input memory charge (evmone-tests: state_tests/state_transition/eof_calls/extstaticcall_memory.json)
391+
- [x] EXTCALL not enough gas for input memory charge (evmone-tests: state_tests/state_transition/eof_calls/extcall_memory.json)
392+
- [x] EXTDELEGATECALL not enough gas for input memory charge (evmone-tests: state_tests/state_transition/eof_calls/extdelegatecall_memory.json)
393+
- [x] EXTSTATICCALL not enough gas for input memory charge (evmone-tests: state_tests/state_transition/eof_calls/extstaticcall_memory.json)
394394
- [x] EXTCALL exception due to target address overflow (bits set in high 12 bytes) (evmone-tests: state_tests/state_transition/eof_calls/extcall_ase_ready_violation.json)
395395
- [x] EXTDELEGATECALL exception due to target address overflow (bits set in high 12 bytes) (evmone-tests: state_tests/state_transition/eof_calls/extdelegatecall_ase_ready_violation.json)
396396
- [x] EXTSTATICCALL exception due to target address overflow (bits set in high 12 bytes) (evmone-tests: state_tests/state_transition/eof_calls/extstaticcall_ase_ready_violation.json)
397-
- [ ] EXTCALL not enough gas for warming up target address (evmone-tests: state_tests/state_transition/eof_calls/extcall_cold_oog.json)
398-
- [ ] EXTDELEGATECALL not enough gas for warming up target address (evmone-tests: state_tests/state_transition/eof_calls/extdelegatecall_cold_oog.json)
399-
- [ ] EXTSTATICCALL not enough gas for warming up target address (evmone-tests: state_tests/state_transition/eof_calls/extstaticcall_cold_oog.json)
400-
- [ ] EXTCALL not enough gas for account creation cost (transfer value to non-existing account) (evmone-tests: state_tests/state_transition/eof_calls/extcall_value_zero_to_nonexistent_account.json)
397+
- [x] EXTCALL not enough gas for warming up target address (evmone-tests: state_tests/state_transition/eof_calls/extcall_cold_oog.json)
398+
- [x] EXTDELEGATECALL not enough gas for warming up target address (evmone-tests: state_tests/state_transition/eof_calls/extdelegatecall_cold_oog.json)
399+
- [x] EXTSTATICCALL not enough gas for warming up target address (evmone-tests: state_tests/state_transition/eof_calls/extstaticcall_cold_oog.json)
400+
- [x] EXTCALL not enough gas for account creation cost (transfer value to non-existing account) (evmone-tests: state_tests/state_transition/eof_calls/extcall_value_zero_to_nonexistent_account.json)
401401
- [x] OOG after EXTCALL (evmone-tests: state_tests/state_transition/eof_calls/extcall_then_oog.json)
402402
- [x] OOG after EXTDELEGATECALL (evmone-tests: state_tests/state_transition/eof_calls/extdelegatecall_then_oog.json)
403403
- [x] OOG after EXTSTATICCALL (evmone-tests: state_tests/state_transition/eof_calls/extstaticcall_then_oog.json)

whitelist.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -244,6 +244,7 @@ makereport
244244
marioevz
245245
markdownlint
246246
md
247+
mem
247248
metaclass
248249
mixhash
249250
mkdocs

0 commit comments

Comments
 (0)