ethereum.tangerine_whistle.vm.instructions.systemethereum.spurious_dragon.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
80
    # OPERATION
81
    evm.memory += b"\x00" * extend_memory.expand_by
82
    sender_address = evm.message.current_target
83
    sender = get_account(evm.message.block_env.state, sender_address)
84
85
    contract_address = compute_contract_address(
86
        evm.message.current_target,
87
        get_account(
88
            evm.message.block_env.state, evm.message.current_target
89
        ).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(
100
        evm.message.block_env.state, contract_address
101
    ) or account_has_storage(evm.message.block_env.state, contract_address):
102
        increment_nonce(
103
            evm.message.block_env.state, evm.message.current_target
104
        )
105
        push(evm.stack, U256(0))
106
    else:
107
        call_data = memory_read_bytes(
108
            evm.memory, memory_start_position, memory_size
109
        )
110
111
        increment_nonce(
112
            evm.message.block_env.state, evm.message.current_target
113
        )
114
115
        child_message = Message(
116
            block_env=evm.message.block_env,
117
            tx_env=evm.message.tx_env,
118
            caller=evm.message.current_target,
119
            target=Bytes0(),
120
            gas=create_message_gas,
121
            value=endowment,
122
            data=b"",
123
            code=call_data,
124
            current_target=contract_address,
125
            depth=evm.message.depth + Uint(1),
126
            code_address=None,
127
            should_transfer_value=True,
128
            parent_evm=evm,
129
        )
130
        child_evm = process_create_message(child_message)
131
132
        if child_evm.error:
133
            incorporate_child_on_error(evm, child_evm)
134
            push(evm.stack, U256(0))
135
        else:
136
            incorporate_child_on_success(evm, child_evm)
137
            push(
138
                evm.stack, U256.from_be_bytes(child_evm.message.current_target)
139
            )
140
141
    # PROGRAM COUNTER
142
    evm.pc += Uint(1)

return_

Halts execution returning output data.

Parameters

evm : The current EVM frame.

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

call

Message-call into an account.

Parameters

evm : The current EVM frame.

def call(evm: Evm) -> None:
237
    """
238
    Message-call into an account.
239
240
    Parameters
241
    ----------
242
    evm :
243
        The current EVM frame.
244
    """
245
    # STACK
246
    gas = Uint(pop(evm.stack))
247
    to = to_address_masked(pop(evm.stack))
248
    value = pop(evm.stack)
249
    memory_input_start_position = pop(evm.stack)
250
    memory_input_size = pop(evm.stack)
251
    memory_output_start_position = pop(evm.stack)
252
    memory_output_size = pop(evm.stack)
253
254
    # GAS
255
    extend_memory = calculate_gas_extend_memory(
256
        evm.memory,
257
        [
258
            (memory_input_start_position, memory_input_size),
259
            (memory_output_start_position, memory_output_size),
260
        ],
261
    )
262
263
    code_address = to
264
264
    _account_exists = account_exists(evm.message.block_env.state, to)
265
    create_gas_cost = Uint(0) if _account_exists else GAS_NEW_ACCOUNT
265
    create_gas_cost = GAS_NEW_ACCOUNT
266
    if value == 0 or is_account_alive(evm.message.block_env.state, to):
267
        create_gas_cost = Uint(0)
268
    transfer_gas_cost = Uint(0) if value == 0 else GAS_CALL_VALUE
269
    message_call_gas = calculate_message_call_gas(
270
        value,
271
        gas,
272
        Uint(evm.gas_left),
273
        extend_memory.cost,
274
        GAS_CALL + create_gas_cost + transfer_gas_cost,
275
    )
276
    charge_gas(evm, message_call_gas.cost + extend_memory.cost)
277
278
    # OPERATION
279
    evm.memory += b"\x00" * extend_memory.expand_by
280
    sender_balance = get_account(
281
        evm.message.block_env.state, evm.message.current_target
282
    ).balance
283
    if sender_balance < value:
284
        push(evm.stack, U256(0))
285
        evm.gas_left += message_call_gas.sub_call
286
    else:
287
        generic_call(
288
            evm,
289
            message_call_gas.sub_call,
290
            value,
291
            evm.message.current_target,
292
            to,
293
            code_address,
294
            True,
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_masked(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.message.block_env.state, evm.message.current_target
347
    ).balance
348
    if sender_balance < value:
349
        push(evm.stack, U256(0))
350
        evm.gas_left += message_call_gas.sub_call
351
    else:
352
        generic_call(
353
            evm,
354
            message_call_gas.sub_call,
355
            value,
356
            evm.message.current_target,
357
            to,
358
            code_address,
359
            True,
360
            memory_input_start_position,
361
            memory_input_size,
362
            memory_output_start_position,
363
            memory_output_size,
364
        )
365
366
    # PROGRAM COUNTER
367
    evm.pc += Uint(1)

selfdestruct

Halt execution and register account for later deletion.

Parameters

evm : The current EVM frame.

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

delegatecall

Message-call into an account.

Parameters

evm : The current EVM frame.

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