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:
65
    """
66
    Core logic used by the `CREATE*` family of opcodes.
67
    """
68
    # This import causes a circular import error
69
    # if it's not moved inside this method
70
    from ...vm.interpreter import (
71
        MAX_INIT_CODE_SIZE,
72
        STACK_DEPTH_LIMIT,
73
        process_create_message,
74
    )
75
76
    # Check static context first
77
    if evm.message.is_static:
78
        raise WriteInStaticContext
79
80
    # Check max init code size early before memory read
81
    if memory_size > U256(MAX_INIT_CODE_SIZE):
82
        raise OutOfGasError
83
84
    tx_state = evm.message.tx_env.state
85
86
    call_data = memory_read_bytes(
87
        evm.memory, memory_start_position, memory_size
88
    )
89
90
    create_message_gas = max_message_call_gas(Uint(evm.gas_left))
91
    evm.gas_left -= create_message_gas
92
    evm.return_data = b""
93
94
    sender_address = evm.message.current_target
95
    sender = get_account(tx_state, sender_address)
96
97
    if (
98
        sender.balance < endowment
99
        or sender.nonce == Uint(2**64 - 1)
100
        or evm.message.depth + Uint(1) > STACK_DEPTH_LIMIT
101
    ):
102
        evm.gas_left += create_message_gas
103
        push(evm.stack, U256(0))
104
        return
105
106
    evm.accessed_addresses.add(contract_address)
107
108
    if account_has_code_or_nonce(
109
        tx_state, contract_address
110
    ) or account_has_storage(tx_state, contract_address):
111
        increment_nonce(tx_state, evm.message.current_target)
112
        push(evm.stack, U256(0))
113
        return
114
115
    increment_nonce(tx_state, evm.message.current_target)
116
117
    child_message = Message(
118
        block_env=evm.message.block_env,
119
        tx_env=evm.message.tx_env,
120
        caller=evm.message.current_target,
121
        target=Bytes0(),
122
        gas=create_message_gas,
123
        value=endowment,
124
        data=b"",
125
        code=call_data,
126
        current_target=contract_address,
127
        depth=evm.message.depth + Uint(1),
128
        code_address=None,
129
        should_transfer_value=True,
130
        is_static=False,
131
        accessed_addresses=evm.accessed_addresses.copy(),
132
        accessed_storage_keys=evm.accessed_storage_keys.copy(),
133
        disable_precompiles=False,
134
        parent_evm=evm,
135
    )
136
    child_evm = process_create_message(child_message)
137
138
    if child_evm.error:
139
        incorporate_child_on_error(evm, child_evm)
140
        evm.return_data = child_evm.output
141
        push(evm.stack, U256(0))
142
    else:
143
        incorporate_child_on_success(evm, child_evm)
144
        evm.return_data = b""
145
        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:
149
    """
150
    Creates a new account with associated code.
151
152
    Parameters
153
    ----------
154
    evm :
155
        The current EVM frame.
156
157
    """
158
    # STACK
159
    endowment = pop(evm.stack)
160
    memory_start_position = pop(evm.stack)
161
    memory_size = pop(evm.stack)
162
163
    # GAS
164
    extend_memory = calculate_gas_extend_memory(
165
        evm.memory, [(memory_start_position, memory_size)]
166
    )
167
    init_code_gas = init_code_cost(Uint(memory_size))
168
169
    charge_gas(
170
        evm, GasCosts.OPCODE_CREATE_BASE + extend_memory.cost + init_code_gas
171
    )
172
173
    # OPERATION
174
    evm.memory += b"\x00" * extend_memory.expand_by
175
    contract_address = compute_contract_address(
176
        evm.message.current_target,
177
        get_account(
178
            evm.message.tx_env.state, evm.message.current_target
179
        ).nonce,
180
    )
181
182
    generic_create(
183
        evm,
184
        endowment,
185
        contract_address,
186
        memory_start_position,
187
        memory_size,
188
    )
189
190
    # PROGRAM COUNTER
191
    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:
