ethereum.byzantium.vm.instructions.system

Ethereum Virtual Machine (EVM) System Instructions ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

.. contents:: Table of Contents :backlinks: none :local:

Introduction

Implementations of the EVM system related instructions.

create

Creates a new account with associated code.

Parameters

evm : The current EVM frame.

def create(evm: Evm) -> None:
54
    """
55
    Creates a new account with associated code.
56
57
    Parameters
58
    ----------
59
    evm :
60
        The current EVM frame.
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
    # STACK
67
    endowment = pop(evm.stack)
68
    memory_start_position = pop(evm.stack)
69
    memory_size = pop(evm.stack)
70
71
    # GAS
72
    extend_memory = calculate_gas_extend_memory(
73
        evm.memory, [(memory_start_position, memory_size)]
74
    )
75
76
    charge_gas(evm, GAS_CREATE + extend_memory.cost)
77
78
    create_message_gas = max_message_call_gas(Uint(evm.gas_left))
79
    evm.gas_left -= create_message_gas
80
    if evm.message.is_static:
81
        raise WriteInStaticContext
82
    evm.memory += b"\x00" * extend_memory.expand_by
83
    evm.return_data = b""
84
85
    sender_address = evm.message.current_target
86
    sender = get_account(evm.message.block_env.state, sender_address)
87
88
    contract_address = compute_contract_address(
89
        evm.message.current_target,
90
        get_account(
91
            evm.message.block_env.state, evm.message.current_target
92
        ).nonce,
93
    )
94
95
    if (
96
        sender.balance < endowment
97
        or sender.nonce == Uint(2**64 - 1)
98
        or evm.message.depth + Uint(1) > STACK_DEPTH_LIMIT
99
    ):
100
        push(evm.stack, U256(0))
101
        evm.gas_left += create_message_gas
102
    elif account_has_code_or_nonce(
103
        evm.message.block_env.state, contract_address
104
    ) or account_has_storage(evm.message.block_env.state, contract_address):
105
        increment_nonce(
106
            evm.message.block_env.state, evm.message.current_target
107
        )
108
        push(evm.stack, U256(0))
109
    else:
110
        call_data = memory_read_bytes(
111
            evm.memory, memory_start_position, memory_size
112
        )
113
114
        increment_nonce(
115
            evm.message.block_env.state, evm.message.current_target
116
        )
117
118
        child_message = Message(
119
            block_env=evm.message.block_env,
120
            tx_env=evm.message.tx_env,
121
            caller=evm.message.current_target,
122
            target=Bytes0(),
123
            gas=create_message_gas,
124
            value=endowment,
125
            data=b"",
126
            code=call_data,
127
            current_target=contract_address,
128
            depth=evm.message.depth + Uint(1),
129
            code_address=None,
130
            should_transfer_value=True,
131
            is_static=False,
132
            parent_evm=evm,
133
        )
134
        child_evm = process_create_message(child_message)
135
136
        if child_evm.error:
137
            incorporate_child_on_error(evm, child_evm)
138
            evm.return_data = child_evm.output
139
            push(evm.stack, U256(0))
140
        else:
141
            incorporate_child_on_success(evm, child_evm)
142
            evm.return_data = b""
143
            push(
144
                evm.stack, U256.from_be_bytes(child_evm.message.current_target)
145
            )
146
147
    # PROGRAM COUNTER
148
    evm.pc += Uint(1)

return_

Halts execution returning output data.

Parameters

evm : The current EVM frame.

def return_(evm: Evm) -> None:
152
    """
153
    Halts execution returning output data.
154
155
    Parameters
156
    ----------
157
    evm :
158
        The current EVM frame.
159
    """
160
    # STACK
161
    memory_start_position = pop(evm.stack)
162
    memory_size = pop(evm.stack)
163
164
    # GAS
165
    extend_memory = calculate_gas_extend_memory(
166
        evm.memory, [(memory_start_position, memory_size)]
167
    )
168
169
    charge_gas(evm, GAS_ZERO + extend_memory.cost)
170
171
    # OPERATION
172
    evm.memory += b"\x00" * extend_memory.expand_by
173
    evm.output = memory_read_bytes(
174
        evm.memory, memory_start_position, memory_size
175
    )
176
177
    evm.running = False
178
179
    # PROGRAM COUNTER
180
    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:
197
    """
