From e7be0d185cee8f200878a968a6f70d7818bbdc29 Mon Sep 17 00:00:00 2001 From: Jordan Hrycaj Date: Wed, 19 Jun 2024 12:40:00 +0000 Subject: [PATCH] Aristo uses pre classified tree types cont2 (#2397) * Provide dedicated functions for fetching accounts and storage trees why: Different prototypes for each class `account`, `generic` and `storage`. * Remove `fetchPayload()` and other cruft from API, `aristo_fetch`, etc. * Fix typos, debugging left overs, comments --- nimbus/db/aristo/aristo_api.nim | 123 ++++++-- nimbus/db/aristo/aristo_delete.nim | 2 +- nimbus/db/aristo/aristo_desc.nim | 6 +- nimbus/db/aristo/aristo_desc/desc_error.nim | 279 +++++++++--------- nimbus/db/aristo/aristo_fetch.nim | 172 ++++++++--- nimbus/db/aristo/aristo_layers.nim | 2 +- nimbus/db/aristo/aristo_merge.nim | 2 +- nimbus/db/aristo/aristo_utils.nim | 10 +- .../backend/aristo_db/handlers_aristo.nim | 69 ++--- 9 files changed, 408 insertions(+), 257 deletions(-) diff --git a/nimbus/db/aristo/aristo_api.nim b/nimbus/db/aristo/aristo_api.nim index b25155df0..98eed8169 100644 --- a/nimbus/db/aristo/aristo_api.nim +++ b/nimbus/db/aristo/aristo_api.nim @@ -108,15 +108,30 @@ type ## Merkle hash tag for vertex with ID 1 and a bespoke `uint64` identifier ## (may be interpreted as block number.) - AristoApiFetchPayloadFn* = + AristoApiFetchAccountPayloadFn* = + proc(db: AristoDbRef; + path: openArray[byte]; + ): Result[AristoAccount,AristoError] + {.noRaise.} + ## Fetch an account record from the database indexed by `path`. + + AristoApiFetchGenericDataFn* = proc(db: AristoDbRef; root: VertexID; path: openArray[byte]; - ): Result[PayloadRef,(VertexID,AristoError)] + ): Result[Blob,AristoError] {.noRaise.} - ## Cascaded attempt to traverse the `Aristo Trie` and fetch the value - ## of a leaf vertex. This function is complementary to some `mergeXXX()` - ## function. + ## For a generic sub-tree starting at `root`, fetch the data record + ## indexed by `path`. + + AristoApiFetchStorageDataFn* = + proc(db: AristoDbRef; + path: openArray[byte]; + accPath: PathID; + ): Result[Blob,AristoError] + {.noRaise.} + ## For a storage tree related to account `accPath`, fetch the data + ## record from the database indexed by `path`. AristoApiFindTxFn* = proc(db: AristoDbRef; @@ -205,15 +220,31 @@ type ## Add keys to the `Patricia Trie` so that it becomes a `Merkle ## Patricia Tree`. - AristoApiHasPathFn* = + AristoApiHasPathAccountFn* = + proc(db: AristoDbRef; + path: openArray[byte]; + ): Result[bool,AristoError] + {.noRaise.} + ## For an account record indexed by `path` query whether this record + ## exists on the database. + + AristoApiHasPathGenericFn* = proc(db: AristoDbRef; root: VertexID; path: openArray[byte]; - ): Result[bool,(VertexID,AristoError)] + ): Result[bool,AristoError] {.noRaise.} - ## Variant of `fetchPayload()` without returning data. It returns - ## `true` iff the database `db` contains a leaf item with the argument - ## path. + ## For a generic sub-tree starting at `root` and indexed by `path`, + ## mquery whether this record exists on the database. + + AristoApiHasPathStorageFn* = + proc(db: AristoDbRef; + path: openArray[byte]; + accPath: PathID; + ): Result[bool,AristoError] + {.noRaise.} + ## For a storage tree related to account `accPath`, query whether the + ## data record indexed by `path` exists on the database. AristoApiHikeUpFn* = proc(path: NibblesSeq; @@ -384,14 +415,18 @@ type deleteStorageData*: AristoApiDeleteStorageDataFn deleteStorageTree*: AristoApiDeleteStorageTreeFn fetchLastSavedState*: AristoApiFetchLastSavedStateFn - fetchPayload*: AristoApiFetchPayloadFn + fetchAccountPayload*: AristoApiFetchAccountPayloadFn + fetchGenericData*: AristoApiFetchGenericDataFn + fetchStorageData*: AristoApiFetchStorageDataFn findTx*: AristoApiFindTxFn finish*: AristoApiFinishFn forget*: AristoApiForgetFn forkTx*: AristoApiForkTxFn getKeyRc*: AristoApiGetKeyRcFn hashify*: AristoApiHashifyFn - hasPath*: AristoApiHasPathFn + hasPathAccount*: AristoApiHasPathAccountFn + hasPathGeneric*: AristoApiHasPathGenericFn + hasPathStorage*: AristoApiHasPathStorageFn hikeUp*: AristoApiHikeUpFn isTop*: AristoApiIsTopFn level*: AristoApiLevelFn @@ -419,14 +454,18 @@ type AristoApiProfDeleteStorageDataFn = "deleteStorageData" AristoApiProfDeleteStorageTreeFn = "deleteStorageTree" AristoApiProfFetchLastSavedStateFn = "fetchPayload" - AristoApiProfFetchPayloadFn = "fetchPayload" + AristoApiProfFetchAccountPayloadFn = "fetchAccountPayload" + AristoApiProfFetchGenericDataFn = "fetchGenericData" + AristoApiProfFetchStorageDataFn = "fetchStorageData" AristoApiProfFindTxFn = "findTx" AristoApiProfFinishFn = "finish" AristoApiProfForgetFn = "forget" AristoApiProfForkTxFn = "forkTx" AristoApiProfGetKeyRcFn = "getKeyRc" AristoApiProfHashifyFn = "hashify" - AristoApiProfHasPathFn = "hasPath" + AristoApiProfHasPathAccountFn = "hasPathAccount" + AristoApiProfHasPathGenericFn = "hasPathGeneric" + AristoApiProfHasPathStorageFn = "hasPathStorage" AristoApiProfHikeUpFn = "hikeUp" AristoApiProfIsTopFn = "isTop" AristoApiProfLevelFn = "level" @@ -470,14 +509,18 @@ when AutoValidateApiHooks: doAssert not api.deleteStorageData.isNil doAssert not api.deleteStorageTree.isNil doAssert not api.fetchLastSavedState.isNil - doAssert not api.fetchPayload.isNil + doAssert not api.fetchAccountPayload.isNil + doAssert not api.fetchGenericData.isNil + doAssert not api.fetchStorageData.isNil doAssert not api.findTx.isNil doAssert not api.finish.isNil doAssert not api.forget.isNil doAssert not api.forkTx.isNil doAssert not api.getKeyRc.isNil doAssert not api.hashify.isNil - doAssert not api.hasPath.isNil + doAssert not api.hasPathAccount.isNil + doAssert not api.hasPathGeneric.isNil + doAssert not api.hasPathStorage.isNil doAssert not api.hikeUp.isNil doAssert not api.isTop.isNil doAssert not api.level.isNil @@ -525,14 +568,18 @@ func init*(api: var AristoApiObj) = api.deleteStorageData = deleteStorageData api.deleteStorageTree = deleteStorageTree api.fetchLastSavedState = fetchLastSavedState - api.fetchPayload = fetchPayload + api.fetchAccountPayload = fetchAccountPayload + api.fetchGenericData = fetchGenericData + api.fetchStorageData = fetchStorageData api.findTx = findTx api.finish = finish api.forget = forget api.forkTx = forkTx api.getKeyRc = getKeyRc api.hashify = hashify - api.hasPath = hasPath + api.hasPathAccount = hasPathAccount + api.hasPathGeneric = hasPathGeneric + api.hasPathStorage = hasPathStorage api.hikeUp = hikeUp api.isTop = isTop api.level = level @@ -563,14 +610,18 @@ func dup*(api: AristoApiRef): AristoApiRef = deleteStorageData: api.deleteStorageData, deleteStorageTree: api.deleteStorageTree, fetchLastSavedState: api.fetchLastSavedState, - fetchPayload: api.fetchPayload, + fetchAccountPayload: api.fetchAccountPayload, + fetchGenericData: api.fetchGenericData, + fetchStorageData: api.fetchStorageData, findTx: api.findTx, finish: api.finish, forget: api.forget, forkTx: api.forkTx, getKeyRc: api.getKeyRc, hashify: api.hashify, - hasPath: api.hasPath, + hasPathAccount: api.hasPathAccount, + hasPathGeneric: api.hasPathGeneric, + hasPathStorage: api.hasPathStorage, hikeUp: api.hikeUp, isTop: api.isTop, level: api.level, @@ -650,10 +701,20 @@ func init*( AristoApiProfFetchLastSavedStateFn.profileRunner: result = api.fetchLastSavedState(a) - profApi.fetchPayload = + profApi.fetchAccountPayload = + proc(a: AristoDbRef; b: openArray[byte]): auto = + AristoApiProfFetchAccountPayloadFn.profileRunner: + result = api.fetchAccountPayload(a, b) + + profApi.fetchGenericData = proc(a: AristoDbRef; b: VertexID; c: openArray[byte]): auto = - AristoApiProfFetchPayloadFn.profileRunner: - result = api.fetchPayload(a, b, c) + AristoApiProfFetchGenericDataFn.profileRunner: + result = api.fetchGenericData(a, b, c) + + profApi.fetchStorageData = + proc(a: AristoDbRef; b: openArray[byte]; c: PathID;): auto = + AristoApiProfFetchStorageDataFn.profileRunner: + result = api.fetchStorageData(a, b, c) profApi.findTx = proc(a: AristoDbRef; b: VertexID; c: HashKey): auto = @@ -685,10 +746,20 @@ func init*( AristoApiProfHashifyFn.profileRunner: result = api.hashify(a) - profApi.hasPath = + profApi.hasPathAccount = + proc(a: AristoDbRef; b: openArray[byte]): auto = + AristoApiProfHasPathAccountFn.profileRunner: + result = api.hasPathAccount(a, b) + + profApi.hasPathGeneric = proc(a: AristoDbRef; b: VertexID; c: openArray[byte]): auto = - AristoApiProfHasPathFn.profileRunner: - result = api.hasPath(a, b, c) + AristoApiProfHasPathGenericFn.profileRunner: + result = api.hasPathGeneric(a, b, c) + + profApi.hasPathStorage = + proc(a: AristoDbRef; b: openArray[byte]; c: PathID;): auto = + AristoApiProfHasPathStorageFn.profileRunner: + result = api.hasPathStorage(a, b, c) profApi.hikeUp = proc(a: NibblesSeq; b: VertexID; c: AristoDbRef): auto = diff --git a/nimbus/db/aristo/aristo_delete.nim b/nimbus/db/aristo/aristo_delete.nim index 6a629ea6c..a65efe10c 100644 --- a/nimbus/db/aristo/aristo_delete.nim +++ b/nimbus/db/aristo/aristo_delete.nim @@ -19,7 +19,7 @@ import std/[sets, typetraits], eth/[common, trie/nibbles], results, - "."/[aristo_desc, aristo_get, aristo_hike, aristo_layers, aristo_path, + "."/[aristo_desc, aristo_get, aristo_hike, aristo_layers, aristo_utils, aristo_vid] type diff --git a/nimbus/db/aristo/aristo_desc.nim b/nimbus/db/aristo/aristo_desc.nim index 1891cd772..af23f5bde 100644 --- a/nimbus/db/aristo/aristo_desc.nim +++ b/nimbus/db/aristo/aristo_desc.nim @@ -239,9 +239,9 @@ proc forget*(db: AristoDbRef): Result[void,AristoError] = ## comments on `fork()`.) ## if db.isCentre: - err(NotAllowedOnCentre) + err(DescNotAllowedOnCentre) elif db notin db.dudes.peers: - err(StaleDescriptor) + err(DescStaleDescriptor) else: db.dudes.peers.excl db # Unlink argument `db` from peers list ok() @@ -252,7 +252,7 @@ proc forgetOthers*(db: AristoDbRef): Result[void,AristoError] = ## if not db.dudes.isNil: if db.dudes.centre != db: - return err(MustBeOnCentre) + return err(DescMustBeOnCentre) db.dudes = DudesRef(nil) ok() diff --git a/nimbus/db/aristo/aristo_desc/desc_error.nim b/nimbus/db/aristo/aristo_desc/desc_error.nim index ddefce590..6bd29727a 100644 --- a/nimbus/db/aristo/aristo_desc/desc_error.nim +++ b/nimbus/db/aristo/aristo_desc/desc_error.nim @@ -11,21 +11,16 @@ type AristoError* = enum NothingSerious = 0 + + # Miscelaneous/unclassified handy helpers GenericError - # Rlp decoder, `read()` - Rlp2Or17ListEntries - RlpBlobExpected - RlpBranchHashKeyExpected - RlpEmptyBlobExpected - RlpExtHashKeyExpected - RlpHashKeyExpected - RlpNonEmptyBlobExpected - RlpOtherException - RlpRlpException + AccRootUnacceptable + MptRootUnacceptable + MptRootMissing + NotImplemented + TrieInvalid - # Serialise decoder - SerCantResolveStorageRoot # Data record transcoders, `deblobify()` and `blobify()` BlobifyBranchMissingRefs @@ -37,6 +32,51 @@ type BlobifyStateSrcLenGarbled BlobifyStateTrgLenGarbled + + # Cache checker `checkCache()` + CheckAnyVidDeadStorageRoot + CheckAnyVidSharedStorageRoot + CheckAnyVtxEmptyKeyMissing + CheckAnyVtxEmptyKeyExpected + CheckAnyVtxEmptyKeyMismatch + CheckAnyVtxBranchLinksMissing + CheckAnyVtxExtPfxMissing + CheckAnyVtxLockWithoutKey + CheckAnyVTopUnset + + CheckBeCacheGarbledVTop + CheckBeCacheIsDirty + CheckBeCacheKeyCantCompile + CheckBeCacheKeyDangling + CheckBeCacheKeyMismatch + CheckBeCacheKeyMissing + CheckBeCacheKeyNonEmpty + CheckBeCacheVidUnsynced + CheckBeCacheVtxDangling + CheckBeFifoSrcTrgMismatch + CheckBeFifoTrgNotStateRoot + CheckBeGarbledVTop + CheckBeKeyCantCompile + CheckBeKeyInvalid + CheckBeKeyMismatch + CheckBeKeyMissing + CheckBeVtxBranchLinksMissing + CheckBeVtxExtPfxMissing + CheckBeVtxInvalid + CheckBeVtxMissing + + CheckStkKeyStrayZeroEntry + CheckStkVtxIncomplete + CheckStkVtxKeyMismatch + CheckStkVtxKeyMissing + + CheckRlxVidVtxMismatch + CheckRlxVtxIncomplete + CheckRlxVtxKeyMissing + CheckRlxVtxKeyMismatch + + + # De-serialiser from `blobify.nim` DeblobNilArgument DeblobUnknown DeblobVtxTooShort @@ -64,8 +104,68 @@ type DeblobFilterTrpVtxSizeGarbled DeblobFilterSizeGarbled - # Converter `asNode()`, currenly for unit tests only - CacheMissingNodekeys + + # Deletion of vertex paths, `deleteXxx()` + DelAccRootNotAccepted + DelBranchExpexted + DelBranchLocked + DelBranchWithoutRefs + DelDanglingStoTrie + DelExtLocked + DelLeafExpexted + DelLeafLocked + DelLeafUnexpected + DelPathNotFound + DelPathTagError + DelRootVidMissing + DelStoAccMissing + DelStoRootMissing + DelStoRootNotAccepted + DelSubTreeAccRoot + DelSubTreeVoidRoot + DelVidStaleVtx + + + # Functions from `aristo_desc.nim` + DescMustBeOnCentre + DescNotAllowedOnCentre + DescStaleDescriptor + + + # Functions from `aristo_filter.nim` + FilBackendMissing + FilBackendRoMode + FilNilFilterRejected + FilSiblingsCommitUnfinshed + FilSrcTrgInconsistent + FilStateRootMismatch + FilTrgSrcMismatch + + + # Fetch functions from `aristo_fetch.nim` + FetchPathNotFound + FetchLeafKeyInvalid + FetchPathInvalid + FetchRootVidMissing + FetchAccRootNotAccepted + FetchStoRootNotAccepted + + + # Get functions from `aristo_get.nim` + GetFilNotFound + GetFqsNotFound + GetKeyNotFound + GetKeyUpdateNeeded + GetLstNotFound + GetTuvNotFound + GetVtxNotFound + + + # Update `Merkle` hashes `hashify()` + HashifyVtxUnresolved + HashifyRootVtxUnresolved + HashifyProofHashMismatch + # Path function `hikeUp()` HikeBranchMissingEdge @@ -79,10 +179,6 @@ type HikeNoLegs HikeRootMissing - # Path/nibble/key conversions in `aisto_path.nim` - PathExpected64Nibbles - PathAtMost64Nibbles - PathExpectedLeaf # Merge leaf `merge()` MergeAssemblyFailed # Ooops, internal error @@ -119,61 +215,6 @@ type MergeRootKeysOverflow MergeRootVidMissing - # Update `Merkle` hashes `hashify()` - HashifyVtxUnresolved - HashifyRootVtxUnresolved - HashifyProofHashMismatch - - # Cache checker `checkCache()` - CheckStkKeyStrayZeroEntry - CheckStkVtxIncomplete - CheckStkVtxKeyMismatch - CheckStkVtxKeyMissing - - CheckRlxVidVtxMismatch - CheckRlxVtxIncomplete - CheckRlxVtxKeyMissing - CheckRlxVtxKeyMismatch - - CheckAnyVidDeadStorageRoot - CheckAnyVidSharedStorageRoot - CheckAnyVtxEmptyKeyMissing - CheckAnyVtxEmptyKeyExpected - CheckAnyVtxEmptyKeyMismatch - CheckAnyVtxBranchLinksMissing - CheckAnyVtxExtPfxMissing - CheckAnyVtxLockWithoutKey - CheckAnyVTopUnset - - # Backend structural check `checkBE()` - CheckBeVtxInvalid - CheckBeVtxMissing - CheckBeVtxBranchLinksMissing - CheckBeVtxExtPfxMissing - CheckBeKeyInvalid - CheckBeKeyMissing - CheckBeKeyCantCompile - CheckBeKeyMismatch - CheckBeGarbledVTop - - CheckBeCacheIsDirty - CheckBeCacheKeyMissing - CheckBeCacheKeyNonEmpty - CheckBeCacheVidUnsynced - CheckBeCacheKeyDangling - CheckBeCacheVtxDangling - CheckBeCacheKeyCantCompile - CheckBeCacheKeyMismatch - CheckBeCacheGarbledVTop - - CheckBeFifoSrcTrgMismatch - CheckBeFifoTrgNotStateRoot - - # Jornal check `checkJournal()` - CheckJrnCachedQidOverlap - CheckJrnSavedQidMissing - CheckJrnSavedQidStale - CheckJrnLinkingGap # Neighbour vertex, tree traversal `nearbyRight()` and `nearbyLeft()` NearbyBeyondRange @@ -189,50 +230,12 @@ type NearbyUnexpectedVtx NearbyVidInvalid - # Deletion of vertices, `delete()` - DelAccRootNotAccepted - DelBranchExpexted - DelBranchLocked - DelBranchWithoutRefs - DelDanglingStoTrie - DelExtLocked - DelLeafExpexted - DelLeafLocked - DelLeafUnexpected - DelPathNotFound - DelPathTagError - DelRootVidMissing - DelStoAccMissing - DelStoRootMissing - DelStoRootNotAccepted - DelSubTreeAccRoot - DelSubTreeVoidRoot - DelVidStaleVtx - # Functions from `aristo_filter.nim` - FilBackendMissing - FilBackendRoMode - FilNilFilterRejected - FilSiblingsCommitUnfinshed - FilSrcTrgInconsistent - FilStateRootMismatch - FilTrgSrcMismatch + # Path/nibble/key conversions in `aisto_path.nim` + PathExpected64Nibbles + PathAtMost64Nibbles + PathExpectedLeaf - # Get functions from `aristo_get.nim` - GetLeafMissing - GetKeyUpdateNeeded - - GetLeafNotFound - GetVtxNotFound - GetKeyNotFound - GetFilNotFound - GetTuvNotFound - GetLstNotFound - GetFqsNotFound - - # Fetch functions from `aristo_fetch.nim` - FetchPathNotFound - LeafKeyInvalid # RocksDB backend RdbBeCantCreateDataDir @@ -256,6 +259,23 @@ type RdbGuestInstanceUnsupported RdbHashKeyExpected + + # Rlp decoder, `read()` + Rlp2Or17ListEntries + RlpBlobExpected + RlpBranchHashKeyExpected + RlpEmptyBlobExpected + RlpExtHashKeyExpected + RlpHashKeyExpected + RlpNonEmptyBlobExpected + RlpOtherException + RlpRlpException + + + # Serialise decoder + SerCantResolveStorageRoot + + # Transaction wrappers TxAccRootMissing TxArgStaleTx @@ -267,38 +287,23 @@ type TxNotFound TxNotTopTx TxPendingTx + TxPrettyPointlessLayer TxStackGarbled TxStackUnderflow - - TxPrettyPointlessLayer TxStateRootMismatch - # Functions from `aristo_desc.nim` - MustBeOnCentre - NotAllowedOnCentre - StaleDescriptor # Functions from `aristo_utils.nim` - AccRlpDecodingError - AccStorageKeyMissing - AccVtxUnsupported - AccNodeUnsupported - PayloadTypeUnsupported - + UtilsAccInaccessible + UtilsAccLeafPayloadExpected + UtilsAccNodeUnsupported UtilsAccPathMissing UtilsAccPathWithoutLeaf - UtilsAccInaccessible + UtilsAccStorageKeyMissing + UtilsAccVtxUnsupported UtilsAccWrongStorageRoot + UtilsPayloadTypeUnsupported UtilsStoRootInaccessible UtilsStoRootMissing - UtilsAccLeafPayloadExpected - - # Miscelaneous handy helpers - AccRootUnacceptable - MptRootUnacceptable - MptRootMissing - NotImplemented - TrieInvalid - VidContextLocked # End diff --git a/nimbus/db/aristo/aristo_fetch.nim b/nimbus/db/aristo/aristo_fetch.nim index ee98e9f28..81e6772bd 100644 --- a/nimbus/db/aristo/aristo_fetch.nim +++ b/nimbus/db/aristo/aristo_fetch.nim @@ -14,70 +14,76 @@ {.push raises: [].} import - eth/trie/nibbles, + std/typetraits, + eth/[common, trie/nibbles], results, - "."/[aristo_desc, aristo_get, aristo_hike] + "."/[aristo_desc, aristo_get, aristo_hike, aristo_utils] # ------------------------------------------------------------------------------ # Private functions # ------------------------------------------------------------------------------ -proc fetchPayloadImpl( - rc: Result[Hike,(VertexID,AristoError,Hike)]; - ): Result[PayloadRef,(VertexID,AristoError)] = - if rc.isErr: - if rc.error[1] in HikeAcceptableStopsNotFound: - return err((rc.error[0], FetchPathNotFound)) - return err((rc.error[0], rc.error[1])) - ok rc.value.legs[^1].wp.vtx.lData +func mustBeGeneric( + root: VertexID; + ): Result[void,AristoError] = + ## Verify that `root` is neither from an accounts tree nor a strorage tree. + if not root.isValid: + return err(FetchRootVidMissing) + elif root == VertexID(1): + return err(FetchAccRootNotAccepted) + elif LEAST_FREE_VID <= root.distinctBase: + return err(FetchStoRootNotAccepted) + ok() -proc fetchPayloadImpl( + +proc retrievePayload( db: AristoDbRef; root: VertexID; path: openArray[byte]; - ): Result[PayloadRef,(VertexID,AristoError)] = - path.initNibbleRange.hikeUp(root, db).fetchPayloadImpl + ): Result[PayloadRef,AristoError] = + if path.len == 0: + return err(FetchPathInvalid) + + let hike = path.initNibbleRange.hikeUp(root, db).valueOr: + if error[1] in HikeAcceptableStopsNotFound: + return err(FetchPathNotFound) + return err(error[1]) + + ok hike.legs[^1].wp.vtx.lData + + +proc retrieveStoID( + db: AristoDbRef; + accPath: PathID; + ): Result[VertexID,AristoError] = + let + accHike = ? db.retrieveStoAccHike accPath # checks for `AccountData` + stoID = accHike.legs[^1].wp.vtx.lData.account.storageID + + if not stoID.isValid: + return err(FetchPathNotFound) + + ok stoID + + +proc hasPayload( + db: AristoDbRef; + root: VertexID; + path: openArray[byte]; + ): Result[bool,AristoError] = + if path.len == 0: + return err(FetchPathInvalid) + + let hike = path.initNibbleRange.hikeUp(VertexID(1), db).valueOr: + if error[1] in HikeAcceptableStopsNotFound: + return ok(false) + return err(error[1]) + ok(true) # ------------------------------------------------------------------------------ # Public functions # ------------------------------------------------------------------------------ -proc fetchPayload*( - db: AristoDbRef; - key: LeafTie; - ): Result[PayloadRef,(VertexID,AristoError)] = - ## Cascaded attempt to traverse the `Aristo Trie` and fetch the value of a - ## leaf vertex. This function is complementary to `mergePayload()`. - ## - key.hikeUp(db).fetchPayloadImpl - -proc fetchPayload*( - db: AristoDbRef; - root: VertexID; - path: openArray[byte]; - ): Result[PayloadRef,(VertexID,AristoError)] = - ## Variant of `fetchPayload()` - ## - if path.len == 0: - return err((VertexID(0),LeafKeyInvalid)) - db.fetchPayloadImpl(root, path) - -proc hasPath*( - db: AristoDbRef; # Database - root: VertexID; - path: openArray[byte]; # Key of database record - ): Result[bool,(VertexID,AristoError)] = - ## Variant of `fetchPayload()` - ## - if path.len == 0: - return err((VertexID(0),LeafKeyInvalid)) - let rc = db.fetchPayloadImpl(root, path) - if rc.isOk: - return ok(true) - if rc.error[1] == FetchPathNotFound: - return ok(false) - err(rc.error) - proc fetchLastSavedState*( db: AristoDbRef; ): Result[SavedState,AristoError] = @@ -86,6 +92,74 @@ proc fetchLastSavedState*( ## `uint64` identifier (may be interpreted as block number.) db.getLstUbe() + +proc fetchAccountPayload*( + db: AristoDbRef; + path: openArray[byte]; + ): Result[AristoAccount,AristoError] = + ## Fetch an account record from the database indexed by `path`. + ## + let pyl = ? db.retrievePayload(VertexID(1), path) + assert pyl.pType == AccountData # debugging only + ok pyl.account + +proc hasPathAccount*( + db: AristoDbRef; + path: openArray[byte]; + ): Result[bool,AristoError] = + ## For an account record indexed by `path` query whether this record exists + ## on the database. + ## + db.hasPayload(VertexID(1), path) + + +proc fetchGenericData*( + db: AristoDbRef; + root: VertexID; + path: openArray[byte]; + ): Result[Blob,AristoError] = + ## For a generic sub-tree starting at `root`, fetch the data record + ## indexed by `path`. + ## + ? root.mustBeGeneric() + let pyl = ? db.retrievePayload(root, path) + assert pyl.pType == RawData # debugging only + ok pyl.rawBlob + +proc hasPathGeneric*( + db: AristoDbRef; + root: VertexID; + path: openArray[byte]; + ): Result[bool,AristoError] = + ## For a generic sub-tree starting at `root` and indexed by `path`, query + ## whether this record exists on the database. + ## + ? root.mustBeGeneric() + db.hasPayload(root, path) + + +proc fetchStorageData*( + db: AristoDbRef; + path: openArray[byte]; + accPath: PathID; + ): Result[Blob,AristoError] = + ## For a storage tree related to account `accPath`, fetch the data record + ## from the database indexed by `path`. + ## + let pyl = ? db.retrievePayload(? db.retrieveStoID accPath, path) + assert pyl.pType == RawData # debugging only + ok pyl.rawBlob + +proc hasPathStorage*( + db: AristoDbRef; + path: openArray[byte]; + accPath: PathID; + ): Result[bool,AristoError] = + ## For a storage tree related to account `accPath`, query whether the data + ## record indexed by `path` exists on the database. + ## + db.hasPayload(? db.retrieveStoID accPath, path) + # ------------------------------------------------------------------------------ # End # ------------------------------------------------------------------------------ diff --git a/nimbus/db/aristo/aristo_layers.nim b/nimbus/db/aristo/aristo_layers.nim index 4b398021f..4d0806184 100644 --- a/nimbus/db/aristo/aristo_layers.nim +++ b/nimbus/db/aristo/aristo_layers.nim @@ -97,7 +97,7 @@ func layersGetKey*(db: AristoDbRef; vid: VertexID): Opt[HashKey] = Opt.none(HashKey) func layersGetKeyOrVoid*(db: AristoDbRef; vid: VertexID): HashKey = - ## Simplified version of `layersGetkey()` + ## Simplified version of `layersGetKey()` db.layersGetKey(vid).valueOr: VOID_HASH_KEY diff --git a/nimbus/db/aristo/aristo_merge.nim b/nimbus/db/aristo/aristo_merge.nim index 6d08726c4..bca83c752 100644 --- a/nimbus/db/aristo/aristo_merge.nim +++ b/nimbus/db/aristo/aristo_merge.nim @@ -120,7 +120,7 @@ proc mergeStorageData*( ## otherwise `VertexID(0)`. ## let - accHike = ?db.retrieveStoAccHike accPath + accHike = ? db.retrieveStoAccHike accPath # checks for `AccountData` wpAcc = accHike.legs[^1].wp stoID = wpAcc.vtx.lData.account.storageID diff --git a/nimbus/db/aristo/aristo_utils.nim b/nimbus/db/aristo/aristo_utils.nim index db78edfe2..057e1a506 100644 --- a/nimbus/db/aristo/aristo_utils.nim +++ b/nimbus/db/aristo/aristo_utils.nim @@ -40,7 +40,7 @@ proc toAccount*( acc.storageRoot = (? db.getKeyRc payload.account.storageID).to(Hash256) return ok(acc) - err PayloadTypeUnsupported + err UtilsPayloadTypeUnsupported proc toAccount*( vtx: VertexRef; @@ -49,7 +49,7 @@ proc toAccount*( ## Variant of `toAccount()` for a `Leaf` vertex. if vtx.isValid and vtx.vType == Leaf: return vtx.lData.toAccount db - err AccVtxUnsupported + err UtilsAccVtxUnsupported proc toAccount*( node: NodeRef; @@ -65,13 +65,13 @@ proc toAccount*( storageRoot: EMPTY_ROOT_HASH) if node.lData.account.storageID.isValid: if not node.key[0].isValid: - return err(AccStorageKeyMissing) + return err(UtilsAccStorageKeyMissing) acc.storageRoot = node.key[0].to(Hash256) return ok(acc) else: - return err(PayloadTypeUnsupported) + return err(UtilsPayloadTypeUnsupported) - err AccNodeUnsupported + err UtilsAccNodeUnsupported # --------------------- diff --git a/nimbus/db/core_db/backend/aristo_db/handlers_aristo.nim b/nimbus/db/core_db/backend/aristo_db/handlers_aristo.nim index 08389d888..2dfd71fa5 100644 --- a/nimbus/db/core_db/backend/aristo_db/handlers_aristo.nim +++ b/nimbus/db/core_db/backend/aristo_db/handlers_aristo.nim @@ -155,6 +155,7 @@ func toRc[T]( return ok(rc.value) err rc.error.toError(base, info, error) + func toRc[T]( rc: Result[T,AristoError]; base: AristoBaseRef; @@ -206,12 +207,11 @@ proc mptMethods(cMpt: AristoCoreDxMptRef): CoreDbMptFns = # The mpt might have become empty let key = cMpt.address.keccakHash.data - pyl = api.fetchPayload(mpt, AccountsVID, key).valueOr: - raiseAssert "mptColFn(): " & $error[1] & " at " & $error[0] + acc = api.fetchAccountPayload(mpt, key).valueOr: + raiseAssert "mptColFn(): " & $error # Update by accounts data - doAssert pyl.pType == AccountData - cMpt.mptRoot = pyl.account.storageID + cMpt.mptRoot = acc.storageID db.bless AristoColRef( base: base, @@ -222,20 +222,24 @@ proc mptMethods(cMpt: AristoCoreDxMptRef): CoreDbMptFns = proc mptFetch(key: openArray[byte]): CoreDbRc[Blob] = const info = "fetchFn()" - # Some pathological behaviour observed with storage column due to lazy - # update. The `fetchPayload()` does not now about this and would complain - # an error different from `FetchPathNotFound`. - let rootVID = cMpt.mptRoot - if not rootVID.isValid: - return err((VoidVID,MptRootMissing).toError(base, info, MptNotFound)) + let rc = block: + if cMpt.accPath.isValid: + api.fetchStorageData(mpt, key, cMpt.accPath) + elif cMpt.mptRoot.isValid: + api.fetchGenericData(mpt, cMpt.mptRoot, key) + else: + # Some pathological behaviour observed with storage column due to lazy + # update. The `fetchXxxPayload()` does not now about this and would + # complain an error different from `FetchPathNotFound`. + return err(MptRootMissing.toError(base, info, MptNotFound)) - let rc = api.fetchPayload(mpt, rootVID, key) + # let rc = api.fetchPayload(mpt, rootVID, key) if rc.isOk: - api.serialise(mpt, rc.value).toRc(base, info) - elif rc.error[1] != FetchPathNotFound: + ok rc.value + elif rc.error != FetchPathNotFound: err(rc.error.toError(base, info)) else: - err rc.error.toError(base, info, MptNotFound) + err(rc.error.toError(base, info, MptNotFound)) proc mptMerge(k: openArray[byte]; v: openArray[byte]): CoreDbRc[void] = const info = "mergeFn()" @@ -280,7 +284,13 @@ proc mptMethods(cMpt: AristoCoreDxMptRef): CoreDbMptFns = proc mptHasPath(key: openArray[byte]): CoreDbRc[bool] = const info = "hasPathFn()" - let rc = api.hasPath(mpt, cMpt.mptRoot, key) + let rc = block: + if cMpt.accPath.isValid: + api.hasPathStorage(mpt, key, cMpt.accPath) + else: + api.hasPathGeneric(mpt, cMpt.mptRoot, key) + + #let rc = api.hasPath(mpt, cMpt.mptRoot, key) if rc.isErr: return err(rc.error.toError(base, info)) ok(rc.value) @@ -333,21 +343,14 @@ proc accMethods(cAcc: AristoCoreDxAccRef): CoreDbAccFns = proc accFetch(address: EthAddress): CoreDbRc[CoreDbAccount] = const info = "acc/fetchFn()" - let pyl = block: - let - key = address.keccakHash.data - rc = api.fetchPayload(mpt, AccountsVID, key) - if rc.isOk: - rc.value - elif rc.error[1] != FetchPathNotFound: - return err(rc.error.toError(base, info)) - else: - return err(rc.error.toError(base, info, AccNotFound)) + let + key = address.keccakHash.data + acc = api.fetchAccountPayload(mpt, key).valueOr: + if error != FetchPathNotFound: + return err(error.toError(base, info)) + return err(error.toError(base, info, AccNotFound)) - if pyl.pType != AccountData: - let vidErrPair = (pyl.account.storageID, PayloadTypeUnsupported) - return err(vidErrPair.toError(base, info & "/" & $pyl.pType)) - ok cAcc.toCoreDbAccount(pyl.account, address) + ok cAcc.toCoreDbAccount(acc, address) proc accMerge(account: CoreDbAccount): CoreDbRc[void] = const info = "acc/mergeFn()" @@ -385,10 +388,9 @@ proc accMethods(cAcc: AristoCoreDxAccRef): CoreDbAccFns = let key = address.keccakHash.data - rc = api.hasPath(mpt, AccountsVID, key) - if rc.isErr: - return err(rc.error.toError(base, info)) - ok(rc.value) + yn = api.hasPathAccount(mpt, key).valueOr: + return err(error.toError(base, info)) + ok(yn) CoreDbAccFns( @@ -499,7 +501,6 @@ proc ctxMethods(cCtx: AristoCoreDbCtxRef): CoreDbCtxFns = if reset: let rc = api.deleteGenericTree(mpt, newMpt.mptRoot) if rc.isErr: - raiseAssert "find me" return err(rc.error.toError(base, info, AutoFlushFailed)) col.reset = false