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

return_

Halts execution returning output data.

Parameters

evm : The current EVM frame.

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

call

Message-call into an account.

Parameters

evm : The current EVM frame.

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

selfdestruct

Halt execution and register account for later deletion.

Parameters

evm : The current EVM frame.

def selfdestruct(evm: Evm) -> None:
355
    """
356
    Halt execution and register account for later deletion.
357
358
    Parameters
359
    ----------
360
    evm :
361
        The current EVM frame.
362
363
    """
364
    # STACK
365
    beneficiary = to_address_masked(pop(evm.stack))
366
367
    # GAS
368
    gas_cost = GasCosts.ZERO
369
370
    originator = evm.message.current_target
371
372
    refunded_accounts = evm.accounts_to_delete
373
    parent_evm = evm.message.parent_evm
374
    while parent_evm is not None:
375
        refunded_accounts.update(parent_evm.accounts_to_delete)
376
        parent_evm = parent_evm.message.parent_evm
377
378
    if originator not in refunded_accounts:
379
        evm.refund_counter += int(GasCosts.REFUND_SELF_DESTRUCT)
380
381
    charge_gas(evm, gas_cost)
382
383
    # OPERATION
384
    beneficiary_balance = get_account(
385
        evm.message.block_env.state, beneficiary
386
    ).balance
387
    originator_balance = get_account(
388
        evm.message.block_env.state, originator
389
    ).balance
390
391
    # First Transfer to beneficiary
392
    set_account_balance(
393
        evm.message.block_env.state,
394
        beneficiary,
395
        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.message.block_env.state, originator, U256(0))
401
402
    # register account for deletion
403
    evm.accounts_to_delete.add(originator)
404
405
    # HALT the execution
406
    evm.running = False
407
408
    # PROGRAM COUNTER
409
    pass

delegatecall

Message-call into an account.

Parameters

evm : The current EVM frame.

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