195
    """
196
    Creates a new account with associated code.
197
198
    It's similar to the CREATE opcode except that the address of the new
199
    account depends on the init_code instead of the nonce of sender.
200
201
    Parameters
202
    ----------
203
    evm :
204
        The current EVM frame.
205
206
    """
207
    # STACK
208
    endowment = pop(evm.stack)
209
    memory_start_position = pop(evm.stack)
210
    memory_size = pop(evm.stack)
211
    salt = pop(evm.stack).to_be_bytes32()
212
213
    # GAS
214
    extend_memory = calculate_gas_extend_memory(
215
        evm.memory, [(memory_start_position, memory_size)]
216
    )
217
    call_data_words = ceil32(Uint(memory_size)) // Uint(32)
218
    init_code_gas = init_code_cost(Uint(memory_size))
219
    charge_gas(
220
        evm,
221
        GasCosts.OPCODE_CREATE_BASE
222
        + GasCosts.OPCODE_KECCACK256_PER_WORD * call_data_words
223
        + extend_memory.cost
224
        + init_code_gas,
225
    )
226
227
    # OPERATION
228
    evm.memory += b"\x00" * extend_memory.expand_by
229
    contract_address = compute_create2_contract_address(
230
        evm.message.current_target,
231
        salt,
232
        memory_read_bytes(evm.memory, memory_start_position, memory_size),
233
    )
234
235
    generic_create(
236
        evm,
237
        endowment,
238
        contract_address,
239
        memory_start_position,
240
        memory_size,
241
    )
242
243
    # PROGRAM COUNTER
244
    evm.pc += Uint(1)

return_

Halts execution returning output data.

Parameters

evm : The current EVM frame.

def return_(evm: Evm) -> None:
248
    """
249
    Halts execution returning output data.
250
251
    Parameters
252
    ----------
253
    evm :
254
        The current EVM frame.
255
256
    """
257
    # STACK
258
    memory_start_position = pop(evm.stack)
259
    memory_size = pop(evm.stack)
260
261
    # GAS
262
    extend_memory = calculate_gas_extend_memory(
263
        evm.memory, [(memory_start_position, memory_size)]
264
    )
265
266
    charge_gas(evm, GasCosts.ZERO + extend_memory.cost)
267
268
    # OPERATION
269
    evm.memory += b"\x00" * extend_memory.expand_by
270
    evm.output = memory_read_bytes(
271
        evm.memory, memory_start_position, memory_size
272
    )
273
274
    evm.running = False
275
276
    # PROGRAM COUNTER
277
    pass

generic_call

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

def generic_call(evm: Evm, ​​gas: Uint, ​​value: U256, ​​caller: Address, ​​to: Address, ​​code_address: Address, ​​should_transfer_value: bool, ​​is_staticcall: bool, ​​memory_input_start_position: U256, ​​memory_input_size: U256, ​​memory_output_start_position: U256, ​​memory_output_size: U256, ​​code: Bytes, ​​disable_precompiles: bool) -> None:
296
    """
297
    Perform the core logic of the `CALL*` family of opcodes.
298
    """
299
    from ...vm.interpreter import STACK_DEPTH_LIMIT, process_message
300
301
    evm.return_data = b""
302
303
    if evm.message.depth + Uint(1) > STACK_DEPTH_LIMIT:
304
        evm.gas_left += gas
305
        push(evm.stack, U256(0))
306
        return
307
308
    call_data = memory_read_bytes(
309
        evm.memory, memory_input_start_position, memory_input_size
310
    )
311
312
    child_message = Message(
313
        block_env=evm.message.block_env,
314
        tx_env=evm.message.tx_env,
315
        caller=caller,
316
        target=to,
317
        gas=gas,
318
        value=value,
319
        data=call_data,
320
        code=code,
321
        current_target=to,
322
        depth=evm.message.depth + Uint(1),
323
        code_address=code_address,
324
        should_transfer_value=should_transfer_value,
325
        is_static=True if is_staticcall else evm.message.is_static,
326
        accessed_addresses=evm.accessed_addresses.copy(),
327
        accessed_storage_keys=evm.accessed_storage_keys.copy(),
328
        disable_precompiles=disable_precompiles,
329
        parent_evm=evm,
330
    )
