ethereum.forks.bpo5.vm.instructions.environmentethereum.forks.amsterdam.vm.instructions.environment

Ethereum Virtual Machine (EVM) Environmental Instructions.

.. contents:: Table of Contents :backlinks: none :local:

Introduction

Implementations of the EVM environment related instructions.

address

Pushes the address of the current executing account to the stack.

Parameters

evm : The current EVM frame.

def address(evm: Evm) -> None:
35
    <snip>
44
    # STACK
45
    pass
46
47
    # GAS
48
    charge_gas(evm, GasCosts.OPCODE_ADDRESS)
49
50
    # OPERATION
51
    push(evm.stack, U256.from_be_bytes(evm.message.current_target))
52
53
    # PROGRAM COUNTER
54
    evm.pc += Uint(1)

balance

Pushes the balance of the given account onto the stack.

Parameters

evm : The current EVM frame.

def balance(evm: Evm) -> None:
58
    <snip>
67
    # STACK
68
    address = to_address_masked(pop(evm.stack))
69
70
    # GAS
71
    if address in evm.accessed_addresses:
72
        charge_gas(evm, GasCosts.WARM_ACCESS)
73
    else:
74
        evm.accessed_addresses.add(address)
75
        charge_gas(evm, GasCosts.COLD_ACCOUNT_ACCESS)
76
77
    # OPERATION
78
    # Non-existent accounts default to EMPTY_ACCOUNT, which has balance 0.
79
    tx_state = evm.message.tx_env.state
80
    balance = get_account(tx_state, address).balance
81
82
    push(evm.stack, balance)
83
84
    # PROGRAM COUNTER
85
    evm.pc += Uint(1)

origin

Pushes the address of the original transaction sender to the stack. The origin address can only be an EOA.

Parameters

evm : The current EVM frame.

def origin(evm: Evm) -> None:
89
    <snip>
99
    # STACK
100
    pass
101
102
    # GAS
103
    charge_gas(evm, GasCosts.OPCODE_ORIGIN)
104
105
    # OPERATION
106
    push(evm.stack, U256.from_be_bytes(evm.message.tx_env.origin))
107
108
    # PROGRAM COUNTER
109
    evm.pc += Uint(1)

caller

Pushes the address of the caller onto the stack.

Parameters

evm : The current EVM frame.

def caller(evm: Evm) -> None:
113
    <snip>
122
    # STACK
123
    pass
124
125
    # GAS
126
    charge_gas(evm, GasCosts.OPCODE_CALLER)
127
128
    # OPERATION
129
    push(evm.stack, U256.from_be_bytes(evm.message.caller))
130
131
    # PROGRAM COUNTER
132
    evm.pc += Uint(1)

callvalue

Push the value (in wei) sent with the call onto the stack.

Parameters

evm : The current EVM frame.

def callvalue(evm: Evm) -> None:
136
    <snip>
145
    # STACK
146
    pass
147
148
    # GAS
149
    charge_gas(evm, GasCosts.OPCODE_CALLVALUE)
150
151
    # OPERATION
152
    push(evm.stack, evm.message.value)
153
154
    # PROGRAM COUNTER
155
    evm.pc += Uint(1)

calldataload

Push a word (32 bytes) of the input data belonging to the current environment onto the stack.

Parameters

evm : The current EVM frame.

def calldataload(evm: Evm) -> None:
159
    <snip>
169
    # STACK
170
    start_index = pop(evm.stack)
171
172
    # GAS
173
    charge_gas(evm, GasCosts.OPCODE_CALLDATALOAD)
174
175
    # OPERATION
176
    value = buffer_read(evm.message.data, start_index, U256(32))
177
178
    push(evm.stack, U256.from_be_bytes(value))
179
180
    # PROGRAM COUNTER
181
    evm.pc += Uint(1)

calldatasize

Push the size of input data in current environment onto the stack.

Parameters

evm : The current EVM frame.

def calldatasize(evm: Evm) -> None:
185
    <snip>
194
    # STACK
195
    pass
196
197
    # GAS
