Skip to content

Commit 63a49c8

Browse files
authored
feat(forks): Add gas costs functions (ethereum#779)
* feat(forks): Add memory expansion, calldata calculators to each fork * fix(fw): Remove `copy_opcode_cost`, `cost_memory_bytes` and `eip_2028_transaction_data_cost` * refactor(tests): Use fork calculator methods instead of helpers * refactor(base_types): Move `AccessList` to base types * fix(forks): GasCosts field description * fix(forks): Initcode word cost * feat(forks): Add transaction_intrinsic_cost_calculator * refactor(tests): Use fork gas calculator methods * refactor(forks): Add authorization to intrinsic gas cost calc * refactor(plugins/execute): Use fork gas calc functions * refactor(tests): Use `fork` gas calc functions * docs: changelog
1 parent 0439522 commit 63a49c8

File tree

13 files changed

+130
-140
lines changed

13 files changed

+130
-140
lines changed

cancun/eip4844_blobs/test_blob_txs.py

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@
4444
Transaction,
4545
TransactionException,
4646
add_kzg_version,
47-
eip_2028_transaction_data_cost,
4847
)
4948

5049
from .spec import Spec, SpecHelpers, ref_spec_4844
@@ -90,20 +89,13 @@ def tx_value() -> int:
9089

9190
@pytest.fixture
9291
def tx_gas(
92+
fork: Fork,
9393
tx_calldata: bytes,
9494
tx_access_list: List[AccessList],
9595
) -> int:
9696
"""Default gas allocated to transactions sent during test."""
97-
access_list_gas = 0
98-
if tx_access_list:
99-
ACCESS_LIST_ADDRESS_COST = 2400
100-
ACCESS_LIST_STORAGE_KEY_COST = 1900
101-
102-
for address in tx_access_list:
103-
access_list_gas += ACCESS_LIST_ADDRESS_COST
104-
access_list_gas += len(address.storage_keys) * ACCESS_LIST_STORAGE_KEY_COST
105-
106-
return 21000 + eip_2028_transaction_data_cost(tx_calldata) + access_list_gas
97+
tx_intrinsic_cost_calculator = fork.transaction_intrinsic_cost_calculator()
98+
return tx_intrinsic_cost_calculator(calldata=tx_calldata, access_list=tx_access_list)
10799

108100

109101
@pytest.fixture

cancun/eip4844_blobs/test_blob_txs_full.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ def tx_value() -> int:
4545
@pytest.fixture
4646
def tx_gas() -> int:
4747
"""Default gas allocated to transactions sent during test."""
48-
return 21000
48+
return 21_000
4949

5050

5151
@pytest.fixture

cancun/eip4844_blobs/test_point_evaluation_precompile.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535

3636
import pytest
3737

38+
from ethereum_test_forks import Fork
3839
from ethereum_test_tools import (
3940
EOA,
4041
Account,
@@ -48,7 +49,6 @@
4849
Storage,
4950
Transaction,
5051
call_return_code,
51-
eip_2028_transaction_data_cost,
5252
)
5353
from ethereum_test_tools.vm.opcode import Opcodes as Op
5454

