ethereum.forks.amsterdam.vm.instructions.system

Ethereum Virtual Machine (EVM) System Instructions.

.. contents:: Table of Contents :backlinks: none :local:

Introduction

Implementations of the EVM system related instructions.

generic_create

Core logic used by the CREATE* family of opcodes.

def generic_create(evm: Evm, ​​endowment: U256, ​​contract_address: Address, ​​memory_start_position: U256, ​​memory_size: U256) -> None:
73
    <snip>
76
    # This import causes a circular import error
77
    # if it's not moved inside this method
78
    from ...vm.interpreter import (
79
        MAX_INIT_CODE_SIZE,
80
        STACK_DEPTH_LIMIT,
81
        process_create_message,
82
    )
83
84
    # Check max init code size early before memory read
85
    if memory_size > U256(MAX_INIT_CODE_SIZE):
86
        raise OutOfGasError
87
88
    # Charge state gas for account creation (pay-before-execute).
89
    # Refunded to the reservoir on any failure path below.
90
    charge_state_gas(evm, StateGasCosts.NEW_ACCOUNT)
91
92
    tx_state = evm.message.tx_env.state
93
94
    call_data = memory_read_bytes(
95
        evm.memory, memory_start_position, memory_size
96
    )
97
98
    create_message_gas = max_message_call_gas(Uint(evm.gas_left))
99
    evm.gas_left -= create_message_gas
100
101
    # Move full reservoir to child (no 63/64 rule for state gas). Parent's
102
    # `state_gas_left` is zeroed and restored when the child returns.
103
    create_message_state_gas_reservoir = evm.state_gas_left
104
    evm.state_gas_left = Uint(0)
105
106
    evm.return_data = b""
107
108
    sender_address = evm.message.current_target
109
    sender = get_account(tx_state, sender_address)
110
111
    if (
112
        sender.balance < endowment
113
        or sender.nonce == Uint(2**64 - 1)
114
        or evm.message.depth + Uint(1) > STACK_DEPTH_LIMIT
115
    ):
116
        evm.gas_left += create_message_gas
117
        evm.state_gas_left += create_message_state_gas_reservoir
118
        credit_state_gas_refund(evm, StateGasCosts.NEW_ACCOUNT)
119
        push(evm.stack, U256(0))
120
        return
121
122
    evm.accessed_addresses.add(contract_address)
123
124
    if not account_deployable(tx_state, contract_address):
125
        increment_nonce(tx_state, evm.message.current_target)
126
        evm.regular_gas_used += create_message_gas
127
        evm.state_gas_left += create_message_state_gas_reservoir
128
        # Address collision — no account created, refund state gas.
129
        credit_state_gas_refund(evm, StateGasCosts.NEW_ACCOUNT)
130
        push(evm.stack, U256(0))
131
        return
132
133
    increment_nonce(tx_state, evm.message.current_target)
134
135
    child_message = Message(
136
        block_env=evm.message.block_env,
137
        tx_env=evm.message.tx_env,
138
        caller=evm.message.current_target,
139
        target=Bytes0(),
140
        gas=create_message_gas,
141
        state_gas_reservoir=create_message_state_gas_reservoir,
142
        value=endowment,
143
        data=b"",
144
        code=call_data,
145
        current_target=contract_address,
146
        depth=evm.message.depth + Uint(1),
147
        code_address=None,
148
        should_transfer_value=True,
149
        is_static=False,
150
        accessed_addresses=evm.accessed_addresses.copy(),
151
        accessed_storage_keys=evm.accessed_storage_keys.copy(),
152
        disable_precompiles=False,
153
        parent_evm=evm,
154
    )
155
    child_evm = process_create_message(child_message)
156
157
    if child_evm.error:
158
        incorporate_child_on_error(evm, child_evm)
159
        # No account created, refund parent's CREATE state gas.
160
        credit_state_gas_refund(evm, StateGasCosts.NEW_ACCOUNT)
161
        evm.return_data = child_evm.output
162
        push(evm.stack, U256(0))
163
    else:
164
        incorporate_child_on_success(evm, child_evm)