198
    Perform the core logic of the `CALL*` family of opcodes.
199
    """
200
    from ...vm.interpreter import STACK_DEPTH_LIMIT, process_message
201
202
    evm.return_data = b""
203
204
    if evm.message.depth + Uint(1) > STACK_DEPTH_LIMIT:
205
        evm.gas_left += gas
206
        push(evm.stack, U256(0))
207
        return
208
209
    call_data = memory_read_bytes(
210
        evm.memory, memory_input_start_position, memory_input_size
211
    )
212
    code = get_account(evm.message.block_env.state, code_address).code
213
    child_message = Message(
214
        block_env=evm.message.block_env,
215
        tx_env=evm.message.tx_env,
216
        caller=caller,
217
        target=to,
218
        gas=gas,
219
        value=value,
220
        data=call_data,
221
        code=code,
222
        current_target=to,
223
        depth=evm.message.depth + Uint(1),
224
        code_address=code_address,
225
        should_transfer_value=should_transfer_value,
226
        is_static=True if is_staticcall else evm.message.is_static,
227
        parent_evm=evm,
228
    )
229
    child_evm = process_message(child_message)
230
231
    if child_evm.error:
232
        incorporate_child_on_error(evm, child_evm)
233
        evm.return_data = child_evm.output
234
        push(evm.stack, U256(0))
235
    else:
236
        incorporate_child_on_success(evm, child_evm)
237
        evm.return_data = child_evm.output
238
        push(evm.stack, U256(1))
239
240
    actual_output_size = min(memory_output_size, U256(len(child_evm.output)))
241
    memory_write(
242
        evm.memory,
243
        memory_output_start_position,
244
        child_evm.output[:actual_output_size],
245
    )

call

Message-call into an account.

Parameters

evm : The current EVM frame.

def call(evm: Evm) -> None:
249
    """
250
    Message-call into an account.
251
252
    Parameters
253
    ----------
254
    evm :
255
        The current EVM frame.
256
    """
257
    # STACK
258
    gas = Uint(pop(evm.stack))
259
    to = to_address(pop(evm.stack))
260
    value = pop(evm.stack)
261
    memory_input_start_position = pop(evm.stack)
262
    memory_input_size = pop(evm.stack)
263
    memory_output_start_position = pop(evm.stack)
264
    memory_output_size = pop(evm.stack)
265
266
    # GAS
267
    extend_memory = calculate_gas_extend_memory(
268
        evm.memory,
269
        [
270
            (memory_input_start_position, memory_input_size),
271
            (memory_output_start_position, memory_output_size),
272
        ],
273
    )
274
275
    code_address = to
276
277
    create_gas_cost = (
278
        Uint(0)
279
        if is_account_alive(evm.message.block_env.state, to) or value == 0
280
        else GAS_NEW_ACCOUNT
281
    )
282
    transfer_gas_cost = Uint(0) if value == 0 else GAS_CALL_VALUE
283
    message_call_gas = calculate_message_call_gas(
284
        value,
285
        gas,
286
        Uint(evm.gas_left),
287
        extend_memory.cost,
288
        GAS_CALL + create_gas_cost + transfer_gas_cost,
289
    )
290
    charge_gas(evm, message_call_gas.cost + extend_memory.cost)
291
    if evm.message.is_static and value != U256(0):
292
        raise WriteInStaticContext
293
    evm.memory += b"\x00" * extend_memory.expand_by
294
    sender_balance = get_account(
295
        evm.message.block_env.state, evm.message.current_target
296
    ).balance
297
    if sender_balance < value:
298
        push(evm.stack, U256(0))
299
        evm.return_data = b""
300
        evm.gas_left += message_call_gas.sub_call
301
    else:
302
        generic_call(
303
            evm,
304
            message_call_gas.sub_call,
305
            value,
306
            evm.message.current_target,
307
            to,
308
            code_address,
309
            True,
310
            False,
311
            memory_input_start_position,
312
            memory_input_size,
313
            memory_output_start_position,
314
            memory_output_size,
315
        )
316
317
    # PROGRAM COUNTER
318
    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:
322
    """
