ethereum.forks.spurious_dragon.vm.instructions.systemethereum.forks.byzantium.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:
52
    <snip>
61
    # This import causes a circular import error
62
    # if it's not moved inside this method
63
    from ...vm.interpreter import STACK_DEPTH_LIMIT, process_create_message
64
65
    # STACK
66
    endowment = pop(evm.stack)
67
    memory_start_position = pop(evm.stack)
68
    memory_size = pop(evm.stack)
69
70
    # GAS
71
    extend_memory = calculate_gas_extend_memory(
72
        evm.memory, [(memory_start_position, memory_size)]
73
    )
74
75
    charge_gas(evm, GasCosts.OPCODE_CREATE_BASE + extend_memory.cost)
76
77
    create_message_gas = max_message_call_gas(Uint(evm.gas_left))
78
    evm.gas_left -= create_message_gas
79
    if evm.message.is_static:
80
        raise WriteInStaticContext
81
    evm.memory += b"\x00" * extend_memory.expand_by
82
    evm.return_data = b""
83
79
    # OPERATION
80
    evm.memory += b"\x00" * extend_memory.expand_by
84
    sender_address = evm.message.current_target
85
    sender = get_account(evm.message.tx_env.state, sender_address)
86
87
    contract_address = compute_contract_address(
88
        evm.message.current_target,
89
        get_account(
90
            evm.message.tx_env.state, evm.message.current_target
91
        ).nonce,
92
    )
93
94
    if (
95
        sender.balance < endowment
96
        or sender.nonce == Uint(2**64 - 1)
97
        or evm.message.depth + Uint(1) > STACK_DEPTH_LIMIT
98
    ):
99
        push(evm.stack, U256(0))
100
        evm.gas_left += create_message_gas
101
    elif account_has_code_or_nonce(
102
        evm.message.tx_env.state, contract_address
103
    ) or account_has_storage(evm.message.tx_env.state, contract_address):
104
        increment_nonce(evm.message.tx_env.state, evm.message.current_target)
105
        push(evm.stack, U256(0))
106
    else:
107
        call_data = memory_read_bytes(
108
            evm.memory, memory_start_position, memory_size
109
        )
110
111
        increment_nonce(evm.message.tx_env.state, evm.message.current_target)
112
113
        child_message = Message(
114
            block_env=evm.message.block_env,
115
            tx_env=evm.message.tx_env,
116
            caller=evm.message.current_target,
117
            target=Bytes0(),
118
            gas=create_message_gas,
119
            value=endowment,
120
            data=b"",
121
            code=call_data,
122
            current_target=contract_address,
123
            depth=evm.message.depth + Uint(1),
124
            code_address=None,
125
            should_transfer_value=True,
126
            is_static=False,
127
            parent_evm=evm,
128
        )
129
        child_evm = process_create_message(child_message)
130
131
        if child_evm.error:
132
            incorporate_child_on_error(evm, child_evm)
133
            evm.return_data = child_evm.output
134
            push(evm.stack, U256(0))
135
        else:
136
            incorporate_child_on_success(evm, child_evm)
137
            evm.return_data = b""
138
            push(
139
                evm.stack, U256.from_be_bytes(child_evm.message.current_target)
140
            )
141
142
    # PROGRAM COUNTER
143
    evm.pc += Uint(1)

return_

Halts execution returning output data.

Parameters

evm : The current EVM frame.

def return_(evm: Evm) -> None:
147
    <snip>
156
    # STACK
157
    memory_start_position = pop(evm.stack)
158
    memory_size = pop(evm.stack)
159
160
    # GAS
161
    extend_memory = calculate_gas_extend_memory(
162
        evm.memory, [(memory_start_position, memory_size)]
163
    )
164
165
    charge_gas(evm, GasCosts.ZERO + extend_memory.cost)
166
167
    # OPERATION
168
    evm.memory += b"\x00" * extend_memory.expand_by
169
    evm.output = memory_read_bytes(
170
        evm.memory, memory_start_position, memory_size
171
    )
172
173
    evm.running = False
174
175
    # PROGRAM COUNTER
176
    pass

GenericCall

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

179
@final
180
@dataclass
class GenericCall:

gas

186
    gas: Uint

value

187
    value: U256

caller

188
    caller: Address

to

189
    to: Address

code_address

190
    code_address: Address

should_transfer_value

191
    should_transfer_value: bool

is_staticcall

192
    is_staticcall: bool

memory_input_start_position

193
    memory_input_start_position: U256

memory_input_size

194
    memory_input_size: U256

