ethereum.forks.prague.vm.instructions.systemethereum.forks.osaka.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:
64
    <snip>
67
    # This import causes a circular import error
68
    # if it's not moved inside this method
69
    from ...vm.interpreter import (
70
        MAX_INIT_CODE_SIZE,
71
        STACK_DEPTH_LIMIT,
72
        process_create_message,
73
    )
74
75
    call_data = memory_read_bytes(
76
        evm.memory, memory_start_position, memory_size
77
    )
78
    if len(call_data) > MAX_INIT_CODE_SIZE:
79
        raise OutOfGasError
80
81
    create_message_gas = max_message_call_gas(Uint(evm.gas_left))
82
    evm.gas_left -= create_message_gas
83
    if evm.message.is_static:
84
        raise WriteInStaticContext
85
    evm.return_data = b""
86
87
    sender_address = evm.message.current_target
88
    sender = get_account(evm.message.tx_env.state, sender_address)
89
90
    if (
91
        sender.balance < endowment
92
        or sender.nonce == Uint(2**64 - 1)
93
        or evm.message.depth + Uint(1) > STACK_DEPTH_LIMIT
94
    ):
95
        evm.gas_left += create_message_gas
96
        push(evm.stack, U256(0))
97
        return
98
99
    evm.accessed_addresses.add(contract_address)
100
101
    if account_has_code_or_nonce(
102
        evm.message.tx_env.state, contract_address
103
    ) or account_has_storage(evm.message.tx_env.state, contract_address):
104
        increment_nonce(evm.message.tx_env.state, evm.message.current_target)
105
        push(evm.stack, U256(0))
106
        return
107
108
    increment_nonce(evm.message.tx_env.state, evm.message.current_target)
109
110
    child_message = Message(
111
        block_env=evm.message.block_env,
112
        tx_env=evm.message.tx_env,
113
        caller=evm.message.current_target,
114
        target=Bytes0(),
115
        gas=create_message_gas,
116
        value=endowment,
117
        data=b"",
118
        code=call_data,
119
        current_target=contract_address,
120
        depth=evm.message.depth + Uint(1),
121
        code_address=None,
122
        should_transfer_value=True,
123
        is_static=False,
124
        accessed_addresses=evm.accessed_addresses.copy(),
125
        accessed_storage_keys=evm.accessed_storage_keys.copy(),
126
        disable_precompiles=False,
127
        parent_evm=evm,
128
    )
129
    child_evm = process_create_message(child_message)
130
131
    if child_evm.error:
132
        incorporate_child_on_error(evm, child_evm)
133
        evm.return_data = child_evm.output
134
        push(evm.stack, U256(0))
135
    else:
136
        incorporate_child_on_success(evm, child_evm)
137
        evm.return_data = b""
138
        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:
142
    <snip>
151
    # STACK
152
    endowment = pop(evm.stack)
153
    memory_start_position = pop(evm.stack)
154
    memory_size = pop(evm.stack)
155
156
    # GAS
157
    extend_memory = calculate_gas_extend_memory(
158
        evm.memory, [(memory_start_position, memory_size)]
159
    )
160
    init_code_gas = init_code_cost(Uint(memory_size))
161
162
    charge_gas(
163
        evm, GasCosts.OPCODE_CREATE_BASE + extend_memory.cost + init_code_gas
163
        evm,
164
        GasCosts.OPCODE_CREATE_BASE + extend_memory.cost + init_code_gas,
165
    )
166
167
    # OPERATION
168
    evm.memory += b"\x00" * extend_memory.expand_by
169
    contract_address = compute_contract_address(
170
        evm.message.current_target,
171
        get_account(
172
            evm.message.tx_env.state, evm.message.current_target
173
        ).nonce,
174
    )
175
176
    generic_create(
177
        evm,
178
        endowment,
179
        contract_address,
180
        memory_start_position,
181
        memory_size,
182
    )
183
184
    # PROGRAM COUNTER
185
    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:
189
    <snip>
201
    # STACK
202
    endowment = pop(evm.stack)
203
    memory_start_position = pop(evm.stack)
204
    memory_size = pop(evm.stack)
205
    salt = pop(evm.stack).to_be_bytes32()
206
207
    # GAS
208
    extend_memory = calculate_gas_extend_memory(
209
        evm.memory, [(memory_start_position, memory_size)]
210
    )
211
    call_data_words = ceil32(Uint(memory_size)) // Uint(32)