@@ -542,6 +542,7 @@ def test_call_opcode_types(
542542
)
543543
@pytest.mark.valid_from("Cancun")
544544
def test_tx_entry_point(
545+
fork: Fork,
545546
state_test: StateTestFiller,
546547
precompile_input: bytes,
547548
call_gas: int,
@@ -559,7 +560,8 @@ def test_tx_entry_point(
559560
sender = pre.fund_eoa(amount=start_balance)
560561

561562
# Gas is appended the intrinsic gas cost of the transaction
562-
intrinsic_gas_cost = 21_000 + eip_2028_transaction_data_cost(precompile_input)
563+
tx_intrinsic_gas_cost_calculator = fork.transaction_intrinsic_cost_calculator()
564+
intrinsic_gas_cost = tx_intrinsic_gas_cost_calculator(calldata=precompile_input)
563565

564566
# Consumed gas will only be the precompile gas if the proof is correct and
565567
# the call gas is sufficient.

cancun/eip4844_blobs/test_point_evaluation_precompile_gas.py

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
import pytest
99

10+
from ethereum_test_forks import Fork
1011
from ethereum_test_tools import (
1112
Account,
1213
Address,
@@ -16,7 +17,7 @@
1617
Environment,
1718
StateTestFiller,
1819
Transaction,
19-
copy_opcode_cost,
20+
ceiling_division,
2021
)
2122
from ethereum_test_tools.vm.opcode import Opcodes as Op
2223

@@ -69,8 +70,23 @@ def call_gas() -> int:
6970
return Spec.POINT_EVALUATION_PRECOMPILE_GAS
7071

7172

73+
def copy_opcode_cost(fork: Fork, length: int) -> int:
74+
"""
75+
Calculates the cost of the COPY opcodes, assuming memory expansion from
76+
empty memory, based on the costs specified in the yellow paper:
77+
https://ethereum.github.io/yellowpaper/paper.pdf
78+
"""
79+
cost_memory_bytes = fork.memory_expansion_gas_calculator()
80+
return (
81+
3
82+
+ (ceiling_division(length, 32) * 3)
83+
+ cost_memory_bytes(new_bytes=length, previous_bytes=0)
84+
)
85+
86+
7287
@pytest.fixture
7388
def precompile_caller_code(
89+
fork: Fork,
7490
call_type: Op,
7591
call_gas: int,
7692
precompile_input: bytes,
@@ -87,7 +103,7 @@ def precompile_caller_code(
87103
WARM_STORAGE_READ_COST
88104
+ (CALLDATASIZE_COST * 1)
89105
+ (PUSH_OPERATIONS_COST * 2)
90-
+ copy_opcode_cost(len(precompile_input))
106+
+ copy_opcode_cost(fork, len(precompile_input))
91107
)
92108
if call_type == Op.CALL or call_type == Op.CALLCODE:
93109
precompile_caller_code += call_type( # type: ignore # https://github.com/ethereum/execution-spec-tests/issues/348 # noqa: E501

cancun/eip5656_mcopy/test_mcopy_memory_expansion.py

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,10 @@
99

1010
import pytest
1111

12+
from ethereum_test_forks import Fork
1213
from ethereum_test_tools import Account, Address, Alloc, Bytecode, Environment
1314
from ethereum_test_tools import Opcodes as Op
14-
from ethereum_test_tools import StateTestFiller, Transaction, cost_memory_bytes
15-
from ethereum_test_types.helpers import eip_2028_transaction_data_cost
15+
from ethereum_test_tools import StateTestFiller, Transaction
1616

1717
from .common import REFERENCE_SPEC_GIT_PATH, REFERENCE_SPEC_VERSION
1818

@@ -53,30 +53,35 @@ def callee_bytecode(dest: int, src: int, length: int) -> Bytecode:
5353

5454
@pytest.fixture
5555
def call_exact_cost(
56+
fork: Fork,
5657
initial_memory: bytes,
5758
dest: int,
5859
length: int,
5960
) -> int:
6061
"""
6162
Returns the exact cost of the subcall, based on the initial memory and the length of the copy.
6263
"""
63-
intrinsic_cost = 21000 + eip_2028_transaction_data_cost(initial_memory)
64+
cost_memory_bytes = fork.memory_expansion_gas_calculator()
65+
gas_costs = fork.gas_costs()
66+
tx_intrinsic_gas_cost_calculator = fork.transaction_intrinsic_cost_calculator()
6467

6568
mcopy_cost = 3
6669
mcopy_cost += 3 * ((length + 31) // 32)
6770
if length > 0 and dest + length > len(initial_memory):
68-
mcopy_cost += cost_memory_bytes(dest + length, len(initial_memory))
71+
mcopy_cost += cost_memory_bytes(
72+
new_bytes=dest + length, previous_bytes=len(initial_memory)
73+
)
6974

7075
calldatacopy_cost = 3
7176
calldatacopy_cost += 3 * ((len(initial_memory) + 31) // 32)
72-
calldatacopy_cost += cost_memory_bytes(len(initial_memory), 0)
77+
calldatacopy_cost += cost_memory_bytes(new_bytes=len(initial_memory))
7378

74-
pushes_cost = 3 * 9
75-
calldatasize_cost = 2
79+
pushes_cost = gas_costs.G_VERY_LOW * 9
80+
calldatasize_cost = gas_costs.G_BASE
7681

7782
sstore_cost = 22100
7883
return (
79-
intrinsic_cost
84+
tx_intrinsic_gas_cost_calculator(calldata=initial_memory)
8085
+ mcopy_cost
8186
+ calldatacopy_cost
8287
+ pushes_cost

osaka/eip7692_eof_v1/eip7069_extcall/test_gas.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@
55

66
import pytest
77

8+
from ethereum_test_forks import Fork
89
from ethereum_test_tools import Alloc, Environment, StateTestFiller
910
from ethereum_test_tools.eof.v1 import Container
1011
from ethereum_test_tools.vm.opcode import Opcodes as Op
11-
from ethereum_test_types.helpers import cost_memory_bytes
1212

1313
from .. import EOF_FORK_NAME
1414
from ..gas_test import gas_test
@@ -114,6 +114,7 @@ def state_env() -> Environment:
114114
def test_ext_calls_gas(
115115
state_test: StateTestFiller,
116116
pre: Alloc,
117+
fork: Fork,
117118
state_env: Environment,
118119
opcode: Op,
119120
pre_setup: Op,
@@ -126,7 +127,7 @@ def test_ext_calls_gas(
126127
address_target = (
127128
pre.fund_eoa(0) if new_account else pre.deploy_contract(Container.Code(Op.STOP))
128129
)
129-
130+
cost_memory_bytes = fork.memory_expansion_gas_calculator()
130131
gas_test(
131132
state_test,
132133
state_env,
@@ -137,8 +138,8 @@ def test_ext_calls_gas(
137138
+ Op.PUSH20(address_target),
138139
subject_code=opcode,
139140
tear_down_code=Op.STOP,
140-
cold_gas=cold_gas + cost_memory_bytes(mem_expansion_bytes, 0),
141-
warm_gas=warm_gas + cost_memory_bytes(mem_expansion_bytes, 0),
141+
cold_gas=cold_gas + cost_memory_bytes(new_bytes=mem_expansion_bytes),
142+
warm_gas=warm_gas + cost_memory_bytes(new_bytes=mem_expansion_bytes),
142143
)
143144

144145

osaka/eip7692_eof_v1/eip7069_extcall/test_returndatacopy_memory_expansion.py

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,10 @@
66

77
import pytest
88

9+
from ethereum_test_forks import Fork
910
from ethereum_test_tools import Account, Address, Alloc, Bytecode, Environment
1011
from ethereum_test_tools import Opcodes as Op
11-
from ethereum_test_tools import StateTestFiller, Storage, Transaction, cost_memory_bytes
12+
from ethereum_test_tools import StateTestFiller, Storage, Transaction
1213
from ethereum_test_tools.eof.v1 import Container
1314

1415
from .. import EOF_FORK_NAME
@@ -42,21 +43,26 @@ def callee_bytecode(dest: int, src: int, length: int) -> Container:
4243

4344
@pytest.fixture
4445
def subcall_exact_cost(
46+
fork: Fork,
4547
initial_memory: bytes,
4648
dest: int,
4749
length: int,
4850
) -> int:
4951
"""
5052
Returns the exact cost of the subcall, based on the initial memory and the length of the copy.
5153
"""
54+
cost_memory_bytes = fork.memory_expansion_gas_calculator()
55+
5256
returndatacopy_cost = 3
5357
returndatacopy_cost += 3 * ((length + 31) // 32)
5458
if length > 0 and dest + length > len(initial_memory):
55-
returndatacopy_cost += cost_memory_bytes(dest + length, len(initial_memory))
59+
returndatacopy_cost += cost_memory_bytes(
60+
new_bytes=dest + length, previous_bytes=len(initial_memory)
61+
)
5662

5763
calldatacopy_cost = 3
5864
calldatacopy_cost += 3 * ((len(initial_memory) + 31) // 32)
59-
calldatacopy_cost += cost_memory_bytes(len(initial_memory), 0)
65+
calldatacopy_cost += cost_memory_bytes(new_bytes=len(initial_memory))
6066

6167
pushes_cost = 3 * 7
6268
calldatasize_cost = 2

osaka/eip7692_eof_v1/eip7480_data_section/test_datacopy_memory_expansion.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
import pytest
77

8+
from ethereum_test_forks import Fork
89
from ethereum_test_tools import (
910
Account,
1011
Address,
@@ -14,7 +15,6 @@
1415
StateTestFiller,
1516
Storage,
1617
Transaction,
17-
cost_memory_bytes,
1818
)
1919
from ethereum_test_tools.eof.v1 import Container, Section
2020
from ethereum_test_tools.vm.opcode import Opcodes as Op
@@ -50,21 +50,26 @@ def callee_bytecode(dest: int, src: int, length: int, data_section: bytes) -> Co
5050

5151
@pytest.fixture
5252
def subcall_exact_cost(
53+
fork: Fork,
5354
initial_memory: bytes,
5455
dest: int,
5556
length: int,
5657
) -> int:
5758
"""
5859
Returns the exact cost of the subcall, based on the initial memory and the length of the copy.
5960
"""
61+
cost_memory_bytes = fork.memory_expansion_gas_calculator()
62+
6063
datacopy_cost = 3
6164
datacopy_cost += 3 * ((length + 31) // 32)
6265
if length > 0 and dest + length > len(initial_memory):
63-
datacopy_cost += cost_memory_bytes(dest + length, len(initial_memory))
66+
datacopy_cost += cost_memory_bytes(
67+
new_bytes=dest + length, previous_bytes=len(initial_memory)
68+
)
6469

6570
calldatacopy_cost = 3
6671
calldatacopy_cost += 3 * ((len(initial_memory) + 31) // 32)
67-
calldatacopy_cost += cost_memory_bytes(len(initial_memory), 0)
72+
calldatacopy_cost += cost_memory_bytes(new_bytes=len(initial_memory))
6873

6974
pushes_cost = 3 * 7
7075
calldatasize_cost = 2

osaka/eip7692_eof_v1/eip7620_eof_create/test_gas.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@
44

55
import pytest
66

7+
from ethereum_test_forks import Fork
78
from ethereum_test_tools import Alloc, Environment, StateTestFiller, compute_eofcreate_address
89
from ethereum_test_tools.eof.v1 import Container, Section
910
from ethereum_test_tools.vm.opcode import Opcodes as Op
10-
from ethereum_test_types.helpers import cost_memory_bytes
1111

1212
from .. import EOF_FORK_NAME
1313
from ..gas_test import gas_test
@@ -115,6 +115,7 @@ def make_factory(initcode: Container):
115115
def test_eofcreate_gas(
116116
state_test: StateTestFiller,
117117
pre: Alloc,
118+
fork: Fork,
118119
value: int,
119120
new_account: bool,
120121
mem_expansion_bytes: int,
@@ -139,7 +140,7 @@ def test_eofcreate_gas(
139140
code_increment_counter = (
140141
Op.TLOAD(slot_counter) + Op.DUP1 + Op.TSTORE(slot_counter, Op.PUSH1(1) + Op.ADD)
141142
)
142-
143+
cost_memory_bytes = fork.memory_expansion_gas_calculator()
143144
gas_test(
144145
state_test,
145146
Environment(),
@@ -151,7 +152,7 @@ def test_eofcreate_gas(
151152
subject_code=Op.EOFCREATE[0],
152153
tear_down_code=Op.STOP,
153154
cold_gas=EOFCREATE_GAS
154-
+ cost_memory_bytes(mem_expansion_bytes, 0)
155+
+ cost_memory_bytes(new_bytes=mem_expansion_bytes)
155156
+ initcode_hashing_cost
156157
+ initcode_execution_cost
157158
+ deployed_code_cost,

0 commit comments

Comments
 (0)