ethereum.shanghai.vm.instructions.systemethereum.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:
67
    """
68
    Core logic used by the `CREATE*` family of opcodes.
69
    """
70
    # This import causes a circular import error
71
    # if it's not moved inside this method
72
    from ...vm.interpreter import (
73
        MAX_CODE_SIZE,
74
        STACK_DEPTH_LIMIT,
75
        process_create_message,
76
    )
77
78
    call_data = memory_read_bytes(
79
        evm.memory, memory_start_position, memory_size
80
    )
81
    if len(call_data) > 2 * MAX_CODE_SIZE:
82
        raise OutOfGasError
83
84
    evm.accessed_addresses.add(contract_address)
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.env.state, sender_address)
94
95
    if (
96
        sender.balance < endowment
97
        or sender.nonce == Uint(2**64 - 1)
98
        or evm.message.depth + 1 > STACK_DEPTH_LIMIT
99
    ):
100
        evm.gas_left += create_message_gas
101
        push(evm.stack, U256(0))
102
        return
103
104
    if account_has_code_or_nonce(evm.env.state, contract_address):
105
        increment_nonce(evm.env.state, evm.message.current_target)
106
        push(evm.stack, U256(0))
107
        return
108
109
    increment_nonce(evm.env.state, evm.message.current_target)
110
111
    child_message = Message(
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 + 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, evm.env)
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
    # STACK
149
    endowment = pop(evm.stack)
150
    memory_start_position = pop(evm.stack)
151
    memory_size = pop(evm.stack)
152
153
    # GAS
154
    extend_memory = calculate_gas_extend_memory(
155
        evm.memory, [(memory_start_position, memory_size)]
156
    )
157
    init_code_gas = init_code_cost(Uint(memory_size))
158
159
    charge_gas(evm, GAS_CREATE + extend_memory.cost + init_code_gas)
160
161
    # OPERATION
162
    evm.memory += b"\x00" * extend_memory.expand_by
163
    contract_address = compute_contract_address(
164
        evm.message.current_target,
165
        get_account(evm.env.state, evm.message.current_target).nonce,
166
    )
167
168
    generic_create(
169
        evm,
170
        endowment,
171
        contract_address,
172
        memory_start_position,
173
        memory_size,
174
        init_code_gas,
175
    )
176
177
    # PROGRAM COUNTER
178
    evm.pc += 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:
182
    """
183
    Creates a new account with associated code.
184
185
    It's similar to CREATE opcode except that the address of new account
186
    depends on the init_code instead of the nonce of sender.
187
188
    Parameters
189
    ----------
190
    evm :
191
        The current EVM frame.
192
    """
193
    # STACK
194
    endowment = pop(evm.stack)
195
    memory_start_position = pop(evm.stack)
196
    memory_size = pop(evm.stack)
197
    salt = pop(evm.stack).to_be_bytes32()
198
199
    # GAS
200
    extend_memory = calculate_gas_extend_memory(
201
        evm.memory, [(memory_start_position, memory_size)]
202
    )
203
    call_data_words = ceil32(Uint(memory_size)) // 32
204
    init_code_gas = init_code_cost(Uint(memory_size))
205
    charge_gas(
206
        evm,
207
        GAS_CREATE
208
        + GAS_KECCAK256_WORD * call_data_words
209
        + extend_memory.cost
210
        + init_code_gas,
211
    )
212
213
    # OPERATION
214
    evm.memory += b"\x00" * extend_memory.expand_by
215
    contract_address = compute_create2_contract_address(
216
        evm.message.current_target,
217
        salt,
218
        memory_read_bytes(evm.memory, memory_start_position, memory_size),
219
    )
220
221
    generic_create(
222
        evm,
223
        endowment,
224
        contract_address,
225
        memory_start_position,
226
        memory_size,
227
        init_code_gas,
228
    )
229
230
    # PROGRAM COUNTER
231
    evm.pc += 1

return_

Halts execution returning output data.

Parameters

evm : The current EVM frame.

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

call

Message-call into an account.

Parameters

evm : The current EVM frame.

def call(evm: Evm) -> None:
332
    """
333
    Message-call into an account.
334
335
    Parameters
336
    ----------
337
    evm :
338
        The current EVM frame.
339
    """
340
    # STACK
341
    gas = Uint(pop(evm.stack))
342
    to = to_address(pop(evm.stack))
343
    value = pop(evm.stack)
344
    memory_input_start_position = pop(evm.stack)
345
    memory_input_size = pop(evm.stack)
346
    memory_output_start_position = pop(evm.stack)
347
    memory_output_size = pop(evm.stack)
348
349
    # GAS
