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

return_

Halts execution returning output data.

Parameters

evm : The current EVM frame.

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

call

Message-call into an account.

Parameters

evm : The current EVM frame.

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

selfdestruct

Halt execution and register account for later deletion.

Parameters

evm : The current EVM frame.

def selfdestruct(evm: Evm) -> None:
376
    """
377
    Halt execution and register account for later deletion.
378
379
    Parameters
380
    ----------
381
    evm :
382
        The current EVM frame.
383
384
    """
385
    # STACK
386
    beneficiary = to_address_masked(pop(evm.stack))
387
388
    # GAS
371
    gas_cost = GAS_ZERO
389
    gas_cost = GAS_SELF_DESTRUCT
390
    if not account_exists(evm.message.block_env.state, beneficiary):
391
        gas_cost += GAS_SELF_DESTRUCT_NEW_ACCOUNT
392
393
    originator = evm.message.current_target
394
395
    refunded_accounts = evm.accounts_to_delete
396
    parent_evm = evm.message.parent_evm
397
    while parent_evm is not None:
398
        refunded_accounts.update(parent_evm.accounts_to_delete)
399
        parent_evm = parent_evm.message.parent_evm
400
401
    if originator not in refunded_accounts:
382
        evm.refund_counter += int(REFUND_SELF_DESTRUCT)
402
        evm.refund_counter += REFUND_SELF_DESTRUCT
403
404
    charge_gas(evm, gas_cost)
405
406
    # OPERATION
407
    beneficiary_balance = get_account(
408
        evm.message.block_env.state, beneficiary
409
    ).balance
410
    originator_balance = get_account(
411
        evm.message.block_env.state, originator
412
    ).balance
413
414
    # First Transfer to beneficiary
415
    set_account_balance(
416
        evm.message.block_env.state,
417
        beneficiary,
418
        beneficiary_balance + originator_balance,
419
    )
420
    # Next, Zero the balance of the address being deleted (must come after
421
    # sending to beneficiary in case the contract named itself as the
422
    # beneficiary).
423
    set_account_balance(evm.message.block_env.state, originator, U256(0))
424
425
    # register account for deletion
426
    evm.accounts_to_delete.add(originator)
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
    )
441
    charge_gas(evm, GAS_CALL + gas + extend_memory.cost)
461
    message_call_gas = calculate_message_call_gas(
462
        U256(0), gas, Uint(evm.gas_left), extend_memory.cost, GAS_CALL
463
    )
464
    charge_gas(evm, message_call_gas.cost + extend_memory.cost)
465
466
    # OPERATION
467
    evm.memory += b"\x00" * extend_memory.expand_by
468
    generic_call(
469
        evm,
447
        gas,
470
        message_call_gas.sub_call,
471
        evm.message.value,
472
        evm.message.caller,
473
        evm.message.current_target,
474
        code_address,
475
        False,
476
        memory_input_start_position,
477
        memory_input_size,
478
        memory_output_start_position,
479
        memory_output_size,
480
    )
481
482
    # PROGRAM COUNTER
483
    evm.pc += Uint(1)