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

return_

Halts execution returning output data.

Parameters

evm : The current EVM frame.

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

call

Message-call into an account.

Parameters

evm : The current EVM frame.

def call(evm: Evm) -> None:
308
    """
309
    Message-call into an account.
310
311
    Parameters
312
    ----------
313
    evm :
314
        The current EVM frame.
315
    """
316
    # STACK
317
    gas = Uint(pop(evm.stack))
318
    to = to_address(pop(evm.stack))
319
    value = pop(evm.stack)
320
    memory_input_start_position = pop(evm.stack)
321
    memory_input_size = pop(evm.stack)
322
    memory_output_start_position = pop(evm.stack)
323
    memory_output_size = pop(evm.stack)
324
325
    # GAS
326
    extend_memory = calculate_gas_extend_memory(
327
        evm.memory,
328
        [
329
            (memory_input_start_position, memory_input_size),
330
            (memory_output_start_position, memory_output_size),
331
        ],
332
    )
333
334
    if to in evm.accessed_addresses:
335
        access_gas_cost = GAS_WARM_ACCESS
336
    else:
337
        evm.accessed_addresses.add(to)
338
        access_gas_cost = GAS_COLD_ACCOUNT_ACCESS
339
340
    create_gas_cost = (
341
        Uint(0)
342
        if is_account_alive(evm.env.state, to) or value == 0
343
        else GAS_NEW_ACCOUNT
344
    )
345
    transfer_gas_cost = Uint(0) if value == 0 else GAS_CALL_VALUE
346
    message_call_gas = calculate_message_call_gas(
347
        value,
348
        gas,
349
        Uint(evm.gas_left),
350
        extend_memory.cost,
351
        access_gas_cost + create_gas_cost + transfer_gas_cost,
352
    )
353
    charge_gas(evm, message_call_gas.cost + extend_memory.cost)
354
    if evm.message.is_static and value != U256(0):
355
        raise WriteInStaticContext
356
    evm.memory += b"\x00" * extend_memory.expand_by
357
    sender_balance = get_account(
358
        evm.env.state, evm.message.current_target
359
    ).balance
360
    if sender_balance < value:
361
        push(evm.stack, U256(0))
362
        evm.return_data = b""
363
        evm.gas_left += message_call_gas.stipend
364
    else:
365
        generic_call(
366
            evm,
367
            message_call_gas.stipend,
368
            value,
369
            evm.message.current_target,
370
            to,
371
            to,
372
            True,
373
            False,
374
            memory_input_start_position,
375
            memory_input_size,
376
            memory_output_start_position,
377
            memory_output_size,
378
        )
379
380
    # PROGRAM COUNTER
381
    evm.pc += 1

callcode

Message-call into this account with alternative account’s code.

Parameters

evm : The current EVM frame.

def callcode(evm: Evm) -> None:
385
    """
386
    Message-call into this account with alternative account’s code.
387
388
    Parameters
389
    ----------
390
    evm :
391
        The current EVM frame.
392
    """
393
    # STACK
394
    gas = Uint(pop(evm.stack))
395
    code_address = to_address(pop(evm.stack))
396
    value = pop(evm.stack)
397
    memory_input_start_position = pop(evm.stack)
398
    memory_input_size = pop(evm.stack)
399
    memory_output_start_position = pop(evm.stack)
400
    memory_output_size = pop(evm.stack)
401
402
    # GAS
403
    to = evm.message.current_target
404
405
    extend_memory = calculate_gas_extend_memory(
406
        evm.memory,
407
        [
408
            (memory_input_start_position, memory_input_size),
409
            (memory_output_start_position, memory_output_size),
410
        ],
411
    )
412
413
    if code_address in evm.accessed_addresses:
414
        access_gas_cost = GAS_WARM_ACCESS
415
    else:
416
        evm.accessed_addresses.add(code_address)
417
        access_gas_cost = GAS_COLD_ACCOUNT_ACCESS
