Ethereum Virtual Machine (EVM) Environmental Instructions

Introduction

Implementations of the EVM environment related instructions.

Module Contents

Functions

address

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

balance

Pushes the balance of the given account onto the stack.

origin

Pushes the address of the original transaction sender to the stack.

caller

Pushes the address of the caller onto the stack.

callvalue

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

calldataload

Push a word (32 bytes) of the input data belonging to the current

calldatasize

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

calldatacopy

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

codesize

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

codecopy

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

gasprice

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

extcodesize

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

extcodecopy

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

returndatasize

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

returndatacopy

Copies data from the return data buffer code to memory

extcodehash

Returns the keccak256 hash of a contract’s bytecode

self_balance

Pushes the balance of the current address to the stack.

base_fee

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

Module Details

address

address(evm)

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

Parameters

evm – The current EVM frame.

def address(evm: Evm) -> None:
    # STACK
    pass

    # GAS
    charge_gas(evm, GAS_BASE)

    # OPERATION
    push(evm.stack, U256.from_be_bytes(evm.message.current_target))

    # PROGRAM COUNTER
    evm.pc += 1

balance

balance(evm)

Pushes the balance of the given account onto the stack.

Parameters

evm – The current EVM frame.

def balance(evm: Evm) -> None:
    # STACK
    address = to_address(pop(evm.stack))

    # GAS
    if address in evm.accessed_addresses:
        charge_gas(evm, GAS_WARM_ACCESS)
    else:
        evm.accessed_addresses.add(address)
        charge_gas(evm, GAS_COLD_ACCOUNT_ACCESS)

    # OPERATION
    # Non-existent accounts default to EMPTY_ACCOUNT, which has balance 0.
    balance = get_account(evm.env.state, address).balance

    push(evm.stack, balance)

    # PROGRAM COUNTER
    evm.pc += 1

origin

origin(evm)

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:
    # STACK
    pass

    # GAS
    charge_gas(evm, GAS_BASE)

    # OPERATION
    push(evm.stack, U256.from_be_bytes(evm.env.origin))

    # PROGRAM COUNTER
    evm.pc += 1

caller

caller(evm)

Pushes the address of the caller onto the stack.

Parameters

evm – The current EVM frame.

def caller(evm: Evm) -> None:
    # STACK
    pass

    # GAS
    charge_gas(evm, GAS_BASE)

    # OPERATION
    push(evm.stack, U256.from_be_bytes(evm.message.caller))

    # PROGRAM COUNTER
    evm.pc += 1

callvalue

callvalue(evm)

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

Parameters

evm – The current EVM frame.

def callvalue(evm: Evm) -> None:
    # STACK
    pass

    # GAS
    charge_gas(evm, GAS_BASE)

    # OPERATION
    push(evm.stack, evm.message.value)

    # PROGRAM COUNTER
    evm.pc += 1

calldataload

calldataload(evm)

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:
    # STACK
    start_index = pop(evm.stack)

    # GAS
    charge_gas(evm, GAS_VERY_LOW)

    # OPERATION
    value = buffer_read(evm.message.data, start_index, U256(32))

    push(evm.stack, U256.from_be_bytes(value))

    # PROGRAM COUNTER
    evm.pc += 1

calldatasize

calldatasize(evm)

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

Parameters

evm – The current EVM frame.

def calldatasize(evm: Evm) -> None:
    # STACK
    pass

    # GAS
    charge_gas(evm, GAS_BASE)

    # OPERATION
    push(evm.stack, U256(len(evm.message.data)))

    # PROGRAM COUNTER
    evm.pc += 1

calldatacopy

calldatacopy(evm)

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:
    # STACK
    memory_start_index = pop(evm.stack)
    data_start_index = pop(evm.stack)
    size = pop(evm.stack)

    # GAS
    words = ceil32(Uint(size)) // 32
    copy_gas_cost = GAS_COPY * words
    extend_memory = calculate_gas_extend_memory(
        evm.memory, [(memory_start_index, size)]
    )
    charge_gas(evm, GAS_VERY_LOW + copy_gas_cost + extend_memory.cost)

    # OPERATION
    evm.memory += b"\x00" * extend_memory.expand_by
    value = buffer_read(evm.message.data, data_start_index, size)
    memory_write(evm.memory, memory_start_index, value)

    # PROGRAM COUNTER
    evm.pc += 1

codesize

codesize(evm)

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

Parameters

evm – The current EVM frame.

def codesize(evm: Evm) -> None:
    # STACK
    pass

    # GAS
    charge_gas(evm, GAS_BASE)

    # OPERATION
    push(evm.stack, U256(len(evm.code)))

    # PROGRAM COUNTER
    evm.pc += 1

codecopy

codecopy(evm)

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:
    # STACK
    memory_start_index = pop(evm.stack)
    code_start_index = pop(evm.stack)
    size = pop(evm.stack)

    # GAS
    words = ceil32(Uint(size)) // 32
    copy_gas_cost = GAS_COPY * words
    extend_memory = calculate_gas_extend_memory(
        evm.memory, [(memory_start_index, size)]
    )
    charge_gas(evm, GAS_VERY_LOW + copy_gas_cost + extend_memory.cost)

    # OPERATION
    evm.memory += b"\x00" * extend_memory.expand_by
    value = buffer_read(evm.code, code_start_index, size)
    memory_write(evm.memory, memory_start_index, value)

    # PROGRAM COUNTER
    evm.pc += 1

