From 420ba073c9a0244c60b42aeadff2a29f35378fd0 Mon Sep 17 00:00:00 2001 From: jangko Date: Wed, 9 Apr 2025 09:30:36 +0700 Subject: [PATCH 1/4] fCU early notification of finalized hash to FC. Before fCU actually call FC.forkchoice, it will go through a series of validation, and the finalized hash may never arrive at FC.forkChoice at all although the finalized hash is valid. e.g. head, finalized, or safe block are being downloaded by the syncer. --- .../beacon/api_handler/api_forkchoice.nim | 21 ++++++++++--------- execution_chain/core/chain/forked_chain.nim | 4 ++++ 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/execution_chain/beacon/api_handler/api_forkchoice.nim b/execution_chain/beacon/api_handler/api_forkchoice.nim index 3a64d684d..860b9b4d6 100644 --- a/execution_chain/beacon/api_handler/api_forkchoice.nim +++ b/execution_chain/beacon/api_handler/api_forkchoice.nim @@ -75,8 +75,7 @@ proc forkchoiceUpdated*(ben: BeaconEngineRef, attrsOpt: Opt[PayloadAttributes]): ForkchoiceUpdatedResponse = let - com = ben.com - txFrame = ben.chain.latestTxFrame() + com = ben.com chain = ben.chain headHash = update.headBlockHash @@ -87,7 +86,7 @@ proc forkchoiceUpdated*(ben: BeaconEngineRef, # Check whether we have the block yet in our database or not. If not, we'll # need to either trigger a sync, or to reject this forkchoice update for a # reason. - let header = ben.chain.headerByHash(headHash).valueOr: + let header = chain.headerByHash(headHash).valueOr: # If this block was previously invalidated, keep rejecting it here too let res = ben.checkInvalidAncestor(headHash, headHash) if res.isSome: @@ -109,6 +108,7 @@ proc forkchoiceUpdated*(ben: BeaconEngineRef, hash = headHash.short # Inform the header cache (used by the syncer) + chain.notifyFinalizedHash(update.finalizedBlockHash) com.fcHeaderClUpdate(header, update.finalizedBlockHash) return simpleFCU(PayloadExecutionStatus.syncing) @@ -124,6 +124,7 @@ proc forkchoiceUpdated*(ben: BeaconEngineRef, let blockNumber = header.number if header.difficulty > 0.u256 or blockNumber == 0'u64: let + txFrame = chain.latestTxFrame() td = txFrame.getScore(headHash) ptd = txFrame.getScore(header.parentHash) ttd = com.ttd.get(high(UInt256)) @@ -151,7 +152,7 @@ proc forkchoiceUpdated*(ben: BeaconEngineRef, # probably resyncing. Ignore the update. # See point 2 of fCUV1 specification # https://github.com/ethereum/execution-apis/blob/v1.0.0-beta.4/src/engine/paris.md#specification-1 - if ben.chain.isCanonicalAncestor(header.number, headHash): + if chain.isCanonicalAncestor(header.number, headHash): notice "Ignoring beacon update to old head", headHash=headHash.short, blockNumber=header.number @@ -161,7 +162,7 @@ proc forkchoiceUpdated*(ben: BeaconEngineRef, # chain final and completely in PoS mode. let finalizedBlockHash = update.finalizedBlockHash if finalizedBlockHash != zeroHash32: - if not ben.chain.equalOrAncestorOf(finalizedBlockHash, headHash): + if not chain.equalOrAncestorOf(finalizedBlockHash, headHash): warn "Final block not in canonical tree", hash=finalizedBlockHash.short raise invalidForkChoiceState("finalized block not in canonical tree") @@ -169,13 +170,13 @@ proc forkchoiceUpdated*(ben: BeaconEngineRef, let safeBlockHash = update.safeBlockHash if safeBlockHash != zeroHash32: - if not ben.chain.equalOrAncestorOf(safeBlockHash, headHash): + if not chain.equalOrAncestorOf(safeBlockHash, headHash): warn "Safe block not in canonical tree", hash=safeBlockHash.short raise invalidForkChoiceState("safe block not in canonical tree") # Current version of FC module is not interested in safeBlockHash # so we save it here - let txFrame = ben.chain.txFrame(safeBlockHash) + let txFrame = chain.txFrame(safeBlockHash) txFrame.safeHeaderHash(safeBlockHash) chain.forkChoice(headHash, update.finalizedBlockHash).isOkOr: @@ -210,8 +211,8 @@ proc forkchoiceUpdated*(ben: BeaconEngineRef, info "Fork choice updated", requested = header.number, hash = headHash.short, - head = ben.chain.latestNumber, - base = ben.chain.baseNumber, - baseHash = ben.chain.baseHash.short + head = chain.latestNumber, + base = chain.baseNumber, + baseHash = chain.baseHash.short return validFCU(Opt.none(Bytes8), headHash) diff --git a/execution_chain/core/chain/forked_chain.nim b/execution_chain/core/chain/forked_chain.nim index fe31761af..36f531363 100644 --- a/execution_chain/core/chain/forked_chain.nim +++ b/execution_chain/core/chain/forked_chain.nim @@ -620,6 +620,10 @@ proc forkChoice*(c: ForkedChainRef, ok() +func notifyFinalizedHash*(c: ForkedChainRef, finHash: Hash32) = + if finHash != zeroHash32: + c.pendingFCU = finHash + func haveBlockAndState*(c: ForkedChainRef, blockHash: Hash32): bool = ## Blocks still in memory with it's txFrame c.hashToBlock.hasKey(blockHash) From 0d031bd8b18c22c73c049ff32006954205681f06 Mon Sep 17 00:00:00 2001 From: jangko Date: Mon, 21 Apr 2025 18:19:31 +0700 Subject: [PATCH 2/4] Refine fcu head, safe, and finalized hash in FC, engine API, and RPC --- .../beacon/api_handler/api_forkchoice.nim | 7 +- execution_chain/common/common.nim | 22 +++--- execution_chain/core/chain/forked_chain.nim | 70 +++++++++++++++--- .../core/chain/forked_chain/chain_branch.nim | 3 + .../core/chain/forked_chain/chain_desc.nim | 6 +- execution_chain/db/core_db/core_apps.nim | 31 -------- execution_chain/db/fcu_db.nim | 74 +++++++++++++++++++ execution_chain/db/storage_types.nim | 26 ++++--- execution_chain/rpc/server_api.nim | 8 ++ 9 files changed, 180 insertions(+), 67 deletions(-) create mode 100644 execution_chain/db/fcu_db.nim diff --git a/execution_chain/beacon/api_handler/api_forkchoice.nim b/execution_chain/beacon/api_handler/api_forkchoice.nim index 6b65001cb..1e302d54f 100644 --- a/execution_chain/beacon/api_handler/api_forkchoice.nim +++ b/execution_chain/beacon/api_handler/api_forkchoice.nim @@ -173,12 +173,9 @@ proc forkchoiceUpdated*(ben: BeaconEngineRef, warn "Safe block not in canonical tree", hash=safeBlockHash.short raise invalidForkChoiceState("safe block not in canonical tree") - # Current version of FC module is not interested in safeBlockHash - # so we save it here - let txFrame = chain.txFrame(safeBlockHash) - txFrame.safeHeaderHash(safeBlockHash) + # similar to headHash, safeBlockHash is saved by FC module - chain.forkChoice(headHash, update.finalizedBlockHash).isOkOr: + chain.forkChoice(headHash, finalizedBlockHash, safeBlockHash).isOkOr: return invalidFCU(error, chain, header) # If payload generation was requested, create a new block to be potentially diff --git a/execution_chain/common/common.nim b/execution_chain/common/common.nim index 8d9ae4e7f..38de4e9cd 100644 --- a/execution_chain/common/common.nim +++ b/execution_chain/common/common.nim @@ -12,7 +12,7 @@ import chronicles, logging, - ../db/[core_db, ledger, storage_types], + ../db/[core_db, ledger, storage_types, fcu_db], ../utils/[utils], ".."/[constants, errors, version], "."/[chain_config, evmforks, genesis, hardforks], @@ -136,18 +136,18 @@ proc initializeDb(com: CommonRef) = fatal "Cannot load base block header", baseNum, err = error quit 1 - finalized = txFrame.finalizedHeader().valueOr: - debug "No finalized block stored in database, reverting to base" - base - head = txFrame.getCanonicalHead().valueOr: - fatal "Cannot load canonical block header", - err = error - quit 1 + baseHash = base.computeBlockHash + finalized = txFrame.fcuFinalized().valueOr: + debug "Reverting to base", err = error + FcuHashAndNumber(hash: baseHash, number: base.number) + head = txFrame.fcuHead().valueOr: + fatal "Reverting to base", err = error + FcuHashAndNumber(hash: baseHash, number: base.number) info "Database initialized", - base = (base.computeBlockHash, base.number), - finalized = (finalized.computeBlockHash, finalized.number), - head = (head.computeBlockHash, head.number) + base = (baseHash, base.number), + finalized = (finalized.hash, finalized.number), + head = (head.hash, head.number) proc init(com : CommonRef, db : CoreDbRef, diff --git a/execution_chain/core/chain/forked_chain.nim b/execution_chain/core/chain/forked_chain.nim index 0c2c85918..7ee535170 100644 --- a/execution_chain/core/chain/forked_chain.nim +++ b/execution_chain/core/chain/forked_chain.nim @@ -16,6 +16,7 @@ import std/[tables, algorithm], ../../common, ../../db/core_db, + ../../db/fcu_db, ../../evm/types, ../../evm/state, ../validate, @@ -111,6 +112,16 @@ proc writeBaggage(c: ForkedChainRef, header.withdrawalsRoot.expect("WithdrawalsRoot should be verified before"), blk.withdrawals.get) +proc fcuSetHead(c: ForkedChainRef, + txFrame: CoreDbTxRef, + header: Header, + hash: Hash32, + number: uint64) = + txFrame.setHead(header, hash).expect("OK") + txFrame.fcuHead(hash, number).expect("OK") + c.fcuHead.number = number + c.fcuHead.hash = hash + proc validateBlock(c: ForkedChainRef, parent: BlockPos, blk: Block): Result[Hash32, string] = @@ -192,11 +203,12 @@ proc validateBlock(c: ForkedChainRef, # If on disk head behind base, move it to base too. let newBaseNumber = c.baseBranch.tailNumber if newBaseNumber > prevBaseNumber: - let canonicalHead = ?c.baseTxFrame.getCanonicalHead() - if canonicalHead.number < newBaseNumber: + if c.fcuHead.number < newBaseNumber: let head = c.baseBranch.firstBlockPos - head.txFrame.setHead(head.branch.tailHeader, - head.branch.tailHash).expect("OK") + c.fcuSetHead(head.txFrame, + head.branch.tailHeader, + head.branch.tailHash, + head.branch.tailNumber) ok(blkHash) @@ -371,8 +383,10 @@ proc updateHead(c: ForkedChainRef, head: BlockPos) = c.removeBlockFromCache(head.branch.blocks[i]) head.branch.blocks.setLen(head.index+1) - head.txFrame.setHead(head.branch.headHeader, - head.branch.headHash).expect("OK") + c.fcuSetHead(head.txFrame, + head.branch.headHeader, + head.branch.headHash, + head.branch.headNumber) proc updateFinalized(c: ForkedChainRef, finalized: BlockPos) = # Pruning @@ -411,7 +425,7 @@ proc updateFinalized(c: ForkedChainRef, finalized: BlockPos) = inc i let txFrame = finalized.txFrame - txFrame.finalizedHeaderHash(finalized.hash) + txFrame.fcuFinalized(finalized.hash, finalized.number).expect("OK") proc updateBase(c: ForkedChainRef, newBase: BlockPos) = ## @@ -541,6 +555,10 @@ proc init*( baseHash = baseTxFrame.getBlockHash(base).expect("baseHash exists") baseHeader = baseTxFrame.getBlockHeader(baseHash).expect("base header exists") baseBranch = branch(baseHeader, baseHash, baseTxFrame) + fcuHead = baseTxFrame.fcuHead().valueOr: + FcuHashAndNumber(hash: baseHash, number: baseHeader.number) + fcuSafe = baseTxFrame.fcuSafe().valueOr: + FcuHashAndNumber(hash: baseHash, number: baseHeader.number) T(com: com, baseBranch: baseBranch, @@ -550,7 +568,9 @@ proc init*( baseTxFrame: baseTxFrame, baseDistance: baseDistance, persistBatchSize:persistBatchSize, - quarantine: Quarantine.init()) + quarantine: Quarantine.init(), + fcuHead: fcuHead, + fcuSafe: fcuSafe) proc importBlock*(c: ForkedChainRef, blk: Block): Result[void, string] = ## Try to import block to canonical or side chain. @@ -596,11 +616,19 @@ proc importBlock*(c: ForkedChainRef, blk: Block): Result[void, string] = proc forkChoice*(c: ForkedChainRef, headHash: Hash32, - finalizedHash: Hash32): Result[void, string] = + finalizedHash: Hash32, + safeHash: Hash32 = zeroHash32): Result[void, string] = if finalizedHash != zeroHash32: c.pendingFCU = finalizedHash + if safeHash != zeroHash32: + c.hashToBlock.withValue(safeHash, loc): + let number = loc[].number + c.fcuSafe.number = number + c.fcuSafe.hash = safeHash + ?loc[].txFrame.fcuSafe(c.fcuSafe) + if headHash == c.activeBranch.headHash: if finalizedHash == zeroHash32: # Do nothing if the new head already our current head @@ -743,6 +771,30 @@ proc headerByNumber*(c: ForkedChainRef, number: BlockNumber): Result[Header, str err("Header not found, number = " & $number) +func finalizedHeader*(c: ForkedChainRef): Header = + c.hashToBlock.withValue(c.pendingFCU, loc): + return loc[].header + + c.baseBranch.tailHeader + +func safeHeader*(c: ForkedChainRef): Header = + c.hashToBlock.withValue(c.fcuSafe.hash, loc): + return loc[].header + + c.baseBranch.tailHeader + +func finalizedBlock*(c: ForkedChainRef): Block = + c.hashToBlock.withValue(c.pendingFCU, loc): + return loc[].blk + + c.baseBranch.tailBlock + +func safeBlock*(c: ForkedChainRef): Block = + c.hashToBlock.withValue(c.fcuSafe.hash, loc): + return loc[].blk + + c.baseBranch.tailBlock + proc headerByHash*(c: ForkedChainRef, blockHash: Hash32): Result[Header, string] = c.hashToBlock.withValue(blockHash, loc): return ok(loc[].header) diff --git a/execution_chain/core/chain/forked_chain/chain_branch.nim b/execution_chain/core/chain/forked_chain/chain_branch.nim index 740b96731..b88edd4cb 100644 --- a/execution_chain/core/chain/forked_chain/chain_branch.nim +++ b/execution_chain/core/chain/forked_chain/chain_branch.nim @@ -29,6 +29,9 @@ type parent*: BranchRef # If parent.isNil: it is a base branch +func tailBlock*(brc: BranchRef): Block = + brc.blocks[0].blk + func tailNumber*(brc: BranchRef): BlockNumber = brc.blocks[0].blk.header.number diff --git a/execution_chain/core/chain/forked_chain/chain_desc.nim b/execution_chain/core/chain/forked_chain/chain_desc.nim index 0b36b9f45..a7aaf6cb9 100644 --- a/execution_chain/core/chain/forked_chain/chain_desc.nim +++ b/execution_chain/core/chain/forked_chain/chain_desc.nim @@ -15,7 +15,8 @@ import ./chain_branch, ./block_quarantine, ../../../common, - ../../../db/core_db + ../../../db/core_db, + ../../../db/fcu_db export deques, tables @@ -66,6 +67,9 @@ type # to move the base. And the bulk writing can works # efficiently. + fcuHead*: FcuHashAndNumber + fcuSafe*: FcuHashAndNumber + # ---------------- func txRecords*(c: ForkedChainRef): var Table[Hash32, (Hash32, uint64)] = diff --git a/execution_chain/db/core_db/core_apps.nim b/execution_chain/db/core_db/core_apps.nim index d8ef2b64b..49f5fa907 100644 --- a/execution_chain/db/core_db/core_apps.nim +++ b/execution_chain/db/core_db/core_apps.nim @@ -601,37 +601,6 @@ proc persistUncles*(db: CoreDbTxRef, uncles: openArray[Header]): Hash32 = warn "persistUncles()", unclesHash=result, error=($$error) return EMPTY_ROOT_HASH - -proc safeHeaderHash*(db: CoreDbTxRef): Hash32 = - db.getHash(safeHashKey()).valueOr(default(Hash32)) - -proc safeHeaderHash*(db: CoreDbTxRef, headerHash: Hash32) = - let safeHashKey = safeHashKey() - db.put(safeHashKey.toOpenArray, rlp.encode(headerHash)).isOkOr: - warn "safeHeaderHash()", safeHashKey, error=($$error) - return - -proc finalizedHeaderHash*( - db: CoreDbTxRef; - ): Hash32 = - db.getHash(finalizedHashKey()).valueOr(default(Hash32)) - -proc finalizedHeaderHash*(db: CoreDbTxRef, headerHash: Hash32) = - let finalizedHashKey = finalizedHashKey() - db.put(finalizedHashKey.toOpenArray, rlp.encode(headerHash)).isOkOr: - warn "finalizedHeaderHash()", finalizedHashKey, error=($$error) - return - -proc safeHeader*( - db: CoreDbTxRef; - ): Result[Header, string] = - db.getBlockHeader(db.safeHeaderHash) - -proc finalizedHeader*( - db: CoreDbTxRef; - ): Result[Header, string] = - db.getBlockHeader(db.finalizedHeaderHash) - # ------------------------------------------------------------------------------ # End # ------------------------------------------------------------------------------ diff --git a/execution_chain/db/fcu_db.nim b/execution_chain/db/fcu_db.nim new file mode 100644 index 000000000..1cfec5c2a --- /dev/null +++ b/execution_chain/db/fcu_db.nim @@ -0,0 +1,74 @@ +# nimbus-execution-client +# Copyright (c) 2025 Status Research & Development GmbH +# Licensed under either of +# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE)) +# * MIT license ([LICENSE-MIT](LICENSE-MIT)) +# at your option. +# This file may not be copied, modified, or distributed except according to +# those terms. + +{.push raises: [].} + +import + eth/common/hashes, + stew/endians2, + stew/assign2, + results, + ./core_db/base, + ./storage_types + +type + FcuHashAndNumber* = object + hash*: Hash32 + number*: uint64 + +const + headKey = fcuKey 0 + finKey = fcuKey 1 + safeKey = fcuKey 2 + DataLen = sizeof(Hash32) + sizeof(uint64) + +template fcuReadImpl(key: DbKey, name: string): auto = + let data = db.getOrEmpty(key.toOpenArray).valueOr: + return err($error) + if data.len != DataLen: + return err("no " & name & " block hash and number") + ok(FcuHashAndNumber( + hash: Hash32.copyFrom(data.toOpenArray(sizeof(uint64), data.len-1)), + number: uint64.fromBytesBE(data), + )) + +template fcuWriteImpl(key: DbKey, hash: Hash32, number: uint64): auto = + var data: array[DataLen, byte] + assign(data, number.toBytesBE) + assign(data.toOpenArray(sizeof(uint64), data.len-1), hash.data) + db.put(key.toOpenArray, data).isOkOr: + return err($error) + ok() + +proc fcuHead*(db: CoreDbTxRef): Result[FcuHashAndNumber, string] = + fcuReadImpl(headKey, "head") + +proc fcuHead*(db: CoreDbTxRef, hash: Hash32, number: uint64): Result[void, string] = + fcuWriteImpl(headKey, hash, number) + +template fcuHead*(db: CoreDbTxRef, head: FcuHashAndNumber): auto = + fcuHead(db, head.hash, head.number) + +proc fcuFinalized*(db: CoreDbTxRef): Result[FcuHashAndNumber, string] = + fcuReadImpl(finKey, "finalized") + +proc fcuFinalized*(db: CoreDbTxRef, hash: Hash32, number: uint64): Result[void, string] = + fcuWriteImpl(finKey, hash, number) + +template fcuFinalized*(db: CoreDbTxRef, finalized: FcuHashAndNumber): auto = + fcuFinalized(db, finalized.hash, finalized.number) + +proc fcuSafe*(db: CoreDbTxRef): Result[FcuHashAndNumber, string] = + fcuReadImpl(safeKey, "safe") + +proc fcuSafe*(db: CoreDbTxRef, hash: Hash32, number: uint64): Result[void, string] = + fcuWriteImpl(safeKey, hash, number) + +template fcuSafe*(db: CoreDbTxRef, safe: FcuHashAndNumber): auto = + fcuSafe(db, safe.hash, safe.number) diff --git a/execution_chain/db/storage_types.nim b/execution_chain/db/storage_types.nim index d96b48aee..22632ae85 100644 --- a/execution_chain/db/storage_types.nim +++ b/execution_chain/db/storage_types.nim @@ -24,8 +24,8 @@ type slotHashToSlot = 5 contractHash = 6 dataDirId = 7 - safeHash = 8 - finalizedHash = 9 + fcuNumAndHash = 8 + # 9 -- not used beaconHeader = 10 DbKey* = object @@ -74,13 +74,15 @@ func contractHashKey*(h: Hash32): DbKey {.inline.} = result.data[1 .. 32] = h.data result.dataEndPos = uint8 32 -func safeHashKey*(): DbKey {.inline.} = - result.data[0] = byte ord(safeHash) - result.dataEndPos = uint8 1 - -func finalizedHashKey*(): DbKey {.inline.} = - result.data[0] = byte ord(finalizedHash) - result.dataEndPos = uint8 1 +func fcuKey*(u: uint64): DbKey {.inline.} = + result.data[0] = byte ord(fcuNumAndHash) + doAssert sizeof(u) <= 32 + when nimvm: + for i in 0.. Date: Mon, 21 Apr 2025 18:44:51 +0700 Subject: [PATCH 3/4] c.latestFinalizedBlockNumber = max(blk.header.number, c.latestFinalizedBlockNumber) --- execution_chain/core/chain/forked_chain.nim | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/execution_chain/core/chain/forked_chain.nim b/execution_chain/core/chain/forked_chain.nim index 7ee535170..cf89f8516 100644 --- a/execution_chain/core/chain/forked_chain.nim +++ b/execution_chain/core/chain/forked_chain.nim @@ -133,7 +133,8 @@ proc validateBlock(c: ForkedChainRef, if blkHash == c.pendingFCU: # Resolve the hash into latestFinalizedBlockNumber - c.latestFinalizedBlockNumber = blk.header.number + c.latestFinalizedBlockNumber = max(blk.header.number, + c.latestFinalizedBlockNumber) let parentFrame = parent.txFrame From b2b74e9052c47583b39babcf06e12edf8da02b22 Mon Sep 17 00:00:00 2001 From: jangko Date: Mon, 21 Apr 2025 19:27:48 +0700 Subject: [PATCH 4/4] Update forked_chain test --- execution_chain/common/common.nim | 6 ++++-- execution_chain/core/chain/forked_chain.nim | 6 +++--- execution_chain/db/fcu_db.nim | 2 +- tests/test_forked_chain.nim | 9 +++++++-- 4 files changed, 15 insertions(+), 8 deletions(-) diff --git a/execution_chain/common/common.nim b/execution_chain/common/common.nim index 38de4e9cd..7e5a08683 100644 --- a/execution_chain/common/common.nim +++ b/execution_chain/common/common.nim @@ -110,8 +110,9 @@ proc initializeDb(com: CommonRef) = proc contains(txFrame: CoreDbTxRef; key: openArray[byte]): bool = txFrame.hasKeyRc(key).expect "valid bool" if canonicalHeadHashKey().toOpenArray notin txFrame: + let genesisHash = com.genesisHeader.computeBlockHash info "Writing genesis to DB", - blockHash = com.genesisHeader.computeBlockHash, + blockHash = genesisHash , stateRoot = com.genesisHeader.stateRoot, difficulty = com.genesisHeader.difficulty, gasLimit = com.genesisHeader.gasLimit, @@ -122,7 +123,8 @@ proc initializeDb(com: CommonRef) = txFrame.persistHeaderAndSetHead(com.genesisHeader, startOfHistory=com.genesisHeader.parentHash). expect("can persist genesis header") - + txFrame.fcuHead(genesisHash, com.genesisHeader.number). + expect("fcuHead OK") doAssert(canonicalHeadHashKey().toOpenArray in txFrame) txFrame.checkpoint(com.genesisHeader.number) diff --git a/execution_chain/core/chain/forked_chain.nim b/execution_chain/core/chain/forked_chain.nim index cf89f8516..2c5da41ca 100644 --- a/execution_chain/core/chain/forked_chain.nim +++ b/execution_chain/core/chain/forked_chain.nim @@ -117,8 +117,8 @@ proc fcuSetHead(c: ForkedChainRef, header: Header, hash: Hash32, number: uint64) = - txFrame.setHead(header, hash).expect("OK") - txFrame.fcuHead(hash, number).expect("OK") + txFrame.setHead(header, hash).expect("setHead OK") + txFrame.fcuHead(hash, number).expect("fcuHead OK") c.fcuHead.number = number c.fcuHead.hash = hash @@ -426,7 +426,7 @@ proc updateFinalized(c: ForkedChainRef, finalized: BlockPos) = inc i let txFrame = finalized.txFrame - txFrame.fcuFinalized(finalized.hash, finalized.number).expect("OK") + txFrame.fcuFinalized(finalized.hash, finalized.number).expect("fcuFinalized OK") proc updateBase(c: ForkedChainRef, newBase: BlockPos) = ## diff --git a/execution_chain/db/fcu_db.nim b/execution_chain/db/fcu_db.nim index 1cfec5c2a..b4d594c7e 100644 --- a/execution_chain/db/fcu_db.nim +++ b/execution_chain/db/fcu_db.nim @@ -40,7 +40,7 @@ template fcuReadImpl(key: DbKey, name: string): auto = template fcuWriteImpl(key: DbKey, hash: Hash32, number: uint64): auto = var data: array[DataLen, byte] - assign(data, number.toBytesBE) + assign(data.toOpenArray(0, sizeof(uint64)-1), number.toBytesBE) assign(data.toOpenArray(sizeof(uint64), data.len-1), hash.data) db.put(key.toOpenArray, data).isOkOr: return err($error) diff --git a/tests/test_forked_chain.nim b/tests/test_forked_chain.nim index 6466be0bd..9c8735a9e 100644 --- a/tests/test_forked_chain.nim +++ b/tests/test_forked_chain.nim @@ -19,6 +19,7 @@ import ../execution_chain/core/chain/forked_chain/chain_desc, ../execution_chain/db/ledger, ../execution_chain/db/era1_db, + ../execution_chain/db/fcu_db, ./test_forked_chain/chain_debug const @@ -117,6 +118,10 @@ template checkHeadHash(chain: ForkedChainRef, hashParam: Hash32) = # also check if the header actually exists check txFrame.getCanonicalHead().isOk + let rc = txFrame.fcuHead() + check rc.isOk + if rc.isErr: + debugEcho "FCU HEAD: ", rc.error func blockHash(x: Block): Hash32 = x.header.computeBlockHash @@ -257,8 +262,8 @@ proc forkedChainMain*() = # It is FC module who is responsible for saving # finalized hash on a correct txFrame. let txFrame = chain.txFrame(blk6.blockHash) - let savedFinalizedHash = txFrame.finalizedHeaderHash() - check blk6.blockHash == savedFinalizedHash + let savedFinalized = txFrame.fcuFinalized().expect("OK") + check blk6.blockHash == savedFinalized.hash # make sure aristo not wiped out baggage check chain.wdWritten(blk3) == 3