114 lines
3.8 KiB
Nim
114 lines
3.8 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))
|
|
|
|
for (rvid,key) in T.walkKeyBe db:
|
|
if topVidBe.vid < rvid.vid:
|
|
topVidBe = rvid
|
|
let _ = 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, 0)
|
|
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
|
|
# ------------------------------------------------------------------------------
|