gasprice

gasprice(evm)

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

Parameters

evm – The current EVM frame.

def gasprice(evm: Evm) -> None:
    # STACK
    pass

    # GAS
    charge_gas(evm, GAS_BASE)

    # OPERATION
    push(evm.stack, evm.env.gas_price)

    # PROGRAM COUNTER
    evm.pc += 1

extcodesize

extcodesize(evm)

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

Parameters

evm – The current EVM frame.

def extcodesize(evm: Evm) -> None:
    # STACK
    address = to_address(pop(evm.stack))

    # GAS
    if address in evm.accessed_addresses:
        charge_gas(evm, GAS_WARM_ACCESS)
    else:
        evm.accessed_addresses.add(address)
        charge_gas(evm, GAS_COLD_ACCOUNT_ACCESS)

    # OPERATION
    # Non-existent accounts default to EMPTY_ACCOUNT, which has empty code.
    codesize = U256(len(get_account(evm.env.state, address).code))

    push(evm.stack, codesize)

    # PROGRAM COUNTER
    evm.pc += 1

extcodecopy

extcodecopy(evm)

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

Parameters

evm – The current EVM frame.

def extcodecopy(evm: Evm) -> None:
    # STACK
    address = to_address(pop(evm.stack))
    memory_start_index = pop(evm.stack)
    code_start_index = pop(evm.stack)
    size = pop(evm.stack)

    # GAS
    words = ceil32(Uint(size)) // 32
    copy_gas_cost = GAS_COPY * words
    extend_memory = calculate_gas_extend_memory(
        evm.memory, [(memory_start_index, size)]
    )

    if address in evm.accessed_addresses:
        charge_gas(evm, GAS_WARM_ACCESS + copy_gas_cost + extend_memory.cost)
    else:
        evm.accessed_addresses.add(address)
        charge_gas(
            evm, GAS_COLD_ACCOUNT_ACCESS + copy_gas_cost + extend_memory.cost
        )

    # OPERATION
    evm.memory += b"\x00" * extend_memory.expand_by
    code = get_account(evm.env.state, address).code
    value = buffer_read(code, code_start_index, size)
    memory_write(evm.memory, memory_start_index, value)

    # PROGRAM COUNTER
    evm.pc += 1

returndatasize

returndatasize(evm)

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

Parameters

evm – The current EVM frame.

def returndatasize(evm: Evm) -> None:
    # STACK
    pass

    # GAS
    charge_gas(evm, GAS_BASE)

    # OPERATION
    push(evm.stack, U256(len(evm.return_data)))

    # PROGRAM COUNTER
    evm.pc += 1

returndatacopy

returndatacopy(evm)

Copies data from the return data buffer code to memory

Parameters

evm – The current EVM frame.

def returndatacopy(evm: Evm) -> None:
    # STACK
    memory_start_index = pop(evm.stack)
    return_data_start_position = pop(evm.stack)
    size = pop(evm.stack)

    # GAS
    words = ceil32(Uint(size)) // 32
    copy_gas_cost = GAS_RETURN_DATA_COPY * words
    extend_memory = calculate_gas_extend_memory(
        evm.memory, [(memory_start_index, size)]
    )
    charge_gas(evm, GAS_VERY_LOW + copy_gas_cost + extend_memory.cost)

    # OPERATION
    ensure(
        Uint(return_data_start_position) + Uint(size) <= len(evm.return_data),
        OutOfBoundsRead,
    )

    evm.memory += b"\x00" * extend_memory.expand_by
    value = evm.return_data[
        return_data_start_position : return_data_start_position + size
    ]
    memory_write(evm.memory, memory_start_index, value)

    # PROGRAM COUNTER
    evm.pc += 1

extcodehash

extcodehash(evm)

Returns the keccak256 hash of a contract’s bytecode :param evm: The current EVM frame.

def extcodehash(evm: Evm) -> None:
    # STACK
    address = to_address(pop(evm.stack))

    # GAS
    if address in evm.accessed_addresses:
        charge_gas(evm, GAS_WARM_ACCESS)
    else:
        evm.accessed_addresses.add(address)
        charge_gas(evm, GAS_COLD_ACCOUNT_ACCESS)

    # OPERATION
    account = get_account(evm.env.state, address)

    if account == EMPTY_ACCOUNT:
        codehash = U256(0)
    else:
        codehash = U256.from_be_bytes(keccak256(account.code))

    push(evm.stack, codehash)

    # PROGRAM COUNTER
    evm.pc += 1

self_balance

self_balance(evm)

Pushes the balance of the current address to the stack.

Parameters

evm – The current EVM frame.

def self_balance(evm: Evm) -> None:
    # STACK
    pass

    # GAS
    charge_gas(evm, GAS_FAST_STEP)

    # OPERATION
    # Non-existent accounts default to EMPTY_ACCOUNT, which has balance 0.
    balance = get_account(evm.env.state, evm.message.current_target).balance

    push(evm.stack, balance)

    # PROGRAM COUNTER
    evm.pc += 1

base_fee

base_fee(evm)

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

Parameters

evm – The current EVM frame.

def base_fee(evm: Evm) -> None:
    # STACK
    pass

    # GAS
    charge_gas(evm, GAS_BASE)

    # OPERATION
    push(evm.stack, U256(evm.env.base_fee_per_gas))

    # PROGRAM COUNTER
    evm.pc += 1