Skip to content

Commit 5c6e20a

Browse files
committed
feat(tests): add CALLCODE no state gas and receipt vs header divergence tests
1 parent 9a5884c commit 5c6e20a

5 files changed

Lines changed: 96 additions & 8 deletions

File tree

tests/amsterdam/eip8037_state_creation_gas_cost_increase/test_block_2d_gas_accounting.py

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -583,3 +583,47 @@ def test_block_2d_gas_tx_gas_limit_exceeds_regular_remaining(
583583
],
584584
post={sstore_contract: Account(storage=storage)},
585585
)
586+
587+
588+
@pytest.mark.valid_from("Amsterdam")
589+
def test_receipt_cumulative_differs_from_header_gas_used(
590+
blockchain_test: BlockchainTestFiller,
591+
pre: Alloc,
592+
fork: Fork,
593+
) -> None:
594+
"""
595+
Verify receipt cumulative_gas_used can differ from header gas_used.
596+
597+
Under 2D accounting, header gas_used = max(sum_regular, sum_state)
598+
while receipt cumulative_gas_used = sum of per-tx (regular + state).
599+
A block with SSTORE txs where state dominates produces a header
600+
gas_used less than the receipt cumulative, because the header uses
601+
the 2D max, not the 1D sum.
602+
603+
A client that uses receipt cumulative for header validation (or
604+
vice versa) would reject valid blocks.
605+
"""
606+
tx_regular, tx_state = sstore_tx_gas(fork)
607+
num_txs = 3
608+
609+
txs, post = sstore_txs(pre, fork, num_txs)
610+
611+
block_regular = num_txs * tx_regular
612+
block_state = num_txs * tx_state
613+
header_gas_used = max(block_regular, block_state)
614+
receipt_cumulative = num_txs * (tx_regular + tx_state)
615+
616+
# State dominates, so header < receipt cumulative
617+
assert block_state > block_regular
618+
assert header_gas_used < receipt_cumulative
619+
620+
blockchain_test(
621+
pre=pre,
622+
blocks=[
623+
Block(
624+
txs=txs,
625+
header_verify=Header(gas_used=header_gas_used),
626+
),
627+
],
628+
post=post,
629+
)

tests/amsterdam/eip8037_state_creation_gas_cost_increase/test_state_gas_call.py

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -933,7 +933,7 @@ def test_call_new_account_header_gas_used(
933933
pytest.param("halt", id="child_halt"),
934934
],
935935
)
936-
@pytest.mark.valid_from("EIP8037")
936+
@pytest.mark.valid_from("Amsterdam")
937937
def test_top_level_halt_preserves_restored_reservoir(
938938
blockchain_test: BlockchainTestFiller,
939939
pre: Alloc,
@@ -991,3 +991,47 @@ def test_top_level_halt_preserves_restored_reservoir(
991991
],
992992
post={child: Account(storage={0: 0})},
993993
)
994+
995+
996+
@pytest.mark.valid_from("Amsterdam")
997+
def test_callcode_value_no_new_account_state_gas(
998+
state_test: StateTestFiller,
999+
pre: Alloc,
1000+
fork: Fork,
1001+
) -> None:
1002+
"""
1003+
Verify CALLCODE with value does not charge GAS_NEW_ACCOUNT.
1004+
1005+
CALLCODE transfers value to the caller, not the target. No new
1006+
account is created regardless of whether the target exists. The
1007+
reservoir should be fully available for a subsequent SSTORE.
1008+
"""
1009+
gas_limit_cap = fork.transaction_gas_limit_cap()
1010+
assert gas_limit_cap is not None
1011+
sstore_state_gas = fork.sstore_state_gas()
1012+
1013+
target = pre.fund_eoa(amount=0)
1014+
1015+
storage = Storage()
1016+
contract = pre.deploy_contract(
1017+
code=(
1018+
Op.POP(
1019+
Op.CALLCODE(
1020+
gas=Op.GAS,
1021+
address=target,
1022+
value=1,
1023+
)
1024+
)
1025+
+ Op.SSTORE(storage.store_next(1, "reservoir_ok"), 1)
1026+
),
1027+
balance=10**18,
1028+
)
1029+
1030+
tx = Transaction(
1031+
to=contract,
1032+
gas_limit=gas_limit_cap + sstore_state_gas,
1033+
sender=pre.fund_eoa(),
1034+
)
1035+
1036+
post = {contract: Account(storage=storage)}
1037+
state_test(pre=pre, post=post, tx=tx)

