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

return_

Halts execution returning output data.

Parameters

evm : The current EVM frame.

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

call

Message-call into an account.

Parameters

evm : The current EVM frame.

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

selfdestruct

Halt execution and register account for later deletion.

Parameters

evm : The current EVM frame.

def selfdestruct(evm: Evm) -> None:
499
    """
500
    Halt execution and register account for later deletion.
501
502
    Parameters
503
    ----------
504
    evm :
505
        The current EVM frame.
506
507
    """
508
    # STACK
509
    beneficiary = to_address_masked(pop(evm.stack))
510
511
    # GAS
512
    gas_cost = GAS_SELF_DESTRUCT
513
    if beneficiary not in evm.accessed_addresses:
514
        evm.accessed_addresses.add(beneficiary)
515
        gas_cost += GAS_COLD_ACCOUNT_ACCESS
516
517
    if (
518
        not is_account_alive(evm.message.block_env.state, beneficiary)
519
        and get_account(
520
            evm.message.block_env.state, evm.message.current_target
521
        ).balance
522
        != 0
523
    ):
524
        gas_cost += GAS_SELF_DESTRUCT_NEW_ACCOUNT
525
526
    charge_gas(evm, gas_cost)
527
    if evm.message.is_static:
528
        raise WriteInStaticContext
529
530
    originator = evm.message.current_target
530
    beneficiary_balance = get_account(
531
        evm.message.block_env.state, beneficiary
532
    ).balance
531
    originator_balance = get_account(
532
        evm.message.block_env.state, originator
533
    ).balance
534
537
    # First Transfer to beneficiary
538
    set_account_balance(
535
    move_ether(
536
        evm.message.block_env.state,
537
        originator,
538
        beneficiary,
541
        beneficiary_balance + originator_balance,
539
        originator_balance,
540
    )
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))
541
548
    # register account for deletion
549
    evm.accounts_to_delete.add(originator)
542
    # register account for deletion only if it was created
543
    # in the same transaction
544
    if originator in evm.message.block_env.state.created_accounts:
545
        # If beneficiary is the same as originator, then
546
        # the ether is burnt.
547
        set_account_balance(evm.message.block_env.state, originator, U256(0))
548
        evm.accounts_to_delete.add(originator)
549
550
    # HALT the execution
551
    evm.running = False
552
553
    # PROGRAM COUNTER
554
    pass

delegatecall

Message-call into an account.

Parameters

evm : The current EVM frame.

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

staticcall

Message-call into an account.

Parameters

evm : The current EVM frame.

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