ethereum.frontier.vm.instructions.systemethereum.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:
44
    """
45
    Creates a new account with associated code.
46
47
    Parameters
48
    ----------
49
    evm :
50
        The current EVM frame.
51
    """
52
    # This import causes a circular import error
53
    # if it's not moved inside this method
54
    from ...vm.interpreter import STACK_DEPTH_LIMIT, process_create_message
55
56
    # STACK
57
    endowment = pop(evm.stack)
58
    memory_start_position = pop(evm.stack)
59
    memory_size = pop(evm.stack)
60
61
    # GAS
62
    extend_memory = calculate_gas_extend_memory(
63
        evm.memory, [(memory_start_position, memory_size)]
64
    )
65
66
    charge_gas(evm, GAS_CREATE + extend_memory.cost)
67
68
    create_message_gas = evm.gas_left
69
    evm.gas_left = Uint(0)
70
71
    # OPERATION
72
    evm.memory += b"\x00" * extend_memory.expand_by
73
    sender_address = evm.message.current_target
74
    sender = get_account(evm.env.state, sender_address)
75
76
    contract_address = compute_contract_address(
77
        evm.message.current_target,
78
        get_account(evm.env.state, evm.message.current_target).nonce,
79
    )
80
81
    if (
82
        sender.balance < endowment
83
        or sender.nonce == Uint(2**64 - 1)
84
        or evm.message.depth + 1 > STACK_DEPTH_LIMIT
85
    ):
86
        push(evm.stack, U256(0))
87
        evm.gas_left += create_message_gas
88
    elif account_has_code_or_nonce(evm.env.state, contract_address):
89
        increment_nonce(evm.env.state, evm.message.current_target)
90
        push(evm.stack, U256(0))
91
    else:
92
        call_data = memory_read_bytes(
93
            evm.memory, memory_start_position, memory_size
94
        )
95
96
        increment_nonce(evm.env.state, evm.message.current_target)
97
98
        child_message = Message(
99
            caller=evm.message.current_target,
100
            target=Bytes0(),
101
            gas=create_message_gas,
102
            value=endowment,
103
            data=b"",
104
            code=call_data,
105
            current_target=contract_address,
106
            depth=evm.message.depth + 1,
107
            code_address=None,
108
            should_transfer_value=True,
109
            parent_evm=evm,
110
        )
111
        child_evm = process_create_message(child_message, evm.env)
112
113
        if child_evm.error:
114
            incorporate_child_on_error(evm, child_evm)
115
            push(evm.stack, U256(0))
116
        else:
117
            incorporate_child_on_success(evm, child_evm)
118
            push(
119
                evm.stack, U256.from_be_bytes(child_evm.message.current_target)
120
            )
121
122
    # PROGRAM COUNTER
123
    evm.pc += 1

return_

Halts execution returning output data.

Parameters

evm : The current EVM frame.

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

call

Message-call into an account.

Parameters

evm : The current EVM frame.

def call(evm: Evm) -> None:
216
    """
217
    Message-call into an account.
218
219
    Parameters
220
    ----------
221
    evm :
222
        The current EVM frame.
223
    """
224
    # STACK
225
    gas = Uint(pop(evm.stack))
226
    to = to_address(pop(evm.stack))
227
    value = pop(evm.stack)
228
    memory_input_start_position = pop(evm.stack)
229
    memory_input_size = pop(evm.stack)
230
    memory_output_start_position = pop(evm.stack)
231
    memory_output_size = pop(evm.stack)
232
233
    # GAS
234
    extend_memory = calculate_gas_extend_memory(
235
        evm.memory,
236
        [
237
            (memory_input_start_position, memory_input_size),
238
            (memory_output_start_position, memory_output_size),
239
        ],
240
    )
241
    message_call_gas = calculate_message_call_gas(
242
        evm.env.state, gas, to, value
243
    )
244
    charge_gas(evm, message_call_gas.cost + extend_memory.cost)
245
246
    # OPERATION
247
    evm.memory += b"\x00" * extend_memory.expand_by
248
    sender_balance = get_account(
249
        evm.env.state, evm.message.current_target
250
    ).balance
251
    if sender_balance < value:
252
        push(evm.stack, U256(0))
253
        evm.gas_left += message_call_gas.stipend
254
    else:
255
        generic_call(
256
            evm,
257
            message_call_gas.stipend,
258
            value,
259
            evm.message.current_target,
260
            to,
261
            to,
262
            True,
263
            memory_input_start_position,
264
            memory_input_size,
265
            memory_output_start_position,
266
            memory_output_size,
267
        )
268
269
    # PROGRAM COUNTER
270
    evm.pc += 1

callcode

Message-call into this account with alternative account’s code.

Parameters

evm : The current EVM frame.

def callcode(evm: Evm) -> None:
274
    """
275
    Message-call into this account with alternative account’s code.
276
277
    Parameters
278
    ----------
279
    evm :
280
        The current EVM frame.
281
    """
282
    # STACK
283
    gas = Uint(pop(evm.stack))
284
    code_address = to_address(pop(evm.stack))
285
    value = pop(evm.stack)
286
    memory_input_start_position = pop(evm.stack)
287
    memory_input_size = pop(evm.stack)
288
    memory_output_start_position = pop(evm.stack)
289
    memory_output_size = pop(evm.stack)
290
291
    # GAS
292
    to = evm.message.current_target
293
294
    extend_memory = calculate_gas_extend_memory(
295
        evm.memory,
296
        [
297
            (memory_input_start_position, memory_input_size),
298
            (memory_output_start_position, memory_output_size),
299
        ],
300
    )
301
    message_call_gas = calculate_message_call_gas(
302
        evm.env.state, gas, to, value
303
    )
304
    charge_gas(evm, message_call_gas.cost + extend_memory.cost)
305
306
    # OPERATION
307
    evm.memory += b"\x00" * extend_memory.expand_by
308
    sender_balance = get_account(
309
        evm.env.state, evm.message.current_target
310
    ).balance
311
    if sender_balance < value:
312
        push(evm.stack, U256(0))
313
        evm.gas_left += message_call_gas.stipend
314
    else:
315
        generic_call(
316
            evm,
317
            message_call_gas.stipend,
318
            value,
319
            evm.message.current_target,
320
            to,
321
            code_address,
322
            True,
323
            memory_input_start_position,
324
            memory_input_size,
325
            memory_output_start_position,
326
            memory_output_size,
327
        )
328
329
    # PROGRAM COUNTER
330
    evm.pc += 1

selfdestruct

Halt execution and register account for later deletion.

Parameters

evm : The current EVM frame.

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

delegatecall

Message-call into an account.

Parameters

evm : The current EVM frame.

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