331
332
    child_evm = process_message(child_message)
333
334
    if child_evm.error:
335
        incorporate_child_on_error(evm, child_evm)
336
        evm.return_data = child_evm.output
337
        push(evm.stack, U256(0))
338
    else:
339
        incorporate_child_on_success(evm, child_evm)
340
        evm.return_data = child_evm.output
341
        push(evm.stack, U256(1))
342
343
    actual_output_size = min(memory_output_size, U256(len(child_evm.output)))
344
    memory_write(
345
        evm.memory,
346
        memory_output_start_position,
347
        child_evm.output[:actual_output_size],
348
    )

call

Message-call into an account.

Parameters

evm : The current EVM frame.

def call(evm: Evm) -> None:
352
    """
353
    Message-call into an account.
354
355
    Parameters
356
    ----------
357
    evm :
358
        The current EVM frame.
359
360
    """
361
    # STACK
362
    gas = Uint(pop(evm.stack))
363
    to = to_address_masked(pop(evm.stack))
364
    value = pop(evm.stack)
365
    memory_input_start_position = pop(evm.stack)
366
    memory_input_size = pop(evm.stack)
367
    memory_output_start_position = pop(evm.stack)
368
    memory_output_size = pop(evm.stack)
369
370
    if evm.message.is_static and value != U256(0):
371
        raise WriteInStaticContext
372
373
    # GAS
374
    extend_memory = calculate_gas_extend_memory(
375
        evm.memory,
376
        [
377
            (memory_input_start_position, memory_input_size),
378
            (memory_output_start_position, memory_output_size),
379
        ],
380
    )
381
382
    is_cold_access = to not in evm.accessed_addresses
383
    if is_cold_access:
384
        access_gas_cost = GasCosts.COLD_ACCOUNT_ACCESS
385
    else:
386
        access_gas_cost = GasCosts.WARM_ACCESS
387
388
    transfer_gas_cost = Uint(0) if value == 0 else GasCosts.CALL_VALUE
389
390
    # check static gas before state access
391
    check_gas(
392
        evm,
393
        access_gas_cost + transfer_gas_cost + extend_memory.cost,
394
    )
395
396
    # STATE ACCESS
397
    tx_state = evm.message.tx_env.state
398
    if is_cold_access:
399
        evm.accessed_addresses.add(to)
400
401
    create_gas_cost = GasCosts.NEW_ACCOUNT
402
    if value == 0 or is_account_alive(tx_state, to):
403
        create_gas_cost = Uint(0)
404
405
    extra_gas = access_gas_cost + transfer_gas_cost + create_gas_cost
406
    (
407
        is_delegated,
408
        code_address,
409
        delegation_access_cost,
410
    ) = calculate_delegation_cost(evm, to)
411
412
    if is_delegated:
413
        # check enough gas for delegation access
414
        extra_gas += delegation_access_cost
415
        check_gas(evm, extra_gas + extend_memory.cost)
416
        if code_address not in evm.accessed_addresses:
417
            evm.accessed_addresses.add(code_address)
418
419
    code_hash = get_account(tx_state, code_address).code_hash
420
    code = get_code(tx_state, code_hash)
421
422
    message_call_gas = calculate_message_call_gas(
423
        value,
424
        gas,
425
        Uint(evm.gas_left),
426
        extend_memory.cost,
427
        extra_gas,
428
    )
429
    charge_gas(evm, message_call_gas.cost + extend_memory.cost)
430
431
    evm.memory += b"\x00" * extend_memory.expand_by
432
    sender_balance = get_account(tx_state, evm.message.current_target).balance
433
    if sender_balance < value:
434
        push(evm.stack, U256(0))
435
        evm.return_data = b""
436
        evm.gas_left += message_call_gas.sub_call
437
    else:
438
        generic_call(
439
            evm,
440
            message_call_gas.sub_call,
441
            value,
442
            evm.message.current_target,
443
            to,
444
            code_address,
445
            True,
446
            False,
447
            memory_input_start_position,
448
            memory_input_size,
449
            memory_output_start_position,
450
            memory_output_size,
451
            code,
452
            is_delegated,
453
        )
454
455
    # PROGRAM COUNTER
456
    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:
460
    """
461
    Message-call into this account with alternative account's code.
462
463
    Parameters
464
    ----------
465
    evm :
466
        The current EVM frame.
467
468
    """
469
    # STACK
470
    gas = Uint(pop(evm.stack))
471
    code_address = to_address_masked(pop(evm.stack))
472
    value = pop(evm.stack)
473
    memory_input_start_position = pop(evm.stack)
474
    memory_input_size = pop(evm.stack)
475
    memory_output_start_position = pop(evm.stack)
476
    memory_output_size = pop(evm.stack)
477
478
    # GAS
479
    to = evm.message.current_target
480
481
    extend_memory = calculate_gas_extend_memory(
482
        evm.memory,
483
        [
484
            (memory_input_start_position, memory_input_size),
485
            (memory_output_start_position, memory_output_size),
486
        ],
487
    )
488
489
    is_cold_access = code_address not in evm.accessed_addresses
490
    if is_cold_access:
491
        access_gas_cost = GasCosts.COLD_ACCOUNT_ACCESS
492
    else:
493
        access_gas_cost = GasCosts.WARM_ACCESS
494
495
    transfer_gas_cost = Uint(0) if value == 0 else GasCosts.CALL_VALUE
496
497
    # check static gas before state access
498
    check_gas(
499
        evm,
500
        access_gas_cost + extend_memory.cost + transfer_gas_cost,
501
    )
502
503
    # STATE ACCESS
504
    tx_state = evm.message.tx_env.state
505
    if is_cold_access:
506
        evm.accessed_addresses.add(code_address)
507
508
    extra_gas = access_gas_cost + transfer_gas_cost
509
    (
510
        is_delegated,
511
        code_address,
512
        delegation_access_cost,
513
    ) = calculate_delegation_cost(evm, code_address)
514
515
    if is_delegated:
516
        # check enough gas for delegation access
517
        extra_gas += delegation_access_cost
518
        check_gas(evm, extra_gas + extend_memory.cost)
519
        if code_address not in evm.accessed_addresses:
520
            evm.accessed_addresses.add(code_address)
521
522
    code_hash = get_account(tx_state, code_address).code_hash
523
    code = get_code(tx_state, code_hash)
524
525
    message_call_gas = calculate_message_call_gas(
526
        value,
527
        gas,
528
        Uint(evm.gas_left),
529
        extend_memory.cost,
530
        extra_gas,
531
    )
532
    charge_gas(evm, message_call_gas.cost + extend_memory.cost)
533
534
    # OPERATION
535
    evm.memory += b"\x00" * extend_memory.expand_by
536
    sender_balance = get_account(tx_state, evm.message.current_target).balance
537
538
    if sender_balance < value:
539
        push(evm.stack, U256(0))
540
        evm.return_data = b""
541
        evm.gas_left += message_call_gas.sub_call
542
    else:
543
        generic_call(
544
            evm,
545
            message_call_gas.sub_call,
546
            value,
547
            evm.message.current_target,
548
            to,
549
            code_address,
550
            True,
551
            False,
552
            memory_input_start_position,
553
            memory_input_size,
554
            memory_output_start_position,
555
            memory_output_size,
556
            code,
557
            is_delegated,
558
        )
559
560
    # PROGRAM COUNTER
561
    evm.pc += Uint(1)

selfdestruct

Halt execution and register account for later deletion.

Parameters

evm : The current EVM frame.

def selfdestruct(evm: Evm) -> None:
565
    """
566
    Halt execution and register account for later deletion.
567
568
    Parameters
569
    ----------
570
    evm :
571
        The current EVM frame.
572
573
    """
574
    if evm.message.is_static:
575
        raise WriteInStaticContext
576
577
    # STACK
578
    beneficiary = to_address_masked(pop(evm.stack))
579
580
    # GAS
