proto node versioning

This commit is contained in:
hopinheimer
2026-02-19 23:07:31 -05:00
parent 54b3576145
commit 491b69f364
5 changed files with 176 additions and 59 deletions

View File

@@ -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,

View File

@@ -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 {

View File

@@ -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;

View File

@@ -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.

View File

@@ -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))
} }