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.env.state, sender_address)
87
88
    contract_address = compute_contract_address(
89
        evm.message.current_target,
90
        get_account(evm.env.state, evm.message.current_target).nonce,
91
    )
92
93
    if (
94
        sender.balance < endowment
95
        or sender.nonce == Uint(2**64 - 1)
96
        or evm.message.depth + Uint(1) > STACK_DEPTH_LIMIT
97
    ):
98
        push(evm.stack, U256(0))
99
        evm.gas_left += create_message_gas
100
    elif account_has_code_or_nonce(
101
        evm.env.state, contract_address
102
    ) or account_has_storage(evm.env.state, contract_address):
103
        increment_nonce(evm.env.state, evm.message.current_target)
104
        push(evm.stack, U256(0))
105
    else:
106
        call_data = memory_read_bytes(
107
            evm.memory, memory_start_position, memory_size
108
        )
109
110
        increment_nonce(evm.env.state, evm.message.current_target)
111
112
        child_message = Message(
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, evm.env)
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
    # STACK
153
    memory_start_position = pop(evm.stack)
154
    memory_size = pop(evm.stack)
155
156
    # GAS
157
    extend_memory = calculate_gas_extend_memory(
158
        evm.memory, [(memory_start_position, memory_size)]
159
    )
160
161
    charge_gas(evm, GAS_ZERO + extend_memory.cost)
162
163
    # OPERATION
164
    evm.memory += b"\x00" * extend_memory.expand_by
165
    evm.output = memory_read_bytes(
166
        evm.memory, memory_start_position, memory_size
167
    )
168
169
    evm.running = False
170
171
    # PROGRAM COUNTER
172
    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:
189
    """
190
    Perform the core logic of the `CALL*` family of opcodes.
191
    """
192
    from ...vm.interpreter import STACK_DEPTH_LIMIT, process_message
193
194
    evm.return_data = b""
195
196
    if evm.message.depth + Uint(1) > STACK_DEPTH_LIMIT:
197
        evm.gas_left += gas
198
        push(evm.stack, U256(0))
199
        return
200
201
    call_data = memory_read_bytes(
202
        evm.memory, memory_input_start_position, memory_input_size
203
    )
204
    code = get_account(evm.env.state, code_address).code
205
    child_message = Message(
206
        caller=caller,
207
        target=to,
208
        gas=gas,
209
        value=value,
210
        data=call_data,
211
        code=code,
212
        current_target=to,
213
        depth=evm.message.depth + Uint(1),
214
        code_address=code_address,
215
        should_transfer_value=should_transfer_value,
216
        is_static=True if is_staticcall else evm.message.is_static,
217
        parent_evm=evm,
218
    )
219
    child_evm = process_message(child_message, evm.env)
220
221
    if child_evm.error:
222
        incorporate_child_on_error(evm, child_evm)
223
        evm.return_data = child_evm.output
224
        push(evm.stack, U256(0))
225
    else:
226
        incorporate_child_on_success(evm, child_evm)
227
        evm.return_data = child_evm.output
228
        push(evm.stack, U256(1))
229
230
    actual_output_size = min(memory_output_size, U256(len(child_evm.output)))
231
    memory_write(
232
        evm.memory,
233
        memory_output_start_position,
234
        child_evm.output[:actual_output_size],
235
    )

call

Message-call into an account.

Parameters

evm : The current EVM frame.

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

selfdestruct

Halt execution and register account for later deletion.

Parameters

evm : The current EVM frame.

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

delegatecall

Message-call into an account.

Parameters

evm : The current EVM frame.

def delegatecall(evm: Evm) -> None:
437
    """
438
    Message-call into an account.
439
440
    Parameters
441
    ----------
442
    evm :
443
        The current EVM frame.
444
    """
445
    # STACK
446
    gas = Uint(pop(evm.stack))
447
    code_address = to_address(pop(evm.stack))
448
    memory_input_start_position = pop(evm.stack)
449
    memory_input_size = pop(evm.stack)
450
    memory_output_start_position = pop(evm.stack)
451
    memory_output_size = pop(evm.stack)
452
453
    # GAS
454
    extend_memory = calculate_gas_extend_memory(
455
        evm.memory,
456
        [
457
            (memory_input_start_position, memory_input_size),
458
            (memory_output_start_position, memory_output_size),
459
        ],
460
    )
461
    message_call_gas = calculate_message_call_gas(
462
        U256(0), gas, Uint(evm.gas_left), extend_memory.cost, GAS_CALL
463
    )
464
    charge_gas(evm, message_call_gas.cost + extend_memory.cost)
465
466
    # OPERATION
467
    evm.memory += b"\x00" * extend_memory.expand_by
468
    generic_call(
469
        evm,
470
        message_call_gas.stipend,
471
        evm.message.value,
472
        evm.message.caller,
473
        evm.message.current_target,
474
        code_address,
475
        False,
476
        False,
477
        memory_input_start_position,
478
        memory_input_size,
479
        memory_output_start_position,
480
        memory_output_size,
481
    )
482
483
    # PROGRAM COUNTER
484
    evm.pc += Uint(1)

staticcall

Message-call into an account.

Parameters

evm : The current EVM frame.

def staticcall(evm: Evm) -> None:
488
    """
489
    Message-call into an account.
490
491
    Parameters
492
    ----------
493
    evm :
494
        The current EVM frame.
495
    """
496
    # STACK
497
    gas = Uint(pop(evm.stack))
498
    to = to_address(pop(evm.stack))
499
    memory_input_start_position = pop(evm.stack)
500
    memory_input_size = pop(evm.stack)
501
    memory_output_start_position = pop(evm.stack)
502
    memory_output_size = pop(evm.stack)
503
504
    # GAS
505
    extend_memory = calculate_gas_extend_memory(
506
        evm.memory,
507
        [
508
            (memory_input_start_position, memory_input_size),
509
            (memory_output_start_position, memory_output_size),
510
        ],
511
    )
512
    message_call_gas = calculate_message_call_gas(
513
        U256(0),
514
        gas,
515
        Uint(evm.gas_left),
516
        extend_memory.cost,
517
        GAS_CALL,
518
    )
519
    charge_gas(evm, message_call_gas.cost + extend_memory.cost)
520
521
    # OPERATION
522
    evm.memory += b"\x00" * extend_memory.expand_by
523
    generic_call(
524
        evm,
525
        message_call_gas.stipend,
526
        U256(0),
527
        evm.message.current_target,
528
        to,
529
        to,
530
        True,
531
        True,
532
        memory_input_start_position,
533
        memory_input_size,
534
        memory_output_start_position,
535
        memory_output_size,
536
    )
537
538
    # PROGRAM COUNTER
539
    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:
543
    """
544
    Stop execution and revert state changes, without consuming all provided gas
545
    and also has the ability to return a reason
546
    Parameters
547
    ----------
548
    evm :
549
        The current EVM frame.
550
    """
551
    # STACK
552
    memory_start_index = pop(evm.stack)
553
    size = pop(evm.stack)
554
555
    # GAS
556
    extend_memory = calculate_gas_extend_memory(
557
        evm.memory, [(memory_start_index, size)]
558
    )
559
560
    charge_gas(evm, extend_memory.cost)
561
562
    # OPERATION
563
    evm.memory += b"\x00" * extend_memory.expand_by
564
    output = memory_read_bytes(evm.memory, memory_start_index, size)
565
    evm.output = bytes(output)
566
    raise Revert
567
568
    # PROGRAM COUNTER
569
    pass