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

return_

Halts execution returning output data.

Parameters

evm : The current EVM frame.

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

call

Message-call into an account.

Parameters

evm : The current EVM frame.

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

selfdestruct

Halt execution and register account for later deletion.

Parameters

evm : The current EVM frame.

def selfdestruct(evm: Evm) -> None:
373
    """
374
    Halt execution and register account for later deletion.
375
376
    Parameters
377
    ----------
378
    evm :
379
        The current EVM frame.
380
381
    """
382
    # STACK
383
    beneficiary = to_address_masked(pop(evm.stack))
384
385
    # GAS
386
    gas_cost = GAS_SELF_DESTRUCT
387
    if not account_exists(evm.message.block_env.state, beneficiary):
388
        gas_cost += GAS_SELF_DESTRUCT_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 += REFUND_SELF_DESTRUCT
400
401
    charge_gas(evm, gas_cost)
402
403
    # OPERATION
404
    beneficiary_balance = get_account(
405
        evm.message.block_env.state, beneficiary
406
    ).balance
407
    originator_balance = get_account(
408
        evm.message.block_env.state, originator
409
    ).balance
410
411
    # First Transfer to beneficiary
412
    set_account_balance(
413
        evm.message.block_env.state,
414
        beneficiary,
415
        beneficiary_balance + originator_balance,
416
    )
417
    # Next, Zero the balance of the address being deleted (must come after
418
    # sending to beneficiary in case the contract named itself as the
419
    # beneficiary).
420
    set_account_balance(evm.message.block_env.state, originator, U256(0))
421
422
    # register account for deletion
423
    evm.accounts_to_delete.add(originator)
424
425
    # HALT the execution
426
    evm.running = False
427
428
    # PROGRAM COUNTER
429
    pass

delegatecall

Message-call into an account.

Parameters

evm : The current EVM frame.

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