remove pPrf, fRpp (#2445)

No longer used now that hashify is gone
This commit is contained in:
Jacek Sieka 2024-07-03 22:21:57 +02:00 committed by GitHub
parent 443c6d1f8e
commit b23795ab39
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 29 additions and 597 deletions

View File

@ -61,27 +61,14 @@ proc checkTopStrict*(
proc checkTopProofMode*(
db: AristoDbRef; # Database, top layer
): Result[void,(VertexID,AristoError)] =
if 0 < db.pPrf.len:
for vid in db.pPrf:
let vtx = db.layersGetVtxOrVoid vid
for (vid,key) in db.layersWalkKey:
if key.isValid: # Otherwise to be deleted
let vtx = db.getVtx vid
if vtx.isValid:
let node = vtx.toNode(db).valueOr:
return err((vid,CheckRlxVtxIncomplete))
let key = db.layersGetKeyOrVoid vid
if not key.isValid:
return err((vid,CheckRlxVtxKeyMissing))
continue
if key != node.digestTo(HashKey):
return err((vid,CheckRlxVtxKeyMismatch))
else:
for (vid,key) in db.layersWalkKey:
if key.isValid: # Otherwise to be deleted
let vtx = db.getVtx vid
if vtx.isValid:
let node = vtx.toNode(db).valueOr:
continue
if key != node.digestTo(HashKey):
return err((vid,CheckRlxVtxKeyMismatch))
ok()
@ -145,9 +132,6 @@ proc checkTopCommon*(
if kMapNilCount != 0 and kMapNilCount < nNilVtx:
return err((VertexID(0),CheckAnyVtxEmptyKeyMismatch))
for vid in db.pPrf:
if db.layersGetKey(vid).isErr:
return err((vid,CheckAnyVtxLockWithoutKey))
ok()
# ------------------------------------------------------------------------------

View File

@ -86,18 +86,6 @@ proc stripZeros(a: string; toExp = false): string =
elif 2 < n:
result &= "" & $n
proc vidCode(key: HashKey, db: AristoDbRef): uint64 =
if key.isValid:
block:
let vid = db.layerGetProofVidOrVoid key
if vid.isValid:
db.xMap.add(key, vid)
return vid.uint64
block:
let vids = db.xMap.getOrVoid key
if vids.isValid:
return vids.sortedKeys[0].uint64
# ---------------------
proc ppKeyOk(
@ -106,11 +94,6 @@ proc ppKeyOk(
vid: VertexID;
): string =
if key.isValid and vid.isValid:
block:
let vid = db.layerGetProofVidOrVoid key
if vid.isValid:
db.xMap.add(key, vid)
return
block:
let vids = db.xMap.getOrVoid key
if vids.isValid:
@ -162,11 +145,6 @@ proc ppVidList(vLst: openArray[VertexID]): string =
proc ppKey(key: HashKey; db: AristoDbRef; pfx = true): string =
proc getVids(): tuple[vids: HashSet[VertexID], xMapTag: string] =
block:
let vid = db.layerGetProofVidOrVoid key
if vid.isValid:
db.xMap.add(key, vid)
return (@[vid].toHashSet, "")
block:
let vids = db.xMap.getOrVoid key
if vids.isValid:
@ -221,7 +199,7 @@ proc ppVtx(nd: VertexRef, db: AristoDbRef, vid: VertexID): string =
if not nd.isValid:
result = "ø"
else:
if not vid.isValid or vid in db.pPrf:
if not vid.isValid:
result = ["L(", "X(", "B("][nd.vType.ord]
elif db.layersGetKey(vid).isOk:
result = ["l(", "x(", "b("][nd.vType.ord]
@ -250,21 +228,6 @@ proc ppSTab(
.mapIt("(" & it[0].ppVid & "," & it[1].ppVtx(db,it[0]) & ")")
.join(indent.toPfx(1)) & "}"
proc ppPPrf(pPrf: HashSet[VertexID]): string =
result = "{"
if 0 < pPrf.len:
let isr = IntervalSetRef[VertexID,uint64].init()
for w in pPrf:
doAssert isr.merge(w,w) == 1
for iv in isr.increasing():
result &= iv.minPt.ppVid
if 1 < iv.len:
result &= ".. " & iv.maxPt.ppVid
result &= ", "
result.setlen(result.len - 2)
#result &= pPrf.sortedKeys.mapIt(it.ppVid).join(",")
result &= "}"
proc ppXMap*(
db: AristoDbRef;
kMap: Table[VertexID,HashKey];
@ -341,10 +304,7 @@ proc ppXMap*(
for vid in kMap.sortedKeys:
let key = kMap.getOrVoid vid
if key.isValid:
cache.add (vid.uint64, key.vidCode(db), vid in multi)
let vids = db.xMap.getOrVoid key
if (0 < vids.len and vid notin vids) or key.len < 32:
cache[^1][2] = true
discard # TODO obsolete - clean up?
else:
cache.add (vid.uint64, 0u64, true)
@ -377,16 +337,6 @@ proc ppXMap*(
else:
result &= "}"
proc ppFRpp(
fRpp: Table[HashKey,VertexID];
db: AristoDbRef;
indent = 4;
): string =
let
xMap = fRpp.pairs.toSeq.mapIt((it[1],it[0])).toTable
xStr = db.ppXMap(xMap, indent)
"<" & xStr[1..^2] & ">"
proc ppFilter(
fl: LayerDeltaRef;
db: AristoDbRef;
@ -468,14 +418,12 @@ proc ppLayer(
vTopOk: bool;
sTabOk: bool;
kMapOk: bool;
pPrfOk: bool;
fRppOk: bool;
indent = 4;
): string =
let
pfx1 = indent.toPfx(1)
pfx2 = indent.toPfx(2)
nOKs = vTopOk.ord + sTabOk.ord + kMapOk.ord + pPrfOk.ord + fRppOk.ord
nOKs = vTopOk.ord + sTabOk.ord + kMapOk.ord
tagOk = 1 < nOKs
var
pfy = ""
@ -510,16 +458,6 @@ proc ppLayer(
info = "kMap(" & lInf & ")"
result &= info.doPrefix(0 < tLen + uLen)
result &= db.ppXMap(layer.delta.kMap, indent+2)
if pPrfOk:
let
tLen = layer.final.pPrf.len
info = "pPrf(" & $tLen & ")"
result &= info.doPrefix(0 < tLen) & layer.final.pPrf.ppPPrf
if fRppOk:
let
tLen = layer.final.fRpp.len
info = "fRpp(" & $tLen & ")"
result &= info.doPrefix(0 < tLen) & layer.final.fRpp.ppFRpp(db,indent+2)
# ------------------------------------------------------------------------------
# Public functions
@ -610,9 +548,6 @@ proc pp*(
): string =
sTab.ppSTab(db.orDefault)
proc pp*(pPrf: HashSet[VertexID]): string =
pPrf.ppPPrf
proc pp*(leg: Leg; db = AristoDbRef(nil)): string =
let db = db.orDefault()
result = "(" & leg.wp.vid.ppVid & ","
@ -669,7 +604,7 @@ proc pp*(
indent = 4;
): string =
layer.ppLayer(
db, vTopOk=true, sTabOk=true, kMapOk=true, pPrfOk=true, fRppOk=true)
db, vTopOk=true, sTabOk=true, kMapOk=true)
proc pp*(
layer: LayerRef;
@ -678,7 +613,7 @@ proc pp*(
indent = 4;
): string =
layer.ppLayer(
db, vTopOk=true, sTabOk=xTabOk, kMapOk=true, pPrfOk=true, fRppOk=true)
db, vTopOk=true, sTabOk=xTabOk, kMapOk=true)
proc pp*(
layer: LayerRef;
@ -689,7 +624,7 @@ proc pp*(
indent = 4;
): string =
layer.ppLayer(
db, vTopOk=other, sTabOk=xTabOk, kMapOk=kMapOk, pPrfOk=other, fRppOk=other)
db, vTopOk=other, sTabOk=xTabOk, kMapOk=kMapOk)
proc pp*(

View File

@ -16,7 +16,7 @@
{.push raises: [].}
import
std/[sets, typetraits],
std/typetraits,
eth/common,
results,
"."/[aristo_desc, aristo_fetch, aristo_get, aristo_hike, aristo_layers,
@ -274,8 +274,6 @@ proc deleteImpl(
let lf = hike.legs[^1].wp
if lf.vtx.vType != Leaf:
return err((lf.vid,DelLeafExpexted))
if lf.vid in db.pPrf:
return err((lf.vid, DelLeafLocked))
db.disposeOfVtx(hike.root, lf.vid)
@ -295,8 +293,6 @@ proc deleteImpl(
# Clear all Merkle hash keys up to the root key
for n in 0 .. hike.legs.len - 2:
let vid = hike.legs[n].wp.vid
if vid in db.top.final.pPrf:
return err((vid, DelBranchLocked))
db.layersResKey(hike.root, vid)
let nibble = block:

View File

@ -15,7 +15,7 @@
{.push raises: [].}
import
std/[hashes, sets, tables],
std/[hashes, tables],
eth/common,
"."/[desc_error, desc_identifiers]
@ -114,23 +114,11 @@ type
accSids*: Table[Hash256, VertexID] ## Account path -> stoID
LayerFinalRef* = ref object
## Final tables fully supersede tables on lower layers when stacked as a
## whole. Missing entries on a higher layers are the final state (for the
## the top layer version of the table.)
##
## These structures are used for tables which are typically smaller then
## the ones on the `LayerDelta` object.
##
pPrf*: HashSet[VertexID] ## Locked vertices (proof nodes)
fRpp*: Table[HashKey,VertexID] ## Key lookup for `pPrf[]` (proof nodes)
LayerRef* = ref LayerObj
LayerObj* = object
## Hexary trie database layer structures. Any layer holds the full
## change relative to the backend.
delta*: LayerDeltaRef ## Most structural tables held as deltas
final*: LayerFinalRef ## Stored as latest version
txUid*: uint ## Transaction identifier if positive
# ------------------------------------------------------------------------------
@ -139,8 +127,7 @@ type
func init*(T: type LayerRef): T =
## Constructor, returns empty layer
T(delta: LayerDeltaRef(),
final: LayerFinalRef())
T(delta: LayerDeltaRef())
func hash*(node: NodeRef): Hash =
## Table/KeyedQueue/HashSet mixin
@ -271,12 +258,6 @@ func dup*(node: NodeRef): NodeRef =
bVid: node.bVid,
key: node.key)
func dup*(final: LayerFinalRef): LayerFinalRef =
## Duplicate final layer.
LayerFinalRef(
pPrf: final.pPrf,
fRpp: final.fRpp)
func dup*(wp: VidVtxPair): VidVtxPair =
## Safe copy of `wp` argument
VidVtxPair(

View File

@ -52,8 +52,7 @@ proc newAristoRdbDbRef(
rc.value
ok((AristoDbRef(
top: LayerRef(
delta: LayerDeltaRef(vTop: vTop),
final: LayerFinalRef()),
delta: LayerDeltaRef(vTop: vTop)),
backend: be), oCfs))
# ------------------------------------------------------------------------------

View File

@ -29,9 +29,6 @@ func dup(sTab: Table[VertexID,VertexRef]): Table[VertexID,VertexRef] =
# Public getters: lazy value lookup for read only versions
# ------------------------------------------------------------------------------
func pPrf*(db: AristoDbRef): lent HashSet[VertexID] =
db.top.final.pPrf
func vTop*(db: AristoDbRef): VertexID =
db.top.delta.vTop
@ -94,20 +91,6 @@ func layersGetKeyOrVoid*(db: AristoDbRef; vid: VertexID): HashKey =
## Simplified version of `layersGetKey()`
db.layersGetKey(vid).valueOr: VOID_HASH_KEY
func layerGetProofKeyOrVoid*(db: AristoDbRef; vid: VertexID): HashKey =
## Get the hash key of a proof node if it was registered as such.
if vid in db.top.final.pPrf:
db.top.delta.kMap.getOrVoid vid
else:
VOID_HASH_KEY
func layerGetProofVidOrVoid*(db: AristoDbRef; key: HashKey): VertexID =
## Reverse look up for a registered proof node or a link key for such a
## node. The vertex for a returned vertex ID might not exist if the
## argument `key` refers to a link key of a registered proof node.
db.top.final.fRpp.getOrVoid key
func layersGetStoID*(db: AristoDbRef; accPath: Hash256): Opt[VertexID] =
db.top.delta.accSids.withValue(accPath, item):
return Opt.some(item[])
@ -156,27 +139,6 @@ func layersResKey*(db: AristoDbRef; root: VertexID; vid: VertexID) =
## equivalent of a delete function.
db.layersPutKey(root, vid, VOID_HASH_KEY)
func layersPutProof*(db: AristoDbRef; vid: VertexID; key: HashKey) =
## Register a link key of a proof node.
let lKey = db.layersGetKeyOrVoid vid
if not lKey.isValid or lKey != key:
db.top.delta.kMap[vid] = key
db.top.final.fRpp[key] = vid
func layersPutProof*(
db: AristoDbRef;
vid: VertexID;
key: HashKey;
vtx: VertexRef;
) =
## Register a full proof node (not only a link key.)
let lVtx = db.layersGetVtxOrVoid vid
if not lVtx.isValid or lVtx != vtx:
db.top.delta.sTab[vid] = vtx
db.top.final.pPrf.incl vid
db.layersPutProof(vid, key)
func layersPutStoID*(db: AristoDbRef; accPath: Hash256; stoID: VertexID) =
db.top.delta.accSids[accPath] = stoID
@ -188,7 +150,6 @@ func layersMergeOnto*(src: LayerRef; trg: var LayerObj) =
## Merges the argument `src` into the argument `trg` and returns `trg`. For
## the result layer, the `txUid` value set to `0`.
##
trg.final = src.final
trg.txUid = 0
for (vid,vtx) in src.delta.sTab.pairs:
@ -209,7 +170,6 @@ func layersCc*(db: AristoDbRef; level = high(int)): LayerRef =
# Set up initial layer (bottom layer)
result = LayerRef(
final: layers[^1].final.dup, # Pre-merged/final values
delta: LayerDeltaRef(
sTab: layers[0].delta.sTab.dup, # explicit dup for ref values
kMap: layers[0].delta.kMap,

View File

@ -29,10 +29,7 @@ import
eth/common,
results,
"."/[aristo_desc, aristo_fetch, aristo_layers, aristo_utils, aristo_vid],
./aristo_merge/[merge_payload_helper, merge_proof]
export
merge_proof
./aristo_merge/merge_payload_helper
const
MergeNoAction = {MergeLeafPathCachedAlready, MergeLeafPathOnBackendAlready}

View File

@ -11,7 +11,7 @@
{.push raises: [].}
import
std/[sets, typetraits],
std/typetraits,
eth/common,
results,
".."/[aristo_desc, aristo_get, aristo_hike, aristo_layers, aristo_vid]
@ -100,10 +100,7 @@ proc insertBranch(
# Install `forkVtx`
block:
# Clear Merkle hashes (aka hash keys) unless proof mode.
if db.pPrf.len == 0:
db.clearMerkleKeys(hike, linkID)
elif linkID in db.pPrf:
return err(MergeNonBranchProofModeLock)
db.clearMerkleKeys(hike, linkID)
if linkVtx.vType == Leaf:
# Double check path prefix
@ -196,10 +193,7 @@ proc concatBranchAndLeaf(
return err(MergeRootBranchLinkBusy)
# Clear Merkle hashes (aka hash keys) unless proof mode.
if db.pPrf.len == 0:
db.clearMerkleKeys(hike, brVid)
elif brVid in db.pPrf:
return err(MergeBranchProofModeLock) # Ooops
db.clearMerkleKeys(hike, brVid)
# Append branch vertex
var okHike = Hike(root: hike.root, legs: hike.legs)
@ -264,26 +258,13 @@ proc mergePayloadTopIsBranchAddLeaf(
#
# <-------- immutable ------------> <---- mutable ----> ..
#
if db.pPrf.len == 0:
# Not much else that can be done here
raiseAssert "Dangling edge:" &
" pfx=" & $hike.legsTo(hike.legs.len-1,NibblesBuf) &
" branch=" & $parent &
" nibble=" & $nibble &
" edge=" & $linkID &
" tail=" & $hike.tail
# Reuse placeholder entry in table
let vtx = VertexRef(
vType: Leaf,
lPfx: hike.tail,
lData: payload)
db.setVtxAndKey(hike.root, linkID, vtx)
var okHike = Hike(root: hike.root, legs: hike.legs)
okHike.legs.add Leg(wp: VidVtxPair(vid: linkID, vtx: vtx), nibble: -1)
if parent notin db.pPrf:
db.layersResKey(hike.root, parent)
return ok(okHike)
# Not much else that can be done here
raiseAssert "Dangling edge:" &
" pfx=" & $hike.legsTo(hike.legs.len-1,NibblesBuf) &
" branch=" & $parent &
" nibble=" & $nibble &
" edge=" & $linkID &
" tail=" & $hike.tail
if linkVtx.vType == Branch:
# Slot link to a branch vertex should be handled by `hikeUp()`
@ -347,10 +328,7 @@ proc mergePayloadTopIsExtAddLeaf(
return err(MergeRootBranchLinkBusy)
# Clear Merkle hashes (aka hash keys) unless proof mode
if db.pPrf.len == 0:
db.clearMerkleKeys(hike, brVid)
elif brVid in db.pPrf:
return err(MergeBranchProofModeLock)
db.clearMerkleKeys(hike, brVid)
let
brDup = brVtx.dup
@ -382,10 +360,7 @@ proc mergePayloadTopIsEmptyAddLeaf(
return err(MergeRootBranchLinkBusy)
# Clear Merkle hashes (aka hash keys) unless proof mode
if db.pPrf.len == 0:
db.clearMerkleKeys(hike, hike.root)
elif hike.root in db.pPrf:
return err(MergeBranchProofModeLock)
db.clearMerkleKeys(hike, hike.root)
let
rootDup = rootVtx.dup
@ -416,8 +391,6 @@ proc mergePayloadUpdate(
# Update payloads if they differ
if leafLeg.wp.vtx.lData != payload:
let vid = leafLeg.wp.vid
if vid in db.pPrf:
return err(MergeLeafProofModeLock)
# Update accounts storage root which is handled implicitly
if hike.root == VertexID(1):

View File

@ -1,364 +0,0 @@
# nimbus-eth1
# Copyright (c) 2023-2024 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: [].}
import
std/[algorithm, sets, tables],
eth/common,
results,
stew/keyed_queue,
../../../sync/protocol/snap/snap_types,
".."/[aristo_desc, aristo_get, aristo_layers, aristo_serialise, aristo_vid]
# ------------------------------------------------------------------------------
# Private functions: add Merkle proof node
# ------------------------------------------------------------------------------
proc mergeNodeImpl(
db: AristoDbRef; # Database, top layer
hashKey: HashKey; # Merkel hash of node (or so)
node: NodeRef; # Node derived from RLP representation
rootVid: VertexID; # Current sub-trie
): Result[void,AristoError] =
## The function merges the argument hash key `lid` as expanded from the
## node RLP representation into the `Aristo Trie` database. The vertex is
## split off from the node and stored separately. So are the Merkle hashes.
## The vertex is labelled `locked`.
##
## The `node` argument is *not* checked, whether the vertex IDs have been
## allocated, already. If the node comes straight from the `decode()` RLP
## decoder as expected, these vertex IDs will be all zero.
##
## This function expects that the parent for the argument `node` has already
## been installed.
##
## Caveat:
## Proof of concept, not in production yet.
##
# Check for error after RLP decoding
doAssert node.error == AristoError(0)
# Verify arguments
if not rootVid.isValid:
return err(MergeRootKeyInvalid)
if not hashKey.isValid:
return err(MergeHashKeyInvalid)
# Make sure that the `vid<->key` reverse mapping is updated.
let vid = db.layerGetProofVidOrVoid hashKey
if not vid.isValid:
return err(MergeRevVidMustHaveBeenCached)
# Use the vertex ID `vid` to be populated by the argument root node
let key = db.layersGetKeyOrVoid vid
if key.isValid and key != hashKey:
return err(MergeHashKeyDiffersFromCached)
# Set up vertex.
let (vtx, newVtxFromNode) = block:
let vty = db.getVtx vid
if vty.isValid:
(vty, false)
else:
(node.to(VertexRef), true)
# The `vertexID <-> hashKey` mappings need to be set up now (if any)
case node.vType:
of Leaf:
# Check whether there is need to convert the payload to `Account` payload
if rootVid == VertexID(1) and newVtxFromNode:
try:
let
# `aristo_serialise.read()` always decodes raw data payloaf
acc = rlp.decode(node.lData.rawBlob, Account)
pyl = PayloadRef(
pType: AccountData,
account: AristoAccount(
nonce: acc.nonce,
balance: acc.balance,
codeHash: acc.codeHash))
if acc.storageRoot.isValid:
var sid = db.layerGetProofVidOrVoid acc.storageRoot.to(HashKey)
if not sid.isValid:
sid = db.vidFetch
db.layersPutProof(sid, acc.storageRoot.to(HashKey))
pyl.stoID = sid
vtx.lData = pyl
except RlpError:
return err(MergeNodeAccountPayloadError)
of Extension:
if node.key[0].isValid:
let eKey = node.key[0]
if newVtxFromNode:
vtx.eVid = db.layerGetProofVidOrVoid eKey
if not vtx.eVid.isValid:
# Brand new reverse lookup link for this vertex
vtx.eVid = db.vidFetch
elif not vtx.eVid.isValid:
return err(MergeNodeVidMissing)
else:
let yEke = db.getKey vtx.eVid
if yEke.isValid and eKey != yEke:
return err(MergeNodeVtxDiffersFromExisting)
db.layersPutProof(vtx.eVid, eKey)
of Branch:
for n in 0..15:
if node.key[n].isValid:
let bKey = node.key[n]
if newVtxFromNode:
vtx.bVid[n] = db.layerGetProofVidOrVoid bKey
if not vtx.bVid[n].isValid:
# Brand new reverse lookup link for this vertex
vtx.bVid[n] = db.vidFetch
elif not vtx.bVid[n].isValid:
return err(MergeNodeVidMissing)
else:
let yEkb = db.getKey vtx.bVid[n]
if yEkb.isValid and yEkb != bKey:
return err(MergeNodeVtxDiffersFromExisting)
db.layersPutProof(vtx.bVid[n], bKey)
# Store and lock vertex
db.layersPutProof(vid, key, vtx)
ok()
# ------------------------------------------------------------------------------
# Public functions
# ------------------------------------------------------------------------------
proc mergeProof*(
db: AristoDbRef; # Database, top layer
proof: openArray[SnapProof]; # RLP encoded node records
rootVid = VertexID(0); # Current sub-trie
): Result[int, AristoError]
{.gcsafe, raises: [RlpError].} =
## The function merges the argument `proof` list of RLP encoded node records
## into the `Aristo Trie` database. This function is intended to be used with
## the proof nodes as returened by `snap/1` messages.
##
## If there is no root vertex ID passed, the function tries to find out what
## the root hashes are and allocates new vertices with static IDs `$2`, `$3`,
## etc.
##
## Caveat:
## Proof of concept, not in production yet.
##
proc update(
seen: var Table[HashKey,NodeRef];
todo: var KeyedQueueNV[NodeRef];
key: HashKey;
) {.gcsafe, raises: [RlpError].} =
## Check for embedded nodes, i.e. fully encoded node instead of a hash.
## They need to be treated as full nodes, here.
if key.isValid and key.len < 32:
let lid = key.data.digestTo(HashKey)
if not seen.hasKey lid:
let node = key.data.decode(NodeRef)
discard todo.append node
seen[lid] = node
let rootKey = block:
if rootVid.isValid:
let vidKey = db.getKey rootVid
if not vidKey.isValid:
return err(MergeRootKeyInvalid)
# Make sure that the reverse lookup for the root vertex key is available.
if not db.layerGetProofVidOrVoid(vidKey).isValid:
return err(MergeProofInitMissing)
vidKey
else:
VOID_HASH_KEY
# Expand and collect hash keys and nodes and parent indicator
var
nodeTab: Table[HashKey,NodeRef]
rootKeys: HashSet[HashKey] # Potential root node hashes
for w in proof:
let
key = w.Blob.digestTo(HashKey)
node = rlp.decode(w.Blob,NodeRef)
if node.error != AristoError(0):
return err(node.error)
nodeTab[key] = node
rootKeys.incl key
# Check for embedded nodes, i.e. fully encoded node instead of a hash.
# They will be added as full nodes to the `nodeTab[]`.
var embNodes: KeyedQueueNV[NodeRef]
discard embNodes.append node
while true:
let node = embNodes.shift.valueOr: break
case node.vType:
of Leaf:
discard
of Branch:
for n in 0 .. 15:
nodeTab.update(embNodes, node.key[n])
of Extension:
nodeTab.update(embNodes, node.key[0])
# Create a table with back links
var
backLink: Table[HashKey,HashKey]
blindNodes: HashSet[HashKey]
for (key,node) in nodeTab.pairs:
case node.vType:
of Leaf:
blindNodes.incl key
of Extension:
if nodeTab.hasKey node.key[0]:
backLink[node.key[0]] = key
rootKeys.excl node.key[0] # predecessor => not root
else:
blindNodes.incl key
of Branch:
var isBlind = true
for n in 0 .. 15:
if nodeTab.hasKey node.key[n]:
isBlind = false
backLink[node.key[n]] = key
rootKeys.excl node.key[n] # predecessor => not root
if isBlind:
blindNodes.incl key
# If it exists, the root key must be in the set `mayBeRoot` in order
# to work.
var roots: Table[HashKey,VertexID]
if rootVid.isValid:
if rootKey notin rootKeys:
return err(MergeRootKeyNotInProof)
roots[rootKey] = rootVid
elif rootKeys.len == 0:
return err(MergeRootKeysMissing)
else:
# Add static root keys different from VertexID(1)
var count = 2
for key in rootKeys.items:
while true:
# Check for already allocated nodes
let vid1 = db.layerGetProofVidOrVoid key
if vid1.isValid:
roots[key] = vid1
break
# Use the next free static free vertex ID
let vid2 = VertexID(count)
count.inc
if not db.getKey(vid2).isValid:
doAssert not db.layerGetProofVidOrVoid(key).isValid
db.layersPutProof(vid2, key)
roots[key] = vid2
break
if LEAST_FREE_VID <= count:
return err(MergeRootKeysOverflow)
# Run over blind nodes and build chains from a blind/bottom level node up
# to the root node. Select only chains that end up at the pre-defined root
# node.
var
accounts: seq[seq[HashKey]] # This one separated, to be processed last
chains: seq[seq[HashKey]]
for w in blindNodes:
# Build a chain of nodes up to the root node
var
chain: seq[HashKey]
nodeKey = w
while nodeKey.isValid and nodeTab.hasKey nodeKey:
chain.add nodeKey
nodeKey = backLink.getOrVoid nodeKey
if 0 < chain.len and chain[^1] in roots:
if roots.getOrVoid(chain[0]) == VertexID(1):
accounts.add chain
else:
chains.add chain
# Process over chains in reverse mode starting with the root node. This
# allows the algorithm to find existing nodes on the backend.
var
seen: HashSet[HashKey]
merged = 0
# Process the root ID which is common to all chains
for chain in chains & accounts:
let chainRootVid = roots.getOrVoid chain[^1]
for key in chain.reversed:
if key notin seen:
seen.incl key
let node = nodeTab.getOrVoid key
db.mergeNodeImpl(key, node, chainRootVid).isOkOr:
return err(error)
merged.inc
ok merged
proc mergeProof*(
db: AristoDbRef; # Database, top layer
rootHash: Hash256; # Merkle hash for root
rootVid = VertexID(0); # Optionally, force root vertex ID
): Result[VertexID,AristoError] =
## Set up a `rootKey` associated with a vertex ID for use with proof nodes.
##
## If argument `rootVid` is unset then a new dybamic root vertex (i.e.
## the ID will be at least `LEAST_FREE_VID`) will be installed.
##
## Otherwise, if the argument `rootVid` is set then a sub-trie with root
## `rootVid` is checked for. An error is returned if it is set up already
## with a different `rootHash`.
##
## Upon successful return, the vertex ID assigned to the root key is returned.
##
## Caveat:
## Proof of concept, not in production yet.
##
let rootKey = rootHash.to(HashKey)
if rootVid.isValid:
let key = db.getKey rootVid
if key.isValid:
if rootKey.isValid and key != rootKey:
# Cannot use installed root key differing from hash argument
return err(MergeRootKeyDiffersForVid)
# Confirm root ID and key for proof nodes processing
db.layersPutProof(rootVid, key) # note that `rootKey` might be void
return ok rootVid
if not rootHash.isValid:
return err(MergeRootArgsIncomplete)
if db.getVtx(rootVid).isValid:
# Cannot use verify root key for existing root vertex
return err(MergeRootKeyMissing)
# Confirm root ID and hash key for proof nodes processing
db.layersPutProof(rootVid, rootKey)
return ok rootVid
if not rootHash.isValid:
return err(MergeRootArgsIncomplete)
# Now there is no root vertex ID, only the hash argument.
# So Create and assign a new root key.
let vid = db.vidFetch
db.layersPutProof(vid, rootKey)
return ok vid
proc mergeProof*(
db: AristoDbRef; # Database, top layer
rootVid: VertexID; # Root ID
): Result[VertexID,AristoError] =
## Variant of `mergeProof()` for missing `rootHash`
db.mergeProof(EMPTY_ROOT_HASH, rootVid)
# ------------------------------------------------------------------------------
# End
# ------------------------------------------------------------------------------

View File

@ -65,8 +65,7 @@ proc txFork*(
let rc = db.getTuvBE()
if rc.isOk:
LayerRef(
delta: LayerDeltaRef(vTop: rc.value),
final: LayerFinalRef())
delta: LayerDeltaRef(vTop: rc.value))
elif rc.error == GetTuvNotFound:
LayerRef.init()
else:

View File

@ -85,7 +85,6 @@ proc txFrameBegin*(db: AristoDbRef): Result[AristoTxRef,AristoError] =
db.stack.add db.top
db.top = LayerRef(
delta: LayerDeltaRef(vTop: vTop),
final: db.top.final.dup,
txUid: db.getTxUid)
db.txRef = AristoTxRef(

View File

@ -100,11 +100,6 @@ proc txStow*(
if rc.isErr and rc.error != TxPrettyPointlessLayer:
return err(rc.error)
# Special treatment for `snap` proofs (aka `chunkedMpt`)
let final =
if chunkedMpt: LayerFinalRef(fRpp: db.top.final.fRpp)
else: LayerFinalRef()
# Move/merge/install `top` layer onto `balancer`
if rc.isOk:
db.topMerge(rc.value).isOkOr:
@ -112,8 +107,7 @@ proc txStow*(
# New empty top layer (probably with `snap` proofs and `vTop` carry over)
db.top = LayerRef(
delta: LayerDeltaRef(),
final: final)
delta: LayerDeltaRef())
if db.balancer.isValid:
db.top.delta.vTop = db.balancer.vTop
else:
@ -137,7 +131,6 @@ proc txStow*(
# New empty top layer (probably with `snap` proofs carry over)
db.top = LayerRef(
delta: LayerDeltaRef(vTop: db.vTop),
final: final,
txUid: db.top.txUid)
ok()

View File

@ -20,7 +20,6 @@ import
stew/byteutils,
"../.."/[errors, constants],
".."/[aristo, storage_types],
./backend/aristo_db,
"."/base
logScope:

View File

@ -27,7 +27,6 @@ import
aristo_hike,
aristo_init/persistent,
aristo_layers,
aristo_merge,
aristo_nearby,
aristo_tx],
../replay/xcheck,
@ -569,19 +568,6 @@ proc testTxMergeProofAndKvpList*(
# var lst = w.kvpLst.mapRootVid testRootVid
if 0 < w.proof.len:
let root = block:
let rc = db.mergeProof(rootKey, testRootVid)
xCheckRc rc.error == 0
rc.value
let nMerged = block:
let rc = db.mergeProof(w.proof, root)
xCheckRc rc.error == 0
rc.value
xCheck w.proof.len == nMerged
xCheck db.nLayersVtx() <= nMerged + sTabLen
let merged = db.mergeList leafs
xCheck merged.error in {AristoError(0), MergeLeafPathCachedAlready}

View File

@ -70,11 +70,6 @@ proc preLoadAristoDb(cdb: CoreDbRef; jKvp: JsonNode; num: BlockNumber) =
# Set up production MPT
doAssert adb.mergeProof(proof).isOk
# Remove locks so that hashify can re-assign changed nodes
adb.top.final.pPrf.clear
adb.top.final.fRpp.clear
# use tracerTestGen.nim to generate additional test data
proc testFixtureImpl(node: JsonNode, testStatusIMPL: var TestStatus, memoryDB: CoreDbRef) =
setErrorLevel()