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

return_

Halts execution returning output data.

Parameters

evm : The current EVM frame.

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

call

Message-call into an account.

Parameters

evm : The current EVM frame.

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

selfdestruct

Halt execution and register account for later deletion.

Parameters

evm : The current EVM frame.

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

delegatecall

Message-call into an account.

Parameters

evm : The current EVM frame.

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

staticcall

Message-call into an account.

Parameters

evm : The current EVM frame.

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