confirmation rule implementation WIP DEBUG DO NOT MERGE
This commit is contained in:
parent
c27a65129b
commit
53d8c63d07
|
@ -133,7 +133,8 @@ proc init*(T: type AttestationPool, dag: ChainDAGRef,
|
|||
# and then to make sure the fork choice data structure doesn't grow
|
||||
# too big - getting an EpochRef can be expensive.
|
||||
forkChoice.backend.process_block(
|
||||
blckRef.bid, blckRef.parent.root, epochRef.checkpoints)
|
||||
blckRef.bid, blckRef.parent.root,
|
||||
epochRef.checkpoints, epochRef.total_active_balance)
|
||||
else:
|
||||
epochRef = dag.getEpochRef(blckRef, blckRef.slot.epoch, false).expect(
|
||||
"Getting an EpochRef should always work for non-finalized blocks")
|
||||
|
@ -777,12 +778,10 @@ proc getBeaconHead*(
|
|||
safeBlock = pool.dag.getBlockRef(safeBlockRoot)
|
||||
safeExecutionPayloadHash =
|
||||
if safeBlock.isErr:
|
||||
# Safe block is currently the justified block determined by fork choice.
|
||||
# If finality already advanced beyond the current justified checkpoint,
|
||||
# e.g., because we have selected a head that did not yet realize the cp,
|
||||
# the justified block may end up not having a `BlockRef` anymore.
|
||||
# Because we know that a different fork already finalized a later point,
|
||||
# let's just report the finalized execution payload hash instead.
|
||||
# If finality already advanced beyond the current safe block,
|
||||
# the safe block may end up not having a `BlockRef` anymore.
|
||||
# Because a different fork already finalized a later point,
|
||||
# report the finalized execution payload hash instead.
|
||||
finalizedExecutionPayloadHash
|
||||
else:
|
||||
pool.dag.loadExecutionBlockHash(safeBlock.get)
|
||||
|
|
|
@ -49,8 +49,10 @@ func compute_deltas(
|
|||
logScope: topics = "fork_choice"
|
||||
|
||||
func init*(
|
||||
T: type ForkChoiceBackend, checkpoints: FinalityCheckpoints): T =
|
||||
T(proto_array: ProtoArray.init(checkpoints))
|
||||
T: type ForkChoiceBackend,
|
||||
checkpoints: FinalityCheckpoints,
|
||||
total_active_balance: Gwei): T =
|
||||
T(proto_array: ProtoArray.init(checkpoints, total_active_balance))
|
||||
|
||||
proc init*(
|
||||
T: type ForkChoice, epochRef: EpochRef, blck: BlockRef): T =
|
||||
|
@ -65,10 +67,12 @@ proc init*(
|
|||
backend: ForkChoiceBackend.init(
|
||||
FinalityCheckpoints(
|
||||
justified: checkpoint,
|
||||
finalized: checkpoint)),
|
||||
finalized: checkpoint),
|
||||
epochRef.total_active_balance),
|
||||
checkpoints: Checkpoints(
|
||||
justified: BalanceCheckpoint(
|
||||
checkpoint: checkpoint,
|
||||
total_active_balance: epochRef.total_active_balance,
|
||||
balances: epochRef.effective_balances),
|
||||
finalized: checkpoint,
|
||||
best_justified: checkpoint))
|
||||
|
@ -94,6 +98,7 @@ proc update_justified(
|
|||
store = self.justified.checkpoint, state = justified
|
||||
self.justified = BalanceCheckpoint(
|
||||
checkpoint: Checkpoint(root: blck.root, epoch: epochRef.epoch),
|
||||
total_active_balance: epochRef.total_active_balance,
|
||||
balances: epochRef.effective_balances)
|
||||
|
||||
proc update_justified(
|
||||
|
@ -256,8 +261,10 @@ func process_block*(self: var ForkChoiceBackend,
|
|||
bid: BlockId,
|
||||
parent_root: Eth2Digest,
|
||||
checkpoints: FinalityCheckpoints,
|
||||
total_active_balance: Gwei,
|
||||
unrealized = none(FinalityCheckpoints)): FcResult[void] =
|
||||
self.proto_array.onBlock(bid, parent_root, checkpoints, unrealized)
|
||||
self.proto_array.onBlock(
|
||||
bid, parent_root, checkpoints, total_active_balance, unrealized)
|
||||
|
||||
proc process_block*(self: var ForkChoice,
|
||||
dag: ChainDAGRef,
|
||||
|
@ -304,24 +311,28 @@ proc process_block*(self: var ForkChoice,
|
|||
blck = shortLog(blckRef), checkpoints = epochRef.checkpoints, unrealized
|
||||
? update_checkpoints(self.checkpoints, dag, unrealized)
|
||||
? process_block(
|
||||
self.backend, blckRef.bid, blck.parent_root, unrealized)
|
||||
self.backend, blckRef.bid, blck.parent_root,
|
||||
unrealized, epochRef.total_active_balance)
|
||||
else:
|
||||
? process_block(
|
||||
self.backend, blckRef.bid, blck.parent_root,
|
||||
epochRef.checkpoints, some unrealized) # Realized in `on_tick`
|
||||
epochRef.checkpoints, epochRef.total_active_balance,
|
||||
some unrealized) # Realized in `on_tick`
|
||||
else:
|
||||
? process_block(
|
||||
self.backend, blckRef.bid, blck.parent_root, epochRef.checkpoints)
|
||||
self.backend, blckRef.bid, blck.parent_root,
|
||||
epochRef.checkpoints, epochRef.total_active_balance)
|
||||
|
||||
ok()
|
||||
|
||||
func find_head*(
|
||||
func find_head(
|
||||
self: var ForkChoiceBackend,
|
||||
current_epoch: Epoch,
|
||||
current_slot: Slot,
|
||||
checkpoints: FinalityCheckpoints,
|
||||
justified_total_active_balance: Gwei,
|
||||
justified_state_balances: seq[Gwei],
|
||||
proposer_boost_root: Eth2Digest
|
||||
): FcResult[Eth2Digest] =
|
||||
): FcResult[tuple[headBlockRoot, safeBlockRoot: Eth2Digest]] =
|
||||
## Returns the new blockchain head
|
||||
|
||||
# Compute deltas with previous call
|
||||
|
@ -336,19 +347,21 @@ func find_head*(
|
|||
|
||||
# Apply score changes
|
||||
? self.proto_array.applyScoreChanges(
|
||||
deltas, current_epoch, checkpoints,
|
||||
justified_state_balances, proposer_boost_root)
|
||||
deltas, current_slot, checkpoints,
|
||||
justified_total_active_balance, proposer_boost_root)
|
||||
|
||||
self.balances = justified_state_balances
|
||||
|
||||
# Find the best block
|
||||
var new_head{.noinit.}: Eth2Digest
|
||||
? self.proto_array.findHead(new_head, checkpoints.justified.root)
|
||||
var
|
||||
new_head {.noinit.}: Eth2Digest
|
||||
confirmed {.noinit.}: Eth2Digest
|
||||
? self.proto_array.findHead(new_head, confirmed, checkpoints.justified.root)
|
||||
|
||||
trace "Fork choice requested",
|
||||
checkpoints, fork_choice_head = shortLog(new_head)
|
||||
|
||||
return ok(new_head)
|
||||
ok (headBlockRoot: new_head, safeBlockRoot: confirmed)
|
||||
|
||||
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-alpha.3/specs/phase0/fork-choice.md#get_head
|
||||
proc get_head*(self: var ForkChoice,
|
||||
|
@ -356,13 +369,16 @@ proc get_head*(self: var ForkChoice,
|
|||
wallTime: BeaconTime): FcResult[Eth2Digest] =
|
||||
? self.update_time(dag, wallTime)
|
||||
|
||||
self.backend.find_head(
|
||||
self.checkpoints.time.slotOrZero.epoch,
|
||||
let res = ? self.backend.find_head(
|
||||
self.checkpoints.time.slotOrZero,
|
||||
FinalityCheckpoints(
|
||||
justified: self.checkpoints.justified.checkpoint,
|
||||
finalized: self.checkpoints.finalized),
|
||||
self.checkpoints.justified.total_active_balance,
|
||||
self.checkpoints.justified.balances,
|
||||
self.checkpoints.proposer_boost_root)
|
||||
self.safeBlockRoot = res.safeBlockRoot
|
||||
ok res.headBlockRoot
|
||||
|
||||
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-alpha.3/fork_choice/safe-block.md#get_safe_beacon_block_root
|
||||
func get_safe_beacon_block_root*(self: ForkChoice): Eth2Digest =
|
||||
|
|
|
@ -88,8 +88,9 @@ type
|
|||
## Subtracted from logical index to get the physical index
|
||||
|
||||
ProtoArray* = object
|
||||
currentEpoch*: Epoch
|
||||
currentSlot*: Slot
|
||||
checkpoints*: FinalityCheckpoints
|
||||
justifiedTotalActiveBalance*: Gwei
|
||||
nodes*: ProtoNodes
|
||||
indices*: Table[Eth2Digest, Index]
|
||||
currentEpochTips*: Table[Index, FinalityCheckpoints]
|
||||
|
@ -100,6 +101,7 @@ type
|
|||
bid*: BlockId
|
||||
parent*: Option[Index]
|
||||
checkpoints*: FinalityCheckpoints
|
||||
totalActiveBalance*: Gwei
|
||||
weight*: int64
|
||||
invalid*: bool
|
||||
bestChild*: Option[Index]
|
||||
|
@ -107,6 +109,7 @@ type
|
|||
|
||||
BalanceCheckpoint* = object
|
||||
checkpoint*: Checkpoint
|
||||
total_active_balance*: Gwei
|
||||
balances*: seq[Gwei]
|
||||
|
||||
Checkpoints* = object
|
||||
|
@ -139,6 +142,7 @@ type
|
|||
ForkChoice* = object
|
||||
backend*: ForkChoiceBackend
|
||||
checkpoints*: Checkpoints
|
||||
safeBlockRoot*: Eth2Digest
|
||||
queuedAttestations*: seq[QueuedAttestation]
|
||||
|
||||
func shortLog*(vote: VoteTracker): auto =
|
||||
|
|
|
@ -72,7 +72,150 @@ func add(nodes: var ProtoNodes, node: ProtoNode) =
|
|||
nodes.buf.add node
|
||||
|
||||
func isPreviousEpochJustified(self: ProtoArray): bool =
|
||||
self.checkpoints.justified.epoch + 1 == self.currentEpoch
|
||||
self.checkpoints.justified.epoch + 1 == self.currentSlot.epoch
|
||||
|
||||
func parentNode(self: ProtoArray, node: ProtoNode): Option[ProtoNode] =
|
||||
if node.parent.isSome:
|
||||
self.nodes[node.parent.unsafeGet]
|
||||
else:
|
||||
none(ProtoNode)
|
||||
|
||||
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-alpha.3/specs/phase0/fork-choice.md#get_checkpoint_block
|
||||
func get_checkpoint_block(
|
||||
self: ProtoArray, node: ProtoNode, epoch: Epoch): Option[ProtoNode] =
|
||||
## Compute the checkpoint block for epoch ``epoch`` in the chain of ``node``
|
||||
let slot = epoch.start_slot
|
||||
var ancestor = some node
|
||||
while ancestor.isSome and ancestor.unsafeGet.bid.slot > slot:
|
||||
if ancestor.unsafeGet.parent.isSome:
|
||||
ancestor = self.nodes[ancestor.unsafeGet.parent.unsafeGet]
|
||||
else:
|
||||
ancestor.reset()
|
||||
ancestor
|
||||
|
||||
# https://github.com/ethereum/consensus-specs/blob/17d528a8ab40d765a7f3f765f370181dc5c795c1/specs/phase0/fork-choice.md#get_proposer_score
|
||||
func get_proposer_score(self: ProtoArray): Gwei =
|
||||
let committeeWeight = self.justifiedTotalActiveBalance div SLOTS_PER_EPOCH
|
||||
(committeeWeight * PROPOSER_SCORE_BOOST) div 100
|
||||
|
||||
# Confirmation rule
|
||||
# ----------------------------------------------------------------------
|
||||
|
||||
# https://github.com/ethereum/consensus-specs/blob/17d528a8ab40d765a7f3f765f370181dc5c795c1/fork_choice/confirmation-rule.md#get_committee_weight_between_slots
|
||||
func get_committee_weight_between_slots(
|
||||
self: ProtoArray, slots: Slice[Slot]): Gwei =
|
||||
## Returns the total weight of committees between ``slots``.
|
||||
## Uses the justified state to compute committee weights.
|
||||
|
||||
# If an entire epoch is covered by the range, return the total active balance
|
||||
let
|
||||
startEpoch = slots.a.epoch
|
||||
endEpoch = slots.b.epoch
|
||||
if endEpoch > startEpoch + 1:
|
||||
return self.justifiedTotalActiveBalance
|
||||
|
||||
let
|
||||
committeeWeight = self.justifiedTotalActiveBalance div SLOTS_PER_EPOCH
|
||||
numCommittees =
|
||||
if startEpoch == endEpoch:
|
||||
slots.len.float
|
||||
else:
|
||||
# A range that spans an epoch boundary, but does not span any full epoch
|
||||
# needs pro-rata calculation
|
||||
let
|
||||
# First, calculate the number of committees in the current epoch
|
||||
numSlotsInCurrentEpoch =
|
||||
slots.b.since_epoch_start + 1
|
||||
# Next, calculate the number of slots remaining in the current epoch
|
||||
remainingSlotsInCurrentEpoch =
|
||||
SLOTS_PER_EPOCH - numSlotsInCurrentEpoch
|
||||
# Then, calculate the number of slots in the previous epoch
|
||||
numSlotsInPreviousEpoch =
|
||||
SLOTS_PER_EPOCH - slots.a.since_epoch_start
|
||||
|
||||
# Each committee from the previous epoch only contributes a
|
||||
# pro-rated weight
|
||||
multiplier =
|
||||
remainingSlotsInCurrentEpoch.float / SLOTS_PER_EPOCH.float
|
||||
numSlotsInCurrentEpoch.float +
|
||||
numSlotsInPreviousEpoch.float * multiplier
|
||||
(numCommittees * committeeWeight.float).Gwei
|
||||
|
||||
# https://github.com/ethereum/consensus-specs/blob/17d528a8ab40d765a7f3f765f370181dc5c795c1/fork_choice/confirmation-rule.md#is_one_confirmed
|
||||
func is_one_confirmed(self: ProtoArray, node, parentNode: ProtoNode): bool =
|
||||
let
|
||||
support = node.weight.float
|
||||
maximumSupport = self.get_committee_weight_between_slots(
|
||||
parentNode.bid.slot + 1 .. self.currentSlot).float
|
||||
proposerScore = self.get_proposer_score().float
|
||||
(support / maximumSupport) >
|
||||
0.5 * proposerScore / maximumSupport +
|
||||
static((50 + confirmation_byzantine_threshold).float / 100.0)
|
||||
|
||||
# https://github.com/ethereum/consensus-specs/blob/17d528a8ab40d765a7f3f765f370181dc5c795c1/fork_choice/confirmation-rule.md#is_lmd_confirmed
|
||||
func is_lmd_confirmed(self: ProtoArray, node: ProtoNode): bool =
|
||||
return
|
||||
if node.bid.root == self.checkpoints.finalized.root:
|
||||
true
|
||||
elif node.bid.slot <= self.checkpoints.finalized.epoch.start_slot:
|
||||
# This block is not in the finalized chain.
|
||||
false
|
||||
else:
|
||||
# Check is_one_confirmed for this block and is_lmd_confirmed for
|
||||
# the preceding chain.
|
||||
let parentNode = self.parentNode(node)
|
||||
if parentNode.isSome:
|
||||
self.is_one_confirmed(node, parentNode.unsafeGet) and
|
||||
self.is_lmd_confirmed(parentNode.unsafeGet)
|
||||
else:
|
||||
false
|
||||
|
||||
# https://github.com/ethereum/consensus-specs/blob/17d528a8ab40d765a7f3f765f370181dc5c795c1/fork_choice/confirmation-rule.md#get_remaining_weight_in_epoch
|
||||
func get_remaining_weight_in_epoch(self: ProtoArray): Gwei =
|
||||
## Returns the total weight of votes for this epoch from future committees
|
||||
## after the current slot
|
||||
let firstSlotNextEpoch = (self.currentSlot.epoch + 1).start_slot
|
||||
self.get_committee_weight_between_slots(
|
||||
self.currentSlot + 1 ..< firstSlotNextEpoch)
|
||||
|
||||
# https://github.com/ethereum/consensus-specs/blob/17d528a8ab40d765a7f3f765f370181dc5c795c1/fork_choice/confirmation-rule.md#is_ffg_confirmed
|
||||
func is_ffg_confirmed(self: ProtoArray, node: ProtoNode): bool =
|
||||
let currentEpoch = self.currentSlot.epoch
|
||||
doAssert node.bid.slot.epoch == currentEpoch
|
||||
|
||||
let checkpointNode = self.get_checkpoint_block(node, currentEpoch)
|
||||
if checkpointNode.isNone:
|
||||
return false
|
||||
|
||||
let
|
||||
remainingFfgWeight = self.get_remaining_weight_in_epoch()
|
||||
totalActiveBalance = checkpointNode.unsafeGet.totalActiveBalance
|
||||
currentWeightInEpoch =
|
||||
|
||||
|
||||
# https://github.com/ethereum/consensus-specs/blob/17d528a8ab40d765a7f3f765f370181dc5c795c1/fork_choice/confirmation-rule.md#is_confirmed
|
||||
func is_confirmed(self: ProtoArray, node: ProtoNode): bool =
|
||||
# This function is only applicable to current epoch blocks
|
||||
let currentEpoch = self.currentSlot.epoch
|
||||
doAssert node.bid.slot.epoch == currentEpoch
|
||||
|
||||
node.checkpoints.justified.epoch + 1 == currentEpoch and
|
||||
self.is_lmd_confirmed(node) and self.is_ffg_confirmed(node)
|
||||
|
||||
# https://github.com/ethereum/consensus-specs/blob/17d528a8ab40d765a7f3f765f370181dc5c795c1/fork_choice/confirmation-rule.md#find_confirmed_block
|
||||
func find_confirmed_block(self: ProtoArray, node: ProtoNode): Eth2Digest =
|
||||
let currentEpoch = self.currentSlot.epoch
|
||||
return
|
||||
if node.bid.slot.epoch != currentEpoch:
|
||||
self.checkpoints.finalized.root
|
||||
elif self.is_confirmed(node):
|
||||
node.bid.root
|
||||
else:
|
||||
let parentNode = self.parentNode(node)
|
||||
if parentNode.isSome:
|
||||
self.find_confirmed_block(parentNode.unsafeGet)
|
||||
else:
|
||||
self.checkpoints.finalized.root
|
||||
|
||||
# Forward declarations
|
||||
# ----------------------------------------------------------------------
|
||||
|
@ -90,13 +233,16 @@ func nodeLeadsToViableHead(
|
|||
# ----------------------------------------------------------------------
|
||||
|
||||
func init*(
|
||||
T: type ProtoArray, checkpoints: FinalityCheckpoints): T =
|
||||
T: type ProtoArray,
|
||||
checkpoints: FinalityCheckpoints,
|
||||
totalActiveBalance: Gwei): T =
|
||||
let node = ProtoNode(
|
||||
bid: BlockId(
|
||||
slot: checkpoints.finalized.epoch.start_slot,
|
||||
root: checkpoints.finalized.root),
|
||||
parent: none(int),
|
||||
checkpoints: checkpoints,
|
||||
totalActiveBalance: totalActiveBalance,
|
||||
weight: 0,
|
||||
invalid: false,
|
||||
bestChild: none(int),
|
||||
|
@ -123,19 +269,11 @@ iterator realizePendingCheckpoints*(
|
|||
# Reset tip tracking for new epoch
|
||||
self.currentEpochTips.clear()
|
||||
|
||||
# https://github.com/ethereum/consensus-specs/blob/v1.3.0/specs/phase0/fork-choice.md#get_weight
|
||||
func calculateProposerBoost(validatorBalances: openArray[Gwei]): uint64 =
|
||||
var total_balance: uint64
|
||||
for balance in validatorBalances:
|
||||
total_balance += balance
|
||||
let committee_weight = total_balance div SLOTS_PER_EPOCH
|
||||
(committee_weight * PROPOSER_SCORE_BOOST) div 100
|
||||
|
||||
func applyScoreChanges*(self: var ProtoArray,
|
||||
deltas: var openArray[Delta],
|
||||
currentEpoch: Epoch,
|
||||
currentSlot: Slot,
|
||||
checkpoints: FinalityCheckpoints,
|
||||
newBalances: openArray[Gwei],
|
||||
justifiedTotalActiveBalance: Gwei,
|
||||
proposerBoostRoot: Eth2Digest): FcResult[void] =
|
||||
## Iterate backwards through the array, touching all nodes and their parents
|
||||
## and potentially the best-child of each parent.
|
||||
|
@ -158,8 +296,9 @@ func applyScoreChanges*(self: var ProtoArray,
|
|||
deltasLen: deltas.len,
|
||||
indicesLen: self.indices.len)
|
||||
|
||||
self.currentEpoch = currentEpoch
|
||||
self.currentSlot = currentSlot
|
||||
self.checkpoints = checkpoints
|
||||
self.justifiedTotalActiveBalance = justifiedTotalActiveBalance
|
||||
|
||||
## Alias
|
||||
# This cannot raise the IndexError exception, how to tell compiler?
|
||||
|
@ -192,7 +331,7 @@ func applyScoreChanges*(self: var ProtoArray,
|
|||
#
|
||||
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-alpha.3/specs/phase0/fork-choice.md#get_weight
|
||||
if (not proposerBoostRoot.isZero) and proposerBoostRoot == node.bid.root:
|
||||
proposerBoostScore = calculateProposerBoost(newBalances)
|
||||
proposerBoostScore = self.get_proposer_score()
|
||||
if nodeDelta >= 0 and
|
||||
high(Delta) - nodeDelta < proposerBoostScore.int64:
|
||||
return err ForkChoiceError(
|
||||
|
@ -268,6 +407,7 @@ func onBlock*(self: var ProtoArray,
|
|||
bid: BlockId,
|
||||
parent: Eth2Digest,
|
||||
checkpoints: FinalityCheckpoints,
|
||||
totalActiveBalance: Gwei,
|
||||
unrealized = none(FinalityCheckpoints)): FcResult[void] =
|
||||
## Register a block with the fork choice
|
||||
## A block `hasParentInForkChoice` may be false
|
||||
|
@ -296,6 +436,7 @@ func onBlock*(self: var ProtoArray,
|
|||
bid: bid,
|
||||
parent: some(parentIdx),
|
||||
checkpoints: checkpoints,
|
||||
totalActiveBalance: totalActiveBalance,
|
||||
weight: 0,
|
||||
invalid: false,
|
||||
bestChild: none(int),
|
||||
|
@ -314,6 +455,7 @@ func onBlock*(self: var ProtoArray,
|
|||
|
||||
func findHead*(self: var ProtoArray,
|
||||
head: var Eth2Digest,
|
||||
confirmed: var Eth2Digest,
|
||||
justifiedRoot: Eth2Digest): FcResult[void] =
|
||||
## Follows the best-descendant links to find the best-block (i.e. head-block)
|
||||
##
|
||||
|
@ -352,6 +494,7 @@ func findHead*(self: var ProtoArray,
|
|||
headCheckpoints: justifiedNode.get().checkpoints)
|
||||
|
||||
head = bestNode.get().bid.root
|
||||
confirmed = self.find_confirmed_block(bestNode.get())
|
||||
ok()
|
||||
|
||||
func prune*(
|
||||
|
@ -534,27 +677,23 @@ func nodeIsViableForHead(
|
|||
# If the previous epoch is justified, the block should be pulled-up.
|
||||
# In this case, check that unrealized justification is higher than the store
|
||||
# and that the voting source is not more than two epochs ago
|
||||
let currentEpoch = self.currentSlot.epoch
|
||||
if not correctJustified and self.isPreviousEpochJustified and
|
||||
node.bid.slot.epoch == self.currentEpoch:
|
||||
node.bid.slot.epoch == 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
|
||||
|
||||
node.checkpoints.justified.epoch + 2 >= 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()
|
||||
let ancestor = self.get_checkpoint_block(
|
||||
node, self.checkpoints.finalized.epoch)
|
||||
if ancestor.isSome:
|
||||
ancestor.unsafeGet.bid.root == self.checkpoints.finalized.root
|
||||
else:
|
||||
|
|
|
@ -185,6 +185,10 @@ proc installConfigApiHandlers*(router: var RestRouter, node: BeaconNode) =
|
|||
Base10.toString(cfg.CHURN_LIMIT_QUOTIENT),
|
||||
PROPOSER_SCORE_BOOST:
|
||||
Base10.toString(PROPOSER_SCORE_BOOST),
|
||||
confirmation_byzantine_threshold:
|
||||
Base10.toString(confirmation_byzantine_threshold),
|
||||
confirmation_slashing_threshold:
|
||||
Base10.toString(confirmation_slashing_threshold),
|
||||
DEPOSIT_CHAIN_ID:
|
||||
Base10.toString(cfg.DEPOSIT_CHAIN_ID),
|
||||
DEPOSIT_NETWORK_ID:
|
||||
|
|
|
@ -48,5 +48,11 @@ const
|
|||
# https://github.com/ethereum/consensus-specs/blob/v1.3.0/specs/phase0/fork-choice.md#configuration
|
||||
PROPOSER_SCORE_BOOST*: uint64 = 40
|
||||
|
||||
# https://github.com/ethereum/consensus-specs/blob/17d528a8ab40d765a7f3f765f370181dc5c795c1/fork_choice/confirmation-rule.md#confirmation-rule
|
||||
confirmation_byzantine_threshold*: uint64 = 33
|
||||
## the maximum percentage of Byzantine validators among the validator set
|
||||
confirmation_slashing_threshold*: uint64 = confirmation_byzantine_threshold
|
||||
## the maximum percentage of slashings among the validator set
|
||||
|
||||
# https://github.com/ethereum/consensus-specs/blob/v1.3.0/specs/phase0/validator.md#misc
|
||||
ATTESTATION_SUBNET_COUNT*: uint64 = 64
|
||||
|
|
|
@ -2802,7 +2802,7 @@
|
|||
"response": {
|
||||
"status": {"operator": "equals", "value": "200"},
|
||||
"headers": [{"key": "Content-Type", "value": "application/json", "operator": "equals"}],
|
||||
"body": [{"operator": "jstructcmps", "start": ["data"], "value": {"MAX_COMMITTEES_PER_SLOT":"","TARGET_COMMITTEE_SIZE":"","MAX_VALIDATORS_PER_COMMITTEE":"","SHUFFLE_ROUND_COUNT":"","HYSTERESIS_QUOTIENT":"","HYSTERESIS_DOWNWARD_MULTIPLIER":"","HYSTERESIS_UPWARD_MULTIPLIER":"","MIN_DEPOSIT_AMOUNT":"","MAX_EFFECTIVE_BALANCE":"","EFFECTIVE_BALANCE_INCREMENT":"","MIN_ATTESTATION_INCLUSION_DELAY":"","SLOTS_PER_EPOCH":"","MIN_SEED_LOOKAHEAD":"","MAX_SEED_LOOKAHEAD":"","EPOCHS_PER_ETH1_VOTING_PERIOD":"","SLOTS_PER_HISTORICAL_ROOT":"","MIN_EPOCHS_TO_INACTIVITY_PENALTY":"","EPOCHS_PER_HISTORICAL_VECTOR":"","EPOCHS_PER_SLASHINGS_VECTOR":"","HISTORICAL_ROOTS_LIMIT":"","VALIDATOR_REGISTRY_LIMIT":"","BASE_REWARD_FACTOR":"","WHISTLEBLOWER_REWARD_QUOTIENT":"","PROPOSER_REWARD_QUOTIENT":"","INACTIVITY_PENALTY_QUOTIENT":"","MIN_SLASHING_PENALTY_QUOTIENT":"","PROPORTIONAL_SLASHING_MULTIPLIER":"","MAX_PROPOSER_SLASHINGS":"","MAX_ATTESTER_SLASHINGS":"","MAX_ATTESTATIONS":"","MAX_DEPOSITS":"","MAX_VOLUNTARY_EXITS":"","INACTIVITY_PENALTY_QUOTIENT_ALTAIR":"","MIN_SLASHING_PENALTY_QUOTIENT_ALTAIR":"","PROPORTIONAL_SLASHING_MULTIPLIER_ALTAIR":"","SYNC_COMMITTEE_SIZE":"","EPOCHS_PER_SYNC_COMMITTEE_PERIOD":"","MIN_SYNC_COMMITTEE_PARTICIPANTS":"","UPDATE_TIMEOUT":"","INACTIVITY_PENALTY_QUOTIENT_BELLATRIX":"","MIN_SLASHING_PENALTY_QUOTIENT_BELLATRIX":"","PROPORTIONAL_SLASHING_MULTIPLIER_BELLATRIX":"","MAX_BYTES_PER_TRANSACTION":"","MAX_TRANSACTIONS_PER_PAYLOAD":"","BYTES_PER_LOGS_BLOOM":"","MAX_EXTRA_DATA_BYTES":"","MAX_BLS_TO_EXECUTION_CHANGES":"","MAX_WITHDRAWALS_PER_PAYLOAD":"","MAX_VALIDATORS_PER_WITHDRAWALS_SWEEP":"","PRESET_BASE":"","CONFIG_NAME":"","TERMINAL_TOTAL_DIFFICULTY":"","TERMINAL_BLOCK_HASH":"","TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH":"","MIN_GENESIS_ACTIVE_VALIDATOR_COUNT":"","MIN_GENESIS_TIME":"","GENESIS_FORK_VERSION":"","GENESIS_DELAY":"","ALTAIR_FORK_VERSION":"","ALTAIR_FORK_EPOCH":"","BELLATRIX_FORK_VERSION":"","BELLATRIX_FORK_EPOCH":"","CAPELLA_FORK_VERSION":"","CAPELLA_FORK_EPOCH":"","DENEB_FORK_VERSION":"","DENEB_FORK_EPOCH":"","SECONDS_PER_SLOT":"","SECONDS_PER_ETH1_BLOCK":"","MIN_VALIDATOR_WITHDRAWABILITY_DELAY":"","SHARD_COMMITTEE_PERIOD":"","ETH1_FOLLOW_DISTANCE":"","INACTIVITY_SCORE_BIAS":"","INACTIVITY_SCORE_RECOVERY_RATE":"","EJECTION_BALANCE":"","MIN_PER_EPOCH_CHURN_LIMIT":"","CHURN_LIMIT_QUOTIENT":"","PROPOSER_SCORE_BOOST":"","DEPOSIT_CHAIN_ID":"","DEPOSIT_NETWORK_ID":"","DEPOSIT_CONTRACT_ADDRESS":"","BLS_WITHDRAWAL_PREFIX":"","ETH1_ADDRESS_WITHDRAWAL_PREFIX":"","DOMAIN_BEACON_PROPOSER":"","DOMAIN_BEACON_ATTESTER":"","DOMAIN_RANDAO":"","DOMAIN_DEPOSIT":"","DOMAIN_VOLUNTARY_EXIT":"","DOMAIN_SELECTION_PROOF":"","DOMAIN_AGGREGATE_AND_PROOF":"","TIMELY_SOURCE_FLAG_INDEX":"","TIMELY_TARGET_FLAG_INDEX":"","TIMELY_HEAD_FLAG_INDEX":"","TIMELY_SOURCE_WEIGHT":"","TIMELY_TARGET_WEIGHT":"","TIMELY_HEAD_WEIGHT":"","SYNC_REWARD_WEIGHT":"","PROPOSER_WEIGHT":"","WEIGHT_DENOMINATOR":"","DOMAIN_SYNC_COMMITTEE":"","DOMAIN_SYNC_COMMITTEE_SELECTION_PROOF":"","DOMAIN_CONTRIBUTION_AND_PROOF":"","DOMAIN_BLS_TO_EXECUTION_CHANGE":"","TARGET_AGGREGATORS_PER_COMMITTEE":"","RANDOM_SUBNETS_PER_VALIDATOR":"","EPOCHS_PER_RANDOM_SUBNET_SUBSCRIPTION":"","ATTESTATION_SUBNET_COUNT":"","TARGET_AGGREGATORS_PER_SYNC_SUBCOMMITTEE":"","SYNC_COMMITTEE_SUBNET_COUNT":""}}]
|
||||
"body": [{"operator": "jstructcmps", "start": ["data"], "value": {"MAX_COMMITTEES_PER_SLOT":"","TARGET_COMMITTEE_SIZE":"","MAX_VALIDATORS_PER_COMMITTEE":"","SHUFFLE_ROUND_COUNT":"","HYSTERESIS_QUOTIENT":"","HYSTERESIS_DOWNWARD_MULTIPLIER":"","HYSTERESIS_UPWARD_MULTIPLIER":"","MIN_DEPOSIT_AMOUNT":"","MAX_EFFECTIVE_BALANCE":"","EFFECTIVE_BALANCE_INCREMENT":"","MIN_ATTESTATION_INCLUSION_DELAY":"","SLOTS_PER_EPOCH":"","MIN_SEED_LOOKAHEAD":"","MAX_SEED_LOOKAHEAD":"","EPOCHS_PER_ETH1_VOTING_PERIOD":"","SLOTS_PER_HISTORICAL_ROOT":"","MIN_EPOCHS_TO_INACTIVITY_PENALTY":"","EPOCHS_PER_HISTORICAL_VECTOR":"","EPOCHS_PER_SLASHINGS_VECTOR":"","HISTORICAL_ROOTS_LIMIT":"","VALIDATOR_REGISTRY_LIMIT":"","BASE_REWARD_FACTOR":"","WHISTLEBLOWER_REWARD_QUOTIENT":"","PROPOSER_REWARD_QUOTIENT":"","INACTIVITY_PENALTY_QUOTIENT":"","MIN_SLASHING_PENALTY_QUOTIENT":"","PROPORTIONAL_SLASHING_MULTIPLIER":"","MAX_PROPOSER_SLASHINGS":"","MAX_ATTESTER_SLASHINGS":"","MAX_ATTESTATIONS":"","MAX_DEPOSITS":"","MAX_VOLUNTARY_EXITS":"","INACTIVITY_PENALTY_QUOTIENT_ALTAIR":"","MIN_SLASHING_PENALTY_QUOTIENT_ALTAIR":"","PROPORTIONAL_SLASHING_MULTIPLIER_ALTAIR":"","SYNC_COMMITTEE_SIZE":"","EPOCHS_PER_SYNC_COMMITTEE_PERIOD":"","MIN_SYNC_COMMITTEE_PARTICIPANTS":"","UPDATE_TIMEOUT":"","INACTIVITY_PENALTY_QUOTIENT_BELLATRIX":"","MIN_SLASHING_PENALTY_QUOTIENT_BELLATRIX":"","PROPORTIONAL_SLASHING_MULTIPLIER_BELLATRIX":"","MAX_BYTES_PER_TRANSACTION":"","MAX_TRANSACTIONS_PER_PAYLOAD":"","BYTES_PER_LOGS_BLOOM":"","MAX_EXTRA_DATA_BYTES":"","MAX_BLS_TO_EXECUTION_CHANGES":"","MAX_WITHDRAWALS_PER_PAYLOAD":"","MAX_VALIDATORS_PER_WITHDRAWALS_SWEEP":"","PRESET_BASE":"","CONFIG_NAME":"","TERMINAL_TOTAL_DIFFICULTY":"","TERMINAL_BLOCK_HASH":"","TERMINAL_BLOCK_HASH_ACTIVATION_EPOCH":"","MIN_GENESIS_ACTIVE_VALIDATOR_COUNT":"","MIN_GENESIS_TIME":"","GENESIS_FORK_VERSION":"","GENESIS_DELAY":"","ALTAIR_FORK_VERSION":"","ALTAIR_FORK_EPOCH":"","BELLATRIX_FORK_VERSION":"","BELLATRIX_FORK_EPOCH":"","CAPELLA_FORK_VERSION":"","CAPELLA_FORK_EPOCH":"","DENEB_FORK_VERSION":"","DENEB_FORK_EPOCH":"","SECONDS_PER_SLOT":"","SECONDS_PER_ETH1_BLOCK":"","MIN_VALIDATOR_WITHDRAWABILITY_DELAY":"","SHARD_COMMITTEE_PERIOD":"","ETH1_FOLLOW_DISTANCE":"","INACTIVITY_SCORE_BIAS":"","INACTIVITY_SCORE_RECOVERY_RATE":"","EJECTION_BALANCE":"","MIN_PER_EPOCH_CHURN_LIMIT":"","CHURN_LIMIT_QUOTIENT":"","PROPOSER_SCORE_BOOST":"","confirmation_byzantine_threshold":"","confirmation_slashing_threshold":"","DEPOSIT_CHAIN_ID":"","DEPOSIT_NETWORK_ID":"","DEPOSIT_CONTRACT_ADDRESS":"","BLS_WITHDRAWAL_PREFIX":"","ETH1_ADDRESS_WITHDRAWAL_PREFIX":"","DOMAIN_BEACON_PROPOSER":"","DOMAIN_BEACON_ATTESTER":"","DOMAIN_RANDAO":"","DOMAIN_DEPOSIT":"","DOMAIN_VOLUNTARY_EXIT":"","DOMAIN_SELECTION_PROOF":"","DOMAIN_AGGREGATE_AND_PROOF":"","TIMELY_SOURCE_FLAG_INDEX":"","TIMELY_TARGET_FLAG_INDEX":"","TIMELY_HEAD_FLAG_INDEX":"","TIMELY_SOURCE_WEIGHT":"","TIMELY_TARGET_WEIGHT":"","TIMELY_HEAD_WEIGHT":"","SYNC_REWARD_WEIGHT":"","PROPOSER_WEIGHT":"","WEIGHT_DENOMINATOR":"","DOMAIN_SYNC_COMMITTEE":"","DOMAIN_SYNC_COMMITTEE_SELECTION_PROOF":"","DOMAIN_CONTRIBUTION_AND_PROOF":"","DOMAIN_BLS_TO_EXECUTION_CHANGE":"","TARGET_AGGREGATORS_PER_COMMITTEE":"","RANDOM_SUBNETS_PER_VALIDATOR":"","EPOCHS_PER_RANDOM_SUBNET_SUBSCRIPTION":"","ATTESTATION_SUBNET_COUNT":"","TARGET_AGGREGATORS_PER_SYNC_SUBCOMMITTEE":"","SYNC_COMMITTEE_SUBNET_COUNT":""}}]
|
||||
}
|
||||
},
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue