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

return_

Halts execution returning output data.

Parameters

evm : The current EVM frame.

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

call

Message-call into an account.

Parameters

evm : The current EVM frame.

def call(evm: Evm) -> None:
212
    """
213
    Message-call into an account.
214
215
    Parameters
216
    ----------
217
    evm :
218
        The current EVM frame.
219
    """
220
    # STACK
221
    gas = Uint(pop(evm.stack))
222
    to = to_address(pop(evm.stack))
223
    value = pop(evm.stack)
224
    memory_input_start_position = pop(evm.stack)
225
    memory_input_size = pop(evm.stack)
226
    memory_output_start_position = pop(evm.stack)
227
    memory_output_size = pop(evm.stack)
228
229
    # GAS
230
    extend_memory = calculate_gas_extend_memory(
231
        evm.memory,
232
        [
233
            (memory_input_start_position, memory_input_size),
234
            (memory_output_start_position, memory_output_size),
235
        ],
236
    )
237
    message_call_gas = calculate_message_call_gas(
238
        evm.env.state, gas, to, value
239
    )
240
    charge_gas(evm, message_call_gas.cost + extend_memory.cost)
241
242
    # OPERATION
243
    evm.memory += b"\x00" * extend_memory.expand_by
244
    sender_balance = get_account(
245
        evm.env.state, evm.message.current_target
246
    ).balance
247
    if sender_balance < value:
248
        push(evm.stack, U256(0))
249
        evm.gas_left += message_call_gas.stipend
250
    else:
251
        generic_call(
252
            evm,
253
            message_call_gas.stipend,
254
            value,
255
            evm.message.current_target,
256
            to,
257
            to,
258
            memory_input_start_position,
259
            memory_input_size,
260
            memory_output_start_position,
261
            memory_output_size,
262
        )
263
264
    # PROGRAM COUNTER
265
    evm.pc += 1

callcode

Message-call into this account with alternative account’s code.

Parameters

evm : The current EVM frame.

def callcode(evm: Evm) -> None:
269
    """
270
    Message-call into this account with alternative account’s code.
271
272
    Parameters
273
    ----------
274
    evm :
275
        The current EVM frame.
276
    """
277
    # STACK
278
    gas = Uint(pop(evm.stack))
279
    code_address = to_address(pop(evm.stack))
280
    value = pop(evm.stack)
281
    memory_input_start_position = pop(evm.stack)
282
    memory_input_size = pop(evm.stack)
283
    memory_output_start_position = pop(evm.stack)
284
    memory_output_size = pop(evm.stack)
285
286
    # GAS
287
    to = evm.message.current_target
288
289
    extend_memory = calculate_gas_extend_memory(
290
        evm.memory,
291
        [
292
            (memory_input_start_position, memory_input_size),
293
            (memory_output_start_position, memory_output_size),
294
        ],
295
    )
296
    message_call_gas = calculate_message_call_gas(
297
        evm.env.state, gas, to, value
298
    )
299
    charge_gas(evm, message_call_gas.cost + extend_memory.cost)
300
301
    # OPERATION
302
    evm.memory += b"\x00" * extend_memory.expand_by
303
    sender_balance = get_account(
304
        evm.env.state, evm.message.current_target
305
    ).balance
306
    if sender_balance < value:
307
        push(evm.stack, U256(0))
308
        evm.gas_left += message_call_gas.stipend
309
    else:
310
        generic_call(
311
            evm,
312
            message_call_gas.stipend,
313
            value,
314
            evm.message.current_target,
315
            to,
316
            code_address,
317
            memory_input_start_position,
318
            memory_input_size,
319
            memory_output_start_position,
320
            memory_output_size,
321
        )
322
323
    # PROGRAM COUNTER
324
    evm.pc += 1

selfdestruct

Halt execution and register account for later deletion.

Parameters

evm : The current EVM frame.

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