memory_output_start_position

195
    memory_output_start_position: U256

memory_output_size

196
    memory_output_size: U256

generic_call

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

def generic_call(evm: Evm, ​​params: GenericCall) -> None:
200
    <snip>
203
    from ...vm.interpreter import STACK_DEPTH_LIMIT, process_message
204
205
    evm.return_data = b""
206
207
    if evm.message.depth + Uint(1) > STACK_DEPTH_LIMIT:
208
        evm.gas_left += params.gas
209
        push(evm.stack, U256(0))
210
        return
211
212
    call_data = memory_read_bytes(
213
        evm.memory,
214
        params.memory_input_start_position,
215
        params.memory_input_size,
216
    )
217
    account = get_account(evm.message.tx_env.state, params.code_address)
218
    code = get_code(evm.message.tx_env.state, account.code_hash)
219
    child_message = Message(
220
        block_env=evm.message.block_env,
221
        tx_env=evm.message.tx_env,
222
        caller=params.caller,
223
        target=params.to,
224
        gas=params.gas,
225
        value=params.value,
226
        data=call_data,
227
        code=code,
228
        current_target=params.to,
229
        depth=evm.message.depth + Uint(1),
230
        code_address=params.code_address,
231
        should_transfer_value=params.should_transfer_value,
232
        is_static=params.is_staticcall or evm.message.is_static,
233
        parent_evm=evm,
234
    )
235
    child_evm = process_message(child_message)
236
237
    if child_evm.error:
238
        incorporate_child_on_error(evm, child_evm)
239
        evm.return_data = child_evm.output
240
        push(evm.stack, U256(0))
241
    else:
242
        incorporate_child_on_success(evm, child_evm)
243
        evm.return_data = child_evm.output
244
        push(evm.stack, U256(1))
245
246
    actual_output_size = min(
247
        params.memory_output_size, U256(len(child_evm.output))
248
    )
249
    memory_write(
250
        evm.memory,
251
        params.memory_output_start_position,
252
        child_evm.output[:actual_output_size],
253
    )

call

Message-call into an account.

Parameters

evm : The current EVM frame.

def call(evm: Evm) -> None:
257
    <snip>
266
    # STACK
267
    gas = Uint(pop(evm.stack))
268
    to = to_address_masked(pop(evm.stack))
269
    value = pop(evm.stack)
270
    memory_input_start_position = pop(evm.stack)
271
    memory_input_size = pop(evm.stack)
272
    memory_output_start_position = pop(evm.stack)
273
    memory_output_size = pop(evm.stack)
274
275
    # GAS
276
    extend_memory = calculate_gas_extend_memory(
277
        evm.memory,
278
        [
279
            (memory_input_start_position, memory_input_size),
280
            (memory_output_start_position, memory_output_size),
281
        ],
282
    )
283
284
    code_address = to
285
286
    create_gas_cost = GasCosts.NEW_ACCOUNT
287
    if value == 0 or is_account_alive(evm.message.tx_env.state, to):
288
        create_gas_cost = Uint(0)
289
    transfer_gas_cost = Uint(0) if value == 0 else GasCosts.CALL_VALUE
290
    message_call_gas = calculate_message_call_gas(
291
        value,
292
        gas,
293
        Uint(evm.gas_left),
294
        memory_cost=extend_memory.cost,
295
        extra_gas=GasCosts.OPCODE_CALL_BASE
296
        + create_gas_cost
297
        + transfer_gas_cost,
298
    )
299
    charge_gas(evm, message_call_gas.cost + extend_memory.cost)
288
289
    # OPERATION
290
    evm.memory += b"\x00" * extend_memory.expand_by
300
    if evm.message.is_static and value != U256(0):
301
        raise WriteInStaticContext
302
    evm.memory += b"\x00" * extend_memory.expand_by
303
    sender_balance = get_account(
304
        evm.message.tx_env.state, evm.message.current_target
305
    ).balance
306
    if sender_balance < value:
307
        push(evm.stack, U256(0))
308
        evm.return_data = b""
309
        evm.gas_left += message_call_gas.sub_call
310
    else:
311
        generic_call(
312
            evm,
313
            GenericCall(
314
                gas=message_call_gas.sub_call,
315
                value=value,
316
                caller=evm.message.current_target,
317
                to=to,
318
                code_address=code_address,
319
                should_transfer_value=True,
320
                is_staticcall=False,
321
                memory_input_start_position=memory_input_start_position,
322
                memory_input_size=memory_input_size,
323
                memory_output_start_position=memory_output_start_position,
324
                memory_output_size=memory_output_size,
325
            ),
326
        )
