Prepare the remaining opcodes, implement context opcodes

This commit is contained in:
Alexander Ivanov 2018-01-29 21:38:24 +02:00
parent 5ad14f59b2
commit 0fa5c5fd94
3 changed files with 116 additions and 108 deletions

View File

@ -107,6 +107,10 @@ let
GAS_JUMP_DEST* = 1.i256
GAS_SSET* = 20_000.i256
GAS_SRESET* = 5000.i256
GAS_EXT_CODE_COST* = 700.i256
GAS_COINBASE* = 20.i256
GAS_SLOAD_COST* = 20.i256
GAS_SELF_DESTRUCT_COST* = 5_000.i256
REFUNDS_CLEAR* = 15_000.i256

View File

@ -1,6 +1,7 @@
import
../constants, ../utils_numeric, ../computation, ../vm_state, ../account, ../db/state_db, ../validation,
.. / vm / [stack, message], .. / utils / [address, padding, bytes]
strformat,
../constants, ../errors, ../utils_numeric, ../computation, ../vm_state, ../account, ../db/state_db, ../validation,
.. / vm / [stack, message, gas_meter, memory, code_stream], .. / utils / [address, padding, bytes], bigints
proc balance*(computation: var BaseComputation) =
let address = forceBytesToAddress(computation.stack.popBinary)
@ -35,124 +36,84 @@ proc callDataSize*(computation: var BaseComputation) =
let size = computation.msg.data.len
computation.stack.push(size)
# def calldatacopy(computation):
# (
# mem_start_position,
# calldata_start_position,
# size,
# ) = computation.stack.pop(num_items=3, type_hint=constants.UINT256)
proc callDataCopy*(computation: var BaseComputation) =
let (memStartPosition,
calldataStartPosition,
size) = computation.stack.popInt(3)
computation.extendMemory(memStartPosition, size)
# computation.extend_memory(mem_start_position, size)
# word_count = ceil32(size) // 32
# copy_gas_cost = word_count * constants.GAS_COPY
# computation.gas_meter.consume_gas(copy_gas_cost, reason="CALLDATACOPY fee")
# value = computation.msg.data[calldata_start_position: calldata_start_position + size]
# padded_value = pad_right(value, size, b'\x00')
# computation.memory.write(mem_start_position, size, padded_value)
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.getInt ..< (calldataStartPosition + size).getInt].toCString
let paddedValue = padRight(value, size.getInt, cstring"\x00")
computation.memory.write(memStartPosition, size, paddedValue)
# def codesize(computation):
# size = len(computation.code)
# computation.stack.push(size)
proc codesize*(computation: var BaseComputation) =
let size = computation.code.len.i256
computation.stack.push(size)
# def codecopy(computation):
# (
# mem_start_position,
# code_start_position,
# size,
# ) = computation.stack.pop(num_items=3, type_hint=constants.UINT256)
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.extend_memory(mem_start_position, size)
# word_count = ceil32(size) // 32
# copy_gas_cost = constants.GAS_COPY * word_count
# computation.gas_meter.consume_gas(
# copy_gas_cost,
# reason="CODECOPY: word gas cost",
# )
# 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)
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)
# def gasprice(computation):
# computation.stack.push(computation.msg.gas_price)
proc gasprice*(computation: var BaseComputation) =
computation.stack.push(computation.msg.gasPrice)
# def extcodesize(computation):
# account = force_bytes_to_address(computation.stack.pop(type_hint=constants.BYTES))
# with computation.vm_state.state_db(read_only=True) as state_db:
# code_size = len(state_db.get_code(account))
proc extCodeSize*(computation: var BaseComputation) =
let account = forceBytesToAddress(computation.stack.popBinary)
# 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)
# computation.stack.push(code_size)
proc extCodeCopy*(computation: var BaseComputation) =
let account = forceBytesToAddress(computation.stack.popBinary)
let (memStartPosition, codeStartPosition, size) = computation.stack.popInt(3)
computation.extendMemory(memStartPosition, size)
let wordCount = ceil32(size) div 32
let copyGasCost = constants.GAS_COPY * wordCount
# def extcodecopy(computation):
# account = force_bytes_to_address(computation.stack.pop(type_hint=constants.BYTES))
# (
# mem_start_position,
# code_start_position,
# size,
# ) = computation.stack.pop(num_items=3, type_hint=constants.UINT256)
computation.gasMeter.consumeGas(copyGasCost, reason="EXTCODECOPY: word gas cost")
# computation.extend_memory(mem_start_position, size)
# 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)
# word_count = ceil32(size) // 32
# copy_gas_cost = constants.GAS_COPY * word_count
proc returnDataSize*(computation: var BaseComputation) =
let size = computation.returnData.len
computation.stack.push(size)
# computation.gas_meter.consume_gas(
# copy_gas_cost,
# reason='EXTCODECOPY: word gas cost',
# )
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")
# 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)
# def returndatasize(computation):
# size = len(computation.return_data)
# computation.stack.push(size)
# def returndatacopy(computation):
# (
# mem_start_position,
# returndata_start_position,
# size,
# ) = computation.stack.pop(num_items=3, type_hint=constants.UINT256)
# if returndata_start_position + size > len(computation.return_data):
# raise OutOfBoundsRead(
# "Return data length is not sufficient to satisfy request. Asked "
# "for data from index {0} to {1}. Return data is {2} bytes in "
# "length.".format(
# returndata_start_position,
# returndata_start_position + size,
# len(computation.return_data),
# )
# )
# computation.extend_memory(mem_start_position, size)
# word_count = ceil32(size) // 32
# copy_gas_cost = word_count * constants.GAS_COPY
# computation.gas_meter.consume_gas(copy_gas_cost, reason="RETURNDATACOPY fee")
# value = computation.return_data[returndata_start_position: returndata_start_position + size]
# computation.memory.write(mem_start_position, size, value)
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 = cstring(($computation.returnData)[returnDataStartPosition.getInt ..< (returnDataStartPosition + size).getInt])
computation.memory.write(memStartPosition, size, value)

