Skip to content
Open
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 @@ -40,8 +40,7 @@ def gas_costs(cls) -> GasCosts:
return replace(
parent,
TX_BASE=12_000,
TRANSFER_LOG_COST=1_756,
TX_VALUE_COST=4_244,
TX_VALUE_COST=6_000,
)

@classmethod
Expand Down Expand Up @@ -75,14 +74,10 @@ def fn(
# CREATE_ACCESS regular gas; TX_CREATE folds in the
# NEW_ACCOUNT state gas, which the floor excludes.
floor += gas_costs.TX_CREATE - gas_costs.NEW_ACCOUNT
if sends_value:
floor += gas_costs.TRANSFER_LOG_COST
elif not is_self_transfer:
floor += gas_costs.COLD_ACCOUNT_ACCESS
if sends_value:
floor += (
gas_costs.TRANSFER_LOG_COST + gas_costs.TX_VALUE_COST
)
floor += gas_costs.TX_VALUE_COST
return floor

return fn
Expand All @@ -97,9 +92,8 @@ def transaction_intrinsic_cost_calculator(

Non-create, non-self targets pay ``COLD_ACCOUNT_ACCESS``
unconditionally; access lists do not warm transaction-level
accounts. Value-bearing transactions pay
``TRANSFER_LOG_COST`` plus ``TX_VALUE_COST``; self-transfers
suppress the value-transfer charge entirely.
accounts. Value-bearing transactions pay ``TX_VALUE_COST``;
self-transfers suppress the value-transfer charge entirely.
"""
super_fn = super(EIP2780, cls).transaction_intrinsic_cost_calculator()
gas_costs = cls.gas_costs()
Expand Down Expand Up @@ -147,14 +141,10 @@ def fn(
# remove it here, mirroring value transfer to an empty
# account whose NEW_ACCOUNT is likewise top-frame.
intrinsic_cost -= gas_costs.NEW_ACCOUNT
if sends_value:
intrinsic_cost += gas_costs.TRANSFER_LOG_COST
elif not is_self_transfer:
intrinsic_cost += gas_costs.COLD_ACCOUNT_ACCESS
if sends_value:
intrinsic_cost += (
gas_costs.TRANSFER_LOG_COST + gas_costs.TX_VALUE_COST
)
intrinsic_cost += gas_costs.TX_VALUE_COST

if return_cost_deducted_prior_execution:
return intrinsic_cost
Expand Down
1 change: 0 additions & 1 deletion packages/testing/src/execution_testing/forks/gas_costs.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ class GasCosts:
NEW_ACCOUNT: int
ACCOUNT_WRITE: int = 0
CREATE_ACCESS: int = 0
TRANSFER_LOG_COST: int = 0
TX_VALUE_COST: int = 0

# Contract Creation
Expand Down
10 changes: 3 additions & 7 deletions src/ethereum/forks/amsterdam/transactions.py
Original file line number Diff line number Diff line change
Expand Up @@ -639,8 +639,8 @@ def calculate_intrinsic_cost(
call, or `CREATE_ACCESS` for a contract creation). The created
account's `NEW_ACCOUNT` state gas is state-dependent and is
charged at the top frame, not here.
3. Value cost (`TRANSFER_LOG_COST`, plus `TX_VALUE_COST` for a
non-self-transfer call) when ``tx.value > 0``.
3. Value cost (`TX_VALUE_COST` for a non-self-transfer call) when
``tx.value > 0``.
4. Calldata cost (zero and non-zero bytes).
5. Access list entries (if applicable).
6. Authorizations (if applicable): only the state-independent base
Expand Down Expand Up @@ -671,14 +671,10 @@ def calculate_intrinsic_cost(
if is_create:
recipient_regular_gas = GasCosts.CREATE_ACCESS
init_code_gas = init_code_cost(ulen(tx.data))
if tx.value > U256(0):
recipient_regular_gas += GasCosts.TRANSFER_LOG_COST
elif not is_self_transfer:
recipient_regular_gas = GasCosts.COLD_ACCOUNT_ACCESS
if tx.value > U256(0):
recipient_regular_gas += (
GasCosts.TRANSFER_LOG_COST + GasCosts.TX_VALUE_COST
)
recipient_regular_gas += GasCosts.TX_VALUE_COST

access_list_cost = Uint(0)
tokens_in_access_list = Uint(0)
Expand Down
3 changes: 1 addition & 2 deletions src/ethereum/forks/amsterdam/vm/gas.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,8 +137,7 @@ class GasCosts:
# Transactions
TX_BASE: Final[Uint] = Uint(12000)
TX_CREATE: Final[Uint] = Uint(32000)
TX_VALUE_COST: Final[Uint] = Uint(4244)
TRANSFER_LOG_COST: Final[Uint] = Uint(1756)
TX_VALUE_COST: Final[Uint] = Uint(6000)
TX_DATA_TOKEN_STANDARD: Final[Uint] = Uint(4)
TX_DATA_TOKEN_FLOOR: Final[Uint] = Uint(16)
TX_ACCESS_LIST_ADDRESS: Final[Uint] = COLD_ACCOUNT_ACCESS
Expand Down
2 changes: 1 addition & 1 deletion tests/amsterdam/eip2780_reduce_intrinsic_tx_gas/spec.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,5 @@ class ReferenceSpec:

ref_spec_2780 = ReferenceSpec(
git_path="EIPS/eip-2780.md",
version="e6d8f589d355e891c37ff479d3ce668352e5b1be",
version="04dd54c2e7ec1f408cf4a150d5c1aa43573bd025",
)
Original file line number Diff line number Diff line change
Expand Up @@ -259,13 +259,11 @@ def test_calldata_floor_contract_creation(
empty code, and prices every byte as one floor token.
- ``floor_binds``: ``gas_used`` pins to the floor, which anchors
on the creation regular base (``TX_BASE + CREATE_ACCESS``, plus
``TRANSFER_LOG_COST`` when value moves) but excludes the created
account's ``NEW_ACCOUNT`` *state* charge and the init-code word
cost -- both masked by the binding floor -- while the deploy
(and any moved wei) still lands. The receipt pins the floor
exactly, so the value-bearing case sits precisely
``TRANSFER_LOG_COST`` above the zero-value one.
on the creation regular base (``TX_BASE + CREATE_ACCESS``)
but excludes the created account's ``NEW_ACCOUNT`` *state* charge
and the init-code word cost -- both masked by the binding floor --
while the deploy (and any moved wei) still lands.
The receipt pins the floor exactly.
- ``below_floor``: a gas limit one short of the floor still covers
the creation intrinsic, so the rejection is pinned to the floor,
with ``INTRINSIC_GAS_BELOW_FLOOR_GAS_COST``.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,9 +102,7 @@ def test_intrinsic_reduction_across_amsterdam_transition(
if not self_transfer:
expected_post += post_gas_costs.COLD_ACCOUNT_ACCESS
if value:
expected_post += (
post_gas_costs.TRANSFER_LOG_COST + post_gas_costs.TX_VALUE_COST
)
expected_post += post_gas_costs.TX_VALUE_COST

timestamps = [PRE_FORK_TIMESTAMP, POST_FORK_TIMESTAMP]
expected_intrinsics = [expected_pre, expected_post]
Expand Down Expand Up @@ -181,9 +179,8 @@ def test_creation_tx_intrinsic_across_amsterdam_transition(
block, each from a fresh sender with the gas limit pinned exactly.
Pre-fork the whole cost is regular intrinsic: ``TX_BASE`` plus the
flat ``TX_CREATE``. Post-fork the intrinsic keeps only the
``CREATE_ACCESS`` regular portion of ``TX_CREATE`` (plus the
transfer-log charge when value moves), while the created account's
``NEW_ACCOUNT`` is charged as *state* gas at the top frame — the
``CREATE_ACCESS`` regular portion of ``TX_CREATE``, while the created
account's ``NEW_ACCOUNT`` is charged as *state* gas at the top frame — the
sender-facing total is the sum of both.
The per-fork costs are hand-derived from each fork's gas constants
Expand Down Expand Up @@ -217,8 +214,6 @@ def test_creation_tx_intrinsic_across_amsterdam_transition(
+ (post_costs.TX_CREATE - post_costs.NEW_ACCOUNT)
+ init_code_terms
)
if value:
expected_post += post_costs.TRANSFER_LOG_COST
expected_post_state = post_costs.NEW_ACCOUNT

timestamps = [PRE_FORK_TIMESTAMP, POST_FORK_TIMESTAMP]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,11 +67,10 @@ def test_value_moving_transactions(
``NEW_ACCOUNT`` state charge when value is transferred.
The EIP-7708 transfer log is asserted to fire exactly when
``TRANSFER_LOG_COST`` is charged: for a non-self value transfer,
``TX_VALUE_COST`` is charged: for a non-self value transfer,
and never for a self-transfer (carve-out) or a zero-value tx.
"""
sender_initial_balance = 10**18
sender = pre.fund_eoa(sender_initial_balance)
sender = pre.fund_eoa()
target = setup_target(pre, recipient_type, sender)

target_initial_balance = (
Expand All @@ -95,13 +94,12 @@ def test_value_moving_transactions(
# spills entirely into regular gas.
total_gas_cost = intrinsic_gas + top_frame_gas + top_frame_state_gas

tx_gas_limit = total_gas_cost + 1000 # add a small buffer
gas_price = 1_000_000_000
tx_gas_limit = total_gas_cost

is_self_transfer = recipient_type == RecipientType.SELF

# A transfer log is emitted iff value moves to a distinct account,
# which is exactly when the intrinsic includes ``TRANSFER_LOG_COST``.
# which is exactly when the intrinsic includes ``TX_VALUE_COST``.
# ``logs=[]`` asserts no log fires for the carved-out cases.
if value > 0 and not is_self_transfer:
expected_logs = [transfer_log(sender, target, value)]
Expand All @@ -113,19 +111,13 @@ def test_value_moving_transactions(
to=target,
value=value,
gas_limit=tx_gas_limit,
gas_price=gas_price,
expected_receipt=TransactionReceipt(logs=expected_logs),
)

sender_value_delta = 0 if is_self_transfer else value
sender_final_balance = (
sender_initial_balance
- sender_value_delta
- total_gas_cost * gas_price
expected_receipt=TransactionReceipt(
cumulative_gas_used=tx_gas_limit, logs=expected_logs
),
)

post: dict[Address, Account | None] = {
sender: Account(nonce=1, balance=sender_final_balance),
sender: Account(nonce=1),
}
if not is_self_transfer:
if recipient_type == RecipientType.EMPTY_ACCOUNT and value == 0:
Expand Down
Loading