tests/amsterdam/eip8037_state_creation_gas_cost_increase/test_state_gas_create.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1696,7 +1696,7 @@ def test_create_oog_during_state_gas_charge(
16961696
state_test(pre=pre, post=post, tx=tx)
16971697

16981698

1699-
@pytest.mark.valid_from("EIP8037")
1699+
@pytest.mark.valid_from("Amsterdam")
17001700
def test_create_nonce_overflow_state_gas_consumed(
17011701
state_test: StateTestFiller,
17021702
pre: Alloc,
@@ -1742,7 +1742,7 @@ def test_create_nonce_overflow_state_gas_consumed(
17421742
state_test(pre=pre, post=post, tx=tx)
17431743

17441744

1745-
@pytest.mark.valid_from("EIP8037")
1745+
@pytest.mark.valid_from("Amsterdam")
17461746
def test_create_stack_depth_state_gas_consumed(
17471747
state_test: StateTestFiller,
17481748
pre: Alloc,
@@ -1788,7 +1788,7 @@ def test_create_stack_depth_state_gas_consumed(
17881788
state_test(pre=pre, post=post, tx=tx)
17891789

17901790

1791-
@pytest.mark.valid_from("EIP8037")
1791+
@pytest.mark.valid_from("Amsterdam")
17921792
def test_create2_collision_state_gas_block_accounting(
17931793
blockchain_test: BlockchainTestFiller,
17941794
pre: Alloc,

tests/amsterdam/eip8037_state_creation_gas_cost_increase/test_state_gas_reservoir.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -432,7 +432,7 @@ def test_create_tx_reservoir(
432432
pytest.param(3, id="with_storage_keys"),
433433
],
434434
)
435-
@pytest.mark.valid_from("EIP8037")
435+
@pytest.mark.valid_from("Amsterdam")
436436
def test_access_list_gas_is_regular_not_state(
437437
blockchain_test: BlockchainTestFiller,
438438
pre: Alloc,
@@ -484,7 +484,7 @@ def test_access_list_gas_is_regular_not_state(
484484
)
485485

486486

487-
@pytest.mark.valid_from("EIP8037")
487+
@pytest.mark.valid_from("Amsterdam")
488488
def test_access_list_warm_savings_stay_regular(
489489
blockchain_test: BlockchainTestFiller,
490490
pre: Alloc,

tests/amsterdam/eip8037_state_creation_gas_cost_increase/test_state_gas_selfdestruct.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,7 @@ def test_selfdestruct_new_beneficiary_header_gas_used(
252252

253253

254254
@pytest.mark.with_all_create_opcodes()
255-
@pytest.mark.valid_from("EIP8037")
255+
@pytest.mark.valid_from("Amsterdam")
256256
def test_create_selfdestruct_same_tx_no_state_gas_refund(
257257
blockchain_test: BlockchainTestFiller,
258258
pre: Alloc,
@@ -311,7 +311,7 @@ def test_create_selfdestruct_same_tx_no_state_gas_refund(
311311

312312

313313
@pytest.mark.with_all_create_opcodes()
314-
@pytest.mark.valid_from("EIP8037")
314+
@pytest.mark.valid_from("Amsterdam")
315315
def test_call_value_to_selfdestructed_same_tx_account(
316316
blockchain_test: BlockchainTestFiller,
317317
pre: Alloc,

0 commit comments

Comments
 (0)