165
        evm.return_data = b""
166
        push(evm.stack, U256.from_be_bytes(child_evm.message.current_target))

create

Creates a new account with associated code.

Parameters

evm : The current EVM frame.

def create(evm: Evm) -> None:
170
    <snip>
179
    if evm.message.is_static:
180
        raise WriteInStaticContext
181
182
    # STACK
183
    endowment = pop(evm.stack)
184
    memory_start_position = pop(evm.stack)
185
    memory_size = pop(evm.stack)
186
187
    # GAS
188
    extend_memory = calculate_gas_extend_memory(
189
        evm.memory, [(memory_start_position, memory_size)]
190
    )
191
    init_code_gas = init_code_cost(Uint(memory_size))
192
    charge_gas(
193
        evm,
194
        GasCosts.REGULAR_GAS_CREATE + extend_memory.cost + init_code_gas,
195
    )
196
197
    # OPERATION
198
    evm.memory += b"\x00" * extend_memory.expand_by
199
    contract_address = compute_contract_address(
200
        evm.message.current_target,
201
        get_account(
202
            evm.message.tx_env.state, evm.message.current_target
203
        ).nonce,
204
    )
205
206
    generic_create(
207
        evm,
208
        endowment,
209
        contract_address,
210
        memory_start_position,
211
        memory_size,
212
    )
213
214
    # PROGRAM COUNTER
215
    evm.pc += Uint(1)

create2

Creates a new account with associated code.

It's similar to the CREATE opcode except that the address of the new account depends on the init_code instead of the nonce of sender.

Parameters

evm : The current EVM frame.

def create2(evm: Evm) -> None:
219
    <snip>
231
    if evm.message.is_static:
232
        raise WriteInStaticContext
233
234
    # STACK
235
    endowment = pop(evm.stack)
236
    memory_start_position = pop(evm.stack)
237
    memory_size = pop(evm.stack)
238
    salt = pop(evm.stack).to_be_bytes32()
239
240
    # GAS
241
    extend_memory = calculate_gas_extend_memory(
242
        evm.memory, [(memory_start_position, memory_size)]
243
    )
244
    call_data_words = ceil32(Uint(memory_size)) // Uint(32)
245
    init_code_gas = init_code_cost(Uint(memory_size))
246
    charge_gas(
247
        evm,
248
        GasCosts.REGULAR_GAS_CREATE
249
        + GasCosts.OPCODE_KECCAK256_PER_WORD * call_data_words
250
        + extend_memory.cost
251
        + init_code_gas,
252
    )
253
254
    # OPERATION
255
    evm.memory += b"\x00" * extend_memory.expand_by
256
    contract_address = compute_create2_contract_address(
257
        evm.message.current_target,
258
        salt,
259
        memory_read_bytes(evm.memory, memory_start_position, memory_size),
260
    )
261
262
    generic_create(
263
        evm,
264
        endowment,
265
        contract_address,
266
        memory_start_position,
267
        memory_size,
268
    )
269
270
    # PROGRAM COUNTER
271
    evm.pc += Uint(1)

return_

Halts execution returning output data.

Parameters

evm : The current EVM frame.

def return_(evm: Evm) -> None:
275
    <snip>
284
    # STACK
285
    memory_start_position = pop(evm.stack)
286
    memory_size = pop(evm.stack)
287
288
    # GAS
289
    extend_memory = calculate_gas_extend_memory(
290
        evm.memory, [(memory_start_position, memory_size)]
291
    )
292
293
    charge_gas(evm, GasCosts.ZERO + extend_memory.cost)
294
295
    # OPERATION
296
    evm.memory += b"\x00" * extend_memory.expand_by
297
    evm.output = memory_read_bytes(
298
        evm.memory, memory_start_position, memory_size
299
    )
300
301
    evm.running = False
302
303
    # PROGRAM COUNTER
304
    pass

GenericCall

Parameters for the core logic of the CALL* family of opcodes.

307
@final
308
@dataclass
class GenericCall:

gas

314
    gas: Uint

state_gas_reservoir

315
    state_gas_reservoir: Uint

value

316
    value: U256

caller

