ethereum.forks.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:
49
    """
50
    Creates a new account with associated code.
51
52
    Parameters
53
    ----------
54
    evm :
55
        The current EVM frame.
56
57
    """
58
    # This import causes a circular import error
59
    # if it's not moved inside this method
60
    from ...vm.interpreter import STACK_DEPTH_LIMIT, process_create_message
61
62
    # STACK
63
    endowment = pop(evm.stack)
64
    memory_start_position = pop(evm.stack)
65
    memory_size = pop(evm.stack)
66
67
    # GAS
68
    extend_memory = calculate_gas_extend_memory(
69
        evm.memory, [(memory_start_position, memory_size)]
70
    )
71
72
    charge_gas(evm, GasCosts.OPCODE_CREATE_BASE + extend_memory.cost)
73
74
    create_message_gas = max_message_call_gas(Uint(evm.gas_left))
75
    evm.gas_left -= create_message_gas
76
    if evm.message.is_static:
77
        raise WriteInStaticContext
78
    evm.memory += b"\x00" * extend_memory.expand_by
79
    evm.return_data = b""
80
81
    sender_address = evm.message.current_target
82
    sender = get_account(evm.message.tx_env.state, sender_address)
83
84
    contract_address = compute_contract_address(
85
        evm.message.current_target,
86
        get_account(
87
            evm.message.tx_env.state, evm.message.current_target
88
        ).nonce,
89
    )
90
91
    if (
92
        sender.balance < endowment
93
        or sender.nonce == Uint(2**64 - 1)
94
        or evm.message.depth + Uint(1) > STACK_DEPTH_LIMIT
95
    ):
96
        push(evm.stack, U256(0))
97
        evm.gas_left += create_message_gas
98
    elif account_has_code_or_nonce(
99
        evm.message.tx_env.state, contract_address
100
    ) or account_has_storage(evm.message.tx_env.state, contract_address):
101
        increment_nonce(evm.message.tx_env.state, evm.message.current_target)
102
        push(evm.stack, U256(0))
103
    else:
104
        call_data = memory_read_bytes(
105
            evm.memory, memory_start_position, memory_size
106
        )
107
108
        increment_nonce(evm.message.tx_env.state, evm.message.current_target)
109
110
        child_message = Message(
111
            block_env=evm.message.block_env,
112
            tx_env=evm.message.tx_env,
113
            caller=evm.message.current_target,
114
            target=Bytes0(),
115
            gas=create_message_gas,
116
            value=endowment,
117
            data=b"",
118
            code=call_data,
119
            current_target=contract_address,
120
            depth=evm.message.depth + Uint(1),
121
            code_address=None,
122
            should_transfer_value=True,
123
            is_static=False,
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(
136
                evm.stack, U256.from_be_bytes(child_evm.message.current_target)
137
            )
138
139
    # PROGRAM COUNTER
140
    evm.pc += Uint(1)

return_

Halts execution returning output data.

Parameters

evm : The current EVM frame.

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

call

Message-call into an account.

Parameters

evm : The current EVM frame.

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

selfdestruct

Halt execution and register account for later deletion.

Parameters

evm : The current EVM frame.

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

delegatecall

Message-call into an account.

Parameters

evm : The current EVM frame.

def delegatecall(evm: Evm) -> None:
454
    """
455
    Message-call into an account.
456
457
    Parameters
458
    ----------
459
    evm :
460
        The current EVM frame.
461
462
    """
463
    # STACK
464
    gas = Uint(pop(evm.stack))
465
    code_address = to_address_masked(pop(evm.stack))
466
    memory_input_start_position = pop(evm.stack)
467
    memory_input_size = pop(evm.stack)
468
    memory_output_start_position = pop(evm.stack)
469
    memory_output_size = pop(evm.stack)
470
471
    # GAS
472
    extend_memory = calculate_gas_extend_memory(
473
        evm.memory,
474
        [
475
            (memory_input_start_position, memory_input_size),
476
            (memory_output_start_position, memory_output_size),
477
        ],
478
    )
479
    message_call_gas = calculate_message_call_gas(
480
        U256(0),
481
        gas,
482
        Uint(evm.gas_left),
483
        extend_memory.cost,
484
        GasCosts.OPCODE_CALL_BASE,
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
    """
519
    # STACK
520
    gas = Uint(pop(evm.stack))
521
    to = to_address_masked(pop(evm.stack))
522
    memory_input_start_position = pop(evm.stack)
523
    memory_input_size = pop(evm.stack)
524
    memory_output_start_position = pop(evm.stack)
525
    memory_output_size = pop(evm.stack)
526
527
    # GAS
528
    extend_memory = calculate_gas_extend_memory(
529
        evm.memory,
530
        [
531
            (memory_input_start_position, memory_input_size),
532
            (memory_output_start_position, memory_output_size),
533
        ],
534
    )
535
536
    code_address = to
537
538
    message_call_gas = calculate_message_call_gas(
539
        U256(0),
540
        gas,
541
        Uint(evm.gas_left),
542
        extend_memory.cost,
543
        GasCosts.OPCODE_CALL_BASE,
544
    )
545
    charge_gas(evm, message_call_gas.cost + extend_memory.cost)
546
547
    # OPERATION
548
    evm.memory += b"\x00" * extend_memory.expand_by
549
    generic_call(
550
        evm,
551
        message_call_gas.sub_call,
552
        U256(0),
553
        evm.message.current_target,
554
        to,
555
        code_address,
556
        True,
557
        True,
558
        memory_input_start_position,
559
        memory_input_size,
560
        memory_output_start_position,
561
        memory_output_size,
562
    )
563
564
    # PROGRAM COUNTER
565
    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:
569
    """
570
    Stop execution and revert state changes, without consuming all provided gas
571
    and also has the ability to return a reason.
572
573
    Parameters
574
    ----------
575
    evm :
576
        The current EVM frame.
577
578
    """
579
    # STACK
580
    memory_start_index = pop(evm.stack)
581
    size = pop(evm.stack)
582
583
    # GAS
584
    extend_memory = calculate_gas_extend_memory(
585
        evm.memory, [(memory_start_index, size)]
586
    )
587
588
    charge_gas(evm, extend_memory.cost)
589
590
    # OPERATION
591
    evm.memory += b"\x00" * extend_memory.expand_by
592
    output = memory_read_bytes(evm.memory, memory_start_index, size)
593
    evm.output = Bytes(output)
594
    raise Revert
595
596
    # PROGRAM COUNTER
597
    # no-op