simplify VertexRef (#2626)

* move pfx out of variant which avoids pointless field type panic checks
and copies on access
* make `VertexRef` a non-inheritable object which reduces its memory
footprint and simplifies its use - it's also unclear from a semantic
point of view why inheritance makes sense for storing keys
This commit is contained in:
Jacek Sieka 2024-09-13 18:55:17 +02:00 committed by GitHub
parent 0be6291fba
commit adb8d64377
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 133 additions and 143 deletions

View File

@ -200,8 +200,8 @@ proc blobifyTo*(vtx: VertexRef; data: var Blob): Result[void,AristoError] =
let let
pSegm = pSegm =
if vtx.ePfx.len > 0: if vtx.pfx.len > 0:
vtx.ePfx.toHexPrefix(isleaf = false) vtx.pfx.toHexPrefix(isleaf = false)
else: else:
default(HexPrefixBuf) default(HexPrefixBuf)
psLen = pSegm.len.byte psLen = pSegm.len.byte
@ -214,7 +214,7 @@ proc blobifyTo*(vtx: VertexRef; data: var Blob): Result[void,AristoError] =
of Leaf: of Leaf:
let let
pSegm = vtx.lPfx.toHexPrefix(isleaf = true) pSegm = vtx.pfx.toHexPrefix(isleaf = true)
psLen = pSegm.len.byte psLen = pSegm.len.byte
if psLen == 0 or 33 < psLen: if psLen == 0 or 33 < psLen:
return err(BlobifyLeafPathOverflow) return err(BlobifyLeafPathOverflow)
@ -325,7 +325,7 @@ proc deblobify*(
# End `while` # End `while`
VertexRef( VertexRef(
vType: Branch, vType: Branch,
ePfx: pathSegment, pfx: pathSegment,
bVid: vtxList) bVid: vtxList)
of 3: # `Leaf` vertex of 3: # `Leaf` vertex
@ -341,7 +341,7 @@ proc deblobify*(
return err(DeblobLeafGotExtPrefix) return err(DeblobLeafGotExtPrefix)
let vtx = VertexRef( let vtx = VertexRef(
vType: Leaf, vType: Leaf,
lPfx: pathSegment) pfx: pathSegment)
? record.toOpenArray(0, pLen - 1).deblobify(vtx.lData) ? record.toOpenArray(0, pLen - 1).deblobify(vtx.lData)
vtx vtx

View File

@ -68,7 +68,7 @@ proc computeKeyImpl(
case vtx.vType: case vtx.vType:
of Leaf: of Leaf:
writer.startList(2) writer.startList(2)
writer.append(vtx.lPfx.toHexPrefix(isLeaf = true).data()) writer.append(vtx.pfx.toHexPrefix(isLeaf = true).data())
case vtx.lData.pType case vtx.lData.pType
of AccountData: of AccountData:
@ -106,12 +106,12 @@ proc computeKeyImpl(
else: else:
w.append(VOID_HASH_KEY) w.append(VOID_HASH_KEY)
w.append EmptyBlob w.append EmptyBlob
if vtx.ePfx.len > 0: # Extension node if vtx.pfx.len > 0: # Extension node
var bwriter = initRlpWriter() var bwriter = initRlpWriter()
writeBranch(bwriter) writeBranch(bwriter)
writer.startList(2) writer.startList(2)
writer.append(vtx.ePfx.toHexPrefix(isleaf = false).data()) writer.append(vtx.pfx.toHexPrefix(isleaf = false).data())
writer.append(bwriter.finish().digestTo(HashKey)) writer.append(bwriter.finish().digestTo(HashKey))
else: else:
writeBranch(writer) writeBranch(writer)

View File

@ -209,9 +209,9 @@ proc ppVtx(nd: VertexRef, db: AristoDbRef, rvid: RootedVertexID): string =
result = ["ł(", "þ("][nd.vType.ord] result = ["ł(", "þ("][nd.vType.ord]
case nd.vType: case nd.vType:
of Leaf: of Leaf:
result &= nd.lPfx.ppPathPfx & "," & nd.lData.ppPayload(db) result &= nd.pfx.ppPathPfx & "," & nd.lData.ppPayload(db)
of Branch: of Branch:
result &= nd.ePfx.ppPathPfx & ":" result &= nd.pfx.ppPathPfx & ":"
for n in 0..15: for n in 0..15:
if nd.bVid[n].isValid: if nd.bVid[n].isValid:
result &= nd.bVid[n].ppVid result &= nd.bVid[n].ppVid
@ -229,33 +229,33 @@ proc ppNode(
result = "ø" result = "ø"
else: else:
if not rvid.isValid: if not rvid.isValid:
result = ["L(", "B("][nd.vType.ord] result = ["L(", "B("][nd.vtx.vType.ord]
elif db.layersGetKey(rvid).isOk: elif db.layersGetKey(rvid).isOk:
result = ["l(", "b("][nd.vType.ord] result = ["l(", "b("][nd.vtx.vType.ord]
else: else:
result = ["ł(", "þ("][nd.vType.ord] result = ["ł(", "þ("][nd.vtx.vType.ord]
case nd.vType: case nd.vtx.vType:
of Leaf: of Leaf:
result &= nd.lPfx.ppPathPfx & "," result &= nd.vtx.pfx.ppPathPfx & ","
if nd.lData.pType == AccountData: if nd.vtx.lData.pType == AccountData:
result &= "(" & nd.lData.account.ppAriAccount() & "," result &= "(" & nd.vtx.lData.account.ppAriAccount() & ","
if nd.lData.stoID.isValid: if nd.vtx.lData.stoID.isValid:
let tag = db.ppKeyOk(nd.key[0],(rvid.root,nd.lData.stoID.vid)) let tag = db.ppKeyOk(nd.key[0],(rvid.root,nd.vtx.lData.stoID.vid))
result &= nd.lData.stoID.ppVid & tag result &= nd.vtx.lData.stoID.ppVid & tag
else: else:
result &= nd.lData.stoID.ppVid result &= nd.vtx.lData.stoID.ppVid
if nd.key[0].isValid: if nd.key[0].isValid:
result &= nd.key[0].ppKey(db) result &= nd.key[0].ppKey(db)
result &= ")" result &= ")"
else: else:
result &= nd.lData.ppPayload(db) result &= nd.vtx.lData.ppPayload(db)
of Branch: of Branch:
let keyOnly = nd.bVid.toSeq.filterIt(it.isValid).len == 0 let keyOnly = nd.vtx.bVid.toSeq.filterIt(it.isValid).len == 0
result &= nd.ePfx.ppPathPfx & ":" result &= nd.vtx.pfx.ppPathPfx & ":"
for n in 0..15: for n in 0..15:
if nd.bVid[n].isValid: if nd.vtx.bVid[n].isValid:
let tag = db.ppKeyOk(nd.key[n],(rvid.root,nd.bVid[n])) let tag = db.ppKeyOk(nd.key[n],(rvid.root,nd.vtx.bVid[n]))
result &= nd.bVid[n].ppVid & tag result &= nd.vtx.bVid[n].ppVid & tag
elif keyOnly and nd.key[n].isValid: elif keyOnly and nd.key[n].isValid:
result &= nd.key[n].ppKey(db) result &= nd.key[n].ppKey(db)
if n < 15: if n < 15:

View File

@ -97,12 +97,12 @@ proc deleteImpl(
of Leaf: of Leaf:
VertexRef( VertexRef(
vType: Leaf, vType: Leaf,
lPfx: br.vtx.ePfx & NibblesBuf.nibble(nbl.byte) & nxt.lPfx, pfx: br.vtx.pfx & NibblesBuf.nibble(nbl.byte) & nxt.pfx,
lData: nxt.lData) lData: nxt.lData)
of Branch: of Branch:
VertexRef( VertexRef(
vType: Branch, vType: Branch,
ePfx: br.vtx.ePfx & NibblesBuf.nibble(nbl.byte) & nxt.ePfx, pfx: br.vtx.pfx & NibblesBuf.nibble(nbl.byte) & nxt.pfx,
bVid: nxt.bVid) bVid: nxt.bVid)
# Put the new vertex at the id of the obsolete branch # Put the new vertex at the id of the obsolete branch

View File

@ -58,10 +58,10 @@ proc delStoTreeNow(
if vtx.bVid[i].isValid: if vtx.bVid[i].isValid:
? db.delStoTreeNow( ? db.delStoTreeNow(
(rvid.root, vtx.bVid[i]), accPath, (rvid.root, vtx.bVid[i]), accPath,
stoPath & vtx.ePfx & NibblesBuf.nibble(byte i)) stoPath & vtx.pfx & NibblesBuf.nibble(byte i))
of Leaf: of Leaf:
let stoPath = Hash256(data: (stoPath & vtx.lPfx).getBytes()) let stoPath = Hash256(data: (stoPath & vtx.pfx).getBytes())
db.layersPutStoLeaf(mixUp(accPath, stoPath), nil) db.layersPutStoLeaf(mixUp(accPath, stoPath), nil)
db.disposeOfVtx(rvid) db.disposeOfVtx(rvid)

View File

@ -68,20 +68,21 @@ type
of StoData: of StoData:
stoData*: UInt256 stoData*: UInt256
VertexRef* = ref object of RootRef VertexRef* = ref object
## Vertex for building a hexary Patricia or Merkle Patricia Trie ## Vertex for building a hexary Patricia or Merkle Patricia Trie
pfx*: NibblesBuf
## Portion of path segment - extension nodes are branch nodes with
## non-empty prefix
case vType*: VertexType case vType*: VertexType
of Leaf: of Leaf:
lPfx*: NibblesBuf ## Portion of path segment
lData*: LeafPayload ## Reference to data payload lData*: LeafPayload ## Reference to data payload
of Branch: of Branch:
ePfx*: NibblesBuf ## Portion of path segment - if non-empty,
## it's an extension node!
bVid*: array[16,VertexID] ## Edge list with vertex IDs bVid*: array[16,VertexID] ## Edge list with vertex IDs
NodeRef* = ref object of VertexRef NodeRef* = ref object of RootRef
## Combined record for a *traditional* ``Merkle Patricia Tree` node merged ## Combined record for a *traditional* ``Merkle Patricia Tree` node merged
## with a structural `VertexRef` type object. ## with a structural `VertexRef` type object.
vtx*: VertexRef
key*: array[16,HashKey] ## Merkle hash/es for vertices key*: array[16,HashKey] ## Merkle hash/es for vertices
# ---------------------- # ----------------------
@ -174,21 +175,21 @@ proc `==`*(a, b: VertexRef): bool =
return false return false
case a.vType: case a.vType:
of Leaf: of Leaf:
if a.lPfx != b.lPfx or a.lData != b.lData: if a.pfx != b.pfx or a.lData != b.lData:
return false return false
of Branch: of Branch:
if a.ePfx != b.ePfx or a.bVid != b.bVid: if a.pfx != b.pfx or a.bVid != b.bVid:
return false return false
true true
proc `==`*(a, b: NodeRef): bool = proc `==`*(a, b: NodeRef): bool =
## Beware, potential deep comparison ## Beware, potential deep comparison
if a.VertexRef != b.VertexRef: if a.vtx != b.vtx:
return false return false
case a.vType: case a.vtx.vType:
of Branch: of Branch:
for n in 0..15: for n in 0..15:
if a.bVid[n] != 0.VertexID or b.bVid[n] != 0.VertexID: if a.vtx.bVid[n] != 0.VertexID or b.vtx.bVid[n] != 0.VertexID:
if a.key[n] != b.key[n]: if a.key[n] != b.key[n]:
return false return false
else: else:
@ -227,12 +228,12 @@ func dup*(vtx: VertexRef): VertexRef =
of Leaf: of Leaf:
VertexRef( VertexRef(
vType: Leaf, vType: Leaf,
lPfx: vtx.lPfx, pfx: vtx.pfx,
lData: vtx.lData.dup) lData: vtx.lData.dup)
of Branch: of Branch:
VertexRef( VertexRef(
vType: Branch, vType: Branch,
ePfx: vtx.ePfx, pfx: vtx.pfx,
bVid: vtx.bVid) bVid: vtx.bVid)
func dup*(node: NodeRef): NodeRef = func dup*(node: NodeRef): NodeRef =
@ -241,18 +242,8 @@ func dup*(node: NodeRef): NodeRef =
if node.isNil: if node.isNil:
NodeRef(nil) NodeRef(nil)
else: else:
case node.vType:
of Leaf:
NodeRef( NodeRef(
vType: Leaf, vtx: node.vtx.dup(),
lPfx: node.lPfx,
lData: node.lData.dup,
key: node.key)
of Branch:
NodeRef(
vType: Branch,
ePfx: node.ePfx,
bVid: node.bVid,
key: node.key) key: node.key)
func dup*(wp: VidVtxPair): VidVtxPair = func dup*(wp: VidVtxPair): VidVtxPair =

View File

@ -47,9 +47,9 @@ func getNibblesImpl(hike: Hike; start = 0; maxLen = high(int)): NibblesBuf =
let leg = hike.legs[n] let leg = hike.legs[n]
case leg.wp.vtx.vType: case leg.wp.vtx.vType:
of Branch: of Branch:
result = result & leg.wp.vtx.ePfx & NibblesBuf.nibble(leg.nibble.byte) result = result & leg.wp.vtx.pfx & NibblesBuf.nibble(leg.nibble.byte)
of Leaf: of Leaf:
result = result & leg.wp.vtx.lPfx result = result & leg.wp.vtx.pfx
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# Public functions # Public functions
@ -89,24 +89,24 @@ proc step*(
case vtx.vType: case vtx.vType:
of Leaf: of Leaf:
# This must be the last vertex, so there cannot be any `tail` left. # This must be the last vertex, so there cannot be any `tail` left.
if path.len != path.sharedPrefixLen(vtx.lPfx): if path.len != path.sharedPrefixLen(vtx.pfx):
return err(HikeLeafUnexpected) return err(HikeLeafUnexpected)
ok (vtx, NibblesBuf(), VertexID(0)) ok (vtx, NibblesBuf(), VertexID(0))
of Branch: of Branch:
# There must be some more data (aka `tail`) after a `Branch` vertex. # There must be some more data (aka `tail`) after a `Branch` vertex.
if path.len <= vtx.ePfx.len: if path.len <= vtx.pfx.len:
return err(HikeBranchTailEmpty) return err(HikeBranchTailEmpty)
let let
nibble = path[vtx.ePfx.len].int8 nibble = path[vtx.pfx.len].int8
nextVid = vtx.bVid[nibble] nextVid = vtx.bVid[nibble]
if not nextVid.isValid: if not nextVid.isValid:
return err(HikeBranchMissingEdge) return err(HikeBranchMissingEdge)
ok (vtx, path.slice(vtx.ePfx.len + 1), nextVid) ok (vtx, path.slice(vtx.pfx.len + 1), nextVid)
iterator stepUp*( iterator stepUp*(
@ -162,7 +162,7 @@ proc hikeUp*(
break break
of Branch: of Branch:
hike.legs.add Leg(wp: wp, nibble: int8 hike.tail[vtx.ePfx.len]) hike.legs.add Leg(wp: wp, nibble: int8 hike.tail[vtx.pfx.len])
hike.tail = path hike.tail = path
vid = next vid = next

View File

@ -16,17 +16,12 @@ import eth/common, results, ".."/[aristo_desc, aristo_get, aristo_layers, aristo
# Private getters & setters # Private getters & setters
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
proc xPfx(vtx: VertexRef): NibblesBuf =
case vtx.vType
of Leaf: vtx.lPfx
of Branch: vtx.ePfx
# ----------- # -----------
proc layersPutLeaf( proc layersPutLeaf(
db: AristoDbRef, rvid: RootedVertexID, path: NibblesBuf, payload: LeafPayload db: AristoDbRef, rvid: RootedVertexID, path: NibblesBuf, payload: LeafPayload
): VertexRef = ): VertexRef =
let vtx = VertexRef(vType: Leaf, lPfx: path, lData: payload) let vtx = VertexRef(vType: Leaf, pfx: path, lData: payload)
db.layersPutVtx(rvid, vtx) db.layersPutVtx(rvid, vtx)
vtx vtx
@ -68,11 +63,11 @@ proc mergePayloadImpl*(
touched[pos] = cur touched[pos] = cur
pos += 1 pos += 1
let n = path.sharedPrefixLen(vtx.xPfx) let n = path.sharedPrefixLen(vtx.pfx)
case vtx.vType case vtx.vType
of Leaf: of Leaf:
let leafVtx = let leafVtx =
if n == vtx.lPfx.len: if n == vtx.pfx.len:
# Same path - replace the current vertex with a new payload # Same path - replace the current vertex with a new payload
if vtx.lData == payload: if vtx.lData == payload:
@ -92,11 +87,11 @@ proc mergePayloadImpl*(
else: else:
# Turn leaf into a branch (or extension) then insert the two leaves # Turn leaf into a branch (or extension) then insert the two leaves
# into the branch # into the branch
let branch = VertexRef(vType: Branch, ePfx: path.slice(0, n)) let branch = VertexRef(vType: Branch, pfx: path.slice(0, n))
block: # Copy of existing leaf node, now one level deeper block: # Copy of existing leaf node, now one level deeper
let local = db.vidFetch() let local = db.vidFetch()
branch.bVid[vtx.lPfx[n]] = local branch.bVid[vtx.pfx[n]] = local
discard db.layersPutLeaf((root, local), vtx.lPfx.slice(n + 1), vtx.lData) discard db.layersPutLeaf((root, local), vtx.pfx.slice(n + 1), vtx.lData)
let leafVtx = block: # Newly inserted leaf node let leafVtx = block: # Newly inserted leaf node
let local = db.vidFetch() let local = db.vidFetch()
@ -111,10 +106,10 @@ proc mergePayloadImpl*(
resetKeys() resetKeys()
return ok(leafVtx) return ok(leafVtx)
of Branch: of Branch:
if vtx.ePfx.len == n: if vtx.pfx.len == n:
# The existing branch is a prefix of the new entry # The existing branch is a prefix of the new entry
let let
nibble = path[vtx.ePfx.len] nibble = path[vtx.pfx.len]
next = vtx.bVid[nibble] next = vtx.bVid[nibble]
if next.isValid: if next.isValid:
@ -137,14 +132,14 @@ proc mergePayloadImpl*(
else: else:
# Partial path match - we need to split the existing branch at # Partial path match - we need to split the existing branch at
# the point of divergence, inserting a new branch # the point of divergence, inserting a new branch
let branch = VertexRef(vType: Branch, ePfx: path.slice(0, n)) let branch = VertexRef(vType: Branch, pfx: path.slice(0, n))
block: # Copy the existing vertex and add it to the new branch block: # Copy the existing vertex and add it to the new branch
let local = db.vidFetch() let local = db.vidFetch()
branch.bVid[vtx.ePfx[n]] = local branch.bVid[vtx.pfx[n]] = local
db.layersPutVtx( db.layersPutVtx(
(root, local), (root, local),
VertexRef(vType: Branch, ePfx: vtx.ePfx.slice(n + 1), bVid: vtx.bVid), VertexRef(vType: Branch, pfx: vtx.pfx.slice(n + 1), bVid: vtx.bVid),
) )
let leafVtx = block: # add the new entry let leafVtx = block: # add the new entry

View File

@ -170,10 +170,10 @@ proc zeroAdjust(
if n < 0: if n < 0:
# Before or after the database range # Before or after the database range
return err((hike.root,NearbyBeyondRange)) return err((hike.root,NearbyBeyondRange))
pfx = rootVtx.ePfx & NibblesBuf.nibble(n.byte) pfx = rootVtx.pfx & NibblesBuf.nibble(n.byte)
of Leaf: of Leaf:
pfx = rootVtx.lPfx pfx = rootVtx.pfx
if not hike.accept pfx: if not hike.accept pfx:
# Before or after the database range # Before or after the database range
return err((hike.root,NearbyBeyondRange)) return err((hike.root,NearbyBeyondRange))
@ -230,12 +230,12 @@ proc finalise(
if not vtx.isValid: if not vtx.isValid:
return err((vid,NearbyDanglingLink)) return err((vid,NearbyDanglingLink))
var pfx: NibblesBuf let pfx =
case vtx.vType: case vtx.vType:
of Leaf: of Leaf:
pfx = vtx.lPfx vtx.pfx
of Branch: of Branch:
pfx = vtx.ePfx & NibblesBuf.nibble(vtx.branchBorderNibble.byte) vtx.pfx & NibblesBuf.nibble(vtx.branchBorderNibble.byte)
if hike.beyond pfx: if hike.beyond pfx:
return err((vid,NearbyBeyondRange)) return err((vid,NearbyBeyondRange))
@ -308,7 +308,7 @@ proc nearbyNext(
case vtx.vType case vtx.vType
of Leaf: of Leaf:
if uHike.accept vtx.lPfx: if uHike.accept vtx.pfx:
return uHike.complete(vid, db, hikeLenMax, doLeast=moveRight) return uHike.complete(vid, db, hikeLenMax, doLeast=moveRight)
of Branch: of Branch:
let nibble = uHike.tail[0].int8 let nibble = uHike.tail[0].int8
@ -408,7 +408,7 @@ iterator rightPairs*(
# Increment `key` by one and update `hike`. In many cases, the current # Increment `key` by one and update `hike`. In many cases, the current
# `hike` can be modified and re-used which saves some database lookups. # `hike` can be modified and re-used which saves some database lookups.
block reuseHike: block reuseHike:
let tail = hike.legs[^1].wp.vtx.lPfx let tail = hike.legs[^1].wp.vtx.pfx
if 0 < tail.len: if 0 < tail.len:
let topNibble = tail[tail.len - 1] let topNibble = tail[tail.len - 1]
if topNibble < 15: if topNibble < 15:
@ -503,7 +503,7 @@ iterator leftPairs*(
# Decrement `key` by one and update `hike`. In many cases, the current # Decrement `key` by one and update `hike`. In many cases, the current
# `hike` can be modified and re-used which saves some database lookups. # `hike` can be modified and re-used which saves some database lookups.
block reuseHike: block reuseHike:
let tail = hike.legs[^1].wp.vtx.lPfx let tail = hike.legs[^1].wp.vtx.pfx
if 0 < tail.len: if 0 < tail.len:
let topNibble = tail[tail.len - 1] let topNibble = tail[tail.len - 1]
if 0 < topNibble: if 0 < topNibble:
@ -567,7 +567,7 @@ proc rightMissing*(
case vtx.vType case vtx.vType
of Leaf: of Leaf:
return ok(vtx.lPfx < hike.tail) return ok(vtx.pfx < hike.tail)
of Branch: of Branch:
return ok(vtx.branchNibbleMin(hike.tail[0].int8) < 0) return ok(vtx.branchNibbleMin(hike.tail[0].int8) < 0)

View File

@ -238,11 +238,11 @@ proc partPut*(
# Register core node. Even though these nodes are only local to this # Register core node. Even though these nodes are only local to this
# loop local, they need to be updated because another `chain` might # loop local, they need to be updated because another `chain` might
# merge into this one at exactly this node. # merge into this one at exactly this node.
case node.vType: case node.vtx.vType:
of Leaf: of Leaf:
node.lData = vtx.lData node.vtx.lData = vtx.lData
of Branch: of Branch:
node.bVid = vtx.bVid node.vtx.bVid = vtx.bVid
ps.addCore(root, key) # register core node ps.addCore(root, key) # register core node
ps.pureExt.del key # core node can't be an extension ps.pureExt.del key # core node can't be an extension
continue continue
@ -251,27 +251,27 @@ proc partPut*(
# stored separately off the database and will only be temporarily # stored separately off the database and will only be temporarily
# inserted into the database on demand. # inserted into the database on demand.
if node.prfType == isExtension: if node.prfType == isExtension:
ps.pureExt[key] = PrfExtension(xPfx: node.ePfx, xLink: node.key[0]) ps.pureExt[key] = PrfExtension(xPfx: node.vtx.pfx, xLink: node.key[0])
continue continue
# Otherwise assign new VIDs to a core node. Even though these nodes are # Otherwise assign new VIDs to a core node. Even though these nodes are
# only local to this loop local, they need to be updated because another # only local to this loop local, they need to be updated because another
# `chain` might merge into this one at exactly this node. # `chain` might merge into this one at exactly this node.
case node.vType: case node.vtx.vType:
of Leaf: of Leaf:
let lKey = node.key[0] let lKey = node.key[0]
if node.lData.pType == AccountData and lKey.isValid: if node.vtx.lData.pType == AccountData and lKey.isValid:
node.lData.stoID = (true, (? ps.getRvid(root, lKey))[0].vid) node.vtx.lData.stoID = (true, (? ps.getRvid(root, lKey))[0].vid)
of Branch: of Branch:
for n in 0 .. 15: for n in 0 .. 15:
let bKey = node.key[n] let bKey = node.key[n]
if bKey.isValid: if bKey.isValid:
node.bVid[n] = (? ps.getRvid(root, bKey))[0].vid node.vtx.bVid[n] = (? ps.getRvid(root, bKey))[0].vid
ps.addCore(root, key) # register core node ps.addCore(root, key) # register core node
ps.pureExt.del key # core node can't be an extension ps.pureExt.del key # core node can't be an extension
# Store vertex on database # Store vertex on database
ps.db.layersPutVtx(rvid, VertexRef(node)) ps.db.layersPutVtx(rvid, node.vtx)
seen.incl key # node was processed here seen.incl key # node was processed here
if stopHere: # follow up tail of earlier chain if stopHere: # follow up tail of earlier chain
#discard ps.pp() #discard ps.pp()
@ -456,7 +456,7 @@ proc partWithExtBegin*(ps: PartStateRef): Result[void,AristoError] =
if ps.db.getKey(rvid).isValid: if ps.db.getKey(rvid).isValid:
restore() restore()
return err(PartExtVtxExistsAlready) return err(PartExtVtxExistsAlready)
ps.db.layersPutVtx(rvid, VertexRef(vType: Branch, ePfx: ext.xPfx)) ps.db.layersPutVtx(rvid, VertexRef(vType: Branch, pfx: ext.xPfx))
rollback.add rvid rollback.add rvid
ok() ok()
@ -464,7 +464,7 @@ proc partWithExtEnd*(ps: PartStateRef): Result[void,AristoError] =
var rollback: seq[(RootedVertexID,PrfExtension)] var rollback: seq[(RootedVertexID,PrfExtension)]
proc restore() = proc restore() =
for (rvid,ext) in rollback: for (rvid,ext) in rollback:
ps.db.layersPutVtx(rvid, VertexRef(vType: Branch, ePfx: ext.xPfx)) ps.db.layersPutVtx(rvid, VertexRef(vType: Branch, pfx: ext.xPfx))
for (key,ext) in ps.pureExt.pairs: for (key,ext) in ps.pureExt.pairs:
let rvid = ps[key] let rvid = ps[key]
@ -474,7 +474,7 @@ proc partWithExtEnd*(ps: PartStateRef): Result[void,AristoError] =
restore() restore()
return err(PartExtVtxHasVanished) return err(PartExtVtxHasVanished)
if vtx.vType != Branch or if vtx.vType != Branch or
vtx.ePfx != ext.xPfx or vtx.pfx != ext.xPfx or
vtx.bVid != array[16,VertexID].default: vtx.bVid != array[16,VertexID].default:
restore() restore()
return err(PartExtVtxWasModified) return err(PartExtVtxWasModified)

View File

@ -48,14 +48,14 @@ proc chainRlpNodes*(
# Follow up child node # Follow up child node
case vtx.vType: case vtx.vType:
of Leaf: of Leaf:
if path != vtx.lPfx: if path != vtx.pfx:
err(PartChnLeafPathMismatch) err(PartChnLeafPathMismatch)
else: else:
ok() ok()
of Branch: of Branch:
let nChewOff = sharedPrefixLen(vtx.ePfx, path) let nChewOff = sharedPrefixLen(vtx.pfx, path)
if nChewOff != vtx.ePfx.len: if nChewOff != vtx.pfx.len:
err(PartChnExtPfxMismatch) err(PartChnExtPfxMismatch)
elif path.len == nChewOff: elif path.len == nChewOff:
err(PartChnBranchPathExhausted) err(PartChnBranchPathExhausted)

View File

@ -41,7 +41,7 @@ proc pp*(n: PrfNode; ps: PartStateRef): string =
elif n.prfType == isError: elif n.prfType == isError:
"(" & $n.error & ")" "(" & $n.error & ")"
elif n.prfType == isExtension: elif n.prfType == isExtension:
"X(" & n.ePfx.pp & "," & n.key[0].pp(ps.db) & ")" "X(" & n.vtx.pfx.pp & "," & n.key[0].pp(ps.db) & ")"
else: else:
"(" & NodeRef(n).pp(ps.db) & ")" "(" & NodeRef(n).pp(ps.db) & ")"

View File

@ -27,7 +27,7 @@ proc read(rlp: var Rlp; T: type PrfNode): T {.gcsafe, raises: [RlpError].} =
## ##
func readError(error: AristoError): PrfNode = func readError(error: AristoError): PrfNode =
## Prettify return code expression ## Prettify return code expression
PrfNode(vType: Leaf, prfType: isError, error: error) PrfNode(vtx: VertexRef(vType: Leaf), prfType: isError, error: error)
if not rlp.isList: if not rlp.isList:
# Otherwise `rlp.items` would raise a `Defect` # Otherwise `rlp.items` would raise a `Defect`
@ -64,17 +64,20 @@ proc read(rlp: var Rlp; T: type PrfNode): T {.gcsafe, raises: [RlpError].} =
let (isLeaf, pathSegment) = NibblesBuf.fromHexPrefix blobs[0] let (isLeaf, pathSegment) = NibblesBuf.fromHexPrefix blobs[0]
if isLeaf: if isLeaf:
return PrfNode( return PrfNode(
vType: Leaf,
prfType: ignore, prfType: ignore,
lPfx: pathSegment,
vtx: VertexRef(
vType: Leaf,
pfx: pathSegment,
lData: LeafPayload( lData: LeafPayload(
pType: RawData, pType: RawData,
rawBlob: blobs[1])) rawBlob: blobs[1])))
else: else:
var node = PrfNode( var node = PrfNode(
vType: Branch,
prfType: isExtension, prfType: isExtension,
ePfx: pathSegment) vtx: VertexRef(
vType: Branch,
pfx: pathSegment))
node.key[0] = HashKey.fromBytes(blobs[1]).valueOr: node.key[0] = HashKey.fromBytes(blobs[1]).valueOr:
return readError(PartRlpExtHashKeyExpected) return readError(PartRlpExtHashKeyExpected)
return node return node
@ -83,7 +86,8 @@ proc read(rlp: var Rlp; T: type PrfNode): T {.gcsafe, raises: [RlpError].} =
links[n] = HashKey.fromBytes(blobs[n]).valueOr: links[n] = HashKey.fromBytes(blobs[n]).valueOr:
return readError(PartRlpBranchHashKeyExpected) return readError(PartRlpBranchHashKeyExpected)
return PrfNode( return PrfNode(
vType: Branch, vtx: VertexRef(
vType: Branch),
prfType: ignore, prfType: ignore,
key: links) key: links)
else: else:
@ -137,11 +141,11 @@ func toNodesTab*(
nodes[w.digestTo HashKey] = nd nodes[w.digestTo HashKey] = nd
# Special decoding for account `Leaf` nodes # Special decoding for account `Leaf` nodes
if nd.vType == Leaf and mode != ForceGenericPayload: if nd.vtx.vType == Leaf and mode != ForceGenericPayload:
# Decode payload to deficated format for storage or accounts # Decode payload to deficated format for storage or accounts
var pyl: PrfPayload var pyl: PrfPayload
try: try:
pyl = rlp.decode(nd.lData.rawBlob, PrfPayload) pyl = rlp.decode(nd.vtx.lData.rawBlob, PrfPayload)
except RlpError: except RlpError:
pyl = PrfPayload(prfType: isError, error: PartRlpPayloadException) pyl = PrfPayload(prfType: isError, error: PartRlpPayloadException)
@ -150,10 +154,10 @@ func toNodesTab*(
# Single value encoding might not be unique so it cannot be # Single value encoding might not be unique so it cannot be
# automatically detected # automatically detected
if mode != AutomaticPayload: if mode != AutomaticPayload:
nd.lData = LeafPayload(pType: StoData, stoData: pyl.num) nd.vtx.lData = LeafPayload(pType: StoData, stoData: pyl.num)
of isAccount: of isAccount:
nd.key[0] = pyl.acc.storageRoot.to(HashKey) nd.key[0] = pyl.acc.storageRoot.to(HashKey)
nd.lData = LeafPayload( nd.vtx.lData = LeafPayload(
pType: AccountData, pType: AccountData,
account: AristoAccount( account: AristoAccount(
nonce: pyl.acc.nonce, nonce: pyl.acc.nonce,
@ -174,11 +178,11 @@ func toNodesTab*(
# Need to store raw extension # Need to store raw extension
nodes[xKey] = xNode nodes[xKey] = xNode
continue continue
if nd.ePfx.len != 0: if nd.vtx.pfx.len != 0:
return err(PartGarbledExtsInProofs) return err(PartGarbledExtsInProofs)
# Move extended `nd` branch node # Move extended `nd` branch node
nd.prfType = ignore nd.prfType = ignore
nd.ePfx = xNode.ePfx nd.vtx.pfx = xNode.vtx.pfx
nodes.del xNode.key[0] nodes.del xNode.key[0]
nodes[xKey] = nd nodes[xKey] = nd
@ -196,8 +200,8 @@ proc backLinks*(nTab: TableRef[HashKey,PrfNode]): PrfBackLinks =
# Collect predecessor list # Collect predecessor list
for (key,nd) in nTab.pairs: for (key,nd) in nTab.pairs:
if nd.vType == Leaf: if nd.vtx.vType == Leaf:
if nd.lData.pType == AccountData and nd.key[0].isValid: if nd.vtx.lData.pType == AccountData and nd.key[0].isValid:
result.links[nd.key[0]] = key result.links[nd.key[0]] = key
elif nd.prfType == isExtension: elif nd.prfType == isExtension:
result.links[nd.key[0]] = key result.links[nd.key[0]] = key
@ -280,7 +284,7 @@ proc updateAccountsTree*(
for chain in bl.chains: for chain in bl.chains:
for key in chain: for key in chain:
nodes[].withValue(key,node): nodes[].withValue(key,node):
if node.vType == Leaf and node.lData.pType == AccountData: if node.vtx.vType == Leaf and node.vtx.lData.pType == AccountData:
# Ok, got an accounts leaf node # Ok, got an accounts leaf node
if not accRootKey.isValid: if not accRootKey.isValid:

View File

@ -70,7 +70,7 @@ proc to*(node: NodeRef; T: type seq[Blob]): T =
## `<rlp-encoded-node>` type entries. Only in case of a combined extension ## `<rlp-encoded-node>` type entries. Only in case of a combined extension
## and branch vertex argument, there will be a double item list result. ## and branch vertex argument, there will be a double item list result.
## ##
case node.vType: case node.vtx.vType:
of Branch: of Branch:
# Do branch node # Do branch node
var wr = initRlpWriter() var wr = initRlpWriter()
@ -80,13 +80,13 @@ proc to*(node: NodeRef; T: type seq[Blob]): T =
wr.append EmptyBlob wr.append EmptyBlob
let brData = wr.finish() let brData = wr.finish()
if 0 < node.ePfx.len: if 0 < node.vtx.pfx.len:
# Prefix branch by embedded extension node # Prefix branch by embedded extension node
let brHash = brData.digestTo(HashKey) let brHash = brData.digestTo(HashKey)
var wrx = initRlpWriter() var wrx = initRlpWriter()
wrx.startList(2) wrx.startList(2)
wrx.append node.ePfx.toHexPrefix(isleaf = false).data() wrx.append node.vtx.pfx.toHexPrefix(isleaf = false).data()
wrx.append brHash wrx.append brHash
result.add wrx.finish() result.add wrx.finish()
@ -104,8 +104,8 @@ proc to*(node: NodeRef; T: type seq[Blob]): T =
var wr = initRlpWriter() var wr = initRlpWriter()
wr.startList(2) wr.startList(2)
wr.append node.lPfx.toHexPrefix(isleaf = true).data() wr.append node.vtx.pfx.toHexPrefix(isleaf = true).data()
wr.append node.lData.serialise(getKey0).value wr.append node.vtx.lData.serialise(getKey0).value
result.add (wr.finish()) result.add (wr.finish())
@ -114,7 +114,7 @@ proc digestTo*(node: NodeRef; T: type HashKey): T =
## that a `Dummy` node is encoded as as a `Leaf`. ## that a `Dummy` node is encoded as as a `Leaf`.
## ##
var wr = initRlpWriter() var wr = initRlpWriter()
case node.vType: case node.vtx.vType:
of Branch: of Branch:
# Do branch node # Do branch node
wr.startList(17) wr.startList(17)
@ -123,11 +123,11 @@ proc digestTo*(node: NodeRef; T: type HashKey): T =
wr.append EmptyBlob wr.append EmptyBlob
# Do for embedded extension node # Do for embedded extension node
if 0 < node.ePfx.len: if 0 < node.vtx.pfx.len:
let brHash = wr.finish().digestTo(HashKey) let brHash = wr.finish().digestTo(HashKey)
wr = initRlpWriter() wr = initRlpWriter()
wr.startList(2) wr.startList(2)
wr.append node.ePfx.toHexPrefix(isleaf = false).data() wr.append node.vtx.pfx.toHexPrefix(isleaf = false).data()
wr.append brHash wr.append brHash
of Leaf: of Leaf:
@ -138,8 +138,8 @@ proc digestTo*(node: NodeRef; T: type HashKey): T =
ok(node.key[0]) # always succeeds ok(node.key[0]) # always succeeds
wr.startList(2) wr.startList(2)
wr.append node.lPfx.toHexPrefix(isleaf = true).data() wr.append node.vtx.pfx.toHexPrefix(isleaf = true).data()
wr.append node.lData.serialise(getKey0).value wr.append node.vtx.lData.serialise(getKey0).value
wr.finish().digestTo(HashKey) wr.finish().digestTo(HashKey)

View File

@ -56,7 +56,7 @@ proc toNode*(
case vtx.vType: case vtx.vType:
of Leaf: of Leaf:
let node = NodeRef(vType: Leaf, lPfx: vtx.lPfx, lData: vtx.lData) let node = NodeRef(vtx: vtx.dup())
# Need to resolve storage root for account leaf # Need to resolve storage root for account leaf
if vtx.lData.pType == AccountData: if vtx.lData.pType == AccountData:
let stoID = vtx.lData.stoID let stoID = vtx.lData.stoID
@ -68,7 +68,7 @@ proc toNode*(
return ok node return ok node
of Branch: of Branch:
let node = NodeRef(vType: Branch, bVid: vtx.bVid, ePfx: vtx.ePfx) let node = NodeRef(vtx: vtx.dup())
var missing: seq[VertexID] var missing: seq[VertexID]
for n in 0 .. 15: for n in 0 .. 15:
let vid = vtx.bVid[n] let vid = vtx.bVid[n]
@ -100,15 +100,15 @@ iterator subVids*(vtx: VertexRef): VertexID =
iterator subVidKeys*(node: NodeRef): (VertexID,HashKey) = iterator subVidKeys*(node: NodeRef): (VertexID,HashKey) =
## Simolar to `subVids()` but for nodes ## Simolar to `subVids()` but for nodes
case node.vType: case node.vtx.vType:
of Leaf: of Leaf:
if node.lData.pType == AccountData: if node.vtx.lData.pType == AccountData:
let stoID = node.lData.stoID let stoID = node.vtx.lData.stoID
if stoID.isValid: if stoID.isValid:
yield (stoID.vid, node.key[0]) yield (stoID.vid, node.key[0])
of Branch: of Branch:
for n in 0 .. 15: for n in 0 .. 15:
let vid = node.bVid[n] let vid = node.vtx.bVid[n]
if vid.isValid: if vid.isValid:
yield (vid,node.key[n]) yield (vid,node.key[n])

View File

@ -43,7 +43,7 @@ suite "Aristo blobify":
extension = VertexRef( extension = VertexRef(
vType: Branch, vType: Branch,
ePfx: NibblesBuf.nibble(2), pfx: NibblesBuf.nibble(2),
bVid: [ bVid: [
VertexID(0), VertexID(0),
VertexID(0), VertexID(0),