From cb49352b6a122d963da28739cf3a4ef75599ebd6 Mon Sep 17 00:00:00 2001 From: Mamy Ratsimbazafy Date: Fri, 25 May 2018 12:25:19 +0200 Subject: [PATCH] Gas & Memory ops refactoring - uses native integer instead of uint256 fixes #35 and #39 (#40) * Gas refactoring - uses int64 * Use primitive int in test_vm_json --- src/computation.nim | 27 ++++++++---------- src/constants.nim | 40 +++++++++++++------------- src/logic/arithmetic.nim | 2 +- src/logic/call.nim | 58 ++++++++++++++++++++------------------ src/logic/context.nim | 35 +++++++++++++---------- src/logic/flow.nim | 2 +- src/logic/logging_ops.nim | 17 +++++------ src/logic/memory_ops.nim | 15 +++++----- src/logic/sha3.nim | 7 +++-- src/logic/storage.nim | 2 +- src/logic/system_ops.nim | 19 +++++++------ src/types.nim | 53 ++++++++++++++++++++++++++++++++-- src/utils_numeric.nim | 10 +++---- src/vm/forks/gas_costs.nim | 50 ++++++++++++++++---------------- src/vm/gas_meter.nim | 25 ++++++++-------- src/vm/memory.nim | 28 +++++++++--------- src/vm/message.nim | 45 ++--------------------------- tests/test_gas_meter.nim | 16 +++++------ tests/test_memory.nim | 24 ++++++++-------- tests/test_opcode.nim | 24 ++++++++-------- tests/test_vm_json.nim | 8 +++--- 21 files changed, 263 insertions(+), 244 deletions(-) diff --git a/src/computation.nim b/src/computation.nim index 03c22dc6e..6fe60d6f6 100644 --- a/src/computation.nim +++ b/src/computation.nim @@ -6,7 +6,7 @@ # at your option. This file may not be copied, modified, or distributed except according to those terms. import - strformat, strutils, sequtils, tables, macros, stint, terminal, + strformat, strutils, sequtils, tables, macros, stint, terminal, math, constants, errors, utils/hexadecimal, utils_numeric, validation, vm_state, logging, opcode_values, types, vm / [code_stream, gas_meter, memory, message, stack], @@ -15,7 +15,7 @@ import vm/forks/f20150730_frontier/frontier_vm_state, vm/forks/f20161018_tangerine_whistle/tangerine_vm_state -proc memoryGasCost*(sizeInBytes: UInt256): UInt256 = +proc memoryGasCost*(sizeInBytes: Natural): GasInt = let sizeInWords = ceil32(sizeInBytes) div 32 linearCost = sizeInWords * GAS_MEMORY @@ -86,7 +86,7 @@ method shouldEraseReturnData*(c: BaseComputation): bool = method prepareChildMessage*( c: var BaseComputation, - gas: UInt256, + gas: GasInt, to: string, value: UInt256, data: seq[byte], @@ -105,13 +105,10 @@ method prepareChildMessage*( code, childOptions) -method extendMemory*(c: var BaseComputation, startPosition: UInt256, size: UInt256) = +method extendMemory*(c: var BaseComputation, startPosition: Natural, size: Natural) = # Memory Management - # - # validate_uint256(start_position, title="Memory start position") - # validate_uint256(size, title="Memory size") - let beforeSize = ceil32(len(c.memory).u256) + let beforeSize = ceil32(len(c.memory)) let afterSize = ceil32(startPosition + size) let beforeCost = memoryGasCost(beforeSize) @@ -201,21 +198,21 @@ method getLogEntries*(c: BaseComputation): seq[(string, seq[UInt256], string)] = else: result = @[] -method getGasRefund*(c: BaseComputation): UInt256 = +method getGasRefund*(c: BaseComputation): GasInt = if c.isError: - result = 0.u256 + result = 0 else: - result = c.gasMeter.gasRefunded + c.children.mapIt(it.getGasRefund()).foldl(a + b, 0.u256) + result = c.gasMeter.gasRefunded + c.children.mapIt(it.getGasRefund()).foldl(a + b, 0'i64) -method getGasUsed*(c: BaseComputation): UInt256 = +method getGasUsed*(c: BaseComputation): GasInt = if c.shouldBurnGas: result = c.msg.gas else: - result = max(0.u256, c.msg.gas - c.gasMeter.gasRemaining) + result = max(0, c.msg.gas - c.gasMeter.gasRemaining) -method getGasRemaining*(c: BaseComputation): UInt256 = +method getGasRemaining*(c: BaseComputation): GasInt = if c.shouldBurnGas: - result = 0.u256 + result = 0 else: result = c.gasMeter.gasRemaining diff --git a/src/constants.nim b/src/constants.nim index ca77c6677..851e6aef4 100644 --- a/src/constants.nim +++ b/src/constants.nim @@ -46,13 +46,13 @@ proc `==`*(a: UInt256, b: int): bool = proc `!=`*(a: UInt256, b: int): bool = a != b.u256 -proc `^`*(base: int; exp: int): UInt256 = - let base = base.u256 - var ex = exp - result = 1.u256 - while ex > 0: - result = result * base - dec(ex) +# proc `^`*(base: int; exp: int): UInt256 = +# let base = base.u256 +# var ex = exp +# result = 1.u256 +# while ex > 0: +# result = result * base +# dec(ex) proc `^`*(left: Int256, right: int): Int256 = var value = right.i256 @@ -123,7 +123,7 @@ let INT_256_MAX_AS_UINT256* = cast[Uint256](high(Int256)) NULLBYTE* = "\x00" EMPTYWORD* = repeat(NULLBYTE, 32) - UINT160CEILING*: UInt256 = 2 ^ 160 + UINT160CEILING*: UInt256 = 2.u256 ^ 160 CREATE_CONTRACT_ADDRESS* = "" ZERO_ADDRESS* = repeat("\x00", 20) ZERO_HASH32* = repeat("\x00", 20) @@ -147,34 +147,34 @@ let # GAS_SLOAD_COST* = 20.u256 # GAS_SELF_DESTRUCT_COST* = 0.u256 # GAS_IN_HANDLER* = 0.u256 # to be calculated in handler - REFUND_SCLEAR* = 15_000.u256 + REFUND_SCLEAR* = 15_000 # GAS_SELF_DESTRUCT* = 0.u256 # GAS_SELF_DESTRUCT_NEW_ACCOUNT* = 25_000.u256 GAS_CREATE* = 32_000.u256 # GAS_CALL* = 40.u256 - GAS_CALL_VALUE* = 9_000.u256 - GAS_CALL_STIPEND* = 2_300.u256 - GAS_NEW_ACCOUNT* = 25_000.u256 + GAS_CALL_VALUE* = 9_000 + GAS_CALL_STIPEND* = 2_300 + GAS_NEW_ACCOUNT* = 25_000 # GAS_COST_BALANCE* = 400.u256 # TODO: this is post-eip150, see also GAS_BALANCE # GAS_EXP* = 10.u256 # GAS_EXP_BYTE* = 10.u256 - GAS_MEMORY* = 3.u256 + GAS_MEMORY* = 3 GAS_TX_CREATE* = 32_000.u256 GAS_TX_DATA_ZERO* = 4.u256 GAS_TX_DATA_NON_ZERO* = 68.u256 GAS_TX* = 21_000.u256 GAS_LOG* = 375.u256 - GAS_LOG_DATA* = 8.u256 - GAS_LOG_TOPIC* = 375.u256 + GAS_LOG_DATA* = 8 + GAS_LOG_TOPIC* = 375 # GAS_SHA3* = 30.u256 - GAS_SHA3_WORD* = 6.u256 - GAS_COPY* = 3.u256 + GAS_SHA3_WORD* = 6 + GAS_COPY* = 3 GAS_BLOCK_HASH* = 20.u256 GAS_CODE_DEPOSIT* = 200.u256 - GAS_MEMORY_QUADRATIC_DENOMINATOR* = 512.u256 + GAS_MEMORY_QUADRATIC_DENOMINATOR* = 512 GAS_SHA256* = 60.u256 GAS_SHA256WORD* = 12.u256 GAS_RIP_EMD160* = 600.u256 @@ -188,7 +188,7 @@ let GAS_ECPAIRING_PER_POINT* = 80_000.u256 GAS_LIMIT_EMA_DENOMINATOR* = 1_024.u256 GAS_LIMIT_ADJUSTMENT_FACTOR* = 1_024.u256 - GAS_LIMIT_MAXIMUM*: UInt256 = 2 ^ 63 - 1.u256 + GAS_LIMIT_MAXIMUM* = high(int64) GAS_LIMIT_USAGE_ADJUSTMENT_NUMERATOR* = 3.u256 GAS_LIMIT_USAGE_ADJUSTMENT_DENOMINATOR* = 2.u256 @@ -206,7 +206,7 @@ let MAX_UNCLE_DEPTH* = 6.u256 MAX_UNCLES* = 2.u256 - SECPK1_P*: UInt256 = 2 ^ 256 - 2 ^ 32 - 977.u256 + SECPK1_P*: UInt256 = 2.u256 ^ 256 - 2.u256 ^ 32 - 977.u256 SECPK1_N*: UInt256 = "115792089237316195423570985008687907852837564279074904382605163141518161494337".u256 SECPK1_A* = 0.u256 SECPK1_B* = 7.u256 diff --git a/src/logic/arithmetic.nim b/src/logic/arithmetic.nim index 50fd42c2d..b33477ee1 100644 --- a/src/logic/arithmetic.nim +++ b/src/logic/arithmetic.nim @@ -92,7 +92,7 @@ proc exp*(computation: var BaseComputation) = var gasCost = computation.gasCosts[GasExp] if not exponent.isZero: - gasCost += gasCost * (one(Uint256) + log256(exponent)) + gasCost += gasCost * (1 + log256(exponent)) computation.gasMeter.consumeGas(gasCost, reason="EXP: exponent bytes") let res = if base.isZero: 0.u256 # 0^0 is 0 in py-evm diff --git a/src/logic/call.nim b/src/logic/call.nim index e1d22bcee..88cb4ea6b 100644 --- a/src/logic/call.nim +++ b/src/logic/call.nim @@ -39,13 +39,13 @@ type using computation: var BaseComputation -method msgExtraGas*(call: BaseCall, computation; gas: UInt256, to: string, value: UInt256): UInt256 {.base.} = +method msgExtraGas*(call: BaseCall, computation; gas: GasInt, to: string, value: UInt256): GasInt {.base.} = raise newException(NotImplementedError, "Must be implemented by subclasses") -method msgGas*(call: BaseCall, computation; gas: UInt256, to: string, value: UInt256): (UInt256, UInt256) {.base.} = +method msgGas*(call: BaseCall, computation; gas: GasInt, to: string, value: UInt256): (GasInt, GasInt) {.base.} = let extraGas = call.msgExtraGas(computation, gas, to, value) let totalFee = gas + extraGas - let childMsgGas = gas + (if value != 0: GAS_CALL_STIPEND else: 0.u256) + let childMsgGas = gas + (if value != 0: GAS_CALL_STIPEND else: 0) (childMsgGas, totalFee) method callParams*(call: BaseCall, computation): (UInt256, UInt256, string, string, string, UInt256, UInt256, UInt256, UInt256, bool, bool) {.base.} = @@ -60,11 +60,13 @@ method runLogic*(call: BaseCall, computation) = shouldTransferValue, isStatic) = call.callParams(computation) - computation.extendMemory(memoryInputStartPosition, memoryInputSize) - computation.extendMemory(memoryOutputStartPosition, memoryOutputSize) + let (memInPos, memInLen, memOutPos, memOutLen) = (memoryInputStartPosition.toInt, memoryInputSize.toInt, memoryOutputStartPosition.toInt, memoryOutputSize.toInt) - let callData = computation.memory.read(memoryInputStartPosition, memoryInputSize) - let (childMsgGas, childMsgGasFee) = call.msgGas(computation, gas, to, value) + computation.extendMemory(memInPos, memInLen) + computation.extendMemory(memOutPos, memOutLen) + + let callData = computation.memory.read(memInPos, memInLen) + let (childMsgGas, childMsgGasFee) = call.msgGas(computation, gas.toInt, to, value) computation.gasMeter.consumeGas(childMsgGasFee, reason = $call.kind) # TODO: Pre-call checks @@ -116,22 +118,22 @@ method runLogic*(call: BaseCall, computation) = else: computation.stack.push(1.u256) if not childComputation.shouldEraseReturnData: - let actualOutputSize = min(memoryOutputSize, childComputation.output.len.u256) + let actualOutputSize = min(memOutLen, childComputation.output.len) computation.memory.write( - memoryOutputStartPosition, + memOutPos, actualOutputSize, - childComputation.output.toBytes[0 ..< actualOutputSize.toInt]) + childComputation.output.toBytes[0 ..< actualOutputSize]) if not childComputation.shouldBurnGas: computation.gasMeter.returnGas(childComputation.gasMeter.gasRemaining) -method msgExtraGas(call: Call, computation; gas: UInt256, to: string, value: UInt256): UInt256 = +method msgExtraGas(call: Call, computation; gas: GasInt, to: string, value: UInt256): GasInt = # TODO: db # with computation.vm_state.state_db(read_only=True) as state_db: # let accountExists = db.accountExists(to) let accountExists = false - let transferGasFee = if value != 0: GAS_CALL_VALUE else: 0.u256 - let createGasFee = if not accountExists: GAS_NEW_ACCOUNT else: 0.u256 + let transferGasFee = if value != 0: GAS_CALL_VALUE else: 0 + let createGasFee = if not accountExists: GAS_NEW_ACCOUNT else: 0 transferGasFee + createGasFee method callParams(call: CallCode, computation): (UInt256, UInt256, string, string, string, UInt256, UInt256, UInt256, UInt256, bool, bool) = @@ -154,8 +156,8 @@ method callParams(call: CallCode, computation): (UInt256, UInt256, string, strin true, # should_transfer_value, computation.msg.isStatic) -method msgExtraGas(call: CallCode, computation; gas: UInt256, to: string, value: UInt256): UInt256 = - if value != 0: GAS_CALL_VALUE else: 0.u256 +method msgExtraGas(call: CallCode, computation; gas: GasInt, to: string, value: UInt256): GasInt = + if value != 0: GAS_CALL_VALUE else: 0 method callParams(call: Call, computation): (UInt256, UInt256, string, string, string, UInt256, UInt256, UInt256, UInt256, bool, bool) = let gas = computation.stack.popInt() @@ -180,11 +182,11 @@ method callParams(call: Call, computation): (UInt256, UInt256, string, string, s true, # should_transfer_value, computation.msg.isStatic) -method msgGas(call: DelegateCall, computation; gas: UInt256, to: string, value: UInt256): (UInt256, UInt256) = +method msgGas(call: DelegateCall, computation; gas: GasInt, to: string, value: UInt256): (GasInt, GasInt) = (gas, gas) -method msgExtraGas(call: DelegateCall, computation; gas: UInt256, to: string, value: UInt256): UInt256 = - 0.u256 +method msgExtraGas(call: DelegateCall, computation; gas: GasInt, to: string, value: UInt256): GasInt = + 0 method callParams(call: DelegateCall, computation): (UInt256, UInt256, string, string, string, UInt256, UInt256, UInt256, UInt256, bool, bool) = let gas = computation.stack.popInt() @@ -209,30 +211,30 @@ method callParams(call: DelegateCall, computation): (UInt256, UInt256, string, s false, # should_transfer_value, computation.msg.isStatic) -proc maxChildGasEIP150*(gas: UInt256): UInt256 = +proc maxChildGasEIP150*(gas: GasInt): GasInt = gas - gas div 64 -proc computeEIP150MsgGas(computation; gas: UInt256, extraGas: UInt256, value: UInt256, name: string, callStipend: UInt256): (UInt256, UInt256) = +proc computeEIP150MsgGas(computation; gas, extraGas: GasInt, value: UInt256, name: string, callStipend: GasInt): (GasInt, GasInt) = if computation.gasMeter.gasRemaining < extraGas: raise newException(OutOfGas, &"Out of gas: Needed {extraGas} - Remaining {computation.gasMeter.gasRemaining} - Reason: {name}") let gas = min(gas, maxChildGasEIP150(computation.gasMeter.gasRemaining - extraGas)) let totalFee = gas + extraGas - let childMsgGas = gas + (if value != 0: callStipend else: 0.u256) + let childMsgGas = gas + (if value != 0: callStipend else: 0) (childMsgGas, totalFee) -method msgGas(call: CallEIP150, computation; gas: UInt256, to: string, value: UInt256): (UInt256, UInt256) = +method msgGas(call: CallEIP150, computation; gas: GasInt, to: string, value: UInt256): (GasInt, GasInt) = let extraGas = call.msgExtraGas(computation, gas, to, value) computeEIP150MsgGas(computation, gas, extraGas, value, $call.kind, GAS_CALL_STIPEND) -method msgGas(call: CallCodeEIP150, computation; gas: UInt256, to: string, value: UInt256): (UInt256, UInt256) = +method msgGas(call: CallCodeEIP150, computation; gas: GasInt, to: string, value: UInt256): (GasInt, GasInt) = let extraGas = call.msgExtraGas(computation, gas, to, value) computeEIP150MsgGas(computation, gas, extraGas, value, $call.kind, GAS_CALL_STIPEND) -method msgGas(call: DelegateCallEIP150, computation; gas: UInt256, to: string, value: UInt256): (UInt256, UInt256) = +method msgGas(call: DelegateCallEIP150, computation; gas: GasInt, to: string, value: UInt256): (GasInt, GasInt) = let extraGas = call.msgExtraGas(computation, gas, to, value) - computeEIP150MsgGas(computation, gas, extraGas, value, $call.kind, 0.u256) + computeEIP150MsgGas(computation, gas, extraGas, value, $call.kind, 0) -proc msgExtraGas*(call: CallEIP161, computation; gas: UInt256, to: string, value: UInt256): UInt256 = +proc msgExtraGas*(call: CallEIP161, computation; gas: GasInt, to: string, value: UInt256): GasInt = # TODO: with # with computation.vm_state.state_db(read_only=True) as state_db: # account_is_dead = ( @@ -240,8 +242,8 @@ proc msgExtraGas*(call: CallEIP161, computation; gas: UInt256, to: string, value # state_db.account_is_empty(to)) let accountIsDead = true - let transferGasFee = if value != 0: GAS_CALL_VALUE else: 0.u256 - let createGasFee = if accountIsDead and value != 0: GAS_NEW_ACCOUNT else: 0.u256 + let transferGasFee = if value != 0: GAS_CALL_VALUE else: 0 + let createGasFee = if accountIsDead and value != 0: GAS_NEW_ACCOUNT else: 0 transferGasFee + createGasFee diff --git a/src/logic/context.nim b/src/logic/context.nim index 041e0b305..5c4e41d27 100644 --- a/src/logic/context.nim +++ b/src/logic/context.nim @@ -47,14 +47,15 @@ proc callDataCopy*(computation: var BaseComputation) = let (memStartPosition, calldataStartPosition, size) = computation.stack.popInt(3) - computation.extendMemory(memStartPosition, size) + let (memPos, callPos, len) = (memStartPosition.toInt, calldataStartPosition.toInt, size.toInt) + computation.extendMemory(memPos, len) - let wordCount = ceil32(size) div 32 + let wordCount = ceil32(len) div 32 let copyGasCost = wordCount * constants.GAS_COPY computation.gasMeter.consumeGas(copyGasCost, reason="CALLDATACOPY fee") - let value = computation.msg.data[calldataStartPosition.toInt ..< (calldataStartPosition + size).toInt] - let paddedValue = padRight(value, size.toInt, 0.byte) - computation.memory.write(memStartPosition, size, paddedValue) + let value = computation.msg.data[callPos ..< callPos + len] + let paddedValue = padRight(value, len, 0.byte) + computation.memory.write(memPos, len, paddedValue) proc codesize*(computation: var BaseComputation) = @@ -66,8 +67,10 @@ proc codecopy*(computation: var BaseComputation) = let (memStartPosition, codeStartPosition, size) = computation.stack.popInt(3) - computation.extendMemory(memStartPosition, size) - let wordCount = ceil32(size) div 32 + let (memPos, codePos, len) = (memStartPosition.toInt, codeStartPosition.toInt, size.toInt) + computation.extendMemory(memPos, len) + + let wordCount = ceil32(len) div 32 let copyGasCost = constants.GAS_COPY * wordCount computation.gasMeter.consumeGas(copyGasCost, reason="CODECOPY: word gas cost") @@ -79,7 +82,7 @@ proc codecopy*(computation: var BaseComputation) = proc gasprice*(computation: var BaseComputation) = - computation.stack.push(computation.msg.gasPrice) + computation.stack.push(computation.msg.gasPrice.u256) proc extCodeSize*(computation: var BaseComputation) = @@ -93,8 +96,9 @@ proc extCodeSize*(computation: var BaseComputation) = 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 (memPos, codePos, len) = (memStartPosition.toInt, codeStartPosition.toInt, size.toInt) + computation.extendMemory(memPos, len) + let wordCount = ceil32(len) div 32 let copyGasCost = constants.GAS_COPY * wordCount computation.gasMeter.consumeGas(copyGasCost, reason="EXTCODECOPY: word gas cost") @@ -112,15 +116,16 @@ proc returnDataSize*(computation: var BaseComputation) = proc returnDataCopy*(computation: var BaseComputation) = let (memStartPosition, returnDataStartPosition, size) = computation.stack.popInt(3) - if returnDataStartPosition + size > computation.returnData.len: + let (memPos, returnPos, len) = (memStartPosition.toInt, returnDataStartPosition.toInt, size.toInt) + if returnPos + len > 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 + computation.extendMemory(memPos, len) + let wordCount = ceil32(len) div 32 let copyGasCost = wordCount * constants.GAS_COPY computation.gasMeter.consumeGas(copyGasCost, reason="RETURNDATACOPY fee") - let value = ($computation.returnData)[returnDataStartPosition.toInt ..< (returnDataStartPosition + size).toInt] - computation.memory.write(memStartPosition, size, value) + let value = ($computation.returnData)[returnPos ..< returnPos + len] + computation.memory.write(memPos, len, value) diff --git a/src/logic/flow.nim b/src/logic/flow.nim index 8380d3289..c9601ba35 100644 --- a/src/logic/flow.nim +++ b/src/logic/flow.nim @@ -55,4 +55,4 @@ proc pc*(computation) = proc gas*(computation) = let gasRemaining = gasMeter.gasRemaining - stack.push(gasRemaining) + stack.push(gasRemaining.u256) diff --git a/src/logic/logging_ops.nim b/src/logic/logging_ops.nim index c2074ac74..37f75266e 100644 --- a/src/logic/logging_ops.nim +++ b/src/logic/logging_ops.nim @@ -17,18 +17,19 @@ using macro logXX(topicCount: static[int]): untyped = if topicCount < 0 or topicCount > 4: - error(&"Invalid log topic size {topicCount} Must be 0, 1, 2, 3, or 4") + error(&"Invalid log topic len {topicCount} Must be 0, 1, 2, 3, or 4") return let name = ident(&"log{topicCount}") let computation = ident("computation") let topics = ident("topics") let topicsTuple = ident("topicsTuple") - let size = ident("size") - let memStartPosition = ident("memStartPosition") + let len = ident("len") + let memPos = ident("memPos") result = quote: proc `name`*(`computation`: var BaseComputation) = - let (`memStartPosition`, `size`) = `computation`.stack.popInt(2) + let (memStartPosition, size) = `computation`.stack.popInt(2) + let (`memPos`, `len`) = (memStartPosition.toInt, size.toInt) var `topics`: seq[UInt256] var topicCode: NimNode @@ -50,12 +51,12 @@ macro logXX(topicCount: static[int]): untyped = result.body.add(topicCode) let logicCode = quote: - let dataGasCost = constants.GAS_LOG_DATA * `size` - let topicGasCost = constants.GAS_LOG_TOPIC * `topicCount`.u256 + let dataGasCost = constants.GAS_LOG_DATA * `len` + let topicGasCost = constants.GAS_LOG_TOPIC * `topicCount` let totalGasCost = dataGasCost + topicGasCost `computation`.gasMeter.consumeGas(totalGasCost, reason="Log topic and data gas cost") - `computation`.extendMemory(`memStartPosition`, `size`) - let logData = `computation`.memory.read(`memStartPosition`, `size`).toString + `computation`.extendMemory(`memPos`, `len`) + let logData = `computation`.memory.read(`memPos`, `len`).toString `computation`.addLogEntry( account=`computation`.msg.storageAddress, topics=`topics`, diff --git a/src/logic/memory_ops.nim b/src/logic/memory_ops.nim index 6719accad..eaf36239d 100644 --- a/src/logic/memory_ops.nim +++ b/src/logic/memory_ops.nim @@ -6,7 +6,8 @@ # at your option. This file may not be copied, modified, or distributed except according to those terms. import - ../constants, ../computation, ../types, .. / vm / [stack, memory], .. / utils / [padding, bytes] + ../constants, ../computation, ../types, .. / vm / [stack, memory], .. / utils / [padding, bytes], + stint {.this: computation.} @@ -16,14 +17,14 @@ using computation: var BaseComputation proc mstoreX(computation; x: int) = - let start = stack.popInt() + let start = stack.popInt().toInt let value = stack.popBinary() let paddedValue = padLeft(value, x, 0.byte) let normalizedValue = paddedValue[^x .. ^1] - extendMemory(start, x.u256) - memory.write(start, 32.u256, normalizedValue) + extendMemory(start, x) + memory.write(start, 32, normalizedValue) # TODO template handler @@ -34,11 +35,11 @@ proc mstore8*(computation) = mstoreX(1) proc mload*(computation) = - let start = stack.popInt() + let start = stack.popInt().toInt - extendMemory(start, 32.u256) + extendMemory(start, 32) - let value = memory.read(start, 32.u256) + let value = memory.read(start, 32) stack.push(value) proc msize*(computation) = diff --git a/src/logic/sha3.nim b/src/logic/sha3.nim index 37754b414..b284652eb 100644 --- a/src/logic/sha3.nim +++ b/src/logic/sha3.nim @@ -10,9 +10,10 @@ import proc sha3op*(computation: var BaseComputation) = let (startPosition, size) = computation.stack.popInt(2) - computation.extendMemory(startPosition, size) - let sha3Bytes = computation.memory.read(startPosition, size) - let wordCount = sha3Bytes.len.u256.ceil32 div 32 + let (pos, len) = (startPosition.toInt, size.toInt) + computation.extendMemory(pos, len) + let sha3Bytes = computation.memory.read(pos, len) + let wordCount = sha3Bytes.len.ceil32 div 32 # TODO, can't we just shr instead of rounding + div let gasCost = constants.GAS_SHA3_WORD * wordCount computation.gasMeter.consumeGas(gasCost, reason="SHA3: word gas cost") var res = keccak("") diff --git a/src/logic/storage.nim b/src/logic/storage.nim index 16ec21a7f..fef369301 100644 --- a/src/logic/storage.nim +++ b/src/logic/storage.nim @@ -29,7 +29,7 @@ proc sstore*(computation) = let isCurrentlyEmpty = not existing # currentValue == 0 let isGoingToBeEmpty = value == 0 - let gasRefund = if isCurrentlyEmpty or not isGoingToBeEmpty: 0.u256 else: REFUND_SCLEAR + let gasRefund = if isCurrentlyEmpty or not isGoingToBeEmpty: 0 else: REFUND_SCLEAR let gasCost = if isCurrentlyEmpty and not isGoingToBeEmpty: GAS_SSET else: GAS_SRESET computation.gasMeter.consumeGas(computation.gasCosts[gasCost], &"SSTORE: {computation.msg.storageAddress}[slot] -> {value} ({currentValue})") diff --git a/src/logic/system_ops.nim b/src/logic/system_ops.nim index 80a8aaf5f..e9c627690 100644 --- a/src/logic/system_ops.nim +++ b/src/logic/system_ops.nim @@ -24,13 +24,14 @@ type CreateByzantium* = ref object of CreateEIP150 # TODO: Refactoring - put that in VM forks -method maxChildGasModifier(create: Create, gas: UInt256): UInt256 {.base.} = +method maxChildGasModifier(create: Create, gas: GasInt): GasInt {.base.} = gas method runLogic*(create: Create, computation) = computation.gasMeter.consumeGas(computation.gasCosts[create.gasCost(computation)], reason = $create.kind) # TODO: Refactoring create gas costs let (value, startPosition, size) = computation.stack.popInt(3) - computation.extendMemory(startPosition, size) + let (pos, len) = (startPosition.toInt, size.toInt) + computation.extendMemory(pos, len) # TODO: with # with computation.vm_state.state_db(read_only=True) as state_db: @@ -42,7 +43,7 @@ method runLogic*(create: Create, computation) = # computation.stack.push(0) # return - let callData = computation.memory.read(startPosition, size) + let callData = computation.memory.read(pos, len) let createMsgGas = create.maxChildGasModifier(computation.gasMeter.gasRemaining) computation.gasMeter.consumeGas(createMsgGas, reason="CREATE") @@ -82,7 +83,7 @@ method runLogic*(create: Create, computation) = computation.stack.push(contractAddress) computation.gasMeter.returnGas(childComputation.gasMeter.gasRemaining) -method maxChildGasModifier(create: CreateEIP150, gas: UInt256): UInt256 = +method maxChildGasModifier(create: CreateEIP150, gas: GasInt): GasInt = maxChildGasEIP150(gas) method runLogic*(create: CreateByzantium, computation) = @@ -142,15 +143,17 @@ proc selfdestruct(computation; beneficiary: string) = proc returnOp*(computation) = let (startPosition, size) = stack.popInt(2) - computation.extendMemory(startPosition, size) - let output = memory.read(startPosition, size) + let (pos, len) = (startPosition.toInt, size.toInt) + computation.extendMemory(pos, len) + let output = memory.read(pos, len) computation.output = output.toString raise newException(Halt, "RETURN") proc revert*(computation) = let (startPosition, size) = stack.popInt(2) - computation.extendMemory(startPosition, size) - let output = memory.read(startPosition, size).toString + let (pos, len) = (startPosition.toInt, size.toInt) + computation.extendMemory(pos, len) + let output = memory.read(pos, len).toString computation.output = output raise newException(Revert, $output) diff --git a/src/types.nim b/src/types.nim index 04856d03b..146b29960 100644 --- a/src/types.nim +++ b/src/types.nim @@ -9,7 +9,8 @@ import tables, constants, vm_state, opcode_values, stint, - vm / [code_stream, gas_meter, memory, message, stack] + vm / [code_stream, memory, stack], + ./logging type BaseComputation* = ref object of RootObj @@ -49,6 +50,16 @@ type gasCostKind*: GasCostKind runLogic*: proc(computation: var BaseComputation) + GasInt* = int64 + ## Type alias used for gas computation + # For reference - https://github.com/status-im/nimbus/issues/35#issuecomment-391726518 + + GasMeter* = ref object + logger*: Logger + gasRefunded*: GasInt + startGas*: GasInt + gasRemaining*: GasInt + GasCostKind* = enum GasZero GasBase @@ -71,4 +82,42 @@ type GasExp GasSHA3 - GasCosts* = array[GasCostKind, UInt256] + GasCosts* = array[GasCostKind, GasInt] + + Message* = ref object + # A message for VM computation + + # depth = None + + # code = None + # codeAddress = None + + # createAddress = None + + # shouldTransferValue = None + # isStatic = None + + # logger = logging.getLogger("evm.vm.message.Message") + + gas*: GasInt + gasPrice*: GasInt + to*: string + sender*: string + value*: UInt256 + data*: seq[byte] + code*: string + internalOrigin*: string + internalCodeAddress*: string + depth*: int + internalStorageAddress*: string + shouldTransferValue*: bool + isStatic*: bool + isCreate*: bool + + MessageOptions* = ref object + origin*: string + depth*: int + createAddress*: string + codeAddress*: string + shouldTransferValue*: bool + isStatic*: bool diff --git a/src/utils_numeric.nim b/src/utils_numeric.nim index e8aca07e9..c22f59772 100644 --- a/src/utils_numeric.nim +++ b/src/utils_numeric.nim @@ -36,8 +36,8 @@ proc bigEndianToInt*(value: Bytes): UInt256 = # proc bitLength*(value: UInt256): int = # 255 - value.countLeadingZeroBits -proc log256*(value: UInt256): UInt256 = - ((255 - value.countLeadingZeroBits) div 8).u256 +proc log256*(value: UInt256): Natural = + (255 - value.countLeadingZeroBits) div 8 # Compilers optimize to `shr 3` # proc ceil8*(value: int): int = # let remainder = value mod 8 @@ -68,12 +68,12 @@ proc pseudoSignedToUnsigned*(value: UInt256): UInt256 = macro ceilXX(ceiling: static[int]): untyped = var name = ident(&"ceil{ceiling}") result = quote: - proc `name`*(value: UInt256): UInt256 = - var remainder = value mod `ceiling`.u256 + proc `name`*(value: Natural): Natural = + var remainder = value mod `ceiling` if remainder == 0: return value else: - return value + `ceiling`.u256 - remainder + return value + `ceiling` - remainder ceilXX(32) diff --git a/src/vm/forks/gas_costs.nim b/src/vm/forks/gas_costs.nim index 53fe7e883..50186befc 100644 --- a/src/vm/forks/gas_costs.nim +++ b/src/vm/forks/gas_costs.nim @@ -10,36 +10,36 @@ import # TODO: Make that computation at compile-time. # Go-Ethereum uses pure uint64 for gas computation -let BaseGasCosts*: GasCosts = [ - GasZero: 0.u256, - GasBase: 2.u256, - GasVeryLow: 3.u256, - GasLow: 5.u256, - GasMid: 8.u256, - GasHigh: 10.u256, - GasSload: 50.u256, # Changed to 200 in Tangerine (EIP150) - GasJumpDest: 1.u256, - GasSset: 20_000.u256, - GasSreset: 5_000.u256, - GasExtCode: 20.u256, - GasCoinbase: 20.u256, - GasSelfDestruct: 0.u256, # Changed to 5000 in Tangerine (EIP150) - GasInHandler: 0.u256, # to be calculated in handler - GasRefundSclear: 15000.u256, +const BaseGasCosts*: GasCosts = [ + GasZero: 0'i64, + GasBase: 2, + GasVeryLow: 3, + GasLow: 5, + GasMid: 8, + GasHigh: 10, + GasSload: 50, # Changed to 200 in Tangerine (EIP150) + GasJumpDest: 1, + GasSset: 20_000, + GasSreset: 5_000, + GasExtCode: 20, + GasCoinbase: 20, + GasSelfDestruct: 0, # Changed to 5000 in Tangerine (EIP150) + GasInHandler: 0, # to be calculated in handler + GasRefundSclear: 15000, - GasBalance: 20.u256, # Changed to 400 in Tangerine (EIP150) - GasCall: 40.u256, # Changed to 700 in Tangerine (EIP150) - GasExp: 10.u256, - GasSHA3: 30.u256 + GasBalance: 20, # Changed to 400 in Tangerine (EIP150) + GasCall: 40, # Changed to 700 in Tangerine (EIP150) + GasExp: 10, + GasSHA3: 30 ] proc tangerineGasCosts(baseCosts: GasCosts): GasCosts = # https://github.com/ethereum/EIPs/blob/master/EIPS/eip-150.md result = baseCosts - result[GasSload] = 200.u256 - result[GasSelfDestruct] = 5000.u256 - result[GasBalance] = 400.u256 - result[GasCall] = 40.u256 + result[GasSload] = 200 + result[GasSelfDestruct] = 5000 + result[GasBalance] = 400 + result[GasCall] = 40 -let TangerineGasCosts* = BaseGasCosts.tangerineGasCosts +const TangerineGasCosts* = BaseGasCosts.tangerineGasCosts diff --git a/src/vm/gas_meter.nim b/src/vm/gas_meter.nim index b920ac32c..528a1cf97 100644 --- a/src/vm/gas_meter.nim +++ b/src/vm/gas_meter.nim @@ -7,25 +7,20 @@ import strformat, - ../logging, ../errors, ../constants, stint + ../logging, ../errors, ../types -type - GasMeter* = ref object - logger*: Logger - gasRefunded*: UInt256 - startGas*: UInt256 - gasRemaining*: UInt256 - -proc newGasMeter*(startGas: UInt256): GasMeter = +proc newGasMeter*(startGas: GasInt): GasMeter = new(result) result.startGas = startGas result.gasRemaining = result.startGas - result.gasRefunded = 0.u256 + result.gasRefunded = 0 result.logger = logging.getLogger("gas") -proc consumeGas*(gasMeter: var GasMeter; amount: UInt256; reason: string) = +proc consumeGas*(gasMeter: var GasMeter; amount: GasInt; reason: string) = #if amount < 0.u256: # raise newException(ValidationError, "Gas consumption amount must be positive") + # Alternatively: use a range type `range[0'i64 .. high(int64)]` + # https://github.com/status-im/nimbus/issues/35#issuecomment-391726518 if amount > gasMeter.gasRemaining: raise newException(OutOfGas, &"Out of gas: Needed {amount} - Remaining {gasMeter.gasRemaining} - Reason: {reason}") @@ -33,16 +28,20 @@ proc consumeGas*(gasMeter: var GasMeter; amount: UInt256; reason: string) = gasMeter.logger.trace( &"GAS CONSUMPTION: {gasMeter.gasRemaining + amount} - {amount} -> {gasMeter.gasRemaining} ({reason})") -proc returnGas*(gasMeter: var GasMeter; amount: UInt256) = +proc returnGas*(gasMeter: var GasMeter; amount: GasInt) = #if amount < 0.int256: # raise newException(ValidationError, "Gas return amount must be positive") + # Alternatively: use a range type `range[0'i64 .. high(int64)]` + # https://github.com/status-im/nimbus/issues/35#issuecomment-391726518 gasMeter.gasRemaining += amount gasMeter.logger.trace( &"GAS RETURNED: {gasMeter.gasRemaining - amount} + {amount} -> {gasMeter.gasRemaining}") -proc refundGas*(gasMeter: var GasMeter; amount: UInt256) = +proc refundGas*(gasMeter: var GasMeter; amount: GasInt) = #if amount < 0.int256: # raise newException(ValidationError, "Gas refund amount must be positive") + # Alternatively: use a range type `range[0'i64 .. high(int64)]` + # https://github.com/status-im/nimbus/issues/35#issuecomment-391726518 gasMeter.gasRefunded += amount gasMeter.logger.trace( &"GAS REFUND: {gasMeter.gasRemaining - amount} + {amount} -> {gasMeter.gasRefunded}") diff --git a/src/vm/memory.nim b/src/vm/memory.nim index 970a57acf..2b8e67d0e 100644 --- a/src/vm/memory.nim +++ b/src/vm/memory.nim @@ -24,39 +24,39 @@ proc len*(memory: Memory): int = # TODO: why is the size passed as a UInt256? -proc extend*(memory: var Memory; startPosition: UInt256; size: UInt256) = +proc extend*(memory: var Memory; startPosition: Natural; size: Natural) = if size == 0: return var newSize = ceil32(startPosition + size) - if newSize <= len(memory).u256: + if newSize <= len(memory): return - var sizeToExtend = newSize - len(memory).u256 - memory.bytes = memory.bytes.concat(repeat(0.byte, sizeToExtend.toInt)) + var sizeToExtend = newSize - len(memory) + memory.bytes = memory.bytes.concat(repeat(0.byte, sizeToExtend)) -proc newMemory*(size: UInt256): Memory = +proc newMemory*(size: Natural): Memory = result = newMemory() - result.extend(0.u256, size) + result.extend(0, size) # TODO: why is the size passed as a UInt256? -proc read*(memory: var Memory, startPosition: UInt256, size: UInt256): seq[byte] = - result = memory.bytes[startPosition.toInt ..< (startPosition + size).toInt] +proc read*(memory: var Memory, startPosition: Natural, size: Natural): seq[byte] = + result = memory.bytes[startPosition ..< (startPosition + size)] # TODO: why is the size passed as a UInt256? -proc write*(memory: var Memory, startPosition: UInt256, size: UInt256, value: seq[byte]) = +proc write*(memory: var Memory, startPosition: Natural, size: Natural, value: seq[byte]) = if size == 0: return #echo size #echo startPosition #validateGte(startPosition, 0) #validateGte(size, 0) - validateLength(value, size.toInt) + validateLength(value, size) validateLte(startPosition + size, memory.len) let index = memory.len - if memory.len.u256 < startPosition + size: - memory.bytes = memory.bytes.concat(repeat(0.byte, memory.len - (startPosition + size).toInt)) # TODO: better logarithmic scaling? + if memory.len < startPosition + size: + memory.bytes = memory.bytes.concat(repeat(0.byte, memory.len - (startPosition + size))) # TODO: better logarithmic scaling? for z, b in value: - memory.bytes[z + startPosition.toInt] = b + memory.bytes[z + startPosition] = b -template write*(memory: var Memory, startPosition: UInt256, size: UInt256, value: cstring) = +template write*(memory: var Memory, startPosition: Natural, size: Natural, value: cstring) = memory.write(startPosition, size, value.toBytes) diff --git a/src/vm/message.nim b/src/vm/message.nim index 0a69b9fab..ed5b7e7e2 100644 --- a/src/vm/message.nim +++ b/src/vm/message.nim @@ -6,46 +6,7 @@ # at your option. This file may not be copied, modified, or distributed except according to those terms. import - ../logging, ../constants, ../validation, stint - -type - Message* = ref object - # A message for VM computation - - # depth = None - - # code = None - # codeAddress = None - - # createAddress = None - - # shouldTransferValue = None - # isStatic = None - - # logger = logging.getLogger("evm.vm.message.Message") - - gas*: UInt256 - gasPrice*: UInt256 - to*: string - sender*: string - value*: UInt256 - data*: seq[byte] - code*: string - internalOrigin: string - internalCodeAddress: string - depth*: int - internalStorageAddress: string - shouldTransferValue*: bool - isStatic*: bool - isCreate*: bool - - MessageOptions* = ref object - origin*: string - depth*: int - createAddress*: string - codeAddress*: string - shouldTransferValue*: bool - isStatic*: bool + ../logging, ../constants, ../validation, stint, ../types proc `origin=`*(message: var Message, value: string) = message.internalOrigin = value @@ -73,8 +34,8 @@ proc newMessageOptions*( isStatic: isStatic) proc newMessage*( - gas: UInt256, - gasPrice: UInt256, + gas: GasInt, + gasPrice: GasInt, to: string, sender: string, value: UInt256, diff --git a/tests/test_gas_meter.nim b/tests/test_gas_meter.nim index fe20e12be..deb1eea63 100644 --- a/tests/test_gas_meter.nim +++ b/tests/test_gas_meter.nim @@ -7,7 +7,7 @@ import unittest, macros, strformat, strutils, sequtils, stint, - ../src/[constants, opcode_values, errors, logging, vm/gas_meter] + ../src/[constants, opcode_values, errors, logging, types, vm/gas_meter] # TODO: quicktest # PS: parametrize can be easily immitated, but still quicktests would be even more useful @@ -15,7 +15,7 @@ import unittest, macros, strformat, strutils, sequtils, disableLogging() proc gasMeters: seq[GasMeter] = - @[newGasMeter(10.u256), newGasMeter(100.u256), newGasMeter(999.u256)] + @[newGasMeter(10), newGasMeter(100), newGasMeter(999)] macro all(element: untyped, handler: untyped): untyped = let name = ident(&"{element.repr}s") @@ -84,15 +84,15 @@ suite "gasMeter": all(gasMeter): check(gasMeter.gasRemaining == gasMeter.startGas) expect(OutOfGas): - gasMeter.consumeGas(gasMeter.startGas + 1.u256, "") + gasMeter.consumeGas(gasMeter.startGas + 1, "") test "return refund works correctly": all(gasMeter): check(gasMeter.gasRemaining == gasMeter.startGas) check(gasMeter.gasRefunded == 0) - gasMeter.consumeGas(5.u256, "") - check(gasMeter.gasRemaining == gasMeter.startGas - 5.u256) - gasMeter.returnGas(5.u256) + gasMeter.consumeGas(5, "") + check(gasMeter.gasRemaining == gasMeter.startGas - 5) + gasMeter.returnGas(5) check(gasMeter.gasRemaining == gasMeter.startGas) - gasMeter.refundGas(5.u256) - check(gasMeter.gasRefunded == 5.u256) + gasMeter.refundGas(5) + check(gasMeter.gasRefunded == 5) diff --git a/tests/test_memory.nim b/tests/test_memory.nim index 8e4ea1605..125393500 100644 --- a/tests/test_memory.nim +++ b/tests/test_memory.nim @@ -11,17 +11,17 @@ import unittest, macros, strformat, strutils, sequtils, proc memory32: Memory = result = newMemory() - result.extend(0.u256, 32.u256) + result.extend(0, 32) proc memory128: Memory = result = newMemory() - result.extend(0.u256, 128.u256) + result.extend(0, 128) suite "memory": test "write": var mem = memory32() # Test that write creates 32byte string == value padded with zeros - mem.write(startPosition = 0.u256, size = 4.u256, value = @[1.byte, 0.byte, 1.byte, 0.byte]) + mem.write(startPosition = 0, size = 4, value = @[1.byte, 0.byte, 1.byte, 0.byte]) check(mem.bytes == @[1.byte, 0.byte, 1.byte, 0.byte].concat(repeat(0.byte, 28))) # test "write rejects invalid position": @@ -47,28 +47,28 @@ suite "memory": test "write rejects invalid value": expect(ValidationError): var mem = memory32() - mem.write(startPosition = 0.u256, size = 4.u256, value = @[1.byte, 0.byte]) + mem.write(startPosition = 0, size = 4, value = @[1.byte, 0.byte]) test "write rejects valyes beyond memory size": expect(ValidationError): var mem = memory128() - mem.write(startPosition = 128.u256, size = 4.u256, value = @[1.byte, 0.byte, 1.byte, 0.byte]) + mem.write(startPosition = 128, size = 4, value = @[1.byte, 0.byte, 1.byte, 0.byte]) test "extends appropriately extends memory": var mem = newMemory() # Test extends to 32 byte array: 0 < (start_position + size) <= 32 - mem.extend(startPosition = 0.u256, size = 10.u256) + mem.extend(startPosition = 0, size = 10) check(mem.bytes == repeat(0.byte, 32)) # Test will extend past length if params require: 32 < (start_position + size) <= 64 - mem.extend(startPosition = 28.u256, size = 32.u256) + mem.extend(startPosition = 28, size = 32) check(mem.bytes == repeat(0.byte, 64)) # Test won't extend past length unless params require: 32 < (start_position + size) <= 64 - mem.extend(startPosition = 48.u256, size = 10.u256) + mem.extend(startPosition = 48, size = 10) check(mem.bytes == repeat(0.byte, 64)) test "read returns correct bytes": var mem = memory32() - mem.write(startPosition = 5.u256, size = 4.u256, value = @[1.byte, 0.byte, 1.byte, 0.byte]) - check(mem.read(startPosition = 5.u256, size = 4.u256) == @[1.byte, 0.byte, 1.byte, 0.byte]) - check(mem.read(startPosition = 6.u256, size = 4.u256) == @[0.byte, 1.byte, 0.byte, 0.byte]) - check(mem.read(startPosition = 1.u256, size = 3.u256) == @[0.byte, 0.byte, 0.byte]) + mem.write(startPosition = 5, size = 4, value = @[1.byte, 0.byte, 1.byte, 0.byte]) + check(mem.read(startPosition = 5, size = 4) == @[1.byte, 0.byte, 1.byte, 0.byte]) + check(mem.read(startPosition = 6, size = 4) == @[0.byte, 1.byte, 0.byte, 0.byte]) + check(mem.read(startPosition = 1, size = 3) == @[0.byte, 0.byte, 0.byte]) diff --git a/tests/test_opcode.nim b/tests/test_opcode.nim index 0d24fb6b0..9ac298178 100644 --- a/tests/test_opcode.nim +++ b/tests/test_opcode.nim @@ -16,7 +16,7 @@ import test_helpers -proc testCode(code: string, initialGas: UInt256, blockNum: UInt256): BaseComputation = +proc testCode(code: string, initialGas: GasInt, blockNum: UInt256): BaseComputation = let header = BlockHeader(blockNumber: blockNum) var vm = newNimbusVM(header, newBaseChainDB(newMemoryDB())) # coinbase: "", @@ -32,7 +32,7 @@ proc testCode(code: string, initialGas: UInt256, blockNum: UInt256): BaseComputa data = @[], code=code, gas=initial_gas, - gasPrice=1.u256) # What is this used for? + gasPrice=1) # What is this used for? # gasPrice=fixture{"exec"}{"gasPrice"}.getHexadecimalInt.u256, #options=newMessageOptions(origin=fixture{"exec"}{"origin"}.getStr)) @@ -53,10 +53,10 @@ suite "opcodes": test "add": var c = testCode( "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01", - 100_000.u256, + 100_000, 0.u256 ) - check(c.gasMeter.gasRemaining == 99_991.u256) + check(c.gasMeter.gasRemaining == 99_991) check(c.stack.peek == "115792089237316195423570985008687907853269984665640564039457584007913129639934".u256) # let address = Address::from_str("0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6").unwrap(); # let code = "7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff01600055".from_hex().unwrap(); @@ -80,33 +80,33 @@ suite "opcodes": block: # Using Balance (0x31) var c = testCode( "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff31", - 100_000.u256, + 100_000, 0.u256 ) - check: c.gasMeter.gasRemaining == 100000.u256 - 3.u256 - 20.u256 # Starting gas - push32 (verylow) - balance + check: c.gasMeter.gasRemaining == 100000 - 3 - 20 # Starting gas - push32 (verylow) - balance block: # Using SLOAD (0x54) var c = testCode( "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff54", - 100_000.u256, + 100_000, 0.u256 ) - check: c.gasMeter.gasRemaining == 100000.u256 - 3.u256 - 50.u256 # Starting gas - push32 (verylow) - SLOAD + check: c.gasMeter.gasRemaining == 100000 - 3 - 50 # Starting gas - push32 (verylow) - SLOAD test "Tangerine VM computation - post-EIP150 gas cost properly applied": block: # Using Balance (0x31) var c = testCode( "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff31", - 100_000.u256, + 100_000, 2_463_000.u256 # Tangerine block ) - check: c.gasMeter.gasRemaining == 100000.u256 - 3.u256 - 400.u256 # Starting gas - push32 (verylow) - balance + check: c.gasMeter.gasRemaining == 100000 - 3 - 400 # Starting gas - push32 (verylow) - balance block: # Using SLOAD (0x54) var c = testCode( "0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff54", - 100_000.u256, + 100_000, 2_463_000.u256 ) - check: c.gasMeter.gasRemaining == 100000.u256 - 3.u256 - 200.u256 # Starting gas - push32 (verylow) - SLOAD + check: c.gasMeter.gasRemaining == 100000 - 3 - 200 # Starting gas - push32 (verylow) - SLOAD diff --git a/tests/test_vm_json.nim b/tests/test_vm_json.nim index b655a7498..40291e100 100644 --- a/tests/test_vm_json.nim +++ b/tests/test_vm_json.nim @@ -45,8 +45,8 @@ proc testFixture(fixtures: JsonNode, testStatusIMPL: var TestStatus) = value=fixture{"exec"}{"value"}.getHexadecimalInt.u256, data=fixture{"exec"}{"data"}.getStr.mapIt(it.byte), code=code, - gas=fixture{"exec"}{"gas"}.getHexadecimalInt.u256, - gasPrice=fixture{"exec"}{"gasPrice"}.getHexadecimalInt.u256, + gas=fixture{"exec"}{"gas"}.getHexadecimalInt, + gasPrice=fixture{"exec"}{"gasPrice"}.getHexadecimalInt, options=newMessageOptions(origin=fixture{"exec"}{"origin"}.getStr)) #echo fixture{"exec"} @@ -81,7 +81,7 @@ proc testFixture(fixtures: JsonNode, testStatusIMPL: var TestStatus) = check(computation.output == expectedOutput) let gasMeter = computation.gasMeter - let expectedGasRemaining = fixture{"gas"}.getHexadecimalInt.u256 + let expectedGasRemaining = fixture{"gas"}.getHexadecimalInt let actualGasRemaining = gasMeter.gasRemaining checkpoint(&"{actualGasRemaining} {expectedGasRemaining}") check(actualGasRemaining == expectedGasRemaining or @@ -100,7 +100,7 @@ proc testFixture(fixtures: JsonNode, testStatusIMPL: var TestStatus) = var (childComputation, createdCall) = child let toAddress = createdCall{"destination"}.getStr let data = createdCall{"data"}.getStr.mapIt(it.byte) - let gasLimit = createdCall{"gasLimit"}.getHexadecimalInt.u256 + let gasLimit = createdCall{"gasLimit"}.getHexadecimalInt let value = createdCall{"value"}.getHexadecimalInt.u256 check(childComputation.msg.to == toAddress)