212
    init_code_gas = init_code_cost(Uint(memory_size))
213
    charge_gas(
214
        evm,
215
        GasCosts.OPCODE_CREATE_BASE
216
        + GasCosts.OPCODE_KECCAK256_PER_WORD * call_data_words
217
        + extend_memory.cost
218
        + init_code_gas,
219
    )
220
221
    # OPERATION
222
    evm.memory += b"\x00" * extend_memory.expand_by
223
    contract_address = compute_create2_contract_address(
224
        evm.message.current_target,
225
        salt,
226
        memory_read_bytes(evm.memory, memory_start_position, memory_size),
227
    )
228
229
    generic_create(
230
        evm,
231
        endowment,
232
        contract_address,
233
        memory_start_position,
234
        memory_size,
235
    )
236
237
    # PROGRAM COUNTER
238
    evm.pc += Uint(1)

return_

Halts execution returning output data.

Parameters

evm : The current EVM frame.

def return_(evm: Evm) -> None:
242
    <snip>
251
    # STACK
252
    memory_start_position = pop(evm.stack)
253
    memory_size = pop(evm.stack)
254
255
    # GAS
256
    extend_memory = calculate_gas_extend_memory(
257
        evm.memory, [(memory_start_position, memory_size)]
258
    )
259
260
    charge_gas(evm, GasCosts.ZERO + extend_memory.cost)
261
262
    # OPERATION
263
    evm.memory += b"\x00" * extend_memory.expand_by
264
    evm.output = memory_read_bytes(
265
        evm.memory, memory_start_position, memory_size
266
    )
267
268
    evm.running = False
269
270
    # PROGRAM COUNTER
271
    pass

GenericCall

Parameters for the core logic of the CALL* family of opcodes.

274
@final
275
@dataclass
class GenericCall:

gas

281
    gas: Uint

value

282
    value: U256

caller

283
    caller: Address

to

284
    to: Address

code_address

285
    code_address: Address

should_transfer_value

286
    should_transfer_value: bool

is_staticcall

287
    is_staticcall: bool

memory_input_start_position

288
    memory_input_start_position: U256

memory_input_size

289
    memory_input_size: U256

memory_output_start_position

290
    memory_output_start_position: U256

memory_output_size

291
    memory_output_size: U256

code

292
    code: Bytes

disable_precompiles

293
    disable_precompiles: bool

generic_call

Perform the core logic of the CALL* family of opcodes.

def generic_call(evm: Evm, ​​params: GenericCall) -> None:
297
    <snip>
300
    from ...vm.interpreter import STACK_DEPTH_LIMIT, process_message
301
302
    evm.return_data = b""
303
304
    if evm.message.depth + Uint(1) > STACK_DEPTH_LIMIT:
305
        evm.gas_left += params.gas
306
        push(evm.stack, U256(0))
307
        return
308
309
    call_data = memory_read_bytes(
310
        evm.memory,
311
        params.memory_input_start_position,
312
        params.memory_input_size,
313
    )
314
315
    child_message = Message(
316
        block_env=evm.message.block_env,
317
        tx_env=evm.message.tx_env,
318
        caller=params.caller,
319
        target=params.to,
320
        gas=params.gas,
321
        value=params.value,
322
        data=call_data,
323
        code=params.code,
324
        current_target=params.to,
325
        depth=evm.message.depth + Uint(1),
326
        code_address=params.code_address,
327
        should_transfer_value=params.should_transfer_value,
328
        is_static=params.is_staticcall or evm.message.is_static,
329
        accessed_addresses=evm.accessed_addresses.copy(),
330
        accessed_storage_keys=evm.accessed_storage_keys.copy(),
331
        disable_precompiles=params.disable_precompiles,
332
        parent_evm=evm,
333
    )
334
    child_evm = process_message(child_message)
335
336
    if child_evm.error:
337
        incorporate_child_on_error(evm, child_evm)
338
        evm.return_data = child_evm.output
339
        push(evm.stack, U256(0))
340
    else:
341
        incorporate_child_on_success(evm, child_evm)
342
        evm.return_data = child_evm.output
343
        push(evm.stack, U256(1))
344
345
    actual_output_size = min(
346
        params.memory_output_size, U256(len(child_evm.output))
347
    )
348
    memory_write(
349
        evm.memory,
350
        params.memory_output_start_position,
351
        child_evm.output[:actual_output_size],
352
    )