317
    caller: Address

to

318
    to: Address

code_address

319
    code_address: Address

should_transfer_value

320
    should_transfer_value: bool

is_staticcall

321
    is_staticcall: bool

memory_input_start_position

322
    memory_input_start_position: U256

memory_input_size

323
    memory_input_size: U256

memory_output_start_position

324
    memory_output_start_position: U256

memory_output_size

325
    memory_output_size: U256

code

326
    code: Bytes

disable_precompiles

327
    disable_precompiles: bool

generic_call

Perform the core logic of the CALL* family of opcodes.

def generic_call(evm: Evm, ​​params: GenericCall) -> None:
331
    <snip>
334
    from ...vm.interpreter import STACK_DEPTH_LIMIT, process_message
335
336
    evm.return_data = b""
337
338
    if evm.message.depth + Uint(1) > STACK_DEPTH_LIMIT:
339
        evm.gas_left += params.gas
340
        evm.state_gas_left += params.state_gas_reservoir
341
        push(evm.stack, U256(0))
342
        return
343
344
    call_data = memory_read_bytes(
345
        evm.memory,
346
        params.memory_input_start_position,
347
        params.memory_input_size,
348
    )
349
350
    child_message = Message(
351
        block_env=evm.message.block_env,
352
        tx_env=evm.message.tx_env,
353
        caller=params.caller,
354
        target=params.to,
355
        gas=params.gas,
356
        state_gas_reservoir=params.state_gas_reservoir,
357
        value=params.value,
358
        data=call_data,
359
        code=params.code,
360
        current_target=params.to,
361
        depth=evm.message.depth + Uint(1),
362
        code_address=params.code_address,
363
        should_transfer_value=params.should_transfer_value,
364
        is_static=params.is_staticcall or evm.message.is_static,
365
        accessed_addresses=evm.accessed_addresses.copy(),
366
        accessed_storage_keys=evm.accessed_storage_keys.copy(),
367
        disable_precompiles=params.disable_precompiles,
368
        parent_evm=evm,
369
    )
370
371
    child_evm = process_message(child_message)
372
373
    if child_evm.error:
374
        incorporate_child_on_error(evm, child_evm)
375
        evm.return_data = child_evm.output
376
        push(evm.stack, U256(0))
377
    else:
378
        incorporate_child_on_success(evm, child_evm)
379
        evm.return_data = child_evm.output
380
        push(evm.stack, CALL_SUCCESS)
381
382
    actual_output_size = min(
383
        params.memory_output_size, U256(len(child_evm.output))
384
    )
385
    memory_write(
386
        evm.memory,
387
        params.memory_output_start_position,
388
        child_evm.output[:actual_output_size],
389
    )

call

Message-call into an account.

Parameters

evm : The current EVM frame.

def call(evm: Evm) -> None:
393
    <snip>
402
    # STACK
403
    gas = Uint(pop(evm.stack))
404
    to = to_address_masked(pop(evm.stack))
405
    value = pop(evm.stack)
406
    memory_input_start_position = pop(evm.stack)
407
    memory_input_size = pop(evm.stack)
408
    memory_output_start_position = pop(evm.stack)
409
    memory_output_size = pop(evm.stack)
410
411
    if evm.message.is_static and value != U256(0):
412
        raise WriteInStaticContext
413
414
    # GAS
415
    extend_memory = calculate_gas_extend_memory(
416
        evm.memory,
417
        [
418
            (memory_input_start_position, memory_input_size),
419
            (memory_output_start_position, memory_output_size),
420
        ],
421
    )
422
423
    is_cold_access = to not in evm.accessed_addresses
424
    if is_cold_access:
425
        access_gas_cost = GasCosts.COLD_ACCOUNT_ACCESS
426
    else:
427
        access_gas_cost = GasCosts.WARM_ACCESS
428
429
    transfer_gas_cost = Uint(0) if value == 0 else GasCosts.CALL_VALUE
430
431
    # check static gas before state access
432
    check_gas(
433
        evm,
434
        access_gas_cost + transfer_gas_cost + extend_memory.cost,
435
    )
