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(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 = (
266
        Uint(0)
267
        if is_account_alive(evm.message.block_env.state, to) or value == 0
268
        else GAS_NEW_ACCOUNT
269
    )
270
    transfer_gas_cost = Uint(0) if value == 0 else GAS_CALL_VALUE
271
    message_call_gas = calculate_message_call_gas(
272
        value,
273
        gas,
274
        Uint(evm.gas_left),
275
        extend_memory.cost,
276
        GAS_CALL + create_gas_cost + transfer_gas_cost,
277
    )
278
    charge_gas(evm, message_call_gas.cost + extend_memory.cost)
279
280
    # OPERATION
281
    evm.memory += b"\x00" * extend_memory.expand_by
282
    sender_balance = get_account(
283
        evm.message.block_env.state, evm.message.current_target
284
    ).balance
285
    if sender_balance < value:
286
        push(evm.stack, U256(0))
287
        evm.gas_left += message_call_gas.sub_call
288
    else:
289
        generic_call(
290
            evm,
291
            message_call_gas.sub_call,
292
            value,
293
            evm.message.current_target,
294
            to,
295
            code_address,
296
            True,
297
            memory_input_start_position,
298
            memory_input_size,
299
            memory_output_start_position,
300
            memory_output_size,
301
        )
302
303
    # PROGRAM COUNTER
304
    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:
308
    """
309
    Message-call into this account with alternative account’s code.
310
311
    Parameters
312
    ----------
313
    evm :
314
        The current EVM frame.
315
    """
316
    # STACK
317
    gas = Uint(pop(evm.stack))
318
    code_address = to_address(pop(evm.stack))
319
    value = pop(evm.stack)
320
    memory_input_start_position = pop(evm.stack)
321
    memory_input_size = pop(evm.stack)
322
    memory_output_start_position = pop(evm.stack)
323
    memory_output_size = pop(evm.stack)
324
325
    # GAS
326
    to = evm.message.current_target
327
328
    extend_memory = calculate_gas_extend_memory(
329
        evm.memory,
330
        [
331
            (memory_input_start_position, memory_input_size),
332
            (memory_output_start_position, memory_output_size),
333
        ],
334
    )
335
    transfer_gas_cost = Uint(0) if value == 0 else GAS_CALL_VALUE
336
    message_call_gas = calculate_message_call_gas(
337
        value,
338
        gas,
339
        Uint(evm.gas_left),
340
        extend_memory.cost,
341
        GAS_CALL + transfer_gas_cost,
342
    )
343
    charge_gas(evm, message_call_gas.cost + extend_memory.cost)
344
345
    # OPERATION
346
    evm.memory += b"\x00" * extend_memory.expand_by
347
    sender_balance = get_account(
348
        evm.message.block_env.state, evm.message.current_target
349
    ).balance
350
    if sender_balance < value:
351
        push(evm.stack, U256(0))
352
        evm.gas_left += message_call_gas.sub_call
353
    else:
354
        generic_call(
355
            evm,
356
            message_call_gas.sub_call,
357
            value,
358
            evm.message.current_target,
359
            to,
360
            code_address,
361
            True,
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
382
    if not account_exists(evm.message.block_env.state, beneficiary):
386
    if (
387
        not is_account_alive(evm.message.block_env.state, beneficiary)
388
        and get_account(
389
            evm.message.block_env.state, evm.message.current_target
390
        ).balance
391
        != 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
398
    # OPERATION
408
    beneficiary_balance = get_account(
409
        evm.message.block_env.state, beneficiary
410
    ).balance
411
    originator_balance = get_account(
412
        evm.message.block_env.state, originator
413
    ).balance
414
415
    # First Transfer to beneficiary
416
    set_account_balance(
417
        evm.message.block_env.state,
418
        beneficiary,
419
        beneficiary_balance + originator_balance,
420
    )
421
    # Next, Zero the balance of the address being deleted (must come after
422
    # sending to beneficiary in case the contract named itself as the
423
    # beneficiary).
424
    set_account_balance(evm.message.block_env.state, originator, U256(0))
425
426
    # register account for deletion
427
    evm.accounts_to_delete.add(originator)
428
429
    # mark beneficiary as touched
430
    if account_exists_and_is_empty(evm.message.block_env.state, beneficiary):
431
        evm.touched_accounts.add(beneficiary)
432
433
    # HALT the execution
434
    evm.running = False
435
436
    # PROGRAM COUNTER
437
    pass

delegatecall

Message-call into an account.

Parameters

evm : The current EVM frame.

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