ethereum.homestead.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(evm.env.state, contract_address):
90
        increment_nonce(evm.env.state, evm.message.current_target)
91
        push(evm.stack, U256(0))
92
    else:
93
        call_data = memory_read_bytes(
94
            evm.memory, memory_start_position, memory_size
95
        )
96
97
        increment_nonce(evm.env.state, evm.message.current_target)
98
99
        child_message = Message(
100
            caller=evm.message.current_target,
101
            target=Bytes0(),
102
            gas=create_message_gas,
103
            value=endowment,
104
            data=b"",
105
            code=call_data,
106
            current_target=contract_address,
107
            depth=evm.message.depth + Uint(1),
108
            code_address=None,
109
            should_transfer_value=True,
110
            parent_evm=evm,
111
        )
112
        child_evm = process_create_message(child_message, evm.env)
113
114
        if child_evm.error:
115
            incorporate_child_on_error(evm, child_evm)
116
            push(evm.stack, U256(0))
117
        else:
118
            incorporate_child_on_success(evm, child_evm)
119
            push(
120
                evm.stack, U256.from_be_bytes(child_evm.message.current_target)
121
            )
122
123
    # PROGRAM COUNTER
124
    evm.pc += Uint(1)

return_

Halts execution returning output data.

Parameters

evm : The current EVM frame.

def return_(evm: Evm) -> None:
128
    """
129
    Halts execution returning output data.
130
131
    Parameters
132
    ----------
133
    evm :
134
        The current EVM frame.
135
    """
136
    # STACK
137
    memory_start_position = pop(evm.stack)
138
    memory_size = pop(evm.stack)
139
140
    # GAS
141
    extend_memory = calculate_gas_extend_memory(
142
        evm.memory, [(memory_start_position, memory_size)]
143
    )
144
145
    charge_gas(evm, GAS_ZERO + extend_memory.cost)
146
147
    # OPERATION
148
    evm.memory += b"\x00" * extend_memory.expand_by
149
    evm.output = memory_read_bytes(
150
        evm.memory, memory_start_position, memory_size
151
    )
152
153
    evm.running = False
154
155
    # PROGRAM COUNTER
156
    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, ​​should_transfer_value: bool, ​​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
        should_transfer_value=should_transfer_value,
197
        parent_evm=evm,
198
    )
199
    child_evm = process_message(child_message, evm.env)
200
201
    if child_evm.error:
202
        incorporate_child_on_error(evm, child_evm)
203
        push(evm.stack, U256(0))
204
    else:
205
        incorporate_child_on_success(evm, child_evm)
206
        push(evm.stack, U256(1))
207
208
    actual_output_size = min(memory_output_size, U256(len(child_evm.output)))
209
    memory_write(
210
        evm.memory,
211
        memory_output_start_position,
212
        child_evm.output[:actual_output_size],
213
    )

call

Message-call into an account.

Parameters

evm : The current EVM frame.

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

selfdestruct

Halt execution and register account for later deletion.

Parameters

evm : The current EVM frame.

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

delegatecall

Message-call into an account.

Parameters

evm : The current EVM frame.

def delegatecall(evm: Evm) -> None:
386
    """
387
    Message-call into an account.
388
389
    Parameters
390
    ----------
391
    evm :
392
        The current EVM frame.
393
    """
394
    # STACK
395
    gas = Uint(pop(evm.stack))
396
    code_address = to_address(pop(evm.stack))
397
    memory_input_start_position = pop(evm.stack)
398
    memory_input_size = pop(evm.stack)
399
    memory_output_start_position = pop(evm.stack)
400
    memory_output_size = pop(evm.stack)
401
402
    # GAS
403
    extend_memory = calculate_gas_extend_memory(
404
        evm.memory,
405
        [
406
            (memory_input_start_position, memory_input_size),
407
            (memory_output_start_position, memory_output_size),
408
        ],
409
    )
410
    charge_gas(evm, GAS_CALL + gas + extend_memory.cost)
411
412
    # OPERATION
413
    evm.memory += b"\x00" * extend_memory.expand_by
414
    generic_call(
415
        evm,
416
        gas,
417
        evm.message.value,
418
        evm.message.caller,
419
        evm.message.current_target,
420
        code_address,
421
        False,
422
        memory_input_start_position,
423
        memory_input_size,
424
        memory_output_start_position,
425
        memory_output_size,
426
    )
427
428
    # PROGRAM COUNTER
429
    evm.pc += Uint(1)