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

return_

Halts execution returning output data.

Parameters

evm : The current EVM frame.

def return_(evm: Evm) -> None:
244
    """
245
    Halts execution returning output data.
246
247
    Parameters
248
    ----------
249
    evm :
250
        The current EVM frame.
251
252
    """
253
    # STACK
254
    memory_start_position = pop(evm.stack)
255
    memory_size = pop(evm.stack)
256
257
    # GAS
258
    extend_memory = calculate_gas_extend_memory(
259
        evm.memory, [(memory_start_position, memory_size)]
260
    )
261
262
    charge_gas(evm, GAS_ZERO + extend_memory.cost)
263
264
    # OPERATION
265
    evm.memory += b"\x00" * extend_memory.expand_by
266
    evm.output = memory_read_bytes(
267
        evm.memory, memory_start_position, memory_size
268
    )
269
270
    evm.running = False
271
272
    # PROGRAM COUNTER
273
    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) -> None:
290
    """
291
    Perform the core logic of the `CALL*` family of opcodes.
292
    """
293
    from ...vm.interpreter import STACK_DEPTH_LIMIT, process_message
294
295
    evm.return_data = b""
296
297
    if evm.message.depth + Uint(1) > STACK_DEPTH_LIMIT:
298
        evm.gas_left += gas
299
        push(evm.stack, U256(0))
300
        return
301
302
    call_data = memory_read_bytes(
303
        evm.memory, memory_input_start_position, memory_input_size
304
    )
305
    state = evm.message.block_env.state
306
    code = get_code(state, get_account(state, code_address).code_hash)
307
    child_message = Message(
308
        block_env=evm.message.block_env,
309
        tx_env=evm.message.tx_env,
310
        caller=caller,
311
        target=to,
312
        gas=gas,
313
        value=value,
314
        data=call_data,
315
        code=code,
316
        current_target=to,
317
        depth=evm.message.depth + Uint(1),
318
        code_address=code_address,
319
        should_transfer_value=should_transfer_value,
320
        is_static=True if is_staticcall else evm.message.is_static,
321
        accessed_addresses=evm.accessed_addresses.copy(),
322
        accessed_storage_keys=evm.accessed_storage_keys.copy(),
323
        parent_evm=evm,
324
    )
325
    child_evm = process_message(child_message)
326
327
    if child_evm.error:
328
        incorporate_child_on_error(evm, child_evm)
329
        evm.return_data = child_evm.output
330
        push(evm.stack, U256(0))
331
    else:
332
        incorporate_child_on_success(evm, child_evm)
333
        evm.return_data = child_evm.output
334
        push(evm.stack, U256(1))
335
336
    actual_output_size = min(memory_output_size, U256(len(child_evm.output)))
337
    memory_write(
338
        evm.memory,
339
        memory_output_start_position,
340
        child_evm.output[:actual_output_size],
341
    )

call

Message-call into an account.

Parameters

evm : The current EVM frame.

def call(evm: Evm) -> None:
345
    """
346
    Message-call into an account.
347
348
    Parameters
349
    ----------
350
    evm :
351
        The current EVM frame.
352
353
    """
354
    # STACK
355
    gas = Uint(pop(evm.stack))
356
    to = to_address_masked(pop(evm.stack))
357
    value = pop(evm.stack)
358
    memory_input_start_position = pop(evm.stack)
359
    memory_input_size = pop(evm.stack)
360
    memory_output_start_position = pop(evm.stack)
361
    memory_output_size = pop(evm.stack)
362
363
    # GAS
364
    extend_memory = calculate_gas_extend_memory(
365
        evm.memory,
366
        [
367
            (memory_input_start_position, memory_input_size),
368
            (memory_output_start_position, memory_output_size),
369
        ],
370
    )
371
372
    if to in evm.accessed_addresses:
373
        access_gas_cost = GAS_WARM_ACCESS
374
    else:
375
        evm.accessed_addresses.add(to)
376
        access_gas_cost = GAS_COLD_ACCOUNT_ACCESS
377
378
    code_address = to
379
380
    create_gas_cost = GAS_NEW_ACCOUNT
381
    if value == 0 or is_account_alive(evm.message.block_env.state, to):
382
        create_gas_cost = Uint(0)
383
    transfer_gas_cost = Uint(0) if value == 0 else GAS_CALL_VALUE
384
    message_call_gas = calculate_message_call_gas(
385
        value,
386
        gas,
387
        Uint(evm.gas_left),
388
        extend_memory.cost,
389
        access_gas_cost + create_gas_cost + transfer_gas_cost,
390
    )
391
    charge_gas(evm, message_call_gas.cost + extend_memory.cost)
392
    if evm.message.is_static and value != U256(0):
393
        raise WriteInStaticContext
394
    evm.memory += b"\x00" * extend_memory.expand_by