198
    charge_gas(evm, GasCosts.OPCODE_CALLDATASIZE)
199
200
    # OPERATION
201
    push(evm.stack, U256(len(evm.message.data)))
202
203
    # PROGRAM COUNTER
204
    evm.pc += Uint(1)

calldatacopy

Copy a portion of the input data in current environment to memory.

This will also expand the memory, in case that the memory is insufficient to store the data.

Parameters

evm : The current EVM frame.

def calldatacopy(evm: Evm) -> None:
208
    <snip>
220
    # STACK
221
    memory_start_index = pop(evm.stack)
222
    data_start_index = pop(evm.stack)
223
    size = pop(evm.stack)
224
225
    # GAS
226
    words = ceil32(Uint(size)) // Uint(32)
227
    copy_gas_cost = GasCosts.OPCODE_COPY_PER_WORD * words
228
    extend_memory = calculate_gas_extend_memory(
229
        evm.memory, [(memory_start_index, size)]
230
    )
231
    charge_gas(
232
        evm,
233
        GasCosts.OPCODE_CALLDATACOPY_BASE + copy_gas_cost + extend_memory.cost,
234
    )
235
236
    # OPERATION
237
    evm.memory += b"\x00" * extend_memory.expand_by
238
    value = buffer_read(evm.message.data, data_start_index, size)
239
    memory_write(evm.memory, memory_start_index, value)
240
241
    # PROGRAM COUNTER
242
    evm.pc += Uint(1)

codesize

Push the size of code running in current environment onto the stack.

Parameters

evm : The current EVM frame.

def codesize(evm: Evm) -> None:
246
    <snip>
255
    # STACK
256
    pass
257
258
    # GAS
259
    charge_gas(evm, GasCosts.OPCODE_CODESIZE)
260
261
    # OPERATION
262
    push(evm.stack, U256(len(evm.code)))
263
264
    # PROGRAM COUNTER
265
    evm.pc += Uint(1)

codecopy

Copy a portion of the code in current environment to memory.

This will also expand the memory, in case that the memory is insufficient to store the data.

Parameters

evm : The current EVM frame.

def codecopy(evm: Evm) -> None:
269
    <snip>
281
    # STACK
282
    memory_start_index = pop(evm.stack)
283
    code_start_index = pop(evm.stack)
284
    size = pop(evm.stack)
285
286
    # GAS
287
    words = ceil32(Uint(size)) // Uint(32)
288
    copy_gas_cost = GasCosts.OPCODE_COPY_PER_WORD * words
289
    extend_memory = calculate_gas_extend_memory(
290
        evm.memory, [(memory_start_index, size)]
291
    )
292
    charge_gas(
293
        evm,
294
        GasCosts.OPCODE_CODECOPY_BASE + copy_gas_cost + extend_memory.cost,
295
    )
296
297
    # OPERATION
298
    evm.memory += b"\x00" * extend_memory.expand_by
299
    value = buffer_read(evm.code, code_start_index, size)
300
    memory_write(evm.memory, memory_start_index, value)
301
302
    # PROGRAM COUNTER
303
    evm.pc += Uint(1)

gasprice

Push the gas price used in current environment onto the stack.

Parameters

evm : The current EVM frame.

def gasprice(evm: Evm) -> None:
307
    <snip>
316
    # STACK
317
    pass
318
319
    # GAS
320
    charge_gas(evm, GasCosts.OPCODE_GASPRICE)
321
322
    # OPERATION
323
    push(evm.stack, U256(evm.message.tx_env.gas_price))
324
325
    # PROGRAM COUNTER
326
    evm.pc += Uint(1)

extcodesize

Push the code size of a given account onto the stack.

Parameters

evm : The current EVM frame.

def extcodesize(evm: Evm) -> None:
330
    <snip>
339
    # STACK
340
    address = to_address_masked(pop(evm.stack))
341
342
    # GAS
343
    if address in evm.accessed_addresses:
344
        access_gas_cost = GasCosts.WARM_ACCESS
345
    else:
346
        evm.accessed_addresses.add(address)
