mirror of
https://github.com/sigp/lighthouse.git
synced 2026-05-08 01:05:47 +00:00
proto node versioning
This commit is contained in:
@@ -138,6 +138,10 @@ pub enum InvalidBlock {
|
|||||||
finalized_root: Hash256,
|
finalized_root: Hash256,
|
||||||
block_ancestor: Option<Hash256>,
|
block_ancestor: Option<Hash256>,
|
||||||
},
|
},
|
||||||
|
MissingExecutionPayloadBid{
|
||||||
|
block_slot: Slot,
|
||||||
|
block_root: Hash256,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@@ -241,6 +245,7 @@ pub struct QueuedAttestation {
|
|||||||
attesting_indices: Vec<u64>,
|
attesting_indices: Vec<u64>,
|
||||||
block_root: Hash256,
|
block_root: Hash256,
|
||||||
target_epoch: Epoch,
|
target_epoch: Epoch,
|
||||||
|
payload_present: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, E: EthSpec> From<IndexedAttestationRef<'a, E>> for QueuedAttestation {
|
impl<'a, E: EthSpec> From<IndexedAttestationRef<'a, E>> for QueuedAttestation {
|
||||||
@@ -250,6 +255,7 @@ impl<'a, E: EthSpec> From<IndexedAttestationRef<'a, E>> for QueuedAttestation {
|
|||||||
attesting_indices: a.attesting_indices_to_vec(),
|
attesting_indices: a.attesting_indices_to_vec(),
|
||||||
block_root: a.data().beacon_block_root,
|
block_root: a.data().beacon_block_root,
|
||||||
target_epoch: a.data().target.epoch,
|
target_epoch: a.data().target.epoch,
|
||||||
|
payload_present: a.data().index == 1,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -882,6 +888,25 @@ where
|
|||||||
ExecutionStatus::irrelevant()
|
ExecutionStatus::irrelevant()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let (execution_payload_parent_hash, execution_payload_block_hash) =
|
||||||
|
if let Ok(signed_bid) = block.body().signed_execution_payload_bid() {
|
||||||
|
(
|
||||||
|
Some(signed_bid.message.parent_block_hash),
|
||||||
|
Some(signed_bid.message.block_hash),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
if spec.fork_name_at_slot::<E>(block.slot()).gloas_enabled() {
|
||||||
|
return Err(Error::InvalidBlock(
|
||||||
|
InvalidBlock::MissingExecutionPayloadBid{
|
||||||
|
block_slot: block.slot(),
|
||||||
|
block_root,
|
||||||
|
}
|
||||||
|
|
||||||
|
))
|
||||||
|
}
|
||||||
|
(None, None)
|
||||||
|
};
|
||||||
|
|
||||||
// This does not apply a vote to the block, it just makes fork choice aware of the block so
|
// This does not apply a vote to the block, it just makes fork choice aware of the block so
|
||||||
// it can still be identified as the head even if it doesn't have any votes.
|
// it can still be identified as the head even if it doesn't have any votes.
|
||||||
self.proto_array.process_block::<E>(
|
self.proto_array.process_block::<E>(
|
||||||
@@ -908,10 +933,14 @@ where
|
|||||||
execution_status,
|
execution_status,
|
||||||
unrealized_justified_checkpoint: Some(unrealized_justified_checkpoint),
|
unrealized_justified_checkpoint: Some(unrealized_justified_checkpoint),
|
||||||
unrealized_finalized_checkpoint: Some(unrealized_finalized_checkpoint),
|
unrealized_finalized_checkpoint: Some(unrealized_finalized_checkpoint),
|
||||||
|
execution_payload_parent_hash,
|
||||||
|
execution_payload_block_hash,
|
||||||
|
|
||||||
},
|
},
|
||||||
current_slot,
|
current_slot,
|
||||||
self.justified_checkpoint(),
|
self.justified_checkpoint(),
|
||||||
self.finalized_checkpoint(),
|
self.finalized_checkpoint(),
|
||||||
|
spec,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -1103,6 +1132,7 @@ where
|
|||||||
|
|
||||||
if attestation.data().slot < self.fc_store.get_current_slot() {
|
if attestation.data().slot < self.fc_store.get_current_slot() {
|
||||||
for validator_index in attestation.attesting_indices_iter() {
|
for validator_index in attestation.attesting_indices_iter() {
|
||||||
|
let payload_present = attestation.data().index == 1;
|
||||||
self.proto_array.process_attestation(
|
self.proto_array.process_attestation(
|
||||||
*validator_index as usize,
|
*validator_index as usize,
|
||||||
attestation.data().beacon_block_root,
|
attestation.data().beacon_block_root,
|
||||||
|
|||||||
@@ -54,6 +54,13 @@ pub enum Error {
|
|||||||
},
|
},
|
||||||
InvalidEpochOffset(u64),
|
InvalidEpochOffset(u64),
|
||||||
Arith(ArithError),
|
Arith(ArithError),
|
||||||
|
GloasNotImplemented,
|
||||||
|
InvalidNodeVariant{
|
||||||
|
block_root: Hash256,
|
||||||
|
},
|
||||||
|
BrokenBlock{
|
||||||
|
block_root: Hash256,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<ArithError> for Error {
|
impl From<ArithError> for Error {
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ pub use crate::justified_balances::JustifiedBalances;
|
|||||||
pub use crate::proto_array::{InvalidationOperation, calculate_committee_fraction};
|
pub use crate::proto_array::{InvalidationOperation, calculate_committee_fraction};
|
||||||
pub use crate::proto_array_fork_choice::{
|
pub use crate::proto_array_fork_choice::{
|
||||||
Block, DisallowedReOrgOffsets, DoNotReOrg, ExecutionStatus, ProposerHeadError,
|
Block, DisallowedReOrgOffsets, DoNotReOrg, ExecutionStatus, ProposerHeadError,
|
||||||
ProposerHeadInfo, ProtoArrayForkChoice, ReOrgThreshold,
|
ProposerHeadInfo, ProtoArrayForkChoice, ReOrgThreshold, PayloadStatus,
|
||||||
};
|
};
|
||||||
pub use error::Error;
|
pub use error::Error;
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use crate::error::InvalidBestNodeInfo;
|
use crate::error::InvalidBestNodeInfo;
|
||||||
use crate::{Block, ExecutionStatus, JustifiedBalances, error::Error};
|
use crate::{Block, ExecutionStatus, JustifiedBalances, error::Error, PayloadStatus};
|
||||||
use fixed_bytes::FixedBytesExtended;
|
use fixed_bytes::FixedBytesExtended;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use ssz::Encode;
|
use ssz::Encode;
|
||||||
@@ -68,47 +68,68 @@ impl InvalidationOperation {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type ProtoNode = ProtoNodeV17;
|
|
||||||
|
|
||||||
#[superstruct(
|
#[superstruct(
|
||||||
variants(V17),
|
variants(V17, V29),
|
||||||
variant_attributes(derive(Clone, PartialEq, Debug, Encode, Decode, Serialize, Deserialize)),
|
variant_attributes(derive(Clone, PartialEq, Debug, Encode, Decode, Serialize, Deserialize)),
|
||||||
no_enum
|
|
||||||
)]
|
)]
|
||||||
|
#[derive(PartialEq, Debug, Encode, Decode, Serialize, Deserialize, Clone)]
|
||||||
|
#[ssz(enum_behaviour = "transparent")]
|
||||||
pub struct ProtoNode {
|
pub struct ProtoNode {
|
||||||
/// The `slot` is not necessary for `ProtoArray`, it just exists so external components can
|
/// The `slot` is not necessary for `ProtoArray`, it just exists so external components can
|
||||||
/// easily query the block slot. This is useful for upstream fork choice logic.
|
/// easily query the block slot. This is useful for upstream fork choice logic.
|
||||||
|
#[superstruct(getter(copy))]
|
||||||
pub slot: Slot,
|
pub slot: Slot,
|
||||||
/// The `state_root` is not necessary for `ProtoArray` either, it also just exists for upstream
|
/// The `state_root` is not necessary for `ProtoArray` either, it also just exists for upstream
|
||||||
/// components (namely attestation verification).
|
/// components (namely attestation verification).
|
||||||
|
#[superstruct(getter(copy))]
|
||||||
pub state_root: Hash256,
|
pub state_root: Hash256,
|
||||||
/// The root that would be used for the `attestation.data.target.root` if a LMD vote was cast
|
/// The root that would be used for the `attestation.data.target.root` if a LMD vote was cast
|
||||||
/// for this block.
|
/// for this block.
|
||||||
///
|
///
|
||||||
/// The `target_root` is not necessary for `ProtoArray` either, it also just exists for upstream
|
/// The `target_root` is not necessary for `ProtoArray` either, it also just exists for upstream
|
||||||
/// components (namely fork choice attestation verification).
|
/// components (namely fork choice attestation verification).
|
||||||
|
#[superstruct(getter(copy))]
|
||||||
pub target_root: Hash256,
|
pub target_root: Hash256,
|
||||||
pub current_epoch_shuffling_id: AttestationShufflingId,
|
pub current_epoch_shuffling_id: AttestationShufflingId,
|
||||||
pub next_epoch_shuffling_id: AttestationShufflingId,
|
pub next_epoch_shuffling_id: AttestationShufflingId,
|
||||||
|
#[superstruct(getter(copy))]
|
||||||
pub root: Hash256,
|
pub root: Hash256,
|
||||||
|
#[superstruct(getter(copy))]
|
||||||
#[ssz(with = "four_byte_option_usize")]
|
#[ssz(with = "four_byte_option_usize")]
|
||||||
pub parent: Option<usize>,
|
pub parent: Option<usize>,
|
||||||
#[superstruct(only(V17))]
|
#[superstruct(only(V17, V29), partial_getter(copy))]
|
||||||
pub justified_checkpoint: Checkpoint,
|
pub justified_checkpoint: Checkpoint,
|
||||||
#[superstruct(only(V17))]
|
#[superstruct(only(V17, V29), partial_getter(copy))]
|
||||||
pub finalized_checkpoint: Checkpoint,
|
pub finalized_checkpoint: Checkpoint,
|
||||||
|
#[superstruct(getter(copy))]
|
||||||
pub weight: u64,
|
pub weight: u64,
|
||||||
|
#[superstruct(getter(copy))]
|
||||||
#[ssz(with = "four_byte_option_usize")]
|
#[ssz(with = "four_byte_option_usize")]
|
||||||
pub best_child: Option<usize>,
|
pub best_child: Option<usize>,
|
||||||
|
#[superstruct(getter(copy))]
|
||||||
#[ssz(with = "four_byte_option_usize")]
|
#[ssz(with = "four_byte_option_usize")]
|
||||||
pub best_descendant: Option<usize>,
|
pub best_descendant: Option<usize>,
|
||||||
/// Indicates if an execution node has marked this block as valid. Also contains the execution
|
/// Indicates if an execution node has marked this block as valid. Also contains the execution
|
||||||
/// block hash.
|
/// block hash.
|
||||||
|
#[superstruct(only(V17), partial_getter(copy))]
|
||||||
pub execution_status: ExecutionStatus,
|
pub execution_status: ExecutionStatus,
|
||||||
|
#[superstruct(getter(copy))]
|
||||||
#[ssz(with = "four_byte_option_checkpoint")]
|
#[ssz(with = "four_byte_option_checkpoint")]
|
||||||
pub unrealized_justified_checkpoint: Option<Checkpoint>,
|
pub unrealized_justified_checkpoint: Option<Checkpoint>,
|
||||||
|
#[superstruct(getter(copy))]
|
||||||
#[ssz(with = "four_byte_option_checkpoint")]
|
#[ssz(with = "four_byte_option_checkpoint")]
|
||||||
pub unrealized_finalized_checkpoint: Option<Checkpoint>,
|
pub unrealized_finalized_checkpoint: Option<Checkpoint>,
|
||||||
|
|
||||||
|
/// We track the parent payload status from which the current node was extended.
|
||||||
|
#[superstruct(only(V29), partial_getter(copy))]
|
||||||
|
pub parent_payload_status: PayloadStatus,
|
||||||
|
#[superstruct(only(V29), partial_getter(copy))]
|
||||||
|
pub empty_payload_weight: u64,
|
||||||
|
#[superstruct(only(V29), partial_getter(copy))]
|
||||||
|
pub full_payload_weight: u64,
|
||||||
|
#[superstruct(only(V29), partial_getter(copy))]
|
||||||
|
pub execution_payload_block_hash: ExecutionBlockHash,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Debug, Encode, Decode, Serialize, Deserialize, Copy, Clone)]
|
#[derive(PartialEq, Debug, Encode, Decode, Serialize, Deserialize, Copy, Clone)]
|
||||||
@@ -181,16 +202,14 @@ impl ProtoArray {
|
|||||||
// There is no need to adjust the balances or manage parent of the zero hash since it
|
// There is no need to adjust the balances or manage parent of the zero hash since it
|
||||||
// is an alias to the genesis block. The weight applied to the genesis block is
|
// is an alias to the genesis block. The weight applied to the genesis block is
|
||||||
// irrelevant as we _always_ choose it and it's impossible for it to have a parent.
|
// irrelevant as we _always_ choose it and it's impossible for it to have a parent.
|
||||||
if node.root == Hash256::zero() {
|
if node.root() == Hash256::zero() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let execution_status_is_invalid = node.execution_status.is_invalid();
|
let mut node_delta = if let Ok(proto_node) = node.as_v17() && proto_node.execution_status.is_invalid() {
|
||||||
|
|
||||||
let mut node_delta = if execution_status_is_invalid {
|
|
||||||
// If the node has an invalid execution payload, reduce its weight to zero.
|
// If the node has an invalid execution payload, reduce its weight to zero.
|
||||||
0_i64
|
0_i64
|
||||||
.checked_sub(node.weight as i64)
|
.checked_sub(node.weight() as i64)
|
||||||
.ok_or(Error::InvalidExecutionDeltaOverflow(node_index))?
|
.ok_or(Error::InvalidExecutionDeltaOverflow(node_index))?
|
||||||
} else {
|
} else {
|
||||||
deltas
|
deltas
|
||||||
@@ -202,7 +221,7 @@ impl ProtoArray {
|
|||||||
// If we find the node for which the proposer boost was previously applied, decrease
|
// If we find the node for which the proposer boost was previously applied, decrease
|
||||||
// the delta by the previous score amount.
|
// the delta by the previous score amount.
|
||||||
if self.previous_proposer_boost.root != Hash256::zero()
|
if self.previous_proposer_boost.root != Hash256::zero()
|
||||||
&& self.previous_proposer_boost.root == node.root
|
&& self.previous_proposer_boost.root == node.root()
|
||||||
// Invalid nodes will always have a weight of zero so there's no need to subtract
|
// Invalid nodes will always have a weight of zero so there's no need to subtract
|
||||||
// the proposer boost delta.
|
// the proposer boost delta.
|
||||||
&& !execution_status_is_invalid
|
&& !execution_status_is_invalid
|
||||||
@@ -217,7 +236,7 @@ impl ProtoArray {
|
|||||||
// https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/fork-choice.md#get_latest_attesting_balance
|
// https://github.com/ethereum/consensus-specs/blob/dev/specs/phase0/fork-choice.md#get_latest_attesting_balance
|
||||||
if let Some(proposer_score_boost) = spec.proposer_score_boost
|
if let Some(proposer_score_boost) = spec.proposer_score_boost
|
||||||
&& proposer_boost_root != Hash256::zero()
|
&& proposer_boost_root != Hash256::zero()
|
||||||
&& proposer_boost_root == node.root
|
&& proposer_boost_root == node.root()
|
||||||
// Invalid nodes (or their ancestors) should not receive a proposer boost.
|
// Invalid nodes (or their ancestors) should not receive a proposer boost.
|
||||||
&& !execution_status_is_invalid
|
&& !execution_status_is_invalid
|
||||||
{
|
{
|
||||||
@@ -232,7 +251,7 @@ impl ProtoArray {
|
|||||||
// Apply the delta to the node.
|
// Apply the delta to the node.
|
||||||
if execution_status_is_invalid {
|
if execution_status_is_invalid {
|
||||||
// Invalid nodes always have a weight of 0.
|
// Invalid nodes always have a weight of 0.
|
||||||
node.weight = 0
|
node.weight() = 0
|
||||||
} else if node_delta < 0 {
|
} else if node_delta < 0 {
|
||||||
// Note: I am conflicted about whether to use `saturating_sub` or `checked_sub`
|
// Note: I am conflicted about whether to use `saturating_sub` or `checked_sub`
|
||||||
// here.
|
// here.
|
||||||
@@ -243,19 +262,19 @@ impl ProtoArray {
|
|||||||
//
|
//
|
||||||
// However, I am not fully convinced that some valid case for `saturating_sub` does
|
// However, I am not fully convinced that some valid case for `saturating_sub` does
|
||||||
// not exist.
|
// not exist.
|
||||||
node.weight = node
|
node.weight() = node
|
||||||
.weight
|
.weight()
|
||||||
.checked_sub(node_delta.unsigned_abs())
|
.checked_sub(node_delta.unsigned_abs())
|
||||||
.ok_or(Error::DeltaOverflow(node_index))?;
|
.ok_or(Error::DeltaOverflow(node_index))?;
|
||||||
} else {
|
} else {
|
||||||
node.weight = node
|
node.weight = node
|
||||||
.weight
|
.weight()
|
||||||
.checked_add(node_delta as u64)
|
.checked_add(node_delta as u64)
|
||||||
.ok_or(Error::DeltaOverflow(node_index))?;
|
.ok_or(Error::DeltaOverflow(node_index))?;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the parent delta (if any).
|
// Update the parent delta (if any).
|
||||||
if let Some(parent_index) = node.parent {
|
if let Some(parent_index) = node.parent() {
|
||||||
let parent_delta = deltas
|
let parent_delta = deltas
|
||||||
.get_mut(parent_index)
|
.get_mut(parent_index)
|
||||||
.ok_or(Error::InvalidParentDelta(parent_index))?;
|
.ok_or(Error::InvalidParentDelta(parent_index))?;
|
||||||
@@ -283,7 +302,7 @@ impl ProtoArray {
|
|||||||
.ok_or(Error::InvalidNodeIndex(node_index))?;
|
.ok_or(Error::InvalidNodeIndex(node_index))?;
|
||||||
|
|
||||||
// If the node has a parent, try to update its best-child and best-descendant.
|
// If the node has a parent, try to update its best-child and best-descendant.
|
||||||
if let Some(parent_index) = node.parent {
|
if let Some(parent_index) = node.parent() {
|
||||||
self.maybe_update_best_child_and_descendant::<E>(
|
self.maybe_update_best_child_and_descendant::<E>(
|
||||||
parent_index,
|
parent_index,
|
||||||
node_index,
|
node_index,
|
||||||
@@ -306,6 +325,7 @@ impl ProtoArray {
|
|||||||
current_slot: Slot,
|
current_slot: Slot,
|
||||||
best_justified_checkpoint: Checkpoint,
|
best_justified_checkpoint: Checkpoint,
|
||||||
best_finalized_checkpoint: Checkpoint,
|
best_finalized_checkpoint: Checkpoint,
|
||||||
|
spec: &ChainSpec,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
// If the block is already known, simply ignore it.
|
// If the block is already known, simply ignore it.
|
||||||
if self.indices.contains_key(&block.root) {
|
if self.indices.contains_key(&block.root) {
|
||||||
@@ -314,45 +334,92 @@ impl ProtoArray {
|
|||||||
|
|
||||||
let node_index = self.nodes.len();
|
let node_index = self.nodes.len();
|
||||||
|
|
||||||
let node = ProtoNode {
|
let parent_index = block
|
||||||
slot: block.slot,
|
.parent_root
|
||||||
root: block.root,
|
.and_then(|parent| self.indices.get(&parent).copied());
|
||||||
target_root: block.target_root,
|
|
||||||
current_epoch_shuffling_id: block.current_epoch_shuffling_id,
|
let node = if !spec.fork_name_at_slot::<E>(current_slot).gloas_enabled() {
|
||||||
next_epoch_shuffling_id: block.next_epoch_shuffling_id,
|
ProtoNode::V17(ProtoNodeV17 {
|
||||||
state_root: block.state_root,
|
slot: block.slot,
|
||||||
parent: block
|
root: block.root,
|
||||||
.parent_root
|
target_root: block.target_root,
|
||||||
.and_then(|parent| self.indices.get(&parent).copied()),
|
current_epoch_shuffling_id: block.current_epoch_shuffling_id,
|
||||||
justified_checkpoint: block.justified_checkpoint,
|
next_epoch_shuffling_id: block.next_epoch_shuffling_id,
|
||||||
finalized_checkpoint: block.finalized_checkpoint,
|
state_root: block.state_root,
|
||||||
weight: 0,
|
parent: parent_index,
|
||||||
best_child: None,
|
justified_checkpoint: block.justified_checkpoint,
|
||||||
best_descendant: None,
|
finalized_checkpoint: block.finalized_checkpoint,
|
||||||
execution_status: block.execution_status,
|
weight: 0,
|
||||||
unrealized_justified_checkpoint: block.unrealized_justified_checkpoint,
|
best_child: None,
|
||||||
unrealized_finalized_checkpoint: block.unrealized_finalized_checkpoint,
|
best_descendant: None,
|
||||||
|
execution_status: block.execution_status,
|
||||||
|
unrealized_justified_checkpoint: block.unrealized_justified_checkpoint,
|
||||||
|
unrealized_finalized_checkpoint: block.unrealized_finalized_checkpoint,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
let execution_payload_block_hash = block
|
||||||
|
.execution_payload_block_hash
|
||||||
|
.ok_or(Error::BrokenBlock{block_root: block.root})?;
|
||||||
|
|
||||||
|
let parent_payload_status: PayloadStatus =
|
||||||
|
if let Some(parent_node) =
|
||||||
|
parent_index.and_then(|idx| self.nodes.get(idx))
|
||||||
|
{
|
||||||
|
let v29 = parent_node
|
||||||
|
.as_v29()
|
||||||
|
.map_err(|_| Error::InvalidNodeVariant{block_root: block.root})?;
|
||||||
|
if execution_payload_block_hash == v29.execution_payload_block_hash
|
||||||
|
{
|
||||||
|
PayloadStatus::Empty
|
||||||
|
} else {
|
||||||
|
PayloadStatus::Full
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
PayloadStatus::Full
|
||||||
|
};
|
||||||
|
|
||||||
|
ProtoNode::V29(ProtoNodeV29 {
|
||||||
|
slot: block.slot,
|
||||||
|
root: block.root,
|
||||||
|
target_root: block.target_root,
|
||||||
|
current_epoch_shuffling_id: block.current_epoch_shuffling_id,
|
||||||
|
next_epoch_shuffling_id: block.next_epoch_shuffling_id,
|
||||||
|
state_root: block.state_root,
|
||||||
|
parent: parent_index,
|
||||||
|
justified_checkpoint: block.justified_checkpoint,
|
||||||
|
finalized_checkpoint: block.finalized_checkpoint,
|
||||||
|
weight: 0,
|
||||||
|
best_child: None,
|
||||||
|
best_descendant: None,
|
||||||
|
unrealized_justified_checkpoint: block.unrealized_justified_checkpoint,
|
||||||
|
unrealized_finalized_checkpoint: block.unrealized_finalized_checkpoint,
|
||||||
|
parent_payload_status,
|
||||||
|
empty_payload_weight: 0,
|
||||||
|
full_payload_weight: 0,
|
||||||
|
execution_payload_block_hash,
|
||||||
|
})
|
||||||
};
|
};
|
||||||
|
|
||||||
// If the parent has an invalid execution status, return an error before adding the block to
|
// If the parent has an invalid execution status, return an error before adding the
|
||||||
// `self`.
|
// block to `self`. This applies when the parent is a V17 node with execution tracking.
|
||||||
if let Some(parent_index) = node.parent {
|
if let Some(parent_index) = node.parent() {
|
||||||
let parent = self
|
let parent = self
|
||||||
.nodes
|
.nodes
|
||||||
.get(parent_index)
|
.get(parent_index)
|
||||||
.ok_or(Error::InvalidNodeIndex(parent_index))?;
|
.ok_or(Error::InvalidNodeIndex(parent_index))?;
|
||||||
if parent.execution_status.is_invalid() {
|
|
||||||
|
if let Ok(status) = parent.execution_status() && status.is_invalid() {
|
||||||
return Err(Error::ParentExecutionStatusIsInvalid {
|
return Err(Error::ParentExecutionStatusIsInvalid {
|
||||||
block_root: block.root,
|
block_root: block.root,
|
||||||
parent_root: parent.root,
|
parent_root: parent.root(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
self.indices.insert(node.root, node_index);
|
self.indices.insert(node.root(), node_index);
|
||||||
self.nodes.push(node.clone());
|
self.nodes.push(node.clone());
|
||||||
|
|
||||||
if let Some(parent_index) = node.parent {
|
if let Some(parent_index) = node.parent() {
|
||||||
self.maybe_update_best_child_and_descendant::<E>(
|
self.maybe_update_best_child_and_descendant::<E>(
|
||||||
parent_index,
|
parent_index,
|
||||||
node_index,
|
node_index,
|
||||||
@@ -805,12 +872,12 @@ impl ProtoArray {
|
|||||||
let change_to_none = (None, None);
|
let change_to_none = (None, None);
|
||||||
let change_to_child = (
|
let change_to_child = (
|
||||||
Some(child_index),
|
Some(child_index),
|
||||||
child.best_descendant.or(Some(child_index)),
|
child.best_descendant().or(Some(child_index)),
|
||||||
);
|
);
|
||||||
let no_change = (parent.best_child, parent.best_descendant);
|
let no_change = (parent.best_child(), parent.best_descendant());
|
||||||
|
|
||||||
let (new_best_child, new_best_descendant) =
|
let (new_best_child, new_best_descendant) =
|
||||||
if let Some(best_child_index) = parent.best_child {
|
if let Some(best_child_index) = parent.best_child() {
|
||||||
if best_child_index == child_index && !child_leads_to_viable_head {
|
if best_child_index == child_index && !child_leads_to_viable_head {
|
||||||
// If the child is already the best-child of the parent but it's not viable for
|
// If the child is already the best-child of the parent but it's not viable for
|
||||||
// the head, remove it.
|
// the head, remove it.
|
||||||
@@ -838,16 +905,16 @@ impl ProtoArray {
|
|||||||
} else if !child_leads_to_viable_head && best_child_leads_to_viable_head {
|
} else if !child_leads_to_viable_head && best_child_leads_to_viable_head {
|
||||||
// The best child leads to a viable head, but the child doesn't.
|
// The best child leads to a viable head, but the child doesn't.
|
||||||
no_change
|
no_change
|
||||||
} else if child.weight == best_child.weight {
|
} else if child.weight() == best_child.weight() {
|
||||||
// Tie-breaker of equal weights by root.
|
// Tie-breaker of equal weights by root.
|
||||||
if child.root >= best_child.root {
|
if *child.root() >= *best_child.root() {
|
||||||
change_to_child
|
change_to_child
|
||||||
} else {
|
} else {
|
||||||
no_change
|
no_change
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Choose the winner by weight.
|
// Choose the winner by weight.
|
||||||
if child.weight > best_child.weight {
|
if child.weight() > best_child.weight() {
|
||||||
change_to_child
|
change_to_child
|
||||||
} else {
|
} else {
|
||||||
no_change
|
no_change
|
||||||
@@ -867,8 +934,8 @@ impl ProtoArray {
|
|||||||
.get_mut(parent_index)
|
.get_mut(parent_index)
|
||||||
.ok_or(Error::InvalidNodeIndex(parent_index))?;
|
.ok_or(Error::InvalidNodeIndex(parent_index))?;
|
||||||
|
|
||||||
parent.best_child = new_best_child;
|
*parent.best_child_mut() = new_best_child;
|
||||||
parent.best_descendant = new_best_descendant;
|
*parent.best_descendant_mut() = new_best_descendant;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -883,7 +950,7 @@ impl ProtoArray {
|
|||||||
best_finalized_checkpoint: Checkpoint,
|
best_finalized_checkpoint: Checkpoint,
|
||||||
) -> Result<bool, Error> {
|
) -> Result<bool, Error> {
|
||||||
let best_descendant_is_viable_for_head =
|
let best_descendant_is_viable_for_head =
|
||||||
if let Some(best_descendant_index) = node.best_descendant {
|
if let Some(best_descendant_index) = node.best_descendant() {
|
||||||
let best_descendant = self
|
let best_descendant = self
|
||||||
.nodes
|
.nodes
|
||||||
.get(best_descendant_index)
|
.get(best_descendant_index)
|
||||||
@@ -921,21 +988,21 @@ impl ProtoArray {
|
|||||||
best_justified_checkpoint: Checkpoint,
|
best_justified_checkpoint: Checkpoint,
|
||||||
best_finalized_checkpoint: Checkpoint,
|
best_finalized_checkpoint: Checkpoint,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
if node.execution_status.is_invalid() {
|
if let Ok(proto_node) = node.as_v17() && proto_node.execution_status.is_invalid() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
let genesis_epoch = Epoch::new(0);
|
let genesis_epoch = Epoch::new(0);
|
||||||
let current_epoch = current_slot.epoch(E::slots_per_epoch());
|
let current_epoch = current_slot.epoch(E::slots_per_epoch());
|
||||||
let node_epoch = node.slot.epoch(E::slots_per_epoch());
|
let node_epoch = node.slot().epoch(E::slots_per_epoch());
|
||||||
let node_justified_checkpoint = node.justified_checkpoint;
|
let node_justified_checkpoint = node.justified_checkpoint();
|
||||||
|
|
||||||
let voting_source = if current_epoch > node_epoch {
|
let voting_source = if current_epoch > node_epoch {
|
||||||
// The block is from a prior epoch, the voting source will be pulled-up.
|
// The block is from a prior epoch, the voting source will be pulled-up.
|
||||||
node.unrealized_justified_checkpoint
|
node.unrealized_justified_checkpoint()
|
||||||
// Sometimes we don't track the unrealized justification. In
|
// Sometimes we don't track the unrealized justification. In
|
||||||
// that case, just use the fully-realized justified checkpoint.
|
// that case, just use the fully-realized justified checkpoint.
|
||||||
.unwrap_or(node_justified_checkpoint)
|
.unwrap_or(*node_justified_checkpoint)
|
||||||
} else {
|
} else {
|
||||||
// The block is not from a prior epoch, therefore the voting source
|
// The block is not from a prior epoch, therefore the voting source
|
||||||
// is not pulled up.
|
// is not pulled up.
|
||||||
|
|||||||
@@ -159,6 +159,10 @@ pub struct Block {
|
|||||||
pub execution_status: ExecutionStatus,
|
pub execution_status: ExecutionStatus,
|
||||||
pub unrealized_justified_checkpoint: Option<Checkpoint>,
|
pub unrealized_justified_checkpoint: Option<Checkpoint>,
|
||||||
pub unrealized_finalized_checkpoint: Option<Checkpoint>,
|
pub unrealized_finalized_checkpoint: Option<Checkpoint>,
|
||||||
|
|
||||||
|
/// post-Gloas fields
|
||||||
|
pub execution_payload_parent_hash: Option<ExecutionBlockHash>,
|
||||||
|
pub execution_payload_block_hash: Option<ExecutionBlockHash>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Block {
|
impl Block {
|
||||||
@@ -422,6 +426,9 @@ impl ProtoArrayForkChoice {
|
|||||||
current_epoch_shuffling_id: AttestationShufflingId,
|
current_epoch_shuffling_id: AttestationShufflingId,
|
||||||
next_epoch_shuffling_id: AttestationShufflingId,
|
next_epoch_shuffling_id: AttestationShufflingId,
|
||||||
execution_status: ExecutionStatus,
|
execution_status: ExecutionStatus,
|
||||||
|
execution_payload_parent_hash: Option<ExecutionBlockHash>,
|
||||||
|
execution_payload_block_hash: Option<ExecutionBlockHash>,
|
||||||
|
|
||||||
) -> Result<Self, String> {
|
) -> Result<Self, String> {
|
||||||
let mut proto_array = ProtoArray {
|
let mut proto_array = ProtoArray {
|
||||||
prune_threshold: DEFAULT_PRUNE_THRESHOLD,
|
prune_threshold: DEFAULT_PRUNE_THRESHOLD,
|
||||||
@@ -445,6 +452,9 @@ impl ProtoArrayForkChoice {
|
|||||||
execution_status,
|
execution_status,
|
||||||
unrealized_justified_checkpoint: Some(justified_checkpoint),
|
unrealized_justified_checkpoint: Some(justified_checkpoint),
|
||||||
unrealized_finalized_checkpoint: Some(finalized_checkpoint),
|
unrealized_finalized_checkpoint: Some(finalized_checkpoint),
|
||||||
|
execution_payload_parent_hash,
|
||||||
|
execution_payload_block_hash,
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
proto_array
|
proto_array
|
||||||
@@ -453,6 +463,7 @@ impl ProtoArrayForkChoice {
|
|||||||
current_slot,
|
current_slot,
|
||||||
justified_checkpoint,
|
justified_checkpoint,
|
||||||
finalized_checkpoint,
|
finalized_checkpoint,
|
||||||
|
spec,
|
||||||
)
|
)
|
||||||
.map_err(|e| format!("Failed to add finalized block to proto_array: {:?}", e))?;
|
.map_err(|e| format!("Failed to add finalized block to proto_array: {:?}", e))?;
|
||||||
|
|
||||||
@@ -506,6 +517,7 @@ impl ProtoArrayForkChoice {
|
|||||||
current_slot: Slot,
|
current_slot: Slot,
|
||||||
justified_checkpoint: Checkpoint,
|
justified_checkpoint: Checkpoint,
|
||||||
finalized_checkpoint: Checkpoint,
|
finalized_checkpoint: Checkpoint,
|
||||||
|
spec: &ChainSpec,
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
if block.parent_root.is_none() {
|
if block.parent_root.is_none() {
|
||||||
return Err("Missing parent root".to_string());
|
return Err("Missing parent root".to_string());
|
||||||
@@ -517,6 +529,7 @@ impl ProtoArrayForkChoice {
|
|||||||
current_slot,
|
current_slot,
|
||||||
justified_checkpoint,
|
justified_checkpoint,
|
||||||
finalized_checkpoint,
|
finalized_checkpoint,
|
||||||
|
spec,
|
||||||
)
|
)
|
||||||
.map_err(|e| format!("process_block_error: {:?}", e))
|
.map_err(|e| format!("process_block_error: {:?}", e))
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user