|
22 | 22 | Op, |
23 | 23 | Storage, |
24 | 24 | Transaction, |
| 25 | + TransactionException, |
| 26 | + TransactionReceipt, |
25 | 27 | ) |
26 | 28 |
|
27 | 29 | from .spec import ref_spec_8037 |
@@ -466,3 +468,170 @@ def test_multi_block_dimension_flip( |
466 | 468 | ], |
467 | 469 | post=post_2, |
468 | 470 | ) |
| 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