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

return_

Halts execution returning output data.

Parameters

evm : The current EVM frame.

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

call

Message-call into an account.

Parameters

evm : The current EVM frame.

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

selfdestruct

Halt execution and register account for later deletion.

Parameters

evm : The current EVM frame.

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