Skip to content

test_set_code_to_system_contract()

Documentation for tests/prague/eip7702_set_code_tx/test_set_code_txs.py::test_set_code_to_system_contract@892e6d1e.

Generate fixtures for these test cases for Amsterdam with:

fill -v tests/prague/eip7702_set_code_tx/test_set_code_txs.py::test_set_code_to_system_contract --fork Amsterdam

Test setting the code of an account to a system contract.

Source code in tests/prague/eip7702_set_code_tx/test_set_code_txs.py
3179
3180
3181
3182
3183
3184
3185
3186
3187
3188
3189
3190
3191
3192
3193
3194
3195
3196
3197
3198
3199
3200
3201
3202
3203
3204
3205
3206
3207
3208
3209
3210
3211
3212
3213
3214
3215
3216
3217
3218
3219
3220
3221
3222
3223
3224
3225
3226
3227
3228
3229
3230
3231
3232
3233
3234
3235
3236
3237
3238
3239
3240
3241
3242
3243
3244
3245
3246
3247
3248
3249
3250
3251
3252
3253
3254
3255
3256
3257
3258
3259
3260
3261
3262
3263
3264
3265
3266
3267
3268
3269
3270
3271
3272
3273
3274
3275
3276
3277
3278
3279
3280
3281
3282
3283
3284
3285
3286
3287
3288
3289
3290
3291
3292
3293
3294
3295
3296
3297
3298
3299
3300
3301
3302
3303
3304
3305
3306
3307
3308
3309
3310
3311
3312
3313
3314
3315
3316
3317
3318
3319
3320
3321
3322
3323
3324
3325
3326
3327
3328
3329
3330
3331
3332
3333
3334
3335
3336
3337
3338
3339
3340
3341
3342
3343
3344
3345
@pytest.mark.with_all_call_opcodes(
    selector=(
        lambda opcode: (
            opcode
            not in [
                Op.STATICCALL,
                Op.CALLCODE,
                Op.DELEGATECALL,
            ]
        )
    )
)
@pytest.mark.with_all_system_contracts
def test_set_code_to_system_contract(
    blockchain_test: BlockchainTestFiller,
    pre: Alloc,
    fork: Fork,
    system_contract: int,
    call_opcode: Op,
) -> None:
    """Test setting the code of an account to a system contract."""
    caller_code_storage = Storage()
    call_return_code_slot = caller_code_storage.store_next(
        call_return_code(
            opcode=call_opcode,
            success=True,
        )
    )
    call_return_data_size_slot = caller_code_storage.store_next(0)

    call_value = 0

    # Setup the initial storage of the account to mimic the system contract if
    # required
    match system_contract:
        case Address(0x00000000219AB540356CBB839CBE05303D7705FA):  # EIP-6110
            # Deposit contract needs specific storage values, so we set them on
            # the account
            auth_signer = pre.fund_eoa(
                auth_account_start_balance,
                storage=deposit_contract_initial_storage(),
            )
        case Address(0x000F3DF6D732807EF1319FB7B8BB8522D0BEAC02):  # EIP-4788
            auth_signer = pre.fund_eoa(
                auth_account_start_balance, storage=Storage({1: 1})
            )
        case _:
            # Pre-fund without storage
            auth_signer = pre.fund_eoa(auth_account_start_balance)

    # Fabricate the payload for the system contract
    match system_contract:
        case Address(0x000F3DF6D732807EF1319FB7B8BB8522D0BEAC02):  # EIP-4788
            caller_payload = Hash(1)
            caller_code_storage[call_return_data_size_slot] = 32
        case Address(0x00000000219AB540356CBB839CBE05303D7705FA):  # EIP-6110
            # Fabricate a valid deposit request to the set-code account
            deposit_request = DepositRequest(
                pubkey=0x01,
                withdrawal_credentials=0x02,
                amount=1_000_000_000,
                signature=0x03,
                index=0x0,
            )
            caller_payload = deposit_request.calldata
            call_value = deposit_request.value
        case Address(0x00000961EF480EB55E80D19AD83579A64C007002):  # EIP-7002
            # Fabricate a valid withdrawal request to the set-code account
            withdrawal_request = WithdrawalRequest(
                source_address=0x01,
                validator_pubkey=0x02,
                amount=0x03,
                fee=0x01,
            )
            caller_payload = withdrawal_request.calldata
            call_value = withdrawal_request.value
        case Address(0x0000BBDDC7CE488642FB579F8B00F3A590007251):  # EIP-7251
            # Fabricate a valid consolidation request to the set-code account
            consolidation_request = ConsolidationRequest(
                source_address=0x01,
                source_pubkey=0x02,
                target_pubkey=0x03,
                fee=0x01,
            )
            caller_payload = consolidation_request.calldata
            call_value = consolidation_request.value
        case Address(0x0000F90827F1C53A10CB7A02335B175320002935):  # EIP-2935
            # This payload is used to identify the number of blocks to be
            # subtracted from the latest block number
            caller_payload = Hash(1)
            caller_code_storage[call_return_data_size_slot] = 32
        case _:
            raise ValueError(
                f"Not implemented system contract: {system_contract}"
            )

    # Setup the code to call the system contract
    match system_contract:
        case Address(0x0000F90827F1C53A10CB7A02335B175320002935):  # EIP-2935
            # Do a trick here to get the block number of the penultimate block
            # to ensure it is saved in the history contract
            check_block_number = Op.SUB(Op.NUMBER, Op.CALLDATALOAD(0))
            call_system_contract_code = Op.MSTORE(
                0, check_block_number
            ) + Op.SSTORE(
                call_return_code_slot,
                call_opcode(
                    address=auth_signer, value=call_value, args_size=32
                ),
            )
        case _:
            # Call another system contract with fabricated payload
            call_system_contract_code = Op.CALLDATACOPY(
                0, 0, Op.CALLDATASIZE
            ) + Op.SSTORE(
                call_return_code_slot,
                call_opcode(
                    address=auth_signer,
                    value=call_value,
                    args_size=Op.CALLDATASIZE,
                ),
            )

    caller_code = (
        call_system_contract_code
        + Op.SSTORE(call_return_data_size_slot, Op.RETURNDATASIZE)
        + Op.STOP
    )
    caller_code_address = pre.deploy_contract(caller_code)
    sender = pre.fund_eoa()

    txs = [
        Transaction(
            sender=sender,
            gas_limit=500_000,
            to=caller_code_address,
            value=call_value,
            data=caller_payload,
            authorization_list=[
                AuthorizationTuple(
                    address=Address(system_contract),
                    nonce=auth_signer.nonce,
                    signer=auth_signer,
                ),
            ],
        )
    ]

    blockchain_test(
        pre=pre,
        blocks=[
            Block(
                txs=txs,
                requests_hash=Requests(),  # Verify nothing slipped into the
                # requests trie
            )
        ],
        post={
            auth_signer: Account(
                nonce=auth_signer.nonce + 1,
                code=Spec.delegation_designation(Address(system_contract)),
            ),
            caller_code_address: Account(
                storage=caller_code_storage,
            ),
        },
    )

Parametrized Test Cases

This test generates 5 parametrized test cases across 3 forks.