350
    extend_memory = calculate_gas_extend_memory(
351
        evm.memory,
352
        [
353
            (memory_input_start_position, memory_input_size),
354
            (memory_output_start_position, memory_output_size),
355
        ],
356
    )
357
358
    if to in evm.accessed_addresses:
359
        access_gas_cost = GAS_WARM_ACCESS
360
    else:
361
        evm.accessed_addresses.add(to)
362
        access_gas_cost = GAS_COLD_ACCOUNT_ACCESS
363
364
    create_gas_cost = (
365
        Uint(0)
366
        if is_account_alive(evm.env.state, to) or value == 0
367
        else GAS_NEW_ACCOUNT
368
    )
369
    transfer_gas_cost = Uint(0) if value == 0 else GAS_CALL_VALUE
370
    message_call_gas = calculate_message_call_gas(
371
        value,
372
        gas,
373
        Uint(evm.gas_left),
374
        extend_memory.cost,
375
        access_gas_cost + create_gas_cost + transfer_gas_cost,
376
    )
377
    charge_gas(evm, message_call_gas.cost + extend_memory.cost)
378
    if evm.message.is_static and value != U256(0):
379
        raise WriteInStaticContext
380
    evm.memory += b"\x00" * extend_memory.expand_by
381
    sender_balance = get_account(
382
        evm.env.state, evm.message.current_target
383
    ).balance
384
    if sender_balance < value:
385
        push(evm.stack, U256(0))
386
        evm.return_data = b""
387
        evm.gas_left += message_call_gas.stipend
388
    else:
389
        generic_call(
390
            evm,
391
            message_call_gas.stipend,
392
            value,
393
            evm.message.current_target,
394
            to,
395
            to,
396
            True,
397
            False,
398
            memory_input_start_position,
399
            memory_input_size,
400
            memory_output_start_position,
401
            memory_output_size,
402
        )
403
404
    # PROGRAM COUNTER
405
    evm.pc += 1

callcode

Message-call into this account with alternative account’s code.

Parameters

evm : The current EVM frame.

def callcode(evm: Evm) -> None:
409
    """
410
    Message-call into this account with alternative account’s code.
411
412
    Parameters
413
    ----------
414
    evm :
415
        The current EVM frame.
416
    """
417
    # STACK
418
    gas = Uint(pop(evm.stack))
419
    code_address = to_address(pop(evm.stack))
420
    value = pop(evm.stack)
421
    memory_input_start_position = pop(evm.stack)
422
    memory_input_size = pop(evm.stack)
423
    memory_output_start_position = pop(evm.stack)
424
    memory_output_size = pop(evm.stack)
425
426
    # GAS
427
    to = evm.message.current_target
428
429
    extend_memory = calculate_gas_extend_memory(
430
        evm.memory,
431
        [
432
            (memory_input_start_position, memory_input_size),
433
            (memory_output_start_position, memory_output_size),
434
        ],
435
    )
436
437
    if code_address in evm.accessed_addresses:
438
        access_gas_cost = GAS_WARM_ACCESS
439
    else:
440
        evm.accessed_addresses.add(code_address)
441
        access_gas_cost = GAS_COLD_ACCOUNT_ACCESS
442
443
    transfer_gas_cost = Uint(0) if value == 0 else GAS_CALL_VALUE
444
    message_call_gas = calculate_message_call_gas(
445
        value,
446
        gas,
447
        Uint(evm.gas_left),
448
        extend_memory.cost,
449
        access_gas_cost + transfer_gas_cost,
450
    )
451
    charge_gas(evm, message_call_gas.cost + extend_memory.cost)
452
453
    # OPERATION
454
    evm.memory += b"\x00" * extend_memory.expand_by
455
    sender_balance = get_account(
456
        evm.env.state, evm.message.current_target
457
    ).balance
458
    if sender_balance < value:
459
        push(evm.stack, U256(0))
460
        evm.return_data = b""
461
        evm.gas_left += message_call_gas.stipend
462
    else:
463
        generic_call(
464
            evm,
465
            message_call_gas.stipend,
466
            value,
467
            evm.message.current_target,
468
            to,
469
            code_address,
470
            True,
471
            False,
472
            memory_input_start_position,
473
            memory_input_size,
474
            memory_output_start_position,
475
            memory_output_size,
476
        )
477
478
    # PROGRAM COUNTER
479
    evm.pc += 1

selfdestruct

Halt execution and register account for later deletion.

Parameters

evm : The current EVM frame.

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

delegatecall

Message-call into an account.

Parameters

evm : The current EVM frame.

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

staticcall

Message-call into an account.

Parameters

evm : The current EVM frame.

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