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.env.state, sender_address)
84
85
    contract_address = compute_contract_address(
86
        evm.message.current_target,
87
        get_account(evm.env.state, evm.message.current_target).nonce,
88
    )
89
90
    if (
91
        sender.balance < endowment
92
        or sender.nonce == Uint(2**64 - 1)
93
        or evm.message.depth + Uint(1) > STACK_DEPTH_LIMIT
94
    ):
95
        push(evm.stack, U256(0))
96
        evm.gas_left += create_message_gas
97
    elif account_has_code_or_nonce(
98
        evm.env.state, contract_address
99
    ) or account_has_storage(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
            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
            push(evm.stack, U256(0))
127
        else:
128
            incorporate_child_on_success(evm, child_evm)
129
            push(
130
                evm.stack, U256.from_be_bytes(child_evm.message.current_target)
131
            )
132
133
    # PROGRAM COUNTER
134
    evm.pc += Uint(1)

return_

Halts execution returning output data.

Parameters

evm : The current EVM frame.

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

call

Message-call into an account.

Parameters

evm : The current EVM frame.

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

selfdestruct

Halt execution and register account for later deletion.

Parameters

evm : The current EVM frame.

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

delegatecall

Message-call into an account.

Parameters

evm : The current EVM frame.

def delegatecall(evm: Evm) -> None:
420
    """
421
    Message-call into an account.
422
423
    Parameters
424
    ----------
425
    evm :
426
        The current EVM frame.
427
    """
428
    # STACK
429
    gas = Uint(pop(evm.stack))
430
    code_address = to_address(pop(evm.stack))
431
    memory_input_start_position = pop(evm.stack)
432
    memory_input_size = pop(evm.stack)
433
    memory_output_start_position = pop(evm.stack)
434
    memory_output_size = pop(evm.stack)
435
436
    # GAS
437
    extend_memory = calculate_gas_extend_memory(
438
        evm.memory,
439
        [
440
            (memory_input_start_position, memory_input_size),
441
            (memory_output_start_position, memory_output_size),
442
        ],
443
    )
444
    message_call_gas = calculate_message_call_gas(
445
        U256(0), gas, Uint(evm.gas_left), extend_memory.cost, GAS_CALL
446
    )
447
    charge_gas(evm, message_call_gas.cost + extend_memory.cost)
448
449
    # OPERATION
450
    evm.memory += b"\x00" * extend_memory.expand_by
451
    generic_call(
452
        evm,
453
        message_call_gas.stipend,
454
        evm.message.value,
455
        evm.message.caller,
456
        evm.message.current_target,
457
        code_address,
458
        False,
459
        memory_input_start_position,
460
        memory_input_size,
461
        memory_output_start_position,
462
        memory_output_size,
463
    )
464
465
    # PROGRAM COUNTER
466
    evm.pc += Uint(1)