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

return_

Halts execution returning output data.

Parameters

evm : The current EVM frame.

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

call

Message-call into an account.

Parameters

evm : The current EVM frame.

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

selfdestruct

Halt execution and register account for later deletion.

Parameters

evm : The current EVM frame.

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

delegatecall

Message-call into an account.

Parameters

evm : The current EVM frame.

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