From e3be8ca30aa4b1969c6baa948135abe161101831 Mon Sep 17 00:00:00 2001 From: Yuriy Glukhov Date: Wed, 29 Aug 2018 11:49:01 +0300 Subject: [PATCH] Separate Chain from ChainDB --- nimbus/db/db_chain.nim | 34 +++---------------- nimbus/nimbus.nim | 17 +++++----- nimbus/p2p/chain.nim | 51 ++++++++++++++++++++++++++++ nimbus/rpc/p2p.nim | 77 +++++++++++------------------------------- tests/test_rpc.nim | 4 +-- 5 files changed, 86 insertions(+), 97 deletions(-) create mode 100644 nimbus/p2p/chain.nim diff --git a/nimbus/db/db_chain.nim b/nimbus/db/db_chain.nim index 6dc6115ec..b956b82b7 100644 --- a/nimbus/db/db_chain.nim +++ b/nimbus/db/db_chain.nim @@ -11,7 +11,7 @@ import ../errors, ../block_types, ../utils/header, ../constants, ./storage_types.nim type - BaseChainDB* = ref object of AbstractChainDB + BaseChainDB* = ref object db*: TrieDatabaseRef # TODO db*: JournalDB @@ -80,6 +80,9 @@ proc getBlockHeader*(self: BaseChainDB; n: BlockNumber): BlockHeader = ## Raises BlockNotFound error if the block is not in the DB. self.getBlockHeader(self.getBlockHash(n)) +proc getBlockBody*(self: BaseChainDB, h: Hash256, output: var BlockBody): bool = + discard # TODO: + proc getScore*(self: BaseChainDB; blockHash: Hash256): int = rlp.decode(self.db.get(blockHashToScoreKey(blockHash).toOpenArray).toRange, int) @@ -250,34 +253,6 @@ proc persistBlockToDb*(self: BaseChainDB; blk: Block) = proc getStateDb*(self: BaseChainDB; stateRoot: Hash256; readOnly: bool = false): AccountStateDB = result = newAccountStateDB(self.db, stateRoot) -method genesisHash*(db: BaseChainDB): KeccakHash = - db.getBlockHash(0.toBlockNumber) - -method getBlockHeader*(db: BaseChainDB, b: HashOrNum): BlockHeaderRef = - var h: BlockHeader - var ok = case b.isHash - of true: - db.getBlockHeader(b.hash, h) - else: - db.getBlockHeader(b.number, h) - - if ok: - result.new() - result[] = h - -method getBestBlockHeader*(self: BaseChainDB): BlockHeaderRef = - result.new() - result[] = self.getCanonicalHead() - -method getSuccessorHeader*(db: BaseChainDB, h: BlockHeader): BlockHeaderRef = - let n = h.blockNumber + 1 - var r: BlockHeader - if db.getBlockHeader(n, r): - result.new() - result[] = r - -method getBlockBody*(db: BaseChainDB, blockHash: KeccakHash): BlockBodyRef = - result = nil # Deprecated: proc getBlockHeaderByHash*(self: BaseChainDB; blockHash: Hash256): BlockHeader {.deprecated.} = @@ -288,3 +263,4 @@ proc lookupBlockHash*(self: BaseChainDB; n: BlockNumber): Hash256 {.deprecated.} proc getCanonicalBlockHeaderByNumber*(self: BaseChainDB; n: BlockNumber): BlockHeader {.deprecated.} = self.getBlockHeader(n) + diff --git a/nimbus/nimbus.nim b/nimbus/nimbus.nim index a11eb3fa5..378344459 100644 --- a/nimbus/nimbus.nim +++ b/nimbus/nimbus.nim @@ -11,7 +11,7 @@ import os, strutils, net, eth_common, db/[storage_types, db_chain], asyncdispatch2, json_rpc/rpcserver, eth_keys, eth_p2p, eth_p2p/rlpx_protocols/[eth, les], - config, genesis, rpc/[common, p2p], + config, genesis, rpc/[common, p2p], p2p/chain, eth_trie const UseSqlite = true @@ -85,10 +85,10 @@ proc start(): NimbusObject = nimbus.ethNode = newEthereumNode(keypair, address, conf.net.networkId, nil, nimbusClientId) - nimbus.ethNode.chain = chainDB + nimbus.ethNode.chain = newChain(chainDB) if RpcFlags.Enabled in conf.rpc.flags: - setupP2PRpc(nimbus.ethNode, nimbus.rpcServer) + setupEthRpc(nimbus.ethNode, chainDB, nimbus.rpcServer) ## Starting servers nimbus.state = Starting @@ -101,10 +101,9 @@ proc start(): NimbusObject = waitFor nimbus.ethNode.connectToNetwork(conf.net.bootNodes) # TODO: temp code until the CLI/RPC interface is fleshed out - if os.getenv("START_SYNC") == "1": - let status = waitFor nimbus.ethNode.fastBlockchainSync() - if status != syncSuccess: - echo "Block sync failed: ", status + let status = waitFor nimbus.ethNode.fastBlockchainSync() + if status != syncSuccess: + echo "Block sync failed: ", status nimbus.state = Running result = nimbus @@ -119,8 +118,8 @@ proc process*(nimbus: NimbusObject) = proc signalBreak(udata: pointer) = nimbus.state = Stopping # Adding SIGINT, SIGTERM handlers - discard addSignal(SIGINT, signalBreak) - discard addSignal(SIGTERM, signalBreak) + # discard addSignal(SIGINT, signalBreak) + # discard addSignal(SIGTERM, signalBreak) # Main loop while nimbus.state == Running: diff --git a/nimbus/p2p/chain.nim b/nimbus/p2p/chain.nim new file mode 100644 index 000000000..ae4abecc5 --- /dev/null +++ b/nimbus/p2p/chain.nim @@ -0,0 +1,51 @@ +import ../db/db_chain, eth_common, chronicles, ../vm_state, ../vm_types, ../transaction, + ../vm/[computation, interpreter_dispatch, message] + + +type + Chain* = ref object of AbstractChainDB + db: BaseChainDB + +proc newChain*(db: BaseChainDB): Chain = + result.new + result.db = db + +method genesisHash*(c: Chain): KeccakHash = + c.db.getBlockHash(0.toBlockNumber) + +method getBlockHeader*(c: Chain, b: HashOrNum, output: var BlockHeader): bool = + case b.isHash + of true: + c.db.getBlockHeader(b.hash, output) + else: + c.db.getBlockHeader(b.number, output) + +method getBestBlockHeader*(c: Chain): BlockHeader = + c.db.getCanonicalHead() + +method getSuccessorHeader*(c: Chain, h: BlockHeader, output: var BlockHeader): bool = + let n = h.blockNumber + 1 + c.db.getBlockHeader(n, output) + +method getBlockBody*(c: Chain, blockHash: KeccakHash): BlockBodyRef = + result = nil + +method persistBlocks*(c: Chain, headers: openarray[BlockHeader], bodies: openarray[BlockBody]) = + # Run the VM here + assert(headers.len == bodies.len) + + for i in 0 ..< headers.len: + let head = c.db.getCanonicalHead() + # assert(head.blockNumber == headers[i].blockNumber - 1) + let vmState = newBaseVMState(head, c.db) + if bodies[i].transactions.len != 0: + # echo "block: ", headers[i].blockNumber + for t in bodies[i].transactions: + var msg: Message + # echo "trns: ", t + + # let msg = newMessage(t.gasLimit, t.gasPrice, t.to, t.getSender, + + # let c = newBaseComputation(vmState, + + discard diff --git a/nimbus/rpc/p2p.nim b/nimbus/rpc/p2p.nim index 22a57e454..d1bb97a3d 100644 --- a/nimbus/rpc/p2p.nim +++ b/nimbus/rpc/p2p.nim @@ -47,15 +47,17 @@ func headerFromTag(chain:BaseChainDB, blockTag: string): BlockHeader = let blockNum = stint.fromHex(UInt256, tag) result = chain.getBlockHeader(blockNum) -proc setupP2PRPC*(node: EthereumNode, rpcsrv: RpcServer) = - template chain: untyped = BaseChainDB(node.chain) # TODO: Sensible casting - +proc setupEthRpc*(node: EthereumNode, chain: BaseChainDB, rpcsrv: RpcServer) = proc accountDbFromTag(tag: string, readOnly = true): AccountStateDb = let header = chain.headerFromTag(tag) vmState = newBaseVMState(header, chain) result = vmState.chaindb.getStateDb(vmState.blockHeader.hash, readOnly) + proc getBlockBody(hash: KeccakHash): BlockBody = + if not chain.getBlockBody(hash, result): + raise newException(ValueError, "Cannot find hash") + rpcsrv.rpc("net_version") do() -> uint: let conf = getConfiguration() result = conf.net.networkId @@ -144,23 +146,15 @@ proc setupP2PRPC*(node: EthereumNode, rpcsrv: RpcServer) = ## data: hash of a block ## Returns integer of the number of transactions in this block. var hashData = strToHash(data.string) - let body = chain.getBlockBody(hashData) - if body == nil: - raise newException(ValueError, "Cannot find hash") - result = body.transactions.len + result = getBlockBody(hashData).transactions.len rpcsrv.rpc("eth_getBlockTransactionCountByNumber") do(quantityTag: string) -> int: ## Returns the number of transactions in a block matching the given block number. ## ## data: integer of a block number, or the string "earliest", "latest" or "pending", as in the default block parameter. ## Returns integer of the number of transactions in this block. - let - header = chain.headerFromTag(quantityTag) - accountDb = accountDbFromTag(quantityTag) - body = chain.getBlockBody(header.hash) - if body == nil: - raise newException(ValueError, "Cannot find hash") - result = body.transactions.len + let header = chain.headerFromTag(quantityTag) + result = getBlockBody(header.hash).transactions.len rpcsrv.rpc("eth_getUncleCountByBlockHash") do(data: HexDataStr) -> int: ## Returns the number of uncles in a block from a block matching the given block hash. @@ -168,22 +162,15 @@ proc setupP2PRPC*(node: EthereumNode, rpcsrv: RpcServer) = ## data: hash of a block. ## Returns integer of the number of uncles in this block. var hashData = strToHash(data.string) - let body = chain.getBlockBody(hashData) - if body == nil: - raise newException(ValueError, "Cannot find hash") - result = body.uncles.len + result = getBlockBody(hashData).uncles.len rpcsrv.rpc("eth_getUncleCountByBlockNumber") do(quantityTag: string) -> int: ## Returns the number of uncles in a block from a block matching the given block number. ## ## quantityTag: integer of a block number, or the string "latest", "earliest" or "pending", see the default block parameter. ## Returns integer of uncles in this block. - let - header = chain.headerFromTag(quantityTag) - body = chain.getBlockBody(header.hash) - if body == nil: - raise newException(ValueError, "Cannot find hash") - result = body.uncles.len + let header = chain.headerFromTag(quantityTag) + result = getBlockBody(header.hash).uncles.len rpcsrv.rpc("eth_getCode") do(data: EthAddressStr, quantityTag: string) -> HexDataStr: ## Returns code at a given address. @@ -243,7 +230,7 @@ proc setupP2PRPC*(node: EthereumNode, rpcsrv: RpcServer) = ## Returns the amount of gas used. discard - func populateBlockObject(header: BlockHeader, blockBody: BlockBodyRef): BlockObject = + func populateBlockObject(header: BlockHeader, blockBody: BlockBody): BlockObject = result.number = new BlockNumber result.number[] = header.blockNumber result.hash = new Hash256 @@ -286,10 +273,7 @@ proc setupP2PRPC*(node: EthereumNode, rpcsrv: RpcServer) = let h = data.string.strToHash header = chain.getBlockHeader(h) - body = chain.getBlockBody(h) - if body == nil: - raise newException(ValueError, "Cannot find hash") - populateBlockObject(header, body) + populateBlockObject(header, getBlockBody(h)) rpcsrv.rpc("eth_getBlockByNumber") do(quantityTag: string, fullTransactions: bool) -> BlockObject: ## Returns information about a block by block number. @@ -299,10 +283,7 @@ proc setupP2PRPC*(node: EthereumNode, rpcsrv: RpcServer) = ## Returns BlockObject or nil when no block was found. let header = chain.headerFromTag(quantityTag) - body = chain.getBlockBody(header.hash) - if body == nil: - raise newException(ValueError, "Cannot find hash") - populateBlockObject(header, body) + populateBlockObject(header, getBlockBody(header.hash)) func populateTransactionObject(transaction: Transaction, txHash: Hash256, txCount: UInt256, txIndex: int, blockHeader: BlockHeader, gas: int64): TransactionObject = result.hash = txHash @@ -332,11 +313,7 @@ proc setupP2PRPC*(node: EthereumNode, rpcsrv: RpcServer) = txDetails = chain.getTransactionKey(h) header = chain.getBlockHeader(txDetails.blockNumber) blockHash = chain.getBlockHash(txDetails.blockNumber) - body = chain.getBlockBody(blockHash) - if body == nil: - raise newException(ValueError, "Cannot find hash") - let - transaction = body.transactions[txDetails.index] + transaction = getBlockBody(blockHash).transactions[txDetails.index] vmState = newBaseVMState(header, chain) addressDb = vmState.chaindb.getStateDb(blockHash, true) # TODO: Get/calculate address for this transaction @@ -355,12 +332,8 @@ proc setupP2PRPC*(node: EthereumNode, rpcsrv: RpcServer) = ## Returns requested transaction information. let blockHash = data.string.strToHash() - body = chain.getBlockBody(blockHash) - if body == nil: - raise newException(ValueError, "Cannot find hash") - let header = chain.getBlockHeader(blockHash) - transaction = body.transactions[quantity] + transaction = getBlockBody(blockHash).transactions[quantity] vmState = newBaseVMState(header, chain) addressDb = vmState.chaindb.getStateDb(blockHash, true) # TODO: Get/calculate address for this transaction @@ -380,11 +353,7 @@ proc setupP2PRPC*(node: EthereumNode, rpcsrv: RpcServer) = let header = chain.headerFromTag(quantityTag) blockHash = header.hash - body = chain.getBlockBody(blockHash) - if body == nil: - raise newException(ValueError, "Cannot find hash") - let - transaction = body.transactions[quantity] + transaction = getBlockBody(blockHash).transactions[quantity] vmState = newBaseVMState(header, chain) addressDb = vmState.chaindb.getStateDb(blockHash, true) # TODO: Get/calculate address for this transaction @@ -429,9 +398,7 @@ proc setupP2PRPC*(node: EthereumNode, rpcsrv: RpcServer) = h = data.string.strToHash() txDetails = chain.getTransactionKey(h) header = chain.getBlockHeader(txDetails.blockNumber) - body = chain.getBlockBody(h) - if body == nil: - raise newException(ValueError, "Cannot find hash") + body = getBlockBody(header.hash) var idx = 0 for receipt in chain.getReceipts(header, Receipt): if idx == txDetails.index: @@ -446,9 +413,7 @@ proc setupP2PRPC*(node: EthereumNode, rpcsrv: RpcServer) = ## Returns BlockObject or nil when no block was found. let blockHash = data.string.strToHash() - body = chain.getBlockBody(blockHash) - if body == nil: - raise newException(ValueError, "Cannot find hash") + body = getBlockBody(blockHash) if quantity < 0 or quantity >= body.uncles.len: raise newException(ValueError, "Uncle index out of range") let uncle = body.uncles[quantity] @@ -462,9 +427,7 @@ proc setupP2PRPC*(node: EthereumNode, rpcsrv: RpcServer) = ## Returns BlockObject or nil when no block was found. let header = chain.headerFromTag(quantityTag) - body = chain.getBlockBody(header.hash) - if body == nil: - raise newException(ValueError, "Cannot find hash") + body = getBlockBody(header.hash) if quantity < 0 or quantity >= body.uncles.len: raise newException(ValueError, "Uncle index out of range") let uncle = body.uncles[quantity] diff --git a/tests/test_rpc.nim b/tests/test_rpc.nim index 3c81e6c13..373ec4a4f 100644 --- a/tests/test_rpc.nim +++ b/tests/test_rpc.nim @@ -60,7 +60,7 @@ proc doTests = rpcServer = newRpcSocketServer(["localhost:8545"]) client = newRpcSocketClient() setupCommonRpc(rpcServer) - setupP2PRpc(ethNode, rpcServer) + setupEthRpc(ethNode, chain, rpcServer) # Begin tests rpcServer.start() @@ -79,4 +79,4 @@ proc doTests = rpcServer.stop() rpcServer.close() -doTests() \ No newline at end of file +doTests()