call

Message-call into an account.

Parameters

evm : The current EVM frame.

def call(evm: Evm) -> None:
356
    <snip>
365
    # STACK
366
    gas = Uint(pop(evm.stack))
367
    to = to_address_masked(pop(evm.stack))
368
    value = pop(evm.stack)
369
    memory_input_start_position = pop(evm.stack)
370
    memory_input_size = pop(evm.stack)
371
    memory_output_start_position = pop(evm.stack)
372
    memory_output_size = pop(evm.stack)
373
374
    # GAS
375
    extend_memory = calculate_gas_extend_memory(
376
        evm.memory,
377
        [
378
            (memory_input_start_position, memory_input_size),
379
            (memory_output_start_position, memory_output_size),
380
        ],
381
    )
382
383
    if to in evm.accessed_addresses:
384
        access_gas_cost = GasCosts.WARM_ACCESS
385
    else:
386
        evm.accessed_addresses.add(to)
387
        access_gas_cost = GasCosts.COLD_ACCOUNT_ACCESS
388
389
    code_address = to
390
    (
391
        disable_precompiles,
392
        code_address,
393
        code,
394
        delegated_access_gas_cost,
395
    ) = access_delegation(evm, code_address)
396
    access_gas_cost += delegated_access_gas_cost
397
398
    create_gas_cost = GasCosts.NEW_ACCOUNT
399
    if value == 0 or is_account_alive(evm.message.tx_env.state, to):
400
        create_gas_cost = Uint(0)
401
    transfer_gas_cost = Uint(0) if value == 0 else GasCosts.CALL_VALUE
402
    message_call_gas = calculate_message_call_gas(
403
        value,
404
        gas,
405
        Uint(evm.gas_left),
406
        memory_cost=extend_memory.cost,
407
        extra_gas=access_gas_cost + create_gas_cost + transfer_gas_cost,
408
    )
409
    charge_gas(evm, message_call_gas.cost + extend_memory.cost)
410
    if evm.message.is_static and value != U256(0):
411
        raise WriteInStaticContext
412
    evm.memory += b"\x00" * extend_memory.expand_by
413
    sender_balance = get_account(
414
        evm.message.tx_env.state, evm.message.current_target
415
    ).balance
416
    if sender_balance < value:
417
        push(evm.stack, U256(0))
418
        evm.return_data = b""
419
        evm.gas_left += message_call_gas.sub_call
420
    else:
421
        generic_call(
422
            evm,
423
            GenericCall(
424
                gas=message_call_gas.sub_call,
425
                value=value,
426
                caller=evm.message.current_target,
427
                to=to,
428
                code_address=code_address,
429
                should_transfer_value=True,
430
                is_staticcall=False,
431
                memory_input_start_position=memory_input_start_position,
432
                memory_input_size=memory_input_size,
433
                memory_output_start_position=memory_output_start_position,
434
                memory_output_size=memory_output_size,
435
                code=code,
436
                disable_precompiles=disable_precompiles,
437
            ),
438
        )
439
440
    # PROGRAM COUNTER
441
    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:
445
    <snip>
454
    # STACK
455
    gas = Uint(pop(evm.stack))
456
    code_address = to_address_masked(pop(evm.stack))
457
    value = pop(evm.stack)
458
    memory_input_start_position = pop(evm.stack)
459
    memory_input_size = pop(evm.stack)
460
    memory_output_start_position = pop(evm.stack)
461
    memory_output_size = pop(evm.stack)
462
463
    # GAS
464
    to = evm.message.current_target
465
466
    extend_memory = calculate_gas_extend_memory(
467
        evm.memory,
468
        [
469
            (memory_input_start_position, memory_input_size),
470
            (memory_output_start_position, memory_output_size),
471
        ],
472
    )
473
474
    if code_address in evm.accessed_addresses:
475
        access_gas_cost = GasCosts.WARM_ACCESS
476
    else:
477
        evm.accessed_addresses.add(code_address)
478
        access_gas_cost = GasCosts.COLD_ACCOUNT_ACCESS
479
480
    (
481
        disable_precompiles,
482
        code_address,
483
        code,
484
        delegated_access_gas_cost,
485
    ) = access_delegation(evm, code_address)
486
    access_gas_cost += delegated_access_gas_cost
487
488
    transfer_gas_cost = Uint(0) if value == 0 else GasCosts.CALL_VALUE