327
328
    # PROGRAM COUNTER
329
    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:
333
    <snip>
342
    # STACK
343
    gas = Uint(pop(evm.stack))
344
    code_address = to_address_masked(pop(evm.stack))
345
    value = pop(evm.stack)
346
    memory_input_start_position = pop(evm.stack)
347
    memory_input_size = pop(evm.stack)
348
    memory_output_start_position = pop(evm.stack)
349
    memory_output_size = pop(evm.stack)
350
351
    # GAS
352
    to = evm.message.current_target
353
354
    extend_memory = calculate_gas_extend_memory(
355
        evm.memory,
356
        [
357
            (memory_input_start_position, memory_input_size),
358
            (memory_output_start_position, memory_output_size),
359
        ],
360
    )
361
    transfer_gas_cost = Uint(0) if value == 0 else GasCosts.CALL_VALUE
362
    message_call_gas = calculate_message_call_gas(
363
        value,
364
        gas,
365
        Uint(evm.gas_left),
366
        extend_memory.cost,
367
        GasCosts.OPCODE_CALL_BASE + transfer_gas_cost,
368
    )
369
    charge_gas(evm, message_call_gas.cost + extend_memory.cost)
370
371
    # OPERATION
372
    evm.memory += b"\x00" * extend_memory.expand_by
373
    sender_balance = get_account(
374
        evm.message.tx_env.state, evm.message.current_target
375
    ).balance
376
    if sender_balance < value:
377
        push(evm.stack, U256(0))
378
        evm.return_data = b""
379
        evm.gas_left += message_call_gas.sub_call
380
    else:
381
        generic_call(
382
            evm,
383
            GenericCall(
384
                gas=message_call_gas.sub_call,
385
                value=value,
386
                caller=evm.message.current_target,
387
                to=to,
388
                code_address=code_address,
389
                should_transfer_value=True,
390
                is_staticcall=False,
391
                memory_input_start_position=memory_input_start_position,
392
                memory_input_size=memory_input_size,
393
                memory_output_start_position=memory_output_start_position,
394
                memory_output_size=memory_output_size,
395
            ),
396
        )
397
398
    # PROGRAM COUNTER
399
    evm.pc += Uint(1)

selfdestruct

Halt execution and register account for later deletion.

Parameters

evm : The current EVM frame.

def selfdestruct(evm: Evm) -> None:
403
    <snip>
412
    # STACK
413
    beneficiary = to_address_masked(pop(evm.stack))
414
415
    # GAS
416
    gas_cost = GasCosts.OPCODE_SELFDESTRUCT_BASE
417
    if (
418
        not is_account_alive(evm.message.tx_env.state, beneficiary)
419
        and get_account(
420
            evm.message.tx_env.state, evm.message.current_target
421
        ).balance
422
        != 0
423
    ):
424
        gas_cost += GasCosts.OPCODE_SELFDESTRUCT_NEW_ACCOUNT
425
426
    originator = evm.message.current_target
427
428
    refunded_accounts = evm.accounts_to_delete
429
    parent_evm = evm.message.parent_evm
430
    while parent_evm is not None:
431
        refunded_accounts.update(parent_evm.accounts_to_delete)
432
        parent_evm = parent_evm.message.parent_evm
433
434
    if originator not in refunded_accounts:
435
        evm.refund_counter += GasCosts.REFUND_SELF_DESTRUCT
436
437
    charge_gas(evm, gas_cost)
438
    if evm.message.is_static:
439
        raise WriteInStaticContext
440
441
    beneficiary_balance = get_account(
442
        evm.message.tx_env.state, beneficiary
443
    ).balance
444
    originator_balance = get_account(
445
        evm.message.tx_env.state, originator
446
    ).balance
447
448
    # First Transfer to beneficiary
449
    set_account_balance(
450
        evm.message.tx_env.state,
451
        beneficiary,
452
        beneficiary_balance + originator_balance,
453
    )
454
    # Next, Zero the balance of the address being deleted (must come after
455
    # sending to beneficiary in case the contract named itself as the
456
    # beneficiary).
457
    set_account_balance(evm.message.tx_env.state, originator, U256(0))
458
459
    # register account for deletion
460
    evm.accounts_to_delete.add(originator)
461
462
    # mark beneficiary as touched
463
    if account_exists_and_is_empty(evm.message.tx_env.state, beneficiary):
464
        evm.touched_accounts.add(beneficiary)