323
    Message-call into this account with alternative account’s code.
324
325
    Parameters
326
    ----------
327
    evm :
328
        The current EVM frame.
329
    """
330
    # STACK
331
    gas = Uint(pop(evm.stack))
332
    code_address = to_address(pop(evm.stack))
333
    value = pop(evm.stack)
334
    memory_input_start_position = pop(evm.stack)
335
    memory_input_size = pop(evm.stack)
336
    memory_output_start_position = pop(evm.stack)
337
    memory_output_size = pop(evm.stack)
338
339
    # GAS
340
    to = evm.message.current_target
341
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
    transfer_gas_cost = Uint(0) if value == 0 else GAS_CALL_VALUE
350
    message_call_gas = calculate_message_call_gas(
351
        value,
352
        gas,
353
        Uint(evm.gas_left),
354
        extend_memory.cost,
355
        GAS_CALL + transfer_gas_cost,
356
    )
357
    charge_gas(evm, message_call_gas.cost + extend_memory.cost)
358
359
    # OPERATION
360
    evm.memory += b"\x00" * extend_memory.expand_by
361
    sender_balance = get_account(
362
        evm.message.block_env.state, evm.message.current_target
363
    ).balance
364
    if sender_balance < value:
365
        push(evm.stack, U256(0))
366
        evm.return_data = b""
367
        evm.gas_left += message_call_gas.sub_call
368
    else:
369
        generic_call(
370
            evm,
371
            message_call_gas.sub_call,
372
            value,
373
            evm.message.current_target,
374
            to,
375
            code_address,
376
            True,
377
            False,
378
            memory_input_start_position,
379
            memory_input_size,
380
            memory_output_start_position,
381
            memory_output_size,
382
        )
383
384
    # PROGRAM COUNTER
385
    evm.pc += Uint(1)

selfdestruct

Halt execution and register account for later deletion.

Parameters

evm : The current EVM frame.

def selfdestruct(evm: Evm) -> None:
389
    """
390
    Halt execution and register account for later deletion.
391
392
    Parameters
393
    ----------
394
    evm :
395
        The current EVM frame.
396
    """
397
    # STACK
398
    beneficiary = to_address(pop(evm.stack))
399
400
    # GAS
401
    gas_cost = GAS_SELF_DESTRUCT
402
    if (
403
        not is_account_alive(evm.message.block_env.state, beneficiary)
404
        and get_account(
405
            evm.message.block_env.state, evm.message.current_target
406
        ).balance
407
        != 0
408
    ):
409
        gas_cost += GAS_SELF_DESTRUCT_NEW_ACCOUNT
410
411
    originator = evm.message.current_target
412
413
    refunded_accounts = evm.accounts_to_delete
414
    parent_evm = evm.message.parent_evm
415
    while parent_evm is not None:
416
        refunded_accounts.update(parent_evm.accounts_to_delete)
417
        parent_evm = parent_evm.message.parent_evm
418
419
    if originator not in refunded_accounts:
420
        evm.refund_counter += REFUND_SELF_DESTRUCT
421
422
    charge_gas(evm, gas_cost)
423
    if evm.message.is_static:
424
        raise WriteInStaticContext
425
426
    beneficiary_balance = get_account(
427
        evm.message.block_env.state, beneficiary
428
    ).balance
429
    originator_balance = get_account(
430
        evm.message.block_env.state, originator
431
    ).balance
432
433
    # First Transfer to beneficiary
434
    set_account_balance(
435
        evm.message.block_env.state,
436
        beneficiary,
437
        beneficiary_balance + originator_balance,
438
    )
439
    # Next, Zero the balance of the address being deleted (must come after
440
    # sending to beneficiary in case the contract named itself as the
441
    # beneficiary).
442
    set_account_balance(evm.message.block_env.state, originator, U256(0))
443
444
    # register account for deletion
445
    evm.accounts_to_delete.add(originator)
446
447
    # mark beneficiary as touched
448
    if account_exists_and_is_empty(evm.message.block_env.state, beneficiary):
449
        evm.touched_accounts.add(beneficiary)
450
451
    # HALT the execution
452
    evm.running = False
453
454
    # PROGRAM COUNTER
455
    pass

delegatecall

Message-call into an account.

Parameters

evm : The current EVM frame.

def delegatecall(evm: Evm) -> None:
459
    """
