diff --git a/nimbus/db/db_chain.nim b/nimbus/db/db_chain.nim index 56866172b..2737a757c 100644 --- a/nimbus/db/db_chain.nim +++ b/nimbus/db/db_chain.nim @@ -332,13 +332,26 @@ proc headerExists*(self: BaseChainDB; blockHash: Hash256): bool = ## Returns True if the header with the given block hash is in our DB. self.db.contains(genericHashKey(blockHash).toOpenArray) -proc markCanonicalChain(self: BaseChainDB, header: BlockHeader, headerHash: Hash256) = +proc markCanonicalChain(self: BaseChainDB, header: BlockHeader, headerHash: Hash256): bool = ## mark this chain as canonical by adding block number to hash lookup ## down to forking point var currHash = headerHash currHeader = header + # mark current header as canonical + let key = blockNumberToHashKey(currHeader.blockNumber) + self.db.put(key.toOpenArray, rlp.encode(currHash)) + + # it is a genesis block, done + if currHeader.parentHash == Hash256(): + return true + + # mark ancestor blocks as canonical too + currHash = currHeader.parentHash + if not self.getBlockHeader(currHeader.parentHash, currHeader): + return false + while currHash != Hash256(): let key = blockNumberToHashKey(currHeader.blockNumber) let data = self.db.get(key.toOpenArray) @@ -352,24 +365,34 @@ proc markCanonicalChain(self: BaseChainDB, header: BlockHeader, headerHash: Hash # forking point, done break + if currHeader.parentHash == Hash256(): + break + currHash = currHeader.parentHash - currHeader = self.getBlockHeader(currHeader.parentHash) + if not self.getBlockHeader(currHeader.parentHash, currHeader): + return false + + return true proc setHead*(self: BaseChainDB, blockHash: Hash256): bool = var header: BlockHeader if not self.getBlockHeader(blockHash, header): return false - self.markCanonicalChain(header, blockHash) + if not self.markCanonicalChain(header, blockHash): + return false + self.db.put(canonicalHeadHashKey().toOpenArray, rlp.encode(blockHash)) return true -proc setHead*(self: BaseChainDB, header: BlockHeader, writeHeader = false) = +proc setHead*(self: BaseChainDB, header: BlockHeader, writeHeader = false): bool = var headerHash = rlpHash(header) if writeHeader: self.db.put(genericHashKey(headerHash).toOpenArray, rlp.encode(header)) - self.markCanonicalChain(header, headerHash) + if not self.markCanonicalChain(header, headerHash): + return false self.db.put(canonicalHeadHashKey().toOpenArray, rlp.encode(headerHash)) + return true proc persistReceipts*(self: BaseChainDB, receipts: openArray[Receipt]): Hash256 = var trie = initHexaryTrie(self.db) diff --git a/nimbus/rpc/debug.nim b/nimbus/rpc/debug.nim index 917cd0294..58f28cc41 100644 --- a/nimbus/rpc/debug.nim +++ b/nimbus/rpc/debug.nim @@ -114,10 +114,10 @@ proc setupDebugRpc*(chainDB: BaseChainDB, rpcsrv: RpcServer) = result = traceBlock(chainDB, header, body, flags) - rpcsrv.rpc("debug_setHead") do(quantityTag: string): + rpcsrv.rpc("debug_setHead") do(quantityTag: string) -> bool: ## Sets the current head of the local chain by block number. ## Note, this is a destructive action and may severely damage your chain. ## Use with extreme caution. let header = chainDB.headerFromTag(quantityTag) - chainDB.setHead(header) + result = chainDB.setHead(header) diff --git a/premix/dumper.nim b/premix/dumper.nim index 76f036551..b89e6686c 100644 --- a/premix/dumper.nim +++ b/premix/dumper.nim @@ -28,7 +28,7 @@ proc dumpDebug(chainDB: BaseChainDB, blockNumber: UInt256) = body = captureChainDB.getBlockBody(headerHash) vmState = BaseVMState.new(parent, header, captureChainDB) - captureChainDB.setHead(parent, true) + discard captureChainDB.setHead(parent, true) discard vmState.processBlockNotPoA(header, body) transaction.rollback() diff --git a/premix/hunter.nim b/premix/hunter.nim index 4704a367b..1a1f241df 100644 --- a/premix/hunter.nim +++ b/premix/hunter.nim @@ -95,7 +95,7 @@ proc huntProblematicBlock(blockNumber: UInt256): ValidationResult = # try to execute current block chainDB = newBaseChainDB(memoryDB, false) - chainDB.setHead(parentBlock.header, true) + discard chainDB.setHead(parentBlock.header, true) let transaction = memoryDB.beginTransaction() defer: transaction.dispose() diff --git a/premix/persist.nim b/premix/persist.nim index b72d07224..48853977e 100644 --- a/premix/persist.nim +++ b/premix/persist.nim @@ -47,7 +47,7 @@ proc main() {.used.} = # move head to block number ... if conf.head != 0.u256: var parentBlock = requestBlock(conf.head) - chainDB.setHead(parentBlock.header) + discard chainDB.setHead(parentBlock.header) if canonicalHeadHashKey().toOpenArray notin trieDB: persistToDb(db): diff --git a/premix/prestate.nim b/premix/prestate.nim index a951c9a04..1f8cad8d2 100644 --- a/premix/prestate.nim +++ b/premix/prestate.nim @@ -12,7 +12,7 @@ proc generatePrestate*(nimbus, geth: JsonNode, blockNumber: UInt256, parent, hea memoryDB = newMemoryDB() chainDB = newBaseChainDB(memoryDB, false) - chainDB.setHead(parent, true) + discard chainDB.setHead(parent, true) discard chainDB.persistTransactions(blockNumber, body.transactions) discard chainDB.persistUncles(body.uncles) diff --git a/tests/persistBlockTestGen.nim b/tests/persistBlockTestGen.nim index acaf66546..7503e2858 100644 --- a/tests/persistBlockTestGen.nim +++ b/tests/persistBlockTestGen.nim @@ -24,7 +24,7 @@ proc dumpTest(chainDB: BaseChainDB, blockNumber: int) = headers = @[header] bodies = @[blockBody] - captureChainDB.setHead(parent, true) + discard captureChainDB.setHead(parent, true) discard chain.persistBlocks(headers, bodies) var metaData = %{ diff --git a/tests/test_persistblock_json.nim b/tests/test_persistblock_json.nim index 8f6b8177a..c40423f74 100644 --- a/tests/test_persistblock_json.nim +++ b/tests/test_persistblock_json.nim @@ -34,7 +34,8 @@ proc testFixture(node: JsonNode, testStatusIMPL: var TestStatus) = headers = @[header] bodies = @[blockBody] - chainDB.setHead(parent, true) + # it's ok if setHead fails here because of missing ancestors + discard chainDB.setHead(parent, true) let validationResult = chain.persistBlocks(headers, bodies) check validationResult == ValidationResult.OK