ethereum.forks.gray_glacier.vm.instructions.systemethereum.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:
66
    """
67
    Core logic used by the `CREATE*` family of opcodes.
68
    """
69
    # This import causes a circular import error
70
    # if it's not moved inside this method
71
    from ...vm.interpreter import STACK_DEPTH_LIMIT, process_create_message
72
73
    call_data = memory_read_bytes(
74
        evm.memory, memory_start_position, memory_size
75
    )
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
158
    charge_gas(evm, GAS_CREATE + extend_memory.cost)
159
160
    # OPERATION
161
    evm.memory += b"\x00" * extend_memory.expand_by
162
    contract_address = compute_contract_address(
163
        evm.message.current_target,
164
        get_account(
165
            evm.message.block_env.state, evm.message.current_target
166
        ).nonce,
167
    )
168
169
    generic_create(
170
        evm, endowment, contract_address, memory_start_position, memory_size
171
    )
172
173
    # PROGRAM COUNTER
174
    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:
178
    """
179
    Creates a new account with associated code.
180
181
    It's similar to CREATE opcode except that the address of new account
182
    depends on the init_code instead of the nonce of sender.
183
184
    Parameters
185
    ----------
186
    evm :
187
        The current EVM frame.
188
189
    """
190
    # STACK
191
    endowment = pop(evm.stack)
192
    memory_start_position = pop(evm.stack)
193
    memory_size = pop(evm.stack)
194
    salt = pop(evm.stack).to_be_bytes32()
195
196
    # GAS
197
    extend_memory = calculate_gas_extend_memory(
198
        evm.memory, [(memory_start_position, memory_size)]
199
    )
200
    call_data_words = ceil32(Uint(memory_size)) // Uint(32)
201
    charge_gas(
202
        evm,
203
        GAS_CREATE + GAS_KECCAK256_WORD * call_data_words + extend_memory.cost,
204
    )
205
206
    # OPERATION
207
    evm.memory += b"\x00" * extend_memory.expand_by
208
    contract_address = compute_create2_contract_address(
209
        evm.message.current_target,
210
        salt,
211
        memory_read_bytes(evm.memory, memory_start_position, memory_size),
212
    )
213
214
    generic_create(
215
        evm, endowment, contract_address, memory_start_position, memory_size
216
    )
217
218
    # PROGRAM COUNTER
219
    evm.pc += Uint(1)

return_

Halts execution returning output data.

Parameters

evm : The current EVM frame.

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

call

Message-call into an account.

Parameters

evm : The current EVM frame.

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

selfdestruct

Halt execution and register account for later deletion.

Parameters

evm : The current EVM frame.

def selfdestruct(evm: Evm) -> None:
476
    """
477
    Halt execution and register account for later deletion.
478
479
    Parameters
480
    ----------
481
    evm :
482
        The current EVM frame.
483
484
    """
485
    # STACK
486
    beneficiary = to_address_masked(pop(evm.stack))
487
488
    # GAS
489
    gas_cost = GAS_SELF_DESTRUCT
490
    if beneficiary not in evm.accessed_addresses:
491
        evm.accessed_addresses.add(beneficiary)
492
        gas_cost += GAS_COLD_ACCOUNT_ACCESS
493
494
    if (
495
        not is_account_alive(evm.message.block_env.state, beneficiary)
496
        and get_account(
497
            evm.message.block_env.state, evm.message.current_target
498
        ).balance
499
        != 0
500
    ):
501
        gas_cost += GAS_SELF_DESTRUCT_NEW_ACCOUNT
502
503
    charge_gas(evm, gas_cost)
504
    if evm.message.is_static:
505
        raise WriteInStaticContext
506
507
    originator = evm.message.current_target
508
    beneficiary_balance = get_account(
509
        evm.message.block_env.state, beneficiary
510
    ).balance
511
    originator_balance = get_account(
512
        evm.message.block_env.state, originator
513
    ).balance
514
515
    # First Transfer to beneficiary
516
    set_account_balance(
517
        evm.message.block_env.state,
518
        beneficiary,
519
        beneficiary_balance + originator_balance,
520
    )
521
    # Next, Zero the balance of the address being deleted (must come after
522
    # sending to beneficiary in case the contract named itself as the
523
    # beneficiary).
524
    set_account_balance(evm.message.block_env.state, originator, U256(0))
525
526
    # register account for deletion
527
    evm.accounts_to_delete.add(originator)
528
530
    # mark beneficiary as touched
531
    if account_exists_and_is_empty(evm.message.block_env.state, beneficiary):
532
        evm.touched_accounts.add(beneficiary)
533
529
    # HALT the execution
530
    evm.running = False
531
532
    # PROGRAM COUNTER
533
    pass

delegatecall

Message-call into an account.

Parameters

evm : The current EVM frame.

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

staticcall

Message-call into an account.

Parameters

evm : The current EVM frame.

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