ethereum.homestead.vm.instructions.systemethereum.dao_fork.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.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
            should_transfer_value=True,
121
            parent_evm=evm,
122
        )
123
        child_evm = process_create_message(child_message)
124
125
        if child_evm.error:
126
            incorporate_child_on_error(evm, child_evm)
127
            push(evm.stack, U256(0))
128
        else:
129
            incorporate_child_on_success(evm, child_evm)
130
            push(
131
                evm.stack, U256.from_be_bytes(child_evm.message.current_target)
132
            )
133
134
    # PROGRAM COUNTER
135
    evm.pc += Uint(1)

return_

Halts execution returning output data.

Parameters

evm : The current EVM frame.

def return_(evm: Evm) -> None:
139
    """
140
    Halts execution returning output data.
141
142
    Parameters
143
    ----------
144
    evm :
145
        The current EVM frame.
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, ​​should_transfer_value: bool, ​​memory_input_start_position: U256, ​​memory_input_size: U256, ​​memory_output_start_position: U256, ​​memory_output_size: U256) -> None:
183
    """
184
    Perform the core logic of the `CALL*` family of opcodes.
185
    """
186
    from ...vm.interpreter import STACK_DEPTH_LIMIT, process_message
187
188
    if evm.message.depth + Uint(1) > STACK_DEPTH_LIMIT:
189
        evm.gas_left += gas
190
        push(evm.stack, U256(0))
191
        return
192
193
    call_data = memory_read_bytes(
194
        evm.memory, memory_input_start_position, memory_input_size
195
    )
196
    code = get_account(evm.message.block_env.state, code_address).code
197
    child_message = Message(
198
        block_env=evm.message.block_env,
199
        tx_env=evm.message.tx_env,
200
        caller=caller,
201
        target=to,
202
        gas=gas,
203
        value=value,
204
        data=call_data,
205
        code=code,
206
        current_target=to,
207
        depth=evm.message.depth + Uint(1),
208
        code_address=code_address,
209
        should_transfer_value=should_transfer_value,
210
        parent_evm=evm,
211
    )
212
    child_evm = process_message(child_message)
213
214
    if child_evm.error:
215
        incorporate_child_on_error(evm, child_evm)
216
        push(evm.stack, U256(0))
217
    else:
218
        incorporate_child_on_success(evm, child_evm)
219
        push(evm.stack, U256(1))
220
221
    actual_output_size = min(memory_output_size, U256(len(child_evm.output)))
222
    memory_write(
223
        evm.memory,
224
        memory_output_start_position,
225
        child_evm.output[:actual_output_size],
226
    )

call

Message-call into an account.

Parameters

evm : The current EVM frame.

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

selfdestruct

Halt execution and register account for later deletion.

Parameters

evm : The current EVM frame.

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

delegatecall

Message-call into an account.

Parameters

evm : The current EVM frame.

def delegatecall(evm: Evm) -> None:
408
    """
409
    Message-call into an account.
410
411
    Parameters
412
    ----------
413
    evm :
414
        The current EVM frame.
415
    """
416
    # STACK
417
    gas = Uint(pop(evm.stack))
418
    code_address = to_address(pop(evm.stack))
419
    memory_input_start_position = pop(evm.stack)
420
    memory_input_size = pop(evm.stack)
421
    memory_output_start_position = pop(evm.stack)
422
    memory_output_size = pop(evm.stack)
423
424
    # GAS
425
    extend_memory = calculate_gas_extend_memory(
426
        evm.memory,
427
        [
428
            (memory_input_start_position, memory_input_size),
429
            (memory_output_start_position, memory_output_size),
430
        ],
431
    )
432
    charge_gas(evm, GAS_CALL + gas + extend_memory.cost)
433
434
    # OPERATION
435
    evm.memory += b"\x00" * extend_memory.expand_by
436
    generic_call(
437
        evm,
438
        gas,
439
        evm.message.value,
440
        evm.message.caller,
441
        evm.message.current_target,
442
        code_address,
443
        False,
444
        memory_input_start_position,
445
        memory_input_size,
446
        memory_output_start_position,
447
        memory_output_size,
448
    )
449
450
    # PROGRAM COUNTER
451
    evm.pc += Uint(1)