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

return_

Halts execution returning output data.

Parameters

evm : The current EVM frame.

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

call

Message-call into an account.

Parameters

evm : The current EVM frame.

def call(evm: Evm) -> None:
304
    """
305
    Message-call into an account.
306
307
    Parameters
308
    ----------
309
    evm :
310
        The current EVM frame.
311
    """
312
    # STACK
313
    gas = Uint(pop(evm.stack))
314
    to = to_address(pop(evm.stack))
315
    value = pop(evm.stack)
316
    memory_input_start_position = pop(evm.stack)
317
    memory_input_size = pop(evm.stack)
318
    memory_output_start_position = pop(evm.stack)
319
    memory_output_size = pop(evm.stack)
320
321
    # GAS
322
    extend_memory = calculate_gas_extend_memory(
323
        evm.memory,
324
        [
325
            (memory_input_start_position, memory_input_size),
326
            (memory_output_start_position, memory_output_size),
327
        ],
328
    )
329
    create_gas_cost = (
330
        Uint(0)
331
        if value == 0 or is_account_alive(evm.env.state, to)
332
        else GAS_NEW_ACCOUNT
333
    )
334
    transfer_gas_cost = Uint(0) if value == 0 else GAS_CALL_VALUE
335
    message_call_gas = calculate_message_call_gas(
336
        value,
337
        gas,
338
        Uint(evm.gas_left),
339
        extend_memory.cost,
340
        GAS_CALL + create_gas_cost + transfer_gas_cost,
341
    )
342
    charge_gas(evm, message_call_gas.cost + extend_memory.cost)
343
    if evm.message.is_static and value != U256(0):
344
        raise WriteInStaticContext
345
    evm.memory += b"\x00" * extend_memory.expand_by
346
    sender_balance = get_account(
347
        evm.env.state, evm.message.current_target
348
    ).balance
349
    if sender_balance < value:
350
        push(evm.stack, U256(0))
351
        evm.return_data = b""
352
        evm.gas_left += message_call_gas.stipend
353
    else:
354
        generic_call(
355
            evm,
356
            message_call_gas.stipend,
357
            value,
358
            evm.message.current_target,
359
            to,
360
            to,
361
            True,
362
            False,
363
            memory_input_start_position,
364
            memory_input_size,
365
            memory_output_start_position,
366
            memory_output_size,
367
        )
368
369
    # PROGRAM COUNTER
370
    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:
374
    """
375
    Message-call into this account with alternative account’s code.
376
377
    Parameters
378
    ----------
379
    evm :
380
        The current EVM frame.
381
    """
382
    # STACK
383
    gas = Uint(pop(evm.stack))
384
    code_address = to_address(pop(evm.stack))
385
    value = pop(evm.stack)
386
    memory_input_start_position = pop(evm.stack)
387
    memory_input_size = pop(evm.stack)
388
    memory_output_start_position = pop(evm.stack)
389
    memory_output_size = pop(evm.stack)
390
391
    # GAS
392
    to = evm.message.current_target
393
394
    extend_memory = calculate_gas_extend_memory(
395
        evm.memory,
396
        [
397
            (memory_input_start_position, memory_input_size),
398
            (memory_output_start_position, memory_output_size),
399
        ],
400
    )
401
    transfer_gas_cost = Uint(0) if value == 0 else GAS_CALL_VALUE
402
    message_call_gas = calculate_message_call_gas(
403
        value,
404
        gas,
405
        Uint(evm.gas_left),
406
        extend_memory.cost,
407
        GAS_CALL + transfer_gas_cost,
408
    )
409
    charge_gas(evm, message_call_gas.cost + extend_memory.cost)
410
411
    # OPERATION
412
    evm.memory += b"\x00" * extend_memory.expand_by