395
    sender_balance = get_account(
396
        evm.message.block_env.state, evm.message.current_target
397
    ).balance
398
    if sender_balance < value:
399
        push(evm.stack, U256(0))
400
        evm.return_data = b""
401
        evm.gas_left += message_call_gas.sub_call
402
    else:
403
        generic_call(
404
            evm,
405
            message_call_gas.sub_call,
406
            value,
407
            evm.message.current_target,
408
            to,
409
            code_address,
410
            True,
411
            False,
412
            memory_input_start_position,
413
            memory_input_size,
414
            memory_output_start_position,
415
            memory_output_size,
416
        )
417
418
    # PROGRAM COUNTER
419
    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:
423
    """
424
    Message-call into this account with alternative account’s code.
425
426
    Parameters
427
    ----------
428
    evm :
429
        The current EVM frame.
430
431
    """
432
    # STACK
433
    gas = Uint(pop(evm.stack))
434
    code_address = to_address_masked(pop(evm.stack))
435
    value = pop(evm.stack)
436
    memory_input_start_position = pop(evm.stack)
437
    memory_input_size = pop(evm.stack)
438
    memory_output_start_position = pop(evm.stack)
439
    memory_output_size = pop(evm.stack)
440
441
    # GAS
442
    to = evm.message.current_target
443
444
    extend_memory = calculate_gas_extend_memory(
445
        evm.memory,
446
        [
447
            (memory_input_start_position, memory_input_size),
448
            (memory_output_start_position, memory_output_size),
449
        ],
450
    )
451
452
    if code_address in evm.accessed_addresses:
453
        access_gas_cost = GAS_WARM_ACCESS
454
    else:
455
        evm.accessed_addresses.add(code_address)
456
        access_gas_cost = GAS_COLD_ACCOUNT_ACCESS
457
458
    transfer_gas_cost = Uint(0) if value == 0 else GAS_CALL_VALUE
459
    message_call_gas = calculate_message_call_gas(
460
        value,
461
        gas,
462
        Uint(evm.gas_left),
463
        extend_memory.cost,
464
        access_gas_cost + transfer_gas_cost,
465
    )
466
    charge_gas(evm, message_call_gas.cost + extend_memory.cost)
467
468
    # OPERATION
469
    evm.memory += b"\x00" * extend_memory.expand_by
470
    sender_balance = get_account(
471
        evm.message.block_env.state, evm.message.current_target
472
    ).balance
473
    if sender_balance < value:
474
        push(evm.stack, U256(0))
475
        evm.return_data = b""
476
        evm.gas_left += message_call_gas.sub_call
477
    else:
478
        generic_call(
479
            evm,
480
            message_call_gas.sub_call,
481
            value,
482
            evm.message.current_target,
483
            to,
484
            code_address,
485
            True,
486
            False,
487
            memory_input_start_position,
488
            memory_input_size,
489
            memory_output_start_position,
490
            memory_output_size,
491
        )
492
493
    # PROGRAM COUNTER
494
    evm.pc += Uint(1)

selfdestruct

Halt execution and register account for later deletion.

Parameters

evm : The current EVM frame.

def selfdestruct(evm: Evm) -> None:
498
    """
499
    Halt execution and register account for later deletion.
500
501
    Parameters
502
    ----------
503
    evm :
504
        The current EVM frame.
505
506
    """
507
    # STACK
508
    beneficiary = to_address_masked(pop(evm.stack))
509
510
    # GAS
511
    gas_cost = GAS_SELF_DESTRUCT
512
    if beneficiary not in evm.accessed_addresses:
513
        evm.accessed_addresses.add(beneficiary)
514
        gas_cost += GAS_COLD_ACCOUNT_ACCESS
515
516
    if (
517
        not is_account_alive(evm.message.block_env.state, beneficiary)
518
        and get_account(
519
            evm.message.block_env.state, evm.message.current_target
520
        ).balance
521
        != 0
522
    ):
523
        gas_cost += GAS_SELF_DESTRUCT_NEW_ACCOUNT
524
525
    charge_gas(evm, gas_cost)
526
    if evm.message.is_static:
527
        raise WriteInStaticContext
528
529
    originator = evm.message.current_target
530
    beneficiary_balance = get_account(
531
        evm.message.block_env.state, beneficiary
532
    ).balance
533
    originator_balance = get_account(
534
        evm.message.block_env.state, originator
535
    ).balance
536
537
    # First Transfer to beneficiary
538
    set_account_balance(
539
        evm.message.block_env.state,
540
        beneficiary,
541
        beneficiary_balance + originator_balance,
542
    )
543
    # Next, Zero the balance of the address being deleted (must come after
544
    # sending to beneficiary in case the contract named itself as the
545
    # beneficiary).
546
    set_account_balance(evm.message.block_env.state, originator, U256(0))
547
548
    # register account for deletion
