mirror of
https://github.com/status-im/nimbus-eth1.git
synced 2025-01-17 07:41:46 +00:00
58cde36656
This kind of data is not used except in tests where it is used only to create databases that don't match actual usage of aristo. Removing simplifies future optimizations that can focus on processing specific leaf types more efficiently. A casualty of this removal is some test code as well as some proof generation code that is unused - on the surface, it looks like it should be possible to port both of these to the more specific data types - doing so would ensure that a database written by one part of the codebase can interact with the other - as it stands, there is confusion on this point since using the proof generation code will result in a database of a shape that is incompatible with the rest of eth1.
299 lines
8.9 KiB
Nim
299 lines
8.9 KiB
Nim
# nimbus-eth1
|
|
# Copyright (c) 2023-2024 Status Research & Development GmbH
|
|
# Licensed under either of
|
|
# * Apache License, version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or
|
|
# http://www.apache.org/licenses/LICENSE-2.0)
|
|
# * MIT license ([LICENSE-MIT](LICENSE-MIT) or
|
|
# http://opensource.org/licenses/MIT)
|
|
# at your option. This file may not be copied, modified, or distributed
|
|
# except according to those terms.
|
|
|
|
## Aristo DB -- Obects Retrival Via Traversal Path
|
|
## ===============================================
|
|
##
|
|
{.push raises: [].}
|
|
|
|
import
|
|
std/typetraits,
|
|
eth/common,
|
|
results,
|
|
"."/[aristo_compute, aristo_desc, aristo_get, aristo_layers, aristo_hike]
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# Private functions
|
|
# ------------------------------------------------------------------------------
|
|
|
|
proc retrieveLeaf(
|
|
db: AristoDbRef;
|
|
root: VertexID;
|
|
path: openArray[byte];
|
|
): Result[VertexRef,AristoError] =
|
|
if path.len == 0:
|
|
return err(FetchPathInvalid)
|
|
|
|
for step in stepUp(NibblesBuf.fromBytes(path), root, db):
|
|
let vtx = step.valueOr:
|
|
if error in HikeAcceptableStopsNotFound:
|
|
return err(FetchPathNotFound)
|
|
return err(error)
|
|
|
|
if vtx.vType == Leaf:
|
|
return ok vtx
|
|
|
|
return err(FetchPathNotFound)
|
|
|
|
proc cachedAccLeaf*(db: AristoDbRef; accPath: Hash32): Opt[VertexRef] =
|
|
# Return vertex from layers or cache, `nil` if it's known to not exist and
|
|
# none otherwise
|
|
db.layersGetAccLeaf(accPath) or
|
|
db.accLeaves.get(accPath) or
|
|
Opt.none(VertexRef)
|
|
|
|
proc cachedStoLeaf*(db: AristoDbRef; mixPath: Hash32): Opt[VertexRef] =
|
|
# Return vertex from layers or cache, `nil` if it's known to not exist and
|
|
# none otherwise
|
|
db.layersGetStoLeaf(mixPath) or
|
|
db.stoLeaves.get(mixPath) or
|
|
Opt.none(VertexRef)
|
|
|
|
proc retrieveAccountLeaf(
|
|
db: AristoDbRef;
|
|
accPath: Hash32;
|
|
): Result[VertexRef,AristoError] =
|
|
if (let leafVtx = db.cachedAccLeaf(accPath); leafVtx.isSome()):
|
|
if not leafVtx[].isValid():
|
|
return err(FetchPathNotFound)
|
|
return ok leafVtx[]
|
|
|
|
# Updated payloads are stored in the layers so if we didn't find them there,
|
|
# it must have been in the database
|
|
let
|
|
leafVtx = db.retrieveLeaf(VertexID(1), accPath.data).valueOr:
|
|
if error == FetchPathNotFound:
|
|
db.accLeaves.put(accPath, nil)
|
|
return err(error)
|
|
|
|
db.accLeaves.put(accPath, leafVtx)
|
|
|
|
ok leafVtx
|
|
|
|
proc retrieveMerkleHash(
|
|
db: AristoDbRef;
|
|
root: VertexID;
|
|
updateOk: bool;
|
|
): Result[Hash32,AristoError] =
|
|
let key =
|
|
if updateOk:
|
|
db.computeKey((root, root)).valueOr:
|
|
if error == GetVtxNotFound:
|
|
return ok(EMPTY_ROOT_HASH)
|
|
return err(error)
|
|
else:
|
|
let (key, _) = db.getKeyRc((root, root)).valueOr:
|
|
if error == GetKeyNotFound:
|
|
return ok(EMPTY_ROOT_HASH) # empty sub-tree
|
|
return err(error)
|
|
key
|
|
ok key.to(Hash32)
|
|
|
|
|
|
proc hasPayload(
|
|
db: AristoDbRef;
|
|
root: VertexID;
|
|
path: openArray[byte];
|
|
): Result[bool,AristoError] =
|
|
let error = db.retrieveLeaf(root, path).errorOr:
|
|
return ok(true)
|
|
|
|
if error == FetchPathNotFound:
|
|
return ok(false)
|
|
err(error)
|
|
|
|
proc hasAccountPayload(
|
|
db: AristoDbRef;
|
|
accPath: Hash32;
|
|
): Result[bool,AristoError] =
|
|
let error = db.retrieveAccountLeaf(accPath).errorOr:
|
|
return ok(true)
|
|
|
|
if error == FetchPathNotFound:
|
|
return ok(false)
|
|
err(error)
|
|
|
|
proc fetchStorageIdImpl(
|
|
db: AristoDbRef;
|
|
accPath: Hash32;
|
|
enaStoRootMissing = false;
|
|
): Result[VertexID,AristoError] =
|
|
## Helper function for retrieving a storage (vertex) ID for a given account.
|
|
let
|
|
leafVtx = ?db.retrieveAccountLeaf(accPath)
|
|
stoID = leafVtx[].lData.stoID
|
|
|
|
if stoID.isValid:
|
|
ok stoID.vid
|
|
elif enaStoRootMissing:
|
|
err(FetchPathStoRootMissing)
|
|
else:
|
|
err(FetchPathNotFound)
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# Public helpers
|
|
# ------------------------------------------------------------------------------
|
|
|
|
proc fetchAccountHike*(
|
|
db: AristoDbRef; # Database
|
|
accPath: Hash32; # Implies a storage ID (if any)
|
|
accHike: var Hike
|
|
): Result[void,AristoError] =
|
|
## Expand account path to account leaf or return failure
|
|
|
|
# Prefer the leaf cache so as not to burden the lower layers
|
|
let leaf = db.cachedAccLeaf(accPath)
|
|
if leaf == Opt.some(VertexRef(nil)):
|
|
return err(FetchAccInaccessible)
|
|
|
|
accPath.hikeUp(VertexID(1), db, leaf, accHike).isOkOr:
|
|
return err(FetchAccInaccessible)
|
|
|
|
# Extract the account payload from the leaf
|
|
if accHike.legs.len == 0 or accHike.legs[^1].wp.vtx.vType != Leaf:
|
|
return err(FetchAccPathWithoutLeaf)
|
|
|
|
assert accHike.legs[^1].wp.vtx.lData.pType == AccountData
|
|
|
|
ok()
|
|
|
|
proc fetchStorageID*(
|
|
db: AristoDbRef;
|
|
accPath: Hash32;
|
|
): Result[VertexID,AristoError] =
|
|
## Public helper function for retrieving a storage (vertex) ID for a given account. This
|
|
## function returns a separate error `FetchPathStoRootMissing` (from `FetchPathNotFound`)
|
|
## if the account for the argument path `accPath` exists but has no storage root.
|
|
##
|
|
db.fetchStorageIdImpl(accPath, enaStoRootMissing=true)
|
|
|
|
proc retrieveStoragePayload(
|
|
db: AristoDbRef;
|
|
accPath: Hash32;
|
|
stoPath: Hash32;
|
|
): Result[UInt256,AristoError] =
|
|
let mixPath = mixUp(accPath, stoPath)
|
|
|
|
if (let leafVtx = db.cachedStoLeaf(mixPath); leafVtx.isSome()):
|
|
if not leafVtx[].isValid():
|
|
return err(FetchPathNotFound)
|
|
return ok leafVtx[].lData.stoData
|
|
|
|
# Updated payloads are stored in the layers so if we didn't find them there,
|
|
# it must have been in the database
|
|
let leafVtx = db.retrieveLeaf(? db.fetchStorageIdImpl(accPath), stoPath.data).valueOr:
|
|
if error == FetchPathNotFound:
|
|
db.stoLeaves.put(mixPath, nil)
|
|
return err(error)
|
|
|
|
db.stoLeaves.put(mixPath, leafVtx)
|
|
|
|
ok leafVtx.lData.stoData
|
|
|
|
proc hasStoragePayload(
|
|
db: AristoDbRef;
|
|
accPath: Hash32;
|
|
stoPath: Hash32;
|
|
): Result[bool,AristoError] =
|
|
let error = db.retrieveStoragePayload(accPath, stoPath).errorOr:
|
|
return ok(true)
|
|
|
|
if error == FetchPathNotFound:
|
|
return ok(false)
|
|
err(error)
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# Public functions
|
|
# ------------------------------------------------------------------------------
|
|
|
|
proc fetchLastSavedState*(
|
|
db: AristoDbRef;
|
|
): Result[SavedState,AristoError] =
|
|
## Wrapper around `getLstUbe()`. The function returns the state of the last
|
|
## saved state. This is a Merkle hash tag for vertex with ID 1 and a bespoke
|
|
## `uint64` identifier (may be interpreted as block number.)
|
|
db.getLstUbe()
|
|
|
|
proc fetchAccountRecord*(
|
|
db: AristoDbRef;
|
|
accPath: Hash32;
|
|
): Result[AristoAccount,AristoError] =
|
|
## Fetch an account record from the database indexed by `accPath`.
|
|
##
|
|
let leafVtx = ? db.retrieveAccountLeaf(accPath)
|
|
assert leafVtx.lData.pType == AccountData # debugging only
|
|
|
|
ok leafVtx.lData.account
|
|
|
|
proc fetchAccountStateRoot*(
|
|
db: AristoDbRef;
|
|
updateOk: bool;
|
|
): Result[Hash32,AristoError] =
|
|
## Fetch the Merkle hash of the account root.
|
|
db.retrieveMerkleHash(VertexID(1), updateOk)
|
|
|
|
proc hasPathAccount*(
|
|
db: AristoDbRef;
|
|
accPath: Hash32;
|
|
): Result[bool,AristoError] =
|
|
## For an account record indexed by `accPath` query whether this record exists
|
|
## on the database.
|
|
##
|
|
db.hasAccountPayload(accPath)
|
|
|
|
proc fetchStorageData*(
|
|
db: AristoDbRef;
|
|
accPath: Hash32;
|
|
stoPath: Hash32;
|
|
): Result[UInt256,AristoError] =
|
|
## For a storage tree related to account `accPath`, fetch the data record
|
|
## from the database indexed by `path`.
|
|
##
|
|
db.retrieveStoragePayload(accPath, stoPath)
|
|
|
|
proc fetchStorageRoot*(
|
|
db: AristoDbRef;
|
|
accPath: Hash32;
|
|
updateOk: bool;
|
|
): Result[Hash32,AristoError] =
|
|
## Fetch the Merkle hash of the storage root related to `accPath`.
|
|
let stoID = db.fetchStorageIdImpl(accPath).valueOr:
|
|
if error == FetchPathNotFound:
|
|
return ok(EMPTY_ROOT_HASH) # no sub-tree
|
|
return err(error)
|
|
db.retrieveMerkleHash(stoID, updateOk)
|
|
|
|
proc hasPathStorage*(
|
|
db: AristoDbRef;
|
|
accPath: Hash32;
|
|
stoPath: Hash32;
|
|
): Result[bool,AristoError] =
|
|
## For a storage tree related to account `accPath`, query whether the data
|
|
## record indexed by `path` exists on the database.
|
|
##
|
|
db.hasStoragePayload(accPath, stoPath)
|
|
|
|
proc hasStorageData*(
|
|
db: AristoDbRef;
|
|
accPath: Hash32;
|
|
): Result[bool,AristoError] =
|
|
## For a storage tree related to account `accPath`, query whether there
|
|
## is a non-empty data storage area at all.
|
|
##
|
|
let stoID = db.fetchStorageIdImpl(accPath).valueOr:
|
|
if error == FetchPathNotFound:
|
|
return ok(false) # no sub-tree
|
|
return err(error)
|
|
ok stoID.isValid
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# End
|
|
# ------------------------------------------------------------------------------
|