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

return_

Halts execution returning output data.

Parameters

evm : The current EVM frame.

def return_(evm: Evm) -> None:
256
    """
257
    Halts execution returning output data.
258
259
    Parameters
260
    ----------
261
    evm :
262
        The current EVM frame.
263
264
    """
265
    # STACK
266
    memory_start_position = pop(evm.stack)
267
    memory_size = pop(evm.stack)
268
269
    # GAS
270
    extend_memory = calculate_gas_extend_memory(
271
        evm.memory, [(memory_start_position, memory_size)]
272
    )
273
274
    charge_gas(evm, GAS_ZERO + extend_memory.cost)
275
276
    # OPERATION
277
    evm.memory += b"\x00" * extend_memory.expand_by
278
    evm.output = memory_read_bytes(
279
        evm.memory, memory_start_position, memory_size
280
    )
281
282
    evm.running = False
283
284
    # PROGRAM COUNTER
285
    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:
304
    """
305
    Perform the core logic of the `CALL*` family of opcodes.
306
    """
307
    from ...vm.interpreter import STACK_DEPTH_LIMIT, process_message
308
309
    evm.return_data = b""
310
311
    if evm.message.depth + Uint(1) > STACK_DEPTH_LIMIT:
312
        evm.gas_left += gas
313
        push(evm.stack, U256(0))
314
        return
315
316
    call_data = memory_read_bytes(
317
        evm.memory, memory_input_start_position, memory_input_size
318
    )
319
320
    child_message = Message(
321
        block_env=evm.message.block_env,
322
        tx_env=evm.message.tx_env,
323
        caller=caller,
324
        target=to,
325
        gas=gas,
326
        value=value,
327
        data=call_data,
328
        code=code,
329
        current_target=to,
330
        depth=evm.message.depth + Uint(1),
331
        code_address=code_address,
332
        should_transfer_value=should_transfer_value,
333
        is_static=True if is_staticcall else evm.message.is_static,
334
        accessed_addresses=evm.accessed_addresses.copy(),
335
        accessed_storage_keys=evm.accessed_storage_keys.copy(),
336
        disable_precompiles=disable_precompiles,
337
        parent_evm=evm,
338
        is_create=False,
339
    )
340
341
    child_evm = process_message(child_message)
342
343
    if child_evm.error:
344
        incorporate_child_on_error(evm, child_evm)
345
        evm.return_data = child_evm.output
346
        push(evm.stack, U256(0))
347
    else:
348
        incorporate_child_on_success(evm, child_evm)
349
        evm.return_data = child_evm.output
350
        push(evm.stack, U256(1))
351
352
    actual_output_size = min(memory_output_size, U256(len(child_evm.output)))
353
    memory_write(
354
        evm.memory,
355
        memory_output_start_position,
356
        child_evm.output[:actual_output_size],
357
    )

call

Message-call into an account.

Parameters

evm : The current EVM frame.

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

selfdestruct

Halt execution and register account for later deletion.

Parameters

evm : The current EVM frame.

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

delegatecall

Message-call into an account.

Parameters

evm : The current EVM frame.

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

staticcall

Message-call into an account.

Parameters

evm : The current EVM frame.

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