Skip to content

Commit

Permalink
Cleanup db/core_apps error handling (#2838)
Browse files Browse the repository at this point in the history
* Cleanup db/core_apps error handling

* Fix persistHeader

* Fix getUncles
  • Loading branch information
jangko authored Nov 7, 2024
1 parent eaf98dc commit 6b86acf
Show file tree
Hide file tree
Showing 35 changed files with 549 additions and 816 deletions.
2 changes: 1 addition & 1 deletion hive_integration/nodocker/consensus/consensus_sim.nim
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ proc processChainData(cd: ChainData): TestStatus =
# bad blocks
discard importRlpBlocks(bytes, c, finalize = true)

let head = com.db.getCanonicalHead()
let head = com.db.getCanonicalHead().expect("canonical head exists")
let blockHash = "0x" & head.blockHash.data.toHex
if blockHash == cd.lastBlockHash:
TestStatus.OK
Expand Down
2 changes: 1 addition & 1 deletion hive_integration/nodocker/engine/engine_env.nim
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ proc newEngineEnv*(conf: var NimbusConf, chainFile: string, enableAuth: bool): E
let
node = setupEthNode(conf, ctx)
com = makeCom(conf)
head = com.db.getCanonicalHead()
head = com.db.getCanonicalHead().expect("canonical head exists")
chain = newForkedChain(com, head)

let txPool = TxPoolRef.new(com)
Expand Down
20 changes: 8 additions & 12 deletions hive_integration/nodocker/engine/node.nim
Original file line number Diff line number Diff line change
Expand Up @@ -102,18 +102,14 @@ proc setBlock*(c: ChainRef; blk: Block): Result[void, string] =
_ = vmState.parent.stateRoot # Check point
? vmState.processBlock(blk)

if not c.db.persistHeader(
header, c.com.proofOfStake(header), c.com.startOfHistory):
return err("Could not persist header")

try:
c.db.persistTransactions(header.number, header.txRoot, blk.transactions)
c.db.persistReceipts(header.receiptsRoot, vmState.receipts)

if blk.withdrawals.isSome:
c.db.persistWithdrawals(header.withdrawalsRoot.get, blk.withdrawals.get)
except CatchableError as exc:
return err(exc.msg)
? c.db.persistHeader(
header, c.com.proofOfStake(header), c.com.startOfHistory)

c.db.persistTransactions(header.number, header.txRoot, blk.transactions)
c.db.persistReceipts(header.receiptsRoot, vmState.receipts)

if blk.withdrawals.isSome:
c.db.persistWithdrawals(header.withdrawalsRoot.get, blk.withdrawals.get)

# update currentBlock *after* we persist it
# so the rpc return consistent result
Expand Down
8 changes: 4 additions & 4 deletions hive_integration/nodocker/pyspec/test_env.nim
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,10 @@ proc setupELClient*(conf: ChainConfig, node: JsonNode): TestEnv =
stateDB.persist()
doAssert stateDB.getStateRoot == genesisHeader.stateRoot

doAssert com.db.persistHeader(genesisHeader,
com.proofOfStake(genesisHeader))
doAssert(com.db.getCanonicalHead().blockHash ==
genesisHeader.blockHash)
com.db.persistHeader(genesisHeader,
com.proofOfStake(genesisHeader)).expect("persistHeader no error")
let head = com.db.getCanonicalHead().expect("canonical head exists")
doAssert(head.blockHash == genesisHeader.blockHash)

let
txPool = TxPoolRef.new(com)
Expand Down
2 changes: 1 addition & 1 deletion hive_integration/nodocker/rpc/test_env.nim
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ proc setupEnv*(): TestEnv =

manageAccounts(ethCtx, conf)

let head = com.db.getCanonicalHead()
let head = com.db.getCanonicalHead().expect("canonical head exists")
let chainRef = newForkedChain(com, head)
let txPool = TxPoolRef.new(com)

Expand Down
15 changes: 6 additions & 9 deletions nimbus/beacon/api_handler/api_exchangeconf.nim
Original file line number Diff line number Diff line change
Expand Up @@ -43,20 +43,17 @@ proc exchangeConf*(ben: BeaconEngineRef,
terminalBlockHash = conf.terminalBlockHash

if terminalBlockHash != default(Hash32):
var headerHash: Hash32

if not db.getBlockHash(terminalBlockNumber, headerHash):
raise newException(ValueError, "cannot get terminal block hash, number $1" %
[$terminalBlockNumber])
let headerHash = db.getBlockHash(terminalBlockNumber).valueOr:
raise newException(ValueError, "cannot get terminal block hash, number $1, msg: $2" %
[$terminalBlockNumber, error])

if terminalBlockHash != headerHash:
raise newException(ValueError, "invalid terminal block hash, got $1 want $2" %
[$terminalBlockHash, $headerHash])

var header: Header
if not db.getBlockHeader(headerHash, header):
raise newException(ValueError, "cannot get terminal block header, hash $1" %
[$terminalBlockHash])
let header = db.getBlockHeader(headerHash).valueOr:
raise newException(ValueError, "cannot get terminal block header, hash $1, msg: $2" %
[$terminalBlockHash, error])

return TransitionConfigurationV1(
terminalTotalDifficulty: ttd.get,
Expand Down
11 changes: 6 additions & 5 deletions nimbus/beacon/api_handler/api_forkchoice.nim
Original file line number Diff line number Diff line change
Expand Up @@ -124,11 +124,12 @@ proc forkchoiceUpdated*(ben: BeaconEngineRef,
if apiVersion == Version.V1:
let blockNumber = header.number
if header.difficulty > 0.u256 or blockNumber == 0'u64:
var
td, ptd: DifficultyInt
let
td = db.getScore(blockHash)
ptd = db.getScore(header.parentHash)
ttd = com.ttd.get(high(UInt256))

if not db.getTd(blockHash, td) or (blockNumber > 0'u64 and not db.getTd(header.parentHash, ptd)):
if td.isNone or (blockNumber > 0'u64 and ptd.isNone):
error "TDs unavailable for TTD check",
number = blockNumber,
hash = blockHash.short,
Expand All @@ -137,12 +138,12 @@ proc forkchoiceUpdated*(ben: BeaconEngineRef,
ptd = ptd
return simpleFCU(PayloadExecutionStatus.invalid, "TDs unavailable for TTD check")

if td < ttd or (blockNumber > 0'u64 and ptd > ttd):
if td.get < ttd or (blockNumber > 0'u64 and ptd.get > ttd):
notice "Refusing beacon update to pre-merge",
number = blockNumber,
hash = blockHash.short,
diff = header.difficulty,
ptd = ptd,
ptd = ptd.get,
ttd = ttd

return invalidFCU("Refusing beacon update to pre-merge")
Expand Down
6 changes: 2 additions & 4 deletions nimbus/beacon/api_handler/api_getbodies.nim
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,7 @@ proc getPayloadBodyByHeader(db: CoreDbRef,
header: Header,
output: var seq[Opt[ExecutionPayloadBodyV1]]) {.raises:[].} =

var body: BlockBody
if not db.getBlockBody(header, body):
let body = db.getBlockBody(header).valueOr:
output.add Opt.none(ExecutionPayloadBodyV1)
return

Expand Down Expand Up @@ -93,7 +92,6 @@ proc getPayloadBodiesByRange*(ben: BeaconEngineRef,

var
last = start+count-1
header: Header

if start > ben.chain.latestNumber:
# requested range beyond the latest known block
Expand All @@ -104,7 +102,7 @@ proc getPayloadBodiesByRange*(ben: BeaconEngineRef,

# get bodies from database
for bn in start..ben.chain.baseNumber:
if not db.getBlockHeader(bn, header):
let header = db.getBlockHeader(bn).valueOr:
result.add Opt.none(ExecutionPayloadBodyV1)
continue
db.getPayloadBodyByHeader(header, result)
Expand Down
16 changes: 6 additions & 10 deletions nimbus/beacon/api_handler/api_utils.nim
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@

import
std/[typetraits, strutils],
eth/rlp,
json_rpc/errors,
nimcrypto/sha2,
stew/endians2,
Expand Down Expand Up @@ -173,28 +172,25 @@ proc tooLargeRequest*(msg: string): ref InvalidRequest =
)

proc latestValidHash*(db: CoreDbRef,
parent: common.Header,
ttd: DifficultyInt): common.Hash32 =
parent: Header,
ttd: DifficultyInt): Hash32 =
if parent.isGenesis:
return default(common.Hash32)
return default(Hash32)
let ptd = db.getScore(parent.parentHash).valueOr(0.u256)
if ptd >= ttd:
parent.blockHash
else:
# If the most recent valid ancestor is a PoW block,
# latestValidHash MUST be set to ZERO
default(common.Hash32)
default(Hash32)

proc invalidFCU*(validationError: string,
com: CommonRef,
header: common.Header): ForkchoiceUpdatedResponse =
var parent: common.Header
if not com.db.getBlockHeader(header.parentHash, parent):
let parent = com.db.getBlockHeader(header.parentHash).valueOr:
return invalidFCU(validationError)

let blockHash = try:
let blockHash =
latestValidHash(com.db, parent, com.ttd.get(high(UInt256)))
except RlpError:
default(common.Hash32)

invalidFCU(validationError, blockHash)
16 changes: 8 additions & 8 deletions nimbus/beacon/beacon_engine.nim
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,13 @@ func setInvalidAncestor*(ben: BeaconEngineRef, header: Header, blockHash: Hash32
# bad ancestor. If yes, it constructs the payload failure response to return.
proc checkInvalidAncestor*(ben: BeaconEngineRef,
check, head: Hash32): Opt[PayloadStatusV1] =
proc latestValidHash(db: CoreDbRef, invalid: auto): Hash32 =
let parent = db.getBlockHeader(invalid.parentHash).valueOr:
return invalid.parentHash
if parent.difficulty != 0.u256:
return default(Hash32)
invalid.parentHash

# If the hash to check is unknown, return valid
ben.invalidTipsets.withValue(check, invalid) do:
# If the bad hash was hit too many times, evict it and try to reprocess in
Expand Down Expand Up @@ -236,16 +243,9 @@ proc checkInvalidAncestor*(ben: BeaconEngineRef,

ben.invalidTipsets[head] = invalid[]

var lastValid = invalid.parentHash

# If the last valid hash is the terminal pow block, return 0x0 for latest valid hash
var header: Header
if ben.com.db.getBlockHeader(invalid.parentHash, header):
if header.difficulty != 0.u256:
lastValid = default(Hash32)

let lastValid = latestValidHash(ben.com.db, invalid)
return Opt.some invalidStatus(lastValid, "links to previously rejected block")

do:
return Opt.none(PayloadStatusV1)

Expand Down
41 changes: 16 additions & 25 deletions nimbus/common/common.nim
Original file line number Diff line number Diff line change
Expand Up @@ -137,36 +137,27 @@ proc initializeDb(com: CommonRef) =
nonce = com.genesisHeader.nonce
doAssert(com.genesisHeader.number == 0.BlockNumber,
"can't commit genesis block with number > 0")
doAssert(com.db.persistHeader(com.genesisHeader,
com.db.persistHeader(com.genesisHeader,
com.proofOfStake(com.genesisHeader),
startOfHistory=com.genesisHeader.parentHash),
"can persist genesis header")
startOfHistory=com.genesisHeader.parentHash).
expect("can persist genesis header")
doAssert(canonicalHeadHashKey().toOpenArray in kvt)

# The database must at least contain the base and head pointers - the base
# is implicitly considered finalized
let
baseNum = com.db.getSavedStateBlockNumber()
base =
try:
com.db.getBlockHeader(baseNum)
except BlockNotFound as exc:
fatal "Cannot load base block header",
baseNum, err = exc.msg
quit 1
finalized =
try:
com.db.finalizedHeader()
except BlockNotFound:
debug "No finalized block stored in database, reverting to base"
base
head =
try:
com.db.getCanonicalHead()
except EVMError as exc:
fatal "Cannot load canonical block header",
err = exc.msg
quit 1
base = com.db.getBlockHeader(baseNum).valueOr:
fatal "Cannot load base block header",
baseNum, err = error
quit 1
finalized = com.db.finalizedHeader().valueOr:
debug "No finalized block stored in database, reverting to base"
base
head = com.db.getCanonicalHead().valueOr:
fatal "Cannot load canonical block header",
err = error
quit 1

info "Database initialized",
base = (base.blockHash, base.number),
Expand Down Expand Up @@ -204,8 +195,8 @@ proc init(com : CommonRef,
fork = toHardFork(com.forkTransitionTable, forkDeterminer)

# Must not overwrite the global state on the single state DB
if not db.getBlockHeader(0.BlockNumber, com.genesisHeader):
com.genesisHeader = toGenesisHeader(genesis, fork, com.db)
com.genesisHeader = db.getBlockHeader(0.BlockNumber).valueOr:
toGenesisHeader(genesis, fork, com.db)

com.setForkId(com.genesisHeader)
com.pos.timestamp = genesis.timestamp
Expand Down
5 changes: 2 additions & 3 deletions nimbus/core/block_import.nim
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,8 @@ proc importRlpBlocks*(importFile: string,
importRlpBlocks(bytes, chain, finalize)

proc importRlpBlocks*(conf: NimbusConf, com: CommonRef) =
var head: Header
if not com.db.getCanonicalHead(head):
error "cannot get canonical head from db"
let head = com.db.getCanonicalHead().valueOr:
error "cannot get canonical head from db", msg=error
quit(QuitFailure)

let chain = newForkedChain(com, head, baseDistance = 0)
Expand Down
20 changes: 8 additions & 12 deletions nimbus/core/chain/chain_desc.nim
Original file line number Diff line number Diff line change
Expand Up @@ -55,16 +55,13 @@ func newChain*(com: CommonRef,
proc newChain*(com: CommonRef): ChainRef =
## Constructor for the `Chain` descriptor object. All sub-object descriptors
## are initialised with defaults. So is extra block chain validation
try:
let header = com.db.getCanonicalHead()
let extraValidation = com.proofOfStake(header)
return ChainRef(
com: com,
extraValidation: extraValidation,
)
except CatchableError:
doAssert(false, "no canonical head")

let header = com.db.getCanonicalHead().expect("canonical head exists")
let extraValidation = com.proofOfStake(header)
return ChainRef(
com: com,
extraValidation: extraValidation,
)

# ------------------------------------------------------------------------------
# Public `Chain` getters
# ------------------------------------------------------------------------------
Expand All @@ -88,8 +85,7 @@ func verifyFrom*(c: ChainRef): BlockNumber =
## Getter
c.verifyFrom

proc currentBlock*(c: ChainRef): Header
{.gcsafe, raises: [CatchableError].} =
proc currentBlock*(c: ChainRef): Result[Header, string] =
## currentBlock retrieves the current head block of the canonical chain.
## Ideally the block should be retrieved from the blockchain's internal cache.
## but now it's enough to retrieve it from database
Expand Down
Loading

0 comments on commit 6b86acf

Please sign in to comment.