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

return_

Halts execution returning output data.

Parameters

evm : The current EVM frame.

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

call

Message-call into an account.

Parameters

evm : The current EVM frame.

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

selfdestruct

Halt execution and register account for later deletion.

Parameters

evm : The current EVM frame.

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

delegatecall

Message-call into an account.

Parameters

evm : The current EVM frame.

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