Smaller leaf types

This commit is contained in:
Jacek Sieka 2024-12-03 11:10:48 +01:00
parent fa09c54a37
commit a984d54c2d
No known key found for this signature in database
GPG Key ID: A1B09461ABB656B8
13 changed files with 117 additions and 151 deletions

View File

@ -48,7 +48,8 @@ proc branchStillNeeded(vtx: VertexRef, removed: int8): Result[int8,void] =
proc deleteImpl( proc deleteImpl(
db: AristoDbRef; # Database, top layer db: AristoDbRef; # Database, top layer
hike: Hike; # Fully expanded path hike: Hike; # Fully expanded path
): Result[VertexRef,AristoError] = T: type
): Result[Opt[T],AristoError] =
## Removes the last node in the hike and returns the updated leaf in case ## Removes the last node in the hike and returns the updated leaf in case
## a branch collapsed ## a branch collapsed
@ -62,7 +63,7 @@ proc deleteImpl(
if hike.legs.len == 1: if hike.legs.len == 1:
# This was the last node in the trie, meaning we don't have any branches or # This was the last node in the trie, meaning we don't have any branches or
# leaves to update # leaves to update
return ok(default(VertexRef)) return ok(default(Opt[T]))
if hike.legs[^2].wp.vtx.vType != Branch: if hike.legs[^2].wp.vtx.vType != Branch:
return err(DelBranchExpexted) return err(DelBranchExpexted)
@ -111,16 +112,16 @@ proc deleteImpl(
db.layersPutVtx((hike.root, br.vid), vtx) db.layersPutVtx((hike.root, br.vid), vtx)
if vtx.vType == Leaf: if vtx.vType == Leaf:
ok(vtx) ok(Opt.some(vtx.to(T)))
else: else:
ok(default(VertexRef)) ok(Opt.none(T))
else: else:
# Clear the removed leaf from the branch (that still contains other children) # Clear the removed leaf from the branch (that still contains other children)
var brDup = br.vtx.dup var brDup = br.vtx.dup
discard brDup.setUsed(uint8 hike.legs[^2].nibble, false) discard brDup.setUsed(uint8 hike.legs[^2].nibble, false)
db.layersPutVtx((hike.root, br.vid), brDup) db.layersPutVtx((hike.root, br.vid), brDup)
ok(default(VertexRef)) ok(Opt.none(T))
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# Public functions # Public functions
@ -145,64 +146,17 @@ proc deleteAccountRecord*(
if stoID.isValid: if stoID.isValid:
? db.delStoTreeImpl((stoID.vid, stoID.vid), accPath) ? db.delStoTreeImpl((stoID.vid, stoID.vid), accPath)
let otherLeaf = ?db.deleteImpl(accHike) let otherLeaf = ?db.deleteImpl(accHike, AccountLeaf)
db.layersPutAccLeaf(accPath, default(VertexRef)) db.layersPutAccLeaf(accPath, default(Opt[AccountLeaf]))
if otherLeaf.isValid: if otherLeaf.isSome:
db.layersPutAccLeaf( db.layersPutAccLeaf(
Hash32(getBytes(NibblesBuf.fromBytes(accPath.data).replaceSuffix(otherLeaf.pfx))), Hash32(getBytes(NibblesBuf.fromBytes(accPath.data).replaceSuffix(otherLeaf[].pfx))),
otherLeaf) otherLeaf)
ok() ok()
proc deleteGenericData*(
db: AristoDbRef;
root: VertexID;
path: openArray[byte];
): Result[bool,AristoError] =
## Delete the leaf data entry addressed by the argument `path`. The MPT
## sub-tree the leaf data entry is subsumed under is passed as argument
## `root` which must be greater than `VertexID(1)` and smaller than
## `LEAST_FREE_VID`.
##
## The return value is `true` if the argument `path` deleted was the last
## one and the tree does not exist anymore.
##
# Verify that `root` is neither an accounts tree nor a strorage tree.
if not root.isValid:
return err(DelRootVidMissing)
elif root == VertexID(1):
return err(DelAccRootNotAccepted)
elif LEAST_FREE_VID <= root.distinctBase:
return err(DelStoRootNotAccepted)
var hike: Hike
path.hikeUp(root, db, Opt.none(VertexRef), hike).isOkOr:
if error[1] in HikeAcceptableStopsNotFound:
return err(DelPathNotFound)
return err(error[1])
discard ?db.deleteImpl(hike)
ok(not db.getVtx((root, root)).isValid)
proc deleteGenericTree*(
db: AristoDbRef; # Database, top layer
root: VertexID; # Root vertex
): Result[void,AristoError] =
## Variant of `deleteGenericData()` for purging the whole MPT sub-tree.
##
# Verify that `root` is neither an accounts tree nor a strorage tree.
if not root.isValid:
return err(DelRootVidMissing)
elif root == VertexID(1):
return err(DelAccRootNotAccepted)
elif LEAST_FREE_VID <= root.distinctBase:
return err(DelStoRootNotAccepted)
db.delSubTreeImpl root
proc deleteStorageData*( proc deleteStorageData*(
db: AristoDbRef; db: AristoDbRef;
accPath: Hash32; # Implies storage data tree accPath: Hash32; # Implies storage data tree
@ -220,7 +174,7 @@ proc deleteStorageData*(
mixPath = mixUp(accPath, stoPath) mixPath = mixUp(accPath, stoPath)
stoLeaf = db.cachedStoLeaf(mixPath) stoLeaf = db.cachedStoLeaf(mixPath)
if stoLeaf == Opt.some(default(VertexRef)): if stoLeaf == Opt.some(default(Opt[StoLeaf])):
return err(DelPathNotFound) return err(DelPathNotFound)
var accHike: Hike var accHike: Hike
@ -246,13 +200,13 @@ proc deleteStorageData*(
# Mark account path Merkle keys for update # Mark account path Merkle keys for update
db.layersResKeys accHike db.layersResKeys accHike
let otherLeaf = ?db.deleteImpl(stoHike) let otherLeaf = ?db.deleteImpl(stoHike, StoLeaf)
db.layersPutStoLeaf(mixPath, default(VertexRef)) db.layersPutStoLeaf(mixPath, default(Opt[StoLeaf]))
if otherLeaf.isValid: if otherLeaf.isSome:
let leafMixPath = mixUp( let leafMixPath = mixUp(
accPath, accPath,
Hash32(getBytes(stoNibbles.replaceSuffix(otherLeaf.pfx)))) Hash32(getBytes(stoNibbles.replaceSuffix(otherLeaf[].pfx))))
db.layersPutStoLeaf(leafMixPath, otherLeaf) db.layersPutStoLeaf(leafMixPath, otherLeaf)
# If there was only one item (that got deleted), update the account as well # If there was only one item (that got deleted), update the account as well
@ -262,7 +216,7 @@ proc deleteStorageData*(
# De-register the deleted storage tree from the account record # De-register the deleted storage tree from the account record
var leaf = wpAcc.vtx.dup # Dup on modify var leaf = wpAcc.vtx.dup # Dup on modify
leaf.lData.stoID.isValid = false leaf.lData.stoID.isValid = false
db.layersPutAccLeaf(accPath, leaf) db.layersPutAccLeaf(accPath, Opt.some(leaf.to(AccountLeaf)))
db.layersPutVtx((accHike.root, wpAcc.vid), leaf) db.layersPutVtx((accHike.root, wpAcc.vid), leaf)
ok(true) ok(true)
@ -294,7 +248,7 @@ proc deleteStorageTree*(
# De-register the deleted storage tree from the accounts record # De-register the deleted storage tree from the accounts record
var leaf = wpAcc.vtx.dup # Dup on modify var leaf = wpAcc.vtx.dup # Dup on modify
leaf.lData.stoID.isValid = false leaf.lData.stoID.isValid = false
db.layersPutAccLeaf(accPath, leaf) db.layersPutAccLeaf(accPath, Opt.some(leaf.to(AccountLeaf)))
db.layersPutVtx((accHike.root, wpAcc.vid), leaf) db.layersPutVtx((accHike.root, wpAcc.vid), leaf)
ok() ok()

View File

@ -61,7 +61,7 @@ proc delStoTreeNow(
of Leaf: of Leaf:
let stoPath = Hash32((stoPath & vtx.pfx).getBytes()) let stoPath = Hash32((stoPath & vtx.pfx).getBytes())
db.layersPutStoLeaf(mixUp(accPath, stoPath), default(VertexRef)) db.layersPutStoLeaf(mixUp(accPath, stoPath), default(Opt[StoLeaf]))
db.layersResVtx(rvid) db.layersResVtx(rvid)

View File

@ -64,7 +64,7 @@ type
txUidGen*: uint ## Tx-relative unique number generator txUidGen*: uint ## Tx-relative unique number generator
dudes: DudesRef ## Related DB descriptors dudes: DudesRef ## Related DB descriptors
accLeaves*: LruCache[Hash32, VertexRef] accLeaves*: LruCache[Hash32, Opt[AccountLeaf]]
## Account path to payload cache - accounts are frequently accessed by ## Account path to payload cache - accounts are frequently accessed by
## account path when contracts interact with them - this cache ensures ## account path when contracts interact with them - this cache ensures
## that we don't have to re-traverse the storage trie for every such ## that we don't have to re-traverse the storage trie for every such
@ -72,7 +72,7 @@ type
## TODO a better solution would probably be to cache this in a type ## TODO a better solution would probably be to cache this in a type
## exposed to the high-level API ## exposed to the high-level API
stoLeaves*: LruCache[Hash32, VertexRef] stoLeaves*: LruCache[Hash32, Opt[StoLeaf]]
## Mixed account/storage path to payload cache - same as above but caches ## Mixed account/storage path to payload cache - same as above but caches
## the full lookup of storage slots ## the full lookup of storage slots

View File

@ -79,6 +79,15 @@ type
startVid*: VertexID startVid*: VertexID
used*: uint16 used*: uint16
AccountLeaf* = object
pfx*: NibblesBuf
account*: AristoAccount
stoID*: StorageID
StoLeaf* = object
pfx*: NibblesBuf
stoData*: UInt256
NodeRef* = ref object of RootRef 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.
@ -125,8 +134,8 @@ type
kMap*: Table[RootedVertexID,HashKey] ## Merkle hash key mapping kMap*: Table[RootedVertexID,HashKey] ## Merkle hash key mapping
vTop*: VertexID ## Last used vertex ID vTop*: VertexID ## Last used vertex ID
accLeaves*: Table[Hash32, VertexRef] ## Account path -> VertexRef accLeaves*: Table[Hash32, Opt[AccountLeaf]] ## Account path -> VertexRef
stoLeaves*: Table[Hash32, VertexRef] ## Storage path -> VertexRef stoLeaves*: Table[Hash32, Opt[StoLeaf]] ## Storage path -> VertexRef
txUid*: uint ## Transaction identifier if positive txUid*: uint ## Transaction identifier if positive
@ -196,6 +205,18 @@ proc `==`*(a, b: VertexRef): bool =
return false return false
true true
func to*(v: VertexRef, _: type AccountLeaf): AccountLeaf =
AccountLeaf(pfx: v.pfx, account: v.lData.account, stoID: v.lData.stoID)
func to*(v: VertexRef, _: type StoLeaf): StoLeaf =
StoLeaf(pfx: v.pfx, stoData: v.lData.stoData)
func to*(v: AccountLeaf, _: type VertexRef): VertexRef =
VertexRef(pfx: v.pfx, vType: Leaf, lData: LeafPayload(pType: AccountData, account: v.account, stoID: v.stoID))
func to*(v: StoLeaf, _: type VertexRef): VertexRef =
VertexRef(pfx: v.pfx, vType: Leaf, lData: LeafPayload(pType: StoData, stoData: v.stoData))
iterator pairs*(vtx: VertexRef): tuple[nibble: uint8, vid: VertexID] = iterator pairs*(vtx: VertexRef): tuple[nibble: uint8, vid: VertexID] =
## Iterates over the sub-vids of a branch (does nothing for leaves) ## Iterates over the sub-vids of a branch (does nothing for leaves)
case vtx.vType: case vtx.vType:

View File

@ -27,7 +27,8 @@ proc retrieveLeaf(
db: AristoDbRef; db: AristoDbRef;
root: VertexID; root: VertexID;
path: Hash32; path: Hash32;
): Result[VertexRef,AristoError] = T: type
): Result[T,AristoError] =
for step in stepUp(NibblesBuf.fromBytes(path.data), root, db): for step in stepUp(NibblesBuf.fromBytes(path.data), root, db):
let vtx = step.valueOr: let vtx = step.valueOr:
if error in HikeAcceptableStopsNotFound: if error in HikeAcceptableStopsNotFound:
@ -35,42 +36,42 @@ proc retrieveLeaf(
return err(error) return err(error)
if vtx.vType == Leaf: if vtx.vType == Leaf:
return ok vtx return ok vtx.to(T)
return err(FetchPathNotFound) return err(FetchPathNotFound)
proc cachedAccLeaf*(db: AristoDbRef; accPath: Hash32): Opt[VertexRef] = proc cachedAccLeaf*(db: AristoDbRef; accPath: Hash32): Opt[Opt[AccountLeaf]] =
# Return vertex from layers or cache, `nil` if it's known to not exist and # Return vertex from layers or cache, `nil` if it's known to not exist and
# none otherwise # none otherwise
db.layersGetAccLeaf(accPath) or db.layersGetAccLeaf(accPath) or
db.accLeaves.get(accPath) or db.accLeaves.get(accPath) or
Opt.none(VertexRef) Opt.none(Opt[AccountLeaf])
proc cachedStoLeaf*(db: AristoDbRef; mixPath: Hash32): Opt[VertexRef] = proc cachedStoLeaf*(db: AristoDbRef; mixPath: Hash32): Opt[Opt[StoLeaf]] =
# Return vertex from layers or cache, `nil` if it's known to not exist and # Return vertex from layers or cache, `nil` if it's known to not exist and
# none otherwise # none otherwise
db.layersGetStoLeaf(mixPath) or db.layersGetStoLeaf(mixPath) or
db.stoLeaves.get(mixPath) or db.stoLeaves.get(mixPath) or
Opt.none(VertexRef) Opt.none(Opt[StoLeaf])
proc retrieveAccountLeaf( proc retrieveAccountLeaf(
db: AristoDbRef; db: AristoDbRef;
accPath: Hash32; accPath: Hash32;
): Result[VertexRef,AristoError] = ): Result[AccountLeaf,AristoError] =
if (let leafVtx = db.cachedAccLeaf(accPath); leafVtx.isSome()): if (let leafVtx = db.cachedAccLeaf(accPath); leafVtx.isSome()):
if not leafVtx[].isValid(): if not leafVtx[].isSome():
return err(FetchPathNotFound) return err(FetchPathNotFound)
return ok leafVtx[] return ok leafVtx[][]
# Updated payloads are stored in the layers so if we didn't find them there, # Updated payloads are stored in the layers so if we didn't find them there,
# it must have been in the database # it must have been in the database
let let
leafVtx = db.retrieveLeaf(VertexID(1), accPath).valueOr: leafVtx = db.retrieveLeaf(VertexID(1), accPath, AccountLeaf).valueOr:
if error == FetchPathNotFound: if error == FetchPathNotFound:
db.accLeaves.put(accPath, default(VertexRef)) db.accLeaves.put(accPath, default(Opt[AccountLeaf]))
return err(error) return err(error)
db.accLeaves.put(accPath, leafVtx) db.accLeaves.put(accPath, Opt.some(leafVtx))
ok leafVtx ok leafVtx
@ -105,7 +106,7 @@ proc fetchStorageIdImpl(
## Helper function for retrieving a storage (vertex) ID for a given account. ## Helper function for retrieving a storage (vertex) ID for a given account.
let let
leafVtx = ?db.retrieveAccountLeaf(accPath) leafVtx = ?db.retrieveAccountLeaf(accPath)
stoID = leafVtx.lData.stoID stoID = leafVtx.stoID
if stoID.isValid: if stoID.isValid:
ok stoID.vid ok stoID.vid
@ -126,11 +127,11 @@ proc fetchAccountHike*(
## Expand account path to account leaf or return failure ## Expand account path to account leaf or return failure
# Prefer the leaf cache so as not to burden the lower layers # Prefer the leaf cache so as not to burden the lower layers
let leaf = db.cachedAccLeaf(accPath) let accLeaf = db.cachedAccLeaf(accPath)
if leaf == Opt.some(default(VertexRef)): if accLeaf == Opt.some(Opt.none(AccountLeaf)):
return err(FetchAccInaccessible) return err(FetchAccInaccessible)
accPath.hikeUp(VertexID(1), db, leaf, accHike).isOkOr: accPath.hikeUp(VertexID(1), db, accLeaf, accHike).isOkOr:
return err(FetchAccInaccessible) return err(FetchAccInaccessible)
# Extract the account payload from the leaf # Extract the account payload from the leaf
@ -159,20 +160,20 @@ proc retrieveStoragePayload(
let mixPath = mixUp(accPath, stoPath) let mixPath = mixUp(accPath, stoPath)
if (let leafVtx = db.cachedStoLeaf(mixPath); leafVtx.isSome()): if (let leafVtx = db.cachedStoLeaf(mixPath); leafVtx.isSome()):
if not leafVtx[].isValid(): if not leafVtx[].isSome():
return err(FetchPathNotFound) return err(FetchPathNotFound)
return ok leafVtx[].lData.stoData return ok leafVtx[][].stoData
# Updated payloads are stored in the layers so if we didn't find them there, # Updated payloads are stored in the layers so if we didn't find them there,
# it must have been in the database # it must have been in the database
let leafVtx = db.retrieveLeaf(? db.fetchStorageIdImpl(accPath), stoPath).valueOr: let leafVtx = db.retrieveLeaf(? db.fetchStorageIdImpl(accPath), stoPath, StoLeaf).valueOr:
if error == FetchPathNotFound: if error == FetchPathNotFound:
db.stoLeaves.put(mixPath, default(VertexRef)) db.stoLeaves.put(mixPath, default(Opt[StoLeaf]))
return err(error) return err(error)
db.stoLeaves.put(mixPath, leafVtx) db.stoLeaves.put(mixPath, Opt.some(leafVtx))
ok leafVtx.lData.stoData ok leafVtx.stoData
proc hasStoragePayload( proc hasStoragePayload(
db: AristoDbRef; db: AristoDbRef;
@ -205,9 +206,8 @@ proc fetchAccountRecord*(
## Fetch an account record from the database indexed by `accPath`. ## Fetch an account record from the database indexed by `accPath`.
## ##
let leafVtx = ? db.retrieveAccountLeaf(accPath) let leafVtx = ? db.retrieveAccountLeaf(accPath)
assert leafVtx.lData.pType == AccountData # debugging only
ok leafVtx.lData.account ok leafVtx.account
proc fetchStateRoot*( proc fetchStateRoot*(
db: AristoDbRef; db: AristoDbRef;

View File

@ -124,11 +124,11 @@ iterator stepUp*(
if path.len == 0: if path.len == 0:
break break
proc hikeUp*( proc hikeUp*[T](
path: NibblesBuf; # Partial path path: NibblesBuf; # Partial path
root: VertexID; # Start vertex root: VertexID; # Start vertex
db: AristoDbRef; # Database db: AristoDbRef; # Database
leaf: Opt[VertexRef]; leaf: Opt[T];
hike: var Hike; hike: var Hike;
): Result[void,(VertexID,AristoError)] = ): Result[void,(VertexID,AristoError)] =
## For the argument `path`, find and return the logest possible path in the ## For the argument `path`, find and return the logest possible path in the
@ -147,10 +147,11 @@ proc hikeUp*(
var vid = root var vid = root
while true: while true:
if leaf.isSome() and leaf[].isValid and path == leaf[].pfx: when T is Opt[AccountLeaf] or T is Opt[StoLeaf]:
hike.legs.add Leg(wp: VidVtxPair(vid: vid, vtx: leaf[]), nibble: -1) if leaf.isSome() and leaf[].isSome and path == leaf[][].pfx:
reset(hike.tail) hike.legs.add Leg(wp: VidVtxPair(vid: vid, vtx: leaf[][].to(VertexRef)), nibble: -1)
break reset(hike.tail)
break
let (vtx, path, next) = step(hike.tail, (root, vid), db).valueOr: let (vtx, path, next) = step(hike.tail, (root, vid), db).valueOr:
return err((vid,error)) return err((vid,error))
@ -173,30 +174,30 @@ proc hikeUp*(
ok() ok()
proc hikeUp*( proc hikeUp*[T](
lty: LeafTie; lty: LeafTie;
db: AristoDbRef; db: AristoDbRef;
leaf: Opt[VertexRef]; leaf: Opt[T];
hike: var Hike hike: var Hike
): Result[void,(VertexID,AristoError)] = ): Result[void,(VertexID,AristoError)] =
## Variant of `hike()` ## Variant of `hike()`
lty.path.to(NibblesBuf).hikeUp(lty.root, db, leaf, hike) lty.path.to(NibblesBuf).hikeUp(lty.root, db, leaf, hike)
proc hikeUp*( proc hikeUp*[T](
path: openArray[byte]; path: openArray[byte];
root: VertexID; root: VertexID;
db: AristoDbRef; db: AristoDbRef;
leaf: Opt[VertexRef]; leaf: Opt[T];
hike: var Hike hike: var Hike
): Result[void,(VertexID,AristoError)] = ): Result[void,(VertexID,AristoError)] =
## Variant of `hike()` ## Variant of `hike()`
NibblesBuf.fromBytes(path).hikeUp(root, db, leaf, hike) NibblesBuf.fromBytes(path).hikeUp(root, db, leaf, hike)
proc hikeUp*( proc hikeUp*[T](
path: Hash32; path: Hash32;
root: VertexID; root: VertexID;
db: AristoDbRef; db: AristoDbRef;
leaf: Opt[VertexRef]; leaf: Opt[T];
hike: var Hike hike: var Hike
): Result[void,(VertexID,AristoError)] = ): Result[void,(VertexID,AristoError)] =
## Variant of `hike()` ## Variant of `hike()`

View File

@ -54,8 +54,8 @@ proc newAristoRdbDbRef(
ok((AristoDbRef( ok((AristoDbRef(
top: LayerRef(vTop: vTop), top: LayerRef(vTop: vTop),
backend: be, backend: be,
accLeaves: LruCache[Hash32, VertexRef].init(ACC_LRU_SIZE), accLeaves: LruCache[Hash32, Opt[AccountLeaf]].init(ACC_LRU_SIZE),
stoLeaves: LruCache[Hash32, VertexRef].init(ACC_LRU_SIZE), stoLeaves: LruCache[Hash32, Opt[StoLeaf]].init(ACC_LRU_SIZE),
), oCfs)) ), oCfs))
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------

View File

@ -91,7 +91,7 @@ func layersGetKeyOrVoid*(db: AristoDbRef; rvid: RootedVertexID): HashKey =
## Simplified version of `layersGetKey()` ## Simplified version of `layersGetKey()`
(db.layersGetKey(rvid).valueOr (VOID_HASH_KEY, 0))[0] (db.layersGetKey(rvid).valueOr (VOID_HASH_KEY, 0))[0]
func layersGetAccLeaf*(db: AristoDbRef; accPath: Hash32): Opt[VertexRef] = func layersGetAccLeaf*(db: AristoDbRef; accPath: Hash32): Opt[Opt[AccountLeaf]] =
db.top.accLeaves.withValue(accPath, item): db.top.accLeaves.withValue(accPath, item):
return Opt.some(item[]) return Opt.some(item[])
@ -99,9 +99,9 @@ func layersGetAccLeaf*(db: AristoDbRef; accPath: Hash32): Opt[VertexRef] =
w.accLeaves.withValue(accPath, item): w.accLeaves.withValue(accPath, item):
return Opt.some(item[]) return Opt.some(item[])
Opt.none(VertexRef) Opt.none(Opt[AccountLeaf])
func layersGetStoLeaf*(db: AristoDbRef; mixPath: Hash32): Opt[VertexRef] = func layersGetStoLeaf*(db: AristoDbRef; mixPath: Hash32): Opt[Opt[StoLeaf]] =
db.top.stoLeaves.withValue(mixPath, item): db.top.stoLeaves.withValue(mixPath, item):
return Opt.some(item[]) return Opt.some(item[])
@ -109,7 +109,7 @@ func layersGetStoLeaf*(db: AristoDbRef; mixPath: Hash32): Opt[VertexRef] =
w.stoLeaves.withValue(mixPath, item): w.stoLeaves.withValue(mixPath, item):
return Opt.some(item[]) return Opt.some(item[])
Opt.none(VertexRef) Opt.none(Opt[StoLeaf])
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------
# Public functions: setter variants # Public functions: setter variants
@ -153,10 +153,10 @@ func layersResKeys*(db: AristoDbRef; hike: Hike) =
for i in 1..hike.legs.len: for i in 1..hike.legs.len:
db.layersResKey((hike.root, hike.legs[^i].wp.vid), hike.legs[^i].wp.vtx) db.layersResKey((hike.root, hike.legs[^i].wp.vid), hike.legs[^i].wp.vtx)
func layersPutAccLeaf*(db: AristoDbRef; accPath: Hash32; leafVtx: VertexRef) = func layersPutAccLeaf*(db: AristoDbRef; accPath: Hash32; leafVtx: Opt[AccountLeaf]) =
db.top.accLeaves[accPath] = leafVtx db.top.accLeaves[accPath] = leafVtx
func layersPutStoLeaf*(db: AristoDbRef; mixPath: Hash32; leafVtx: VertexRef) = func layersPutStoLeaf*(db: AristoDbRef; mixPath: Hash32; leafVtx: Opt[StoLeaf]) =
db.top.stoLeaves[mixPath] = leafVtx db.top.stoLeaves[mixPath] = leafVtx
# ------------------------------------------------------------------------------ # ------------------------------------------------------------------------------

View File

@ -38,13 +38,13 @@ proc layersPutLeaf(
db.layersPutVtx(rvid, vtx) db.layersPutVtx(rvid, vtx)
vtx vtx
proc mergePayloadImpl( proc mergePayloadImpl[T](
db: AristoDbRef, # Database, top layer db: AristoDbRef, # Database, top layer
root: VertexID, # MPT state root root: VertexID, # MPT state root
path: Hash32, # Leaf item to add to the database path: Hash32, # Leaf item to add to the database
leaf: Opt[VertexRef], leaf: Opt[Opt[T]],
payload: LeafPayload, # Payload value payload: LeafPayload, # Payload value
): Result[(VertexRef, VertexRef, VertexRef), AristoError] = ): Result[(T, Opt[NibblesBuf], Opt[T]), AristoError] =
## Merge the argument `(root,path)` key-value-pair into the top level vertex ## Merge the argument `(root,path)` key-value-pair into the top level vertex
## table of the database `db`. The `path` argument is used to address the ## table of the database `db`. The `path` argument is used to address the
## leaf vertex with the payload. It is stored or updated on the database ## leaf vertex with the payload. It is stored or updated on the database
@ -59,7 +59,7 @@ proc mergePayloadImpl(
# We're at the root vertex and there is no data - this must be a fresh # We're at the root vertex and there is no data - this must be a fresh
# VertexID! # VertexID!
return ok (db.layersPutLeaf((root, cur), path, payload), default(VertexRef), default(VertexRef)) return ok (db.layersPutLeaf((root, cur), path, payload).to(T), Opt.none(NibblesBuf), Opt.none(T))
vids: ArrayBuf[NibblesBuf.high + 1, VertexID] vids: ArrayBuf[NibblesBuf.high + 1, VertexID]
vtxs: ArrayBuf[NibblesBuf.high + 1, VertexRef] vtxs: ArrayBuf[NibblesBuf.high + 1, VertexRef]
@ -93,7 +93,7 @@ proc mergePayloadImpl(
db.layersPutLeaf((root, cur), path, payload) db.layersPutLeaf((root, cur), path, payload)
else: else:
db.layersPutLeaf((root, cur), path, payload) db.layersPutLeaf((root, cur), path, payload)
(leafVtx, default(VertexRef), default(VertexRef)) (leafVtx.to(T), Opt.none(NibblesBuf), Opt.none(T))
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
@ -111,7 +111,7 @@ proc mergePayloadImpl(
# We need to return vtx here because its pfx member hasn't yet been # We need to return vtx here because its pfx member hasn't yet been
# sliced off and is therefore shared with the hike # sliced off and is therefore shared with the hike
(leafVtx, vtx, other) (leafVtx.to(T), Opt.some(vtx.pfx), Opt.some(other.to(T)))
resetKeys() resetKeys()
return ok(res) return ok(res)
@ -126,8 +126,8 @@ proc mergePayloadImpl(
cur = next cur = next
path = path.slice(n + 1) path = path.slice(n + 1)
vtx = vtx =
if leaf.isSome and leaf[].isValid and leaf[].pfx == path: if leaf.isSome and leaf[].isSome and leaf[][].pfx == path:
leaf[] leaf[][].to(VertexRef)
else: else:
(?db.getVtxRc((root, next)))[0] (?db.getVtxRc((root, next)))[0]
@ -143,7 +143,7 @@ proc mergePayloadImpl(
leafVtx = db.layersPutLeaf((root, local), path.slice(n + 1), payload) leafVtx = db.layersPutLeaf((root, local), path.slice(n + 1), payload)
resetKeys() resetKeys()
return ok((leafVtx, default(VertexRef), default(VertexRef))) return ok((leafVtx.to(T), Opt.none(NibblesBuf), Opt.none(T)))
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
@ -163,7 +163,7 @@ proc mergePayloadImpl(
db.layersPutVtx((root, cur), branch) db.layersPutVtx((root, cur), branch)
resetKeys() resetKeys()
return ok((leafVtx, default(VertexRef), default(VertexRef))) return ok((leafVtx.to(T), Opt.none(NibblesBuf), Opt.none(T)))
err(MergeHikeFailed) err(MergeHikeFailed)
@ -193,10 +193,10 @@ proc mergeAccountRecord*(
# Update leaf cache both of the merged value and potentially the displaced # Update leaf cache both of the merged value and potentially the displaced
# leaf resulting from splitting a leaf into a branch with two leaves # leaf resulting from splitting a leaf into a branch with two leaves
db.layersPutAccLeaf(accPath, updated[0]) db.layersPutAccLeaf(accPath, Opt.some(updated[0]))
if updated[1].isValid: if updated[1].isSome:
let otherPath = Hash32(getBytes( let otherPath = Hash32(getBytes(
NibblesBuf.fromBytes(accPath.data).replaceSuffix(updated[1].pfx))) NibblesBuf.fromBytes(accPath.data).replaceSuffix(updated[1][])))
db.layersPutAccLeaf(otherPath, updated[2]) db.layersPutAccLeaf(otherPath, updated[2])
ok true ok true
@ -239,18 +239,18 @@ proc mergeStorageData*(
# Update leaf cache both of the merged value and potentially the displaced # Update leaf cache both of the merged value and potentially the displaced
# leaf resulting from splitting a leaf into a branch with two leaves # leaf resulting from splitting a leaf into a branch with two leaves
db.layersPutStoLeaf(mixPath, updated[0]) db.layersPutStoLeaf(mixPath, Opt.some(updated[0]))
if updated[1].isValid: if updated[1].isSome:
let otherPath = Hash32(getBytes( let otherPath = Hash32(getBytes(
NibblesBuf.fromBytes(stoPath.data).replaceSuffix(updated[1].pfx))) NibblesBuf.fromBytes(stoPath.data).replaceSuffix(updated[1][])))
db.layersPutStoLeaf(mixUp(accPath, otherPath), updated[2]) db.layersPutStoLeaf(mixUp(accPath, otherPath), updated[2])
if not stoID.isValid: if not stoID.isValid:
# Make sure that there is an account that refers to that storage trie # Make sure that there is an account that refers to that storage trie
var leaf = accHike.legs[^1].wp.vtx.dup # Dup on modify var leaf = accHike.legs[^1].wp.vtx.dup # Dup on modify
leaf.lData.stoID = useID leaf.lData.stoID = useID
db.layersPutAccLeaf(accPath, leaf) db.layersPutAccLeaf(accPath, Opt.some(leaf.to(AccountLeaf)))
db.layersPutVtx((VertexID(1), accHike.legs[^1].wp.vid), leaf) db.layersPutVtx((VertexID(1), accHike.legs[^1].wp.vid), leaf)
ok() ok()

View File

@ -145,9 +145,9 @@ proc zeroAdjust(
proc toHike(pfx: NibblesBuf, root: VertexID, db: AristoDbRef): Hike = proc toHike(pfx: NibblesBuf, root: VertexID, db: AristoDbRef): Hike =
when doLeast: when doLeast:
discard pfx.pathPfxPad(0).hikeUp(root, db, Opt.none(VertexRef), result) discard pfx.pathPfxPad(0).hikeUp(root, db, Opt.none(void), result)
else: else:
discard pfx.pathPfxPad(255).hikeUp(root, db, Opt.none(VertexRef), result) discard pfx.pathPfxPad(255).hikeUp(root, db, Opt.none(void), result)
if 0 < hike.legs.len: if 0 < hike.legs.len:
return ok(hike) return ok(hike)
@ -354,7 +354,7 @@ proc nearbyNextLeafTie(
): Result[PathID,(VertexID,AristoError)] = ): Result[PathID,(VertexID,AristoError)] =
## Variant of `nearbyNext()`, convenience wrapper ## Variant of `nearbyNext()`, convenience wrapper
var hike: Hike var hike: Hike
discard lty.hikeUp(db, Opt.none(VertexRef), hike) discard lty.hikeUp(db, Opt.none(void), hike)
hike = ?hike.nearbyNext(db, hikeLenMax, moveRight) hike = ?hike.nearbyNext(db, hikeLenMax, moveRight)
if 0 < hike.legs.len: if 0 < hike.legs.len:
@ -403,7 +403,7 @@ iterator rightPairs*(
## Traverse the sub-trie implied by the argument `start` with increasing ## Traverse the sub-trie implied by the argument `start` with increasing
## order. ## order.
var hike: Hike var hike: Hike
discard start.hikeUp(db, Opt.none(VertexRef), hike) discard start.hikeUp(db, Opt.none(void), hike)
var rc = hike.right db var rc = hike.right db
while rc.isOk: while rc.isOk:
hike = rc.value hike = rc.value
@ -431,7 +431,7 @@ iterator rightPairs*(
hike.legs.setLen(hike.legs.len - 1) hike.legs.setLen(hike.legs.len - 1)
break reuseHike break reuseHike
# Fall back to default method # Fall back to default method
discard key.next.hikeUp(db, Opt.none(VertexRef), hike) discard key.next.hikeUp(db, Opt.none(void), hike)
rc = hike.right db rc = hike.right db
# End while # End while
@ -488,7 +488,7 @@ iterator leftPairs*(
## the `path` field decremented by `1`. ## the `path` field decremented by `1`.
var var
hike: Hike hike: Hike
discard start.hikeUp(db, Opt.none(VertexRef), hike) discard start.hikeUp(db, Opt.none(void), hike)
var rc = hike.left db var rc = hike.left db
while rc.isOk: while rc.isOk:
@ -517,7 +517,7 @@ iterator leftPairs*(
hike.legs.setLen(hike.legs.len - 1) hike.legs.setLen(hike.legs.len - 1)
break reuseHike break reuseHike
# Fall back to default method # Fall back to default method
discard key.prev.hikeUp(db, Opt.none(VertexRef), hike) discard key.prev.hikeUp(db, Opt.none(void), hike)
rc = hike.left db rc = hike.left db
# End while # End while

View File

@ -125,27 +125,17 @@ proc ctxAcceptChange(psc: PartStateCtx): Result[bool,AristoError] =
proc ctxMergeBegin*( proc ctxMergeBegin*(
ps: PartStateRef; ps: PartStateRef;
root: VertexID; accPath: Hash32;
path: openArray[byte];
): Result[PartStateCtx,AristoError] = ): Result[PartStateCtx,AristoError] =
## This function clears the way for mering some payload at the argument ## Variant of `partMergeBegin()` for different path representation
## path `(root,path)`.
var hike: Hike var hike: Hike
path.hikeUp(root,ps.db, Opt.none(VertexRef), hike).isOkOr: accPath.hikeUp(VertexID(1),ps.db, Opt.none(Opt[AccountLeaf]), hike).isOkOr:
if error[1] != HikeDanglingEdge: if error[1] != HikeDanglingEdge:
return err error[1] # Cannot help here return err error[1] # Cannot help here
return ps.newCtx hike return ps.newCtx hike
ok PartStateCtx(nil) # Nothing to do ok PartStateCtx(nil) # Nothing to do
proc ctxMergeBegin*(
ps: PartStateRef;
accPath: Hash32;
): Result[PartStateCtx,AristoError] =
## Variant of `partMergeBegin()` for different path representation
ps.ctxMergeBegin(VertexID(1), accPath.data)
proc ctxMergeCommit*(psc: PartStateCtx): Result[bool,AristoError] = proc ctxMergeCommit*(psc: PartStateCtx): Result[bool,AristoError] =
## ##
if psc.isNil: if psc.isNil:

View File

@ -153,7 +153,7 @@ proc testCreatePortalProof(node: JsonNode, testStatusIMPL: var TestStatus) {.dep
let let
path = a.data.keccak256 path = a.data.keccak256
var hike: Hike var hike: Hike
let rc = path.hikeUp(VertexID(1), ps.db, Opt.none(VertexRef), hike) let rc = path.hikeUp(VertexID(1), ps.db, Opt.none(void), hike)
sample[path] = ProofData( sample[path] = ProofData(
error: (if rc.isErr: rc.error[1] else: AristoError(0)), error: (if rc.isErr: rc.error[1] else: AristoError(0)),
hike: hike) # keep `hike` for potential debugging hike: hike) # keep `hike` for potential debugging

View File

@ -95,7 +95,7 @@ proc randomisedLeafs(
var lvp: seq[(LeafTie,RootedVertexID)] var lvp: seq[(LeafTie,RootedVertexID)]
for lty in ltys: for lty in ltys:
var hike: Hike var hike: Hike
?lty.hikeUp(db, Opt.none(VertexRef), hike) ?lty.hikeUp(db, Opt.none(void), hike)
lvp.add (lty,(hike.root, hike.legs[^1].wp.vid)) lvp.add (lty,(hike.root, hike.legs[^1].wp.vid))
var lvp2 = lvp.sorted( var lvp2 = lvp.sorted(