183 lines
5.6 KiB
Nim
183 lines
5.6 KiB
Nim
# Nimbus
|
|
# Copyright (c) 2023-2024 Status Research & Development GmbH
|
|
# Licensed and distributed under either of
|
|
# * MIT license (license terms in the root directory or at
|
|
# https://opensource.org/licenses/MIT).
|
|
# * Apache v2 license (license terms in the root directory or at
|
|
# https://www.apache.org/licenses/LICENSE-2.0).
|
|
# at your option. This file may not be copied, modified, or distributed
|
|
# except according to those terms.
|
|
|
|
{.push raises:[].}
|
|
|
|
import
|
|
pkg/[chronicles, chronos],
|
|
pkg/eth/[common, rlp],
|
|
pkg/stew/[byteutils, interval_set, sorted_set],
|
|
pkg/results,
|
|
../../../db/storage_types,
|
|
../../../common,
|
|
../worker_desc,
|
|
./headers_unproc
|
|
|
|
logScope:
|
|
topics = "beacon db"
|
|
|
|
const
|
|
LhcStateKey = 1.beaconStateKey
|
|
|
|
type
|
|
SavedDbStateSpecs = tuple
|
|
number: BlockNumber
|
|
hash: Hash32
|
|
parent: Hash32
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# Private debugging & logging helpers
|
|
# ------------------------------------------------------------------------------
|
|
|
|
formatIt(Hash32):
|
|
it.data.toHex
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# Private helpers
|
|
# ------------------------------------------------------------------------------
|
|
|
|
proc fetchLinkedHChainsLayout(ctx: BeaconCtxRef): Opt[LinkedHChainsLayout] =
|
|
let data = ctx.db.ctx.getKvt().get(LhcStateKey.toOpenArray).valueOr:
|
|
return err()
|
|
try:
|
|
result = ok(rlp.decode(data, LinkedHChainsLayout))
|
|
except RlpError:
|
|
return err()
|
|
|
|
|
|
proc fetchSavedState(ctx: BeaconCtxRef): Opt[SavedDbStateSpecs] =
|
|
let db = ctx.db
|
|
var val: SavedDbStateSpecs
|
|
val.number = db.getSavedStateBlockNumber()
|
|
|
|
if db.getBlockHash(val.number, val.hash):
|
|
var header: Header
|
|
if db.getBlockHeader(val.hash, header):
|
|
val.parent = header.parentHash
|
|
return ok(val)
|
|
|
|
err()
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# Public functions
|
|
# ------------------------------------------------------------------------------
|
|
|
|
proc dbStoreLinkedHChainsLayout*(ctx: BeaconCtxRef): bool =
|
|
## Save chain layout to persistent db
|
|
const info = "dbStoreLinkedHChainsLayout"
|
|
if ctx.layout == ctx.lhc.lastLayout:
|
|
return false
|
|
|
|
let data = rlp.encode(ctx.layout)
|
|
ctx.db.ctx.getKvt().put(LhcStateKey.toOpenArray, data).isOkOr:
|
|
raiseAssert info & " put() failed: " & $$error
|
|
|
|
# While executing blocks there are frequent save cycles. Otherwise, an
|
|
# extra save request might help to pick up an interrupted sync session.
|
|
let txLevel = ctx.db.level()
|
|
if txLevel == 0:
|
|
let number = ctx.db.getSavedStateBlockNumber()
|
|
ctx.db.persistent(number).isOkOr:
|
|
debug info & ": failed to save persistently", error=($$error)
|
|
return false
|
|
else:
|
|
trace info & ": not saved, tx pending", txLevel
|
|
return false
|
|
|
|
trace info & ": saved pesistently on DB"
|
|
true
|
|
|
|
|
|
proc dbLoadLinkedHChainsLayout*(ctx: BeaconCtxRef) =
|
|
## Restore chain layout from persistent db
|
|
const info = "dbLoadLinkedHChainsLayout"
|
|
|
|
let rc = ctx.fetchLinkedHChainsLayout()
|
|
if rc.isOk:
|
|
ctx.lhc.layout = rc.value
|
|
let (uMin,uMax) = (rc.value.coupler+1, rc.value.dangling-1)
|
|
if uMin <= uMax:
|
|
# Add interval of unprocessed block range `(C,D)` from `README.md`
|
|
ctx.headersUnprocSet(uMin, uMax)
|
|
trace info & ": restored layout", C=rc.value.coupler.bnStr,
|
|
D=rc.value.dangling.bnStr, E=rc.value.endBn.bnStr
|
|
else:
|
|
let val = ctx.fetchSavedState().expect "saved states"
|
|
ctx.lhc.layout = LinkedHChainsLayout(
|
|
coupler: val.number,
|
|
couplerHash: val.hash,
|
|
dangling: val.number,
|
|
danglingParent: val.parent,
|
|
endBn: val.number,
|
|
endHash: val.hash)
|
|
trace info & ": new layout", B=val.number, C=rc.value.coupler.bnStr,
|
|
D=rc.value.dangling.bnStr, E=rc.value.endBn.bnStr
|
|
|
|
ctx.lhc.lastLayout = ctx.layout
|
|
|
|
|
|
# ------------------
|
|
|
|
proc dbStashHeaders*(
|
|
ctx: BeaconCtxRef;
|
|
first: BlockNumber;
|
|
revBlobs: openArray[seq[byte]];
|
|
) =
|
|
## Temporarily store header chain to persistent db (oblivious of the chain
|
|
## layout.) The headers should not be stashed if they are imepreted and
|
|
## executed on the database, already.
|
|
##
|
|
## The `revBlobs[]` arguments are passed in reverse order so that block
|
|
## numbers apply as
|
|
## ::
|
|
## #first -- revBlobs[^1]
|
|
## #(first+1) -- revBlobs[^2]
|
|
## ..
|
|
##
|
|
const info = "dbStashHeaders"
|
|
let
|
|
kvt = ctx.db.ctx.getKvt()
|
|
last = first + revBlobs.len.uint64 - 1
|
|
for n,data in revBlobs:
|
|
let key = beaconHeaderKey(last - n.uint64)
|
|
kvt.put(key.toOpenArray, data).isOkOr:
|
|
raiseAssert info & ": put() failed: " & $$error
|
|
|
|
proc dbPeekHeader*(ctx: BeaconCtxRef; num: BlockNumber): Opt[Header] =
|
|
## Retrieve some stashed header.
|
|
let
|
|
key = beaconHeaderKey(num)
|
|
rc = ctx.db.ctx.getKvt().get(key.toOpenArray)
|
|
if rc.isOk:
|
|
try:
|
|
return ok(rlp.decode(rc.value, Header))
|
|
except RlpError:
|
|
discard
|
|
err()
|
|
|
|
proc dbPeekParentHash*(ctx: BeaconCtxRef; num: BlockNumber): Opt[Hash32] =
|
|
## Retrieve some stashed parent hash.
|
|
ok (? ctx.dbPeekHeader num).parentHash
|
|
|
|
proc dbUnstashHeader*(ctx: BeaconCtxRef; bn: BlockNumber) =
|
|
## Remove header from temporary DB list
|
|
discard ctx.db.ctx.getKvt().del(beaconHeaderKey(bn).toOpenArray)
|
|
|
|
# ------------------
|
|
|
|
proc dbStateBlockNumber*(ctx: BeaconCtxRef): BlockNumber =
|
|
## Currently only a wrapper around the function returning the current
|
|
## database state block number
|
|
ctx.db.getSavedStateBlockNumber()
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# End
|
|
# ------------------------------------------------------------------------------
|