nimbus-eth1/nimbus/db/aristo/aristo_check/check_be.nim

117 lines
3.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.
{.push raises: [].}
import
std/[sets, tables],
eth/common,
results,
stew/interval_set,
../../aristo,
../aristo_walk/persistent,
".."/[aristo_desc, aristo_get, aristo_layers]
# ------------------------------------------------------------------------------
# Public functions
# ------------------------------------------------------------------------------
proc checkBE*[T: RdbBackendRef|MemBackendRef|VoidBackendRef](
_: type T;
db: AristoDbRef; # Database, top layer
): Result[void,(VertexID,AristoError)] =
## Make sure that each vertex has a Merkle hash and vice versa. Also check
## the vertex ID generator state.
var topVidBe: RootedVertexID = (VertexID(0), VertexID(0))
for (rvid,vtx) in T.walkVtxBe db:
if topVidBe.vid < rvid.vid:
topVidBe = rvid
if not vtx.isValid:
return err((rvid.vid,CheckBeVtxInvalid))
case vtx.vType:
of Leaf:
discard
of Branch:
block check42Links:
var seen = false
for n in 0 .. 15:
if vtx.bVid[n].isValid:
if seen:
break check42Links
seen = true
return err((rvid.vid,CheckBeVtxBranchLinksMissing))
of Extension:
if vtx.ePfx.len == 0:
return err((rvid.vid,CheckBeVtxExtPfxMissing))
for (rvid,key) in T.walkKeyBe db:
if topVidBe.vid < rvid.vid:
topVidBe = rvid
let vtx = db.getVtxBE(rvid).valueOr:
return err((rvid.vid,CheckBeVtxMissing))
# Compare calculated `vTop` against database state
# TODO
# if topVidBe.isValid:
# let vidTuvBe = block:
# let rc = db.getTuvBE()
# if rc.isOk:
# rc.value
# elif rc.error == GetTuvNotFound:
# VertexID(0)
# else:
# return err((VertexID(0),rc.error))
# if vidTuvBe != topVidBe:
# # All vertices and keys between `topVidBe` and `vidTuvBe` must have
# # been deleted.
# for vid in max(topVidBe + 1, VertexID(LEAST_FREE_VID)) .. vidTuvBe:
# if db.getVtxBE(vid).isOk or db.getKeyBE(vid).isOk:
# return err((vid,CheckBeGarbledVTop))
# Check layer cache against backend
block:
var topVidCache: RootedVertexID = (VertexID(0), VertexID(0))
# Check structural table
for (rvid,vtx) in db.layersWalkVtx:
if vtx.isValid and topVidCache.vid < rvid.vid:
topVidCache = rvid
let key = db.layersGetKey(rvid).valueOr: VOID_HASH_KEY
if not vtx.isValid:
# Some vertex is to be deleted, the key must be empty
if key.isValid:
return err((rvid.vid,CheckBeCacheKeyNonEmpty))
# Check key table
var list: seq[RootedVertexID]
for (rvid,key) in db.layersWalkKey:
if key.isValid and topVidCache.vid < rvid.vid:
topVidCache = rvid
list.add rvid
let vtx = db.getVtx rvid
if db.layersGetVtx(rvid).isErr and not vtx.isValid:
return err((rvid.vid,CheckBeCacheKeyDangling))
# Check vTop
# TODO
# if topVidCache.isValid and topVidCache != db.vTop:
# # All vertices and keys between `topVidCache` and `db.vTop` must have
# # been deleted.
# for vid in max(db.vTop + 1, VertexID(LEAST_FREE_VID)) .. topVidCache:
# if db.layersGetVtxOrVoid(vid).isValid or
# db.layersGetKeyOrVoid(vid).isValid:
# return err((db.vTop,CheckBeCacheGarbledVTop))
ok()
# ------------------------------------------------------------------------------
# End
# ------------------------------------------------------------------------------