mirror of
https://github.com/status-im/nimbus-eth1.git
synced 2025-02-02 23:35:31 +00:00
0d2a72d2a9
* Cosmetics, small fixes, add stashed headers verifier * Remove direct `Era1` support why: Era1 is indirectly supported by using the import tool before syncing. * Clarify database persistent save function. why: Function relied on the last saved state block number which was wrong. It now relies on the tx-level. If it is 0, then data are saved directly. Otherwise the task that owns the tx will do it. * Extracted configuration constants into separate file * Enable single peer mode for debugging * Fix peer losing issue in multi-mode details: Running concurrent download peers was previously programmed as running a batch downloading and storing ~8k headers and then leaving the `async` function to be restarted by a scheduler. This was unfortunate because of occasionally occurring long waiting times for restart. While the time gap until restarting were typically observed a few millisecs, there were always a few outliers which well exceed several seconds. This seemed to let remote peers run into timeouts. * Prefix function names `unprocXxx()` and `stagedYyy()` by `headers` why: There will be other `unproc` and `staged` modules. * Remove cruft, update logging * Fix accounting issue details: When staging after fetching headers from the network, there was an off by 1 error occurring when the result was by one smaller than requested. Also, a whole range was mis-accounted when a peer was terminating connection immediately after responding. * Fix slow/error header accounting when fetching why: Originally set for detecting slow headers in a row, the counter was wrongly extended to general errors. * Ban peers for a while that respond with too few headers continuously why: Some peers only returned one header at a time. If these peers sit on a farm, they might collectively slow down the download process. * Update RPC beacon header updater why: Old function hook has slightly changed its meaning since it was used for snap sync. Also, the old hook is used by other functions already. * Limit number of peers or set to single peer mode details: Merge several concepts, single peer mode being one of it. * Some code clean up, fixings for removing of compiler warnings * De-noise header fetch related sources why: Header download looks relatively stable, so general debugging is not needed, anymore. This is the equivalent of removing the scaffold from the part of the building where work has completed. * More clean up and code prettification for headers stuff * Implement body fetch and block import details: Available headers are used stage blocks by combining existing headers with newly fetched blocks. Then these blocks are imported/executed via `persistBlocks()`. * Logger cosmetics and cleanup * Remove staged block queue debugging details: Feature still available, just not executed anymore * Docu, logging update * Update/simplify `runDaemon()` * Re-calibrate block body requests and soft config for import blocks batch why: * For fetching, larger fetch requests are mostly truncated anyway on MainNet. * For executing, smaller batch sizes reduce the memory needed for the price of longer execution times. * Update metrics counters * Docu update * Some fixes, formatting updates, etc. * Update `borrowed` type: uint -. uint64 also: Always convert to `uint64` rather than `uint` where appropriate
173 lines
5.3 KiB
Nim
173 lines
5.3 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/sorted_set,
|
|
../worker_desc,
|
|
./update/metrics,
|
|
"."/[blocks_unproc, db, headers_staged, headers_unproc]
|
|
|
|
logScope:
|
|
topics = "flare update"
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# Private functions
|
|
# ------------------------------------------------------------------------------
|
|
|
|
proc updateBeaconChange(ctx: FlareCtxRef): bool =
|
|
##
|
|
## Layout (see (3) in README):
|
|
## ::
|
|
## G B==L==F Z
|
|
## o----------------o---------------------o---->
|
|
## | <-- linked --> |
|
|
##
|
|
## or
|
|
## ::
|
|
## G==Z B==L==F
|
|
## o----------------o-------------------------->
|
|
## | <-- linked --> |
|
|
##
|
|
## with `Z == beacon.header.number` or `Z == 0`
|
|
##
|
|
## to be updated to
|
|
## ::
|
|
## G B==L L'==F'
|
|
## o----------------o---------------------o---->
|
|
## | <-- linked --> | <-- unprocessed --> |
|
|
##
|
|
const info = "updateBeaconChange"
|
|
|
|
var z = ctx.lhc.beacon.header.number
|
|
|
|
# Need: `F < Z` and `B == L`
|
|
if z != 0 and z <= ctx.layout.final: # violates `F < Z`
|
|
trace info & ": not applicable", Z=z.bnStr, F=ctx.layout.final.bnStr
|
|
return false
|
|
|
|
if ctx.layout.base != ctx.layout.least: # violates `B == L`
|
|
trace info & ": not applicable",
|
|
B=ctx.layout.base.bnStr, L=ctx.layout.least.bnStr
|
|
return false
|
|
|
|
# Check consistency: `B == L <= F` for maximal `B` => `L == F`
|
|
doAssert ctx.layout.least == ctx.layout.final
|
|
|
|
let rlpHeader = rlp.encode(ctx.lhc.beacon.header)
|
|
|
|
ctx.lhc.layout = LinkedHChainsLayout(
|
|
base: ctx.layout.base,
|
|
baseHash: ctx.layout.baseHash,
|
|
least: z,
|
|
leastParent: ctx.lhc.beacon.header.parentHash,
|
|
final: z,
|
|
finalHash: rlpHeader.keccakHash)
|
|
|
|
# Save this header on the database so it needs not be fetched again from
|
|
# somewhere else.
|
|
ctx.dbStashHeaders(z, @[rlpHeader])
|
|
|
|
# Save state
|
|
discard ctx.dbStoreLinkedHChainsLayout()
|
|
|
|
# Update range
|
|
doAssert ctx.headersUnprocTotal() == 0
|
|
doAssert ctx.headersUnprocBorrowed() == 0
|
|
doAssert ctx.headersStagedQueueIsEmpty()
|
|
ctx.headersUnprocSet(ctx.layout.base+1, ctx.layout.least-1)
|
|
|
|
trace info & ": updated"
|
|
true
|
|
|
|
|
|
proc mergeAdjacentChains(ctx: FlareCtxRef): bool =
|
|
const info = "mergeAdjacentChains"
|
|
|
|
if ctx.lhc.layout.base + 1 < ctx.lhc.layout.least or # gap betw `B` and `L`
|
|
ctx.lhc.layout.base == ctx.lhc.layout.least: # merged already
|
|
return false
|
|
|
|
# No overlap allowed!
|
|
doAssert ctx.lhc.layout.base + 1 == ctx.lhc.layout.least
|
|
|
|
# Verify adjacent chains
|
|
if ctx.lhc.layout.baseHash != ctx.lhc.layout.leastParent:
|
|
# FIXME: Oops -- any better idea than to defect?
|
|
raiseAssert info & ": hashes do not match" &
|
|
" B=" & ctx.lhc.layout.base.bnStr & " L=" & $ctx.lhc.layout.least.bnStr
|
|
|
|
trace info & ": merging", B=ctx.lhc.layout.base.bnStr,
|
|
L=ctx.lhc.layout.least.bnStr
|
|
|
|
# Merge adjacent linked chains
|
|
ctx.lhc.layout = LinkedHChainsLayout(
|
|
base: ctx.layout.final, # `B`
|
|
baseHash: ctx.layout.finalHash,
|
|
least: ctx.layout.final, # `L`
|
|
leastParent: ctx.dbPeekParentHash(ctx.layout.final).expect "Hash256",
|
|
final: ctx.layout.final, # `F`
|
|
finalHash: ctx.layout.finalHash)
|
|
|
|
# Save state
|
|
discard ctx.dbStoreLinkedHChainsLayout()
|
|
|
|
true
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# Public functions
|
|
# ------------------------------------------------------------------------------
|
|
|
|
proc updateLinkedHChainsLayout*(ctx: FlareCtxRef): bool =
|
|
## Update layout
|
|
|
|
# Check whether there is something to do regarding beacon node change
|
|
if ctx.lhc.beacon.changed:
|
|
ctx.lhc.beacon.changed = false
|
|
result = ctx.updateBeaconChange()
|
|
|
|
# Check whether header downloading is done
|
|
if ctx.mergeAdjacentChains():
|
|
result = true
|
|
|
|
|
|
proc updateBlockRequests*(ctx: FlareCtxRef): bool =
|
|
## Update block requests if there staged block queue is empty
|
|
const info = "updateBlockRequests"
|
|
|
|
let t = ctx.dbStateBlockNumber()
|
|
if t < ctx.layout.base: # so the half open interval `(T,B]` is not empty
|
|
|
|
# One can fill/import/execute blocks by number from `(T,B]`
|
|
if ctx.blk.topRequest < ctx.layout.base:
|
|
# So there is some space
|
|
trace info & ": extending", T=t.bnStr, topReq=ctx.blk.topRequest.bnStr,
|
|
B=ctx.layout.base.bnStr
|
|
|
|
ctx.blocksUnprocCommit(0, max(t,ctx.blk.topRequest) + 1, ctx.layout.base)
|
|
ctx.blk.topRequest = ctx.layout.base
|
|
return true
|
|
|
|
false
|
|
|
|
|
|
proc updateMetrics*(ctx: FlareCtxRef) =
|
|
let now = Moment.now()
|
|
if ctx.pool.nextUpdate < now:
|
|
ctx.updateMetricsImpl()
|
|
ctx.pool.nextUpdate = now + metricsUpdateInterval
|
|
|
|
# ------------------------------------------------------------------------------
|
|
# End
|
|
# ------------------------------------------------------------------------------
|