Environment#

These opcodes give you access to the Ethereum environment

Address#

Returns the address of the account currently executing this program

def address(evm):
    evm.stack.push(evm.sender)
    evm.pc += 1
    evm.gas_dec(3)

Balance#

Get the balance of the given address. We only mock this, so we always return the same value for every address.

def balance(evm):
    address = cpu.stack.pop()
    evm.stack.push(99999999999)

    evm.pc += 1
    evm.gas_dec(2600) # 100 if warm

Origin#

The address that originally triggered the execution. This is tx.originin Solidity. For us tx.origin is always equal to msg.sender. That is why we simply return the sender.

def origin(evm):
    evm.stack.push(evm.sender)
    evm.pc += 1
    evm.gas_dec(2)

Caller#

def caller(evm):
    evm.stack.push("0x414b60745072088d013721b4a28a0559b1A9d213")
    evm.pc += 1
    evm.gas_dec(2)

Callvalue#

Returns the value of Ether (wei) provided for this execution

def callvalue(evm):
    evm.stack.push(evm.value)
    evm.pc += 1
    evm.gas_dec(2)

Calldataload#

Pushes the current input data (32 bytes) on the stack

def calldataload(evm):
    i = evm.stack.pop()

    delta = 0
    if i+32 > len(evm.calldata):
        delta = i+32 - len(evm.calldata)

    # always has to be 32 bytes
    # if its not we append 0x00 bytes until it is
    calldata = evm.calldata[i:i+32-delta]
    calldata += 0x00*delta

    evm.stack.push(calldata)
    evm.pc += 1
    evm.gas_dec(3)

Calldatasize#

Pushes the size of the calldata on the stack

def calldatasize(evm):
    evm.stack.push(len(evm.calldata))
    evm.pc += 1
    evm.gas_dec(2)

Calldatacopy#

Stores a specified part of the calldata in memory

def calldatacopy(evm):
    destOffset = cpu.stack.pop()
    offset = evm.stack.pop()
    size = evm.stack.pop()

    calldata = evm.calldata[offset:offset+size]
    memory_expansion_cost = evm.memory.store(destOffset, calldata)

    static_gas = 3
    minimum_word_size = (size + 31) // 32
    dynamic_gas = 3 * minimum_word_size + memory_expansion_cost

    evm.gas_dec(static_gas + dynamic_gas)
    evm.pc += 1

Codesize#

Puts the size of the currently running program on the stack

def codesize(evm):
    evm.stack.push(len(evm.program))
    evm.pc += 1
    evm.gas_dec(2)

Codecopy#

Stores a specified part of the program in memory

def codecopy(evm):
    destOffset = evm.stack.pop()
    offset     = evm.stack.pop()
    size       = evm.stack.pop()

    code = evm.program[offset:offset+size]
    memory_expansion_cost = evm.memory.store(destOffset, code)

    static_gas = 3
    minimum_word_size = (size + 31) / 32
    dynamic_gas = 3 * minimum_word_size + memory_expansion_cost

    evm.gas_dec(static_gas + dynamic_gas)
    evm.pc += 1

Gas Price#

The current gas price. Because we are running everything locally, the gas price is simply 0.

def gasprice(evm):
    evm.stack.push(0x00)
    evm.pc += 1
    evm.gas_dec(2)

External Code Size#

The size of another program given by its address. There are no other programs in our simplified world so we simply return 0.

def extcodesize(evm):
    address = evm.stack.pop()
    evm.stack.push(0x00)
    evm.gas_dec(2600) # 100 if warm
    evm.pc += 1

External Code Copy#

Stores a specified part of another program in memory

def extcodecopy(evm):
    address    = evm.stack.pop()
    destOffset = evm.stack.pop()
    offset     = evm.stack.pop()
    size       = evm.stack.pop()

    extcode = [] # no external code
    memory_expansion_cost = evm.memory.store(destOffset, extcode)

    # refactor this in seperate method
    minimum_word_size = (size + 31) / 32
    dynamic_gas = 3 * minimum_word_size + memory_expansion_cost
    address_access_cost = 100 if warm else 2600

    evm.gas_dec(dynamic_gas + address_access_cost)
    evm.pc += 1

Return Data Size#

Get size of output data from the previous call from the current environment. As our execution is the only one running, there is no previous return data. Therefore we can simply return 0.

def returndatasize(evm):
    evm.stack.push(0x00) # no return data
    evm.pc += 1
    evm.gas_dec(2)

Return Data Copy#

Stores a specified part of the previous return data in memory

def returndatacopy(evm):
    destOffset = evm.stack.pop()
    offset     = evm.stack.pop()
    size       = evm.stack.pop()

    returndata            = evm.program[offset:offset+size]
    memory_expansion_cost = evm.memory.store(destOffset, returndata)

    minimum_word_size = (size + 31) / 32
    dynamic_gas = 3 * minimum_word_size + memory_expansion_cost

    evm.gas_dec(3 + dynamic_gas)
    evm.pc += 1

External Code Hash#

The hash of another program given by its address. There are no other programs in our simplified world so we simply return 0.

def extcodehash(evm):
    address = evm.stack.pop()
    evm.stack.push(0x00) # no code

    evm.gas_dec(2600) # 100 if warm
    evm.pc += 1

Block Hash#

Get the hash of one of the 256 most recent complete blocks and push it on the stack.

def blockhash(evm):
    blockNumber = evm.stack.pop()
    if blockNumber > 256: raise Exception("Only last 256 blocks can be accessed")
    evm.stack.push(0x1cbcfa1ffb1ca1ca8397d4f490194db5fc0543089b9dee43f76cf3f962a185e8)
    evm.pc += 1
    evm.gas_dec(20)

Coinbase#

Get the address of the miner for this block

def coinbase(evm):
    evm.stack.push(0x1cbcfa1ffb1ca1ca8397d4f490194db5fc0543089b9dee43f76cf3f962a185e8)
    evm.pc += 1
    evm.gas_dec(2)