ethereum.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:
48
    """
49
    Creates a new account with associated code.
50
51
    Parameters
52
    ----------
53
    evm :
54
        The current EVM frame.
55
56
    """
57
    # This import causes a circular import error
58
    # if it's not moved inside this method
59
    from ...vm.interpreter import STACK_DEPTH_LIMIT, process_create_message
60
61
    # STACK
62
    endowment = pop(evm.stack)
63
    memory_start_position = pop(evm.stack)
64
    memory_size = pop(evm.stack)
65
66
    # GAS
67
    extend_memory = calculate_gas_extend_memory(
68
        evm.memory, [(memory_start_position, memory_size)]
69
    )
70
71
    charge_gas(evm, GasCosts.OPCODE_CREATE_BASE + extend_memory.cost)
72
73
    create_message_gas = max_message_call_gas(Uint(evm.gas_left))
74
    evm.gas_left -= create_message_gas
75
76
    # OPERATION
77
    evm.memory += b"\x00" * extend_memory.expand_by
78
    sender_address = evm.message.current_target
79
    sender = get_account(evm.message.tx_env.state, sender_address)
80
81
    contract_address = compute_contract_address(
82
        evm.message.current_target,
83
        get_account(
84
            evm.message.tx_env.state, evm.message.current_target
85
        ).nonce,
86
    )
87
88
    if (
89
        sender.balance < endowment
90
        or sender.nonce == Uint(2**64 - 1)
91
        or evm.message.depth + Uint(1) > STACK_DEPTH_LIMIT
92
    ):
93
        push(evm.stack, U256(0))
94
        evm.gas_left += create_message_gas
95
    elif account_has_code_or_nonce(
96
        evm.message.tx_env.state, contract_address
97
    ) or account_has_storage(evm.message.tx_env.state, contract_address):
98
        increment_nonce(evm.message.tx_env.state, evm.message.current_target)
99
        push(evm.stack, U256(0))
100
    else:
101
        call_data = memory_read_bytes(
102
            evm.memory, memory_start_position, memory_size
103
        )
104
105
        increment_nonce(evm.message.tx_env.state, evm.message.current_target)
106
107
        child_message = Message(
108
            block_env=evm.message.block_env,
109
            tx_env=evm.message.tx_env,
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)
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
    """
147
    # STACK
148
    memory_start_position = pop(evm.stack)
149
    memory_size = pop(evm.stack)
150
151
    # GAS
152
    extend_memory = calculate_gas_extend_memory(
153
        evm.memory, [(memory_start_position, memory_size)]
154
    )
155
156
    charge_gas(evm, GasCosts.ZERO + extend_memory.cost)
157
158
    # OPERATION
159
    evm.memory += b"\x00" * extend_memory.expand_by
160
    evm.output = memory_read_bytes(
161
        evm.memory, memory_start_position, memory_size
162
    )
163
164
    evm.running = False
165
166
    # PROGRAM COUNTER
167
    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:
183
    """
184
    Perform the core logic of the `CALL*` family of opcodes.
185
    """
186
    from ...vm.interpreter import STACK_DEPTH_LIMIT, process_message
187
188
    if evm.message.depth + Uint(1) > STACK_DEPTH_LIMIT:
189
        evm.gas_left += gas
190
        push(evm.stack, U256(0))
191
        return
192
193
    call_data = memory_read_bytes(
194
        evm.memory, memory_input_start_position, memory_input_size
195
    )
196
    account = get_account(evm.message.tx_env.state, code_address)
197
    code = get_code(evm.message.tx_env.state, account.code_hash)
198
    child_message = Message(
199
        block_env=evm.message.block_env,
200
        tx_env=evm.message.tx_env,
201
        caller=caller,
202
        target=to,
203
        gas=gas,
204
        value=value,
205
        data=call_data,
206
        code=code,
207
        current_target=to,
208
        depth=evm.message.depth + Uint(1),
209
        code_address=code_address,
210
        should_transfer_value=should_transfer_value,
211
        parent_evm=evm,
212
    )
213
    child_evm = process_message(child_message)
214
215
    if child_evm.error:
216
        incorporate_child_on_error(evm, child_evm)
217
        push(evm.stack, U256(0))
218
    else:
219
        incorporate_child_on_success(evm, child_evm)
220
        push(evm.stack, U256(1))
221
222
    actual_output_size = min(memory_output_size, U256(len(child_evm.output)))
223
    memory_write(
224
        evm.memory,
225
        memory_output_start_position,
226
        child_evm.output[:actual_output_size],
227
    )

call

Message-call into an account.

Parameters

evm : The current EVM frame.

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

selfdestruct

Halt execution and register account for later deletion.

Parameters

evm : The current EVM frame.

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

delegatecall

Message-call into an account.

Parameters

evm : The current EVM frame.

def delegatecall(evm: Evm) -> None:
436
    """
437
    Message-call into an account.
438
439
    Parameters
440
    ----------
441
    evm :
442
        The current EVM frame.
443
444
    """
445
    # STACK
446
    gas = Uint(pop(evm.stack))
447
    code_address = to_address_masked(pop(evm.stack))
448
    memory_input_start_position = pop(evm.stack)
449
    memory_input_size = pop(evm.stack)
450
    memory_output_start_position = pop(evm.stack)
451
    memory_output_size = pop(evm.stack)
452
453
    # GAS
454
    extend_memory = calculate_gas_extend_memory(
455
        evm.memory,
456
        [
457
            (memory_input_start_position, memory_input_size),
458
            (memory_output_start_position, memory_output_size),
459
        ],
460
    )
461
    message_call_gas = calculate_message_call_gas(
462
        U256(0),
463
        gas,
464
        Uint(evm.gas_left),
465
        extend_memory.cost,
466
        GasCosts.OPCODE_CALL_BASE,
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)