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

return_

Halts execution returning output data.

Parameters

evm : The current EVM frame.

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

call

Message-call into an account.

Parameters

evm : The current EVM frame.

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

selfdestruct

Halt execution and register account for later deletion.

Parameters

evm : The current EVM frame.

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

delegatecall

Message-call into an account.

Parameters

evm : The current EVM frame.

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

staticcall

Message-call into an account.

Parameters

evm : The current EVM frame.

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