549
    evm.accounts_to_delete.add(originator)
550
551
    # HALT the execution
552
    evm.running = False
553
554
    # PROGRAM COUNTER
555
    pass

delegatecall

Message-call into an account.

Parameters

evm : The current EVM frame.

def delegatecall(evm: Evm) -> None:
559
    """
560
    Message-call into an account.
561
562
    Parameters
563
    ----------
564
    evm :
565
        The current EVM frame.
566
567
    """
568
    # STACK
569
    gas = Uint(pop(evm.stack))
570
    code_address = to_address_masked(pop(evm.stack))
571
    memory_input_start_position = pop(evm.stack)
572
    memory_input_size = pop(evm.stack)
573
    memory_output_start_position = pop(evm.stack)
574
    memory_output_size = pop(evm.stack)
575
576
    # GAS
577
    extend_memory = calculate_gas_extend_memory(
578
        evm.memory,
579
        [
580
            (memory_input_start_position, memory_input_size),
581
            (memory_output_start_position, memory_output_size),
582
        ],
583
    )
584
585
    if code_address in evm.accessed_addresses:
586
        access_gas_cost = GAS_WARM_ACCESS
587
    else:
588
        evm.accessed_addresses.add(code_address)
589
        access_gas_cost = GAS_COLD_ACCOUNT_ACCESS
590
591
    message_call_gas = calculate_message_call_gas(
592
        U256(0), gas, Uint(evm.gas_left), extend_memory.cost, access_gas_cost
593
    )
594
    charge_gas(evm, message_call_gas.cost + extend_memory.cost)
595
596
    # OPERATION
597
    evm.memory += b"\x00" * extend_memory.expand_by
598
    generic_call(
599
        evm,
600
        message_call_gas.sub_call,
601
        evm.message.value,
602
        evm.message.caller,
603
        evm.message.current_target,
604
        code_address,
605
        False,
606
        False,
607
        memory_input_start_position,
608
        memory_input_size,
609
        memory_output_start_position,
610
        memory_output_size,
611
    )
612
613
    # PROGRAM COUNTER
614
    evm.pc += Uint(1)

staticcall

Message-call into an account.

Parameters

evm : The current EVM frame.

def staticcall(evm: Evm) -> None:
618
    """
619
    Message-call into an account.
620
621
    Parameters
622
    ----------
623
    evm :
624
        The current EVM frame.
625
626
    """
627
    # STACK
628
    gas = Uint(pop(evm.stack))
629
    to = to_address_masked(pop(evm.stack))
630
    memory_input_start_position = pop(evm.stack)
631
    memory_input_size = pop(evm.stack)
632
    memory_output_start_position = pop(evm.stack)
633
    memory_output_size = pop(evm.stack)
634
635
    # GAS
636
    extend_memory = calculate_gas_extend_memory(
637
        evm.memory,
638
        [
639
            (memory_input_start_position, memory_input_size),
640
            (memory_output_start_position, memory_output_size),
641
        ],
642
    )
643
644
    if to in evm.accessed_addresses:
645
        access_gas_cost = GAS_WARM_ACCESS
646
    else:
647
        evm.accessed_addresses.add(to)
648
        access_gas_cost = GAS_COLD_ACCOUNT_ACCESS
649
650
    code_address = to
651
652
    message_call_gas = calculate_message_call_gas(
653
        U256(0),
654
        gas,
655
        Uint(evm.gas_left),
656
        extend_memory.cost,
657
        access_gas_cost,
658
    )
659
    charge_gas(evm, message_call_gas.cost + extend_memory.cost)
660
661
    # OPERATION
662
    evm.memory += b"\x00" * extend_memory.expand_by
663
    generic_call(
664
        evm,
665
        message_call_gas.sub_call,
666
        U256(0),
667
        evm.message.current_target,
668
        to,
669
        code_address,
670
        True,
671
        True,
672
        memory_input_start_position,
673
        memory_input_size,
674
        memory_output_start_position,
675
        memory_output_size,
676
    )
677
678
    # PROGRAM COUNTER
679
    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:
683
    """
684
    Stop execution and revert state changes, without consuming all provided gas
685
    and also has the ability to return a reason.
686
687
    Parameters
688
    ----------
689
    evm :
690
        The current EVM frame.
691
692
    """
693
    # STACK
694
    memory_start_index = pop(evm.stack)
695
    size = pop(evm.stack)
696
697
    # GAS
698
    extend_memory = calculate_gas_extend_memory(
699
        evm.memory, [(memory_start_index, size)]
700
    )
701
702
    charge_gas(evm, extend_memory.cost)
703
704
    # OPERATION
705
    evm.memory += b"\x00" * extend_memory.expand_by
706
    output = memory_read_bytes(evm.memory, memory_start_index, size)
707
    evm.output = Bytes(output)
708
    raise Revert