465
466
    # HALT the execution
467
    evm.running = False
468
469
    # PROGRAM COUNTER
470
    pass

delegatecall

Message-call into an account.

Parameters

evm : The current EVM frame.

def delegatecall(evm: Evm) -> None:
474
    <snip>
483
    # STACK
484
    gas = Uint(pop(evm.stack))
485
    code_address = to_address_masked(pop(evm.stack))
486
    memory_input_start_position = pop(evm.stack)
487
    memory_input_size = pop(evm.stack)
488
    memory_output_start_position = pop(evm.stack)
489
    memory_output_size = pop(evm.stack)
490
491
    # GAS
492
    extend_memory = calculate_gas_extend_memory(
493
        evm.memory,
494
        [
495
            (memory_input_start_position, memory_input_size),
496
            (memory_output_start_position, memory_output_size),
497
        ],
498
    )
499
    message_call_gas = calculate_message_call_gas(
500
        U256(0),
501
        gas,
502
        Uint(evm.gas_left),
503
        extend_memory.cost,
504
        GasCosts.OPCODE_CALL_BASE,
505
    )
506
    charge_gas(evm, message_call_gas.cost + extend_memory.cost)
507
508
    # OPERATION
509
    evm.memory += b"\x00" * extend_memory.expand_by
510
    generic_call(
511
        evm,
512
        GenericCall(
513
            gas=message_call_gas.sub_call,
514
            value=evm.message.value,
515
            caller=evm.message.caller,
516
            to=evm.message.current_target,
517
            code_address=code_address,
518
            should_transfer_value=False,
519
            is_staticcall=False,
520
            memory_input_start_position=memory_input_start_position,
521
            memory_input_size=memory_input_size,
522
            memory_output_start_position=memory_output_start_position,
523
            memory_output_size=memory_output_size,
524
        ),
525
    )
526
527
    # PROGRAM COUNTER
528
    evm.pc += Uint(1)

staticcall

Message-call into an account.

Parameters

evm : The current EVM frame.

def staticcall(evm: Evm) -> None:
532
    <snip>
541
    # STACK
542
    gas = Uint(pop(evm.stack))
543
    to = to_address_masked(pop(evm.stack))
544
    memory_input_start_position = pop(evm.stack)
545
    memory_input_size = pop(evm.stack)
546
    memory_output_start_position = pop(evm.stack)
547
    memory_output_size = pop(evm.stack)
548
549
    # GAS
550
    extend_memory = calculate_gas_extend_memory(
551
        evm.memory,
552
        [
553
            (memory_input_start_position, memory_input_size),
554
            (memory_output_start_position, memory_output_size),
555
        ],
556
    )
557
558
    code_address = to
559
560
    message_call_gas = calculate_message_call_gas(
561
        U256(0),
562
        gas,
563
        Uint(evm.gas_left),
564
        extend_memory.cost,
565
        GasCosts.OPCODE_CALL_BASE,
566
    )
567
    charge_gas(evm, message_call_gas.cost + extend_memory.cost)
568
569
    # OPERATION
570
    evm.memory += b"\x00" * extend_memory.expand_by
571
    generic_call(
572
        evm,
573
        GenericCall(
574
            gas=message_call_gas.sub_call,
575
            value=U256(0),
576
            caller=evm.message.current_target,
577
            to=to,
578
            code_address=code_address,
579
            should_transfer_value=True,
580
            is_staticcall=True,
581
            memory_input_start_position=memory_input_start_position,
582
            memory_input_size=memory_input_size,
583
            memory_output_start_position=memory_output_start_position,
584
            memory_output_size=memory_output_size,
585
        ),
586
    )
587
588
    # PROGRAM COUNTER
589
    evm.pc += Uint(1)

revert

Stop execution and revert state changes, without consuming all provided gas and also has the ability to return a reason.

Parameters

evm : The current EVM frame.

def revert(evm: Evm) -> None:
593
    <snip>
603
    # STACK
604
    memory_start_index = pop(evm.stack)
605
    size = pop(evm.stack)
606
607
    # GAS
608
    extend_memory = calculate_gas_extend_memory(
609
        evm.memory, [(memory_start_index, size)]
610
    )
611
612
    charge_gas(evm, extend_memory.cost)
613
614
    # OPERATION
615
    evm.memory += b"\x00" * extend_memory.expand_by
616
    output = memory_read_bytes(evm.memory, memory_start_index, size)
617
    evm.output = Bytes(output)
618
    raise Revert
619
620
    # PROGRAM COUNTER
621
    # no-op