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

return_

Halts execution returning output data.

Parameters

evm : The current EVM frame.

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

call

Message-call into an account.

Parameters

evm : The current EVM frame.

def call(evm: Evm) -> None:
222
    """
223
    Message-call into an account.
224
225
    Parameters
226
    ----------
227
    evm :
228
        The current EVM frame.
229
    """
230
    # STACK
231
    gas = Uint(pop(evm.stack))
232
    to = to_address(pop(evm.stack))
233
    value = pop(evm.stack)
234
    memory_input_start_position = pop(evm.stack)
235
    memory_input_size = pop(evm.stack)
236
    memory_output_start_position = pop(evm.stack)
237
    memory_output_size = pop(evm.stack)
238
239
    # GAS
240
    extend_memory = calculate_gas_extend_memory(
241
        evm.memory,
242
        [
243
            (memory_input_start_position, memory_input_size),
244
            (memory_output_start_position, memory_output_size),
245
        ],
246
    )
247
    _account_exists = account_exists(evm.env.state, to)
248
    create_gas_cost = Uint(0) if _account_exists else GAS_NEW_ACCOUNT
249
    transfer_gas_cost = Uint(0) if value == 0 else GAS_CALL_VALUE
250
    message_call_gas = calculate_message_call_gas(
242
        evm.env.state, gas, to, value
251
        value,
252
        gas,
253
        Uint(evm.gas_left),
254
        extend_memory.cost,
255
        GAS_CALL + create_gas_cost + transfer_gas_cost,
256
    )
257
    charge_gas(evm, message_call_gas.cost + extend_memory.cost)
258
259
    # OPERATION
260
    evm.memory += b"\x00" * extend_memory.expand_by
261
    sender_balance = get_account(
262
        evm.env.state, evm.message.current_target
263
    ).balance
264
    if sender_balance < value:
265
        push(evm.stack, U256(0))
266
        evm.gas_left += message_call_gas.stipend
267
    else:
268
        generic_call(
269
            evm,
270
            message_call_gas.stipend,
271
            value,
272
            evm.message.current_target,
273
            to,
274
            to,
275
            True,
276
            memory_input_start_position,
277
            memory_input_size,
278
            memory_output_start_position,
279
            memory_output_size,
280
        )
281
282
    # PROGRAM COUNTER
283
    evm.pc += 1

callcode

Message-call into this account with alternative account’s code.

Parameters

evm : The current EVM frame.

def callcode(evm: Evm) -> None:
287
    """
288
    Message-call into this account with alternative account’s code.
289
290
    Parameters
291
    ----------
292
    evm :
293
        The current EVM frame.
294
    """
295
    # STACK
296
    gas = Uint(pop(evm.stack))
297
    code_address = to_address(pop(evm.stack))
298
    value = pop(evm.stack)
299
    memory_input_start_position = pop(evm.stack)
300
    memory_input_size = pop(evm.stack)
301
    memory_output_start_position = pop(evm.stack)
302
    memory_output_size = pop(evm.stack)
303
304
    # GAS
305
    to = evm.message.current_target
306
307
    extend_memory = calculate_gas_extend_memory(
308
        evm.memory,
309
        [
310
            (memory_input_start_position, memory_input_size),
311
            (memory_output_start_position, memory_output_size),
312
        ],
313
    )
314
    transfer_gas_cost = Uint(0) if value == 0 else GAS_CALL_VALUE
315
    message_call_gas = calculate_message_call_gas(
302
        evm.env.state, gas, to, value
316
        value,
317
        gas,
318
        Uint(evm.gas_left),
319
        extend_memory.cost,
320
        GAS_CALL + transfer_gas_cost,
321
    )
322
    charge_gas(evm, message_call_gas.cost + extend_memory.cost)
323
324
    # OPERATION
325
    evm.memory += b"\x00" * extend_memory.expand_by
326
    sender_balance = get_account(
327
        evm.env.state, evm.message.current_target
328
    ).balance
329
    if sender_balance < value:
330
        push(evm.stack, U256(0))
331
        evm.gas_left += message_call_gas.stipend
332
    else:
333
        generic_call(
334
            evm,
335
            message_call_gas.stipend,
336
            value,
337
            evm.message.current_target,
338
            to,
339
            code_address,
340
            True,
341
            memory_input_start_position,
342
            memory_input_size,
343
            memory_output_start_position,
344
            memory_output_size,
345
        )
346
347
    # PROGRAM COUNTER
348
    evm.pc += 1

selfdestruct

Halt execution and register account for later deletion.

Parameters

evm : The current EVM frame.

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

delegatecall

Message-call into an account.

Parameters

evm : The current EVM frame.

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