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

return_

Halts execution returning output data.

Parameters

evm : The current EVM frame.

def return_(evm: Evm) -> None:
134
    <snip>
143
    # STACK
144
    memory_start_position = pop(evm.stack)
145
    memory_size = pop(evm.stack)
146
147
    # GAS
148
    extend_memory = calculate_gas_extend_memory(
149
        evm.memory, [(memory_start_position, memory_size)]
150
    )
151
152
    charge_gas(evm, GasCosts.ZERO + extend_memory.cost)
153
154
    # OPERATION
155
    evm.memory += b"\x00" * extend_memory.expand_by
156
    evm.output = memory_read_bytes(
157
        evm.memory, memory_start_position, memory_size
158
    )
159
160
    evm.running = False
161
162
    # PROGRAM COUNTER
163
    pass

GenericCall

Parameters for the core logic of the CALL* family of opcodes.

166
@final
167
@dataclass
class GenericCall:

gas

173
    gas: Uint

value

174
    value: U256

caller

175
    caller: Address

to

176
    to: Address

code_address

177
    code_address: Address

memory_input_start_position

178
    memory_input_start_position: U256

memory_input_size

179
    memory_input_size: U256

memory_output_start_position

180
    memory_output_start_position: U256

memory_output_size

181
    memory_output_size: U256

generic_call

Perform the core logic of the CALL* family of opcodes.

def generic_call(evm: Evm, ​​params: GenericCall) -> None:
185
    <snip>
188
    from ...vm.interpreter import STACK_DEPTH_LIMIT, process_message
189
190
    if evm.message.depth + Uint(1) > STACK_DEPTH_LIMIT:
191
        evm.gas_left += params.gas
192
        push(evm.stack, U256(0))
193
        return
194
195
    call_data = memory_read_bytes(
196
        evm.memory,
197
        params.memory_input_start_position,
198
        params.memory_input_size,
199
    )
200
    account_to_call = get_account(
201
        evm.message.tx_env.state, params.code_address
202
    )
203
    code = get_code(evm.message.tx_env.state, account_to_call.code_hash)
204
    child_message = Message(
205
        block_env=evm.message.block_env,
206
        tx_env=evm.message.tx_env,
207
        caller=params.caller,
208
        target=params.to,
209
        gas=params.gas,
210
        value=params.value,
211
        data=call_data,
212
        code=code,
213
        current_target=params.to,
214
        depth=evm.message.depth + Uint(1),
215
        code_address=params.code_address,
216
        parent_evm=evm,
217
    )
218
    child_evm = process_message(child_message)
219
220
    if child_evm.error:
221
        incorporate_child_on_error(evm, child_evm)
222
        push(evm.stack, U256(0))
223
    else:
224
        incorporate_child_on_success(evm, child_evm)
225
        push(evm.stack, U256(1))
226
227
    actual_output_size = min(
228
        params.memory_output_size, U256(len(child_evm.output))
229
    )
230
    memory_write(
231
        evm.memory,
232
        params.memory_output_start_position,
233
        child_evm.output[:actual_output_size],
234
    )

call

Message-call into an account.

Parameters

evm : The current EVM frame.

def call(evm: Evm) -> None:
238
    <snip>
247
    # STACK
248
    gas = Uint(pop(evm.stack))
249
    to = to_address_masked(pop(evm.stack))
250
    value = pop(evm.stack)
251
    memory_input_start_position = pop(evm.stack)
252
    memory_input_size = pop(evm.stack)
253
    memory_output_start_position = pop(evm.stack)
254
    memory_output_size = pop(evm.stack)
255
256
    # GAS
257
    extend_memory = calculate_gas_extend_memory(
258
        evm.memory,
259
        [
260
            (memory_input_start_position, memory_input_size),
261
            (memory_output_start_position, memory_output_size),
262
        ],
263
    )
264
265
    code_address = to
266
267
    message_call_gas = calculate_message_call_gas(
268
        evm.message.tx_env.state, gas, to, value
269
    )
270
    charge_gas(evm, message_call_gas.cost + extend_memory.cost)
271
272
    # OPERATION
273
    evm.memory += b"\x00" * extend_memory.expand_by
274
    sender_balance = get_account(
275
        evm.message.tx_env.state, evm.message.current_target
276
    ).balance