489
    message_call_gas = calculate_message_call_gas(
490
        value,
491
        gas,
492
        Uint(evm.gas_left),
493
        extend_memory.cost,
494
        access_gas_cost + transfer_gas_cost,
495
    )
496
    charge_gas(evm, message_call_gas.cost + extend_memory.cost)
497
498
    # OPERATION
499
    evm.memory += b"\x00" * extend_memory.expand_by
500
    sender_balance = get_account(
500
        evm.message.tx_env.state, evm.message.current_target
501
        evm.message.tx_env.state,
502
        evm.message.current_target,
503
    ).balance
504
    if sender_balance < value:
505
        push(evm.stack, U256(0))
506
        evm.return_data = b""
507
        evm.gas_left += message_call_gas.sub_call
508
    else:
509
        generic_call(
510
            evm,
511
            GenericCall(
512
                gas=message_call_gas.sub_call,
513
                value=value,
514
                caller=evm.message.current_target,
515
                to=to,
516
                code_address=code_address,
517
                should_transfer_value=True,
518
                is_staticcall=False,
519
                memory_input_start_position=memory_input_start_position,
520
                memory_input_size=memory_input_size,
521
                memory_output_start_position=memory_output_start_position,
522
                memory_output_size=memory_output_size,
523
                code=code,
524
                disable_precompiles=disable_precompiles,
525
            ),
526
        )
527
528
    # PROGRAM COUNTER
529
    evm.pc += Uint(1)

selfdestruct

Halt execution and register account for later deletion.

Parameters

evm : The current EVM frame.

def selfdestruct(evm: Evm) -> None:
533
    <snip>
542
    # STACK
543
    beneficiary = to_address_masked(pop(evm.stack))
544
545
    # GAS
546
    gas_cost = GasCosts.OPCODE_SELFDESTRUCT_BASE
547
    if beneficiary not in evm.accessed_addresses:
548
        evm.accessed_addresses.add(beneficiary)
549
        gas_cost += GasCosts.COLD_ACCOUNT_ACCESS
550
551
    if (
552
        not is_account_alive(evm.message.tx_env.state, beneficiary)
553
        and get_account(
552
            evm.message.tx_env.state, evm.message.current_target
554
            evm.message.tx_env.state,
555
            evm.message.current_target,
556
        ).balance
557
        != 0
558
    ):
559
        gas_cost += GasCosts.OPCODE_SELFDESTRUCT_NEW_ACCOUNT
560
561
    charge_gas(evm, gas_cost)
562
    if evm.message.is_static:
563
        raise WriteInStaticContext
564
565
    originator = evm.message.current_target
566
    originator_balance = get_account(
567
        evm.message.tx_env.state, originator
568
    ).balance
569
570
    move_ether(
571
        evm.message.tx_env.state,
572
        originator,
573
        beneficiary,
574
        originator_balance,
575
    )
576
577
    # register account for deletion only if it was created
578
    # in the same transaction
579
    if originator in evm.message.tx_env.state.created_accounts:
580
        # If beneficiary is the same as originator, then
581
        # the ether is burnt.
582
        set_account_balance(evm.message.tx_env.state, originator, U256(0))
583
        evm.accounts_to_delete.add(originator)
584
585
    # HALT the execution
586
    evm.running = False
587
588
    # PROGRAM COUNTER
589
    pass

delegatecall

Message-call into an account.

Parameters

evm : The current EVM frame.

def delegatecall(evm: Evm) -> None:
593
    <snip>
602
    # STACK
603
    gas = Uint(pop(evm.stack))
604
    code_address = to_address_masked(pop(evm.stack))
605
    memory_input_start_position = pop(evm.stack)
606
    memory_input_size = pop(evm.stack)
607
    memory_output_start_position = pop(evm.stack)
608
    memory_output_size = pop(evm.stack)
609
610
    # GAS
611
    extend_memory = calculate_gas_extend_memory(
612
        evm.memory,
613
        [
614
            (memory_input_start_position, memory_input_size),
615
            (memory_output_start_position, memory_output_size),
616
        ],
617
    )
618
619
    if code_address in evm.accessed_addresses:
620
        access_gas_cost = GasCosts.WARM_ACCESS
621
    else:
622
        evm.accessed_addresses.add(code_address)
623
        access_gas_cost = GasCosts.COLD_ACCOUNT_ACCESS
