ethereum.spurious_dragon.vm.instructions.systemethereum.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
80
    # OPERATION
81
    evm.memory += b"\x00" * extend_memory.expand_by
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_masked(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 = GAS_NEW_ACCOUNT
278
    if value == 0 or is_account_alive(evm.message.block_env.state, to):
279
        create_gas_cost = Uint(0)
280
    transfer_gas_cost = Uint(0) if value == 0 else GAS_CALL_VALUE
281
    message_call_gas = calculate_message_call_gas(
282
        value,
283
        gas,
284
        Uint(evm.gas_left),
285
        extend_memory.cost,
286
        GAS_CALL + create_gas_cost + transfer_gas_cost,
287
    )
288
    charge_gas(evm, message_call_gas.cost + extend_memory.cost)
277
278
    # OPERATION
289
    if evm.message.is_static and value != U256(0):
290
        raise WriteInStaticContext
291
    evm.memory += b"\x00" * extend_memory.expand_by
292
    sender_balance = get_account(
293
        evm.message.block_env.state, evm.message.current_target
294
    ).balance
295
    if sender_balance < value:
296
        push(evm.stack, U256(0))
297
        evm.return_data = b""
298
        evm.gas_left += message_call_gas.sub_call
299
    else:
300
        generic_call(
301
            evm,
302
            message_call_gas.sub_call,
303
            value,
304
            evm.message.current_target,
305
            to,
306
            code_address,
307
            True,
308
            False,
309
            memory_input_start_position,
310
            memory_input_size,
311
            memory_output_start_position,
312
            memory_output_size,
313
        )
314
315
    # PROGRAM COUNTER
316
    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:
320
    """
321
    Message-call into this account with alternative account’s code.
322
323
    Parameters
324
    ----------
325
    evm :
326
        The current EVM frame.
327
    """
328
    # STACK
329
    gas = Uint(pop(evm.stack))
330
    code_address = to_address_masked(pop(evm.stack))
331
    value = pop(evm.stack)
332
    memory_input_start_position = pop(evm.stack)
333
    memory_input_size = pop(evm.stack)
334
    memory_output_start_position = pop(evm.stack)
335
    memory_output_size = pop(evm.stack)
336
337
    # GAS
338
    to = evm.message.current_target
339
340
    extend_memory = calculate_gas_extend_memory(
341
        evm.memory,
342
        [
343
            (memory_input_start_position, memory_input_size),
344
            (memory_output_start_position, memory_output_size),
345
        ],
346
    )
347
    transfer_gas_cost = Uint(0) if value == 0 else GAS_CALL_VALUE
348
    message_call_gas = calculate_message_call_gas(
349
        value,
350
        gas,
351
        Uint(evm.gas_left),
352
        extend_memory.cost,
353
        GAS_CALL + transfer_gas_cost,
354
    )
355
    charge_gas(evm, message_call_gas.cost + extend_memory.cost)
356
357
    # OPERATION
358
    evm.memory += b"\x00" * extend_memory.expand_by
359
    sender_balance = get_account(
360
        evm.message.block_env.state, evm.message.current_target
361
    ).balance
362
    if sender_balance < value:
363
        push(evm.stack, U256(0))
364
        evm.return_data = b""
365
        evm.gas_left += message_call_gas.sub_call
366
    else:
367
        generic_call(
368
            evm,
369
            message_call_gas.sub_call,
370
            value,
371
            evm.message.current_target,
372
            to,
373
            code_address,
374
            True,
375
            False,
376
            memory_input_start_position,
377
            memory_input_size,
378
            memory_output_start_position,
379
            memory_output_size,
380
        )
381
382
    # PROGRAM COUNTER
383
    evm.pc += Uint(1)

selfdestruct

Halt execution and register account for later deletion.

Parameters

evm : The current EVM frame.

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

delegatecall

Message-call into an account.

Parameters

evm : The current EVM frame.

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

staticcall

Message-call into an account.

Parameters

evm : The current EVM frame.

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