277
    if sender_balance < value:
278
        push(evm.stack, U256(0))
279
        evm.gas_left += message_call_gas.sub_call
280
    else:
281
        generic_call(
282
            evm,
283
            GenericCall(
284
                gas=message_call_gas.sub_call,
285
                value=value,
286
                caller=evm.message.current_target,
287
                to=to,
288
                code_address=code_address,
289
                memory_input_start_position=memory_input_start_position,
290
                memory_input_size=memory_input_size,
291
                memory_output_start_position=memory_output_start_position,
292
                memory_output_size=memory_output_size,
293
            ),
294
        )
295
296
    # PROGRAM COUNTER
297
    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:
301
    <snip>
310
    # STACK
311
    gas = Uint(pop(evm.stack))
312
    code_address = to_address_masked(pop(evm.stack))
313
    value = pop(evm.stack)
314
    memory_input_start_position = pop(evm.stack)
315
    memory_input_size = pop(evm.stack)
316
    memory_output_start_position = pop(evm.stack)
317
    memory_output_size = pop(evm.stack)
318
319
    # GAS
320
    to = evm.message.current_target
321
322
    extend_memory = calculate_gas_extend_memory(
323
        evm.memory,
324
        [
325
            (memory_input_start_position, memory_input_size),
326
            (memory_output_start_position, memory_output_size),
327
        ],
328
    )
329
    message_call_gas = calculate_message_call_gas(
330
        evm.message.tx_env.state, gas, to, value
331
    )
332
    charge_gas(evm, message_call_gas.cost + extend_memory.cost)
333
334
    # OPERATION
335
    evm.memory += b"\x00" * extend_memory.expand_by
336
    sender_balance = get_account(
337
        evm.message.tx_env.state, evm.message.current_target
338
    ).balance
339
    if sender_balance < value:
340
        push(evm.stack, U256(0))
341
        evm.gas_left += message_call_gas.sub_call
342
    else:
343
        generic_call(
344
            evm,
345
            GenericCall(
346
                gas=message_call_gas.sub_call,
347
                value=value,
348
                caller=evm.message.current_target,
349
                to=to,
350
                code_address=code_address,
351
                memory_input_start_position=memory_input_start_position,
352
                memory_input_size=memory_input_size,
353
                memory_output_start_position=memory_output_start_position,
354
                memory_output_size=memory_output_size,
355
            ),
356
        )
357
358
    # PROGRAM COUNTER
359
    evm.pc += Uint(1)

selfdestruct

Halt execution and register account for later deletion.

Parameters

evm : The current EVM frame.

def selfdestruct(evm: Evm) -> None:
363
    <snip>
372
    # STACK
373
    beneficiary = to_address_masked(pop(evm.stack))
374
375
    # GAS
376
    gas_cost = GasCosts.ZERO
377
378
    originator = evm.message.current_target
379
380
    refunded_accounts = evm.accounts_to_delete
381
    parent_evm = evm.message.parent_evm
382
    while parent_evm is not None:
383
        refunded_accounts.update(parent_evm.accounts_to_delete)
384
        parent_evm = parent_evm.message.parent_evm
385
386
    if originator not in refunded_accounts:
387
        evm.refund_counter += int(GasCosts.REFUND_SELF_DESTRUCT)
388
389
    charge_gas(evm, gas_cost)
390
391
    # OPERATION
392
    beneficiary_balance = get_account(
393
        evm.message.tx_env.state, beneficiary
394
    ).balance
395
    originator_balance = get_account(
396
        evm.message.tx_env.state, originator
397
    ).balance
398
399
    # First Transfer to beneficiary
400
    set_account_balance(
401
        evm.message.tx_env.state,
402
        beneficiary,
403
        beneficiary_balance + originator_balance,
404
    )
405
    # Next, Zero the balance of the address being deleted (must come after
406
    # sending to beneficiary in case the contract named itself as the
407
    # beneficiary).
408
    set_account_balance(evm.message.tx_env.state, originator, U256(0))
409
410
    # register account for deletion
411
    evm.accounts_to_delete.add(originator)
412
413
    # HALT the execution
414
    evm.running = False
415
416
    # PROGRAM COUNTER
417
    pass