413
    sender_balance = get_account(
414
        evm.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.stipend
420
    else:
421
        generic_call(
422
            evm,
423
            message_call_gas.stipend,
424
            value,
425
            evm.message.current_target,
426
            to,
427
            code_address,
428
            True,
429
            False,
430
            memory_input_start_position,
431
            memory_input_size,
432
            memory_output_start_position,
433
            memory_output_size,
434
        )
435
436
    # PROGRAM COUNTER
437
    evm.pc += Uint(1)

selfdestruct

Halt execution and register account for later deletion.

Parameters

evm : The current EVM frame.

def selfdestruct(evm: Evm) -> None:
441
    """
442
    Halt execution and register account for later deletion.
443
444
    Parameters
445
    ----------
446
    evm :
447
        The current EVM frame.
448
    """
449
    # STACK
450
    beneficiary = to_address(pop(evm.stack))
451
452
    # GAS
453
    gas_cost = GAS_SELF_DESTRUCT
454
    if (
455
        not is_account_alive(evm.env.state, beneficiary)
456
        and get_account(evm.env.state, evm.message.current_target).balance != 0
457
    ):
458
        gas_cost += GAS_SELF_DESTRUCT_NEW_ACCOUNT
459
460
    originator = evm.message.current_target
461
462
    refunded_accounts = evm.accounts_to_delete
463
    parent_evm = evm.message.parent_evm
464
    while parent_evm is not None:
465
        refunded_accounts.update(parent_evm.accounts_to_delete)
466
        parent_evm = parent_evm.message.parent_evm
467
468
    if originator not in refunded_accounts:
469
        evm.refund_counter += REFUND_SELF_DESTRUCT
470
471
    charge_gas(evm, gas_cost)
472
    if evm.message.is_static:
473
        raise WriteInStaticContext
474
475
    beneficiary_balance = get_account(evm.env.state, beneficiary).balance
476
    originator_balance = get_account(evm.env.state, originator).balance
477
478
    # First Transfer to beneficiary
479
    set_account_balance(
480
        evm.env.state, beneficiary, beneficiary_balance + originator_balance
481
    )
482
    # Next, Zero the balance of the address being deleted (must come after
483
    # sending to beneficiary in case the contract named itself as the
484
    # beneficiary).
485
    set_account_balance(evm.env.state, originator, U256(0))
486
487
    # register account for deletion
488
    evm.accounts_to_delete.add(originator)
489
490
    # mark beneficiary as touched
491
    if account_exists_and_is_empty(evm.env.state, beneficiary):
492
        evm.touched_accounts.add(beneficiary)
493
494
    # HALT the execution
495
    evm.running = False
496
497
    # PROGRAM COUNTER
498
    pass

delegatecall

Message-call into an account.

Parameters

evm : The current EVM frame.

def delegatecall(evm: Evm) -> None:
502
    """
503
    Message-call into an account.
504
505
    Parameters
506
    ----------
507
    evm :
508
        The current EVM frame.
509
    """
510
    # STACK
511
    gas = Uint(pop(evm.stack))
512
    code_address = to_address(pop(evm.stack))
513
    memory_input_start_position = pop(evm.stack)
514
    memory_input_size = pop(evm.stack)
515
    memory_output_start_position = pop(evm.stack)
516
    memory_output_size = pop(evm.stack)
517
518
    # GAS
519
    extend_memory = calculate_gas_extend_memory(
520
        evm.memory,
521
        [
522
            (memory_input_start_position, memory_input_size),
523
            (memory_output_start_position, memory_output_size),
524
        ],
525
    )
526
    message_call_gas = calculate_message_call_gas(
527
        U256(0), gas, Uint(evm.gas_left), extend_memory.cost, GAS_CALL
528
    )
529
    charge_gas(evm, message_call_gas.cost + extend_memory.cost)
530
531
    # OPERATION
532
    evm.memory += b"\x00" * extend_memory.expand_by
533
    generic_call(
534
        evm,
535
        message_call_gas.stipend,
536
        evm.message.value,
537
        evm.message.caller,
538
        evm.message.current_target,
539
        code_address,
540
        False,
541
        False,
542
        memory_input_start_position,
543
        memory_input_size,
544
        memory_output_start_position,
545
        memory_output_size,
546
    )
547
548
    # PROGRAM COUNTER
549
    evm.pc += Uint(1)

staticcall

Message-call into an account.

Parameters

evm : The current EVM frame.

def staticcall(evm: Evm) -> None:
553
    """
554
    Message-call into an account.
555
556
    Parameters
557
    ----------
558
    evm :
559
        The current EVM frame.
560
    """
561
    # STACK
562
    gas = Uint(pop(evm.stack))
563
    to = to_address(pop(evm.stack))
564
    memory_input_start_position = pop(evm.stack)
565
    memory_input_size = pop(evm.stack)
566
    memory_output_start_position = pop(evm.stack)
567
    memory_output_size = pop(evm.stack)
568
569
    # GAS
570
    extend_memory = calculate_gas_extend_memory(
571
        evm.memory,
572
        [
573
            (memory_input_start_position, memory_input_size),
574
            (memory_output_start_position, memory_output_size),
575
        ],
576
    )
577
    message_call_gas = calculate_message_call_gas(
578
        U256(0),
579
        gas,
580
        Uint(evm.gas_left),
581
        extend_memory.cost,
582
        GAS_CALL,
583
    )
584
    charge_gas(evm, message_call_gas.cost + extend_memory.cost)
585
586
    # OPERATION
587
    evm.memory += b"\x00" * extend_memory.expand_by
588
    generic_call(
589
        evm,
590
        message_call_gas.stipend,
591
        U256(0),
592
        evm.message.current_target,
593
        to,
594
        to,
595
        True,
596
        True,
597
        memory_input_start_position,
598
        memory_input_size,
599
        memory_output_start_position,
600
        memory_output_size,
601
    )
602
603
    # PROGRAM COUNTER
604
    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:
608
    """
609
    Stop execution and revert state changes, without consuming all provided gas
610
    and also has the ability to return a reason
611
    Parameters
612
    ----------
613
    evm :
614
        The current EVM frame.
615
    """
616
    # STACK
617
    memory_start_index = pop(evm.stack)
618
    size = pop(evm.stack)
619
620
    # GAS
621
    extend_memory = calculate_gas_extend_memory(
622
        evm.memory, [(memory_start_index, size)]
623
    )
624
625
    charge_gas(evm, extend_memory.cost)
626
627
    # OPERATION
628
    evm.memory += b"\x00" * extend_memory.expand_by
629
    output = memory_read_bytes(evm.memory, memory_start_index, size)
630
    evm.output = bytes(output)
631
    raise Revert
632
633
    # PROGRAM COUNTER
634
    pass