Skip to content

test_trailing_tx_admission_at_fork_transition()

Documentation for tests/amsterdam/eip7778_block_gas_accounting_without_refunds/test_fork_transition.py::test_trailing_tx_admission_at_fork_transition@622620d8.

Generate fixtures for these test cases for Amsterdam with:

fill -v tests/amsterdam/eip7778_block_gas_accounting_without_refunds/test_fork_transition.py::test_trailing_tx_admission_at_fork_transition --fork Amsterdam

Pin the block gas allowance flip across the activation boundary.

The block gas limit leaves room for the trailing transaction only when the refund is credited back to the accumulator, so the same shape is accepted before the fork and rejected after it.

Source code in tests/amsterdam/eip7778_block_gas_accounting_without_refunds/test_fork_transition.py
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
@EIPChecklist.BlockLevelConstraint.Test.ForkTransition.AcceptedBeforeFork()
@EIPChecklist.BlockLevelConstraint.Test.ForkTransition.AcceptedAfterFork()
@EIPChecklist.BlockLevelConstraint.Test.ForkTransition.RejectedAfterFork()
@pytest.mark.parametrize(
    "timestamp,block_gas_limit_delta,block_is_invalid",
    [
        pytest.param(PRE_FORK_TIMESTAMP, -1, False, id="accepted_before_fork"),
        pytest.param(POST_FORK_TIMESTAMP, 0, False, id="accepted_after_fork"),
        pytest.param(
            POST_FORK_TIMESTAMP,
            -1,
            True,
            marks=pytest.mark.exception_test,
            id="rejected_after_fork",
        ),
    ],
)
def test_trailing_tx_admission_at_fork_transition(
    blockchain_test: BlockchainTestFiller,
    pre: Alloc,
    fork: TransitionFork,
    timestamp: int,
    block_gas_limit_delta: int,
    block_is_invalid: bool,
) -> None:
    """
    Pin the block gas allowance flip across the activation boundary.

    The block gas limit leaves room for the trailing transaction only
    when the refund is credited back to the accumulator, so the same
    shape is accepted before the fork and rejected after it.
    """
    sub_fork = fork.fork_at(timestamp=timestamp)

    refund_tx = RefundTransaction.build(
        fork=sub_fork,
        sender=pre.fund_eoa(INITIAL_FUND),
        refund_types={RefundTypes.STORAGE_CLEAR},
        refunds_count=REFUNDS_COUNT,
    )
    refund_tx.set_pre(pre)

    receipt_gas_used = refund_tx.expected_receipt.gas_used
    assert receipt_gas_used is not None
    # Without a refund the two accumulators coincide and the boundary is
    # unobservable.
    assert refund_tx.block_execution() > receipt_gas_used, (
        "Parametrization must produce a refund; without one pre- and "
        "post-refund accounting agree"
    )

    stop_address = pre.deterministic_deploy_contract(deploy_code=Op.STOP)
    intrinsic_cost_calc = sub_fork.transaction_intrinsic_cost_calculator()
    # Slack so a post-refund gate admits the trailing tx and still keeps
    # the block within its gas limit, instead of being caught by the
    # header gas_used check.
    trailing_tx_gas_limit = 2 * intrinsic_cost_calc(calldata=b"")
    trailing_tx = Transaction(
        to=stop_address,
        gas_limit=trailing_tx_gas_limit,
        sender=pre.fund_eoa(),
        error=TransactionException.GAS_ALLOWANCE_EXCEEDED
        if block_is_invalid
        else None,
    )

    # Sized against the post-refund accumulator, which only the
    # post-fork rules exceed.
    block_gas_limit = (
        refund_tx.block_execution()
        + trailing_tx_gas_limit
        + block_gas_limit_delta
    )

    blockchain_test(
        pre=pre,
        blocks=[
            Block(
                timestamp=timestamp,
                txs=[refund_tx, trailing_tx],
                gas_limit=block_gas_limit,
                exception=[
                    BlockException.GAS_USED_OVERFLOW,
                    TransactionException.GAS_ALLOWANCE_EXCEEDED,
                ]
                if block_is_invalid
                else None,
            )
        ],
        post=refund_tx.post(pre, block_is_invalid=block_is_invalid),
        genesis_environment=Environment(gas_limit=block_gas_limit),
    )

Parametrized Test Cases

This test generates 3 parametrized test cases across 1 fork.