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

return_

Halts execution returning output data.

Parameters

evm : The current EVM frame.

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

call

Message-call into an account.

Parameters

evm : The current EVM frame.

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

selfdestruct

Halt execution and register account for later deletion.

Parameters

evm : The current EVM frame.

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

delegatecall

Message-call into an account.

Parameters

evm : The current EVM frame.

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

staticcall

Message-call into an account.

Parameters

evm : The current EVM frame.

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