347
        access_gas_cost = GasCosts.COLD_ACCOUNT_ACCESS
348
348
    access_gas_cost += GasCosts.WARM_ACCESS  # Code reading cost (EIP-8038)
349
    charge_gas(evm, access_gas_cost)
350
351
    # OPERATION
352
    tx_state = evm.message.tx_env.state
353
    code = get_code(tx_state, get_account(tx_state, address).code_hash)
353
    code_hash = get_account(tx_state, address).code_hash
354
    code = get_code(tx_state, code_hash)
355
356
    codesize = U256(len(code))
357
    push(evm.stack, codesize)
358
359
    # PROGRAM COUNTER
360
    evm.pc += Uint(1)

extcodecopy

Copy a portion of an account's code to memory.

Parameters

evm : The current EVM frame.

def extcodecopy(evm: Evm) -> None:
364
    <snip>
373
    # STACK
374
    address = to_address_masked(pop(evm.stack))
375
    memory_start_index = pop(evm.stack)
376
    code_start_index = pop(evm.stack)
377
    size = pop(evm.stack)
378
379
    # GAS
380
    words = ceil32(Uint(size)) // Uint(32)
381
    copy_gas_cost = GasCosts.OPCODE_COPY_PER_WORD * words
382
    extend_memory = calculate_gas_extend_memory(
383
        evm.memory, [(memory_start_index, size)]
384
    )
385
386
    if address in evm.accessed_addresses:
387
        access_gas_cost = GasCosts.WARM_ACCESS
388
    else:
389
        evm.accessed_addresses.add(address)
390
        access_gas_cost = GasCosts.COLD_ACCOUNT_ACCESS
391
    access_gas_cost += GasCosts.WARM_ACCESS  # Code reading cost (EIP-8038)
392
391
    charge_gas(evm, access_gas_cost + copy_gas_cost + extend_memory.cost)
393
    total_gas_cost = access_gas_cost + copy_gas_cost + extend_memory.cost
394
395
    charge_gas(evm, total_gas_cost)
396
397
    # OPERATION
398
    evm.memory += b"\x00" * extend_memory.expand_by
399
    tx_state = evm.message.tx_env.state
396
    code = get_code(tx_state, get_account(tx_state, address).code_hash)
400
    code_hash = get_account(tx_state, address).code_hash
401
    code = get_code(tx_state, code_hash)
402
403
    value = buffer_read(code, code_start_index, size)
404
    memory_write(evm.memory, memory_start_index, value)
405
406
    # PROGRAM COUNTER
407
    evm.pc += Uint(1)

returndatasize

Pushes the size of the return data buffer onto the stack.

Parameters

evm : The current EVM frame.

def returndatasize(evm: Evm) -> None:
411
    <snip>
420
    # STACK
421
    pass
422
423
    # GAS
424
    charge_gas(evm, GasCosts.OPCODE_RETURNDATASIZE)
425
426
    # OPERATION
427
    push(evm.stack, U256(len(evm.return_data)))
428
429
    # PROGRAM COUNTER
430
    evm.pc += Uint(1)

returndatacopy

Copies data from the return data buffer to memory.

Parameters

evm : The current EVM frame.

def returndatacopy(evm: Evm) -> None:
434
    <snip>
443
    # STACK
444
    memory_start_index = pop(evm.stack)
445
    return_data_start_position = pop(evm.stack)
446
    size = pop(evm.stack)
447
448
    # GAS
449
    words = ceil32(Uint(size)) // Uint(32)
450
    copy_gas_cost = GasCosts.OPCODE_RETURNDATACOPY_PER_WORD * words
451
    extend_memory = calculate_gas_extend_memory(
452
        evm.memory, [(memory_start_index, size)]
453
    )
454
    charge_gas(
455
        evm,
456
        GasCosts.OPCODE_RETURNDATACOPY_BASE
457
        + copy_gas_cost
458
        + extend_memory.cost,
459
    )
460
    if Uint(return_data_start_position) + Uint(size) > ulen(evm.return_data):