418
419
    transfer_gas_cost = Uint(0) if value == 0 else GAS_CALL_VALUE
420
    message_call_gas = calculate_message_call_gas(
421
        value,
422
        gas,
423
        Uint(evm.gas_left),
424
        extend_memory.cost,
425
        access_gas_cost + transfer_gas_cost,
426
    )
427
    charge_gas(evm, message_call_gas.cost + extend_memory.cost)
428
429
    # OPERATION
430
    evm.memory += b"\x00" * extend_memory.expand_by
431
    sender_balance = get_account(
432
        evm.env.state, evm.message.current_target
433
    ).balance
434
    if sender_balance < value:
435
        push(evm.stack, U256(0))
436
        evm.return_data = b""
437
        evm.gas_left += message_call_gas.stipend
438
    else:
439
        generic_call(
440
            evm,
441
            message_call_gas.stipend,
442
            value,
443
            evm.message.current_target,
444
            to,
445
            code_address,
446
            True,
447
            False,
448
            memory_input_start_position,
449
            memory_input_size,
450
            memory_output_start_position,
451
            memory_output_size,
452
        )
453
454
    # PROGRAM COUNTER
455
    evm.pc += 1

selfdestruct

Halt execution and register account for later deletion.

Parameters

evm : The current EVM frame.

def selfdestruct(evm: Evm) -> None:
459
    """
460
    Halt execution and register account for later deletion.
461
462
    Parameters
463
    ----------
464
    evm :
465
        The current EVM frame.
466
    """
467
    # STACK
468
    beneficiary = to_address(pop(evm.stack))
469
470
    # GAS
471
    gas_cost = GAS_SELF_DESTRUCT
472
    if beneficiary not in evm.accessed_addresses:
473
        evm.accessed_addresses.add(beneficiary)
474
        gas_cost += GAS_COLD_ACCOUNT_ACCESS
475
476
    if (
477
        not is_account_alive(evm.env.state, beneficiary)
478
        and get_account(evm.env.state, evm.message.current_target).balance != 0
479
    ):
480
        gas_cost += GAS_SELF_DESTRUCT_NEW_ACCOUNT
481
482
    charge_gas(evm, gas_cost)
483
    if evm.message.is_static:
484
        raise WriteInStaticContext
485
486
    originator = evm.message.current_target
487
    beneficiary_balance = get_account(evm.env.state, beneficiary).balance
488
    originator_balance = get_account(evm.env.state, originator).balance
489
490
    # First Transfer to beneficiary
491
    set_account_balance(
492
        evm.env.state, beneficiary, beneficiary_balance + originator_balance
493
    )
494
    # Next, Zero the balance of the address being deleted (must come after
495
    # sending to beneficiary in case the contract named itself as the
496
    # beneficiary).
497
    set_account_balance(evm.env.state, originator, U256(0))
498
499
    # register account for deletion
500
    evm.accounts_to_delete.add(originator)
501
502
    # mark beneficiary as touched
503
    if account_exists_and_is_empty(evm.env.state, beneficiary):
504
        evm.touched_accounts.add(beneficiary)
505
506
    # HALT the execution
507
    evm.running = False
508
509
    # PROGRAM COUNTER
510
    pass

delegatecall

Message-call into an account.

Parameters

evm : The current EVM frame.

def delegatecall(evm: Evm) -> None:
514
    """
515
    Message-call into an account.
516
517
    Parameters
518
    ----------
519
    evm :
520
        The current EVM frame.
521
    """
522
    # STACK
523
    gas = Uint(pop(evm.stack))
524
    code_address = to_address(pop(evm.stack))
525
    memory_input_start_position = pop(evm.stack)
526
    memory_input_size = pop(evm.stack)
527
    memory_output_start_position = pop(evm.stack)
528
    memory_output_size = pop(evm.stack)
529
530
    # GAS
