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:
46
    """
47
    Creates a new account with associated code.
48
49
    Parameters
50
    ----------
51
    evm :
52
        The current EVM frame.
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.env.state, sender_address)
77
78
    contract_address = compute_contract_address(
79
        evm.message.current_target,
80
        get_account(evm.env.state, evm.message.current_target).nonce,
81
    )
82
83
    if (
84
        sender.balance < endowment
85
        or sender.nonce == Uint(2**64 - 1)
86
        or evm.message.depth + Uint(1) > STACK_DEPTH_LIMIT
87
    ):
88
        push(evm.stack, U256(0))
89
        evm.gas_left += create_message_gas
90
    elif account_has_code_or_nonce(
91
        evm.env.state, contract_address
92
    ) or account_has_storage(evm.env.state, contract_address):
93
        increment_nonce(evm.env.state, evm.message.current_target)
94
        push(evm.stack, U256(0))
95
    else:
96
        call_data = memory_read_bytes(
97
            evm.memory, memory_start_position, memory_size
98
        )
99
100
        increment_nonce(evm.env.state, evm.message.current_target)
101
102
        child_message = Message(
103
            caller=evm.message.current_target,
104
            target=Bytes0(),
105
            gas=create_message_gas,
106
            value=endowment,
107
            data=b"",
108
            code=call_data,
109
            current_target=contract_address,
110
            depth=evm.message.depth + Uint(1),
111
            code_address=None,
112
            should_transfer_value=True,
113
            parent_evm=evm,
114
        )
115
        child_evm = process_create_message(child_message, evm.env)
116
117
        if child_evm.error:
118
            incorporate_child_on_error(evm, child_evm)
119
            push(evm.stack, U256(0))
120
        else:
121
            incorporate_child_on_success(evm, child_evm)
122
            push(
123
                evm.stack, U256.from_be_bytes(child_evm.message.current_target)
124
            )
125
126
    # PROGRAM COUNTER
127
    evm.pc += Uint(1)

return_

Halts execution returning output data.

Parameters

evm : The current EVM frame.

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

call

Message-call into an account.

Parameters

evm : The current EVM frame.

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

selfdestruct

Halt execution and register account for later deletion.

Parameters

evm : The current EVM frame.

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

delegatecall

Message-call into an account.

Parameters

evm : The current EVM frame.

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