127 lines
5.2 KiB
Nim
127 lines
5.2 KiB
Nim
# Nimbus
|
|
# Copyright (c) 2018 Status Research & Development GmbH
|
|
# Licensed under either of
|
|
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
|
|
# * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT)
|
|
# at your option. This file may not be copied, modified, or distributed except according to those terms.
|
|
|
|
import
|
|
strformat,
|
|
../constants, ../types, ../errors, ../utils_numeric, ../computation, ../vm_state, ../account, ../db/state_db, ../validation,
|
|
.. / vm / [stack, message, gas_meter, memory, code_stream], .. / utils / [address, padding, bytes], ttmath
|
|
|
|
proc balance*(computation: var BaseComputation) =
|
|
let address = forceBytesToAddress(computation.stack.popString)
|
|
var balance: Int256
|
|
# TODO computation.vmState.stateDB(read_only=True):
|
|
# balance = db.getBalance(address)
|
|
# computation.stack.push(balance)
|
|
|
|
proc origin*(computation: var BaseComputation) =
|
|
computation.stack.push(computation.msg.origin)
|
|
|
|
proc address*(computation: var BaseComputation) =
|
|
computation.stack.push(computation.msg.storageAddress)
|
|
|
|
proc caller*(computation: var BaseComputation) =
|
|
computation.stack.push(computation.msg.sender)
|
|
|
|
|
|
proc callValue*(computation: var BaseComputation) =
|
|
computation.stack.push(computation.msg.value)
|
|
|
|
proc callDataLoad*(computation: var BaseComputation) =
|
|
# Load call data into memory
|
|
let startPosition = computation.stack.popInt.getUInt.int
|
|
let value = computation.msg.data[startPosition ..< startPosition + 32]
|
|
let paddedValue = padRight(value, 32, 0.byte)
|
|
let normalizedValue = paddedValue.lStrip(0.byte)
|
|
computation.stack.push(normalizedValue)
|
|
|
|
|
|
proc callDataSize*(computation: var BaseComputation) =
|
|
let size = computation.msg.data.len.u256
|
|
computation.stack.push(size)
|
|
|
|
proc callDataCopy*(computation: var BaseComputation) =
|
|
let (memStartPosition,
|
|
calldataStartPosition,
|
|
size) = computation.stack.popInt(3)
|
|
computation.extendMemory(memStartPosition, size)
|
|
|
|
let wordCount = ceil32(size) div 32
|
|
let copyGasCost = wordCount * constants.GAS_COPY
|
|
computation.gasMeter.consumeGas(copyGasCost, reason="CALLDATACOPY fee")
|
|
let value = computation.msg.data[calldataStartPosition.getUInt.int ..< (calldataStartPosition + size).getUInt.int]
|
|
let paddedValue = padRight(value, size.getUInt.int, 0.byte)
|
|
computation.memory.write(memStartPosition, size, paddedValue)
|
|
|
|
|
|
proc codesize*(computation: var BaseComputation) =
|
|
let size = computation.code.len.u256
|
|
computation.stack.push(size)
|
|
|
|
|
|
proc codecopy*(computation: var BaseComputation) =
|
|
let (memStartPosition,
|
|
codeStartPosition,
|
|
size) = computation.stack.popInt(3)
|
|
computation.extendMemory(memStartPosition, size)
|
|
let wordCount = ceil32(size) div 32
|
|
let copyGasCost = constants.GAS_COPY * wordCount
|
|
|
|
computation.gasMeter.consumeGas(copyGasCost, reason="CODECOPY: word gas cost")
|
|
# TODO
|
|
# with computation.code.seek(code_start_position):
|
|
# code_bytes = computation.code.read(size)
|
|
# padded_code_bytes = pad_right(code_bytes, size, b'\x00')
|
|
# computation.memory.write(mem_start_position, size, padded_code_bytes)
|
|
|
|
|
|
proc gasprice*(computation: var BaseComputation) =
|
|
computation.stack.push(computation.msg.gasPrice)
|
|
|
|
|
|
proc extCodeSize*(computation: var BaseComputation) =
|
|
let account = forceBytesToAddress(computation.stack.popString)
|
|
# TODO
|
|
# with computation.vm_state.state_db(read_only=True) as state_db:
|
|
# code_size = len(state_db.get_code(account))
|
|
|
|
# computation.stack.push(code_size)
|
|
|
|
proc extCodeCopy*(computation: var BaseComputation) =
|
|
let account = forceBytesToAddress(computation.stack.popString)
|
|
let (memStartPosition, codeStartPosition, size) = computation.stack.popInt(3)
|
|
computation.extendMemory(memStartPosition, size)
|
|
let wordCount = ceil32(size) div 32
|
|
let copyGasCost = constants.GAS_COPY * wordCount
|
|
|
|
computation.gasMeter.consumeGas(copyGasCost, reason="EXTCODECOPY: word gas cost")
|
|
|
|
# TODO:
|
|
# with computation.vm_state.state_db(read_only=True) as state_db:
|
|
# code = state_db.get_code(account)
|
|
# code_bytes = code[code_start_position:code_start_position + size]
|
|
# padded_code_bytes = pad_right(code_bytes, size, b'\x00')
|
|
# computation.memory.write(mem_start_position, size, padded_code_bytes)
|
|
|
|
proc returnDataSize*(computation: var BaseComputation) =
|
|
let size = computation.returnData.len.u256
|
|
computation.stack.push(size)
|
|
|
|
proc returnDataCopy*(computation: var BaseComputation) =
|
|
let (memStartPosition, returnDataStartPosition, size) = computation.stack.popInt(3)
|
|
if returnDataStartPosition + size > computation.returnData.len:
|
|
raise newException(OutOfBoundsRead,
|
|
"Return data length is not sufficient to satisfy request. Asked \n" &
|
|
&"for data from index {returnDataStartPosition} to {returnDataStartPosition + size}. Return data is {computation.returnData.len} in \n" &
|
|
"length")
|
|
|
|
computation.extendMemory(memStartPosition, size)
|
|
let wordCount = ceil32(size) div 32
|
|
let copyGasCost = wordCount * constants.GAS_COPY
|
|
computation.gasMeter.consumeGas(copyGasCost, reason="RETURNDATACOPY fee")
|
|
let value = ($computation.returnData)[returnDataStartPosition.getUInt.int ..< (returnDataStartPosition + size).getUInt.int]
|
|
computation.memory.write(memStartPosition, size, value)
|