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, GAS_CREATE + 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, GAS_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
    code = get_account(evm.message.block_env.state, code_address).code
196
    child_message = Message(
197
        block_env=evm.message.block_env,
198
        tx_env=evm.message.tx_env,
199
        caller=caller,
200
        target=to,
201
        gas=gas,
202
        value=value,
203
        data=call_data,
204
        code=code,
205
        current_target=to,
206
        depth=evm.message.depth + Uint(1),
207
        code_address=code_address,
208
        parent_evm=evm,
209
    )
210
    child_evm = process_message(child_message)
211
212
    if child_evm.error:
213
        incorporate_child_on_error(evm, child_evm)
214
        push(evm.stack, U256(0))
215
    else:
216
        incorporate_child_on_success(evm, child_evm)
217
        push(evm.stack, U256(1))
218
219
    actual_output_size = min(memory_output_size, U256(len(child_evm.output)))
220
    memory_write(
221
        evm.memory,
222
        memory_output_start_position,
223
        child_evm.output[:actual_output_size],
224
    )

call

Message-call into an account.

Parameters

evm : The current EVM frame.

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

selfdestruct

Halt execution and register account for later deletion.

Parameters

evm : The current EVM frame.

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