531
    extend_memory = calculate_gas_extend_memory(
532
        evm.memory,
533
        [
534
            (memory_input_start_position, memory_input_size),
535
            (memory_output_start_position, memory_output_size),
536
        ],
537
    )
538
539
    if code_address in evm.accessed_addresses:
540
        access_gas_cost = GAS_WARM_ACCESS
541
    else:
542
        evm.accessed_addresses.add(code_address)
543
        access_gas_cost = GAS_COLD_ACCOUNT_ACCESS
544
545
    message_call_gas = calculate_message_call_gas(
546
        U256(0), gas, Uint(evm.gas_left), extend_memory.cost, access_gas_cost
547
    )
548
    charge_gas(evm, message_call_gas.cost + extend_memory.cost)
549
550
    # OPERATION
551
    evm.memory += b"\x00" * extend_memory.expand_by
552
    generic_call(
553
        evm,
554
        message_call_gas.stipend,
555
        evm.message.value,
556
        evm.message.caller,
557
        evm.message.current_target,
558
        code_address,
559
        False,
560
        False,
561
        memory_input_start_position,
562
        memory_input_size,
563
        memory_output_start_position,
564
        memory_output_size,
565
    )
566
567
    # PROGRAM COUNTER
568
    evm.pc += 1

staticcall

Message-call into an account.

Parameters

evm : The current EVM frame.

def staticcall(evm: Evm) -> None:
572
    """
573
    Message-call into an account.
574
575
    Parameters
576
    ----------
577
    evm :
578
        The current EVM frame.
579
    """
580
    # STACK
581
    gas = Uint(pop(evm.stack))
582
    to = to_address(pop(evm.stack))
583
    memory_input_start_position = pop(evm.stack)
584
    memory_input_size = pop(evm.stack)
585
    memory_output_start_position = pop(evm.stack)
586
    memory_output_size = pop(evm.stack)
587
588
    # GAS
589
    extend_memory = calculate_gas_extend_memory(
590
        evm.memory,
591
        [
592
            (memory_input_start_position, memory_input_size),
593
            (memory_output_start_position, memory_output_size),
594
        ],
595
    )
596
597
    if to in evm.accessed_addresses:
598
        access_gas_cost = GAS_WARM_ACCESS
599
    else:
600
        evm.accessed_addresses.add(to)
601
        access_gas_cost = GAS_COLD_ACCOUNT_ACCESS
602
603
    message_call_gas = calculate_message_call_gas(
604
        U256(0),
605
        gas,
606
        Uint(evm.gas_left),
607
        extend_memory.cost,
608
        access_gas_cost,
609
    )
610
    charge_gas(evm, message_call_gas.cost + extend_memory.cost)
611
612
    # OPERATION
613
    evm.memory += b"\x00" * extend_memory.expand_by
614
    generic_call(
615
        evm,
616
        message_call_gas.stipend,
617
        U256(0),
618
        evm.message.current_target,
619
        to,
620
        to,
621
        True,
622
        True,
623
        memory_input_start_position,
624
        memory_input_size,
625
        memory_output_start_position,
626
        memory_output_size,
627
    )
628
629
    # PROGRAM COUNTER
630
    evm.pc += 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:
634
    """
635
    Stop execution and revert state changes, without consuming all provided gas
636
    and also has the ability to return a reason
637
    Parameters
638
    ----------
639
    evm :
640
        The current EVM frame.
641
    """
642
    # STACK
643
    memory_start_index = pop(evm.stack)
644
    size = pop(evm.stack)
645
646
    # GAS
647
    extend_memory = calculate_gas_extend_memory(
648
        evm.memory, [(memory_start_index, size)]
649
    )
650
651
    charge_gas(evm, extend_memory.cost)
652
653
    # OPERATION
654
    evm.memory += b"\x00" * extend_memory.expand_by
655
    output = memory_read_bytes(evm.memory, memory_start_index, size)
656
    evm.output = bytes(output)
657
    raise Revert
658
659
    # PROGRAM COUNTER
660
    pass