From 0471f059c46ba188e2f2aa8b532cb3d6191f993b Mon Sep 17 00:00:00 2001 From: jangko Date: Tue, 25 Jun 2024 21:34:22 +0700 Subject: [PATCH] Separate finalizedHash from baseHash --- nimbus/core/chain/forked_chain.nim | 98 ++++++++++++++++++++++-------- tests/test_blockchain_json.nim | 9 ++- 2 files changed, 80 insertions(+), 27 deletions(-) diff --git a/nimbus/core/chain/forked_chain.nim b/nimbus/core/chain/forked_chain.nim index 211a71a61..0b93fc270 100644 --- a/nimbus/core/chain/forked_chain.nim +++ b/nimbus/core/chain/forked_chain.nim @@ -30,6 +30,10 @@ type hash: Hash256 header: BlockHeader + CanonicalDesc = object + cursorHash: Hash256 + header: BlockHeader + ForkedChain* = object stagingTx: CoreDbTxRef db: CoreDbRef @@ -168,7 +172,9 @@ proc writeBaggage(c: var ForkedChain, target: Hash256) = prevHash = blk.blk.header.parentHash func updateBase(c: var ForkedChain, - newBaseHash: Hash256, newBaseHeader: BlockHeader) = + newBaseHash: Hash256, + newBaseHeader: BlockHeader, + canonicalCursorHash: Hash256) = var cursorHeadsLen = c.cursorHeads.len # Remove obsolete chains, example: # -- A1 - A2 - A3 -- D5 - D6 @@ -180,7 +186,8 @@ func updateBase(c: var ForkedChain, # but not D for i in 0.. head.header.number: + c.blocks.del(prevHash) + else: + break + prevHash = header.parentHash + # ------------------------------------------------------------------------------ # Public functions # ------------------------------------------------------------------------------ @@ -302,30 +336,43 @@ proc forkChoice*(c: var ForkedChain, finalizedHash: Hash256): Result[void, string] = # If there are multiple heads, find which chain headHash belongs to - let headHeader = ?c.findCanonicalHead(headHash) + let head = ?c.findCanonicalHead(headHash) # Finalized block must be part of canonical chain let finalizedHeader = ?c.canonicalChain(finalizedHash, headHash) - if finalizedHash == c.baseHash: - # The base is not updated + let newBase = c.calculateNewBase( + finalizedHeader, headHash, head.header) + + if newBase.hash == c.baseHash: + # The base is not updated but the cursor maybe need update + if c.cursorHash != head.cursorHash: + if not c.stagingTx.isNil: + c.stagingTx.rollback() + c.stagingTx = c.db.newTransaction() + c.replaySegment(headHash) + + c.trimCanonicalChain(head) + if c.cursorHash != headHash: + c.cursorHeader = head.header + c.cursorHash = headHash return ok() # At this point cursorHeader.number > baseHeader.number - if finalizedHash == c.cursorHash: + if newBase.hash == c.cursorHash: # Paranoid check, guaranteed by findCanonicalHead doAssert(c.cursorHash == headHash) # Current segment is canonical chain - c.writeBaggage(finalizedHash) + c.writeBaggage(newBase.hash) - # Paranoid check, guaranteed by `finalizedHash == c.cursorHash` + # Paranoid check, guaranteed by `newBase.hash == c.cursorHash` doAssert(not c.stagingTx.isNil) c.stagingTx.commit() c.stagingTx = nil - # Move base to finalized - c.updateBase(finalizedHash, c.cursorHeader) + # Move base to newBase + c.updateBase(newBase.hash, c.cursorHeader, head.cursorHash) # Save and record the block number before the last saved block state. c.db.persistent(c.cursorHeader.number).isOkOr: @@ -335,10 +382,7 @@ proc forkChoice*(c: var ForkedChain, # At this point finalizedHeader.number is <= headHeader.number # and possibly switched to other chain beside the one with cursor - doAssert(finalizedHeader.number <= headHeader.number) - - let newBase = c.calculateNewBase( - finalizedHeader, headHash, headHeader) + doAssert(finalizedHeader.number <= head.header.number) # Write segment from base+1 to newBase into database c.stagingTx.rollback() @@ -347,18 +391,22 @@ proc forkChoice*(c: var ForkedChain, c.replaySegment(newBase.hash) c.writeBaggage(newBase.hash) c.stagingTx.commit() + c.stagingTx = nil # Update base forward to newBase - c.updateBase(newBase.hash, newBase.header) + c.updateBase(newBase.hash, newBase.header, head.cursorHash) c.db.persistent(newBase.header.number).isOkOr: return err("Failed to save state: " & $$error) # Move chain state forward to current head - if newBase.header.number < headHeader.number: - c.stagingTx = c.db.newTransaction() + if newBase.header.number < head.header.number: + if c.stagingTx.isNil: + c.stagingTx = c.db.newTransaction() c.replaySegment(headHash) # Move cursor forward to current head - c.cursorHeader = headHeader - c.cursorHash = headHash + c.trimCanonicalChain(head) + if c.cursorHash != headHash: + c.cursorHeader = head.header + c.cursorHash = headHash ok() diff --git a/tests/test_blockchain_json.nim b/tests/test_blockchain_json.nim index 96091cae4..2da6d0455 100644 --- a/tests/test_blockchain_json.nim +++ b/tests/test_blockchain_json.nim @@ -21,6 +21,9 @@ import ../nimbus/common/common, ../nimbus/core/eip4844 +const + debugMode = false + type BlockDesc = object blk: EthBlock @@ -118,6 +121,8 @@ proc executeCase(node: JsonNode): bool = proc executeFile(node: JsonNode, testStatusIMPL: var TestStatus) = for name, bctCase in node: + when debugMode: + debugEcho "TEST NAME: ", name check executeCase(bctCase) proc blockchainJsonMain*() = @@ -138,12 +143,12 @@ proc blockchainJsonMain*() = jsonTest(newFolder, "newBlockchainTests", executeFile, skipNewBCTests) when isMainModule: - when false: + when debugMode: proc executeFile(name: string) = var testStatusIMPL: TestStatus let node = json.parseFile(name) executeFile(node, testStatusIMPL) - executeFile("tests/fixtures/eth_tests/BlockchainTests/TransitionTests/bcFrontierToHomestead/HomesteadOverrideFrontier.json") + executeFile("tests/fixtures/eth_tests/BlockchainTests/ValidBlocks/bcTotalDifficultyTest/sideChainWithMoreTransactions.json") else: blockchainJsonMain()