nimbus-eth1/nimbus/db/aristo/aristo_get.nim
Jordan Hrycaj 657379f484
Aristo db update merkle hasher (#1925)
* Register paths for added leafs because of trie re-balancing

why:
  While the payload would not change, the prefix in the leaf vertex
  would. So it needs to be flagged for hash recompilation for the
  `hashify()` module.

also:
  Make sure that `Hike` paths which might have vertex links into the
  backend filter are replaced by vertex copies before manipulating.
  Otherwise the vertices on the immutable filter might be involuntarily
  changed.

* Also check for paths where the leaf vertex is on the backend, already

why:
  A a path can have dome vertices on the top layer cache with the
  `Leaf` vertex on  the backend.

* Re-define a void `HashLabel` type.

why:
  A `HashLabel` type is a pair `(root-vertex-ID, Keccak-hash)`. Previously,
  a valid `HashLabel` consisted of a non-empty hash and a non-zero vertex
  ID. This definition leads to a non-unique representation of a void
  `HashLabel` with either root-ID or has void. This has been changed to
  the unique void `HashLabel` exactly if the hash entry is void.

* Update consistency checkers

* Re-org `hashify()` procedure

why:
  Syncing against block chain showed serious deficiencies which produced
  wrong hashes or simply bailed out with error.

  So all fringe cases (mainly due to deleted entries) could be integrated
  into the labelling schedule rather than handling separate fringe cases.
2023-12-04 20:39:26 +00:00

192 lines
5.7 KiB
Nim

# nimbus-eth1
# Copyright (c) 2023 Status Research & Development GmbH
# Licensed under either of
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
# http://www.apache.org/licenses/LICENSE-2.0)
# * MIT license ([LICENSE-MIT](LICENSE-MIT) or
# http://opensource.org/licenses/MIT)
# at your option. This file may not be copied, modified, or distributed
# except according to those terms.
## Read vertex record on the layered Aristo DB delta architecture
## ==============================================================
{.push raises: [].}
import
std/tables,
results,
./aristo_desc
type
VidVtxPair* = object
vid*: VertexID ## Table lookup vertex ID (if any)
vtx*: VertexRef ## Reference to vertex
# ------------------------------------------------------------------------------
# Public helpers
# ------------------------------------------------------------------------------
func dup*(wp: VidVtxPair): VidVtxPair =
VidVtxPair(
vid: wp.vid,
vtx: wp.vtx.dup)
# ------------------------------------------------------------------------------
# Public functions
# ------------------------------------------------------------------------------
proc getIdgUBE*(
db: AristoDbRef;
): Result[seq[VertexID],AristoError] =
## Get the ID generator state from the unfiltered backened if available.
let be = db.backend
if not be.isNil:
return be.getIdgFn()
err(GetIdgNotFound)
proc getFqsUBE*(
db: AristoDbRef;
): Result[seq[(QueueID,QueueID)],AristoError] =
## Get the list of filter IDs unfiltered backened if available.
let be = db.backend
if not be.isNil:
return be.getFqsFn()
err(GetFqsNotFound)
proc getVtxUBE*(
db: AristoDbRef;
vid: VertexID;
): Result[VertexRef,AristoError] =
## Get the vertex from the unfiltered backened if available.
let be = db.backend
if not be.isNil:
return be.getVtxFn vid
err GetVtxNotFound
proc getKeyUBE*(
db: AristoDbRef;
vid: VertexID;
): Result[HashKey,AristoError] =
## Get the merkle hash/key from the unfiltered backend if available.
let be = db.backend
if not be.isNil:
return be.getKeyFn vid
err GetKeyNotFound
proc getFilUBE*(
db: AristoDbRef;
qid: QueueID;
): Result[FilterRef,AristoError] =
## Get the filter from the unfiltered backened if available.
let be = db.backend
if not be.isNil:
return be.getFilFn qid
err GetFilNotFound
# ------------------
proc getIdgBE*(
db: AristoDbRef;
): Result[seq[VertexID],AristoError] =
## Get the ID generator state the `backened` layer if available.
if not db.roFilter.isNil:
return ok(db.roFilter.vGen)
db.getIdgUBE()
proc getVtxBE*(
db: AristoDbRef;
vid: VertexID;
): Result[VertexRef,AristoError] =
## Get the vertex from the (filtered) backened if available.
if not db.roFilter.isNil and db.roFilter.sTab.hasKey vid:
let vtx = db.roFilter.sTab.getOrVoid vid
if vtx.isValid:
return ok(vtx)
return err(GetVtxNotFound)
db.getVtxUBE vid
proc getKeyBE*(
db: AristoDbRef;
vid: VertexID;
): Result[HashKey,AristoError] =
## Get the merkle hash/key from the (filtered) backend if available.
if not db.roFilter.isNil and db.roFilter.kMap.hasKey vid:
let key = db.roFilter.kMap.getOrVoid vid
if key.isValid:
return ok(key)
return err(GetKeyNotFound)
db.getKeyUBE vid
# ------------------
proc getLeaf*(
db: AristoDbRef;
lty: LeafTie;
): Result[VidVtxPair,AristoError] =
## Get the vertex from the top layer by the `Patricia Trie` path. This
## function does not search on the `backend` layer.
let vid = db.top.lTab.getOrVoid lty
if not vid.isValid:
return err(GetLeafNotFound)
let vtx = db.top.sTab.getOrVoid vid
if not vtx.isValid:
return err(GetVtxNotFound)
ok VidVtxPair(vid: vid, vtx: vtx)
proc getLeafVtx*(db: AristoDbRef; lty: LeafTie): VertexRef =
## Variant of `getLeaf()` returning `nil` on error (while ignoring the
## detailed error type information.)
##
let rc = db.getLeaf lty
if rc.isOk:
return rc.value.vtx
# ------------------
proc getVtxRc*(db: AristoDbRef; vid: VertexID): Result[VertexRef,AristoError] =
## Cascaded attempt to fetch a vertex from the top layer or the backend.
##
if db.top.sTab.hasKey vid:
# If the vertex is to be deleted on the backend, a `VertexRef(nil)` entry
# is kept in the local table in which case it is OK to return this value.
let vtx = db.top.sTab.getOrVoid vid
if vtx.isValid:
return ok(vtx)
return err(GetVtxNotFound)
db.getVtxBE vid
proc getVtx*(db: AristoDbRef; vid: VertexID): VertexRef =
## Cascaded attempt to fetch a vertex from the top layer or the backend.
## The function returns `nil` on error or failure.
##
let rc = db.getVtxRc vid
if rc.isOk:
return rc.value
VertexRef(nil)
proc getKeyRc*(db: AristoDbRef; vid: VertexID): Result[HashKey,AristoError] =
## Cascaded attempt to fetch a Merkle hash from the top layer or the backend.
##
if db.top.kMap.hasKey vid:
# If the key is to be deleted on the backend, a `VOID_HASH_LABEL` entry
# is kept on the local table in which case it is OK to return this value.
let lbl = db.top.kMap.getOrVoid vid
if lbl.isValid:
return ok lbl.key
return err(GetKeyTempLocked)
db.getKeyBE vid
proc getKey*(db: AristoDbRef; vid: VertexID): HashKey =
## Cascaded attempt to fetch a vertex from the top layer or the backend.
## The function returns `nil` on error or failure.
##
db.getKeyRc(vid).valueOr:
return VOID_HASH_KEY
# ------------------------------------------------------------------------------
# End
# ------------------------------------------------------------------------------