461
        raise OutOfBoundsRead
462
463
    evm.memory += b"\x00" * extend_memory.expand_by
464
    value = evm.return_data[
465
        return_data_start_position : return_data_start_position + size
466
    ]
467
    memory_write(evm.memory, memory_start_index, value)
468
469
    # PROGRAM COUNTER
470
    evm.pc += Uint(1)

extcodehash

Returns the keccak256 hash of a contract’s bytecode.

Parameters

evm : The current EVM frame.

def extcodehash(evm: Evm) -> None:
474
    <snip>
483
    # STACK
484
    address = to_address_masked(pop(evm.stack))
485
486
    # GAS
487
    if address in evm.accessed_addresses:
488
        access_gas_cost = GasCosts.WARM_ACCESS
489
    else:
490
        evm.accessed_addresses.add(address)
491
        access_gas_cost = GasCosts.COLD_ACCOUNT_ACCESS
492
493
    charge_gas(evm, access_gas_cost)
494
495
    # OPERATION
491
    account = get_account(evm.message.tx_env.state, address)
496
    tx_state = evm.message.tx_env.state
497
    account = get_account(tx_state, address)
498
499
    if account == EMPTY_ACCOUNT:
500
        codehash = U256(0)
501
    else:
502
        codehash = U256.from_be_bytes(account.code_hash)
503
504
    push(evm.stack, codehash)
505
506
    # PROGRAM COUNTER
507
    evm.pc += Uint(1)

self_balance

Pushes the balance of the current address to the stack.

Parameters

evm : The current EVM frame.

def self_balance(evm: Evm) -> None:
511
    <snip>
520
    # STACK
521
    pass
522
523
    # GAS
524
    charge_gas(evm, GasCosts.FAST_STEP)
525
526
    # OPERATION
527
    # Non-existent accounts default to EMPTY_ACCOUNT, which has balance 0.
528
    balance = get_account(
529
        evm.message.tx_env.state, evm.message.current_target
530
    ).balance
531
532
    push(evm.stack, balance)
533
534
    # PROGRAM COUNTER
535
    evm.pc += Uint(1)

base_fee

Pushes the base fee of the current block on to the stack.

Parameters

evm : The current EVM frame.

def base_fee(evm: Evm) -> None:
539
    <snip>
548
    # STACK
549
    pass
550
551
    # GAS
552
    charge_gas(evm, GasCosts.OPCODE_BASEFEE)
553
554
    # OPERATION
555
    push(evm.stack, U256(evm.message.block_env.base_fee_per_gas))
556
557
    # PROGRAM COUNTER
558
    evm.pc += Uint(1)

blob_hash

Pushes the versioned hash at a particular index on to the stack.

Parameters

evm : The current EVM frame.

def blob_hash(evm: Evm) -> None:
562
    <snip>
571
    # STACK
572
    index = pop(evm.stack)
573
574
    # GAS
575
    charge_gas(evm, GasCosts.OPCODE_BLOBHASH)
576
577
    # OPERATION
578
    if int(index) < len(evm.message.tx_env.blob_versioned_hashes):
579
        blob_hash = evm.message.tx_env.blob_versioned_hashes[index]
580
    else:
581
        blob_hash = Bytes32(b"\x00" * 32)
582
    push(evm.stack, U256.from_be_bytes(blob_hash))
583
584
    # PROGRAM COUNTER
585
    evm.pc += Uint(1)

blob_base_fee

Pushes the blob base fee on to the stack.

Parameters

evm : The current EVM frame.

def blob_base_fee(evm: Evm) -> None:
589
    <snip>
598
    # STACK
599
    pass
600
601
    # GAS
602
    charge_gas(evm, GasCosts.OPCODE_BLOBBASEFEE)
603
604
    # OPERATION
605
    blob_base_fee = calculate_blob_gas_price(
606
        evm.message.block_env.excess_blob_gas
607
    )
608
    push(evm.stack, U256(blob_base_fee))
609
610
    # PROGRAM COUNTER
611
    evm.pc += Uint(1)