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

return_

Halts execution returning output data.

Parameters

evm : The current EVM frame.

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

call

Message-call into an account.

Parameters

evm : The current EVM frame.

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

selfdestruct

Halt execution and register account for later deletion.

Parameters

evm : The current EVM frame.

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

delegatecall

Message-call into an account.

Parameters

evm : The current EVM frame.

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

staticcall

Message-call into an account.

Parameters

evm : The current EVM frame.

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