diff --git a/src/constants.nim b/src/constants.nim index 87f9fb267..bec61ccd3 100644 --- a/src/constants.nim +++ b/src/constants.nim @@ -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 diff --git a/src/logic/context.nim b/src/logic/context.nim index d8f5fd2e4..cbbb30b5d 100644 --- a/src/logic/context.nim +++ b/src/logic/context.nim @@ -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) diff --git a/src/runner.nim b/src/runner.nim index 502ed0e6b..6bcbd17db 100644 --- a/src/runner.nim +++ b/src/runner.nim @@ -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