track slot as part of fork choice debug API (#4565)
Extends fork choice state to also track slot numbers to improve accuracy of `/eth/v1/debug/fork_choice` endpoint. Autoenable this API on devnet, and disable some extra checks on devnet to aid focused testing efforts. Align fork choice pruning logic with API based on checkpoints vs root.
This commit is contained in:
parent
58ed9308d2
commit
ea6a6b1acd
4
Makefile
4
Makefile
|
@ -261,8 +261,8 @@ local-testnet-mainnet:
|
||||||
|
|
||||||
# test binaries that can output an XML report
|
# test binaries that can output an XML report
|
||||||
XML_TEST_BINARIES_CORE := \
|
XML_TEST_BINARIES_CORE := \
|
||||||
consensus_spec_tests_mainnet \
|
consensus_spec_tests_minimal \
|
||||||
consensus_spec_tests_minimal
|
consensus_spec_tests_mainnet
|
||||||
|
|
||||||
XML_TEST_BINARIES := \
|
XML_TEST_BINARIES := \
|
||||||
$(XML_TEST_BINARIES_CORE) \
|
$(XML_TEST_BINARIES_CORE) \
|
||||||
|
|
|
@ -134,7 +134,7 @@ proc init*(T: type AttestationPool, dag: ChainDAGRef,
|
||||||
# and then to make sure the fork choice data structure doesn't grow
|
# and then to make sure the fork choice data structure doesn't grow
|
||||||
# too big - getting an EpochRef can be expensive.
|
# too big - getting an EpochRef can be expensive.
|
||||||
forkChoice.backend.process_block(
|
forkChoice.backend.process_block(
|
||||||
blckRef.root, blckRef.parent.root, epochRef.checkpoints)
|
blckRef.bid, blckRef.parent.root, epochRef.checkpoints)
|
||||||
else:
|
else:
|
||||||
epochRef = dag.getEpochRef(blckRef, blckRef.slot.epoch, false).expect(
|
epochRef = dag.getEpochRef(blckRef, blckRef.slot.epoch, false).expect(
|
||||||
"Getting an EpochRef should always work for non-finalized blocks")
|
"Getting an EpochRef should always work for non-finalized blocks")
|
||||||
|
|
|
@ -79,15 +79,18 @@ template withUpdatedState*(
|
||||||
else:
|
else:
|
||||||
failureBody
|
failureBody
|
||||||
|
|
||||||
func get_effective_balances(validators: openArray[Validator], epoch: Epoch):
|
func get_effective_balances(
|
||||||
seq[Gwei] =
|
validators: openArray[Validator],
|
||||||
|
epoch: Epoch,
|
||||||
|
ignoreSlashed: bool): seq[Gwei] =
|
||||||
## Get the balances from a state as counted for fork choice
|
## Get the balances from a state as counted for fork choice
|
||||||
result.newSeq(validators.len) # zero-init
|
result.newSeq(validators.len) # zero-init
|
||||||
|
|
||||||
for i in 0 ..< result.len:
|
for i in 0 ..< result.len:
|
||||||
# All non-active validators have a 0 balance
|
# All non-active validators have a 0 balance
|
||||||
let validator = unsafeAddr validators[i]
|
let validator = unsafeAddr validators[i]
|
||||||
if validator[].is_active_validator(epoch):
|
if validator[].is_active_validator(epoch) and (
|
||||||
|
ignoreSlashed or not validator[].slashed):
|
||||||
result[i] = validator[].effective_balance
|
result[i] = validator[].effective_balance
|
||||||
|
|
||||||
proc updateValidatorKeys*(dag: ChainDAGRef, validators: openArray[Validator]) =
|
proc updateValidatorKeys*(dag: ChainDAGRef, validators: openArray[Validator]) =
|
||||||
|
@ -569,7 +572,9 @@ func init*(
|
||||||
epochRef.effective_balances_bytes =
|
epochRef.effective_balances_bytes =
|
||||||
snappyEncode(SSZ.encode(
|
snappyEncode(SSZ.encode(
|
||||||
List[Gwei, Limit VALIDATOR_REGISTRY_LIMIT](
|
List[Gwei, Limit VALIDATOR_REGISTRY_LIMIT](
|
||||||
get_effective_balances(getStateField(state, validators).asSeq, epoch))))
|
get_effective_balances(
|
||||||
|
getStateField(state, validators).asSeq, epoch,
|
||||||
|
experimental notin dag.updateFlags))))
|
||||||
|
|
||||||
epochRef
|
epochRef
|
||||||
|
|
||||||
|
@ -898,7 +903,7 @@ proc init*(T: type ChainDAGRef, cfg: RuntimeConfig, db: BeaconChainDB,
|
||||||
cfg.checkForkConsistency()
|
cfg.checkForkConsistency()
|
||||||
|
|
||||||
doAssert updateFlags - {
|
doAssert updateFlags - {
|
||||||
strictVerification, enableTestFeatures, lowParticipation
|
strictVerification, experimental, enableTestFeatures, lowParticipation
|
||||||
} == {}, "Other flags not supported in ChainDAG"
|
} == {}, "Other flags not supported in ChainDAG"
|
||||||
|
|
||||||
# TODO we require that the db contains both a head and a tail block -
|
# TODO we require that the db contains both a head and a tail block -
|
||||||
|
@ -928,7 +933,7 @@ proc init*(T: type ChainDAGRef, cfg: RuntimeConfig, db: BeaconChainDB,
|
||||||
# The only allowed flag right now is strictVerification, as the others all
|
# The only allowed flag right now is strictVerification, as the others all
|
||||||
# allow skipping some validation.
|
# allow skipping some validation.
|
||||||
updateFlags: updateFlags * {
|
updateFlags: updateFlags * {
|
||||||
strictVerification, enableTestFeatures, lowParticipation
|
strictVerification, experimental, enableTestFeatures, lowParticipation
|
||||||
},
|
},
|
||||||
cfg: cfg,
|
cfg: cfg,
|
||||||
|
|
||||||
|
|
|
@ -36,6 +36,8 @@ type
|
||||||
## When process_slots() is being called as part of a state_transition(),
|
## When process_slots() is being called as part of a state_transition(),
|
||||||
## the hash_tree_root() from the block will fill in the state.root so it
|
## the hash_tree_root() from the block will fill in the state.root so it
|
||||||
## should skip calculating that last state root.
|
## should skip calculating that last state root.
|
||||||
|
experimental ##\
|
||||||
|
## Whether to enable extra features in development.
|
||||||
enableTestFeatures ##\
|
enableTestFeatures ##\
|
||||||
## Whether to enable extra features for testing.
|
## Whether to enable extra features for testing.
|
||||||
lowParticipation ##\
|
lowParticipation ##\
|
||||||
|
|
|
@ -50,12 +50,13 @@ logScope: topics = "fork_choice"
|
||||||
|
|
||||||
func init*(
|
func init*(
|
||||||
T: type ForkChoiceBackend, checkpoints: FinalityCheckpoints,
|
T: type ForkChoiceBackend, checkpoints: FinalityCheckpoints,
|
||||||
hasLowParticipation = false): T =
|
experimental = false, hasLowParticipation = false): T =
|
||||||
T(proto_array: ProtoArray.init(checkpoints, hasLowParticipation))
|
T(proto_array: ProtoArray.init(
|
||||||
|
checkpoints, experimental, hasLowParticipation))
|
||||||
|
|
||||||
proc init*(
|
proc init*(
|
||||||
T: type ForkChoice, epochRef: EpochRef, blck: BlockRef,
|
T: type ForkChoice, epochRef: EpochRef, blck: BlockRef,
|
||||||
hasLowParticipation = false): T =
|
experimental = false, hasLowParticipation = false): T =
|
||||||
## Initialize a fork choice context for a finalized state - in the finalized
|
## Initialize a fork choice context for a finalized state - in the finalized
|
||||||
## state, the justified and finalized checkpoints are the same, so only one
|
## state, the justified and finalized checkpoints are the same, so only one
|
||||||
## is used here
|
## is used here
|
||||||
|
@ -68,8 +69,9 @@ proc init*(
|
||||||
FinalityCheckpoints(
|
FinalityCheckpoints(
|
||||||
justified: checkpoint,
|
justified: checkpoint,
|
||||||
finalized: checkpoint),
|
finalized: checkpoint),
|
||||||
hasLowParticipation),
|
experimental, hasLowParticipation),
|
||||||
checkpoints: Checkpoints(
|
checkpoints: Checkpoints(
|
||||||
|
experimental: experimental,
|
||||||
justified: BalanceCheckpoint(
|
justified: BalanceCheckpoint(
|
||||||
checkpoint: checkpoint,
|
checkpoint: checkpoint,
|
||||||
balances: epochRef.effective_balances),
|
balances: epochRef.effective_balances),
|
||||||
|
@ -116,7 +118,7 @@ proc update_justified(
|
||||||
epochRef = dag.getEpochRef(blck, epoch, false).valueOr:
|
epochRef = dag.getEpochRef(blck, epoch, false).valueOr:
|
||||||
# Shouldn't happen for justified data unless out of sync with ChainDAG
|
# Shouldn't happen for justified data unless out of sync with ChainDAG
|
||||||
warn "Skipping justified checkpoint update, no EpochRef - report bug",
|
warn "Skipping justified checkpoint update, no EpochRef - report bug",
|
||||||
blck, epoch, best = self.best_justified.epoch, error
|
blck, epoch, error
|
||||||
return
|
return
|
||||||
justified = Checkpoint(root: blck.root, epoch: epochRef.epoch)
|
justified = Checkpoint(root: blck.root, epoch: epochRef.epoch)
|
||||||
|
|
||||||
|
@ -144,10 +146,13 @@ proc update_checkpoints(
|
||||||
## Update checkpoints in store if necessary
|
## Update checkpoints in store if necessary
|
||||||
# Update justified checkpoint
|
# Update justified checkpoint
|
||||||
if checkpoints.justified.epoch > self.justified.checkpoint.epoch:
|
if checkpoints.justified.epoch > self.justified.checkpoint.epoch:
|
||||||
if checkpoints.justified.epoch > self.best_justified.epoch:
|
if not self.experimental:
|
||||||
self.best_justified = checkpoints.justified
|
if checkpoints.justified.epoch > self.best_justified.epoch:
|
||||||
|
self.best_justified = checkpoints.justified
|
||||||
|
|
||||||
if ? should_update_justified_checkpoint(self, dag, checkpoints.justified):
|
if ? should_update_justified_checkpoint(self, dag, checkpoints.justified):
|
||||||
|
? self.update_justified(dag, checkpoints.justified)
|
||||||
|
else:
|
||||||
? self.update_justified(dag, checkpoints.justified)
|
? self.update_justified(dag, checkpoints.justified)
|
||||||
|
|
||||||
# Update finalized checkpoint
|
# Update finalized checkpoint
|
||||||
|
@ -155,8 +160,9 @@ proc update_checkpoints(
|
||||||
trace "Updating finalized",
|
trace "Updating finalized",
|
||||||
store = self.finalized, state = checkpoints.finalized
|
store = self.finalized, state = checkpoints.finalized
|
||||||
self.finalized = checkpoints.finalized
|
self.finalized = checkpoints.finalized
|
||||||
if checkpoints.justified != self.justified.checkpoint:
|
if not self.experimental:
|
||||||
? self.update_justified(dag, checkpoints.justified)
|
if checkpoints.justified != self.justified.checkpoint:
|
||||||
|
? self.update_justified(dag, checkpoints.justified)
|
||||||
|
|
||||||
ok()
|
ok()
|
||||||
|
|
||||||
|
@ -185,18 +191,19 @@ proc on_tick(
|
||||||
|
|
||||||
# Update store.justified_checkpoint if a better checkpoint on the
|
# Update store.justified_checkpoint if a better checkpoint on the
|
||||||
# store.finalized_checkpoint chain
|
# store.finalized_checkpoint chain
|
||||||
let
|
if not self.checkpoints.experimental:
|
||||||
best_justified_epoch = self.checkpoints.best_justified.epoch
|
|
||||||
store_justified_epoch = self.checkpoints.justified.checkpoint.epoch
|
|
||||||
if best_justified_epoch > store_justified_epoch:
|
|
||||||
let
|
let
|
||||||
blck = dag.getBlockRef(self.checkpoints.best_justified.root).valueOr:
|
best_justified_epoch = self.checkpoints.best_justified.epoch
|
||||||
return err ForkChoiceError(
|
store_justified_epoch = self.checkpoints.justified.checkpoint.epoch
|
||||||
kind: fcJustifiedNodeUnknown,
|
if best_justified_epoch > store_justified_epoch:
|
||||||
blockRoot: self.checkpoints.best_justified.root)
|
let
|
||||||
finalized_ancestor = blck.atEpochStart(self.checkpoints.finalized.epoch)
|
blck = dag.getBlockRef(self.checkpoints.best_justified.root).valueOr:
|
||||||
if finalized_ancestor.blck.root == self.checkpoints.finalized.root:
|
return err ForkChoiceError(
|
||||||
self.checkpoints.update_justified(dag, blck, best_justified_epoch)
|
kind: fcJustifiedNodeUnknown,
|
||||||
|
blockRoot: self.checkpoints.best_justified.root)
|
||||||
|
finalized_ancestor = blck.atEpochStart(self.checkpoints.finalized.epoch)
|
||||||
|
if finalized_ancestor.blck.root == self.checkpoints.finalized.root:
|
||||||
|
self.checkpoints.update_justified(dag, blck, best_justified_epoch)
|
||||||
|
|
||||||
# Pull-up chain tips from previous epoch
|
# Pull-up chain tips from previous epoch
|
||||||
for realized in self.backend.proto_array.realizePendingCheckpoints():
|
for realized in self.backend.proto_array.realizePendingCheckpoints():
|
||||||
|
@ -307,11 +314,11 @@ func process_equivocation*(
|
||||||
|
|
||||||
# https://github.com/ethereum/consensus-specs/blob/v1.3.0-rc.1/specs/phase0/fork-choice.md#on_block
|
# https://github.com/ethereum/consensus-specs/blob/v1.3.0-rc.1/specs/phase0/fork-choice.md#on_block
|
||||||
func process_block*(self: var ForkChoiceBackend,
|
func process_block*(self: var ForkChoiceBackend,
|
||||||
block_root: Eth2Digest,
|
bid: BlockId,
|
||||||
parent_root: Eth2Digest,
|
parent_root: Eth2Digest,
|
||||||
checkpoints: FinalityCheckpoints,
|
checkpoints: FinalityCheckpoints,
|
||||||
unrealized = none(FinalityCheckpoints)): FcResult[void] =
|
unrealized = none(FinalityCheckpoints)): FcResult[void] =
|
||||||
self.proto_array.onBlock(block_root, parent_root, checkpoints, unrealized)
|
self.proto_array.onBlock(bid, parent_root, checkpoints, unrealized)
|
||||||
|
|
||||||
proc process_block*(self: var ForkChoice,
|
proc process_block*(self: var ForkChoice,
|
||||||
dag: ChainDAGRef,
|
dag: ChainDAGRef,
|
||||||
|
@ -358,14 +365,14 @@ proc process_block*(self: var ForkChoice,
|
||||||
blck = shortLog(blckRef), checkpoints = epochRef.checkpoints, unrealized
|
blck = shortLog(blckRef), checkpoints = epochRef.checkpoints, unrealized
|
||||||
? update_checkpoints(self.checkpoints, dag, unrealized)
|
? update_checkpoints(self.checkpoints, dag, unrealized)
|
||||||
? process_block(
|
? process_block(
|
||||||
self.backend, blckRef.root, blck.parent_root, unrealized)
|
self.backend, blckRef.bid, blck.parent_root, unrealized)
|
||||||
else:
|
else:
|
||||||
? process_block(
|
? process_block(
|
||||||
self.backend, blckRef.root, blck.parent_root,
|
self.backend, blckRef.bid, blck.parent_root,
|
||||||
epochRef.checkpoints, some unrealized) # Realized in `on_tick`
|
epochRef.checkpoints, some unrealized) # Realized in `on_tick`
|
||||||
else:
|
else:
|
||||||
? process_block(
|
? process_block(
|
||||||
self.backend, blckRef.root, blck.parent_root, epochRef.checkpoints)
|
self.backend, blckRef.bid, blck.parent_root, epochRef.checkpoints)
|
||||||
|
|
||||||
ok()
|
ok()
|
||||||
|
|
||||||
|
@ -424,13 +431,16 @@ func get_safe_beacon_block_root*(self: ForkChoice): Eth2Digest =
|
||||||
self.checkpoints.justified.checkpoint.root
|
self.checkpoints.justified.checkpoint.root
|
||||||
|
|
||||||
func prune*(
|
func prune*(
|
||||||
self: var ForkChoiceBackend, finalized_root: Eth2Digest
|
self: var ForkChoiceBackend, checkpoints: FinalityCheckpoints
|
||||||
): FcResult[void] =
|
): FcResult[void] =
|
||||||
## Prune blocks preceding the finalized root as they are now unneeded.
|
## Prune blocks preceding the finalized root as they are now unneeded.
|
||||||
self.proto_array.prune(finalized_root)
|
self.proto_array.prune(checkpoints)
|
||||||
|
|
||||||
func prune*(self: var ForkChoice): FcResult[void] =
|
func prune*(self: var ForkChoice): FcResult[void] =
|
||||||
self.backend.prune(self.checkpoints.finalized.root)
|
self.backend.prune(
|
||||||
|
FinalityCheckpoints(
|
||||||
|
justified: self.checkpoints.justified.checkpoint,
|
||||||
|
finalized: self.checkpoints.finalized))
|
||||||
|
|
||||||
func mark_root_invalid*(self: var ForkChoice, root: Eth2Digest) =
|
func mark_root_invalid*(self: var ForkChoice, root: Eth2Digest) =
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -88,6 +88,7 @@ type
|
||||||
## Subtracted from logical index to get the physical index
|
## Subtracted from logical index to get the physical index
|
||||||
|
|
||||||
ProtoArray* = object
|
ProtoArray* = object
|
||||||
|
experimental*: bool
|
||||||
hasLowParticipation*: bool
|
hasLowParticipation*: bool
|
||||||
currentEpoch*: Epoch
|
currentEpoch*: Epoch
|
||||||
checkpoints*: FinalityCheckpoints
|
checkpoints*: FinalityCheckpoints
|
||||||
|
@ -98,7 +99,7 @@ type
|
||||||
previousProposerBoostScore*: uint64
|
previousProposerBoostScore*: uint64
|
||||||
|
|
||||||
ProtoNode* = object
|
ProtoNode* = object
|
||||||
root*: Eth2Digest
|
bid*: BlockId
|
||||||
parent*: Option[Index]
|
parent*: Option[Index]
|
||||||
checkpoints*: FinalityCheckpoints
|
checkpoints*: FinalityCheckpoints
|
||||||
weight*: int64
|
weight*: int64
|
||||||
|
@ -111,6 +112,7 @@ type
|
||||||
balances*: seq[Gwei]
|
balances*: seq[Gwei]
|
||||||
|
|
||||||
Checkpoints* = object
|
Checkpoints* = object
|
||||||
|
experimental*: bool
|
||||||
time*: BeaconTime
|
time*: BeaconTime
|
||||||
justified*: BalanceCheckpoint
|
justified*: BalanceCheckpoint
|
||||||
finalized*: Checkpoint
|
finalized*: Checkpoint
|
||||||
|
|
|
@ -81,17 +81,21 @@ func maybeUpdateBestChildAndDescendant(self: var ProtoArray,
|
||||||
parentIdx: Index,
|
parentIdx: Index,
|
||||||
childIdx: Index): FcResult[void]
|
childIdx: Index): FcResult[void]
|
||||||
|
|
||||||
func nodeIsViableForHead(self: ProtoArray, node: ProtoNode): bool
|
func nodeIsViableForHead(
|
||||||
func nodeLeadsToViableHead(self: ProtoArray, node: ProtoNode): FcResult[bool]
|
self: ProtoArray, node: ProtoNode, nodeIdx: Index): bool
|
||||||
|
func nodeLeadsToViableHead(
|
||||||
|
self: ProtoArray, node: ProtoNode, nodeIdx: Index): FcResult[bool]
|
||||||
|
|
||||||
# ProtoArray routines
|
# ProtoArray routines
|
||||||
# ----------------------------------------------------------------------
|
# ----------------------------------------------------------------------
|
||||||
|
|
||||||
func init*(
|
func init*(
|
||||||
T: type ProtoArray, checkpoints: FinalityCheckpoints,
|
T: type ProtoArray, checkpoints: FinalityCheckpoints,
|
||||||
hasLowParticipation: bool): T =
|
experimental, hasLowParticipation: bool): T =
|
||||||
let node = ProtoNode(
|
let node = ProtoNode(
|
||||||
root: checkpoints.finalized.root,
|
bid: BlockId(
|
||||||
|
slot: checkpoints.finalized.epoch.start_slot,
|
||||||
|
root: checkpoints.finalized.root),
|
||||||
parent: none(int),
|
parent: none(int),
|
||||||
checkpoints: checkpoints,
|
checkpoints: checkpoints,
|
||||||
weight: 0,
|
weight: 0,
|
||||||
|
@ -99,10 +103,11 @@ func init*(
|
||||||
bestChild: none(int),
|
bestChild: none(int),
|
||||||
bestDescendant: none(int))
|
bestDescendant: none(int))
|
||||||
|
|
||||||
T(hasLowParticipation: hasLowParticipation,
|
T(experimental: experimental,
|
||||||
|
hasLowParticipation: hasLowParticipation,
|
||||||
checkpoints: checkpoints,
|
checkpoints: checkpoints,
|
||||||
nodes: ProtoNodes(buf: @[node], offset: 0),
|
nodes: ProtoNodes(buf: @[node], offset: 0),
|
||||||
indices: {node.root: 0}.toTable())
|
indices: {node.bid.root: 0}.toTable())
|
||||||
|
|
||||||
iterator realizePendingCheckpoints*(
|
iterator realizePendingCheckpoints*(
|
||||||
self: var ProtoArray, resetTipTracking = true): FinalityCheckpoints =
|
self: var ProtoArray, resetTipTracking = true): FinalityCheckpoints =
|
||||||
|
@ -111,7 +116,7 @@ iterator realizePendingCheckpoints*(
|
||||||
let physicalIdx = idx - self.nodes.offset
|
let physicalIdx = idx - self.nodes.offset
|
||||||
if unrealized != self.nodes.buf[physicalIdx].checkpoints:
|
if unrealized != self.nodes.buf[physicalIdx].checkpoints:
|
||||||
trace "Pulling up chain tip",
|
trace "Pulling up chain tip",
|
||||||
blck = self.nodes.buf[physicalIdx].root,
|
blck = self.nodes.buf[physicalIdx].bid.root,
|
||||||
checkpoints = self.nodes.buf[physicalIdx].checkpoints,
|
checkpoints = self.nodes.buf[physicalIdx].checkpoints,
|
||||||
unrealized
|
unrealized
|
||||||
self.nodes.buf[physicalIdx].checkpoints = unrealized
|
self.nodes.buf[physicalIdx].checkpoints = unrealized
|
||||||
|
@ -173,7 +178,7 @@ func applyScoreChanges*(self: var ProtoArray,
|
||||||
self.checkpoints = checkpoints
|
self.checkpoints = checkpoints
|
||||||
|
|
||||||
# If previous epoch is justified, pull up all current tips to previous epoch
|
# If previous epoch is justified, pull up all current tips to previous epoch
|
||||||
if self.hasLowParticipation and self.isPreviousEpochJustified:
|
if self.experimental and self.isPreviousEpochJustified:
|
||||||
for realized in self.realizePendingCheckpoints(resetTipTracking = false):
|
for realized in self.realizePendingCheckpoints(resetTipTracking = false):
|
||||||
discard
|
discard
|
||||||
|
|
||||||
|
@ -187,7 +192,7 @@ func applyScoreChanges*(self: var ProtoArray,
|
||||||
|
|
||||||
# Iterate backwards through all the indices in `self.nodes`
|
# Iterate backwards through all the indices in `self.nodes`
|
||||||
for nodePhysicalIdx in countdown(self.nodes.len - 1, 0):
|
for nodePhysicalIdx in countdown(self.nodes.len - 1, 0):
|
||||||
if node.root.isZero:
|
if node.bid.root.isZero:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
var nodeDelta = deltas[nodePhysicalIdx]
|
var nodeDelta = deltas[nodePhysicalIdx]
|
||||||
|
@ -195,7 +200,7 @@ func applyScoreChanges*(self: var ProtoArray,
|
||||||
# If we find the node for which the proposer boost was previously applied,
|
# If we find the node for which the proposer boost was previously applied,
|
||||||
# decrease the delta by the previous score amount.
|
# decrease the delta by the previous score amount.
|
||||||
if (not self.previousProposerBoostRoot.isZero) and
|
if (not self.previousProposerBoostRoot.isZero) and
|
||||||
self.previousProposerBoostRoot == node.root:
|
self.previousProposerBoostRoot == node.bid.root:
|
||||||
if nodeDelta < 0 and
|
if nodeDelta < 0 and
|
||||||
nodeDelta - low(Delta) < self.previousProposerBoostScore.int64:
|
nodeDelta - low(Delta) < self.previousProposerBoostScore.int64:
|
||||||
return err ForkChoiceError(
|
return err ForkChoiceError(
|
||||||
|
@ -207,7 +212,7 @@ func applyScoreChanges*(self: var ProtoArray,
|
||||||
# the delta by the new score amount.
|
# the delta by the new score amount.
|
||||||
#
|
#
|
||||||
# https://github.com/ethereum/consensus-specs/blob/v1.1.10/specs/phase0/fork-choice.md#get_latest_attesting_balance
|
# https://github.com/ethereum/consensus-specs/blob/v1.1.10/specs/phase0/fork-choice.md#get_latest_attesting_balance
|
||||||
if (not proposerBoostRoot.isZero) and proposerBoostRoot == node.root:
|
if (not proposerBoostRoot.isZero) and proposerBoostRoot == node.bid.root:
|
||||||
proposerBoostScore = calculateProposerBoost(newBalances)
|
proposerBoostScore = calculateProposerBoost(newBalances)
|
||||||
if nodeDelta >= 0 and
|
if nodeDelta >= 0 and
|
||||||
high(Delta) - nodeDelta < proposerBoostScore.int64:
|
high(Delta) - nodeDelta < proposerBoostScore.int64:
|
||||||
|
@ -265,7 +270,7 @@ func applyScoreChanges*(self: var ProtoArray,
|
||||||
self.previousProposerBoostScore = proposerBoostScore
|
self.previousProposerBoostScore = proposerBoostScore
|
||||||
|
|
||||||
for nodePhysicalIdx in countdown(self.nodes.len - 1, 0):
|
for nodePhysicalIdx in countdown(self.nodes.len - 1, 0):
|
||||||
if node.root.isZero:
|
if node.bid.root.isZero:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if node.parent.isSome():
|
if node.parent.isSome():
|
||||||
|
@ -281,7 +286,7 @@ func applyScoreChanges*(self: var ProtoArray,
|
||||||
ok()
|
ok()
|
||||||
|
|
||||||
func onBlock*(self: var ProtoArray,
|
func onBlock*(self: var ProtoArray,
|
||||||
root: Eth2Digest,
|
bid: BlockId,
|
||||||
parent: Eth2Digest,
|
parent: Eth2Digest,
|
||||||
checkpoints: FinalityCheckpoints,
|
checkpoints: FinalityCheckpoints,
|
||||||
unrealized = none(FinalityCheckpoints)): FcResult[void] =
|
unrealized = none(FinalityCheckpoints)): FcResult[void] =
|
||||||
|
@ -294,7 +299,7 @@ func onBlock*(self: var ProtoArray,
|
||||||
# Note: if parent is an "Option" type, we can run out of stack space.
|
# Note: if parent is an "Option" type, we can run out of stack space.
|
||||||
|
|
||||||
# If the block is already known, ignore it
|
# If the block is already known, ignore it
|
||||||
if root in self.indices:
|
if bid.root in self.indices:
|
||||||
return ok()
|
return ok()
|
||||||
|
|
||||||
var parentIdx: Index
|
var parentIdx: Index
|
||||||
|
@ -303,13 +308,13 @@ func onBlock*(self: var ProtoArray,
|
||||||
do:
|
do:
|
||||||
return err ForkChoiceError(
|
return err ForkChoiceError(
|
||||||
kind: fcUnknownParent,
|
kind: fcUnknownParent,
|
||||||
childRoot: root,
|
childRoot: bid.root,
|
||||||
parentRoot: parent)
|
parentRoot: parent)
|
||||||
|
|
||||||
let nodeLogicalIdx = self.nodes.offset + self.nodes.buf.len
|
let nodeLogicalIdx = self.nodes.offset + self.nodes.buf.len
|
||||||
|
|
||||||
let node = ProtoNode(
|
let node = ProtoNode(
|
||||||
root: root,
|
bid: bid,
|
||||||
parent: some(parentIdx),
|
parent: some(parentIdx),
|
||||||
checkpoints: checkpoints,
|
checkpoints: checkpoints,
|
||||||
weight: 0,
|
weight: 0,
|
||||||
|
@ -317,11 +322,11 @@ func onBlock*(self: var ProtoArray,
|
||||||
bestChild: none(int),
|
bestChild: none(int),
|
||||||
bestDescendant: none(int))
|
bestDescendant: none(int))
|
||||||
|
|
||||||
self.indices[node.root] = nodeLogicalIdx
|
self.indices[node.bid.root] = nodeLogicalIdx
|
||||||
self.nodes.add node
|
self.nodes.add node
|
||||||
|
|
||||||
|
self.currentEpochTips.del parentIdx
|
||||||
if unrealized.isSome:
|
if unrealized.isSome:
|
||||||
self.currentEpochTips.del parentIdx
|
|
||||||
self.currentEpochTips[nodeLogicalIdx] = unrealized.get
|
self.currentEpochTips[nodeLogicalIdx] = unrealized.get
|
||||||
|
|
||||||
? self.maybeUpdateBestChildAndDescendant(parentIdx, nodeLogicalIdx)
|
? self.maybeUpdateBestChildAndDescendant(parentIdx, nodeLogicalIdx)
|
||||||
|
@ -359,34 +364,38 @@ func findHead*(self: var ProtoArray,
|
||||||
index: bestDescendantIdx)
|
index: bestDescendantIdx)
|
||||||
|
|
||||||
# Perform a sanity check to ensure the node can be head
|
# Perform a sanity check to ensure the node can be head
|
||||||
if not self.nodeIsViableForHead(bestNode.get()):
|
if not self.nodeIsViableForHead(bestNode.get(), bestDescendantIdx):
|
||||||
return err ForkChoiceError(
|
return err ForkChoiceError(
|
||||||
kind: fcInvalidBestNode,
|
kind: fcInvalidBestNode,
|
||||||
startRoot: justifiedRoot,
|
startRoot: justifiedRoot,
|
||||||
fkChoiceCheckpoints: self.checkpoints,
|
fkChoiceCheckpoints: self.checkpoints,
|
||||||
headRoot: justifiedNode.get().root,
|
headRoot: justifiedNode.get().bid.root,
|
||||||
headCheckpoints: justifiedNode.get().checkpoints)
|
headCheckpoints: justifiedNode.get().checkpoints)
|
||||||
|
|
||||||
head = bestNode.get().root
|
head = bestNode.get().bid.root
|
||||||
ok()
|
ok()
|
||||||
|
|
||||||
func prune*(self: var ProtoArray, finalizedRoot: Eth2Digest): FcResult[void] =
|
func prune*(
|
||||||
|
self: var ProtoArray,
|
||||||
|
checkpoints: FinalityCheckpoints): FcResult[void] =
|
||||||
## Update the tree with new finalization information.
|
## Update the tree with new finalization information.
|
||||||
## The tree is pruned if and only if:
|
## The tree is pruned if and only if:
|
||||||
## - The `finalizedRoot` and finalized epoch are different from current
|
## - `checkpoints.finalized.root` and finalized epoch
|
||||||
|
## are different from current
|
||||||
##
|
##
|
||||||
## Returns error if:
|
## Returns error if:
|
||||||
## - The finalized epoch is less than the current one
|
## - The finalized epoch is less than the current one
|
||||||
## - The finalized epoch matches the current one but the finalized root is different
|
## - The finalized epoch matches the current one but the f
|
||||||
|
## inalized root is different
|
||||||
## - Internal error due to invalid indices in `self`
|
## - Internal error due to invalid indices in `self`
|
||||||
|
|
||||||
var finalizedIdx: int
|
var finalizedIdx: int
|
||||||
self.indices.withValue(finalizedRoot, value) do:
|
self.indices.withValue(checkpoints.finalized.root, value) do:
|
||||||
finalizedIdx = value[]
|
finalizedIdx = value[]
|
||||||
do:
|
do:
|
||||||
return err ForkChoiceError(
|
return err ForkChoiceError(
|
||||||
kind: fcFinalizedNodeUnknown,
|
kind: fcFinalizedNodeUnknown,
|
||||||
blockRoot: finalizedRoot)
|
blockRoot: checkpoints.finalized.root)
|
||||||
|
|
||||||
if finalizedIdx == self.nodes.offset:
|
if finalizedIdx == self.nodes.offset:
|
||||||
# Nothing to do
|
# Nothing to do
|
||||||
|
@ -395,15 +404,14 @@ func prune*(self: var ProtoArray, finalizedRoot: Eth2Digest): FcResult[void] =
|
||||||
if finalizedIdx < self.nodes.offset:
|
if finalizedIdx < self.nodes.offset:
|
||||||
return err ForkChoiceError(
|
return err ForkChoiceError(
|
||||||
kind: fcPruningFromOutdatedFinalizedRoot,
|
kind: fcPruningFromOutdatedFinalizedRoot,
|
||||||
finalizedRoot: finalizedRoot)
|
finalizedRoot: checkpoints.finalized.root)
|
||||||
|
|
||||||
trace "Pruning blocks from fork choice",
|
trace "Pruning blocks from fork choice", checkpoints
|
||||||
finalizedRoot = shortLog(finalizedRoot)
|
|
||||||
|
|
||||||
let finalPhysicalIdx = finalizedIdx - self.nodes.offset
|
let finalPhysicalIdx = finalizedIdx - self.nodes.offset
|
||||||
for nodeIdx in 0 ..< finalPhysicalIdx:
|
for nodeIdx in 0 ..< finalPhysicalIdx:
|
||||||
self.currentEpochTips.del nodeIdx
|
self.currentEpochTips.del nodeIdx
|
||||||
self.indices.del(self.nodes.buf[nodeIdx].root)
|
self.indices.del(self.nodes.buf[nodeIdx].bid.root)
|
||||||
|
|
||||||
# Drop all nodes prior to finalization.
|
# Drop all nodes prior to finalization.
|
||||||
# This is done in-place with `moveMem` to avoid costly reallocations.
|
# This is done in-place with `moveMem` to avoid costly reallocations.
|
||||||
|
@ -445,7 +453,8 @@ func maybeUpdateBestChildAndDescendant(self: var ProtoArray,
|
||||||
kind: fcInvalidNodeIndex,
|
kind: fcInvalidNodeIndex,
|
||||||
index: parentIdx)
|
index: parentIdx)
|
||||||
|
|
||||||
let childLeadsToViableHead = ? self.nodeLeadsToViableHead(child.get())
|
let childLeadsToViableHead =
|
||||||
|
? self.nodeLeadsToViableHead(child.get(), childIdx)
|
||||||
|
|
||||||
let # Aliases to the 3 possible (bestChild, bestDescendant) tuples
|
let # Aliases to the 3 possible (bestChild, bestDescendant) tuples
|
||||||
changeToNone = (none(Index), none(Index))
|
changeToNone = (none(Index), none(Index))
|
||||||
|
@ -477,7 +486,7 @@ func maybeUpdateBestChildAndDescendant(self: var ProtoArray,
|
||||||
index: bestChildIdx)
|
index: bestChildIdx)
|
||||||
|
|
||||||
let bestChildLeadsToViableHead =
|
let bestChildLeadsToViableHead =
|
||||||
? self.nodeLeadsToViableHead(bestChild.get())
|
? self.nodeLeadsToViableHead(bestChild.get(), bestChildIdx)
|
||||||
|
|
||||||
if childLeadsToViableHead and not bestChildLeadsToViableHead:
|
if childLeadsToViableHead and not bestChildLeadsToViableHead:
|
||||||
# The child leads to a viable head, but the current best-child doesn't
|
# The child leads to a viable head, but the current best-child doesn't
|
||||||
|
@ -487,7 +496,7 @@ func maybeUpdateBestChildAndDescendant(self: var ProtoArray,
|
||||||
noChange
|
noChange
|
||||||
elif child.get().weight == bestChild.get().weight:
|
elif child.get().weight == bestChild.get().weight:
|
||||||
# Tie-breaker of equal weights by root
|
# Tie-breaker of equal weights by root
|
||||||
if child.get().root.tiebreak(bestChild.get().root):
|
if child.get().bid.root.tiebreak(bestChild.get().bid.root):
|
||||||
changeToChild
|
changeToChild
|
||||||
else:
|
else:
|
||||||
noChange
|
noChange
|
||||||
|
@ -511,7 +520,8 @@ func maybeUpdateBestChildAndDescendant(self: var ProtoArray,
|
||||||
|
|
||||||
ok()
|
ok()
|
||||||
|
|
||||||
func nodeLeadsToViableHead(self: ProtoArray, node: ProtoNode): FcResult[bool] =
|
func nodeLeadsToViableHead(
|
||||||
|
self: ProtoArray, node: ProtoNode, nodeIdx: Index): FcResult[bool] =
|
||||||
## Indicates if the node itself or its best-descendant are viable
|
## Indicates if the node itself or its best-descendant are viable
|
||||||
## for blockchain head
|
## for blockchain head
|
||||||
let bestDescendantIsViableForHead = block:
|
let bestDescendantIsViableForHead = block:
|
||||||
|
@ -522,13 +532,14 @@ func nodeLeadsToViableHead(self: ProtoArray, node: ProtoNode): FcResult[bool] =
|
||||||
return err ForkChoiceError(
|
return err ForkChoiceError(
|
||||||
kind: fcInvalidBestDescendant,
|
kind: fcInvalidBestDescendant,
|
||||||
index: bestDescendantIdx)
|
index: bestDescendantIdx)
|
||||||
self.nodeIsViableForHead(bestDescendant.get())
|
self.nodeIsViableForHead(bestDescendant.get(), bestDescendantIdx)
|
||||||
else:
|
else:
|
||||||
false
|
false
|
||||||
|
|
||||||
ok(bestDescendantIsViableForHead or self.nodeIsViableForHead(node))
|
ok(bestDescendantIsViableForHead or self.nodeIsViableForHead(node, nodeIdx))
|
||||||
|
|
||||||
func nodeIsViableForHead(self: ProtoArray, node: ProtoNode): bool =
|
func nodeIsViableForHead(
|
||||||
|
self: ProtoArray, node: ProtoNode, nodeIdx: Index): bool =
|
||||||
## This is the equivalent of `filter_block_tree` function in eth2 spec
|
## This is the equivalent of `filter_block_tree` function in eth2 spec
|
||||||
## https://github.com/ethereum/consensus-specs/blob/v1.3.0-rc.1/specs/phase0/fork-choice.md#filter_block_tree
|
## https://github.com/ethereum/consensus-specs/blob/v1.3.0-rc.1/specs/phase0/fork-choice.md#filter_block_tree
|
||||||
|
|
||||||
|
@ -545,6 +556,35 @@ func nodeIsViableForHead(self: ProtoArray, node: ProtoNode): bool =
|
||||||
node.checkpoints.finalized == self.checkpoints.finalized or
|
node.checkpoints.finalized == self.checkpoints.finalized or
|
||||||
self.checkpoints.finalized.epoch == GENESIS_EPOCH
|
self.checkpoints.finalized.epoch == GENESIS_EPOCH
|
||||||
|
|
||||||
|
if self.experimental:
|
||||||
|
var correctJustified =
|
||||||
|
self.checkpoints.justified.epoch == GENESIS_EPOCH or
|
||||||
|
node.checkpoints.justified.epoch == self.checkpoints.justified.epoch
|
||||||
|
if not correctJustified and self.isPreviousEpochJustified and
|
||||||
|
node.bid.slot.epoch == self.currentEpoch:
|
||||||
|
let unrealized =
|
||||||
|
self.currentEpochTips.getOrDefault(nodeIdx, node.checkpoints)
|
||||||
|
correctJustified =
|
||||||
|
unrealized.justified.epoch >= self.checkpoints.justified.epoch and
|
||||||
|
node.checkpoints.justified.epoch + 2 >= self.currentEpoch
|
||||||
|
return
|
||||||
|
if not correctJustified:
|
||||||
|
false
|
||||||
|
elif self.checkpoints.finalized.epoch == GENESIS_EPOCH:
|
||||||
|
true
|
||||||
|
else:
|
||||||
|
let finalizedSlot = self.checkpoints.finalized.epoch.start_slot
|
||||||
|
var ancestor = some node
|
||||||
|
while ancestor.isSome and ancestor.unsafeGet.bid.slot > finalizedSlot:
|
||||||
|
if ancestor.unsafeGet.parent.isSome:
|
||||||
|
ancestor = self.nodes[ancestor.unsafeGet.parent.unsafeGet]
|
||||||
|
else:
|
||||||
|
ancestor.reset()
|
||||||
|
if ancestor.isSome:
|
||||||
|
ancestor.unsafeGet.bid.root == self.checkpoints.finalized.root
|
||||||
|
else:
|
||||||
|
false
|
||||||
|
|
||||||
## Any node that has a different finalized or justified epoch
|
## Any node that has a different finalized or justified epoch
|
||||||
## should not be viable for the head.
|
## should not be viable for the head.
|
||||||
(
|
(
|
||||||
|
@ -582,7 +622,7 @@ func propagateInvalidity*(
|
||||||
# Helpers to dump internal state
|
# Helpers to dump internal state
|
||||||
|
|
||||||
type ProtoArrayItem* = object
|
type ProtoArrayItem* = object
|
||||||
root*: Eth2Digest
|
bid*: BlockId
|
||||||
parent*: Eth2Digest
|
parent*: Eth2Digest
|
||||||
checkpoints*: FinalityCheckpoints
|
checkpoints*: FinalityCheckpoints
|
||||||
unrealized*: Option[FinalityCheckpoints]
|
unrealized*: Option[FinalityCheckpoints]
|
||||||
|
@ -597,13 +637,13 @@ func root(self: ProtoNodes, logicalIdx: Option[Index]): Eth2Digest =
|
||||||
let node = self[logicalIdx.unsafeGet]
|
let node = self[logicalIdx.unsafeGet]
|
||||||
if node.isNone:
|
if node.isNone:
|
||||||
return ZERO_HASH
|
return ZERO_HASH
|
||||||
node.unsafeGet.root
|
node.unsafeGet.bid.root
|
||||||
|
|
||||||
iterator items*(self: ProtoArray): ProtoArrayItem =
|
iterator items*(self: ProtoArray): ProtoArrayItem =
|
||||||
## Iterate over all nodes known by fork choice.
|
## Iterate over all nodes known by fork choice.
|
||||||
doAssert self.indices.len == self.nodes.len
|
doAssert self.indices.len == self.nodes.len
|
||||||
for nodePhysicalIdx, node in self.nodes.buf:
|
for nodePhysicalIdx, node in self.nodes.buf:
|
||||||
if node.root.isZero:
|
if node.bid.root.isZero:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
let unrealized = block:
|
let unrealized = block:
|
||||||
|
@ -614,7 +654,7 @@ iterator items*(self: ProtoArray): ProtoArrayItem =
|
||||||
none(FinalityCheckpoints)
|
none(FinalityCheckpoints)
|
||||||
|
|
||||||
yield ProtoArrayItem(
|
yield ProtoArrayItem(
|
||||||
root: node.root,
|
bid: node.bid,
|
||||||
parent: self.nodes.root(node.parent),
|
parent: self.nodes.root(node.parent),
|
||||||
checkpoints: node.checkpoints,
|
checkpoints: node.checkpoints,
|
||||||
unrealized: unrealized,
|
unrealized: unrealized,
|
||||||
|
|
|
@ -142,8 +142,7 @@ proc loadChainDag(
|
||||||
db: BeaconChainDB,
|
db: BeaconChainDB,
|
||||||
eventBus: EventBus,
|
eventBus: EventBus,
|
||||||
validatorMonitor: ref ValidatorMonitor,
|
validatorMonitor: ref ValidatorMonitor,
|
||||||
networkGenesisValidatorsRoot: Opt[Eth2Digest],
|
networkGenesisValidatorsRoot: Opt[Eth2Digest]): ChainDAGRef =
|
||||||
shouldEnableTestFeatures: bool): ChainDAGRef =
|
|
||||||
info "Loading block DAG from database", path = config.databaseDir
|
info "Loading block DAG from database", path = config.databaseDir
|
||||||
|
|
||||||
var dag: ChainDAGRef
|
var dag: ChainDAGRef
|
||||||
|
@ -170,10 +169,12 @@ proc loadChainDag(
|
||||||
jsonVersion: contextFork,
|
jsonVersion: contextFork,
|
||||||
sszContext: dag.forkDigests[].atStateFork(contextFork)))
|
sszContext: dag.forkDigests[].atStateFork(contextFork)))
|
||||||
|
|
||||||
|
var extraFlags = {enableTestFeatures}
|
||||||
|
if config.deploymentPhase <= DeploymentPhase.Testnet:
|
||||||
|
extraFlags.incl experimental
|
||||||
|
if config.deploymentPhase <= DeploymentPhase.Devnet:
|
||||||
|
extraFlags.incl lowParticipation
|
||||||
let
|
let
|
||||||
extraFlags =
|
|
||||||
if shouldEnableTestFeatures: {enableTestFeatures, lowParticipation}
|
|
||||||
else: {enableTestFeatures}
|
|
||||||
chainDagFlags =
|
chainDagFlags =
|
||||||
if config.strictVerification: {strictVerification}
|
if config.strictVerification: {strictVerification}
|
||||||
else: {}
|
else: {}
|
||||||
|
@ -548,8 +549,7 @@ proc init*(T: type BeaconNode,
|
||||||
|
|
||||||
dag = loadChainDag(
|
dag = loadChainDag(
|
||||||
config, cfg, db, eventBus,
|
config, cfg, db, eventBus,
|
||||||
validatorMonitor, networkGenesisValidatorsRoot,
|
validatorMonitor, networkGenesisValidatorsRoot)
|
||||||
config.deploymentPhase <= DeploymentPhase.Testnet)
|
|
||||||
genesisTime = getStateField(dag.headState, genesis_time)
|
genesisTime = getStateField(dag.headState, genesis_time)
|
||||||
beaconClock = BeaconClock.init(genesisTime)
|
beaconClock = BeaconClock.init(genesisTime)
|
||||||
getBeaconTime = beaconClock.getBeaconTimeFn()
|
getBeaconTime = beaconClock.getBeaconTimeFn()
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# beacon_chain
|
# beacon_chain
|
||||||
# Copyright (c) 2021-2022 Status Research & Development GmbH
|
# Copyright (c) 2021-2023 Status Research & Development GmbH
|
||||||
# Licensed and distributed under either of
|
# Licensed and distributed under either of
|
||||||
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
|
# * 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).
|
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
|
||||||
|
@ -82,7 +82,7 @@ proc installDebugApiHandlers*(router: var RestRouter, node: BeaconNode) =
|
||||||
)
|
)
|
||||||
|
|
||||||
# https://github.com/ethereum/beacon-APIs/pull/232
|
# https://github.com/ethereum/beacon-APIs/pull/232
|
||||||
if node.config.debugForkChoice:
|
if node.config.debugForkChoice or experimental in node.dag.updateFlags:
|
||||||
router.api(MethodGet,
|
router.api(MethodGet,
|
||||||
"/eth/v1/debug/fork_choice") do () -> RestApiResponse:
|
"/eth/v1/debug/fork_choice") do () -> RestApiResponse:
|
||||||
type
|
type
|
||||||
|
@ -109,17 +109,6 @@ proc installDebugApiHandlers*(router: var RestRouter, node: BeaconNode) =
|
||||||
var responses: seq[ForkChoiceResponse]
|
var responses: seq[ForkChoiceResponse]
|
||||||
for item in node.attestationPool[].forkChoice.backend.proto_array:
|
for item in node.attestationPool[].forkChoice.backend.proto_array:
|
||||||
let
|
let
|
||||||
bid = node.dag.getBlockId(item.root)
|
|
||||||
slot =
|
|
||||||
if bid.isOk:
|
|
||||||
bid.unsafeGet.slot
|
|
||||||
else:
|
|
||||||
FAR_FUTURE_SLOT
|
|
||||||
executionPayloadRoot =
|
|
||||||
if bid.isOk:
|
|
||||||
node.dag.loadExecutionBlockRoot(bid.unsafeGet)
|
|
||||||
else:
|
|
||||||
ZERO_HASH
|
|
||||||
unrealized = item.unrealized.get(item.checkpoints)
|
unrealized = item.unrealized.get(item.checkpoints)
|
||||||
u_justified_checkpoint =
|
u_justified_checkpoint =
|
||||||
if unrealized.justified != item.checkpoints.justified:
|
if unrealized.justified != item.checkpoints.justified:
|
||||||
|
@ -133,14 +122,14 @@ proc installDebugApiHandlers*(router: var RestRouter, node: BeaconNode) =
|
||||||
none(Checkpoint)
|
none(Checkpoint)
|
||||||
|
|
||||||
responses.add ForkChoiceResponse(
|
responses.add ForkChoiceResponse(
|
||||||
slot: slot,
|
slot: item.bid.slot,
|
||||||
block_root: item.root,
|
block_root: item.bid.root,
|
||||||
parent_root: item.parent,
|
parent_root: item.parent,
|
||||||
justified_epoch: item.checkpoints.justified.epoch,
|
justified_epoch: item.checkpoints.justified.epoch,
|
||||||
finalized_epoch: item.checkpoints.finalized.epoch,
|
finalized_epoch: item.checkpoints.finalized.epoch,
|
||||||
weight: cast[uint64](item.weight),
|
weight: cast[uint64](item.weight),
|
||||||
execution_optimistic: node.dag.is_optimistic(item.root),
|
execution_optimistic: node.dag.is_optimistic(item.bid.root),
|
||||||
execution_payload_root: executionPayloadRoot,
|
execution_payload_root: node.dag.loadExecutionBlockRoot(item.bid),
|
||||||
extra_data: some ForkChoiceResponseExtraData(
|
extra_data: some ForkChoiceResponseExtraData(
|
||||||
justified_root: item.checkpoints.justified.root,
|
justified_root: item.checkpoints.justified.root,
|
||||||
finalized_root: item.checkpoints.finalized.root,
|
finalized_root: item.checkpoints.finalized.root,
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
# beacon_chain
|
# beacon_chain
|
||||||
# Copyright (c) 2018-2022 Status Research & Development GmbH
|
# Copyright (c) 2018-2023 Status Research & Development GmbH
|
||||||
# Licensed and distributed under either of
|
# Licensed and distributed under either of
|
||||||
# * MIT license (license terms in the root directory or at https://opensource.org/licenses/MIT).
|
# * 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).
|
# * Apache v2 license (license terms in the root directory or at https://www.apache.org/licenses/LICENSE-2.0).
|
||||||
|
@ -46,7 +46,7 @@ type
|
||||||
justified_state_balances*: seq[Gwei]
|
justified_state_balances*: seq[Gwei]
|
||||||
expected_head*: Eth2Digest
|
expected_head*: Eth2Digest
|
||||||
of ProcessBlock:
|
of ProcessBlock:
|
||||||
root*: Eth2Digest
|
bid*: BlockId
|
||||||
parent_root*: Eth2Digest
|
parent_root*: Eth2Digest
|
||||||
blk_checkpoints*: FinalityCheckpoints
|
blk_checkpoints*: FinalityCheckpoints
|
||||||
of ProcessAttestation:
|
of ProcessAttestation:
|
||||||
|
@ -54,7 +54,7 @@ type
|
||||||
block_root*: Eth2Digest
|
block_root*: Eth2Digest
|
||||||
target_epoch*: Epoch
|
target_epoch*: Epoch
|
||||||
of Prune: # ProtoArray specific
|
of Prune: # ProtoArray specific
|
||||||
finalized_root*: Eth2Digest
|
prune_checkpoints*: FinalityCheckpoints
|
||||||
expected_len*: int
|
expected_len*: int
|
||||||
|
|
||||||
func apply(ctx: var ForkChoiceBackend, id: int, op: Operation) =
|
func apply(ctx: var ForkChoiceBackend, id: int, op: Operation) =
|
||||||
|
@ -79,11 +79,11 @@ func apply(ctx: var ForkChoiceBackend, id: int, op: Operation) =
|
||||||
debugEcho &" Detected an expected invalid head from justified checkpoint {op.checkpoints.justified}, finalized checkpoint {op.checkpoints.finalized}"
|
debugEcho &" Detected an expected invalid head from justified checkpoint {op.checkpoints.justified}, finalized checkpoint {op.checkpoints.finalized}"
|
||||||
of ProcessBlock:
|
of ProcessBlock:
|
||||||
let r = ctx.process_block(
|
let r = ctx.process_block(
|
||||||
block_root = op.root,
|
bid = op.bid,
|
||||||
parent_root = op.parent_root,
|
parent_root = op.parent_root,
|
||||||
checkpoints = op.blk_checkpoints)
|
checkpoints = op.blk_checkpoints)
|
||||||
doAssert r.isOk(), &"process_block (op #{id}) returned an error: {r.error}"
|
doAssert r.isOk(), &"process_block (op #{id}) returned an error: {r.error}"
|
||||||
debugEcho " Processed block 0x", op.root, " with parent 0x", op.parent_root, " and justified checkpoint ", op.blk_checkpoints.justified
|
debugEcho " Processed block 0x", op.bid.root, " with parent 0x", op.parent_root, " and justified checkpoint ", op.blk_checkpoints.justified
|
||||||
of ProcessAttestation:
|
of ProcessAttestation:
|
||||||
ctx.process_attestation(
|
ctx.process_attestation(
|
||||||
validator_index = op.validator_index,
|
validator_index = op.validator_index,
|
||||||
|
@ -91,11 +91,11 @@ func apply(ctx: var ForkChoiceBackend, id: int, op: Operation) =
|
||||||
target_epoch = op.target_epoch)
|
target_epoch = op.target_epoch)
|
||||||
debugEcho " Processed att target 0x", op.block_root, " from validator ", op.validator_index, " for epoch ", op.target_epoch
|
debugEcho " Processed att target 0x", op.block_root, " from validator ", op.validator_index, " for epoch ", op.target_epoch
|
||||||
of Prune:
|
of Prune:
|
||||||
let r = ctx.prune(op.finalized_root)
|
let r = ctx.prune(op.prune_checkpoints)
|
||||||
doAssert r.isOk(), &"prune (op #{id}) returned an error: {r.error}"
|
doAssert r.isOk(), &"prune (op #{id}) returned an error: {r.error}"
|
||||||
doAssert ctx.proto_array.nodes.len == op.expected_len,
|
doAssert ctx.proto_array.nodes.len == op.expected_len,
|
||||||
&"prune (op #{id}): the resulting length ({ctx.proto_array.nodes.len}) was not expected ({op.expected_len})"
|
&"prune (op #{id}): the resulting length ({ctx.proto_array.nodes.len}) was not expected ({op.expected_len})"
|
||||||
debugEcho " Maybe_pruned block preceding finalized block 0x", op.finalized_root
|
debugEcho " Maybe_pruned block preceding finalized block 0x", op.prune_checkpoints.finalized.root
|
||||||
|
|
||||||
func run*(ctx: var ForkChoiceBackend, ops: seq[Operation]) =
|
func run*(ctx: var ForkChoiceBackend, ops: seq[Operation]) =
|
||||||
## Apply a sequence of fork-choice operations on a store
|
## Apply a sequence of fork-choice operations on a store
|
||||||
|
|
|
@ -41,7 +41,9 @@ func setup_finality_01(): tuple[fork_choice: ForkChoiceBackend, ops: seq[Operati
|
||||||
# 3 <- just: 2, fin: 1
|
# 3 <- just: 2, fin: 1
|
||||||
result.ops.add Operation(
|
result.ops.add Operation(
|
||||||
kind: ProcessBlock,
|
kind: ProcessBlock,
|
||||||
root: fakeHash(1),
|
bid: BlockId(
|
||||||
|
slot: Epoch(1).start_slot,
|
||||||
|
root: fakeHash(1)),
|
||||||
parent_root: GenesisRoot,
|
parent_root: GenesisRoot,
|
||||||
blk_checkpoints: FinalityCheckpoints(
|
blk_checkpoints: FinalityCheckpoints(
|
||||||
justified: Checkpoint(root: GenesisRoot, epoch: Epoch(0)),
|
justified: Checkpoint(root: GenesisRoot, epoch: Epoch(0)),
|
||||||
|
@ -49,7 +51,9 @@ func setup_finality_01(): tuple[fork_choice: ForkChoiceBackend, ops: seq[Operati
|
||||||
|
|
||||||
result.ops.add Operation(
|
result.ops.add Operation(
|
||||||
kind: ProcessBlock,
|
kind: ProcessBlock,
|
||||||
root: fakeHash(2),
|
bid: BlockId(
|
||||||
|
slot: Epoch(2).start_slot,
|
||||||
|
root: fakeHash(2)),
|
||||||
parent_root: fakeHash(1),
|
parent_root: fakeHash(1),
|
||||||
blk_checkpoints: FinalityCheckpoints(
|
blk_checkpoints: FinalityCheckpoints(
|
||||||
justified: Checkpoint(root: fakeHash(1), epoch: Epoch(1)),
|
justified: Checkpoint(root: fakeHash(1), epoch: Epoch(1)),
|
||||||
|
@ -57,7 +61,9 @@ func setup_finality_01(): tuple[fork_choice: ForkChoiceBackend, ops: seq[Operati
|
||||||
|
|
||||||
result.ops.add Operation(
|
result.ops.add Operation(
|
||||||
kind: ProcessBlock,
|
kind: ProcessBlock,
|
||||||
root: fakeHash(3),
|
bid: BlockId(
|
||||||
|
slot: Epoch(3).start_slot,
|
||||||
|
root: fakeHash(3)),
|
||||||
parent_root: fakeHash(2),
|
parent_root: fakeHash(2),
|
||||||
blk_Checkpoints: FinalityCheckpoints(
|
blk_Checkpoints: FinalityCheckpoints(
|
||||||
justified: Checkpoint(root: fakeHash(2), epoch: Epoch(2)),
|
justified: Checkpoint(root: fakeHash(2), epoch: Epoch(2)),
|
||||||
|
|
|
@ -47,7 +47,9 @@ func setup_finality_02(): tuple[fork_choice: ForkChoiceBackend, ops: seq[Operati
|
||||||
# Left branch
|
# Left branch
|
||||||
result.ops.add Operation(
|
result.ops.add Operation(
|
||||||
kind: ProcessBlock,
|
kind: ProcessBlock,
|
||||||
root: fakeHash(1),
|
bid: BlockId(
|
||||||
|
slot: Slot(1),
|
||||||
|
root: fakeHash(1)),
|
||||||
parent_root: GenesisRoot,
|
parent_root: GenesisRoot,
|
||||||
blk_checkpoints: FinalityCheckpoints(
|
blk_checkpoints: FinalityCheckpoints(
|
||||||
justified: Checkpoint(root: GenesisRoot, epoch: Epoch(0)),
|
justified: Checkpoint(root: GenesisRoot, epoch: Epoch(0)),
|
||||||
|
@ -55,7 +57,9 @@ func setup_finality_02(): tuple[fork_choice: ForkChoiceBackend, ops: seq[Operati
|
||||||
|
|
||||||
result.ops.add Operation(
|
result.ops.add Operation(
|
||||||
kind: ProcessBlock,
|
kind: ProcessBlock,
|
||||||
root: fakeHash(3),
|
bid: BlockId(
|
||||||
|
slot: Epoch(2).start_slot,
|
||||||
|
root: fakeHash(3)),
|
||||||
parent_root: fakeHash(1),
|
parent_root: fakeHash(1),
|
||||||
blk_checkpoints: FinalityCheckpoints(
|
blk_checkpoints: FinalityCheckpoints(
|
||||||
justified: Checkpoint(root: fakeHash(1), epoch: Epoch(1)),
|
justified: Checkpoint(root: fakeHash(1), epoch: Epoch(1)),
|
||||||
|
@ -63,7 +67,9 @@ func setup_finality_02(): tuple[fork_choice: ForkChoiceBackend, ops: seq[Operati
|
||||||
|
|
||||||
result.ops.add Operation(
|
result.ops.add Operation(
|
||||||
kind: ProcessBlock,
|
kind: ProcessBlock,
|
||||||
root: fakeHash(5),
|
bid: BlockId(
|
||||||
|
slot: Epoch(2).start_slot + 2,
|
||||||
|
root: fakeHash(5)),
|
||||||
parent_root: fakeHash(3),
|
parent_root: fakeHash(3),
|
||||||
blk_checkpoints: FinalityCheckpoints(
|
blk_checkpoints: FinalityCheckpoints(
|
||||||
justified: Checkpoint(root: fakeHash(1), epoch: Epoch(1)),
|
justified: Checkpoint(root: fakeHash(1), epoch: Epoch(1)),
|
||||||
|
@ -71,7 +77,9 @@ func setup_finality_02(): tuple[fork_choice: ForkChoiceBackend, ops: seq[Operati
|
||||||
|
|
||||||
result.ops.add Operation(
|
result.ops.add Operation(
|
||||||
kind: ProcessBlock,
|
kind: ProcessBlock,
|
||||||
root: fakeHash(7),
|
bid: BlockId(
|
||||||
|
slot: Epoch(2).start_slot + 4,
|
||||||
|
root: fakeHash(7)),
|
||||||
parent_root: fakeHash(5),
|
parent_root: fakeHash(5),
|
||||||
blk_checkpoints: FinalityCheckpoints(
|
blk_checkpoints: FinalityCheckpoints(
|
||||||
justified: Checkpoint(root: fakeHash(1), epoch: Epoch(1)),
|
justified: Checkpoint(root: fakeHash(1), epoch: Epoch(1)),
|
||||||
|
@ -79,7 +87,9 @@ func setup_finality_02(): tuple[fork_choice: ForkChoiceBackend, ops: seq[Operati
|
||||||
|
|
||||||
result.ops.add Operation(
|
result.ops.add Operation(
|
||||||
kind: ProcessBlock,
|
kind: ProcessBlock,
|
||||||
root: fakeHash(9),
|
bid: BlockId(
|
||||||
|
slot: Epoch(3).start_slot,
|
||||||
|
root: fakeHash(9)),
|
||||||
parent_root: fakeHash(7),
|
parent_root: fakeHash(7),
|
||||||
blk_checkpoints: FinalityCheckpoints(
|
blk_checkpoints: FinalityCheckpoints(
|
||||||
justified: Checkpoint(root: fakeHash(3), epoch: Epoch(2)),
|
justified: Checkpoint(root: fakeHash(3), epoch: Epoch(2)),
|
||||||
|
@ -102,7 +112,9 @@ func setup_finality_02(): tuple[fork_choice: ForkChoiceBackend, ops: seq[Operati
|
||||||
# Right branch
|
# Right branch
|
||||||
result.ops.add Operation(
|
result.ops.add Operation(
|
||||||
kind: ProcessBlock,
|
kind: ProcessBlock,
|
||||||
root: fakeHash(2),
|
bid: BlockId(
|
||||||
|
slot: Slot(2),
|
||||||
|
root: fakeHash(2)),
|
||||||
parent_root: GenesisRoot,
|
parent_root: GenesisRoot,
|
||||||
blk_checkpoints: FinalityCheckpoints(
|
blk_checkpoints: FinalityCheckpoints(
|
||||||
justified: Checkpoint(root: GenesisRoot, epoch: Epoch(0)),
|
justified: Checkpoint(root: GenesisRoot, epoch: Epoch(0)),
|
||||||
|
@ -110,7 +122,9 @@ func setup_finality_02(): tuple[fork_choice: ForkChoiceBackend, ops: seq[Operati
|
||||||
|
|
||||||
result.ops.add Operation(
|
result.ops.add Operation(
|
||||||
kind: ProcessBlock,
|
kind: ProcessBlock,
|
||||||
root: fakeHash(4),
|
bid: BlockId(
|
||||||
|
slot: Epoch(1).start_slot + 1,
|
||||||
|
root: fakeHash(4)),
|
||||||
parent_root: fakeHash(2),
|
parent_root: fakeHash(2),
|
||||||
blk_checkpoints: FinalityCheckpoints(
|
blk_checkpoints: FinalityCheckpoints(
|
||||||
justified: Checkpoint(root: GenesisRoot, epoch: Epoch(0)),
|
justified: Checkpoint(root: GenesisRoot, epoch: Epoch(0)),
|
||||||
|
@ -118,7 +132,9 @@ func setup_finality_02(): tuple[fork_choice: ForkChoiceBackend, ops: seq[Operati
|
||||||
|
|
||||||
result.ops.add Operation(
|
result.ops.add Operation(
|
||||||
kind: ProcessBlock,
|
kind: ProcessBlock,
|
||||||
root: fakeHash(6),
|
bid: BlockId(
|
||||||
|
slot: Epoch(2).start_slot + 3,
|
||||||
|
root: fakeHash(6)),
|
||||||
parent_root: fakeHash(4),
|
parent_root: fakeHash(4),
|
||||||
blk_checkpoints: FinalityCheckpoints(
|
blk_checkpoints: FinalityCheckpoints(
|
||||||
justified: Checkpoint(root: GenesisRoot, epoch: Epoch(0)),
|
justified: Checkpoint(root: GenesisRoot, epoch: Epoch(0)),
|
||||||
|
@ -126,7 +142,9 @@ func setup_finality_02(): tuple[fork_choice: ForkChoiceBackend, ops: seq[Operati
|
||||||
|
|
||||||
result.ops.add Operation(
|
result.ops.add Operation(
|
||||||
kind: ProcessBlock,
|
kind: ProcessBlock,
|
||||||
root: fakeHash(8),
|
bid: BlockId(
|
||||||
|
slot: Epoch(3).start_slot + 1,
|
||||||
|
root: fakeHash(8)),
|
||||||
parent_root: fakeHash(6),
|
parent_root: fakeHash(6),
|
||||||
blk_checkpoints: FinalityCheckpoints(
|
blk_checkpoints: FinalityCheckpoints(
|
||||||
justified: Checkpoint(root: fakeHash(2), epoch: Epoch(1)),
|
justified: Checkpoint(root: fakeHash(2), epoch: Epoch(1)),
|
||||||
|
@ -134,7 +152,9 @@ func setup_finality_02(): tuple[fork_choice: ForkChoiceBackend, ops: seq[Operati
|
||||||
|
|
||||||
result.ops.add Operation(
|
result.ops.add Operation(
|
||||||
kind: ProcessBlock,
|
kind: ProcessBlock,
|
||||||
root: fakeHash(10),
|
bid: BlockId(
|
||||||
|
slot: Epoch(5).start_slot + 1,
|
||||||
|
root: fakeHash(10)),
|
||||||
parent_root: fakeHash(8),
|
parent_root: fakeHash(8),
|
||||||
blk_checkpoints: FinalityCheckpoints(
|
blk_checkpoints: FinalityCheckpoints(
|
||||||
justified: Checkpoint(root: fakeHash(4), epoch: Epoch(2)),
|
justified: Checkpoint(root: fakeHash(4), epoch: Epoch(2)),
|
||||||
|
|
|
@ -38,7 +38,9 @@ func setup_no_votes(): tuple[fork_choice: ForkChoiceBackend, ops: seq[Operation]
|
||||||
# 2
|
# 2
|
||||||
result.ops.add Operation(
|
result.ops.add Operation(
|
||||||
kind: ProcessBlock,
|
kind: ProcessBlock,
|
||||||
root: fakeHash(2),
|
bid: BlockId(
|
||||||
|
slot: Epoch(3).start_slot + 2,
|
||||||
|
root: fakeHash(2)),
|
||||||
parent_root: GenesisRoot,
|
parent_root: GenesisRoot,
|
||||||
blk_checkpoints: FinalityCheckpoints(
|
blk_checkpoints: FinalityCheckpoints(
|
||||||
justified: Checkpoint(root: GenesisRoot, epoch: Epoch(1)),
|
justified: Checkpoint(root: GenesisRoot, epoch: Epoch(1)),
|
||||||
|
@ -64,7 +66,9 @@ func setup_no_votes(): tuple[fork_choice: ForkChoiceBackend, ops: seq[Operation]
|
||||||
# 2 1
|
# 2 1
|
||||||
result.ops.add Operation(
|
result.ops.add Operation(
|
||||||
kind: ProcessBlock,
|
kind: ProcessBlock,
|
||||||
root: fakeHash(1),
|
bid: BlockId(
|
||||||
|
slot: Epoch(3).start_slot + 1,
|
||||||
|
root: fakeHash(1)),
|
||||||
parent_root: GenesisRoot,
|
parent_root: GenesisRoot,
|
||||||
blk_checkpoints: FinalityCheckpoints(
|
blk_checkpoints: FinalityCheckpoints(
|
||||||
justified: Checkpoint(root: GenesisRoot, epoch: Epoch(1)),
|
justified: Checkpoint(root: GenesisRoot, epoch: Epoch(1)),
|
||||||
|
@ -92,7 +96,9 @@ func setup_no_votes(): tuple[fork_choice: ForkChoiceBackend, ops: seq[Operation]
|
||||||
# 3
|
# 3
|
||||||
result.ops.add Operation(
|
result.ops.add Operation(
|
||||||
kind: ProcessBlock,
|
kind: ProcessBlock,
|
||||||
root: fakeHash(3),
|
bid: BlockId(
|
||||||
|
slot: Epoch(3).start_slot + 3,
|
||||||
|
root: fakeHash(3)),
|
||||||
parent_root: fakeHash(1),
|
parent_root: fakeHash(1),
|
||||||
blk_checkpoints: FinalityCheckpoints(
|
blk_checkpoints: FinalityCheckpoints(
|
||||||
justified: Checkpoint(root: GenesisRoot, epoch: Epoch(1)),
|
justified: Checkpoint(root: GenesisRoot, epoch: Epoch(1)),
|
||||||
|
@ -122,7 +128,9 @@ func setup_no_votes(): tuple[fork_choice: ForkChoiceBackend, ops: seq[Operation]
|
||||||
# 4 3
|
# 4 3
|
||||||
result.ops.add Operation(
|
result.ops.add Operation(
|
||||||
kind: ProcessBlock,
|
kind: ProcessBlock,
|
||||||
root: fakeHash(4),
|
bid: BlockId(
|
||||||
|
slot: Epoch(3).start_slot + 4,
|
||||||
|
root: fakeHash(4)),
|
||||||
parent_root: fakeHash(2),
|
parent_root: fakeHash(2),
|
||||||
blk_checkpoints: FinalityCheckpoints(
|
blk_checkpoints: FinalityCheckpoints(
|
||||||
justified: Checkpoint(root: GenesisRoot, epoch: Epoch(1)),
|
justified: Checkpoint(root: GenesisRoot, epoch: Epoch(1)),
|
||||||
|
@ -154,7 +162,9 @@ func setup_no_votes(): tuple[fork_choice: ForkChoiceBackend, ops: seq[Operation]
|
||||||
# 5 <- justified epoch = 2
|
# 5 <- justified epoch = 2
|
||||||
result.ops.add Operation(
|
result.ops.add Operation(
|
||||||
kind: ProcessBlock,
|
kind: ProcessBlock,
|
||||||
root: fakeHash(5),
|
bid: BlockId(
|
||||||
|
slot: Epoch(4).start_slot,
|
||||||
|
root: fakeHash(5)),
|
||||||
parent_root: fakeHash(4),
|
parent_root: fakeHash(4),
|
||||||
blk_checkpoints: FinalityCheckpoints(
|
blk_checkpoints: FinalityCheckpoints(
|
||||||
justified: Checkpoint(root: fakeHash(5), epoch: Epoch(2)),
|
justified: Checkpoint(root: fakeHash(5), epoch: Epoch(2)),
|
||||||
|
@ -221,7 +231,9 @@ func setup_no_votes(): tuple[fork_choice: ForkChoiceBackend, ops: seq[Operation]
|
||||||
# 6
|
# 6
|
||||||
result.ops.add Operation(
|
result.ops.add Operation(
|
||||||
kind: ProcessBlock,
|
kind: ProcessBlock,
|
||||||
root: fakeHash(6),
|
bid: BlockId(
|
||||||
|
slot: Epoch(4).start_slot + 1,
|
||||||
|
root: fakeHash(6)),
|
||||||
parent_root: fakeHash(5),
|
parent_root: fakeHash(5),
|
||||||
blk_checkpoints: FinalityCheckpoints(
|
blk_checkpoints: FinalityCheckpoints(
|
||||||
justified: Checkpoint(root: fakeHash(5), epoch: Epoch(2)),
|
justified: Checkpoint(root: fakeHash(5), epoch: Epoch(2)),
|
||||||
|
|
|
@ -38,7 +38,9 @@ func setup_votes(): tuple[fork_choice: ForkChoiceBackend, ops: seq[Operation]] =
|
||||||
# 2
|
# 2
|
||||||
result.ops.add Operation(
|
result.ops.add Operation(
|
||||||
kind: ProcessBlock,
|
kind: ProcessBlock,
|
||||||
root: fakeHash(2),
|
bid: BlockId(
|
||||||
|
slot: Epoch(1).start_slot + 2,
|
||||||
|
root: fakeHash(2)),
|
||||||
parent_root: GenesisRoot,
|
parent_root: GenesisRoot,
|
||||||
blk_checkpoints: FinalityCheckpoints(
|
blk_checkpoints: FinalityCheckpoints(
|
||||||
justified: Checkpoint(root: GenesisRoot, epoch: Epoch(1)),
|
justified: Checkpoint(root: GenesisRoot, epoch: Epoch(1)),
|
||||||
|
@ -64,7 +66,9 @@ func setup_votes(): tuple[fork_choice: ForkChoiceBackend, ops: seq[Operation]] =
|
||||||
# 2 1
|
# 2 1
|
||||||
result.ops.add Operation(
|
result.ops.add Operation(
|
||||||
kind: ProcessBlock,
|
kind: ProcessBlock,
|
||||||
root: fakeHash(1),
|
bid: BlockId(
|
||||||
|
slot: Epoch(1).start_slot + 1,
|
||||||
|
root: fakeHash(1)),
|
||||||
parent_root: GenesisRoot,
|
parent_root: GenesisRoot,
|
||||||
blk_checkpoints: FinalityCheckpoints(
|
blk_checkpoints: FinalityCheckpoints(
|
||||||
justified: Checkpoint(root: GenesisRoot, epoch: Epoch(1)),
|
justified: Checkpoint(root: GenesisRoot, epoch: Epoch(1)),
|
||||||
|
@ -140,7 +144,9 @@ func setup_votes(): tuple[fork_choice: ForkChoiceBackend, ops: seq[Operation]] =
|
||||||
# 3
|
# 3
|
||||||
result.ops.add Operation(
|
result.ops.add Operation(
|
||||||
kind: ProcessBlock,
|
kind: ProcessBlock,
|
||||||
root: fakeHash(3),
|
bid: BlockId(
|
||||||
|
slot: Epoch(1).start_slot + 3,
|
||||||
|
root: fakeHash(3)),
|
||||||
parent_root: fakeHash(1),
|
parent_root: fakeHash(1),
|
||||||
blk_checkpoints: FinalityCheckpoints(
|
blk_checkpoints: FinalityCheckpoints(
|
||||||
justified: Checkpoint(root: GenesisRoot, epoch: Epoch(1)),
|
justified: Checkpoint(root: GenesisRoot, epoch: Epoch(1)),
|
||||||
|
@ -226,7 +232,9 @@ func setup_votes(): tuple[fork_choice: ForkChoiceBackend, ops: seq[Operation]] =
|
||||||
# 4
|
# 4
|
||||||
result.ops.add Operation(
|
result.ops.add Operation(
|
||||||
kind: ProcessBlock,
|
kind: ProcessBlock,
|
||||||
root: fakeHash(4),
|
bid: BlockId(
|
||||||
|
slot: Epoch(1).start_slot + 4,
|
||||||
|
root: fakeHash(4)),
|
||||||
parent_root: fakeHash(3),
|
parent_root: fakeHash(3),
|
||||||
blk_checkpoints: FinalityCheckpoints(
|
blk_checkpoints: FinalityCheckpoints(
|
||||||
justified: Checkpoint(root: GenesisRoot, epoch: Epoch(1)),
|
justified: Checkpoint(root: GenesisRoot, epoch: Epoch(1)),
|
||||||
|
@ -262,7 +270,9 @@ func setup_votes(): tuple[fork_choice: ForkChoiceBackend, ops: seq[Operation]] =
|
||||||
# 5 <- justified epoch = 2
|
# 5 <- justified epoch = 2
|
||||||
result.ops.add Operation(
|
result.ops.add Operation(
|
||||||
kind: ProcessBlock,
|
kind: ProcessBlock,
|
||||||
root: fakeHash(5),
|
bid: BlockId(
|
||||||
|
slot: Epoch(2).start_slot,
|
||||||
|
root: fakeHash(5)),
|
||||||
parent_root: fakeHash(4),
|
parent_root: fakeHash(4),
|
||||||
blk_checkpoints: FinalityCheckpoints(
|
blk_checkpoints: FinalityCheckpoints(
|
||||||
justified: Checkpoint(root: fakeHash(5), epoch: Epoch(2)),
|
justified: Checkpoint(root: fakeHash(5), epoch: Epoch(2)),
|
||||||
|
@ -300,7 +310,9 @@ func setup_votes(): tuple[fork_choice: ForkChoiceBackend, ops: seq[Operation]] =
|
||||||
# 5 6 <- justified epoch = 0
|
# 5 6 <- justified epoch = 0
|
||||||
result.ops.add Operation(
|
result.ops.add Operation(
|
||||||
kind: ProcessBlock,
|
kind: ProcessBlock,
|
||||||
root: fakeHash(6),
|
bid: BlockId(
|
||||||
|
slot: Epoch(2).start_slot + 1,
|
||||||
|
root: fakeHash(6)),
|
||||||
parent_root: fakeHash(4),
|
parent_root: fakeHash(4),
|
||||||
blk_checkpoints: FinalityCheckpoints(
|
blk_checkpoints: FinalityCheckpoints(
|
||||||
justified: Checkpoint(root: GenesisRoot, epoch: Epoch(1)),
|
justified: Checkpoint(root: GenesisRoot, epoch: Epoch(1)),
|
||||||
|
@ -349,7 +361,9 @@ func setup_votes(): tuple[fork_choice: ForkChoiceBackend, ops: seq[Operation]] =
|
||||||
# 9
|
# 9
|
||||||
result.ops.add Operation(
|
result.ops.add Operation(
|
||||||
kind: ProcessBlock,
|
kind: ProcessBlock,
|
||||||
root: fakeHash(7),
|
bid: BlockId(
|
||||||
|
slot: Epoch(2).start_slot + 2,
|
||||||
|
root: fakeHash(7)),
|
||||||
parent_root: fakeHash(5),
|
parent_root: fakeHash(5),
|
||||||
blk_checkpoints: FinalityCheckpoints(
|
blk_checkpoints: FinalityCheckpoints(
|
||||||
justified: Checkpoint(root: fakeHash(5), epoch: Epoch(2)),
|
justified: Checkpoint(root: fakeHash(5), epoch: Epoch(2)),
|
||||||
|
@ -357,7 +371,9 @@ func setup_votes(): tuple[fork_choice: ForkChoiceBackend, ops: seq[Operation]] =
|
||||||
|
|
||||||
result.ops.add Operation(
|
result.ops.add Operation(
|
||||||
kind: ProcessBlock,
|
kind: ProcessBlock,
|
||||||
root: fakeHash(8),
|
bid: BlockId(
|
||||||
|
slot: Epoch(2).start_slot + 3,
|
||||||
|
root: fakeHash(8)),
|
||||||
parent_root: fakeHash(7),
|
parent_root: fakeHash(7),
|
||||||
blk_checkpoints: FinalityCheckpoints(
|
blk_checkpoints: FinalityCheckpoints(
|
||||||
justified: Checkpoint(root: fakeHash(5), epoch: Epoch(2)),
|
justified: Checkpoint(root: fakeHash(5), epoch: Epoch(2)),
|
||||||
|
@ -366,7 +382,9 @@ func setup_votes(): tuple[fork_choice: ForkChoiceBackend, ops: seq[Operation]] =
|
||||||
# Finalizes 5
|
# Finalizes 5
|
||||||
result.ops.add Operation(
|
result.ops.add Operation(
|
||||||
kind: ProcessBlock,
|
kind: ProcessBlock,
|
||||||
root: fakeHash(9),
|
bid: BlockId(
|
||||||
|
slot: Epoch(2).start_slot + 4,
|
||||||
|
root: fakeHash(9)),
|
||||||
parent_root: fakeHash(8),
|
parent_root: fakeHash(8),
|
||||||
blk_checkpoints: FinalityCheckpoints(
|
blk_checkpoints: FinalityCheckpoints(
|
||||||
justified: Checkpoint(root: fakeHash(5), epoch: Epoch(2)),
|
justified: Checkpoint(root: fakeHash(5), epoch: Epoch(2)),
|
||||||
|
@ -481,7 +499,9 @@ func setup_votes(): tuple[fork_choice: ForkChoiceBackend, ops: seq[Operation]] =
|
||||||
# 9 10
|
# 9 10
|
||||||
result.ops.add Operation(
|
result.ops.add Operation(
|
||||||
kind: ProcessBlock,
|
kind: ProcessBlock,
|
||||||
root: fakeHash(10),
|
bid: BlockId(
|
||||||
|
slot: Epoch(3).start_slot,
|
||||||
|
root: fakeHash(10)),
|
||||||
parent_root: fakeHash(8),
|
parent_root: fakeHash(8),
|
||||||
blk_checkpoints: FinalityCheckpoints(
|
blk_checkpoints: FinalityCheckpoints(
|
||||||
justified: Checkpoint(root: fakeHash(5), epoch: Epoch(2)),
|
justified: Checkpoint(root: fakeHash(5), epoch: Epoch(2)),
|
||||||
|
@ -626,7 +646,9 @@ func setup_votes(): tuple[fork_choice: ForkChoiceBackend, ops: seq[Operation]] =
|
||||||
# - 6 is a discarded chain
|
# - 6 is a discarded chain
|
||||||
result.ops.add Operation(
|
result.ops.add Operation(
|
||||||
kind: Prune,
|
kind: Prune,
|
||||||
finalized_root: fakeHash(5),
|
prune_checkpoints: FinalityCheckpoints(
|
||||||
|
justified: Checkpoint(root: fakeHash(5), epoch: Epoch(2)),
|
||||||
|
finalized: Checkpoint(root: fakeHash(5), epoch: Epoch(2))),
|
||||||
expected_len: 6)
|
expected_len: 6)
|
||||||
|
|
||||||
# Prune shouldn't have changed the head
|
# Prune shouldn't have changed the head
|
||||||
|
@ -651,7 +673,9 @@ func setup_votes(): tuple[fork_choice: ForkChoiceBackend, ops: seq[Operation]] =
|
||||||
# 11
|
# 11
|
||||||
result.ops.add Operation(
|
result.ops.add Operation(
|
||||||
kind: ProcessBlock,
|
kind: ProcessBlock,
|
||||||
root: fakeHash(11),
|
bid: BlockId(
|
||||||
|
slot: Epoch(3).start_slot + 1,
|
||||||
|
root: fakeHash(11)),
|
||||||
parent_root: fakeHash(9),
|
parent_root: fakeHash(9),
|
||||||
blk_checkpoints: FinalityCheckpoints(
|
blk_checkpoints: FinalityCheckpoints(
|
||||||
justified: Checkpoint(root: fakeHash(5), epoch: Epoch(2)),
|
justified: Checkpoint(root: fakeHash(5), epoch: Epoch(2)),
|
||||||
|
|
Loading…
Reference in New Issue