View File

@ -45,6 +45,49 @@ var opcodes = initOpcodes:
Op.CallValue: GAS_BASE callValue
Op.CallDataLoad: GAS_VERY_LOW callDataLoad
Op.CallDataSize: GAS_BASE callDataSize
Op.CallDataCopy: GAS_BASE callDataCopy
Op.CodeSize: GAS_BASE codesize
Op.CodeCopy: GAS_BASE codecopy
Op.ExtCodeSize: GAS_EXT_CODE_COST extCodeSize
Op.ExtCodeCopy: GAS_EXT_CODE_COST extCodeCopy
# Op.Blockhash: GAS_BASE blockhash
# Op.Coinbase: GAS_COINBASE coinbase
# Op.Timestamp: GAS_BASE timestamp
# Op.Number: GAS_BASE number
# Op.Difficulty: GAS_BASE difficulty
# Op.GasLimit: GAS_BASE gasLimitOp
# Op.Pop: GAS_BASE popOp
# Op.MLoad: GAS_VERY_LOW mload
# Op.MStore: GAS_VERY_LOW mstore
# Op.MStore8: GAS_VERY_LOW mstore8
# Op.SLoad: GAS_SLOAD_COST sload
# Op.SStore: 0.i256 sstore
# Op.Jump: GAS_MID jump
# Op.JumpI: GAS_MID jumpI
# Op.PC: GAS_HIGH pc
# Op.MSize: GAS_BASE msize
# Op.Gas: GAS_BASE gasOp
# Op.JumpDest: GAS_JUMP_DEST jumpDest
# Op.Push: GAS_VERY_LOW push
# Op.Dup: GAS_VERY_LOW dup
# Op.Swap: GAS_VERY_LOW swap
# Op.Log0: GAS_LOG log0
# Op.Log1: 2 * GAS_LOG log1
# Op.Log2: 3 * GAS_LOG log2
# Op.Log3: 4 * GAS_LOG log3
# Op.Log4: 5 * GAS_LOG log4
# Op.Create: GAS_CREATE create
# Op.Call: 0.i256 callOp
# Op.CallCode: 0.i256 callCodeOp
# Op.Return: 0.i256 returnOp
# Op.DelegateCall: 0.i256 delegateCall
# Op.Invalid: 0.i256 invalidOp
# Op.SelfDestruct: GAS_SELF_DESTRUCT_COST selfDestruct
var mem = newMemory(pow(1024.int256, 2))
@ -90,7 +133,7 @@ var c = BaseComputation(
macro runOpcodes*(computation: untyped, program: untyped): untyped =
# runOpcodes(c):
# stack: @[Value..]
#
#
# Op
# Op
#
@ -125,5 +168,5 @@ runOpcodes(c):
Op.Div
Op.Sub
Op.Mul
Op.Mul
Op.Mul