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

return_

Halts execution returning output data.

Parameters

evm : The current EVM frame.

def return_(evm: Evm) -> None:
129
    """
130
    Halts execution returning output data.
131
132
    Parameters
133
    ----------
134
    evm :
135
        The current EVM frame.
136
    """
137
    # STACK
138
    memory_start_position = pop(evm.stack)
139
    memory_size = pop(evm.stack)
140
141
    # GAS
142
    extend_memory = calculate_gas_extend_memory(
143
        evm.memory, [(memory_start_position, memory_size)]
144
    )
145
146
    charge_gas(evm, GAS_ZERO + extend_memory.cost)
147
148
    # OPERATION
149
    evm.memory += b"\x00" * extend_memory.expand_by
150
    evm.output = memory_read_bytes(
151
        evm.memory, memory_start_position, memory_size
152
    )
153
154
    evm.running = False
155
156
    # PROGRAM COUNTER
157
    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:
172
    """
173
    Perform the core logic of the `CALL*` family of opcodes.
174
    """
175
    from ...vm.interpreter import STACK_DEPTH_LIMIT, process_message
176
177
    if evm.message.depth + Uint(1) > STACK_DEPTH_LIMIT:
178
        evm.gas_left += gas
179
        push(evm.stack, U256(0))
180
        return
181
182
    call_data = memory_read_bytes(
183
        evm.memory, memory_input_start_position, memory_input_size
184
    )
185
    code = get_account(evm.env.state, code_address).code
186
    child_message = Message(
187
        caller=caller,
188
        target=to,
189
        gas=gas,
190
        value=value,
191
        data=call_data,
192
        code=code,
193
        current_target=to,
194
        depth=evm.message.depth + Uint(1),
195
        code_address=code_address,
196
        parent_evm=evm,
197
    )
198
    child_evm = process_message(child_message, evm.env)
199
200
    if child_evm.error:
201
        incorporate_child_on_error(evm, child_evm)
202
        push(evm.stack, U256(0))
203
    else:
204
        incorporate_child_on_success(evm, child_evm)
205
        push(evm.stack, U256(1))
206
207
    actual_output_size = min(memory_output_size, U256(len(child_evm.output)))
208
    memory_write(
209
        evm.memory,
210
        memory_output_start_position,
211
        child_evm.output[:actual_output_size],
212
    )

call

Message-call into an account.

Parameters

evm : The current EVM frame.

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

selfdestruct

Halt execution and register account for later deletion.

Parameters

evm : The current EVM frame.

def selfdestruct(evm: Evm) -> None:
332
    """
333
    Halt execution and register account for later deletion.
334
335
    Parameters
336
    ----------
337
    evm :
338
        The current EVM frame.
339
    """
340
    # STACK
341
    beneficiary = to_address(pop(evm.stack))
342
343
    # GAS
344
    gas_cost = GAS_ZERO
345
346
    originator = evm.message.current_target
347
348
    refunded_accounts = evm.accounts_to_delete
349
    parent_evm = evm.message.parent_evm
350
    while parent_evm is not None:
351
        refunded_accounts.update(parent_evm.accounts_to_delete)
352
        parent_evm = parent_evm.message.parent_evm
353
354
    if originator not in refunded_accounts:
355
        evm.refund_counter += int(REFUND_SELF_DESTRUCT)
356
357
    charge_gas(evm, gas_cost)
358
359
    # OPERATION
360
    beneficiary_balance = get_account(evm.env.state, beneficiary).balance
361
    originator_balance = get_account(evm.env.state, originator).balance
362
363
    # First Transfer to beneficiary
364
    set_account_balance(
365
        evm.env.state, beneficiary, beneficiary_balance + originator_balance
366
    )
367
    # Next, Zero the balance of the address being deleted (must come after
368
    # sending to beneficiary in case the contract named itself as the
369
    # beneficiary).
370
    set_account_balance(evm.env.state, originator, U256(0))
371
372
    # register account for deletion
373
    evm.accounts_to_delete.add(originator)
374
375
    # HALT the execution
376
    evm.running = False
377
378
    # PROGRAM COUNTER
379
    pass