436
437
    # STATE ACCESS
438
    tx_state = evm.message.tx_env.state
439
    if is_cold_access:
440
        evm.accessed_addresses.add(to)
441
442
    extra_gas = access_gas_cost + transfer_gas_cost
443
    (
444
        is_delegated,
445
        code_address,
446
        delegation_access_cost,
447
    ) = calculate_delegation_cost(evm, to)
448
449
    if is_delegated:
450
        # check enough gas for delegation access
451
        extra_gas += delegation_access_cost
452
        check_gas(evm, extra_gas + extend_memory.cost)
453
        if code_address not in evm.accessed_addresses:
454
            evm.accessed_addresses.add(code_address)
455
456
    code_hash = get_account(tx_state, code_address).code_hash
457
    code = get_code(tx_state, code_hash)
458
459
    charge_gas(evm, extra_gas + extend_memory.cost)
460
    if value != 0 and not is_account_alive(tx_state, to):
461
        charge_state_gas(evm, StateGasCosts.NEW_ACCOUNT)
462
463
    message_call_gas = calculate_message_call_gas(
464
        value,
465
        gas,
466
        Uint(evm.gas_left),
467
        memory_cost=Uint(0),
468
        extra_gas=Uint(0),
469
    )
470
    charge_gas(evm, message_call_gas.cost)
471
    evm.regular_gas_used -= message_call_gas.sub_call
472
473
    # OPERATION
474
    evm.memory += b"\x00" * extend_memory.expand_by
475
476
    # Pass full reservoir to child (no 63/64 rule for state gas)
477
    call_state_gas_reservoir = evm.state_gas_left
478
    evm.state_gas_left = Uint(0)
479
480
    sender_balance = get_account(tx_state, evm.message.current_target).balance
481
    if sender_balance < value:
482
        push(evm.stack, U256(0))
483
        evm.return_data = b""
484
        evm.gas_left += message_call_gas.sub_call
485
        evm.state_gas_left += call_state_gas_reservoir
486
    else:
487
        generic_call(
488
            evm,
489
            GenericCall(
490
                gas=message_call_gas.sub_call,
491
                state_gas_reservoir=call_state_gas_reservoir,
492
                value=value,
493
                caller=evm.message.current_target,
494
                to=to,
495
                code_address=code_address,
496
                should_transfer_value=True,
497
                is_staticcall=False,
498
                memory_input_start_position=memory_input_start_position,
499
                memory_input_size=memory_input_size,
500
                memory_output_start_position=memory_output_start_position,
501
                memory_output_size=memory_output_size,
502
                code=code,
503
                disable_precompiles=is_delegated,
504
            ),
505
        )
506
507
    # PROGRAM COUNTER
508
    evm.pc += Uint(1)

callcode

Message-call into this account with alternative account's code.

Parameters

evm : The current EVM frame.

def callcode(evm: Evm) -> None:
512
    <snip>
521
    # STACK
522
    gas = Uint(pop(evm.stack))
523
    code_address = to_address_masked(pop(evm.stack))
524
    value = pop(evm.stack)
525
    memory_input_start_position = pop(evm.stack)
526
    memory_input_size = pop(evm.stack)
527
    memory_output_start_position = pop(evm.stack)
528
    memory_output_size = pop(evm.stack)
529
530
    # GAS
531
    to = evm.message.current_target
532
533
    extend_memory = calculate_gas_extend_memory(
534
        evm.memory,
535
        [
536
            (memory_input_start_position, memory_input_size),
537
            (memory_output_start_position, memory_output_size),
538
        ],
539
    )
540
541
    is_cold_access = code_address not in evm.accessed_addresses
542
    if is_cold_access:
543
        access_gas_cost = GasCosts.COLD_ACCOUNT_ACCESS
544
    else:
545
        access_gas_cost = GasCosts.WARM_ACCESS
546
547
    transfer_gas_cost = Uint(0) if value == 0 else GasCosts.CALL_VALUE
548
549
    # check static gas before state access
550
    check_gas(
551
        evm,
552
        access_gas_cost + extend_memory.cost + transfer_gas_cost,
553
    )
