EIP-6780: a same-tx-created contract sends value to a fresh
beneficiary, charged ACCOUNT_WRITE and creation state gas.
A creation transaction whose initcode SELFDESTRUCTs the new contract
to a fresh Address(0xDEAD): the fresh, non-existent beneficiary
receives a positive balance, so account_new is true —
execution = OPCODE_SELFDESTRUCT_BASE + COLD_ACCOUNT_ACCESS +
ACCOUNT_WRITE plus a beneficiary NEW_ACCOUNT on the state
axis. The
beneficiary creation charge keys on the beneficiary, while the
originator (created in this transaction) is still deleted: a
Transfer log is emitted (not a Burn).
The net state gas is a single beneficiary NEW_ACCOUNT: the
intrinsic creation NEW_ACCOUNT is refunded because the pre-funded
created target is alive at message entry (EIP-8037), while the fresh
beneficiary's NEW_ACCOUNT persists.
Source code in tests/amsterdam/eip8038_state_access_gas_cost_increase/test_selfdestruct_gas.py
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632 | @EIPChecklist.GasCostChanges.Test.GasUpdatesMeasurement()
@pytest.mark.pre_alloc_mutable()
def test_same_tx_created_selfdestruct_to_fresh_beneficiary(
state_test: StateTestFiller,
pre: Alloc,
fork: Fork,
) -> None:
"""
EIP-6780: a same-tx-created contract sends value to a fresh
beneficiary, charged ``ACCOUNT_WRITE`` and creation state gas.
A creation transaction whose initcode SELFDESTRUCTs the new contract
to a fresh ``Address(0xDEAD)``: the fresh, non-existent beneficiary
receives a positive balance, so ``account_new`` is true —
``execution = OPCODE_SELFDESTRUCT_BASE + COLD_ACCOUNT_ACCESS +
ACCOUNT_WRITE`` plus a beneficiary ``NEW_ACCOUNT`` on the state
axis. The
beneficiary creation charge keys on the beneficiary, while the
originator (created in this transaction) is still deleted: a
``Transfer`` log is emitted (not a ``Burn``).
The net state gas is a single beneficiary ``NEW_ACCOUNT``: the
intrinsic creation ``NEW_ACCOUNT`` is refunded because the pre-funded
created target is alive at message entry (EIP-8037), while the fresh
beneficiary's ``NEW_ACCOUNT`` persists.
"""
intrinsic_calc = fork.transaction_intrinsic_cost_calculator()
amount = 1
beneficiary = Address(0xDEAD) # fresh, non-existent
sender = pre.fund_eoa(amount=10**18)
created = compute_create_address(address=sender, nonce=0)
# Pre-fund the created address so its balance is present without an
# in-tx value transfer (which would emit its own Transfer log). The
# pre-funded target is alive at message entry, so the create-tx
# intrinsic NEW_ACCOUNT is refunded (EIP-8037).
pre.fund_address(created, amount)
# Cold beneficiary receiving value: account_new is true.
init_code = Op.SELFDESTRUCT.with_metadata(
address_warm=False, account_new=True
)(beneficiary)
# The creation NEW_ACCOUNT is refunded (target alive at entry) and is
# not part of the intrinsic under EIP-2780; only the fresh
# beneficiary's NEW_ACCOUNT (the SELFDESTRUCT state cost) persists.
new_account_state_gas = init_code.state_cost(fork)
intrinsic_execution = intrinsic_calc(
calldata=bytes(init_code), contract_creation=True
)
expected_state = new_account_state_gas
expected_execution = intrinsic_execution + init_code.execution_cost(fork)
expected_gas_used = max(expected_execution, expected_state)
tx = Transaction(
to=None,
data=init_code,
sender=sender,
# Reservoir holds the beneficiary-creation state gas (above the
# creation's intrinsic NEW_ACCOUNT) so it does not spill into
# execution gas.
state_gas_reservoir=new_account_state_gas,
expected_receipt=TransactionReceipt(
logs=[transfer_log(created, beneficiary, amount)]
),
)
state_test(
pre=pre,
# Same-tx-created originator is deleted; the fresh beneficiary is
# created and credited the originator balance.
post={
created: Account.NONEXISTENT,
beneficiary: Account(balance=amount),
},
tx=tx,
blockchain_test_header_verify=Header(gas_used=expected_gas_used),
)
|