ethereum.forks.muir_glacier.vm.instructions.systemethereum.forks.berlin.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:
69
    """
70
    Core logic used by the `CREATE*` family of opcodes.
71
    """
72
    # This import causes a circular import error
73
    # if it's not moved inside this method
74
    from ...vm.interpreter import STACK_DEPTH_LIMIT, process_create_message
75
76
    call_data = memory_read_bytes(
77
        evm.memory, memory_start_position, memory_size
78
    )
79
80
    create_message_gas = max_message_call_gas(Uint(evm.gas_left))
81
    evm.gas_left -= create_message_gas
82
    if evm.message.is_static:
83
        raise WriteInStaticContext
84
    evm.return_data = b""
85
86
    sender_address = evm.message.current_target
87
    sender = get_account(evm.message.block_env.state, sender_address)
88
89
    if (
90
        sender.balance < endowment
91
        or sender.nonce == Uint(2**64 - 1)
92
        or evm.message.depth + Uint(1) > STACK_DEPTH_LIMIT
93
    ):
94
        evm.gas_left += create_message_gas
95
        push(evm.stack, U256(0))
96
        return
97
98
    evm.accessed_addresses.add(contract_address)
99
100
    if account_has_code_or_nonce(
101
        evm.message.block_env.state, contract_address
102
    ) or account_has_storage(evm.message.block_env.state, contract_address):
103
        increment_nonce(
104
            evm.message.block_env.state, evm.message.current_target
105
        )
106
        push(evm.stack, U256(0))
107
        return
105
106
    call_data = memory_read_bytes(
107
        evm.memory, memory_start_position, memory_size
108
    )
108
109
    increment_nonce(evm.message.block_env.state, evm.message.current_target)
110
111
    child_message = Message(
112
        block_env=evm.message.block_env,
113
        tx_env=evm.message.tx_env,
114
        caller=evm.message.current_target,
115
        target=Bytes0(),
116
        gas=create_message_gas,
117
        value=endowment,
118
        data=b"",
119
        code=call_data,
120
        current_target=contract_address,
121
        depth=evm.message.depth + Uint(1),
122
        code_address=None,
123
        should_transfer_value=True,
124
        is_static=False,
125
        accessed_addresses=evm.accessed_addresses.copy(),
126
        accessed_storage_keys=evm.accessed_storage_keys.copy(),
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
    """
143
    Creates a new account with associated code.
144
145
    Parameters
146
    ----------
147
    evm :
148
        The current EVM frame.
149
150
    """
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
161
    charge_gas(evm, GAS_CREATE + extend_memory.cost)
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(
173
        evm, endowment, contract_address, memory_start_position, memory_size
174
    )
175
176
    # PROGRAM COUNTER
177
    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:
181
    """
182
    Creates a new account with associated code.
183
184
    It's similar to the CREATE opcode except that the address of the new
185
    account depends on the init_code instead of the nonce of sender.
186
187
    Parameters
188
    ----------
189
    evm :
190
        The current EVM frame.
191
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)) // Uint(32)
204
    charge_gas(
205
        evm,
206
        GAS_CREATE
207
        + GAS_KECCAK256_PER_WORD * call_data_words
208
        + extend_memory.cost,
209
    )
210
211
    # OPERATION
212
    evm.memory += b"\x00" * extend_memory.expand_by
213
    contract_address = compute_create2_contract_address(
214
        evm.message.current_target,
215
        salt,
216
        memory_read_bytes(evm.memory, memory_start_position, memory_size),
217
    )
218
219
    generic_create(
220
        evm, endowment, contract_address, memory_start_position, memory_size
221
    )
222
223
    # PROGRAM COUNTER
224
    evm.pc += Uint(1)

return_

Halts execution returning output data.

Parameters

evm : The current EVM frame.

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

call

Message-call into an account.

Parameters

evm : The current EVM frame.

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

selfdestruct

Halt execution and register account for later deletion.

Parameters

evm : The current EVM frame.

def selfdestruct(evm: Evm) -> None:
482
    """
483
    Halt execution and register account for later deletion.
484
485
    Parameters
486
    ----------
487
    evm :
488
        The current EVM frame.
489
490
    """
491
    # STACK
492
    beneficiary = to_address_masked(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.message.block_env.state, beneficiary)
502
        and get_account(
503
            evm.message.block_env.state, evm.message.current_target
504
        ).balance
505
        != 0
506
    ):
507
        gas_cost += GAS_SELF_DESTRUCT_NEW_ACCOUNT
508
509
    originator = evm.message.current_target
510
511
    refunded_accounts = evm.accounts_to_delete
512
    parent_evm = evm.message.parent_evm
513
    while parent_evm is not None:
514
        refunded_accounts.update(parent_evm.accounts_to_delete)
515
        parent_evm = parent_evm.message.parent_evm
516
517
    if originator not in refunded_accounts:
518
        evm.refund_counter += REFUND_SELF_DESTRUCT
519
520
    charge_gas(evm, gas_cost)
521
    if evm.message.is_static:
522
        raise WriteInStaticContext
523
524
    originator = evm.message.current_target
525
    beneficiary_balance = get_account(
526
        evm.message.block_env.state, beneficiary
527
    ).balance
528
    originator_balance = get_account(
529
        evm.message.block_env.state, originator
530
    ).balance
531
532
    # First Transfer to beneficiary
533
    set_account_balance(
534
        evm.message.block_env.state,
535
        beneficiary,
536
        beneficiary_balance + originator_balance,
537
    )
538
    # Next, Zero the balance of the address being deleted (must come after
539
    # sending to beneficiary in case the contract named itself as the
540
    # beneficiary).
541
    set_account_balance(evm.message.block_env.state, originator, U256(0))
542
543
    # register account for deletion
544
    evm.accounts_to_delete.add(originator)
545
546
    # mark beneficiary as touched
547
    if account_exists_and_is_empty(evm.message.block_env.state, beneficiary):
548
        evm.touched_accounts.add(beneficiary)
549
550
    # HALT the execution
551
    evm.running = False
552
553
    # PROGRAM COUNTER
554
    pass

delegatecall

Message-call into an account.

Parameters

evm : The current EVM frame.

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

staticcall

Message-call into an account.

Parameters

evm : The current EVM frame.

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