554
555
    # STATE ACCESS
556
    tx_state = evm.message.tx_env.state
557
    if is_cold_access:
558
        evm.accessed_addresses.add(code_address)
559
560
    extra_gas = access_gas_cost + transfer_gas_cost
561
    (
562
        is_delegated,
563
        code_address,
564
        delegation_access_cost,
565
    ) = calculate_delegation_cost(evm, code_address)
566
567
    if is_delegated:
568
        # check enough gas for delegation access
569
        extra_gas += delegation_access_cost
570
        check_gas(evm, extra_gas + extend_memory.cost)
571
        if code_address not in evm.accessed_addresses:
572
            evm.accessed_addresses.add(code_address)
573
574
    code_hash = get_account(tx_state, code_address).code_hash
575
    code = get_code(tx_state, code_hash)
576
577
    message_call_gas = calculate_message_call_gas(
578
        value,
579
        gas,
580
        Uint(evm.gas_left),
581
        extend_memory.cost,
582
        extra_gas,
583
    )
584
    charge_gas(evm, message_call_gas.cost + extend_memory.cost)
585
    evm.regular_gas_used -= message_call_gas.sub_call
586
587
    # OPERATION
588
    evm.memory += b"\x00" * extend_memory.expand_by
589
590
    # Pass full reservoir to child (no 63/64 rule for state gas)
591
    call_state_gas_reservoir = evm.state_gas_left
592
    evm.state_gas_left = Uint(0)
593
594
    sender_balance = get_account(tx_state, evm.message.current_target).balance
595
596
    if sender_balance < value:
597
        push(evm.stack, U256(0))
598
        evm.return_data = b""
599
        evm.gas_left += message_call_gas.sub_call
600
        evm.state_gas_left += call_state_gas_reservoir
601
    else:
602
        generic_call(
603
            evm,
604
            GenericCall(
605
                gas=message_call_gas.sub_call,
606
                state_gas_reservoir=call_state_gas_reservoir,
607
                value=value,
608
                caller=evm.message.current_target,
609
                to=to,
610
                code_address=code_address,
611
                should_transfer_value=True,
612
                is_staticcall=False,
613
                memory_input_start_position=memory_input_start_position,
614
                memory_input_size=memory_input_size,
615
                memory_output_start_position=memory_output_start_position,
616
                memory_output_size=memory_output_size,
617
                code=code,
618
                disable_precompiles=is_delegated,
619
            ),
620
        )
621
622
    # PROGRAM COUNTER
623
    evm.pc += Uint(1)

selfdestruct

Halt execution and register account for later deletion.

Parameters

evm : The current EVM frame.

def selfdestruct(evm: Evm) -> None:
627
    <snip>
636
    if evm.message.is_static:
637
        raise WriteInStaticContext
638
639
    # STACK
640
    beneficiary = to_address_masked(pop(evm.stack))
641
642
    # GAS
643
    gas_cost = GasCosts.OPCODE_SELFDESTRUCT_BASE
644
645
    is_cold_access = beneficiary not in evm.accessed_addresses
646
    if is_cold_access:
647
        gas_cost += GasCosts.COLD_ACCOUNT_ACCESS
648
649
    # check access gas cost before state access
650
    check_gas(evm, gas_cost)
651
652
    # STATE ACCESS
653
    tx_state = evm.message.tx_env.state
654
    if is_cold_access:
655
        evm.accessed_addresses.add(beneficiary)
656
657
    state_gas = Uint(0)
658
    if (
659
        not is_account_alive(tx_state, beneficiary)
660
        and get_account(tx_state, evm.message.current_target).balance != 0
661
    ):
662
        state_gas = StateGasCosts.NEW_ACCOUNT
663
664
    # Charge regular gas before state gas so that a regular-gas OOG
665
    # does not consume state gas that would inflate the parent's
666
    # reservoir on frame failure.
667
    charge_gas(evm, gas_cost)
668
    charge_state_gas(evm, state_gas)
669
670
    originator = evm.message.current_target
671
    originator_balance = get_account(tx_state, originator).balance
672
673
    # Transfer balance
