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

return_

Halts execution returning output data.

Parameters

evm : The current EVM frame.

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

call

Message-call into an account.

Parameters

evm : The current EVM frame.

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

selfdestruct

Halt execution and register account for later deletion.

Parameters

evm : The current EVM frame.

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

delegatecall

Message-call into an account.

Parameters

evm : The current EVM frame.

def delegatecall(evm: Evm) -> None:
425
    """
426
    Message-call into an account.
427
428
    Parameters
429
    ----------
430
    evm :
431
        The current EVM frame.
432
433
    """
434
    # STACK
435
    gas = Uint(pop(evm.stack))
436
    code_address = to_address_masked(pop(evm.stack))
437
    memory_input_start_position = pop(evm.stack)
438
    memory_input_size = pop(evm.stack)
439
    memory_output_start_position = pop(evm.stack)
440
    memory_output_size = pop(evm.stack)
441
442
    # GAS
443
    extend_memory = calculate_gas_extend_memory(
444
        evm.memory,
445
        [
446
            (memory_input_start_position, memory_input_size),
447
            (memory_output_start_position, memory_output_size),
448
        ],
449
    )
450
    message_call_gas = calculate_message_call_gas(
451
        U256(0),
452
        gas,
453
        Uint(evm.gas_left),
454
        extend_memory.cost,
455
        GasCosts.OPCODE_CALL_BASE,
456
    )
457
    charge_gas(evm, message_call_gas.cost + extend_memory.cost)
458
459
    # OPERATION
460
    evm.memory += b"\x00" * extend_memory.expand_by
461
    generic_call(
462
        evm,
463
        message_call_gas.sub_call,
464
        evm.message.value,
465
        evm.message.caller,
466
        evm.message.current_target,
467
        code_address,
468
        False,
469
        memory_input_start_position,
470
        memory_input_size,
471
        memory_output_start_position,
472
        memory_output_size,
473
    )
474
475
    # PROGRAM COUNTER
476
    evm.pc += Uint(1)