624
625
    (
626
        disable_precompiles,
627
        code_address,
628
        code,
629
        delegated_access_gas_cost,
630
    ) = access_delegation(evm, code_address)
631
    access_gas_cost += delegated_access_gas_cost
632
633
    message_call_gas = calculate_message_call_gas(
631
        U256(0), gas, Uint(evm.gas_left), extend_memory.cost, access_gas_cost
634
        U256(0),
635
        gas,
636
        Uint(evm.gas_left),
637
        extend_memory.cost,
638
        access_gas_cost,
639
    )
640
    charge_gas(evm, message_call_gas.cost + extend_memory.cost)
641
642
    # OPERATION
643
    evm.memory += b"\x00" * extend_memory.expand_by
644
    generic_call(
645
        evm,
646
        GenericCall(
647
            gas=message_call_gas.sub_call,
648
            value=evm.message.value,
649
            caller=evm.message.caller,
650
            to=evm.message.current_target,
651
            code_address=code_address,
652
            should_transfer_value=False,
653
            is_staticcall=False,
654
            memory_input_start_position=memory_input_start_position,
655
            memory_input_size=memory_input_size,
656
            memory_output_start_position=memory_output_start_position,
657
            memory_output_size=memory_output_size,
658
            code=code,
659
            disable_precompiles=disable_precompiles,
660
        ),
661
    )
662
663
    # PROGRAM COUNTER
664
    evm.pc += Uint(1)

staticcall

Message-call into an account.

Parameters

evm : The current EVM frame.

def staticcall(evm: Evm) -> None:
668
    <snip>
677
    # STACK
678
    gas = Uint(pop(evm.stack))
679
    to = to_address_masked(pop(evm.stack))
680
    memory_input_start_position = pop(evm.stack)
681
    memory_input_size = pop(evm.stack)
682
    memory_output_start_position = pop(evm.stack)
683
    memory_output_size = pop(evm.stack)
684
685
    # GAS
686
    extend_memory = calculate_gas_extend_memory(
687
        evm.memory,
688
        [
689
            (memory_input_start_position, memory_input_size),
690
            (memory_output_start_position, memory_output_size),
691
        ],
692
    )
693
694
    if to in evm.accessed_addresses:
695
        access_gas_cost = GasCosts.WARM_ACCESS
696
    else:
697
        evm.accessed_addresses.add(to)
698
        access_gas_cost = GasCosts.COLD_ACCOUNT_ACCESS
699
700
    code_address = to
701
    (
702
        disable_precompiles,
703
        code_address,
704
        code,
705
        delegated_access_gas_cost,
706
    ) = access_delegation(evm, code_address)
707
    access_gas_cost += delegated_access_gas_cost
708
709
    message_call_gas = calculate_message_call_gas(
710
        U256(0),
711
        gas,
712
        Uint(evm.gas_left),
713
        extend_memory.cost,
714
        access_gas_cost,
715
    )
716
    charge_gas(evm, message_call_gas.cost + extend_memory.cost)
717
718
    # OPERATION
719
    evm.memory += b"\x00" * extend_memory.expand_by
720
    generic_call(
721
        evm,
722
        GenericCall(
723
            gas=message_call_gas.sub_call,
724
            value=U256(0),
725
            caller=evm.message.current_target,
726
            to=to,
727
            code_address=code_address,
728
            should_transfer_value=True,
729
            is_staticcall=True,
730
            memory_input_start_position=memory_input_start_position,
731
            memory_input_size=memory_input_size,
732
            memory_output_start_position=memory_output_start_position,
733
            memory_output_size=memory_output_size,
734
            code=code,
735
            disable_precompiles=disable_precompiles,
736
        ),
737
    )
738
739
    # PROGRAM COUNTER
740
    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:
744
    <snip>
754
    # STACK
755
    memory_start_index = pop(evm.stack)
756
    size = pop(evm.stack)
757
758
    # GAS
759
    extend_memory = calculate_gas_extend_memory(
760
        evm.memory, [(memory_start_index, size)]
761
    )
762
763
    charge_gas(evm, extend_memory.cost)
764
765
    # OPERATION
766
    evm.memory += b"\x00" * extend_memory.expand_by
767
    output = memory_read_bytes(evm.memory, memory_start_index, size)
768
    evm.output = Bytes(output)
769
    raise Revert
770
771
    # PROGRAM COUNTER
772
    # no-op