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

return_

Halts execution returning output data.

Parameters

evm : The current EVM frame.

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

call

Message-call into an account.

Parameters

evm : The current EVM frame.

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

selfdestruct

Halt execution and register account for later deletion.

Parameters

evm : The current EVM frame.

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

delegatecall

Message-call into an account.

Parameters

evm : The current EVM frame.

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