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

return_

Halts execution returning output data.

Parameters

evm : The current EVM frame.

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

call

Message-call into an account.

Parameters

evm : The current EVM frame.

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

selfdestruct

Halt execution and register account for later deletion.

Parameters

evm : The current EVM frame.

def selfdestruct(evm: Evm) -> None:
472
    """
473
    Halt execution and register account for later deletion.
474
475
    Parameters
476
    ----------
477
    evm :
478
        The current EVM frame.
479
480
    """
481
    # STACK
482
    beneficiary = to_address_masked(pop(evm.stack))
483
484
    # GAS
485
    gas_cost = GasCosts.OPCODE_SELFDESTRUCT_BASE
486
    if beneficiary not in evm.accessed_addresses:
487
        evm.accessed_addresses.add(beneficiary)
488
        gas_cost += GasCosts.COLD_ACCOUNT_ACCESS
489
490
    if (
491
        not is_account_alive(evm.message.block_env.state, beneficiary)
492
        and get_account(
493
            evm.message.block_env.state, evm.message.current_target
494
        ).balance
495
        != 0
496
    ):
497
        gas_cost += GasCosts.OPCODE_SELFDESTRUCT_NEW_ACCOUNT
498
499
    charge_gas(evm, gas_cost)
500
    if evm.message.is_static:
501
        raise WriteInStaticContext
502
503
    originator = evm.message.current_target
504
    beneficiary_balance = get_account(
505
        evm.message.block_env.state, beneficiary
506
    ).balance
507
    originator_balance = get_account(
508
        evm.message.block_env.state, originator
509
    ).balance
510
511
    # First Transfer to beneficiary
512
    set_account_balance(
513
        evm.message.block_env.state,
514
        beneficiary,
515
        beneficiary_balance + originator_balance,
516
    )
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.message.block_env.state, originator, U256(0))
521
522
    # register account for deletion
523
    evm.accounts_to_delete.add(originator)
524
525
    # HALT the execution
526
    evm.running = False
527
528
    # PROGRAM COUNTER
529
    pass

delegatecall

Message-call into an account.

Parameters

evm : The current EVM frame.

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

staticcall

Message-call into an account.

Parameters

evm : The current EVM frame.

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