674
    move_ether(tx_state, originator, beneficiary, originator_balance)
675
676
    # Emit transfer or burn log
677
    if originator in tx_state.created_accounts and beneficiary == originator:
678
        emit_burn_log(evm, originator, originator_balance)
679
    elif beneficiary != originator:
680
        emit_transfer_log(evm, originator, beneficiary, originator_balance)
681
682
    # Register account for deletion iff created in same transaction
683
    if originator in tx_state.created_accounts:
684
        # If beneficiary and originator are the same then the ether is burnt.
685
        set_account_balance(tx_state, originator, U256(0))
686
        evm.accounts_to_delete.add(originator)
687
688
    # HALT the execution
689
    evm.running = False
690
691
    # PROGRAM COUNTER
692
    pass

delegatecall

Message-call into an account.

Parameters

evm : The current EVM frame.

def delegatecall(evm: Evm) -> None:
696
    <snip>
705
    # STACK
706
    gas = Uint(pop(evm.stack))
707
    code_address = to_address_masked(pop(evm.stack))
708
    memory_input_start_position = pop(evm.stack)
709
    memory_input_size = pop(evm.stack)
710
    memory_output_start_position = pop(evm.stack)
711
    memory_output_size = pop(evm.stack)
712
713
    # GAS
714
    extend_memory = calculate_gas_extend_memory(
715
        evm.memory,
716
        [
717
            (memory_input_start_position, memory_input_size),
718
            (memory_output_start_position, memory_output_size),
719
        ],
720
    )
721
722
    is_cold_access = code_address not in evm.accessed_addresses
723
    if is_cold_access:
724
        access_gas_cost = GasCosts.COLD_ACCOUNT_ACCESS
725
    else:
726
        access_gas_cost = GasCosts.WARM_ACCESS
727
728
    # check static gas before state access
729
    check_gas(evm, access_gas_cost + extend_memory.cost)
730
731
    # STATE ACCESS
732
    if is_cold_access:
733
        evm.accessed_addresses.add(code_address)
734
735
    extra_gas = access_gas_cost
736
    (
737
        is_delegated,
738
        code_address,
739
        delegation_access_cost,
740
    ) = calculate_delegation_cost(evm, code_address)
741
742
    if is_delegated:
743
        # check enough gas for delegation access
744
        extra_gas += delegation_access_cost
745
        check_gas(evm, extra_gas + extend_memory.cost)
746
        if code_address not in evm.accessed_addresses:
747
            evm.accessed_addresses.add(code_address)
748
749
    tx_state = evm.message.tx_env.state
750
    code_hash = get_account(tx_state, code_address).code_hash
751
    code = get_code(tx_state, code_hash)
752
753
    message_call_gas = calculate_message_call_gas(
754
        U256(0),
755
        gas,
756
        Uint(evm.gas_left),
757
        extend_memory.cost,
758
        extra_gas,
759
    )
760
    charge_gas(evm, message_call_gas.cost + extend_memory.cost)
761
    evm.regular_gas_used -= message_call_gas.sub_call
762
763
    # OPERATION
764
    evm.memory += b"\x00" * extend_memory.expand_by
765
766
    # Pass full reservoir to child (no 63/64 rule for state gas)
767
    call_state_gas_reservoir = evm.state_gas_left
768
    evm.state_gas_left = Uint(0)
769
770
    generic_call(
771
        evm,
772
        GenericCall(
773
            gas=message_call_gas.sub_call,
774
            state_gas_reservoir=call_state_gas_reservoir,
775
            value=evm.message.value,
776
            caller=evm.message.caller,
777
            to=evm.message.current_target,
778
            code_address=code_address,
779
            should_transfer_value=False,
780
            is_staticcall=False,
781
            memory_input_start_position=memory_input_start_position,
782
            memory_input_size=memory_input_size,
783
            memory_output_start_position=memory_output_start_position,
784
            memory_output_size=memory_output_size,
785
            code=code,
786
            disable_precompiles=is_delegated,
787
        ),
788
    )
789
790
    # PROGRAM COUNTER
791
    evm.pc += Uint(1)

