Skip to content

Commit f5da8ef

Browse files
authored
feat(tests): EIP-8037 additional state gas coverage (#2718)
1 parent a23c650 commit f5da8ef

5 files changed

Lines changed: 1278 additions & 0 deletions

File tree

tests/amsterdam/eip8037_state_creation_gas_cost_increase/test_block_2d_gas_accounting.py

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@
2222
Op,
2323
Storage,
2424
Transaction,
25+
TransactionException,
26+
TransactionReceipt,
2527
)
2628

2729
from .spec import ref_spec_8037
@@ -466,3 +468,170 @@ def test_multi_block_dimension_flip(
466468
],
467469
post=post_2,
468470
)
471+
472+
473+
@pytest.mark.exception_test
474+
@pytest.mark.valid_from("EIP8037")
475+
def test_tx_rejected_when_regular_gas_exceeds_block_limit_small(
476+
blockchain_test: BlockchainTestFiller,
477+
pre: Alloc,
478+
fork: Fork,
479+
) -> None:
480+
"""Reject a small-gas tx whose regular gas overflows the block."""
481+
gas_limit_cap = fork.transaction_gas_limit_cap()
482+
assert gas_limit_cap is not None
483+
intrinsic_gas = fork.transaction_intrinsic_cost_calculator()()
484+
485+
block_gas_limit = intrinsic_gas * 2
486+
487+
filler = pre.deploy_contract(code=Op.STOP)
488+
filler_tx = Transaction(
489+
to=filler,
490+
gas_limit=intrinsic_gas,
491+
sender=pre.fund_eoa(),
492+
)
493+
494+
rejected_gas_limit = intrinsic_gas + 1
495+
assert rejected_gas_limit < gas_limit_cap
496+
rejected = pre.deploy_contract(code=Op.STOP)
497+
rejected_tx = Transaction(
498+
to=rejected,
499+
gas_limit=rejected_gas_limit,
500+
sender=pre.fund_eoa(),
501+
error=TransactionException.GAS_ALLOWANCE_EXCEEDED,
502+
)
503+
504+
blockchain_test(
505+
genesis_environment=Environment(gas_limit=block_gas_limit),
506+
pre=pre,
507+
blocks=[
508+
Block(
509+
txs=[filler_tx, rejected_tx],
510+
gas_limit=block_gas_limit,
511+
exception=TransactionException.GAS_ALLOWANCE_EXCEEDED,
512+
)
513+
],
514+
post={},
515+
)
516+
517+
518+
@pytest.mark.parametrize(
519+
"tx2_gas_limit_equals_block_gas_limit",
520+
[
521+
pytest.param(True, id="tx_gas_limit_equals_block_limit"),
522+
pytest.param(False, id="tx_gas_limit_just_above_remaining"),
523+
],
524+
)
525+
@pytest.mark.valid_from("EIP8037")
526+
def test_block_2d_gas_tx_gas_limit_exceeds_regular_remaining(
527+
blockchain_test: BlockchainTestFiller,
528+
pre: Alloc,
529+
fork: Fork,
530+
tx2_gas_limit_equals_block_gas_limit: bool,
531+
) -> None:
532+
"""
533+
Verify a block is valid when a later tx's gas_limit exceeds the
534+
regular budget remaining but its capped regular contribution fits.
535+
"""
536+
gas_limit_cap = fork.transaction_gas_limit_cap()
537+
assert gas_limit_cap is not None
538+
intrinsic_gas = fork.transaction_intrinsic_cost_calculator()()
539+
env = Environment()
540+
block_gas_limit = int(env.gas_limit)
541+
542+
if tx2_gas_limit_equals_block_gas_limit:
543+
tx2_gas_limit = block_gas_limit
544+
else:
545+
tx2_gas_limit = block_gas_limit - intrinsic_gas + 1
546+
547+
assert tx2_gas_limit > gas_limit_cap
548+
assert tx2_gas_limit > block_gas_limit - intrinsic_gas
549+
550+
stop_contract = pre.deploy_contract(code=Op.STOP)
551+
552+
storage = Storage()
553+
sstore_contract = pre.deploy_contract(
554+
code=Op.SSTORE(storage.store_next(1), 1),
555+
)
556+
557+
tx1_regular = intrinsic_gas
558+
tx2_regular, tx2_state = sstore_tx_gas(fork)
559+
expected_gas_used = max(tx1_regular + tx2_regular, tx2_state)
560+
561+
blockchain_test(
562+
pre=pre,
563+
blocks=[
564+
Block(
565+
txs=[
566+
Transaction(
567+
to=stop_contract,
568+
gas_limit=intrinsic_gas,
569+
sender=pre.fund_eoa(),
570+
),
571+
Transaction(
572+
to=sstore_contract,
573+
gas_limit=tx2_gas_limit,
574+
sender=pre.fund_eoa(),
575+
),
576+
],
577+
header_verify=Header(gas_used=expected_gas_used),
578+
),
579+
],
580+
post={sstore_contract: Account(storage=storage)},
581+
)
582+
583+
584+
@pytest.mark.valid_from("EIP8037")
585+
def test_receipt_cumulative_differs_from_header_gas_used(
586+
blockchain_test: BlockchainTestFiller,
587+
pre: Alloc,
588+
fork: Fork,
589+
) -> None:
590+
"""
591+
Verify receipt cumulative_gas_used can diverge from header
592+
gas_used under 2D accounting when state gas dominates.
593+
"""
594+
tx_regular, tx_state = sstore_tx_gas(fork)
595+
num_txs = 3
596+
597+
gas_limit_cap = fork.transaction_gas_limit_cap()
598+
assert gas_limit_cap is not None
599+
tx_gas_limit = gas_limit_cap + fork.sstore_state_gas()
600+
per_tx_gas_used = tx_regular + tx_state
601+
602+
txs: list[Transaction] = []
603+
post: dict = {}
604+
for i in range(num_txs):
605+
storage = Storage()
606+
contract = pre.deploy_contract(
607+
code=Op.SSTORE(storage.store_next(1), 1) + Op.STOP,
608+
)
609+
txs.append(
610+
Transaction(
611+
to=contract,
612+
gas_limit=tx_gas_limit,
613+
sender=pre.fund_eoa(),
614+
expected_receipt=TransactionReceipt(
615+
cumulative_gas_used=(i + 1) * per_tx_gas_used,
616+
),
617+
)
618+
)
619+
post[contract] = Account(storage=storage)
620+
621+
block_regular = num_txs * tx_regular
622+
block_state = num_txs * tx_state
623+
header_gas_used = max(block_regular, block_state)
624+
625+
assert block_state > block_regular
626+
assert header_gas_used < num_txs * per_tx_gas_used
627+
628+
blockchain_test(
629+
pre=pre,
630+
blocks=[
631+
Block(
632+
txs=txs,
633+
header_verify=Header(gas_used=header_gas_used),
634+
),
635+
],
636+
post=post,
637+
)

0 commit comments

Comments
 (0)