ethereum.forks.frontier.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
            parent_evm=evm,
121
        )
122
        child_evm = process_create_message(child_message)
123
124
        if child_evm.error:
125
            incorporate_child_on_error(evm, child_evm)
126
            push(evm.stack, U256(0))
127
        else:
128
            incorporate_child_on_success(evm, child_evm)
129
            push(
130
                evm.stack, U256.from_be_bytes(child_evm.message.current_target)
131
            )
132
133
    # PROGRAM COUNTER
134
    evm.pc += Uint(1)

return_

Halts execution returning output data.

Parameters

evm : The current EVM frame.

def return_(evm: Evm) -> None:
138
    """
139
    Halts execution returning output data.
140
141
    Parameters
142
    ----------
143
    evm :
144
        The current EVM frame.
145
146
    """
147
    # STACK
148
    memory_start_position = pop(evm.stack)
149
    memory_size = pop(evm.stack)
150
151
    # GAS
152
    extend_memory = calculate_gas_extend_memory(
153
        evm.memory, [(memory_start_position, memory_size)]
154
    )
155
156
    charge_gas(evm, GasCosts.ZERO + extend_memory.cost)
157
158
    # OPERATION
159
    evm.memory += b"\x00" * extend_memory.expand_by
160
    evm.output = memory_read_bytes(
161
        evm.memory, memory_start_position, memory_size
162
    )
163
164
    evm.running = False
165
166
    # PROGRAM COUNTER
167
    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, ​​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_to_call = get_account(evm.message.block_env.state, code_address)
196
    code = get_code(evm.message.block_env.state, account_to_call.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
        parent_evm=evm,
210
    )
211
    child_evm = process_message(child_message)
212
213
    if child_evm.error:
214
        incorporate_child_on_error(evm, child_evm)
215
        push(evm.stack, U256(0))
216
    else:
217
        incorporate_child_on_success(evm, child_evm)
218
        push(evm.stack, U256(1))
219
220
    actual_output_size = min(memory_output_size, U256(len(child_evm.output)))
221
    memory_write(
222
        evm.memory,
223
        memory_output_start_position,
224
        child_evm.output[:actual_output_size],
225
    )

call

Message-call into an account.

Parameters

evm : The current EVM frame.

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

selfdestruct

Halt execution and register account for later deletion.

Parameters

evm : The current EVM frame.

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