use executionValid bit in BlockRef (#4956)

Update `beacon_node/rpc` usage for the new `executionValid` field.
This commit is contained in:
Etan Kissling 2023-05-25 15:57:24 +02:00 committed by GitHub
parent 10569ff2e9
commit 00728e9bb7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 58 additions and 79 deletions

View File

@ -1961,13 +1961,13 @@ proc pruneBlocksDAG(dag: ChainDAGRef) =
dagPruneDur = Moment.now() - startTick
# https://github.com/ethereum/consensus-specs/blob/v1.3.0/sync/optimistic.md#helpers
template is_optimistic*(dag: ChainDAGRef, root: Eth2Digest): bool =
let blck = dag.getBlockRef(root)
if blck.isSome:
not blck.get.executionValid
else:
# Either it doesn't exist at all, or it's finalized
not dag.finalizedHead.blck.executionValid
template is_optimistic*(dag: ChainDAGRef, bid: BlockId): bool =
let blck =
if bid.slot <= dag.finalizedHead.slot:
dag.finalizedHead.blck
else:
dag.getBlockRef(bid.root).expect("Non-finalized block is known")
not blck.executionValid
proc markBlockVerified*(dag: ChainDAGRef, blck: BlockRef) =
var cur = blck

View File

@ -246,7 +246,7 @@ proc initFullNode(
proc onBlockAdded(data: ForkedTrustedSignedBeaconBlock) =
let optimistic =
if node.currentSlot().epoch() >= dag.cfg.BELLATRIX_FORK_EPOCH:
some node.dag.is_optimistic(data.root)
some node.dag.is_optimistic(data.toBlockId())
else:
none[bool]()
node.eventBus.blocksQueue.emit(
@ -255,7 +255,8 @@ proc initFullNode(
let eventData =
if node.currentSlot().epoch() >= dag.cfg.BELLATRIX_FORK_EPOCH:
var res = data
res.optimistic = some node.dag.is_optimistic(data.block_root)
res.optimistic = some node.dag.is_optimistic(
BlockId(slot: data.slot, root: data.block_root))
res
else:
data
@ -264,7 +265,8 @@ proc initFullNode(
let eventData =
if node.currentSlot().epoch() >= dag.cfg.BELLATRIX_FORK_EPOCH:
var res = data
res.optimistic = some node.dag.is_optimistic(data.new_head_block)
res.optimistic = some node.dag.is_optimistic(
BlockId(slot: data.slot, root: data.new_head_block))
res
else:
data
@ -285,7 +287,10 @@ proc initFullNode(
let eventData =
if node.currentSlot().epoch() >= dag.cfg.BELLATRIX_FORK_EPOCH:
var res = data
res.optimistic = some node.dag.is_optimistic(data.block_root)
# `slot` in this `BlockId` may be higher than block's actual slot,
# this is alright for the purpose of calling `is_optimistic`.
res.optimistic = some node.dag.is_optimistic(
BlockId(slot: data.epoch.start_slot, root: data.block_root))
res
else:
data
@ -1186,7 +1191,7 @@ proc onSlotEnd(node: BeaconNode, slot: Slot) {.async.} =
# Update upcoming actions - we do this every slot in case a reorg happens
let head = node.dag.head
if node.isSynced(head) == SyncStatus.synced:
if node.isSynced(head) and head.executionValid:
withState(node.dag.headState):
if node.consensusManager[].actionTracker.needsUpdate(
forkyState, slot.epoch + 1):

View File

@ -114,7 +114,7 @@ proc installDebugApiHandlers*(router: var RestRouter, node: BeaconNode) =
validity:
if item.invalid:
RestNodeValidity.invalid
elif node.dag.is_optimistic(item.bid.root):
elif node.dag.is_optimistic(item.bid):
RestNodeValidity.optimistic
else:
RestNodeValidity.valid,

View File

@ -1,3 +1,4 @@
# beacon_chain
# Copyright (c) 2018-2023 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).
@ -238,9 +239,9 @@ proc installNimbusApiHandlers*(router: var RestRouter, node: BeaconNode) =
return RestApiResponse.jsonError(Http503, BeaconNodeInSyncError,
$res.error())
let tres = res.get()
if tres.optimistic:
if not tres.executionValid:
return RestApiResponse.jsonError(Http503, BeaconNodeInSyncError)
tres.head
tres
let proposalState = assignClone(node.dag.headState)
node.dag.withUpdatedState(
proposalState[],

View File

@ -33,23 +33,17 @@ func match(data: openArray[char], charset: set[char]): int =
proc getSyncedHead*(
node: BeaconNode,
slot: Slot
): Result[tuple[head: BlockRef, optimistic: bool], cstring] =
let
head = node.dag.head
optimistic =
case node.isSynced(head)
of SyncStatus.unsynced:
return err("Beacon node not fully and non-optimistically synced")
of SyncStatus.synced:
false
of SyncStatus.optimistic:
true
): Result[BlockRef, cstring] =
let head = node.dag.head
if not node.isSynced(head):
return err("Beacon node not fully and non-optimistically synced")
# Enough ahead not to know the shuffling
if slot > head.slot + SLOTS_PER_EPOCH * 2:
return err("Requesting far ahead of the current head")
ok((head, optimistic))
ok(head)
func getCurrentSlot*(node: BeaconNode, slot: Slot):
Result[Slot, cstring] =
@ -61,7 +55,7 @@ func getCurrentSlot*(node: BeaconNode, slot: Slot):
proc getSyncedHead*(
node: BeaconNode,
epoch: Epoch,
): Result[tuple[head: BlockRef, optimistic: bool], cstring] =
): Result[BlockRef, cstring] =
if epoch > MaxEpoch:
return err("Requesting epoch for which slot would overflow")
node.getSyncedHead(epoch.start_slot())
@ -276,30 +270,22 @@ proc getShufflingOptimistic*(node: BeaconNode,
dependentSlot: Slot,
dependentRoot: Eth2Digest): Option[bool] =
if node.currentSlot().epoch() >= node.dag.cfg.BELLATRIX_FORK_EPOCH:
if dependentSlot <= node.dag.finalizedHead.slot:
some[bool](false)
else:
some[bool](node.dag.is_optimistic(dependentRoot))
# `slot` in this `BlockId` may be higher than block's actual slot,
# this is alright for the purpose of calling `is_optimistic`.
let bid = BlockId(slot: dependentSlot, root: dependentRoot)
some[bool](node.dag.is_optimistic(bid))
else:
none[bool]()
proc getStateOptimistic*(node: BeaconNode,
state: ForkedHashedBeaconState): Option[bool] =
if node.currentSlot().epoch() >= node.dag.cfg.BELLATRIX_FORK_EPOCH:
case state.kind
of ConsensusFork.Phase0, ConsensusFork.Altair:
some[bool](false)
of ConsensusFork.Bellatrix, ConsensusFork.Capella,
ConsensusFork.Deneb:
if state.kind >= ConsensusFork.Bellatrix:
# A state is optimistic iff the block which created it is
withState(state):
# The block root which created the state at slot `n` is at slot `n-1`
if forkyState.data.slot == GENESIS_SLOT:
some[bool](false)
else:
doAssert forkyState.data.slot > 0
some[bool](node.dag.is_optimistic(
get_block_root_at_slot(forkyState.data, forkyState.data.slot - 1)))
let stateBid = withState(state): forkyState.latest_block_id
some[bool](node.dag.is_optimistic(stateBid))
else:
some[bool](false)
else:
none[bool]()
@ -307,11 +293,10 @@ proc getBlockOptimistic*(node: BeaconNode,
blck: ForkedTrustedSignedBeaconBlock |
ForkedSignedBeaconBlock): Option[bool] =
if node.currentSlot().epoch() >= node.dag.cfg.BELLATRIX_FORK_EPOCH:
case blck.kind
of ConsensusFork.Phase0, ConsensusFork.Altair:
if blck.kind >= ConsensusFork.Bellatrix:
some[bool](node.dag.is_optimistic(blck.toBlockId()))
else:
some[bool](false)
of ConsensusFork.Bellatrix, ConsensusFork.Capella, ConsensusFork.Deneb:
some[bool](node.dag.is_optimistic(blck.root))
else:
none[bool]()

View File

@ -65,7 +65,7 @@ proc installValidatorApiHandlers*(router: var RestRouter, node: BeaconNode) =
return RestApiResponse.jsonError(Http400, InvalidEpochValueError,
"Cannot request duties past next epoch")
res
let (qhead, _) =
let qhead =
block:
let res = node.getSyncedHead(qepoch)
if res.isErr():
@ -126,7 +126,7 @@ proc installValidatorApiHandlers*(router: var RestRouter, node: BeaconNode) =
return RestApiResponse.jsonError(Http400, InvalidEpochValueError,
"Cannot request duties past next epoch")
res
let (qhead, _) =
let qhead =
block:
let res = node.getSyncedHead(qepoch)
if res.isErr():
@ -278,7 +278,7 @@ proc installValidatorApiHandlers*(router: var RestRouter, node: BeaconNode) =
return RestApiResponse.jsonResponseWOpt(res, optimistic)
elif qSyncPeriod > headSyncPeriod:
# The requested epoch may still be too far in the future.
if node.isSynced(node.dag.head) != SyncStatus.synced:
if not node.isSynced(node.dag.head) or not node.dag.head.executionValid:
return RestApiResponse.jsonError(Http503, BeaconNodeInSyncError)
else:
return RestApiResponse.jsonError(Http400, EpochFromFutureError)
@ -378,9 +378,9 @@ proc installValidatorApiHandlers*(router: var RestRouter, node: BeaconNode) =
return RestApiResponse.jsonError(Http503, BeaconNodeInSyncError,
$res.error())
let tres = res.get()
if tres.optimistic:
if not tres.executionValid:
return RestApiResponse.jsonError(Http503, BeaconNodeInSyncError)
tres.head
tres
let
proposer = node.dag.getProposer(qhead, qslot).valueOr:
return RestApiResponse.jsonError(Http400, ProposerNotFoundError)
@ -488,9 +488,9 @@ proc installValidatorApiHandlers*(router: var RestRouter, node: BeaconNode) =
return RestApiResponse.jsonError(Http503, BeaconNodeInSyncError,
$res.error())
let tres = res.get()
if tres.optimistic:
if not tres.executionValid:
return RestApiResponse.jsonError(Http503, BeaconNodeInSyncError)
tres.head
tres
let proposer = node.dag.getProposer(qhead, qslot).valueOr:
return RestApiResponse.jsonError(Http400, ProposerNotFoundError)
@ -586,9 +586,9 @@ proc installValidatorApiHandlers*(router: var RestRouter, node: BeaconNode) =
return RestApiResponse.jsonError(Http503, BeaconNodeInSyncError,
$res.error())
let tres = res.get()
if tres.optimistic:
if not tres.executionValid:
return RestApiResponse.jsonError(Http503, BeaconNodeInSyncError)
tres.head
tres
let epochRef = node.dag.getEpochRef(qhead, qslot.epoch, true).valueOr:
return RestApiResponse.jsonError(Http400, PrunedStateError, $error)
makeAttestationData(epochRef, qhead.atSlot(qslot), qindex)
@ -677,7 +677,7 @@ proc installValidatorApiHandlers*(router: var RestRouter, node: BeaconNode) =
$dres.error())
dres.get()
if node.isSynced(node.dag.head) == SyncStatus.unsynced:
if not node.isSynced(node.dag.head):
return RestApiResponse.jsonError(Http503, BeaconNodeInSyncError)
let
@ -833,7 +833,7 @@ proc installValidatorApiHandlers*(router: var RestRouter, node: BeaconNode) =
return RestApiResponse.jsonError(Http503, BeaconNodeInSyncError,
$res.error())
let tres = res.get()
if tres.optimistic:
if not tres.executionValid:
return RestApiResponse.jsonError(Http503, BeaconNodeInSyncError)
var contribution = SyncCommitteeContribution()

View File

@ -90,11 +90,6 @@ type
BlindedBlockResult[SBBB] =
Result[tuple[blindedBlckPart: SBBB, blockValue: UInt256], string]
SyncStatus* {.pure.} = enum
synced
unsynced
optimistic
proc getValidator*(validators: auto,
pubkey: ValidatorPubKey): Opt[ValidatorAndIndex] =
let idx = validators.findIt(it.pubkey == pubkey)
@ -139,7 +134,7 @@ proc getValidatorForDuties*(
node.attachedValidators[].getValidatorForDuties(
key.toPubKey(), slot, slashingSafe)
proc isSynced*(node: BeaconNode, head: BlockRef): SyncStatus =
proc isSynced*(node: BeaconNode, head: BlockRef): bool =
## TODO This function is here as a placeholder for some better heurestics to
## determine if we're in sync and should be producing blocks and
## attestations. Generally, the problem is that slot time keeps advancing
@ -160,14 +155,8 @@ proc isSynced*(node: BeaconNode, head: BlockRef): SyncStatus =
# TODO if everyone follows this logic, the network will not recover from a
# halt: nobody will be producing blocks because everone expects someone
# else to do it
if wallSlot.afterGenesis and
head.slot + node.config.syncHorizon < wallSlot.slot:
SyncStatus.unsynced
else:
if not head.executionValid:
SyncStatus.optimistic
else:
SyncStatus.synced
not wallSlot.afterGenesis or
head.slot + node.config.syncHorizon >= wallSlot.slot
proc handleLightClientUpdates*(node: BeaconNode, slot: Slot) {.async.} =
static: doAssert lightClientFinalityUpdateSlotOffset ==
@ -1550,8 +1539,7 @@ proc handleValidatorDuties*(node: BeaconNode, lastSlot, slot: Slot) {.async.} =
# The dag head might be updated by sync while we're working due to the
# await calls, thus we use a local variable to keep the logic straight here
var head = node.dag.head
case node.isSynced(head)
of SyncStatus.unsynced:
if not node.isSynced(head):
info "Beacon node not in sync; skipping validator duties for now",
slot, headSlot = head.slot
@ -1560,7 +1548,7 @@ proc handleValidatorDuties*(node: BeaconNode, lastSlot, slot: Slot) {.async.} =
return
of SyncStatus.optimistic:
elif not head.executionValid:
info "Execution client not in sync; skipping validator duties for now",
slot, headSlot = head.slot
@ -1568,7 +1556,7 @@ proc handleValidatorDuties*(node: BeaconNode, lastSlot, slot: Slot) {.async.} =
updateValidatorMetrics(node)
return
of SyncStatus.synced:
else:
discard # keep going
withState(node.dag.headState):
@ -1681,7 +1669,7 @@ proc registerDuties*(node: BeaconNode, wallSlot: Slot) {.async.} =
## Register upcoming duties of attached validators with the duty tracker
if node.attachedValidators[].count() == 0 or
node.isSynced(node.dag.head) != SyncStatus.synced:
not node.isSynced(node.dag.head) or not node.dag.head.executionValid:
# Nothing to do because we have no validator attached
return