ethereum.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, ​​init_code_gas: Uint) -> None:
70
    """
71
    Core logic used by the `CREATE*` family of opcodes.
72
    """
73
    # This import causes a circular import error
74
    # if it's not moved inside this method
75
    from ...vm.interpreter import (
76
        MAX_CODE_SIZE,
77
        STACK_DEPTH_LIMIT,
78
        process_create_message,
79
    )
80
81
    call_data = memory_read_bytes(
82
        evm.memory, memory_start_position, memory_size
83
    )
84
    if len(call_data) > 2 * MAX_CODE_SIZE:
85
        raise OutOfGasError
86
87
    evm.accessed_addresses.add(contract_address)
88
89
    create_message_gas = max_message_call_gas(Uint(evm.gas_left))
90
    evm.gas_left -= create_message_gas
91
    if evm.message.is_static:
92
        raise WriteInStaticContext
93
    evm.return_data = b""
94
95
    sender_address = evm.message.current_target
96
    sender = get_account(evm.env.state, sender_address)
97
98
    if (
99
        sender.balance < endowment
100
        or sender.nonce == Uint(2**64 - 1)
101
        or evm.message.depth + Uint(1) > STACK_DEPTH_LIMIT
102
    ):
103
        evm.gas_left += create_message_gas
104
        push(evm.stack, U256(0))
105
        return
106
107
    if account_has_code_or_nonce(
108
        evm.env.state, contract_address
109
    ) or account_has_storage(evm.env.state, contract_address):
110
        increment_nonce(evm.env.state, evm.message.current_target)
111
        push(evm.stack, U256(0))
112
        return
113
114
    increment_nonce(evm.env.state, evm.message.current_target)
115
116
    child_message = Message(
117
        caller=evm.message.current_target,
118
        target=Bytes0(),
119
        gas=create_message_gas,
120
        value=endowment,
121
        data=b"",
122
        code=call_data,
123
        current_target=contract_address,
124
        depth=evm.message.depth + Uint(1),
125
        code_address=None,
126
        should_transfer_value=True,
127
        is_static=False,
128
        accessed_addresses=evm.accessed_addresses.copy(),
129
        accessed_storage_keys=evm.accessed_storage_keys.copy(),
130
        parent_evm=evm,
131
    )
132
    child_evm = process_create_message(child_message, evm.env)
133
134
    if child_evm.error:
135
        incorporate_child_on_error(evm, child_evm)
136
        evm.return_data = child_evm.output
137
        push(evm.stack, U256(0))
138
    else:
139
        incorporate_child_on_success(evm, child_evm)
140
        evm.return_data = b""
141
        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:
145
    """
146
    Creates a new account with associated code.
147
148
    Parameters
149
    ----------
150
    evm :
151
        The current EVM frame.
152
    """
153
    # STACK
154
    endowment = pop(evm.stack)
155
    memory_start_position = pop(evm.stack)
156
    memory_size = pop(evm.stack)
157
158
    # GAS
159
    extend_memory = calculate_gas_extend_memory(
160
        evm.memory, [(memory_start_position, memory_size)]
161
    )
162
    init_code_gas = init_code_cost(Uint(memory_size))
163
164
    charge_gas(evm, GAS_CREATE + extend_memory.cost + init_code_gas)
165
166
    # OPERATION
167
    evm.memory += b"\x00" * extend_memory.expand_by
168
    contract_address = compute_contract_address(
169
        evm.message.current_target,
170
        get_account(evm.env.state, evm.message.current_target).nonce,
171
    )
172
173
    generic_create(
174
        evm,
175
        endowment,
176
        contract_address,
177
        memory_start_position,
178
        memory_size,
179
        init_code_gas,
180
    )
181
182
    # PROGRAM COUNTER
183
    evm.pc += Uint(1)

create2

Creates a new account with associated code.

It's similar to CREATE opcode except that the address of new account depends on the init_code instead of the nonce of sender.

Parameters

evm : The current EVM frame.

def create2(evm: Evm) -> None:
187
    """
188
    Creates a new account with associated code.
189
190
    It's similar to CREATE opcode except that the address of new account
191
    depends on the init_code instead of the nonce of sender.
192
193
    Parameters
194
    ----------
195
    evm :
196
        The current EVM frame.
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
        GAS_CREATE
213
        + GAS_KECCAK256_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
        init_code_gas,
233
    )
234
235
    # PROGRAM COUNTER
236
    evm.pc += Uint(1)

return_

Halts execution returning output data.

Parameters

evm : The current EVM frame.

def return_(evm: Evm) -> None:
240
    """
241
    Halts execution returning output data.
242
243
    Parameters
244
    ----------
245
    evm :
246
        The current EVM frame.
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, GAS_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
    code = get_account(evm.env.state, code_address).code
301
    child_message = Message(
302
        caller=caller,
303
        target=to,
304
        gas=gas,
305
        value=value,
306
        data=call_data,
307
        code=code,
308
        current_target=to,
309
        depth=evm.message.depth + Uint(1),
310
        code_address=code_address,
311
        should_transfer_value=should_transfer_value,
312
        is_static=True if is_staticcall else evm.message.is_static,
313
        accessed_addresses=evm.accessed_addresses.copy(),
314
        accessed_storage_keys=evm.accessed_storage_keys.copy(),
315
        parent_evm=evm,
316
    )
317
    child_evm = process_message(child_message, evm.env)
318
319
    if child_evm.error:
320
        incorporate_child_on_error(evm, child_evm)
321
        evm.return_data = child_evm.output
322
        push(evm.stack, U256(0))
323
    else:
324
        incorporate_child_on_success(evm, child_evm)
325
        evm.return_data = child_evm.output
326
        push(evm.stack, U256(1))
327
328
    actual_output_size = min(memory_output_size, U256(len(child_evm.output)))
329
    memory_write(
330
        evm.memory,
331
        memory_output_start_position,
332
        child_evm.output[:actual_output_size],
333
    )

call

Message-call into an account.

Parameters

evm : The current EVM frame.

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

selfdestruct

Halt execution and register account for later deletion.

Parameters

evm : The current EVM frame.

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

delegatecall

Message-call into an account.

Parameters

evm : The current EVM frame.

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

staticcall

Message-call into an account.

Parameters

evm : The current EVM frame.

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