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

return_

Halts execution returning output data.

Parameters

evm : The current EVM frame.

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

call

Message-call into an account.

Parameters

evm : The current EVM frame.

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

selfdestruct

Halt execution and register account for later deletion.

Parameters

evm : The current EVM frame.

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

delegatecall

Message-call into an account.

Parameters

evm : The current EVM frame.

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

staticcall

Message-call into an account.

Parameters

evm : The current EVM frame.

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