581
    gas_cost = GasCosts.OPCODE_SELFDESTRUCT_BASE
582
583
    is_cold_access = beneficiary not in evm.accessed_addresses
584
    if is_cold_access:
585
        gas_cost += GasCosts.COLD_ACCOUNT_ACCESS
586
587
    # check access gas cost before state access
588
    check_gas(evm, gas_cost)
589
590
    # STATE ACCESS
591
    tx_state = evm.message.tx_env.state
592
    if is_cold_access:
593
        evm.accessed_addresses.add(beneficiary)
594
595
    if (
596
        not is_account_alive(tx_state, beneficiary)
597
        and get_account(tx_state, evm.message.current_target).balance != 0
598
    ):
599
        gas_cost += GasCosts.OPCODE_SELFDESTRUCT_NEW_ACCOUNT
600
601
    charge_gas(evm, gas_cost)
602
603
    originator = evm.message.current_target
604
    originator_balance = get_account(tx_state, originator).balance
605
606
    # Transfer balance
607
    move_ether(tx_state, originator, beneficiary, originator_balance)
608
609
    # register account for deletion only if it was created
610
    # in the same transaction
611
    if originator in tx_state.created_accounts:
612
        # If beneficiary is the same as originator, then
613
        # the ether is burnt.
614
        set_account_balance(tx_state, originator, U256(0))
615
        evm.accounts_to_delete.add(originator)
616
617
    # HALT the execution
618
    evm.running = False
619
620
    # PROGRAM COUNTER
621
    pass

delegatecall

Message-call into an account.

Parameters

evm : The current EVM frame.

def delegatecall(evm: Evm) -> None:
625
    """
626
    Message-call into an account.
627
628
    Parameters
629
    ----------
630
    evm :
631
        The current EVM frame.
632
633
    """
634
    # STACK
635
    gas = Uint(pop(evm.stack))
636
    code_address = to_address_masked(pop(evm.stack))
637
    memory_input_start_position = pop(evm.stack)
638
    memory_input_size = pop(evm.stack)
639
    memory_output_start_position = pop(evm.stack)
640
    memory_output_size = pop(evm.stack)
641
642
    # GAS
643
    extend_memory = calculate_gas_extend_memory(
644
        evm.memory,
645
        [
646
            (memory_input_start_position, memory_input_size),
647
            (memory_output_start_position, memory_output_size),
648
        ],
649
    )
650
651
    is_cold_access = code_address not in evm.accessed_addresses
652
    if is_cold_access:
653
        access_gas_cost = GasCosts.COLD_ACCOUNT_ACCESS
654
    else:
655
        access_gas_cost = GasCosts.WARM_ACCESS
656
657
    # check static gas before state access
658
    check_gas(evm, access_gas_cost + extend_memory.cost)
659
660
    # STATE ACCESS
661
    tx_state = evm.message.tx_env.state
662
    if is_cold_access:
663
        evm.accessed_addresses.add(code_address)
664
665
    extra_gas = access_gas_cost
666
    (
667
        is_delegated,
668
        code_address,
669
        delegation_access_cost,
670
    ) = calculate_delegation_cost(evm, code_address)
671
672
    if is_delegated:
673
        # check enough gas for delegation access
674
        extra_gas += delegation_access_cost
675
        check_gas(evm, extra_gas + extend_memory.cost)
676
        if code_address not in evm.accessed_addresses:
677
            evm.accessed_addresses.add(code_address)
678
679
    code_hash = get_account(tx_state, code_address).code_hash
680
    code = get_code(tx_state, code_hash)
681
682
    message_call_gas = calculate_message_call_gas(
683
        U256(0),
684
        gas,
685
        Uint(evm.gas_left),
686
        extend_memory.cost,
687
        extra_gas,
688
    )
689
    charge_gas(evm, message_call_gas.cost + extend_memory.cost)
690
691
    # OPERATION
692
    evm.memory += b"\x00" * extend_memory.expand_by
