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:
parent
0be6291fba
commit
adb8d64377
|
@ -200,8 +200,8 @@ proc blobifyTo*(vtx: VertexRef; data: var Blob): Result[void,AristoError] =
|
|||
|
||||
let
|
||||
pSegm =
|
||||
if vtx.ePfx.len > 0:
|
||||
vtx.ePfx.toHexPrefix(isleaf = false)
|
||||
if vtx.pfx.len > 0:
|
||||
vtx.pfx.toHexPrefix(isleaf = false)
|
||||
else:
|
||||
default(HexPrefixBuf)
|
||||
psLen = pSegm.len.byte
|
||||
|
@ -214,7 +214,7 @@ proc blobifyTo*(vtx: VertexRef; data: var Blob): Result[void,AristoError] =
|
|||
|
||||
of Leaf:
|
||||
let
|
||||
pSegm = vtx.lPfx.toHexPrefix(isleaf = true)
|
||||
pSegm = vtx.pfx.toHexPrefix(isleaf = true)
|
||||
psLen = pSegm.len.byte
|
||||
if psLen == 0 or 33 < psLen:
|
||||
return err(BlobifyLeafPathOverflow)
|
||||
|
@ -325,7 +325,7 @@ proc deblobify*(
|
|||
# End `while`
|
||||
VertexRef(
|
||||
vType: Branch,
|
||||
ePfx: pathSegment,
|
||||
pfx: pathSegment,
|
||||
bVid: vtxList)
|
||||
|
||||
of 3: # `Leaf` vertex
|
||||
|
@ -341,7 +341,7 @@ proc deblobify*(
|
|||
return err(DeblobLeafGotExtPrefix)
|
||||
let vtx = VertexRef(
|
||||
vType: Leaf,
|
||||
lPfx: pathSegment)
|
||||
pfx: pathSegment)
|
||||
|
||||
? record.toOpenArray(0, pLen - 1).deblobify(vtx.lData)
|
||||
vtx
|
||||
|
|
|
@ -68,7 +68,7 @@ proc computeKeyImpl(
|
|||
case vtx.vType:
|
||||
of Leaf:
|
||||
writer.startList(2)
|
||||
writer.append(vtx.lPfx.toHexPrefix(isLeaf = true).data())
|
||||
writer.append(vtx.pfx.toHexPrefix(isLeaf = true).data())
|
||||
|
||||
case vtx.lData.pType
|
||||
of AccountData:
|
||||
|
@ -106,12 +106,12 @@ proc computeKeyImpl(
|
|||
else:
|
||||
w.append(VOID_HASH_KEY)
|
||||
w.append EmptyBlob
|
||||
if vtx.ePfx.len > 0: # Extension node
|
||||
if vtx.pfx.len > 0: # Extension node
|
||||
var bwriter = initRlpWriter()
|
||||
writeBranch(bwriter)
|
||||
|
||||
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))
|
||||
else:
|
||||
writeBranch(writer)
|
||||
|
|
|
@ -209,9 +209,9 @@ proc ppVtx(nd: VertexRef, db: AristoDbRef, rvid: RootedVertexID): string =
|
|||
result = ["ł(", "þ("][nd.vType.ord]
|
||||
case nd.vType:
|
||||
of Leaf:
|
||||
result &= nd.lPfx.ppPathPfx & "," & nd.lData.ppPayload(db)
|
||||
result &= nd.pfx.ppPathPfx & "," & nd.lData.ppPayload(db)
|
||||
of Branch:
|
||||
result &= nd.ePfx.ppPathPfx & ":"
|
||||
result &= nd.pfx.ppPathPfx & ":"
|
||||
for n in 0..15:
|
||||
if nd.bVid[n].isValid:
|
||||
result &= nd.bVid[n].ppVid
|
||||
|
@ -229,33 +229,33 @@ proc ppNode(
|
|||
result = "ø"
|
||||
else:
|
||||
if not rvid.isValid:
|
||||
result = ["L(", "B("][nd.vType.ord]
|
||||
result = ["L(", "B("][nd.vtx.vType.ord]
|
||||
elif db.layersGetKey(rvid).isOk:
|
||||
result = ["l(", "b("][nd.vType.ord]
|
||||
result = ["l(", "b("][nd.vtx.vType.ord]
|
||||
else:
|
||||
result = ["ł(", "þ("][nd.vType.ord]
|
||||
case nd.vType:
|
||||
result = ["ł(", "þ("][nd.vtx.vType.ord]
|
||||
case nd.vtx.vType:
|
||||
of Leaf:
|
||||
result &= nd.lPfx.ppPathPfx & ","
|
||||
if nd.lData.pType == AccountData:
|
||||
result &= "(" & nd.lData.account.ppAriAccount() & ","
|
||||
if nd.lData.stoID.isValid:
|
||||
let tag = db.ppKeyOk(nd.key[0],(rvid.root,nd.lData.stoID.vid))
|
||||
result &= nd.lData.stoID.ppVid & tag
|
||||
result &= nd.vtx.pfx.ppPathPfx & ","
|
||||
if nd.vtx.lData.pType == AccountData:
|
||||
result &= "(" & nd.vtx.lData.account.ppAriAccount() & ","
|
||||
if nd.vtx.lData.stoID.isValid:
|
||||
let tag = db.ppKeyOk(nd.key[0],(rvid.root,nd.vtx.lData.stoID.vid))
|
||||
result &= nd.vtx.lData.stoID.ppVid & tag
|
||||
else:
|
||||
result &= nd.lData.stoID.ppVid
|
||||
result &= nd.vtx.lData.stoID.ppVid
|
||||
if nd.key[0].isValid:
|
||||
result &= nd.key[0].ppKey(db)
|
||||
result &= ")"
|
||||
else:
|
||||
result &= nd.lData.ppPayload(db)
|
||||
result &= nd.vtx.lData.ppPayload(db)
|
||||
of Branch:
|
||||
let keyOnly = nd.bVid.toSeq.filterIt(it.isValid).len == 0
|
||||
result &= nd.ePfx.ppPathPfx & ":"
|
||||
let keyOnly = nd.vtx.bVid.toSeq.filterIt(it.isValid).len == 0
|
||||
result &= nd.vtx.pfx.ppPathPfx & ":"
|
||||
for n in 0..15:
|
||||
if nd.bVid[n].isValid:
|
||||
let tag = db.ppKeyOk(nd.key[n],(rvid.root,nd.bVid[n]))
|
||||
result &= nd.bVid[n].ppVid & tag
|
||||
if nd.vtx.bVid[n].isValid:
|
||||
let tag = db.ppKeyOk(nd.key[n],(rvid.root,nd.vtx.bVid[n]))
|
||||
result &= nd.vtx.bVid[n].ppVid & tag
|
||||
elif keyOnly and nd.key[n].isValid:
|
||||
result &= nd.key[n].ppKey(db)
|
||||
if n < 15:
|
||||
|
|
|
@ -97,12 +97,12 @@ proc deleteImpl(
|
|||
of Leaf:
|
||||
VertexRef(
|
||||
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)
|
||||
of Branch:
|
||||
VertexRef(
|
||||
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)
|
||||
|
||||
# Put the new vertex at the id of the obsolete branch
|
||||
|
|
|
@ -58,10 +58,10 @@ proc delStoTreeNow(
|
|||
if vtx.bVid[i].isValid:
|
||||
? db.delStoTreeNow(
|
||||
(rvid.root, vtx.bVid[i]), accPath,
|
||||
stoPath & vtx.ePfx & NibblesBuf.nibble(byte i))
|
||||
stoPath & vtx.pfx & NibblesBuf.nibble(byte i))
|
||||
|
||||
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.disposeOfVtx(rvid)
|
||||
|
|
|
@ -68,20 +68,21 @@ type
|
|||
of StoData:
|
||||
stoData*: UInt256
|
||||
|
||||
VertexRef* = ref object of RootRef
|
||||
VertexRef* = ref object
|
||||
## 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
|
||||
of Leaf:
|
||||
lPfx*: NibblesBuf ## Portion of path segment
|
||||
lData*: LeafPayload ## Reference to data payload
|
||||
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
|
||||
|
||||
NodeRef* = ref object of VertexRef
|
||||
NodeRef* = ref object of RootRef
|
||||
## Combined record for a *traditional* ``Merkle Patricia Tree` node merged
|
||||
## with a structural `VertexRef` type object.
|
||||
vtx*: VertexRef
|
||||
key*: array[16,HashKey] ## Merkle hash/es for vertices
|
||||
|
||||
# ----------------------
|
||||
|
@ -174,21 +175,21 @@ proc `==`*(a, b: VertexRef): bool =
|
|||
return false
|
||||
case a.vType:
|
||||
of Leaf:
|
||||
if a.lPfx != b.lPfx or a.lData != b.lData:
|
||||
if a.pfx != b.pfx or a.lData != b.lData:
|
||||
return false
|
||||
of Branch:
|
||||
if a.ePfx != b.ePfx or a.bVid != b.bVid:
|
||||
if a.pfx != b.pfx or a.bVid != b.bVid:
|
||||
return false
|
||||
true
|
||||
|
||||
proc `==`*(a, b: NodeRef): bool =
|
||||
## Beware, potential deep comparison
|
||||
if a.VertexRef != b.VertexRef:
|
||||
if a.vtx != b.vtx:
|
||||
return false
|
||||
case a.vType:
|
||||
case a.vtx.vType:
|
||||
of Branch:
|
||||
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]:
|
||||
return false
|
||||
else:
|
||||
|
@ -227,12 +228,12 @@ func dup*(vtx: VertexRef): VertexRef =
|
|||
of Leaf:
|
||||
VertexRef(
|
||||
vType: Leaf,
|
||||
lPfx: vtx.lPfx,
|
||||
pfx: vtx.pfx,
|
||||
lData: vtx.lData.dup)
|
||||
of Branch:
|
||||
VertexRef(
|
||||
vType: Branch,
|
||||
ePfx: vtx.ePfx,
|
||||
pfx: vtx.pfx,
|
||||
bVid: vtx.bVid)
|
||||
|
||||
func dup*(node: NodeRef): NodeRef =
|
||||
|
@ -241,19 +242,9 @@ func dup*(node: NodeRef): NodeRef =
|
|||
if node.isNil:
|
||||
NodeRef(nil)
|
||||
else:
|
||||
case node.vType:
|
||||
of Leaf:
|
||||
NodeRef(
|
||||
vType: Leaf,
|
||||
lPfx: node.lPfx,
|
||||
lData: node.lData.dup,
|
||||
key: node.key)
|
||||
of Branch:
|
||||
NodeRef(
|
||||
vType: Branch,
|
||||
ePfx: node.ePfx,
|
||||
bVid: node.bVid,
|
||||
key: node.key)
|
||||
NodeRef(
|
||||
vtx: node.vtx.dup(),
|
||||
key: node.key)
|
||||
|
||||
func dup*(wp: VidVtxPair): VidVtxPair =
|
||||
## Safe copy of `wp` argument
|
||||
|
|
|
@ -47,9 +47,9 @@ func getNibblesImpl(hike: Hike; start = 0; maxLen = high(int)): NibblesBuf =
|
|||
let leg = hike.legs[n]
|
||||
case leg.wp.vtx.vType:
|
||||
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:
|
||||
result = result & leg.wp.vtx.lPfx
|
||||
result = result & leg.wp.vtx.pfx
|
||||
|
||||
# ------------------------------------------------------------------------------
|
||||
# Public functions
|
||||
|
@ -89,24 +89,24 @@ proc step*(
|
|||
case vtx.vType:
|
||||
of Leaf:
|
||||
# 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)
|
||||
|
||||
ok (vtx, NibblesBuf(), VertexID(0))
|
||||
|
||||
of Branch:
|
||||
# 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)
|
||||
|
||||
let
|
||||
nibble = path[vtx.ePfx.len].int8
|
||||
nibble = path[vtx.pfx.len].int8
|
||||
nextVid = vtx.bVid[nibble]
|
||||
|
||||
if not nextVid.isValid:
|
||||
return err(HikeBranchMissingEdge)
|
||||
|
||||
ok (vtx, path.slice(vtx.ePfx.len + 1), nextVid)
|
||||
ok (vtx, path.slice(vtx.pfx.len + 1), nextVid)
|
||||
|
||||
|
||||
iterator stepUp*(
|
||||
|
@ -162,7 +162,7 @@ proc hikeUp*(
|
|||
break
|
||||
|
||||
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
|
||||
vid = next
|
||||
|
|
|
@ -16,17 +16,12 @@ import eth/common, results, ".."/[aristo_desc, aristo_get, aristo_layers, aristo
|
|||
# Private getters & setters
|
||||
# ------------------------------------------------------------------------------
|
||||
|
||||
proc xPfx(vtx: VertexRef): NibblesBuf =
|
||||
case vtx.vType
|
||||
of Leaf: vtx.lPfx
|
||||
of Branch: vtx.ePfx
|
||||
|
||||
# -----------
|
||||
|
||||
proc layersPutLeaf(
|
||||
db: AristoDbRef, rvid: RootedVertexID, path: NibblesBuf, payload: LeafPayload
|
||||
): VertexRef =
|
||||
let vtx = VertexRef(vType: Leaf, lPfx: path, lData: payload)
|
||||
let vtx = VertexRef(vType: Leaf, pfx: path, lData: payload)
|
||||
db.layersPutVtx(rvid, vtx)
|
||||
vtx
|
||||
|
||||
|
@ -68,11 +63,11 @@ proc mergePayloadImpl*(
|
|||
touched[pos] = cur
|
||||
pos += 1
|
||||
|
||||
let n = path.sharedPrefixLen(vtx.xPfx)
|
||||
let n = path.sharedPrefixLen(vtx.pfx)
|
||||
case vtx.vType
|
||||
of Leaf:
|
||||
let leafVtx =
|
||||
if n == vtx.lPfx.len:
|
||||
if n == vtx.pfx.len:
|
||||
# Same path - replace the current vertex with a new payload
|
||||
|
||||
if vtx.lData == payload:
|
||||
|
@ -92,11 +87,11 @@ proc mergePayloadImpl*(
|
|||
else:
|
||||
# Turn leaf into a branch (or extension) then insert the two leaves
|
||||
# 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
|
||||
let local = db.vidFetch()
|
||||
branch.bVid[vtx.lPfx[n]] = local
|
||||
discard db.layersPutLeaf((root, local), vtx.lPfx.slice(n + 1), vtx.lData)
|
||||
branch.bVid[vtx.pfx[n]] = local
|
||||
discard db.layersPutLeaf((root, local), vtx.pfx.slice(n + 1), vtx.lData)
|
||||
|
||||
let leafVtx = block: # Newly inserted leaf node
|
||||
let local = db.vidFetch()
|
||||
|
@ -111,10 +106,10 @@ proc mergePayloadImpl*(
|
|||
resetKeys()
|
||||
return ok(leafVtx)
|
||||
of Branch:
|
||||
if vtx.ePfx.len == n:
|
||||
if vtx.pfx.len == n:
|
||||
# The existing branch is a prefix of the new entry
|
||||
let
|
||||
nibble = path[vtx.ePfx.len]
|
||||
nibble = path[vtx.pfx.len]
|
||||
next = vtx.bVid[nibble]
|
||||
|
||||
if next.isValid:
|
||||
|
@ -137,14 +132,14 @@ proc mergePayloadImpl*(
|
|||
else:
|
||||
# Partial path match - we need to split the existing branch at
|
||||
# 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
|
||||
let local = db.vidFetch()
|
||||
branch.bVid[vtx.ePfx[n]] = local
|
||||
branch.bVid[vtx.pfx[n]] = local
|
||||
|
||||
db.layersPutVtx(
|
||||
(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
|
||||
|
|
|
@ -170,10 +170,10 @@ proc zeroAdjust(
|
|||
if n < 0:
|
||||
# Before or after the database range
|
||||
return err((hike.root,NearbyBeyondRange))
|
||||
pfx = rootVtx.ePfx & NibblesBuf.nibble(n.byte)
|
||||
pfx = rootVtx.pfx & NibblesBuf.nibble(n.byte)
|
||||
|
||||
of Leaf:
|
||||
pfx = rootVtx.lPfx
|
||||
pfx = rootVtx.pfx
|
||||
if not hike.accept pfx:
|
||||
# Before or after the database range
|
||||
return err((hike.root,NearbyBeyondRange))
|
||||
|
@ -230,12 +230,12 @@ proc finalise(
|
|||
if not vtx.isValid:
|
||||
return err((vid,NearbyDanglingLink))
|
||||
|
||||
var pfx: NibblesBuf
|
||||
case vtx.vType:
|
||||
of Leaf:
|
||||
pfx = vtx.lPfx
|
||||
of Branch:
|
||||
pfx = vtx.ePfx & NibblesBuf.nibble(vtx.branchBorderNibble.byte)
|
||||
let pfx =
|
||||
case vtx.vType:
|
||||
of Leaf:
|
||||
vtx.pfx
|
||||
of Branch:
|
||||
vtx.pfx & NibblesBuf.nibble(vtx.branchBorderNibble.byte)
|
||||
if hike.beyond pfx:
|
||||
return err((vid,NearbyBeyondRange))
|
||||
|
||||
|
@ -308,7 +308,7 @@ proc nearbyNext(
|
|||
|
||||
case vtx.vType
|
||||
of Leaf:
|
||||
if uHike.accept vtx.lPfx:
|
||||
if uHike.accept vtx.pfx:
|
||||
return uHike.complete(vid, db, hikeLenMax, doLeast=moveRight)
|
||||
of Branch:
|
||||
let nibble = uHike.tail[0].int8
|
||||
|
@ -408,7 +408,7 @@ iterator rightPairs*(
|
|||
# Increment `key` by one and update `hike`. In many cases, the current
|
||||
# `hike` can be modified and re-used which saves some database lookups.
|
||||
block reuseHike:
|
||||
let tail = hike.legs[^1].wp.vtx.lPfx
|
||||
let tail = hike.legs[^1].wp.vtx.pfx
|
||||
if 0 < tail.len:
|
||||
let topNibble = tail[tail.len - 1]
|
||||
if topNibble < 15:
|
||||
|
@ -503,7 +503,7 @@ iterator leftPairs*(
|
|||
# Decrement `key` by one and update `hike`. In many cases, the current
|
||||
# `hike` can be modified and re-used which saves some database lookups.
|
||||
block reuseHike:
|
||||
let tail = hike.legs[^1].wp.vtx.lPfx
|
||||
let tail = hike.legs[^1].wp.vtx.pfx
|
||||
if 0 < tail.len:
|
||||
let topNibble = tail[tail.len - 1]
|
||||
if 0 < topNibble:
|
||||
|
@ -567,7 +567,7 @@ proc rightMissing*(
|
|||
|
||||
case vtx.vType
|
||||
of Leaf:
|
||||
return ok(vtx.lPfx < hike.tail)
|
||||
return ok(vtx.pfx < hike.tail)
|
||||
of Branch:
|
||||
return ok(vtx.branchNibbleMin(hike.tail[0].int8) < 0)
|
||||
|
||||
|
|
|
@ -238,11 +238,11 @@ proc partPut*(
|
|||
# Register core node. Even though these nodes are only local to this
|
||||
# loop local, they need to be updated because another `chain` might
|
||||
# merge into this one at exactly this node.
|
||||
case node.vType:
|
||||
case node.vtx.vType:
|
||||
of Leaf:
|
||||
node.lData = vtx.lData
|
||||
node.vtx.lData = vtx.lData
|
||||
of Branch:
|
||||
node.bVid = vtx.bVid
|
||||
node.vtx.bVid = vtx.bVid
|
||||
ps.addCore(root, key) # register core node
|
||||
ps.pureExt.del key # core node can't be an extension
|
||||
continue
|
||||
|
@ -251,27 +251,27 @@ proc partPut*(
|
|||
# stored separately off the database and will only be temporarily
|
||||
# inserted into the database on demand.
|
||||
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
|
||||
|
||||
# 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
|
||||
# `chain` might merge into this one at exactly this node.
|
||||
case node.vType:
|
||||
case node.vtx.vType:
|
||||
of Leaf:
|
||||
let lKey = node.key[0]
|
||||
if node.lData.pType == AccountData and lKey.isValid:
|
||||
node.lData.stoID = (true, (? ps.getRvid(root, lKey))[0].vid)
|
||||
if node.vtx.lData.pType == AccountData and lKey.isValid:
|
||||
node.vtx.lData.stoID = (true, (? ps.getRvid(root, lKey))[0].vid)
|
||||
of Branch:
|
||||
for n in 0 .. 15:
|
||||
let bKey = node.key[n]
|
||||
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.pureExt.del key # core node can't be an extension
|
||||
|
||||
# Store vertex on database
|
||||
ps.db.layersPutVtx(rvid, VertexRef(node))
|
||||
ps.db.layersPutVtx(rvid, node.vtx)
|
||||
seen.incl key # node was processed here
|
||||
if stopHere: # follow up tail of earlier chain
|
||||
#discard ps.pp()
|
||||
|
@ -456,7 +456,7 @@ proc partWithExtBegin*(ps: PartStateRef): Result[void,AristoError] =
|
|||
if ps.db.getKey(rvid).isValid:
|
||||
restore()
|
||||
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
|
||||
ok()
|
||||
|
||||
|
@ -464,7 +464,7 @@ proc partWithExtEnd*(ps: PartStateRef): Result[void,AristoError] =
|
|||
var rollback: seq[(RootedVertexID,PrfExtension)]
|
||||
proc restore() =
|
||||
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:
|
||||
let rvid = ps[key]
|
||||
|
@ -474,7 +474,7 @@ proc partWithExtEnd*(ps: PartStateRef): Result[void,AristoError] =
|
|||
restore()
|
||||
return err(PartExtVtxHasVanished)
|
||||
if vtx.vType != Branch or
|
||||
vtx.ePfx != ext.xPfx or
|
||||
vtx.pfx != ext.xPfx or
|
||||
vtx.bVid != array[16,VertexID].default:
|
||||
restore()
|
||||
return err(PartExtVtxWasModified)
|
||||
|
|
|
@ -48,14 +48,14 @@ proc chainRlpNodes*(
|
|||
# Follow up child node
|
||||
case vtx.vType:
|
||||
of Leaf:
|
||||
if path != vtx.lPfx:
|
||||
if path != vtx.pfx:
|
||||
err(PartChnLeafPathMismatch)
|
||||
else:
|
||||
ok()
|
||||
|
||||
of Branch:
|
||||
let nChewOff = sharedPrefixLen(vtx.ePfx, path)
|
||||
if nChewOff != vtx.ePfx.len:
|
||||
let nChewOff = sharedPrefixLen(vtx.pfx, path)
|
||||
if nChewOff != vtx.pfx.len:
|
||||
err(PartChnExtPfxMismatch)
|
||||
elif path.len == nChewOff:
|
||||
err(PartChnBranchPathExhausted)
|
||||
|
|
|
@ -41,7 +41,7 @@ proc pp*(n: PrfNode; ps: PartStateRef): string =
|
|||
elif n.prfType == isError:
|
||||
"(" & $n.error & ")"
|
||||
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:
|
||||
"(" & NodeRef(n).pp(ps.db) & ")"
|
||||
|
||||
|
@ -93,7 +93,7 @@ proc pp*(t: Table[VertexID,HashKey]; ps: PartStateRef; indent = 4): string =
|
|||
.mapIt((it,t.getOrDefault it))
|
||||
.mapIt("(" & it[0].pp & "," & it[1].pp(ps.db) & ")")
|
||||
.join("," & indent.toPfx(1)) & "}"
|
||||
|
||||
|
||||
proc pp*(q: seq[HashKey]; ps: PartStateRef): string =
|
||||
"(" & q.mapIt(it.pp ps.db).join("->") & ")[#" & $q.len & "]"
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ proc read(rlp: var Rlp; T: type PrfNode): T {.gcsafe, raises: [RlpError].} =
|
|||
##
|
||||
func readError(error: AristoError): PrfNode =
|
||||
## Prettify return code expression
|
||||
PrfNode(vType: Leaf, prfType: isError, error: error)
|
||||
PrfNode(vtx: VertexRef(vType: Leaf), prfType: isError, error: error)
|
||||
|
||||
if not rlp.isList:
|
||||
# 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]
|
||||
if isLeaf:
|
||||
return PrfNode(
|
||||
vType: Leaf,
|
||||
prfType: ignore,
|
||||
lPfx: pathSegment,
|
||||
lData: LeafPayload(
|
||||
pType: RawData,
|
||||
rawBlob: blobs[1]))
|
||||
|
||||
vtx: VertexRef(
|
||||
vType: Leaf,
|
||||
pfx: pathSegment,
|
||||
lData: LeafPayload(
|
||||
pType: RawData,
|
||||
rawBlob: blobs[1])))
|
||||
else:
|
||||
var node = PrfNode(
|
||||
vType: Branch,
|
||||
prfType: isExtension,
|
||||
ePfx: pathSegment)
|
||||
vtx: VertexRef(
|
||||
vType: Branch,
|
||||
pfx: pathSegment))
|
||||
node.key[0] = HashKey.fromBytes(blobs[1]).valueOr:
|
||||
return readError(PartRlpExtHashKeyExpected)
|
||||
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:
|
||||
return readError(PartRlpBranchHashKeyExpected)
|
||||
return PrfNode(
|
||||
vType: Branch,
|
||||
vtx: VertexRef(
|
||||
vType: Branch),
|
||||
prfType: ignore,
|
||||
key: links)
|
||||
else:
|
||||
|
@ -137,11 +141,11 @@ func toNodesTab*(
|
|||
nodes[w.digestTo HashKey] = nd
|
||||
|
||||
# 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
|
||||
var pyl: PrfPayload
|
||||
try:
|
||||
pyl = rlp.decode(nd.lData.rawBlob, PrfPayload)
|
||||
pyl = rlp.decode(nd.vtx.lData.rawBlob, PrfPayload)
|
||||
except RlpError:
|
||||
pyl = PrfPayload(prfType: isError, error: PartRlpPayloadException)
|
||||
|
||||
|
@ -150,10 +154,10 @@ func toNodesTab*(
|
|||
# Single value encoding might not be unique so it cannot be
|
||||
# automatically detected
|
||||
if mode != AutomaticPayload:
|
||||
nd.lData = LeafPayload(pType: StoData, stoData: pyl.num)
|
||||
nd.vtx.lData = LeafPayload(pType: StoData, stoData: pyl.num)
|
||||
of isAccount:
|
||||
nd.key[0] = pyl.acc.storageRoot.to(HashKey)
|
||||
nd.lData = LeafPayload(
|
||||
nd.vtx.lData = LeafPayload(
|
||||
pType: AccountData,
|
||||
account: AristoAccount(
|
||||
nonce: pyl.acc.nonce,
|
||||
|
@ -174,11 +178,11 @@ func toNodesTab*(
|
|||
# Need to store raw extension
|
||||
nodes[xKey] = xNode
|
||||
continue
|
||||
if nd.ePfx.len != 0:
|
||||
if nd.vtx.pfx.len != 0:
|
||||
return err(PartGarbledExtsInProofs)
|
||||
# Move extended `nd` branch node
|
||||
nd.prfType = ignore
|
||||
nd.ePfx = xNode.ePfx
|
||||
nd.vtx.pfx = xNode.vtx.pfx
|
||||
nodes.del xNode.key[0]
|
||||
nodes[xKey] = nd
|
||||
|
||||
|
@ -196,8 +200,8 @@ proc backLinks*(nTab: TableRef[HashKey,PrfNode]): PrfBackLinks =
|
|||
|
||||
# Collect predecessor list
|
||||
for (key,nd) in nTab.pairs:
|
||||
if nd.vType == Leaf:
|
||||
if nd.lData.pType == AccountData and nd.key[0].isValid:
|
||||
if nd.vtx.vType == Leaf:
|
||||
if nd.vtx.lData.pType == AccountData and nd.key[0].isValid:
|
||||
result.links[nd.key[0]] = key
|
||||
elif nd.prfType == isExtension:
|
||||
result.links[nd.key[0]] = key
|
||||
|
@ -280,7 +284,7 @@ proc updateAccountsTree*(
|
|||
for chain in bl.chains:
|
||||
for key in chain:
|
||||
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
|
||||
if not accRootKey.isValid:
|
||||
|
|
|
@ -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
|
||||
## and branch vertex argument, there will be a double item list result.
|
||||
##
|
||||
case node.vType:
|
||||
case node.vtx.vType:
|
||||
of Branch:
|
||||
# Do branch node
|
||||
var wr = initRlpWriter()
|
||||
|
@ -80,13 +80,13 @@ proc to*(node: NodeRef; T: type seq[Blob]): T =
|
|||
wr.append EmptyBlob
|
||||
let brData = wr.finish()
|
||||
|
||||
if 0 < node.ePfx.len:
|
||||
if 0 < node.vtx.pfx.len:
|
||||
# Prefix branch by embedded extension node
|
||||
let brHash = brData.digestTo(HashKey)
|
||||
|
||||
var wrx = initRlpWriter()
|
||||
wrx.startList(2)
|
||||
wrx.append node.ePfx.toHexPrefix(isleaf = false).data()
|
||||
wrx.append node.vtx.pfx.toHexPrefix(isleaf = false).data()
|
||||
wrx.append brHash
|
||||
|
||||
result.add wrx.finish()
|
||||
|
@ -104,8 +104,8 @@ proc to*(node: NodeRef; T: type seq[Blob]): T =
|
|||
|
||||
var wr = initRlpWriter()
|
||||
wr.startList(2)
|
||||
wr.append node.lPfx.toHexPrefix(isleaf = true).data()
|
||||
wr.append node.lData.serialise(getKey0).value
|
||||
wr.append node.vtx.pfx.toHexPrefix(isleaf = true).data()
|
||||
wr.append node.vtx.lData.serialise(getKey0).value
|
||||
|
||||
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`.
|
||||
##
|
||||
var wr = initRlpWriter()
|
||||
case node.vType:
|
||||
case node.vtx.vType:
|
||||
of Branch:
|
||||
# Do branch node
|
||||
wr.startList(17)
|
||||
|
@ -123,11 +123,11 @@ proc digestTo*(node: NodeRef; T: type HashKey): T =
|
|||
wr.append EmptyBlob
|
||||
|
||||
# Do for embedded extension node
|
||||
if 0 < node.ePfx.len:
|
||||
if 0 < node.vtx.pfx.len:
|
||||
let brHash = wr.finish().digestTo(HashKey)
|
||||
wr = initRlpWriter()
|
||||
wr.startList(2)
|
||||
wr.append node.ePfx.toHexPrefix(isleaf = false).data()
|
||||
wr.append node.vtx.pfx.toHexPrefix(isleaf = false).data()
|
||||
wr.append brHash
|
||||
|
||||
of Leaf:
|
||||
|
@ -138,8 +138,8 @@ proc digestTo*(node: NodeRef; T: type HashKey): T =
|
|||
ok(node.key[0]) # always succeeds
|
||||
|
||||
wr.startList(2)
|
||||
wr.append node.lPfx.toHexPrefix(isleaf = true).data()
|
||||
wr.append node.lData.serialise(getKey0).value
|
||||
wr.append node.vtx.pfx.toHexPrefix(isleaf = true).data()
|
||||
wr.append node.vtx.lData.serialise(getKey0).value
|
||||
|
||||
wr.finish().digestTo(HashKey)
|
||||
|
||||
|
|
|
@ -56,7 +56,7 @@ proc toNode*(
|
|||
|
||||
case vtx.vType:
|
||||
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
|
||||
if vtx.lData.pType == AccountData:
|
||||
let stoID = vtx.lData.stoID
|
||||
|
@ -68,7 +68,7 @@ proc toNode*(
|
|||
return ok node
|
||||
|
||||
of Branch:
|
||||
let node = NodeRef(vType: Branch, bVid: vtx.bVid, ePfx: vtx.ePfx)
|
||||
let node = NodeRef(vtx: vtx.dup())
|
||||
var missing: seq[VertexID]
|
||||
for n in 0 .. 15:
|
||||
let vid = vtx.bVid[n]
|
||||
|
@ -100,15 +100,15 @@ iterator subVids*(vtx: VertexRef): VertexID =
|
|||
|
||||
iterator subVidKeys*(node: NodeRef): (VertexID,HashKey) =
|
||||
## Simolar to `subVids()` but for nodes
|
||||
case node.vType:
|
||||
case node.vtx.vType:
|
||||
of Leaf:
|
||||
if node.lData.pType == AccountData:
|
||||
let stoID = node.lData.stoID
|
||||
if node.vtx.lData.pType == AccountData:
|
||||
let stoID = node.vtx.lData.stoID
|
||||
if stoID.isValid:
|
||||
yield (stoID.vid, node.key[0])
|
||||
of Branch:
|
||||
for n in 0 .. 15:
|
||||
let vid = node.bVid[n]
|
||||
let vid = node.vtx.bVid[n]
|
||||
if vid.isValid:
|
||||
yield (vid,node.key[n])
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ suite "Aristo blobify":
|
|||
|
||||
extension = VertexRef(
|
||||
vType: Branch,
|
||||
ePfx: NibblesBuf.nibble(2),
|
||||
pfx: NibblesBuf.nibble(2),
|
||||
bVid: [
|
||||
VertexID(0),
|
||||
VertexID(0),
|
||||
|
|
Loading…
Reference in New Issue