460
    Message-call into an account.
461
462
    Parameters
463
    ----------
464
    evm :
465
        The current EVM frame.
466
    """
467
    # STACK
468
    gas = Uint(pop(evm.stack))
469
    code_address = to_address(pop(evm.stack))
470
    memory_input_start_position = pop(evm.stack)
471
    memory_input_size = pop(evm.stack)
472
    memory_output_start_position = pop(evm.stack)
473
    memory_output_size = pop(evm.stack)
474
475
    # GAS
476
    extend_memory = calculate_gas_extend_memory(
477
        evm.memory,
478
        [
479
            (memory_input_start_position, memory_input_size),
480
            (memory_output_start_position, memory_output_size),
481
        ],
482
    )
483
    message_call_gas = calculate_message_call_gas(
484
        U256(0), gas, Uint(evm.gas_left), extend_memory.cost, GAS_CALL
485
    )
486
    charge_gas(evm, message_call_gas.cost + extend_memory.cost)
487
488
    # OPERATION
489
    evm.memory += b"\x00" * extend_memory.expand_by
490
    generic_call(
491
        evm,
492
        message_call_gas.sub_call,
493
        evm.message.value,
494
        evm.message.caller,
495
        evm.message.current_target,
496
        code_address,
497
        False,
498
        False,
499
        memory_input_start_position,
500
        memory_input_size,
501
        memory_output_start_position,
502
        memory_output_size,
503
    )
504
505
    # PROGRAM COUNTER
506
    evm.pc += Uint(1)

staticcall

Message-call into an account.

Parameters

evm : The current EVM frame.

def staticcall(evm: Evm) -> None:
510
    """
511
    Message-call into an account.
512
513
    Parameters
514
    ----------
515
    evm :
516
        The current EVM frame.
517
    """
518
    # STACK
519
    gas = Uint(pop(evm.stack))
520
    to = to_address(pop(evm.stack))
521
    memory_input_start_position = pop(evm.stack)
522
    memory_input_size = pop(evm.stack)
523
    memory_output_start_position = pop(evm.stack)
524
    memory_output_size = pop(evm.stack)
525
526
    # GAS
527
    extend_memory = calculate_gas_extend_memory(
528
        evm.memory,
529
        [
530
            (memory_input_start_position, memory_input_size),
531
            (memory_output_start_position, memory_output_size),
532
        ],
533
    )
534
535
    code_address = to
536
537
    message_call_gas = calculate_message_call_gas(
538
        U256(0),
539
        gas,
540
        Uint(evm.gas_left),
541
        extend_memory.cost,
542
        GAS_CALL,
543
    )
544
    charge_gas(evm, message_call_gas.cost + extend_memory.cost)
545
546
    # OPERATION
547
    evm.memory += b"\x00" * extend_memory.expand_by
548
    generic_call(
549
        evm,
550
        message_call_gas.sub_call,
551
        U256(0),
552
        evm.message.current_target,
553
        to,
554
        code_address,
555
        True,
556
        True,
557
        memory_input_start_position,
558
        memory_input_size,
559
        memory_output_start_position,
560
        memory_output_size,
561
    )
562
563
    # PROGRAM COUNTER
564
    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:
568
    """
569
    Stop execution and revert state changes, without consuming all provided gas
570
    and also has the ability to return a reason
571
    Parameters
572
    ----------
573
    evm :
574
        The current EVM frame.
575
    """
576
    # STACK
577
    memory_start_index = pop(evm.stack)
578
    size = pop(evm.stack)
579
580
    # GAS
581
    extend_memory = calculate_gas_extend_memory(
582
        evm.memory, [(memory_start_index, size)]
583
    )
584
585
    charge_gas(evm, extend_memory.cost)
586
587
    # OPERATION
588
    evm.memory += b"\x00" * extend_memory.expand_by
589
    output = memory_read_bytes(evm.memory, memory_start_index, size)
590
    evm.output = Bytes(output)
591
    raise Revert