Skip to content

Commit

Permalink
simplify VertexRef (#2626)
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
arnetheduck authored Sep 13, 2024
1 parent 0be6291 commit adb8d64
Show file tree
Hide file tree
Showing 16 changed files with 133 additions and 143 deletions.
10 changes: 5 additions & 5 deletions nimbus/db/aristo/aristo_blobify.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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)
Expand Down Expand Up @@ -325,7 +325,7 @@ proc deblobify*(
# End `while`
VertexRef(
vType: Branch,
ePfx: pathSegment,
pfx: pathSegment,
bVid: vtxList)

of 3: # `Leaf` vertex
Expand All @@ -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
Expand Down
6 changes: 3 additions & 3 deletions nimbus/db/aristo/aristo_compute.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -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)
Expand Down
38 changes: 19 additions & 19 deletions nimbus/db/aristo/aristo_debug.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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:
Expand Down
4 changes: 2 additions & 2 deletions nimbus/db/aristo/aristo_delete.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions nimbus/db/aristo/aristo_delete/delete_subtree.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
41 changes: 16 additions & 25 deletions nimbus/db/aristo/aristo_desc/desc_structural.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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

# ----------------------
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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 =
Expand All @@ -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
Expand Down
14 changes: 7 additions & 7 deletions nimbus/db/aristo/aristo_hike.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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*(
Expand Down Expand Up @@ -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
Expand Down
27 changes: 11 additions & 16 deletions nimbus/db/aristo/aristo_merge/merge_payload_helper.nim
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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:
Expand All @@ -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()
Expand All @@ -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:
Expand All @@ -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
Expand Down
Loading

0 comments on commit adb8d64

Please sign in to comment.