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:
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, GAS_CREATE + extend_memory.cost)
71
72
    create_message_gas = evm.gas_left
73
    evm.gas_left = Uint(0)
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.block_env.state, sender_address)
79
80
    contract_address = compute_contract_address(
81
        evm.message.current_target,
82
        get_account(
83
            evm.message.block_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.block_env.state, contract_address
96
    ) or account_has_storage(evm.message.block_env.state, contract_address):
97
        increment_nonce(
98
            evm.message.block_env.state, evm.message.current_target
99
        )
100
        push(evm.stack, U256(0))
101
    else:
102
        call_data = memory_read_bytes(
103
            evm.memory, memory_start_position, memory_size
104
        )
105
106
        increment_nonce(
107
            evm.message.block_env.state, evm.message.current_target
108
        )
109
110
        child_message = Message(
111
            block_env=evm.message.block_env,
112
            tx_env=evm.message.tx_env,
113
            caller=evm.message.current_target,
114
            target=Bytes0(),
115
            gas=create_message_gas,
116
            value=endowment,
117
            data=b"",
118
            code=call_data,
119
            current_target=contract_address,
120
            depth=evm.message.depth + Uint(1),
121
            code_address=None,
122
            parent_evm=evm,
123
        )
124
        child_evm = process_create_message(child_message)
125
126
        if child_evm.error:
127
            incorporate_child_on_error(evm, child_evm)
128
            push(evm.stack, U256(0))
129
        else:
130
            incorporate_child_on_success(evm, child_evm)
131
            push(
132
                evm.stack, U256.from_be_bytes(child_evm.message.current_target)
133
            )
134
135
    # PROGRAM COUNTER
136
    evm.pc += Uint(1)

return_

Halts execution returning output data.

Parameters

evm : The current EVM frame.

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

call

Message-call into an account.

Parameters

evm : The current EVM frame.

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

selfdestruct

Halt execution and register account for later deletion.

Parameters

evm : The current EVM frame.

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