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

return_

Halts execution returning output data.

Parameters

evm : The current EVM frame.

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

call

Message-call into an account.

Parameters

evm : The current EVM frame.

def call(evm: Evm) -> None:
235
    """
236
    Message-call into an account.
237
238
    Parameters
239
    ----------
240
    evm :
241
        The current EVM frame.
242
    """
243
    # STACK
244
    gas = Uint(pop(evm.stack))
245
    to = to_address(pop(evm.stack))
246
    value = pop(evm.stack)
247
    memory_input_start_position = pop(evm.stack)
248
    memory_input_size = pop(evm.stack)
249
    memory_output_start_position = pop(evm.stack)
250
    memory_output_size = pop(evm.stack)
251
252
    # GAS
253
    extend_memory = calculate_gas_extend_memory(
254
        evm.memory,
255
        [
256
            (memory_input_start_position, memory_input_size),
257
            (memory_output_start_position, memory_output_size),
258
        ],
259
    )
260
    create_gas_cost = (
261
        Uint(0)
262
        if value == 0 or is_account_alive(evm.env.state, to)
263
        else GAS_NEW_ACCOUNT
264
    )
265
    transfer_gas_cost = Uint(0) if value == 0 else GAS_CALL_VALUE
266
    message_call_gas = calculate_message_call_gas(
267
        value,
268
        gas,
269
        Uint(evm.gas_left),
270
        extend_memory.cost,
271
        GAS_CALL + create_gas_cost + transfer_gas_cost,
272
    )
273
    charge_gas(evm, message_call_gas.cost + extend_memory.cost)
274
    if evm.message.is_static and value != U256(0):
275
        raise WriteInStaticContext
276
    evm.memory += b"\x00" * extend_memory.expand_by
277
    sender_balance = get_account(
278
        evm.env.state, evm.message.current_target
279
    ).balance
280
    if sender_balance < value:
281
        push(evm.stack, U256(0))
282
        evm.return_data = b""
283
        evm.gas_left += message_call_gas.stipend
284
    else:
285
        generic_call(
286
            evm,
287
            message_call_gas.stipend,
288
            value,
289
            evm.message.current_target,
290
            to,
291
            to,
292
            True,
293
            False,
294
            memory_input_start_position,
295
            memory_input_size,
296
            memory_output_start_position,
297
            memory_output_size,
298
        )
299
300
    # PROGRAM COUNTER
301
    evm.pc += 1

callcode

Message-call into this account with alternative account’s code.

Parameters

evm : The current EVM frame.

def callcode(evm: Evm) -> None:
305
    """
306
    Message-call into this account with alternative account’s code.
307
308
    Parameters
309
    ----------
310
    evm :
311
        The current EVM frame.
312
    """
313
    # STACK
314
    gas = Uint(pop(evm.stack))
315
    code_address = to_address(pop(evm.stack))
316
    value = pop(evm.stack)
317
    memory_input_start_position = pop(evm.stack)
318
    memory_input_size = pop(evm.stack)
319
    memory_output_start_position = pop(evm.stack)
320
    memory_output_size = pop(evm.stack)
321
322
    # GAS
323
    to = evm.message.current_target
324
325
    extend_memory = calculate_gas_extend_memory(
326
        evm.memory,
327
        [
328
            (memory_input_start_position, memory_input_size),
329
            (memory_output_start_position, memory_output_size),
330
        ],
331
    )
332
    transfer_gas_cost = Uint(0) if value == 0 else GAS_CALL_VALUE
333
    message_call_gas = calculate_message_call_gas(
334
        value,
335
        gas,
336
        Uint(evm.gas_left),
337
        extend_memory.cost,
338
        GAS_CALL + transfer_gas_cost,
339
    )
340
    charge_gas(evm, message_call_gas.cost + extend_memory.cost)
341
342
    # OPERATION
343
    evm.memory += b"\x00" * extend_memory.expand_by
344
    sender_balance = get_account(
345
        evm.env.state, evm.message.current_target
346
    ).balance
347
    if sender_balance < value:
348
        push(evm.stack, U256(0))
349
        evm.return_data = b""
350
        evm.gas_left += message_call_gas.stipend
351
    else:
352
        generic_call(
353
            evm,
354
            message_call_gas.stipend,
355
            value,
356
            evm.message.current_target,
357
            to,
358
            code_address,
359
            True,
360
            False,
361
            memory_input_start_position,
362
            memory_input_size,
363
            memory_output_start_position,
364
            memory_output_size,
365
        )
366
367
    # PROGRAM COUNTER
368
    evm.pc += 1

selfdestruct

Halt execution and register account for later deletion.

Parameters

evm : The current EVM frame.

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

delegatecall

Message-call into an account.

Parameters

evm : The current EVM frame.

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

staticcall

Message-call into an account.

Parameters

evm : The current EVM frame.

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