From c26c751f9b639865390caf6e67af07500b366e2c Mon Sep 17 00:00:00 2001 From: Mamy Ratsimbazafy Date: Fri, 15 Jun 2018 11:11:25 +0200 Subject: [PATCH] Reorganize VM/interpreter + cleanup (#52) * Move and cleanup interpreter files - prepare for redesign of VM * fix call comment aobut recursive dependencies * memory: use a template again and avoid (?) a cstring-> string conversion * Fix stack test regression * Fix recursive dependency on logging_ops, test_vm_json compiles but regression :/ * Fix signextend regression * Fix 3 signed test and sha3 test --- nimbus/chain.nim | 106 ----------------- nimbus/constants.nim | 107 +----------------- nimbus/db/state_db.nim | 19 ++-- nimbus/errors.nim | 2 +- nimbus/nim.cfg | 1 - nimbus/opcode.nim | 34 ------ nimbus/runner.nim | 93 --------------- nimbus/utils/bytes.nim | 2 - nimbus/utils/header.nim | 4 + nimbus/utils/state.nim | 20 ---- nimbus/vm/base.nim | 4 +- nimbus/vm/code_stream.nim | 2 +- nimbus/{ => vm}/computation.nim | 31 ++++- nimbus/vm/forks/README.md | 1 + .../hexadecimal.nim => vm/interpreter.nim} | 22 ++-- .../vm/{forks => interpreter}/forks_list.md | 0 .../vm/{forks => interpreter}/forks_list.png | Bin .../vm/{forks => interpreter}/gas_costs.nim | 7 +- nimbus/vm/{ => interpreter}/gas_meter.nim | 4 +- nimbus/{ => vm/interpreter}/opcode_table.nim | 8 +- nimbus/{ => vm/interpreter}/opcode_values.nim | 2 +- .../interpreter/opcodes_impl}/arithmetic.nim | 6 +- .../interpreter/opcodes_impl}/block.nim | 0 .../interpreter/opcodes_impl}/block_ops.nim | 3 +- .../interpreter/opcodes_impl}/call.nim | 16 ++- .../interpreter/opcodes_impl}/comparison.nim | 5 +- .../interpreter/opcodes_impl}/context.nim | 4 +- .../interpreter/opcodes_impl}/duplication.nim | 3 +- .../interpreter/opcodes_impl}/flow.nim | 4 +- .../interpreter/opcodes_impl}/helpers.nim | 6 +- .../opcodes_impl/impl_std_import.nim | 22 ++++ .../interpreter/opcodes_impl}/invalid.nim | 2 +- .../interpreter/opcodes_impl}/logging_ops.nim | 13 +-- .../interpreter/opcodes_impl}/memory_ops.nim | 5 +- .../interpreter/opcodes_impl}/sha3.nim | 10 +- .../interpreter/opcodes_impl}/stack_ops.nim | 3 +- .../interpreter/opcodes_impl}/storage.nim | 9 +- .../interpreter/opcodes_impl}/swap.nim | 3 +- .../interpreter/opcodes_impl}/system_ops.nim | 6 +- nimbus/vm/{forks => interpreter}/vm_forks.nim | 4 +- nimbus/vm/memory.nim | 7 +- nimbus/vm/stack.nim | 4 +- nimbus/{ => vm}/utils/macros_gen_opcodes.nim | 0 nimbus/{ => vm/utils}/utils_numeric.nim | 16 +-- nimbus/vm_state.nim | 2 +- nimbus/vm_state_transactions.nim | 3 +- nimbus/vm_types.nim | 12 +- tests/all_tests.nim | 1 - tests/fixtures.nim | 38 ------- tests/test_code_stream.nim | 2 +- tests/test_gas_meter.nim | 4 +- tests/test_helpers.nim | 6 +- tests/test_memory.nim | 4 +- tests/test_opcode.nim | 11 +- tests/test_stack.nim | 8 +- tests/test_vm.nim | 43 ------- tests/test_vm_json.nim | 10 +- 57 files changed, 171 insertions(+), 593 deletions(-) delete mode 100644 nimbus/chain.nim delete mode 100644 nimbus/nim.cfg delete mode 100644 nimbus/opcode.nim delete mode 100644 nimbus/runner.nim delete mode 100644 nimbus/utils/state.nim rename nimbus/{ => vm}/computation.nim (88%) create mode 100644 nimbus/vm/forks/README.md rename nimbus/{utils/hexadecimal.nim => vm/interpreter.nim} (50%) rename nimbus/vm/{forks => interpreter}/forks_list.md (100%) rename nimbus/vm/{forks => interpreter}/forks_list.png (100%) rename nimbus/vm/{forks => interpreter}/gas_costs.nim (99%) rename nimbus/vm/{ => interpreter}/gas_meter.nim (96%) rename nimbus/{ => vm/interpreter}/opcode_table.nim (93%) rename nimbus/{ => vm/interpreter}/opcode_values.nim (99%) rename nimbus/{logic => vm/interpreter/opcodes_impl}/arithmetic.nim (94%) rename nimbus/{logic => vm/interpreter/opcodes_impl}/block.nim (100%) rename nimbus/{logic => vm/interpreter/opcodes_impl}/block_ops.nim (91%) rename nimbus/{logic => vm/interpreter/opcodes_impl}/call.nim (91%) rename nimbus/{logic => vm/interpreter/opcodes_impl}/comparison.nim (91%) rename nimbus/{logic => vm/interpreter/opcodes_impl}/context.nim (95%) rename nimbus/{logic => vm/interpreter/opcodes_impl}/duplication.nim (92%) rename nimbus/{logic => vm/interpreter/opcodes_impl}/flow.nim (91%) rename nimbus/{logic => vm/interpreter/opcodes_impl}/helpers.nim (91%) create mode 100644 nimbus/vm/interpreter/opcodes_impl/impl_std_import.nim rename nimbus/{logic => vm/interpreter/opcodes_impl}/invalid.nim (92%) rename nimbus/{logic => vm/interpreter/opcodes_impl}/logging_ops.nim (87%) rename nimbus/{logic => vm/interpreter/opcodes_impl}/memory_ops.nim (92%) rename nimbus/{logic => vm/interpreter/opcodes_impl}/sha3.nim (71%) rename nimbus/{logic => vm/interpreter/opcodes_impl}/stack_ops.nim (89%) rename nimbus/{logic => vm/interpreter/opcodes_impl}/storage.nim (88%) rename nimbus/{logic => vm/interpreter/opcodes_impl}/swap.nim (92%) rename nimbus/{logic => vm/interpreter/opcodes_impl}/system_ops.nim (95%) rename nimbus/vm/{forks => interpreter}/vm_forks.nim (91%) rename nimbus/{ => vm}/utils/macros_gen_opcodes.nim (100%) rename nimbus/{ => vm/utils}/utils_numeric.nim (75%) delete mode 100644 tests/fixtures.nim delete mode 100644 tests/test_vm.nim diff --git a/nimbus/chain.nim b/nimbus/chain.nim deleted file mode 100644 index d2993f14a..000000000 --- a/nimbus/chain.nim +++ /dev/null @@ -1,106 +0,0 @@ -# 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 - tables, stint, eth_common, eth_keys, - ./logging, ./constants, ./errors, ./validation, ./utils/hexadecimal, ./vm/base, ./db/db_chain, - ./utils/header, ./vm/forks/f20150730_frontier/frontier_vm - -type - Chain* = ref object - ## An Chain is a combination of one or more VM classes. Each VM is associated - ## with a range of blocks. The Chain class acts as a wrapper around these other - ## VM classes, delegating operations to the appropriate VM depending on the - ## current block number. - header*: BlockHeader - logger*: Logger - networkId*: string - vmsByRange*: seq[tuple[blockNumber: UInt256, vmk: VMkind]] # TODO: VM should actually be a runtime typedesc(VM) - importBlock*: bool - validateBlock*: bool - db*: BaseChainDB - fundedAddress*: EthAddress - fundedAddressInitialBalance*: int - fundedAddressPrivateKey*: PrivateKey - - GenesisParams* = ref object - blockNumber*: BlockNumber - difficulty*: UInt256 - gasLimit*: GasInt - parentHash*: Hash256 - coinbase*: EthAddress - nonce*: string - mixHash*: Hash256 - extraData*: string - timestamp*: EthTime - stateRoot*: Hash256 - - FundedAddress* = ref object - balance*: Int256 - nonce*: int - code*: string - - -proc configureChain*(name: string, blockNumber: UInt256, vmk: VMKind, importBlock: bool = true, validateBlock: bool = true): Chain = - new(result) - result.vmsByRange = @[(blockNumber: blockNumber, vmk: vmk)] - result.importBlock = importBlock - result.validateBlock = validateBlock - -proc fromGenesis*( - chain: Chain, - chainDB: BaseChainDB, - genesisParams: GenesisParams, - genesisState: Table[string, FundedAddress]): Chain = - ## Initialize the Chain from a genesis state - var stateDB = chaindb.getStateDB(BLANK_ROOT_HASH) - # TODO - # for account, accountData in genesisState: - # stateDB.setBalance(account, accountData.balance) - # stateDB.setNonce(account, accountData.nonce) - # stateDB.setCode(account, accountData.code) - - new(result) - result.db = chainDB - result.header = BlockHeader() - result.logger = logging.getLogger("evm.chain.chain.Chain") - result.importBlock = chain.importBlock - result.validateBlock = chain.validateBlock - result.vmsByRange = chain.vmsByRange - # TODO - # chainDB.persistBlockToDB(result.getBlock) - - -proc getVMClassForBlockNumber*(chain: Chain, blockNumber: BlockNumber): VMKind = - ## Returns the VM class for the given block number - # TODO - Refactoring: superseded by newNimbusVM for the time being #https://github.com/status-im/nimbus/pull/37 - # TODO - Refactoring: redundant with constants.nim `toFork` - # TODO should the return value be a typedesc? - - # TODO: validate_block_number - for idx in countdown(chain.vmsByRange.high, chain.vmsByRange.low): - let (n, vmk) = chain.vmsByRange[idx] - if blockNumber >= n: - return vmk - - raise newException(ValueError, "VM not found for block #" & $blockNumber) # TODO: VMNotFound exception - -# TODO - Refactoring: superseded by newNimbusVM for the time being #https://github.com/status-im/nimbus/pull/37 - -proc getVM*(chain: Chain, header: BlockHeader): VM = - ## Returns the VM instance for the given block number - # TODO - Refactoring: superseded by newNimbusVM for the time being #https://github.com/status-im/nimbus/pull/37 - # TODO - Refactoring: redundant with constants.nim `toFork` - # shadowing input param - let vm_class = chain.getVMClassForBlockNumber(header.blockNumber) - - case vm_class: - of vmkFrontier: result = newFrontierVM(header, chain.db) - else: - raise newException(ValueError, "Chain: only FrontierVM is implemented") - -proc getVM*(chain: Chain): VM {.inline.} = getVM(chain, chain.header) diff --git a/nimbus/constants.nim b/nimbus/constants.nim index 2c19b8699..e63c4bef7 100644 --- a/nimbus/constants.nim +++ b/nimbus/constants.nim @@ -2,103 +2,6 @@ import stint, math, strutils, utils/padding, eth_common -proc int256*(i: int): Int256 = - i.i256 - -# template i256*(i: int): Int256 = -# i.initBigInt - -template i256*(i: Int256): Int256 = - i - -template u256*(i: int): UInt256 = - i.uint.u256 - -template u256*(i: UInt256): UInt256 = - i - -template getInt*(i: int): int = - i - -# TODO -# We'll have a fast fixed i256, for now this works - -proc `==`*(a: Int256, b: int): bool = - a == b.i256 - -proc `!=`*(a: Int256, b: int): bool = - a != b.i256 - -proc `==`*(a: UInt256, b: int): bool = - a == b.u256 - -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 `^`*(left: Int256, right: int): Int256 = - var value = right.i256 - result = 1.i256 - var m = right.i256 - while value > 0.i256: - result = result * m - value -= 1.i256 - -proc `^`*(left: UInt256, right: UInt256): UInt256 = - var value = right - result = 1.u256 - var m = right.u256 - while value > 0.u256: - result = result * m - value -= 1.u256 - -proc `^`*(left: UInt256, right: int): UInt256 = - left ^ right.u256 - -proc `>`*(a: Int256, b: int): bool = - a > b.i256 - -proc `<`*(a: Int256, b: int): bool = - a < b.i256 - -proc `>`*(a: UInt256, b: int): bool = - a > b.u256 - -proc `<`*(a: UInt256, b: int): bool = - a < b.u256 - -proc `mod`*(a: Int256, b: int): Int256 = - a mod b.i256 - -proc `div`*(a: Int256, b: int): Int256 = - a div b.i256 - -proc `mod`*(a: UInt256, b: int): UInt256 = - a mod b.u256 - -proc `div`*(a: UInt256, b: int): UInt256 = - a div b.u256 - -template mapOp(op: untyped): untyped = - proc `op`*(left: Int256, right: int): Int256 = - result = left.i256 - result = `op`(result, right.i256) - - proc `op`*(left: UInt256, right: int): UInt256 = - result = left.u256 - result = `op`(result, right.u256) - -mapOp(`and`) -mapOp(`or`) -mapOp(`xor`) - proc default(t: typedesc): t = discard # constants @@ -108,7 +11,7 @@ let INT_256_MAX_AS_UINT256* = cast[Uint256](high(Int256)) NULLBYTE* = "\x00" EMPTYWORD* = repeat(NULLBYTE, 32) - UINT160CEILING*: UInt256 = 2.u256 ^ 160 + UINT160CEILING*: UInt256 = 2.u256.pow(160) ZERO_ADDRESS* = default(EthAddress) CREATE_CONTRACT_ADDRESS* = ZERO_ADDRESS ZERO_HASH32* = Hash256() @@ -133,14 +36,6 @@ let MAX_UNCLE_DEPTH* = 6.u256 MAX_UNCLES* = 2.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 - SECPK1_Gx* = 0.u256 - SECPK1_Gy* = 0.u256 - SECPK1_G* = (SECPK1Gx, SECPK1Gy) - EMPTY_UNCLE_HASH* = "1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347".toDigest GENESIS_BLOCK_NUMBER* = 0.u256 diff --git a/nimbus/db/state_db.nim b/nimbus/db/state_db.nim index 49112cfbe..dfa673d79 100644 --- a/nimbus/db/state_db.nim +++ b/nimbus/db/state_db.nim @@ -6,9 +6,8 @@ # at your option. This file may not be copied, modified, or distributed except according to those terms. import - eth_common, tables, - ../constants, ../errors, ../validation, ../account, ../logging, ../utils_numeric, .. / utils / [padding, bytes, keccak], - stint, rlp + eth_common, tables, nimcrypto, stint, rlp, + ../constants, ../errors, ../validation, ../account, ../logging type AccountStateDB* = ref object @@ -64,11 +63,11 @@ proc setStorage*(db: var AccountStateDB, address: EthAddress, slot: UInt256, val # let account = db.getAccount(address) # var storage = HashTrie(HexaryTrie(self.db, account.storageRoot)) - let slotAsKey = slot.intToBigEndian.pad32.toString + let slotAsKey = "0x" & slot.dumpHex # Convert to a number to hex big-endian representation including prefix and leading zeros var storage = db.db # TODO fix if value > 0: - let encodedValue = rlp.encode value.intToBigEndian + let encodedValue = rlp.encode value.toByteArrayBE storage[slotAsKey] = encodedValue else: storage.del(slotAsKey) @@ -87,13 +86,11 @@ proc getStorage*(db: var AccountStateDB, address: EthAddress, slot: UInt256): (U # let account = db.GetAccount(address) # var storage = HashTrie(HexaryTrie(self.db, account.storageRoot)) - let slotAsKey = slot.intToBigEndian.pad32.toString + let slotAsKey = "0x" & slot.dumpHex # Convert to a number to hex big-endian representation including prefix and leading zeros var storage = db.db if storage.hasKey(slotAsKey): - #result = storage[slotAsKey] - # XXX: `bigEndianToInt` can be refactored to work with a BytesRange/openarray - # Then we won't need to call `toSeq` here. - result = (storage[slotAsKey].toSeq.bigEndianToInt, true) + let byteRange = storage[slotAsKey] + result = (readUintBE[256](byteRange.toOpenArray), true) else: result = (0.u256, false) @@ -117,7 +114,7 @@ proc setCode*(db: var AccountStateDB, address: EthAddress, code: string) = var account = db.getAccount(address) - account.codeHash = keccak(code) + account.codeHash = keccak256.digest code #db.db[account.codeHash] = code db.setAccount(address, account) diff --git a/nimbus/errors.nim b/nimbus/errors.nim index 776abed69..08216d347 100644 --- a/nimbus/errors.nim +++ b/nimbus/errors.nim @@ -51,7 +51,7 @@ type ## Error signaling that an account has insufficient funds to transfer the ## requested value. - StackDepthLimit* = object of VMError + StackDepthError* = object of VMError ## Error signaling that the call stack has exceeded it's maximum allowed depth. ContractCreationCollision* = object of VMError diff --git a/nimbus/nim.cfg b/nimbus/nim.cfg deleted file mode 100644 index fe1a63477..000000000 --- a/nimbus/nim.cfg +++ /dev/null @@ -1 +0,0 @@ -# --warning[XDeclaredButNotUsed]:off \ No newline at end of file diff --git a/nimbus/opcode.nim b/nimbus/opcode.nim deleted file mode 100644 index 4c2b15dd3..000000000 --- a/nimbus/opcode.nim +++ /dev/null @@ -1,34 +0,0 @@ -# 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, strutils, sequtils, macros, - constants, logging, errors, opcode_values, computation, vm/stack, stint, - ./vm_types - - -# Super dirty fix for https://github.com/status-im/nimbus/issues/46 -# Pending https://github.com/status-im/nimbus/issues/36 -# Disentangle opcode logic -from logic.call import runLogic, BaseCall - - -template run*(opcode: Opcode, computation: var BaseComputation) = - # Hook for performing the actual VM execution - # opcode.consumeGas(computation) - - if opcode.kind == Op.Call: # Super dirty fix for https://github.com/status-im/nimbus/issues/46 - # TODO remove this branch - runLogic(BaseCall(opcode), computation) - elif computation.gasCosts[opcode.kind].kind != GckFixed: - opcode.runLogic(computation) - else: - computation.gasMeter.consumeGas(computation.gasCosts[opcode.kind].cost, reason = $opcode.kind) - opcode.runLogic(computation) - -method logger*(opcode: Opcode): Logger = - logging.getLogger(&"vm.opcode.{opcode.kind}") diff --git a/nimbus/runner.nim b/nimbus/runner.nim deleted file mode 100644 index cc612e03e..000000000 --- a/nimbus/runner.nim +++ /dev/null @@ -1,93 +0,0 @@ -# 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, strutils, tables, macros, - constants, stint, errors, logging, vm_state, opcode_table, - vm / [gas_meter, stack, code_stream, memory, message, value], 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 mem = newMemory(pow(1024.int256, 2)) - -var to = toCanonicalAddress("0x0f572e5295c57f15886f9b263e2f6d2d6c7b5ec6") -var sender = toCanonicalAddress("0xcd1722f3947def4cf144679da39c4c32bdc35681") - -var code = "" -var data: seq[byte] = @[] - -var msg = newMessage( - 25.int256, - 1.int256, - to, - sender, - 0.int256, - data, - code, - MessageOptions(depth: 1)) - -var c = BaseComputation( - vmState: BaseVMState( - prevHeaders: @[], - chaindb: BaseChainDB(), - blockHeader: BlockHeader(), - name: "zero"), - msg: msg, - memory: mem, - stack: newStack(), - gasMeter: newGasMeter(msg.gas), - code: newCodeStream(code), - children: @[], - rawOutput: "", - returnData: "", - error: nil, - logEntries: @[], - shouldEraseReturnData: false, - accountsToDelete: initTable[string, string](), - opcodes: OPCODE_TABLE, - precompiles: initTable[string, Opcode]()) - -# var c2 = c.applyComputation(c.vmState, c.msg) - -macro runOpcodes*(computation: untyped, program: untyped): untyped = - # runOpcodes(c): - # stack: @[Value..] - # - # Op - # Op - # - # becomes - # - # c.stack.push(Value) .. - # - # c.getOpcodeFn(Op).run(c) - # echo c.stack .. - var stack = nnkStmtList.newTree() - for child in program[0][1][0][1]: - let push = quote: - `computation`.stack.push(`child`) - stack.add(push) - - var ops = nnkStmtList.newTree() - for z, op in program: - if z > 0: - let run = quote: - `computation`.getOpcodeFn(`op`).run(`computation`) - echo `computation`.stack - ops.add(run) - - result = nnkStmtList.newTree(stack, ops) - -# useful for testing simple cases -runOpcodes(c): - stack: @[2.vint, 2.vint, 2.vint, 2.vint, 2.vint, 2.vint, 4.vint] - - Op.Add - Op.Mul - Op.Div - Op.Sub - Op.Mul - diff --git a/nimbus/utils/bytes.nim b/nimbus/utils/bytes.nim index 292347758..cdbfabcce 100644 --- a/nimbus/utils/bytes.nim +++ b/nimbus/utils/bytes.nim @@ -24,5 +24,3 @@ proc toString*(value: seq[byte]): string = proc toBytes*(value: string): seq[byte] = result = value.mapIt(it.byte) - - diff --git a/nimbus/utils/header.nim b/nimbus/utils/header.nim index 87a171814..8bdc8eaa1 100644 --- a/nimbus/utils/header.nim +++ b/nimbus/utils/header.nim @@ -92,4 +92,8 @@ proc generateHeaderFromParentHeader*( # TODO: data: extraData, ) +import nimcrypto +# TODO: required otherwise +# eth_common/rlp_serialization.nim(18, 12) template/generic instantiation from here +# nimcrypto/hash.nim(46, 6) Error: attempting to call undeclared routine: 'init' proc hash*(b: BlockHeader): Hash256 {.inline.} = rlpHash(b) diff --git a/nimbus/utils/state.nim b/nimbus/utils/state.nim deleted file mode 100644 index 99849e09d..000000000 --- a/nimbus/utils/state.nim +++ /dev/null @@ -1,20 +0,0 @@ -# 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 -# eth_utils, rlp, trie, evm.db.backends.memory, evm.db.chain - -# proc makeTrieRootAndNodes*(transactions: auto; trieClass: auto): auto = -# var -# chaindb = BaseChainDB(MemoryDB()) -# db = chaindb.db -# transactionDb = trieClass(db) -# for index, transaction in transactions: -# var indexKey = rlp.encode(index) -# transactionDb[indexKey] = rlp.encode(transaction) -# return (transactionDb.rootHash, transactionDb.db.wrappedDb.kvStore) - diff --git a/nimbus/vm/base.nim b/nimbus/vm/base.nim index d70571ea6..1ad6f3865 100644 --- a/nimbus/vm/base.nim +++ b/nimbus/vm/base.nim @@ -6,7 +6,9 @@ # at your option. This file may not be copied, modified, or distributed except according to those terms. import - ../logging, ../constants, ../errors, ../transaction, ../vm_types, ../computation, ../block_types, ../vm_state, ../vm_state_transactions, ../db/db_chain, ../utils/header + ../logging, ../constants, ../errors, ../transaction, ../vm_types, + ../block_types, ../vm_state, ../vm_state_transactions, ../db/db_chain, ../utils/header, + ./computation type VMkind* = enum diff --git a/nimbus/vm/code_stream.nim b/nimbus/vm/code_stream.nim index b17517c66..d3b46440a 100644 --- a/nimbus/vm/code_stream.nim +++ b/nimbus/vm/code_stream.nim @@ -7,7 +7,7 @@ import strformat, strutils, sequtils, parseutils, sets, macros, - ../logging, ../constants, ../opcode_values + ../logging, ../constants, ./interpreter/opcode_values type CodeStream* = ref object diff --git a/nimbus/computation.nim b/nimbus/vm/computation.nim similarity index 88% rename from nimbus/computation.nim rename to nimbus/vm/computation.nim index 956b5361e..2d6cda063 100644 --- a/nimbus/computation.nim +++ b/nimbus/vm/computation.nim @@ -7,13 +7,13 @@ import strformat, strutils, sequtils, macros, stint, terminal, math, eth_common, byteutils, tables, - ./constants, ./errors, ./utils/hexadecimal, ./utils_numeric, ./validation, ./vm_state, ./logging, ./opcode_values, ./vm_types, - ./vm/[code_stream, gas_meter, memory, message, stack], + ../constants, ../errors, ../validation, ../vm_state, ../logging, ../vm_types, + ./interpreter/[opcode_values,gas_meter, gas_costs], + ./code_stream, ./memory, ./message, ./stack, # TODO further refactoring of gas cost - vm/forks/gas_costs, - vm/forks/f20150730_frontier/frontier_vm_state, - vm/forks/f20161018_tangerine_whistle/tangerine_vm_state + ./forks/f20150730_frontier/frontier_vm_state, + ./forks/f20161018_tangerine_whistle/tangerine_vm_state method newBaseComputation*(vmState: BaseVMState, message: Message): BaseComputation {.base.}= raise newException(ValueError, "Must be implemented by subclasses") @@ -239,6 +239,27 @@ method getOpcodeFn*(computation: var BaseComputation, op: Op): Opcode = raise newException(InvalidInstruction, &"Invalid opcode {op}") +# Super dirty fix for https://github.com/status-im/nimbus/issues/46 +# Pending https://github.com/status-im/nimbus/issues/36 +# Disentangle opcode logic +from ./interpreter/opcodes_impl/call import runLogic, BaseCall + +template run*(opcode: Opcode, computation: var BaseComputation) = + # Hook for performing the actual VM execution + # opcode.consumeGas(computation) + + if opcode.kind == Op.Call: # Super dirty fix for https://github.com/status-im/nimbus/issues/46 + # TODO remove this branch + runLogic(BaseCall(opcode), computation) + elif computation.gasCosts[opcode.kind].kind != GckFixed: + opcode.runLogic(computation) + else: + computation.gasMeter.consumeGas(computation.gasCosts[opcode.kind].cost, reason = $opcode.kind) + opcode.runLogic(computation) + +method logger*(opcode: Opcode): Logger = + logging.getLogger(&"vm.opcode.{opcode.kind}") + macro applyComputation*(t: typed, vmState: untyped, message: untyped): untyped = # Perform the computation that would be triggered by the VM message # c.applyComputation(vmState, message) diff --git a/nimbus/vm/forks/README.md b/nimbus/vm/forks/README.md new file mode 100644 index 000000000..bfdfe7cda --- /dev/null +++ b/nimbus/vm/forks/README.md @@ -0,0 +1 @@ +Folder to be deleted diff --git a/nimbus/utils/hexadecimal.nim b/nimbus/vm/interpreter.nim similarity index 50% rename from nimbus/utils/hexadecimal.nim rename to nimbus/vm/interpreter.nim index fe6096c17..10e75331c 100644 --- a/nimbus/utils/hexadecimal.nim +++ b/nimbus/vm/interpreter.nim @@ -5,14 +5,20 @@ # * 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 strutils +import + ./interpreter/[opcode_values, gas_meter, opcode_table], + ./interpreter/vm_forks -# proc encodeHex*(value: string): string = -# # return "0x" & codecs.decode(codecs.encode(value, "hex"), "utf8") -# return value +from utils/utils_numeric import bigEndianToInt -# proc decodeHex*(value: string): string = -# # var hexPart = value.rsplit("x", 1)[1] -# return value -# # return codecs.decode(hexPart, "hex") +import # Used in vm_types. Beware of recursive dependencies + ./code_stream, ./computation, ./stack, ./message +export + opcode_values, gas_meter, opcode_table, + vm_forks + +export utils_numeric.bigEndianToInt + +export + code_stream, computation, stack, message diff --git a/nimbus/vm/forks/forks_list.md b/nimbus/vm/interpreter/forks_list.md similarity index 100% rename from nimbus/vm/forks/forks_list.md rename to nimbus/vm/interpreter/forks_list.md diff --git a/nimbus/vm/forks/forks_list.png b/nimbus/vm/interpreter/forks_list.png similarity index 100% rename from nimbus/vm/forks/forks_list.png rename to nimbus/vm/interpreter/forks_list.png diff --git a/nimbus/vm/forks/gas_costs.nim b/nimbus/vm/interpreter/gas_costs.nim similarity index 99% rename from nimbus/vm/forks/gas_costs.nim rename to nimbus/vm/interpreter/gas_costs.nim index 098d40d59..55c092762 100644 --- a/nimbus/vm/forks/gas_costs.nim +++ b/nimbus/vm/interpreter/gas_costs.nim @@ -6,10 +6,9 @@ # at your option. This file may not be copied, modified, or distributed except according to those terms. import - stint, eth_common, math, - ../../utils/macros_gen_opcodes, - ../../opcode_values, - ../../utils_numeric + stint, math, eth_common, # GasInt + ../utils/[macros_gen_opcodes, utils_numeric], + ./opcode_values # Gas Fee Schedule # Yellow Paper Appendix G - https://ethereum.github.io/yellowpaper/paper.pdf diff --git a/nimbus/vm/gas_meter.nim b/nimbus/vm/interpreter/gas_meter.nim similarity index 96% rename from nimbus/vm/gas_meter.nim rename to nimbus/vm/interpreter/gas_meter.nim index dd10c2351..5870527ca 100644 --- a/nimbus/vm/gas_meter.nim +++ b/nimbus/vm/interpreter/gas_meter.nim @@ -6,8 +6,8 @@ # at your option. This file may not be copied, modified, or distributed except according to those terms. import - strformat, - ../logging, ../errors, ../vm_types + strformat, eth_common, # GasInt + ../../logging, ../../errors, ../../vm_types proc newGasMeter*(startGas: GasInt): GasMeter = new(result) diff --git a/nimbus/opcode_table.nim b/nimbus/vm/interpreter/opcode_table.nim similarity index 93% rename from nimbus/opcode_table.nim rename to nimbus/vm/interpreter/opcode_table.nim index 923aec925..e9c2ec27e 100644 --- a/nimbus/opcode_table.nim +++ b/nimbus/vm/interpreter/opcode_table.nim @@ -6,11 +6,9 @@ # at your option. This file may not be copied, modified, or distributed except according to those terms. import - tables, - stint, logging, - vm / [gas_meter, stack, code_stream, memory, message], 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], - ./vm_types + tables, stint, + ../../vm_types, ./opcode_values, + opcodes_impl/[arithmetic, comparison, sha3, context, block_ops, stack_ops, duplication, swap, memory_ops, storage, flow, logging_ops, invalid, call, system_ops] const OpLogic*: Table[Op, proc(computation: var BaseComputation){.nimcall.}] = { diff --git a/nimbus/opcode_values.nim b/nimbus/vm/interpreter/opcode_values.nim similarity index 99% rename from nimbus/opcode_values.nim rename to nimbus/vm/interpreter/opcode_values.nim index dc5678676..4554e26fc 100644 --- a/nimbus/opcode_values.nim +++ b/nimbus/vm/interpreter/opcode_values.nim @@ -5,7 +5,7 @@ # * 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 ./utils/macros_gen_opcodes +import ../utils/macros_gen_opcodes fill_enum_holes: type diff --git a/nimbus/logic/arithmetic.nim b/nimbus/vm/interpreter/opcodes_impl/arithmetic.nim similarity index 94% rename from nimbus/logic/arithmetic.nim rename to nimbus/vm/interpreter/opcodes_impl/arithmetic.nim index 5212425d6..a778c70fa 100644 --- a/nimbus/logic/arithmetic.nim +++ b/nimbus/vm/interpreter/opcodes_impl/arithmetic.nim @@ -6,9 +6,7 @@ # at your option. This file may not be copied, modified, or distributed except according to those terms. import - ../constants, ../utils_numeric, ../computation, ../vm_types, - .. / vm / [gas_meter, stack], ../opcode, ../opcode_values, - helpers, stint, strutils + helpers, stint, strutils, ./impl_std_import proc add*(computation: var BaseComputation) = # Addition @@ -107,7 +105,7 @@ proc signextend*(computation: var BaseComputation) = if bits <= 31.u256: let testBit = bits.toInt * 8 + 7 let bitPos = (1 shl testBit) - let mask = bitPos - 1 + let mask = u256(bitPos - 1) if not (value and bitPos).isZero: res = value or (not mask) else: diff --git a/nimbus/logic/block.nim b/nimbus/vm/interpreter/opcodes_impl/block.nim similarity index 100% rename from nimbus/logic/block.nim rename to nimbus/vm/interpreter/opcodes_impl/block.nim diff --git a/nimbus/logic/block_ops.nim b/nimbus/vm/interpreter/opcodes_impl/block_ops.nim similarity index 91% rename from nimbus/logic/block_ops.nim rename to nimbus/vm/interpreter/opcodes_impl/block_ops.nim index a305061fe..1ed969942 100644 --- a/nimbus/logic/block_ops.nim +++ b/nimbus/vm/interpreter/opcodes_impl/block_ops.nim @@ -6,8 +6,7 @@ # at your option. This file may not be copied, modified, or distributed except according to those terms. import - times, - ../constants, ../errors, ../computation, ../vm_state, ../vm_types, .. / vm / [stack], stint + times, ./impl_std_import {.this: computation.} {.experimental.} diff --git a/nimbus/logic/call.nim b/nimbus/vm/interpreter/opcodes_impl/call.nim similarity index 91% rename from nimbus/logic/call.nim rename to nimbus/vm/interpreter/opcodes_impl/call.nim index 9ddb7bbdd..59eb943fe 100644 --- a/nimbus/logic/call.nim +++ b/nimbus/vm/interpreter/opcodes_impl/call.nim @@ -6,11 +6,15 @@ # at your option. This file may not be copied, modified, or distributed except according to those terms. import - strformat, eth_common, - ../constants, ../vm_types, ../errors, ../computation, ../opcode_values, ../logging, - .. / vm / [stack, memory, gas_meter, message], - .. / utils / [address, bytes], - stint + strformat, eth_common, stint, + # ./impl_std_import # Cannot do that due to recursive dependencies + # .../vm/interpreter/opcodes_impl/impl_std_import.nim imports .../vm/computation.nim + # .../vm/computation.nim imports .../vm/interpreter/opcodes_impl/call.nim + # .../vm/interpreter/opcodes_impl/call.nim imports .../vm/interpreter/opcodes_impl/impl_std_import.nim + ../../../constants, ../../../vm_types, ../../../errors, ../../../logging, + ../../../utils/bytes, + ../../computation, ../../stack, ../../memory, ../../message, + ../opcode_values, ../gas_meter, ../gas_costs type # TODO most of these are for gas handling @@ -68,7 +72,7 @@ method runLogic*(call: BaseCall, computation) = let senderBalance = 0.u256 let insufficientFunds = shouldTransferValue and senderBalance < value - let stackTooDeep = computation.msg.depth + 1 > constants.STACK_DEPTH_LIMIT + let stackTooDeep = computation.msg.depth + 1 > STACK_DEPTH_LIMIT if insufficientFunds or stackTooDeep: computation.returnData = "" diff --git a/nimbus/logic/comparison.nim b/nimbus/vm/interpreter/opcodes_impl/comparison.nim similarity index 91% rename from nimbus/logic/comparison.nim rename to nimbus/vm/interpreter/opcodes_impl/comparison.nim index 5280b077c..752414eb3 100644 --- a/nimbus/logic/comparison.nim +++ b/nimbus/vm/interpreter/opcodes_impl/comparison.nim @@ -6,8 +6,7 @@ # at your option. This file may not be copied, modified, or distributed except according to those terms. import - ../constants, ../utils_numeric, ../computation, ../vm/stack, ../vm_types, - helpers, stint + helpers, ./impl_std_import quasiBoolean(lt, `<`) # Lesser Comparison @@ -35,7 +34,7 @@ proc iszero*(computation: var BaseComputation) = proc notOp*(computation: var BaseComputation) = var value = computation.stack.popInt() - var res = constants.UINT_256_MAX - value + var res = UINT_256_MAX - value pushRes() # TODO: seems like there is an implementation or a comment issue diff --git a/nimbus/logic/context.nim b/nimbus/vm/interpreter/opcodes_impl/context.nim similarity index 95% rename from nimbus/logic/context.nim rename to nimbus/vm/interpreter/opcodes_impl/context.nim index a013ade85..00fc85ffa 100644 --- a/nimbus/logic/context.nim +++ b/nimbus/vm/interpreter/opcodes_impl/context.nim @@ -7,9 +7,7 @@ import strformat, - ../constants, ../vm_types, ../errors, ../utils_numeric, ../computation, ../vm_state, ../account, ../db/state_db, ../validation, - .. /vm/[stack, message, gas_meter, memory, code_stream], ../utils/[address, padding, bytes], stint, - ../opcode_values + ./impl_std_import proc balance*(computation: var BaseComputation) = let address = computation.stack.popAddress() diff --git a/nimbus/logic/duplication.nim b/nimbus/vm/interpreter/opcodes_impl/duplication.nim similarity index 92% rename from nimbus/logic/duplication.nim rename to nimbus/vm/interpreter/opcodes_impl/duplication.nim index 6ba577a79..8c172b3a6 100644 --- a/nimbus/logic/duplication.nim +++ b/nimbus/vm/interpreter/opcodes_impl/duplication.nim @@ -6,8 +6,7 @@ # at your option. This file may not be copied, modified, or distributed except according to those terms. import - macros, strformat, - ../vm_types, ../computation, ../vm/stack + macros, strformat, ./impl_std_import macro dupXX(position: static[int]): untyped = let name = ident(&"dup{position}") diff --git a/nimbus/logic/flow.nim b/nimbus/vm/interpreter/opcodes_impl/flow.nim similarity index 91% rename from nimbus/logic/flow.nim rename to nimbus/vm/interpreter/opcodes_impl/flow.nim index 46a635dba..ec5875b03 100644 --- a/nimbus/logic/flow.nim +++ b/nimbus/vm/interpreter/opcodes_impl/flow.nim @@ -6,9 +6,7 @@ # at your option. This file may not be copied, modified, or distributed except according to those terms. import - strformat, stint, - ../constants, ../vm_types, ../opcode_values, ../logging, ../errors, ../computation, .. /vm / [code_stream, stack] - + strformat, ./impl_std_import {.this: computation.} {.experimental.} diff --git a/nimbus/logic/helpers.nim b/nimbus/vm/interpreter/opcodes_impl/helpers.nim similarity index 91% rename from nimbus/logic/helpers.nim rename to nimbus/vm/interpreter/opcodes_impl/helpers.nim index 556d8f014..27f70ac67 100644 --- a/nimbus/logic/helpers.nim +++ b/nimbus/vm/interpreter/opcodes_impl/helpers.nim @@ -5,7 +5,7 @@ # * 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 macros +import macros, stint template pushRes*: untyped = computation.stack.push(res) @@ -22,8 +22,8 @@ macro quasiBoolean*(name: untyped, op: untyped, signed: untyped = nil, nonzero: actualLeftNode = ident("leftSigned") actualRightNode = ident("rightSigned") signedNode = quote: - let `actualLeftNode` = unsignedToSigned(`leftNode`) - let `actualRightNode` = unsignedToSigned(`rightNode`) + let `actualLeftNode` = cast[Int256](`leftNode`) + let `actualRightNode` = cast[Int256](`rightNode`) var test = if nonzero.isNil: quote: `op`(`actualLeftNode`, `actualRightNode`) diff --git a/nimbus/vm/interpreter/opcodes_impl/impl_std_import.nim b/nimbus/vm/interpreter/opcodes_impl/impl_std_import.nim new file mode 100644 index 000000000..3672d6b54 --- /dev/null +++ b/nimbus/vm/interpreter/opcodes_impl/impl_std_import.nim @@ -0,0 +1,22 @@ +# 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 + stint, stint/lenient_stint, + ../../../constants, ../../../vm_state, ../../../vm_types, ../../../vm_types, + ../../../errors, ../../../logging, ../../../utils/padding, ../../../utils/bytes, + ../../stack, ../../computation, ../../stack, ../../memory, ../../message, + ../../code_stream, ../../utils/utils_numeric, + ../opcode_values, ../gas_meter, ../gas_costs + +export + stint, lenient_stint, + constants, vm_state, vm_types, vm_types, + errors, logging, padding, bytes, + stack, computation, stack, memory, message, + code_stream, utils_numeric, + opcode_values, gas_meter, gas_costs diff --git a/nimbus/logic/invalid.nim b/nimbus/vm/interpreter/opcodes_impl/invalid.nim similarity index 92% rename from nimbus/logic/invalid.nim rename to nimbus/vm/interpreter/opcodes_impl/invalid.nim index 05ca3d202..05ec36aff 100644 --- a/nimbus/logic/invalid.nim +++ b/nimbus/vm/interpreter/opcodes_impl/invalid.nim @@ -6,7 +6,7 @@ # at your option. This file may not be copied, modified, or distributed except according to those terms. import - ../errors, ../vm_types, ../computation + ./impl_std_import proc invalidOp*(computation: var BaseComputation) = raise newException(InvalidInstruction, "Invalid opcode") diff --git a/nimbus/logic/logging_ops.nim b/nimbus/vm/interpreter/opcodes_impl/logging_ops.nim similarity index 87% rename from nimbus/logic/logging_ops.nim rename to nimbus/vm/interpreter/opcodes_impl/logging_ops.nim index d170a89aa..c7049543c 100644 --- a/nimbus/logic/logging_ops.nim +++ b/nimbus/vm/interpreter/opcodes_impl/logging_ops.nim @@ -7,9 +7,7 @@ import strformat, macros, - ../constants, ../errors, ../vm_types, ../computation, ../vm/[stack, memory, gas_meter, message], ../utils/bytes, - ../opcode_values, - stint + ./impl_std_import {.this: computation.} {.experimental.} @@ -53,19 +51,18 @@ macro logXX(topicCount: static[int]): untyped = result.body.add(topicCode) let OpName = ident(&"Log{topicCount}") - let logicCode = quote: + let logicCode = quote do: `computation`.gasMeter.consumeGas( `computation`.gasCosts[`OpName`].m_handler(`computation`.memory.len, `memPos`, `len`), reason="Memory expansion, Log topic and data gas cost") `computation`.memory.extend(`memPos`, `len`) let logData = `computation`.memory.read(`memPos`, `len`).toString `computation`.addLogEntry( - account=`computation`.msg.storageAddress, - topics=`topics`, - data=log_data) + account = `computation`.msg.storageAddress, + topics = `topics`, + data = log_data) result.body.add(logicCode) - # echo result.repr logXX(0) logXX(1) diff --git a/nimbus/logic/memory_ops.nim b/nimbus/vm/interpreter/opcodes_impl/memory_ops.nim similarity index 92% rename from nimbus/logic/memory_ops.nim rename to nimbus/vm/interpreter/opcodes_impl/memory_ops.nim index 267fa01b9..cc6e53efd 100644 --- a/nimbus/logic/memory_ops.nim +++ b/nimbus/vm/interpreter/opcodes_impl/memory_ops.nim @@ -6,10 +6,7 @@ # at your option. This file may not be copied, modified, or distributed except according to those terms. import - ../constants, ../computation, ../vm_types, ../vm/[stack, memory, gas_meter], .. /utils/[padding, bytes], - ../opcode_values, - stint - + ./impl_std_import {.this: computation.} {.experimental.} diff --git a/nimbus/logic/sha3.nim b/nimbus/vm/interpreter/opcodes_impl/sha3.nim similarity index 71% rename from nimbus/logic/sha3.nim rename to nimbus/vm/interpreter/opcodes_impl/sha3.nim index 0a76a3db2..fd05e0887 100644 --- a/nimbus/logic/sha3.nim +++ b/nimbus/vm/interpreter/opcodes_impl/sha3.nim @@ -6,21 +6,19 @@ # at your option. This file may not be copied, modified, or distributed except according to those terms. import - ../constants, ../utils_numeric, ../utils/[keccak, bytes], ../vm/[stack, memory, gas_meter], - ../computation, ../vm_types, ../opcode_values, - ./helpers, - stint + nimcrypto, + ./impl_std_import, ./helpers proc sha3op*(computation: var BaseComputation) = let (startPosition, size) = computation.stack.popInt(2) let (pos, len) = (startPosition.toInt, size.toInt) computation.gasMeter.consumeGas( - computation.gasCosts[Sha3].m_handler(computation.memory.len, pos, len), + computation.gasCosts[Op.Sha3].m_handler(computation.memory.len, pos, len), reason="SHA3: word gas cost" ) computation.memory.extend(pos, len) - var res = keccak("") # TODO: stub + var res = keccak256.digest("") # TODO: stub pushRes() diff --git a/nimbus/logic/stack_ops.nim b/nimbus/vm/interpreter/opcodes_impl/stack_ops.nim similarity index 89% rename from nimbus/logic/stack_ops.nim rename to nimbus/vm/interpreter/opcodes_impl/stack_ops.nim index 3f0ecdc94..fb491b4d3 100644 --- a/nimbus/logic/stack_ops.nim +++ b/nimbus/vm/interpreter/opcodes_impl/stack_ops.nim @@ -6,8 +6,7 @@ # at your option. This file may not be copied, modified, or distributed except according to those terms. import - strformat, macros, sequtils, - ../vm_types, ../constants, ../errors, ../computation, .. / vm / [stack, code_stream], .. / utils / [padding, bytes], stint + strformat, macros, ./impl_std_import {.this: computation.} {.experimental.} diff --git a/nimbus/logic/storage.nim b/nimbus/vm/interpreter/opcodes_impl/storage.nim similarity index 88% rename from nimbus/logic/storage.nim rename to nimbus/vm/interpreter/opcodes_impl/storage.nim index 85c406e87..18f97e26d 100644 --- a/nimbus/logic/storage.nim +++ b/nimbus/vm/interpreter/opcodes_impl/storage.nim @@ -6,11 +6,10 @@ # at your option. This file may not be copied, modified, or distributed except according to those terms. import - ../constants, ../vm_types, ../errors, ../computation, ../vm_state, - ../utils/header, - ../db/[db_chain, state_db], ../vm/[stack, gas_meter, message], - ../opcode_values, - strformat, stint + ./impl_std_import, strformat, + ../../../utils/header, + ../../../db/[db_chain, state_db] + {.this: computation.} {.experimental.} diff --git a/nimbus/logic/swap.nim b/nimbus/vm/interpreter/opcodes_impl/swap.nim similarity index 92% rename from nimbus/logic/swap.nim rename to nimbus/vm/interpreter/opcodes_impl/swap.nim index f457a7b26..ad4d52d55 100644 --- a/nimbus/logic/swap.nim +++ b/nimbus/vm/interpreter/opcodes_impl/swap.nim @@ -6,8 +6,7 @@ # at your option. This file may not be copied, modified, or distributed except according to those terms. import - macros, strformat, - ../vm_types, ../computation, ../vm/stack + macros, strformat, ./impl_std_import macro swapXX(position: static[int]): untyped = let name = ident(&"swap{position}") diff --git a/nimbus/logic/system_ops.nim b/nimbus/vm/interpreter/opcodes_impl/system_ops.nim similarity index 95% rename from nimbus/logic/system_ops.nim rename to nimbus/vm/interpreter/opcodes_impl/system_ops.nim index ffca08d70..21c56673d 100644 --- a/nimbus/logic/system_ops.nim +++ b/nimbus/vm/interpreter/opcodes_impl/system_ops.nim @@ -7,9 +7,7 @@ import strformat, - ../constants, ../vm_types, ../errors, ../computation, ../opcode, ../opcode_values, ../logging, ../vm_state, call, - .. / vm / [stack, gas_meter, memory, message], .. / utils / [address, hexadecimal, bytes], - ../opcode_values, + ./call, ./impl_std_import, stint, byteutils, eth_common {.this: computation.} @@ -70,7 +68,7 @@ method runLogic*(create: Create, computation) = let childMsg = computation.prepareChildMessage( gas=0, # TODO refactor gas - to=constants.CREATE_CONTRACT_ADDRESS, + to=CREATE_CONTRACT_ADDRESS, value=value, data=cast[seq[byte]](@[]), code=callData.toString, diff --git a/nimbus/vm/forks/vm_forks.nim b/nimbus/vm/interpreter/vm_forks.nim similarity index 91% rename from nimbus/vm/forks/vm_forks.nim rename to nimbus/vm/interpreter/vm_forks.nim index 5cfd7bfed..c189f8561 100644 --- a/nimbus/vm/forks/vm_forks.nim +++ b/nimbus/vm/interpreter/vm_forks.nim @@ -9,8 +9,8 @@ import ../../db/db_chain, ../../constants, ../../utils/header, ../base, - ./f20150730_frontier/frontier_vm, - ./f20161018_tangerine_whistle/tangerine_vm, + ../forks/f20150730_frontier/frontier_vm, + ../forks/f20161018_tangerine_whistle/tangerine_vm, stint # Note (mamy): refactoring is in progress (2018-05-23), this is redundant with diff --git a/nimbus/vm/memory.nim b/nimbus/vm/memory.nim index 49a14b263..be47fdfdf 100644 --- a/nimbus/vm/memory.nim +++ b/nimbus/vm/memory.nim @@ -7,7 +7,8 @@ import sequtils, stint, - ../constants, ../errors, ../logging, ../validation, ../utils_numeric, ../utils/bytes + ../constants, ../errors, ../logging, ../validation, ../utils/bytes, + ./utils/utils_numeric type Memory* = ref object @@ -57,3 +58,7 @@ proc write*(memory: var Memory, startPosition: Natural, value: openarray[byte]) template write*(memory: var Memory, startPosition: Natural, size: Natural, value: cstring) = memory.write(startPosition, value.toBytes) + # TODO ~ O(n^3): + # - there is a string allocation with $ (?) + # - then a conversion to seq (= new allocation) with toBytes + # - then writing to memory diff --git a/nimbus/vm/stack.nim b/nimbus/vm/stack.nim index 76c186a12..76d924465 100644 --- a/nimbus/vm/stack.nim +++ b/nimbus/vm/stack.nim @@ -7,7 +7,7 @@ import strformat, strutils, sequtils, macros, rlp, eth_common, nimcrypto, - ../errors, ../validation, ../utils_numeric, ../constants, stint, ../logging, .. / utils / bytes + ../errors, ../validation, ./utils/utils_numeric, ../constants, stint, ../logging, .. / utils / bytes type Stack* = ref object of RootObj @@ -99,6 +99,8 @@ proc swap*(stack: var Stack, position: int) = raise newException(InsufficientStack, &"Insufficient stack items for SWAP{position}") +template getint(x: int): int = x + proc dup*(stack: var Stack, position: int | UInt256) = ## Perform a DUP operation on the stack let position = position.getInt diff --git a/nimbus/utils/macros_gen_opcodes.nim b/nimbus/vm/utils/macros_gen_opcodes.nim similarity index 100% rename from nimbus/utils/macros_gen_opcodes.nim rename to nimbus/vm/utils/macros_gen_opcodes.nim diff --git a/nimbus/utils_numeric.nim b/nimbus/vm/utils/utils_numeric.nim similarity index 75% rename from nimbus/utils_numeric.nim rename to nimbus/vm/utils/utils_numeric.nim index 0a20ccd6f..804f00b10 100644 --- a/nimbus/utils_numeric.nim +++ b/nimbus/vm/utils/utils_numeric.nim @@ -5,14 +5,12 @@ # * 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 stint, constants, strformat, strutils, sequtils, endians, macros, utils / padding, rlp +import + stint, strformat, strutils, sequtils, endians, macros, rlp, + ../../constants, ../../utils/padding # some methods based on py-evm utils/numeric -proc intToBigEndian*(value: UInt256): Bytes {.deprecated.} = - result = newSeq[byte](32) - result[0 .. ^1] = value.toByteArrayBE() - proc bigEndianToInt*(value: openarray[byte]): UInt256 = if value.len == 32: readUintBE[256](value) @@ -22,14 +20,6 @@ proc bigEndianToInt*(value: openarray[byte]): UInt256 = proc log256*(value: UInt256): Natural = (255 - value.countLeadingZeroBits) div 8 # Compilers optimize to `shr 3` -proc unsignedToSigned*(value: UInt256): Int256 = - 0.i256 - # TODO Remove stub (used in quasiBoolean for signed comparison) - -proc signedToUnsigned*(value: Int256): UInt256 = - 0.u256 - # TODO Remove stub (used in quasiBoolean for signed comparison) - proc unsignedToPseudoSigned*(value: UInt256): UInt256 = result = value if value > INT_256_MAX_AS_UINT256: diff --git a/nimbus/vm_state.nim b/nimbus/vm_state.nim index 066fa955b..01d181129 100644 --- a/nimbus/vm_state.nim +++ b/nimbus/vm_state.nim @@ -9,7 +9,7 @@ import macros, strformat, tables, stint, eth_common, ./logging, ./constants, ./errors, ./transaction, ./db/[db_chain, state_db], - ./utils/[state, header] + ./utils/header type BaseVMState* = ref object of RootObj diff --git a/nimbus/vm_state_transactions.nim b/nimbus/vm_state_transactions.nim index b1b016bd4..5322bc178 100644 --- a/nimbus/vm_state_transactions.nim +++ b/nimbus/vm_state_transactions.nim @@ -7,7 +7,8 @@ import strformat, tables, - logging, constants, errors, computation, transaction, vm_types, vm_state, block_types, db / db_chain, utils / [state, header] + ./logging, ./constants, ./errors, ./vm/computation, + ./transaction, ./vm_types, ./vm_state, ./block_types, ./db/db_chain, ./utils/header method executeTransaction(vmState: var BaseVMState, transaction: BaseTransaction): (BaseComputation, BlockHeader) {.base.}= # Execute the transaction in the vm diff --git a/nimbus/vm_types.nim b/nimbus/vm_types.nim index 5f8e2e2fc..5a4c3c518 100644 --- a/nimbus/vm_types.nim +++ b/nimbus/vm_types.nim @@ -6,13 +6,11 @@ # at your option. This file may not be copied, modified, or distributed except according to those terms. import - tables, - constants, vm_state, - opcode_values, stint, eth_common, - vm / [code_stream, memory, stack, forks/gas_costs], - ./logging + tables, stint, eth_common, + ./constants, ./vm_state, ./logging, + ./vm/[memory, stack, code_stream], + ./vm/interpreter/[gas_costs, opcode_values] # TODO - will be hidden at a lower layer -export GasInt, gas_costs type BaseComputation* = ref object of RootObj @@ -32,7 +30,7 @@ type accountsToDelete*: Table[EthAddress, EthAddress] opcodes*: Table[Op, proc(computation: var BaseComputation){.nimcall.}] precompiles*: Table[string, Opcode] - gasCosts*: GasCosts # TODO - avoid allocating memory for this const + gasCosts*: GasCosts # TODO - will be hidden at a lower layer Error* = ref object info*: string diff --git a/tests/all_tests.nim b/tests/all_tests.nim index 711408085..514013e21 100644 --- a/tests/all_tests.nim +++ b/tests/all_tests.nim @@ -10,5 +10,4 @@ import ./test_code_stream, ./test_memory, ./test_stack, ./test_opcode - # ./test_vm # ./test_vm_json diff --git a/tests/fixtures.nim b/tests/fixtures.nim deleted file mode 100644 index 39fa54433..000000000 --- a/tests/fixtures.nim +++ /dev/null @@ -1,38 +0,0 @@ -# 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 - unittest, strformat, tables, times, - stint, eth_keys, eth_common, - ../nimbus/[constants, chain, vm/base, vm/forks/f20150730_frontier/frontier_vm, utils/header, utils/address, db/db_chain, db/backends/memory_backend] - -proc chainWithoutBlockValidation*: Chain = - result = configureChain("TestChain", GENESIS_BLOCK_NUMBER, vmkFrontier, false, false) - let privateKey = initPrivateKey("45a915e4d060149eb4365960e6a7a45f334393093061116b197e3240065ff2d8") - let fundedAddr = privateKey.getPublicKey.toCanonicalAddress - let initialBalance = 100_000_000 - let genesisParams = GenesisParams( - blockNumber: GENESIS_BLOCK_NUMBER, - difficulty: GENESIS_DIFFICULTY, - gasLimit: GENESIS_GAS_LIMIT, - parentHash: GENESIS_PARENT_HASH, - coinbase: GENESIS_COINBASE, - nonce: GENESIS_NONCE, - mixHash: GENESIS_MIX_HASH, - extraData: GENESIS_EXTRA_DATA, - timestamp: fromUnix 1501851927, - stateRoot: "9d354f9b5ba851a35eced279ef377111387197581429cfcc7f744ef89a30b5d4".toDigest) - let genesisState = {"fundedAddr": FundedAddress(balance: initialBalance.int256, nonce: 0, code: "")}.toTable() - result = fromGenesis( - result, - newBaseChainDB(newMemoryDB()), - genesisParams, - genesisState) - result.fundedAddress = fundedAddr - result.fundedAddressInitialBalance = initialBalance - result.fundedAddressPrivateKey = privateKey - diff --git a/tests/test_code_stream.nim b/tests/test_code_stream.nim index 3b33d26ac..5270de9e0 100644 --- a/tests/test_code_stream.nim +++ b/tests/test_code_stream.nim @@ -6,7 +6,7 @@ # at your option. This file may not be copied, modified, or distributed except according to those terms. import unittest, strutils, sequtils, - ../nimbus/opcode_values, ../nimbus/vm/code_stream + ../nimbus/vm/interpreter suite "parse bytecode": test "accepts bytes": diff --git a/tests/test_gas_meter.nim b/tests/test_gas_meter.nim index 3781740d4..9ad8e7aa5 100644 --- a/tests/test_gas_meter.nim +++ b/tests/test_gas_meter.nim @@ -5,9 +5,9 @@ # * 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 unittest, macros, strformat, strutils, sequtils, +import unittest, macros, strformat, stint, - ../nimbus/[constants, opcode_values, errors, logging, vm_types, vm/gas_meter] + ../nimbus/[vm_types, errors, logging, vm/interpreter] # TODO: quicktest # PS: parametrize can be easily immitated, but still quicktests would be even more useful diff --git a/tests/test_helpers.nim b/tests/test_helpers.nim index 9b1d55168..472e35805 100644 --- a/tests/test_helpers.nim +++ b/tests/test_helpers.nim @@ -8,9 +8,9 @@ import os, macros, json, strformat, strutils, parseutils, ospaths, tables, stint, byteutils, eth_common, eth_keys, - ../nimbus/utils/[hexadecimal, address, padding], - ../nimbus/[chain, vm_state, constants], - ../nimbus/db/[db_chain, state_db], ../nimbus/vm/forks/f20150730_frontier/frontier_vm, + ../nimbus/utils/[address, padding], + ../nimbus/[vm_state, constants], + ../nimbus/db/[db_chain, state_db], ../nimbus/vm/base, ../nimbus/transaction type diff --git a/tests/test_memory.nim b/tests/test_memory.nim index c33c8b5ab..c8e4efce2 100644 --- a/tests/test_memory.nim +++ b/tests/test_memory.nim @@ -5,9 +5,9 @@ # * 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 unittest, macros, strformat, strutils, sequtils, +import unittest, sequtils, stint, - ../nimbus/[constants, opcode_values, errors, vm/memory] + ../nimbus/[constants, errors, vm/memory] proc memory32: Memory = result = newMemory() diff --git a/tests/test_opcode.nim b/tests/test_opcode.nim index ca738c8ec..ab2c9eb75 100644 --- a/tests/test_opcode.nim +++ b/tests/test_opcode.nim @@ -7,14 +7,13 @@ import unittest, stint, tables, parseutils, - ../nimbus/[constants, vm_types, errors, logging], - ../nimbus/[chain, vm_state, computation, opcode, opcode_table], - ../nimbus/[utils/header, utils/padding], - ../nimbus/vm/[gas_meter, message, code_stream, stack], - ../nimbus/vm/forks/vm_forks, + ../nimbus/[constants, vm_types, logging], + ../nimbus/vm/interpreter, + ../nimbus/utils/header, ../nimbus/db/[db_chain, state_db, backends/memory_backend], - test_helpers + ./test_helpers +from eth_common import GasInt proc testCode(code: string, initialGas: GasInt, blockNum: UInt256): BaseComputation = let header = BlockHeader(blockNumber: blockNum) diff --git a/tests/test_stack.nim b/tests/test_stack.nim index b43044576..587ae65d7 100644 --- a/tests/test_stack.nim +++ b/tests/test_stack.nim @@ -5,9 +5,8 @@ # * 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 unittest, macros, strformat, strutils, sequtils, - stint, - ../nimbus/[constants, opcode_values, errors, utils_numeric, vm/stack, utils/bytes, utils/padding] +import unittest, stint, + ../nimbus/[constants, errors, vm/interpreter, utils/bytes] template testPush(value: untyped, expected: untyped): untyped = @@ -36,9 +35,6 @@ suite "stack": expect(FullStack): stack.push(1025) - - - test "dup does not allow stack to exceed 1024": var stack = newStack() stack.push(1.u256) diff --git a/tests/test_vm.nim b/tests/test_vm.nim deleted file mode 100644 index a56a5b0d0..000000000 --- a/tests/test_vm.nim +++ /dev/null @@ -1,43 +0,0 @@ -# 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 - unittest, stint, eth_common, - ./test_helpers, ./fixtures, - ../nimbus/[db/backends/memory_backend, db/state_db, chain, constants, utils/hexadecimal, vm_state], - ../nimbus/[vm/base, computation] - -import typetraits - -suite "VM": - test "Apply transaction with no validation": - var - chain = chainWithoutBlockValidation() - vm = chain.getVM() - # txIdx = len(vm.`block`.transactions) # Can't take len of a runtime field - let - recipient = parseAddress("0xa94f5374fce5edbc8e2a8697c15331677e6ebf0c") - amount = 100.u256 - ethaddr_from = chain.fundedAddress - tx = newTransaction(vm, ethaddr_from, recipient, amount, chain.fundedAddressPrivateKey) - # (computation, _) = vm.applyTransaction(tx) - # accessLogs = computation.vmState.accessLogs - - # check(not computation.isError) - - let - # txGas = tx.gasPrice * constants.GAS_TX - state_db = vm.state.readOnlyStateDB - b = vm.`block` - - echo state_db.getBalance(ethaddr_from).type.name - - # check: - # state_db.getBalance(ethaddr_from) == chain.fundedAddressInitialBalance - amount - txGas # TODO: this really should be i256 - # state_db.getBalance(recipient) == amount - # b.transactions[txIdx] == tx - # b.header.gasUsed == constants.GAS_TX diff --git a/tests/test_vm_json.nim b/tests/test_vm_json.nim index 9c533e813..9f669eeaf 100644 --- a/tests/test_vm_json.nim +++ b/tests/test_vm_json.nim @@ -9,14 +9,12 @@ import unittest, strformat, strutils, sequtils, tables, stint, json, ospaths, times, ./test_helpers, ../nimbus/[constants, errors, logging], - ../nimbus/[chain, vm_state, computation, opcode, vm_types], + ../nimbus/[vm_state, vm_types], ../nimbus/utils/[header, padding], - ../nimbus/vm/[gas_meter, message, code_stream, stack], - ../nimbus/vm/forks/vm_forks, ../nimbus/db/[db_chain, state_db, backends/memory_backend], + ../nimbus/vm/interpreter, + ../nimbus/db/[db_chain, state_db, backends/memory_backend], eth_common -from ../nimbus/opcode_table import OpLogic - proc testFixture(fixtures: JsonNode, testStatusIMPL: var TestStatus) suite "vm json tests": @@ -47,7 +45,7 @@ proc testFixture(fixtures: JsonNode, testStatusIMPL: var TestStatus) = let message = newMessage( to = fexec{"address"}.getStr.parseAddress, sender = fexec{"caller"}.getStr.parseAddress, - value = fexec{"value"}.getHexadecimalInt.u256, + value = cast[uint](fexec{"value"}.getHexadecimalInt).u256, # Cast workaround for negative value data = fexec{"data"}.getStr.mapIt(it.byte), code = code, gas = fexec{"gas"}.getHexadecimalInt,