From eabacb0a331f268269d74183a7074217b5991647 Mon Sep 17 00:00:00 2001 From: jangko Date: Wed, 10 Jun 2020 12:54:15 +0700 Subject: [PATCH] allow nimbus to read geth database --- nimbus/db/accounts_cache.nim | 20 ++++++++++++++------ nimbus/db/geth_db.nim | 35 +++++++++++++++++++++++++++++++++++ nimbus/p2p/executor.nim | 5 ++++- nimbus/tracer.nim | 11 +++++++++-- nimbus/vm_state.nim | 8 +++++++- 5 files changed, 69 insertions(+), 10 deletions(-) create mode 100644 nimbus/db/geth_db.nim diff --git a/nimbus/db/accounts_cache.nim b/nimbus/db/accounts_cache.nim index 157f4e977..5179c6e48 100644 --- a/nimbus/db/accounts_cache.nim +++ b/nimbus/db/accounts_cache.nim @@ -222,7 +222,10 @@ proc persistMode(acc: RefAccount): PersistMode = proc persistCode(acc: RefAccount, db: TrieDatabaseRef) = if acc.code.len != 0: - db.put(contractHashKey(acc.account.codeHash).toOpenArray, acc.code) + when defined(geth): + db.put(acc.account.codeHash.data, acc.code) + else: + db.put(contractHashKey(acc.account.codeHash).toOpenArray, acc.code) proc persistStorage(acc: RefAccount, db: TrieDatabaseRef) = if acc.overlayStorage.len == 0: @@ -283,7 +286,11 @@ proc getCode*(ac: AccountsCache, address: EthAddress): seq[byte] = if CodeLoaded in acc.flags or CodeChanged in acc.flags: result = acc.code else: - let data = ac.db.get(contractHashKey(acc.account.codeHash).toOpenArray) + when defined(geth): + let data = ac.db.get(acc.account.codeHash.data) + else: + let data = ac.db.get(contractHashKey(acc.account.codeHash).toOpenArray) + acc.code = data acc.flags.incl CodeLoaded result = acc.code @@ -411,10 +418,11 @@ iterator storage*(ac: AccountsCache, address: EthAddress): (UInt256, UInt256) = let storageRoot = acc.account.storageRoot var trie = initHexaryTrie(ac.db, storageRoot) - for slot, value in trie: - if slot.len != 0: - var keyData = ac.db.get(slotHashToSlotKey(slot).toOpenArray) - yield (rlp.decode(keyData, UInt256), rlp.decode(value, UInt256)) + for slotHash, value in trie: + if slotHash.len == 0: continue + let keyData = ac.db.get(slotHashToSlotKey(slotHash).toOpenArray) + if keyData.len == 0: continue + yield (rlp.decode(keyData, UInt256), rlp.decode(value, UInt256)) proc getStorageRoot*(ac: AccountsCache, address: EthAddress): Hash256 = # beware that if the account not persisted, diff --git a/nimbus/db/geth_db.nim b/nimbus/db/geth_db.nim new file mode 100644 index 000000000..985a9021a --- /dev/null +++ b/nimbus/db/geth_db.nim @@ -0,0 +1,35 @@ +import eth/[rlp, common], db_chain, eth/trie/db + +const + headerPrefix = 'h'.byte # headerPrefix + num (uint64 big endian) + hash -> header + headerHashSuffix = 'n'.byte # headerPrefix + num (uint64 big endian) + headerHashSuffix -> hash + blockBodyPrefix = 'b'.byte # blockBodyPrefix + num (uint64 big endian) + hash -> block body + +proc headerHash*(db: BaseChainDB, number: uint64): Hash256 = + var key: array[10, byte] + key[0] = headerPrefix + key[1..8] = toBytesBE(number)[0..^1] + key[^1] = headerHashSuffix + let res = db.db.get(key) + doAssert(res.len == 32) + result.data[0..31] = res[0..31] + +proc blockHeader*(db: BaseChainDB, hash: Hash256, number: uint64): BlockHeader = + var key: array[41, byte] + key[0] = headerPrefix + key[1..8] = toBytesBE(number)[0..^1] + key[9..40] = hash.data[0..^1] + let res = db.db.get(key) + result = rlp.decode(res, BlockHeader) + +proc blockHeader*(db: BaseChainDB, number: uint64): BlockHeader = + let hash = db.headerHash(number) + db.blockHeader(hash, number) + +proc blockBody*(db: BaseChainDB, hash: Hash256, number: uint64): BlockBody = + var key: array[41, byte] + key[0] = blockBodyPrefix + key[1..8] = toBytesBE(number)[0..^1] + key[9..40] = hash.data[0..^1] + let res = db.db.get(key) + result = rlp.decode(res, BlockBody) diff --git a/nimbus/p2p/executor.nim b/nimbus/p2p/executor.nim index ea1179f9b..9e1dc9eda 100644 --- a/nimbus/p2p/executor.nim +++ b/nimbus/p2p/executor.nim @@ -150,7 +150,10 @@ proc processBlock*(chainDB: BaseChainDB, header: BlockHeader, body: BlockBody, v let stateDb = vmState.accountDb if header.stateRoot != stateDb.rootHash: - error "Wrong state root in block", blockNumber=header.blockNumber, expected=header.stateRoot, actual=stateDb.rootHash, arrivedFrom=chainDB.getCanonicalHead().stateRoot + when defined(geth): + error "Wrong state root in block", blockNumber=header.blockNumber, expected=header.stateRoot, actual=stateDb.rootHash + else: + error "Wrong state root in block", blockNumber=header.blockNumber, expected=header.stateRoot, actual=stateDb.rootHash, arrivedFrom=chainDB.getCanonicalHead().stateRoot # this one is a show stopper until we are confident in our VM's # compatibility with the main chain return ValidationResult.Error diff --git a/nimbus/tracer.nim b/nimbus/tracer.nim index b4b5c2d37..5e08d38bc 100644 --- a/nimbus/tracer.nim +++ b/nimbus/tracer.nim @@ -5,8 +5,15 @@ import chronicles, rpc/hexstrings, launcher, vm/interpreter/vm_forks, ./config -proc getParentHeader(self: BaseChainDB, header: BlockHeader): BlockHeader = - self.getBlockHeader(header.parentHash) +when defined(geth): + import db/geth_db + + proc getParentHeader(db: BaseChainDB, header: BlockHeader): BlockHeader = + db.blockHeader(header.blockNumber.truncate(uint64) - 1) + +else: + proc getParentHeader(self: BaseChainDB, header: BlockHeader): BlockHeader = + self.getBlockHeader(header.parentHash) proc `%`(x: openArray[byte]): JsonNode = result = %toHex(x, false) diff --git a/nimbus/vm_state.nim b/nimbus/vm_state.nim index eabc63976..376873c92 100644 --- a/nimbus/vm_state.nim +++ b/nimbus/vm_state.nim @@ -75,6 +75,9 @@ method difficulty*(vmState: BaseVMState): UInt256 {.base, gcsafe.} = method gasLimit*(vmState: BaseVMState): GasInt {.base, gcsafe.} = vmState.blockHeader.gasLimit +when defined(geth): + import db/geth_db + method getAncestorHash*(vmState: BaseVMState, blockNumber: BlockNumber): Hash256 {.base, gcsafe.} = var ancestorDepth = vmState.blockHeader.blockNumber - blockNumber - 1 if ancestorDepth >= constants.MAX_PREV_HEADER_DEPTH: @@ -82,7 +85,10 @@ method getAncestorHash*(vmState: BaseVMState, blockNumber: BlockNumber): Hash256 if blockNumber >= vmState.blockHeader.blockNumber: return - result = vmState.chainDB.getBlockHash(blockNumber) + when defined(geth): + result = vmState.chainDB.headerHash(blockNumber.truncate(uint64)) + else: + result = vmState.chainDB.getBlockHash(blockNumber) #TODO: should we use deque here? # someday we may revive this code when # we already have working miner