From 9c056b85dedd1df693cf4027125bfc825c6aac18 Mon Sep 17 00:00:00 2001 From: Alexander Ivanov Date: Wed, 14 Feb 2018 18:38:01 +0200 Subject: [PATCH] Pass first fixtures tests Todo Pass most VM opcode tests that we can (of those that don't depend too much on porting the whole py-evm) Simplify a bit the current py-evm-inspired internal loop arch --- src/computation.nim | 10 +- src/db/db_chain.nim | 4 + src/errors.nim | 22 +++- src/logic/storage.nim | 8 +- src/opcode_table.nim | 111 ++++++++++++++++++++ src/runner.nim | 110 +------------------ src/utils/header.nim | 8 +- src/vm/code_stream.nim | 12 ++- src/vm/forks/frontier/frontier_vm_state.nim | 9 +- src/vm/forks/frontier/vm.nim | 1 + src/vm_state.nim | 8 ++ tests/{helpers.nim => test_helpers.nim} | 18 +++- tests/vm_json_test.nim | 48 ++++++--- tests/vm_test.nim | 2 +- 14 files changed, 228 insertions(+), 143 deletions(-) create mode 100644 src/opcode_table.nim rename tests/{helpers.nim => test_helpers.nim} (90%) diff --git a/src/computation.nim b/src/computation.nim index 04591a645..ce08f39bb 100644 --- a/src/computation.nim +++ b/src/computation.nim @@ -55,7 +55,8 @@ proc newBaseComputation*(vmState: BaseVMState, message: Message): BaseComputatio result.children = @[] result.accountsToDelete = initTable[string, string]() result.logEntries = @[] - result.code = newCodeStream(message.code) + result.code = newCodeStreamFromUnescaped(message.code) # TODO: what is the best repr + result.rawOutput = "0x" method logger*(computation: BaseComputation): Logger = logging.getLogger("vm.computation.BaseComputation") @@ -264,7 +265,7 @@ template inComputation*(c: untyped, handler: untyped): untyped = method getOpcodeFn*(computation: var BaseComputation, op: Op): Opcode = - if computation.opcodes.hasKey(op): + if computation.opcodes.len > 0 and computation.opcodes.hasKey(op): computation.opcodes[op] else: raise newException(InvalidInstruction, @@ -279,7 +280,7 @@ macro applyComputation*(t: typed, vmState: untyped, message: untyped): untyped = result = quote: block: var res: `typName` - var c = `name`(`vmState`, `message`) + var c = `t` # `name`(`vmState`, `message`) var handler = proc: `typName` = # TODO # if `message`.codeAddress in c.precompiles: @@ -290,7 +291,6 @@ macro applyComputation*(t: typed, vmState: untyped, message: untyped): untyped = var opcode = c.getOpcodeFn(op) c.logger.trace( "OPCODE: 0x$1 ($2) | pc: $3" % [opcode.kind.int.toHex(2), $opcode.kind, $max(0, c.code.pc - 1)]) - try: opcode.run(c) except Halt: @@ -298,4 +298,4 @@ macro applyComputation*(t: typed, vmState: untyped, message: untyped): untyped = return c inComputation(c): res = handler() - res + c diff --git a/src/db/db_chain.nim b/src/db/db_chain.nim index 3a9f06865..31273500f 100644 --- a/src/db/db_chain.nim +++ b/src/db/db_chain.nim @@ -6,11 +6,15 @@ type # TODO db*: JournalDB proc newBaseChainDB*(db: MemoryDB): BaseChainDB = + new(result) result.db = db proc exists*(self: BaseChainDB; key: string): bool = return self.db.exists(key) +proc `$`*(db: BaseChainDB): string = + result = "BaseChainDB" + # proc getCanonicalHead*(self: BaseChainDB): BlockHeader = # if notself.exists(CANONICALHEADHASHDBKEY): # raise newException(CanonicalHeadNotFound, diff --git a/src/errors.nim b/src/errors.nim index 69250ef70..4d0e4313e 100644 --- a/src/errors.nim +++ b/src/errors.nim @@ -67,11 +67,27 @@ type NotImplementedError* = object of VMError ## Not implemented error -# proc makeVMError*(): VMError = -# result.burnsGas = true -# result.erasesReturnData = true +#proc makeVMError*: ref VMError = +# var e: ref VMError +# new(e) +# e.burnsGas = true +# e.erasesReturnData = true +#var a: ref VMError +#new(a) # proc makeRevert*(): Revert = # result.burnsGas = false # result.erasesReturnData = false +#var e = VMError() +#raise makeVMError() +#var e: ref VMError +#new(e) +#echo e[] +#proc x* = +# raise newException(VMError, "") +#var e = makeVMError() +#echo e[] + + +#x() \ No newline at end of file diff --git a/src/logic/storage.nim b/src/logic/storage.nim index 6caac3518..41bb106c1 100644 --- a/src/logic/storage.nim +++ b/src/logic/storage.nim @@ -1,5 +1,5 @@ import - ../constants, ../errors, ../computation, .. / db / state_db, .. / vm / [stack, gas_meter, message] + ../constants, ../errors, ../computation, .. / db / state_db, .. / vm / [stack, gas_meter, message], strformat {.this: computation.} {.experimental.} @@ -9,8 +9,10 @@ using proc sstore*(computation) = let (slot, value) = stack.popInt(2) - - # TODO: stateDB + #if value != 0: #and slot == 0: + computation.gasMeter.consumeGas(GAS_SSET, &"SSTORE: {computation.msg.storageAddress}[slot] -> {value} (TODO)") + #else: + #computation.gasMeter.consumeGas(GAS_SRESET, &"SSTORE: {computation.msg.storageAddress}[slot] -> {value} (TODO)") # with computation.vm_state.state_db(read_only=True) as state_db: # current_value = state_db.get_storage( # address=computation.msg.storage_address, diff --git a/src/opcode_table.nim b/src/opcode_table.nim new file mode 100644 index 000000000..2b009eb6c --- /dev/null +++ b/src/opcode_table.nim @@ -0,0 +1,111 @@ +import + strformat, strutils, tables, macros, + constants, ttmath, errors, logging, vm_state, + vm / [gas_meter, stack, code_stream, memory, message, value, gas_costs], db / db_chain, computation, opcode, opcode_values, utils / [header, address], + logic / [arithmetic, comparison, sha3, context, block_ops, stack_ops, duplication, swap, memory_ops, storage, flow, logging_ops, invalid, call, system_ops] + +var OPCODE_TABLE* = initOpcodes: + # arithmetic + Op.Add: GAS_VERY_LOW add + Op.Mul: GAS_LOW mul + Op.Sub: GAS_VERY_LOW sub + Op.Div: GAS_LOW divide + Op.SDiv: GAS_LOW sdiv + Op.Mod: GAS_LOW modulo + Op.SMod: GAS_LOW smod + Op.AddMod: GAS_MID addmod + Op.MulMod: GAS_MID mulmod + Op.Exp: expGasCost arithmetic.exp + Op.SignExtend: GAS_LOW signextend + + + # comparison + Op.Lt: GAS_VERY_LOW lt + Op.Gt: GAS_VERY_LOW gt + Op.SLt: GAS_VERY_LOW slt + Op.SGt: GAS_VERY_LOW sgt + Op.Eq: GAS_VERY_LOW eq + Op.IsZero: GAS_VERY_LOW iszero + Op.And: GAS_VERY_LOW andOp + Op.Or: GAS_VERY_LOW orOp + Op.Xor: GAS_VERY_LOW xorOp + Op.Not: GAS_VERY_LOW notOp + Op.Byte: GAS_VERY_LOW byteOp + + + # sha3 + Op.SHA3: GAS_SHA3 sha3op + + + # context + Op.Address: GAS_BASE context.address + Op.Balance: GAS_COST_BALANCE balance + Op.Origin: GAS_BASE origin + Op.Caller: GAS_BASE caller + 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 + + + # block + Op.Blockhash: GAS_BASE block_ops.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 gaslimit + + + # stack + Op.Pop: GAS_BASE stack_ops.pop + 1..32 Op.PushXX: GAS_VERY_LOW pushXX # XX replaced by macro + 1..16 Op.DupXX: GAS_VERY_LOW dupXX + 1..16 Op.SwapXX: GAS_VERY_LOW swapXX + + + # memory + Op.MLoad: GAS_VERY_LOW mload + Op.MStore: GAS_VERY_LOW mstore + Op.MStore8: GAS_VERY_LOW mstore8 + Op.MSize: GAS_BASE msize + + # storage + Op.SLoad: GAS_SLOAD_COST sload + Op.SStore: GAS_ZERO sstore + + + # flow + Op.Jump: GAS_MID jump + Op.JumpI: GAS_MID jumpi + Op.PC: GAS_HIGH pc + Op.Gas: GAS_BASE flow.gas + Op.JumpDest: GAS_JUMP_DEST jumpdest + Op.Stop: GAS_ZERO stop + + + # logging + 0..4 Op.LogXX: GAS_IN_HANDLER logXX + + + # invalid + Op.Invalid: GAS_ZERO invalidOp + + + # system + Op.Return: 0.i256 returnOp + Op.SelfDestruct: GAS_SELF_DESTRUCT_COST selfdestruct + + +# call +OPCODE_TABLE[Op.Call] = Call(kind: Op.Call) +OPCODE_TABLE[Op.CallCode] = CallCode(kind: Op.CallCode) +OPCODE_TABLE[Op.DelegateCall] = DelegateCall(kind: Op.DelegateCall) + + +# system +OPCODE_TABLE[Op.Create] = Create(kind: Op.Create) diff --git a/src/runner.nim b/src/runner.nim index 3c5cf3bb5..f9f16f595 100644 --- a/src/runner.nim +++ b/src/runner.nim @@ -1,115 +1,9 @@ import strformat, strutils, tables, macros, - constants, ttmath, errors, logging, vm_state, + constants, ttmath, errors, logging, vm_state, opcode_table, vm / [gas_meter, stack, code_stream, memory, message, value, gas_costs], db / chain, computation, opcode, opcode_values, utils / [header, address], logic / [arithmetic, comparison, sha3, context, block_ops, stack_ops, duplication, swap, memory_ops, storage, flow, logging_ops, invalid, call, system_ops] -var opcodes = initOpcodes: - # arithmetic - Op.Add: GAS_VERY_LOW add - Op.Mul: GAS_LOW mul - Op.Sub: GAS_VERY_LOW sub - Op.Div: GAS_LOW divide - Op.SDiv: GAS_LOW sdiv - Op.Mod: GAS_LOW modulo - Op.SMod: GAS_LOW smod - Op.AddMod: GAS_MID addmod - Op.MulMod: GAS_MID mulmod - Op.Exp: expGasCost arithmetic.exp - Op.SignExtend: GAS_LOW signextend - - - # comparison - Op.Lt: GAS_VERY_LOW lt - Op.Gt: GAS_VERY_LOW gt - Op.SLt: GAS_VERY_LOW slt - Op.SGt: GAS_VERY_LOW sgt - Op.Eq: GAS_VERY_LOW eq - Op.IsZero: GAS_VERY_LOW iszero - Op.And: GAS_VERY_LOW andOp - Op.Or: GAS_VERY_LOW orOp - Op.Xor: GAS_VERY_LOW xorOp - Op.Not: GAS_VERY_LOW notOp - Op.Byte: GAS_VERY_LOW byteOp - - - # sha3 - Op.SHA3: GAS_SHA3 sha3op - - - # context - Op.Address: GAS_BASE context.address - Op.Balance: GAS_COST_BALANCE balance - Op.Origin: GAS_BASE origin - Op.Caller: GAS_BASE caller - 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 - - - # block - Op.Blockhash: GAS_BASE block_ops.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 gaslimit - - - # stack - Op.Pop: GAS_BASE stack_ops.pop - 1..32 Op.PushXX: GAS_VERY_LOW pushXX # XX replaced by macro - 1..16 Op.DupXX: GAS_VERY_LOW dupXX - 1..16 Op.SwapXX: GAS_VERY_LOW swapXX - - - # memory - Op.MLoad: GAS_VERY_LOW mload - Op.MStore: GAS_VERY_LOW mstore - Op.MStore8: GAS_VERY_LOW mstore8 - Op.MSize: GAS_BASE msize - - # storage - Op.SLoad: GAS_SLOAD_COST sload - Op.SStore: GAS_ZERO sstore - - - # flow - Op.Jump: GAS_MID jump - Op.JumpI: GAS_MID jumpi - Op.PC: GAS_HIGH pc - Op.Gas: GAS_BASE flow.gas - Op.JumpDest: GAS_JUMP_DEST jumpdest - Op.Stop: GAS_ZERO stop - - - # logging - 0..4 Op.LogXX: GAS_IN_HANDLER logXX - - - # invalid - Op.Invalid: GAS_ZERO invalidOp - - - # system - Op.Return: 0.i256 returnOp - Op.SelfDestruct: GAS_SELF_DESTRUCT_COST selfdestruct - - -# call -opcodes[Op.Call] = Call(kind: Op.Call) -opcodes[Op.CallCode] = CallCode(kind: Op.CallCode) -opcodes[Op.DelegateCall] = DelegateCall(kind: Op.DelegateCall) - - -# system -opcodes[Op.Create] = Create(kind: Op.Create) - var mem = newMemory(pow(1024.int256, 2)) var to = toCanonicalAddress("0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6") @@ -146,7 +40,7 @@ var c = BaseComputation( logEntries: @[], shouldEraseReturnData: false, accountsToDelete: initTable[string, string](), - opcodes: opcodes, + opcodes: OPCODE_TABLE, precompiles: initTable[string, Opcode]()) # var c2 = c.applyComputation(c.vmState, c.msg) diff --git a/src/utils/header.nim b/src/utils/header.nim index 5ced41e6d..33cb42ad6 100644 --- a/src/utils/header.nim +++ b/src/utils/header.nim @@ -1,4 +1,4 @@ -import ../constants, ttmath +import ../constants, ttmath, strformat type Header* = ref object @@ -12,6 +12,12 @@ type # TODO +proc `$`*(header: Header): string = + if header.isNil: + result = "nil" + else: + result = &"Header(timestamp: {header.timestamp} difficulty: {header.difficulty} blockNumber: {header.blockNumber} gasLimit: {header.gasLimit})" + proc generateHeaderFromParentHeader*( computeDifficultyFn: proc(parentHeader: Header, timestamp: int): int, parentHeader: Header, diff --git a/src/vm/code_stream.nim b/src/vm/code_stream.nim index f35ac80fb..de30b6156 100644 --- a/src/vm/code_stream.nim +++ b/src/vm/code_stream.nim @@ -1,5 +1,5 @@ import - strformat, strutils, sequtils, sets, macros, + strformat, strutils, sequtils, parseutils, sets, macros, ../logging, ../constants, ../opcode_values type @@ -24,6 +24,16 @@ proc newCodeStream*(codeBytes: seq[byte]): CodeStream = proc newCodeStream*(codeBytes: string): CodeStream = newCodeStream(codeBytes.mapIt(it.byte)) +proc newCodeStreamFromUnescaped*(code: string): CodeStream = + # from 0xunescaped + var codeBytes: seq[byte] = @[] + for z, c in code[2..^1]: + if z mod 2 == 1: + var value: int + discard parseHex(&"0x{code[z+1..z+2]}", value) + codeBytes.add(value.byte) + newCodeStream(codeBytes) + proc read*(c: var CodeStream, size: int): seq[byte] = if c.pc + size - 1 < c.bytes.len: result = c.bytes[c.pc .. c.pc + size - 1] diff --git a/src/vm/forks/frontier/frontier_vm_state.nim b/src/vm/forks/frontier/frontier_vm_state.nim index 7b4c978e9..2612cef17 100644 --- a/src/vm/forks/frontier/frontier_vm_state.nim +++ b/src/vm/forks/frontier/frontier_vm_state.nim @@ -2,11 +2,18 @@ import logging, constants, errors, vm_state, utils/header, db/db_chain type - FrontierVMState* = object of BaseVMState + FrontierVMState* = ref object of BaseVMState # receipts*: # computationClass*: Any # accessLogs*: AccessLogs +proc newFrontierVMState*: FrontierVMState = + new(result) + result.prevHeaders = @[] + result.name = "FrontierVM" + result.accessLogs = newAccessLogs() + result.blockHeader = Header(hash: "TODO", coinbase: "TODO", stateRoot: "TODO") + # import # py2nim_helpers, __future__, rlp, evm, evm.constants, evm.exceptions, evm.rlp.logs, # evm.rlp.receipts, evm.vm.message, evm.vm_state, evm.utils.address, diff --git a/src/vm/forks/frontier/vm.nim b/src/vm/forks/frontier/vm.nim index ca7737b15..ad78bb144 100644 --- a/src/vm/forks/frontier/vm.nim +++ b/src/vm/forks/frontier/vm.nim @@ -23,3 +23,4 @@ proc newFrontierVM*(header: Header, chainDB: BaseChainDB): FrontierVM = new(result) result.chainDB = chainDB result.isStateless = true + result.state = newFrontierVMState() diff --git a/src/vm_state.nim b/src/vm_state.nim index 45326afa5..6d503d9dc 100644 --- a/src/vm_state.nim +++ b/src/vm_state.nim @@ -22,11 +22,18 @@ proc update*[K, V](t: var Table[K, V], elements: Table[K, V]) = for k, v in elements: t[k] = v +proc `$`*(vmState: BaseVMState): string = + if vmState.isNil: + result = "nil" + else: + result = &"VMState {vmState.name}:\n header: {vmState.blockHeader}\n chaindb: {vmState.chaindb}" + proc newBaseVMState*: BaseVMState = new(result) result.prevHeaders = @[] result.name = "BaseVM" result.accessLogs = newAccessLogs() + result.blockHeader = Header(hash: "TODO", coinbase: "TODO", stateRoot: "TODO") method logger*(vmState: BaseVMState): Logger = logging.getLogger(&"evm.vmState.{vmState.name}") @@ -65,6 +72,7 @@ macro db*(vmState: untyped, readOnly: untyped, handler: untyped): untyped = let db = ident("db") result = quote: block: + echo `vmState` var `db` = `vmState`.chaindb.getStateDB(`vmState`.blockHeader.stateRoot, `readOnly`) `handler` if `readOnly`: diff --git a/tests/helpers.nim b/tests/test_helpers.nim similarity index 90% rename from tests/helpers.nim rename to tests/test_helpers.nim index 09896bbf0..9aac09af5 100644 --- a/tests/helpers.nim +++ b/tests/test_helpers.nim @@ -1,5 +1,5 @@ import - os, macros, json, strformat, strutils, ttmath, utils / [hexadecimal, address], chain, vm_state, constants, db / [db_chain, state_db], vm / forks / frontier / vm + os, macros, json, strformat, strutils, ttmath, utils / [hexadecimal, address], chain, vm_state, constants, db / [db_chain, state_db], vm / forks / frontier / vm, parseutils # TODO # This block is a child of the genesis defined in the chain fixture above and contains a single tx @@ -56,14 +56,21 @@ import # proc generateTest(filename: string, handler: NimNode): NimNode = echo filename + let testStatusIMPL = ident("testStatusIMPL") result = quote: test `filename`: - `handler`(parseJSON(readFile(`filename`))) + `handler`(parseJSON(readFile(`filename`)), `testStatusIMPL`) macro jsonTest*(s: static[string], handler: untyped): untyped = result = nnkStmtList.newTree() - for filename in walkDir(&"tests/{s}", relative=true): - result.add(generateTest(filename.path, handler)) + echo &"tests/fixtures/{s}" + var z = 0 + for filename in walkDirRec(&"tests/fixtures/{s}"): + if "mul" in filename: + if z >= 4: + break + result.add(generateTest(filename, handler)) + z += 1 proc setupStateDB*(desiredState: JsonNode, stateDB: var AccountStateDB) = for account, accountData in desiredState: @@ -77,3 +84,6 @@ proc setupStateDB*(desiredState: JsonNode, stateDB: var AccountStateDB) = stateDB.setNonce(account, nonce) stateDB.setCode(account, code) stateDB.setBalance(account, balance) + +proc getHexadecimalInt*(j: JsonNode): int = + discard parseHex(j.getStr, result) diff --git a/tests/vm_json_test.nim b/tests/vm_json_test.nim index 08985bdb1..87adb4699 100644 --- a/tests/vm_json_test.nim +++ b/tests/vm_json_test.nim @@ -1,38 +1,55 @@ import unittest, strformat, strutils, sequtils, tables, ttmath, json, - helpers, constants, errors, logging, - chain, vm_state, computation, opcode, utils / header, vm / [gas_meter, message, code_stream], vm / forks / frontier / vm, db / [db_chain, state_db], db / backends / memory_backend + test_helpers, constants, errors, logging, + chain, vm_state, computation, opcode, opcode_table, utils / header, vm / [gas_meter, message, code_stream], vm / forks / frontier / vm, db / [db_chain, state_db], db / backends / memory_backend -proc testFixture(fixture: JsonNode) +proc testFixture(fixtures: JsonNode, testStatusIMPL: var TestStatus) suite "vm json tests": jsonTest("VMTests", testFixture) -proc testFixture(fixture: JsonNode) = +proc testFixture(fixtures: JsonNode, testStatusIMPL: var TestStatus) = + var fixture: JsonNode + for label, child in fixtures: + fixture = child + break var vm = newFrontierVM(Header(), newBaseChainDB(newMemoryDB())) let header = Header( coinbase: fixture{"env"}{"currentCoinbase"}.getStr, - difficulty: fixture{"env"}{"currentDifficulty"}.getInt.i256, - blockNumber: fixture{"env"}{"currentNumber"}.getInt.i256, - gasLimit: fixture{"env"}{"currentGasLimit"}.getInt.i256, - timestamp: fixture{"env"}{"currentTimestamp"}.getInt) + difficulty: fixture{"env"}{"currentDifficulty"}.getHexadecimalInt.i256, + blockNumber: fixture{"env"}{"currentNumber"}.getHexadecimalInt.i256, + gasLimit: fixture{"env"}{"currentGasLimit"}.getHexadecimalInt.i256, + timestamp: fixture{"env"}{"currentTimestamp"}.getHexadecimalInt) var code = "" vm.state.db(readOnly=false): setupStateDB(fixture{"pre"}, db) code = db.getCode(fixture{"exec"}{"address"}.getStr) + code = fixture{"exec"}{"code"}.getStr let message = newMessage( to=fixture{"exec"}{"address"}.getStr, sender=fixture{"exec"}{"caller"}.getStr, - value=fixture{"exec"}{"value"}.getInt.i256, + value=fixture{"exec"}{"value"}.getHexadecimalInt.i256, data=fixture{"exec"}{"data"}.getStr.mapIt(it.byte), code=code, - gas=fixture{"exec"}{"gas"}.getInt.i256, - gasPrice=fixture{"exec"}{"gasPrice"}.getInt.i256, + gas=fixture{"exec"}{"gas"}.getHexadecimalInt.i256, + gasPrice=fixture{"exec"}{"gasPrice"}.getHexadecimalInt.i256, options=newMessageOptions(origin=fixture{"exec"}{"origin"}.getStr)) - let computation = newBaseComputation(vm.state, message).applyComputation(vm.state, message) + + echo fixture{"exec"} + var c = newCodeStreamFromUnescaped(code) + var opcodes = c.decompile + for opcode in opcodes: + echo opcode[0], " ", opcode[1], " ", opcode[2] + + var computation = newBaseComputation(vm.state, message) + computation.accountsToDelete = initTable[string, string]() + computation.opcodes = OPCODE_TABLE + computation.precompiles = initTable[string, Opcode]() + + computation = computation.applyComputation(vm.state, message) if not fixture{"post"}.isNil: # Success checks @@ -50,10 +67,9 @@ proc testFixture(fixture: JsonNode) = let expectedOutput = fixture{"out"}.getStr check(computation.output == expectedOutput) - let gasMeter = computation.gasMeter - let expectedGasRemaining = fixture{"gas"}.getInt.i256 + let expectedGasRemaining = fixture{"gas"}.getHexadecimalInt.i256 let actualGasRemaining = gasMeter.gasRemaining let gasDelta = actualGasRemaining - expectedGasRemaining check(gasDelta == 0) @@ -69,8 +85,8 @@ proc testFixture(fixture: JsonNode) = var (childComputation, createdCall) = child let toAddress = createdCall{"destination"}.getStr let data = createdCall{"data"}.getStr.mapIt(it.byte) - let gasLimit = createdCall{"gasLimit"}.getInt.i256 - let value = createdCall{"value"}.getInt.i256 + let gasLimit = createdCall{"gasLimit"}.getHexadecimalInt.i256 + let value = createdCall{"value"}.getHexadecimalInt.i256 check(childComputation.msg.to == toAddress) check(data == childComputation.msg.data or childComputation.msg.code.len > 0) diff --git a/tests/vm_test.nim b/tests/vm_test.nim index c35f1a42b..3267ca983 100644 --- a/tests/vm_test.nim +++ b/tests/vm_test.nim @@ -1,6 +1,6 @@ import unittest, - helpers, .. / src / [db / backends / memory, db / chain, constants, utils / hexadecimal] + test_helpers, .. / src / [db / backends / memory, db / chain, constants, utils / hexadecimal] suite "vm": test "apply no validation":