Skip to content

test_block_gas_used_at_fork_transition()

Documentation for tests/amsterdam/eip7778_block_gas_accounting_without_refunds/test_fork_transition.py::test_block_gas_used_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_block_gas_used_at_fork_transition --fork Amsterdam

Pin the gas a block reports on each side of the activation boundary.

The same refunding transaction shape is sent in a pre-fork and a post-fork block, each with its own sender so the receipt and balance pins stay per-fork. The header reports post-refund gas before the fork and pre-refund gas after it, while the sender is charged the post-refund amount on both sides.

Source code in tests/amsterdam/eip7778_block_gas_accounting_without_refunds/test_fork_transition.py
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
@EIPChecklist.BlockLevelConstraint.Test.ForkTransition.AcceptedBeforeFork()
@EIPChecklist.BlockLevelConstraint.Test.ForkTransition.AcceptedAfterFork()
def test_block_gas_used_at_fork_transition(
    blockchain_test: BlockchainTestFiller,
    pre: Alloc,
    fork: TransitionFork,
) -> None:
    """
    Pin the gas a block reports on each side of the activation boundary.

    The same refunding transaction shape is sent in a pre-fork and a
    post-fork block, each with its own sender so the receipt and balance
    pins stay per-fork. The header reports post-refund gas before the
    fork and pre-refund gas after it, while the sender is charged the
    post-refund amount on both sides.
    """
    blocks = []
    post: Dict[Address, Account | None] = {}

    for timestamp in (PRE_FORK_TIMESTAMP, POST_FORK_TIMESTAMP):
        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
        assert refund_tx.block_execution() > receipt_gas_used, (
            "Parametrization must produce a refund; without one pre- and "
            "post-refund accounting agree"
        )

        # EIP-7778 switches the block from the post-refund charge to the
        # pre-refund one; the sender pays the post-refund amount either
        # way.
        expected_gas_used: int
        if timestamp < POST_FORK_TIMESTAMP:
            expected_gas_used = receipt_gas_used
        else:
            expected_gas_used = refund_tx.block_execution()

        blocks.append(
            Block(
                timestamp=timestamp,
                txs=[refund_tx],
                expected_gas_used=expected_gas_used,
            )
        )
        post.update(dict(refund_tx.post(pre).items()))

    blockchain_test(pre=pre, blocks=blocks, post=post)

Parametrized Test Cases

This test generates 1 parametrized test case across 1 fork.