staticcall

Message-call into an account.

Parameters

evm : The current EVM frame.

def staticcall(evm: Evm) -> None:
795
    <snip>
804
    # STACK
805
    gas = Uint(pop(evm.stack))
806
    to = to_address_masked(pop(evm.stack))
807
    memory_input_start_position = pop(evm.stack)
808
    memory_input_size = pop(evm.stack)
809
    memory_output_start_position = pop(evm.stack)
810
    memory_output_size = pop(evm.stack)
811
812
    # GAS
813
    extend_memory = calculate_gas_extend_memory(
814
        evm.memory,
815
        [
816
            (memory_input_start_position, memory_input_size),
817
            (memory_output_start_position, memory_output_size),
818
        ],
819
    )
820
821
    is_cold_access = to not in evm.accessed_addresses
822
    if is_cold_access:
823
        access_gas_cost = GasCosts.COLD_ACCOUNT_ACCESS
824
    else:
825
        access_gas_cost = GasCosts.WARM_ACCESS
826
827
    # check static gas before state access
828
    check_gas(evm, access_gas_cost + extend_memory.cost)
829
830
    # STATE ACCESS
831
    if is_cold_access:
832
        evm.accessed_addresses.add(to)
833
834
    extra_gas = access_gas_cost
835
    (
836
        is_delegated,
837
        code_address,
838
        delegation_access_cost,
839
    ) = calculate_delegation_cost(evm, to)
840
841
    if is_delegated:
842
        # check enough gas for delegation access
843
        extra_gas += delegation_access_cost
844
        check_gas(evm, extra_gas + extend_memory.cost)
845
        if code_address not in evm.accessed_addresses:
846
            evm.accessed_addresses.add(code_address)
847
848
    tx_state = evm.message.tx_env.state
849
    code_hash = get_account(tx_state, code_address).code_hash
850
    code = get_code(tx_state, code_hash)
851
852
    message_call_gas = calculate_message_call_gas(
853
        U256(0),
854
        gas,
855
        Uint(evm.gas_left),
856
        extend_memory.cost,
857
        extra_gas,
858
    )
859
    charge_gas(evm, message_call_gas.cost + extend_memory.cost)
860
    evm.regular_gas_used -= message_call_gas.sub_call
861
862
    # OPERATION
863
    evm.memory += b"\x00" * extend_memory.expand_by
864
865
    # Pass full reservoir to child (no 63/64 rule for state gas)
866
    call_state_gas_reservoir = evm.state_gas_left
867
    evm.state_gas_left = Uint(0)
868
869
    generic_call(
870
        evm,
871
        GenericCall(
872
            gas=message_call_gas.sub_call,
873
            state_gas_reservoir=call_state_gas_reservoir,
874
            value=U256(0),
875
            caller=evm.message.current_target,
876
            to=to,
877
            code_address=code_address,
878
            should_transfer_value=True,
879
            is_staticcall=True,
880
            memory_input_start_position=memory_input_start_position,
881
            memory_input_size=memory_input_size,
882
            memory_output_start_position=memory_output_start_position,
883
            memory_output_size=memory_output_size,
884
            code=code,
885
            disable_precompiles=is_delegated,
886
        ),
887
    )
888
889
    # PROGRAM COUNTER
890
    evm.pc += Uint(1)

revert

Stop execution and revert state changes, without consuming all provided gas and also has the ability to return a reason.

Parameters

evm : The current EVM frame.

def revert(evm: Evm) -> None:
894
    <snip>
904
    # STACK
905
    memory_start_index = pop(evm.stack)
906
    size = pop(evm.stack)
907
908
    # GAS
909
    extend_memory = calculate_gas_extend_memory(
910
        evm.memory, [(memory_start_index, size)]
911
    )
912
913
    charge_gas(evm, extend_memory.cost)
914
915
    # OPERATION
916
    evm.memory += b"\x00" * extend_memory.expand_by
917
    output = memory_read_bytes(evm.memory, memory_start_index, size)
918
    evm.output = Bytes(output)
919
    raise Revert
920
921
    # PROGRAM COUNTER
922
    # no-op