693
    generic_call(
694
        evm,
695
        message_call_gas.sub_call,
696
        evm.message.value,
697
        evm.message.caller,
698
        evm.message.current_target,
699
        code_address,
700
        False,
701
        False,
702
        memory_input_start_position,
703
        memory_input_size,
704
        memory_output_start_position,
705
        memory_output_size,
706
        code,
707
        is_delegated,
708
    )
709
710
    # PROGRAM COUNTER
711
    evm.pc += Uint(1)

staticcall

Message-call into an account.

Parameters

evm : The current EVM frame.

def staticcall(evm: Evm) -> None:
715
    """
716
    Message-call into an account.
717
718
    Parameters
719
    ----------
720
    evm :
721
        The current EVM frame.
722
723
    """
724
    # STACK
725
    gas = Uint(pop(evm.stack))
726
    to = to_address_masked(pop(evm.stack))
727
    memory_input_start_position = pop(evm.stack)
728
    memory_input_size = pop(evm.stack)
729
    memory_output_start_position = pop(evm.stack)
730
    memory_output_size = pop(evm.stack)
731
732
    # GAS
733
    extend_memory = calculate_gas_extend_memory(
734
        evm.memory,
735
        [
736
            (memory_input_start_position, memory_input_size),
737
            (memory_output_start_position, memory_output_size),
738
        ],
739
    )
740
741
    is_cold_access = to not in evm.accessed_addresses
742
    if is_cold_access:
743
        access_gas_cost = GasCosts.COLD_ACCOUNT_ACCESS
744
    else:
745
        access_gas_cost = GasCosts.WARM_ACCESS
746
747
    # check static gas before state access
748
    check_gas(evm, access_gas_cost + extend_memory.cost)
749
750
    # STATE ACCESS
751
    tx_state = evm.message.tx_env.state
752
    if is_cold_access:
753
        evm.accessed_addresses.add(to)
754
755
    extra_gas = access_gas_cost
756
    (
757
        is_delegated,
758
        code_address,
759
        delegation_access_cost,
760
    ) = calculate_delegation_cost(evm, to)
761
762
    if is_delegated:
763
        # check enough gas for delegation access
764
        extra_gas += delegation_access_cost
765
        check_gas(evm, extra_gas + extend_memory.cost)
766
        if code_address not in evm.accessed_addresses:
767
            evm.accessed_addresses.add(code_address)
768
769
    code_hash = get_account(tx_state, code_address).code_hash
770
    code = get_code(tx_state, code_hash)
771
772
    message_call_gas = calculate_message_call_gas(
773
        U256(0),
774
        gas,
775
        Uint(evm.gas_left),
776
        extend_memory.cost,
777
        extra_gas,
778
    )
779
    charge_gas(evm, message_call_gas.cost + extend_memory.cost)
780
781
    # OPERATION
782
    evm.memory += b"\x00" * extend_memory.expand_by
783
    generic_call(
784
        evm,
785
        message_call_gas.sub_call,
786
        U256(0),
787
        evm.message.current_target,
788
        to,
789
        code_address,
790
        True,
791
        True,
792
        memory_input_start_position,
793
        memory_input_size,
794
        memory_output_start_position,
795
        memory_output_size,
796
        code,
797
        is_delegated,
798
    )
799
800
    # PROGRAM COUNTER
801
    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:
805
    """
806
    Stop execution and revert state changes, without consuming all provided gas
807
    and also has the ability to return a reason.
808
809
    Parameters
810
    ----------
811
    evm :
812
        The current EVM frame.
813
814
    """
815
    # STACK
816
    memory_start_index = pop(evm.stack)
817
    size = pop(evm.stack)
818
819
    # GAS
820
    extend_memory = calculate_gas_extend_memory(
821
        evm.memory, [(memory_start_index, size)]
822
    )
823
824
    charge_gas(evm, extend_memory.cost)
825
826
    # OPERATION
827
    evm.memory += b"\x00" * extend_memory.expand_by
828
    output = memory_read_bytes(evm.memory, memory_start_index, size)
829
    evm.output = Bytes(output)
830
    raise Revert
831
832
    # PROGRAM COUNTER
833
    # no-op