nimbus-eth1/tests/test_aristo/test_aristo_cache.nim

198 lines
6.1 KiB
Nim

# nimbus-eth1
# Copyright (c) 2021 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.
{.push raises: [].}
## Parked here, currently uded only for trancode tests
import
std/tables,
eth/common,
stew/results,
../../nimbus/db/aristo/[aristo_desc, aristo_transcode, aristo_vid]
# ------------------------------------------------------------------------------
# Private helpers
# ------------------------------------------------------------------------------
proc convertPartially(
db: AristoDbRef;
vtx: VertexRef;
nd: var NodeRef;
): seq[VertexID] =
## Returns true if completely converted by looking up the cached hashes.
## This function does not recurse. It will return the vertex IDs that are
## are missing in order to convert in a single step.
case vtx.vType:
of Leaf:
nd = NodeRef(
vType: Leaf,
lPfx: vtx.lPfx,
lData: vtx.lData)
if vtx.lData.pType != AccountData:
return
let vid = vtx.lData.account.storageID
if vid.isValid:
let lbl = db.top.kMap.getOrVoid vid
if lbl.isValid:
nd.key[0] = lbl.key
return
result.add vid
of Extension:
nd = NodeRef(
vType: Extension,
ePfx: vtx.ePfx,
eVid: vtx.eVid)
let lbl = db.top.kMap.getOrVoid vtx.eVid
if lbl.isValid:
nd.key[0] = lbl.key
return
result.add vtx.eVid
of Branch:
nd = NodeRef(
vType: Branch,
bVid: vtx.bVid)
for n in 0..15:
if vtx.bVid[n].isValid:
let lbl = db.top.kMap.getOrVoid vtx.bVid[n]
if lbl.isValid:
nd.key[n] = lbl.key
continue
result.add vtx.bVid[n]
proc convertPartiallyOk(
db: AristoDbRef;
vtx: VertexRef;
nd: var NodeRef;
): bool =
## Variant of `convertPartially()`, shortcut for `convertPartially().le==0`.
case vtx.vType:
of Leaf:
nd = NodeRef(
vType: Leaf,
lPfx: vtx.lPfx,
lData: vtx.lData)
if vtx.lData.pType != AccountData:
result = true
else:
let vid = vtx.lData.account.storageID
if vid.isValid:
let lbl = db.top.kMap.getOrVoid vid
if lbl.isValid:
nd.key[0] = lbl.key
result = true
of Extension:
nd = NodeRef(
vType: Extension,
ePfx: vtx.ePfx,
eVid: vtx.eVid)
let lbl = db.top.kMap.getOrVoid vtx.eVid
if lbl.isValid:
nd.key[0] = lbl.key
result = true
of Branch:
nd = NodeRef(
vType: Branch,
bVid: vtx.bVid)
result = true
for n in 0..15:
if vtx.bVid[n].isValid:
let lbl = db.top.kMap.getOrVoid vtx.bVid[n]
if lbl.isValid:
nd.key[n] = lbl.key
continue
return false
proc cachedVID(db: AristoDbRef; lbl: HashLabel): VertexID =
## Get vertex ID from reverse cache
result = db.top.pAmk.getOrVoid lbl
if not result.isValid:
result = db.vidAttach lbl
# ------------------------------------------------------------------------------
# Public functions for `VertexID` => `HashKey` mapping
# ------------------------------------------------------------------------------
proc pal*(db: AristoDbRef; rootID: VertexID; vid: VertexID): HashKey =
## Retrieve the cached `Merkel` hash (aka `HashKey` object) associated with
## the argument `VertexID` type argument `vid`. Return a zero `HashKey` if
## there is none.
##
## If the vertex ID `vid` is not found in the cache, then the structural
## table is checked whether the cache can be updated.
if not db.top.isNil:
let lbl = db.top.kMap.getOrVoid vid
if lbl.isValid:
return lbl.key
let vtx = db.top.sTab.getOrVoid vid
if vtx.isValid:
var node: NodeRef
if db.convertPartiallyOk(vtx,node):
var w = initRlpWriter()
w.append node
result = w.finish.keccakHash.data.HashKey
db.top.kMap[vid] = HashLabel(root: rootID, key: result)
# ------------------------------------------------------------------------------
# Public funcions extending/completing vertex records
# ------------------------------------------------------------------------------
proc updated*(nd: NodeRef; root: VertexID; db: AristoDbRef): NodeRef =
## Return a copy of the argument node `nd` with updated missing vertex IDs.
##
## For a `Leaf` node, the payload data `PayloadRef` type reference is *not*
## duplicated and returned as-is.
##
## This function will not complain if all `Merkel` hashes (aka `HashKey`
## objects) are zero for either `Extension` or `Leaf` nodes.
if nd.isValid:
case nd.vType:
of Leaf:
result = NodeRef(
vType: Leaf,
lPfx: nd.lPfx,
lData: nd.lData)
of Extension:
result = NodeRef(
vType: Extension,
ePfx: nd.ePfx)
if nd.key[0].isValid:
result.eVid = db.cachedVID HashLabel(root: root, key: nd.key[0])
result.key[0] = nd.key[0]
of Branch:
result = NodeRef(
vType: Branch,
key: nd.key)
for n in 0..15:
if nd.key[n].isValid:
result.bVid[n] = db.cachedVID HashLabel(root: root, key: nd.key[n])
proc asNode*(vtx: VertexRef; db: AristoDbRef): NodeRef =
## Return a `NodeRef` object by augmenting missing `Merkel` hashes (aka
## `HashKey` objects) from the cache or from calculated cached vertex
## entries, if available.
##
## If not all `Merkel` hashes are available in a single lookup, then the
## result object is a wrapper around an error code.
if not db.convertPartiallyOk(vtx, result):
return NodeRef(error: CacheMissingNodekeys)
proc asNode*(rc: Result[VertexRef,AristoError]; db: AristoDbRef): NodeRef =
## Variant of `asNode()`.
if rc.isErr:
return NodeRef(error: rc.error)
rc.value.asNode(db)
# ------------------------------------------------------------------------------
# End
# ------------------------------------------------------------------------------