mirror of
https://github.com/sigp/lighthouse.git
synced 2026-05-01 11:43:44 +00:00
Merge branch 'gloas-walk-always' into epbs-devnet-1
This commit is contained in:
@@ -98,7 +98,7 @@ pub enum Operation {
|
||||
},
|
||||
/// Simulate receiving and validating an execution payload for `block_root`.
|
||||
/// Sets `payload_received = true` on the V29 node via the live validation path.
|
||||
ProcessExecutionPayload {
|
||||
ProcessExecutionPayloadEnvelope {
|
||||
block_root: Hash256,
|
||||
},
|
||||
AssertPayloadReceived {
|
||||
@@ -500,9 +500,9 @@ impl ForkChoiceTestDefinition {
|
||||
// the payload to be in payload_states (payload_received).
|
||||
node_v29.payload_received = is_timely || is_data_available;
|
||||
}
|
||||
Operation::ProcessExecutionPayload { block_root } => {
|
||||
Operation::ProcessExecutionPayloadEnvelope { block_root } => {
|
||||
fork_choice
|
||||
.on_execution_payload(block_root)
|
||||
.on_valid_payload_envelope_received(block_root)
|
||||
.unwrap_or_else(|e| {
|
||||
panic!(
|
||||
"on_execution_payload op at index {} returned error: {}",
|
||||
|
||||
@@ -53,7 +53,7 @@ pub fn get_gloas_chain_following_test_definition() -> ForkChoiceTestDefinition {
|
||||
|
||||
// Mark root_1 as having received its execution payload so that
|
||||
// its FULL virtual node exists in the Gloas fork choice tree.
|
||||
ops.push(Operation::ProcessExecutionPayload {
|
||||
ops.push(Operation::ProcessExecutionPayloadEnvelope {
|
||||
block_root: get_root(1),
|
||||
});
|
||||
|
||||
@@ -263,7 +263,7 @@ pub fn get_gloas_find_head_vote_transition_test_definition() -> ForkChoiceTestDe
|
||||
|
||||
// Mark root_1 as having received its execution payload so that
|
||||
// its FULL virtual node exists in the Gloas fork choice tree.
|
||||
ops.push(Operation::ProcessExecutionPayload {
|
||||
ops.push(Operation::ProcessExecutionPayloadEnvelope {
|
||||
block_root: get_root(1),
|
||||
});
|
||||
|
||||
@@ -368,7 +368,7 @@ pub fn get_gloas_weight_priority_over_payload_preference_test_definition()
|
||||
|
||||
// Mark root_1 as having received its execution payload so that
|
||||
// its FULL virtual node exists in the Gloas fork choice tree.
|
||||
ops.push(Operation::ProcessExecutionPayload {
|
||||
ops.push(Operation::ProcessExecutionPayloadEnvelope {
|
||||
block_root: get_root(1),
|
||||
});
|
||||
|
||||
@@ -538,7 +538,7 @@ pub fn get_gloas_interleaved_attestations_test_definition() -> ForkChoiceTestDef
|
||||
|
||||
// Mark root_1 as having received its execution payload so that
|
||||
// its FULL virtual node exists in the Gloas fork choice tree.
|
||||
ops.push(Operation::ProcessExecutionPayload {
|
||||
ops.push(Operation::ProcessExecutionPayloadEnvelope {
|
||||
block_root: get_root(1),
|
||||
});
|
||||
|
||||
@@ -674,8 +674,8 @@ pub fn get_gloas_payload_received_interleaving_test_definition() -> ForkChoiceTe
|
||||
expected_payload_status: None,
|
||||
});
|
||||
|
||||
// ProcessExecutionPayload on genesis is a no-op (already received at init).
|
||||
ops.push(Operation::ProcessExecutionPayload {
|
||||
// ProcessExecutionPayloadEnvelope on genesis is a no-op (already received at init).
|
||||
ops.push(Operation::ProcessExecutionPayloadEnvelope {
|
||||
block_root: get_root(0),
|
||||
});
|
||||
|
||||
@@ -778,7 +778,7 @@ mod tests {
|
||||
|
||||
// Mark root 2's execution payload as received so the Full virtual child exists.
|
||||
if first_gloas_block_full {
|
||||
ops.push(Operation::ProcessExecutionPayload {
|
||||
ops.push(Operation::ProcessExecutionPayloadEnvelope {
|
||||
block_root: get_root(2),
|
||||
});
|
||||
}
|
||||
|
||||
@@ -165,8 +165,6 @@ pub struct ProtoNode {
|
||||
pub payload_data_availability_votes: BitVector<U512>,
|
||||
/// Whether the execution payload for this block has been received and validated locally.
|
||||
/// Maps to `root in store.payload_states` in the spec.
|
||||
/// When true, `is_payload_timely` and `is_payload_data_available` return true
|
||||
/// regardless of PTC vote counts.
|
||||
#[superstruct(only(V29), partial_getter(copy))]
|
||||
pub payload_received: bool,
|
||||
/// The proposer index for this block, used by `should_apply_proposer_boost`
|
||||
@@ -369,7 +367,6 @@ pub struct ProtoArray {
|
||||
pub prune_threshold: usize,
|
||||
pub nodes: Vec<ProtoNode>,
|
||||
pub indices: HashMap<Hash256, usize>,
|
||||
pub previous_proposer_boost: ProposerBoost,
|
||||
}
|
||||
|
||||
impl ProtoArray {
|
||||
@@ -492,20 +489,14 @@ impl ProtoArray {
|
||||
.ok_or(Error::DeltaOverflow(parent_index))?;
|
||||
}
|
||||
} else {
|
||||
// V17 child of a V29 parent (fork transition): treat as FULL
|
||||
// since V17 nodes always have execution payloads inline.
|
||||
parent_delta.full_delta = parent_delta
|
||||
.full_delta
|
||||
.checked_add(delta)
|
||||
.ok_or(Error::DeltaOverflow(parent_index))?;
|
||||
// This is a v17 node with a v17 parent.
|
||||
// There is no empty or full weight for v17 nodes, so nothing to propagate.
|
||||
// In the tree walk, the v17 nodes have an empty child with 0 weight, which
|
||||
// wins by default (it is the only child).
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Proposer boost is now applied on-the-fly in `get_weight` during the
|
||||
// walk, so clear any stale boost from a prior call.
|
||||
self.previous_proposer_boost = ProposerBoost::default();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -641,11 +632,9 @@ impl ProtoArray {
|
||||
// Anchor gets [True, True]. Others computed from time_into_slot.
|
||||
block_timeliness_attestation_threshold: is_genesis
|
||||
|| (is_current_slot
|
||||
&& time_into_slot < spec.get_unaggregated_attestation_due()),
|
||||
// TODO(gloas): use Gloas-specific PTC due threshold once
|
||||
// `get_payload_attestation_due_ms` is on ChainSpec.
|
||||
&& time_into_slot < spec.get_attestation_due::<E>(current_slot)),
|
||||
block_timeliness_ptc_threshold: is_genesis
|
||||
|| (is_current_slot && time_into_slot < spec.get_slot_duration() / 2),
|
||||
|| (is_current_slot && time_into_slot < spec.get_payload_attestation_due()),
|
||||
equivocating_attestation_score: 0,
|
||||
})
|
||||
};
|
||||
@@ -682,11 +671,17 @@ impl ProtoArray {
|
||||
}
|
||||
|
||||
/// Spec: `is_head_weak`.
|
||||
///
|
||||
/// The spec adds weight from equivocating validators in the head slot's
|
||||
/// committees. We approximate this with `equivocating_attestation_score`
|
||||
/// which tracks equivocating validators that voted for this block (close
|
||||
/// but not identical to committee membership).
|
||||
// TODO(gloas): the spec adds weight from equivocating validators in the
|
||||
// head slot's *committees*, regardless of who they voted for. We approximate
|
||||
// with `equivocating_attestation_score` which only tracks equivocating
|
||||
// validators whose vote pointed at this block. This under-counts when an
|
||||
// equivocating validator is in the committee but voted for a different fork,
|
||||
// which could allow a re-org the spec wouldn't. In practice the deviation
|
||||
// is small — it requires equivocating validators voting for competing forks
|
||||
// AND the head weight to be exactly at the reorg threshold boundary.
|
||||
// Fixing this properly requires committee computation from BeaconState,
|
||||
// which is not available in proto_array. The fix would be to pass
|
||||
// pre-computed equivocating committee weight from the beacon_chain caller.
|
||||
fn is_head_weak<E: EthSpec>(
|
||||
&self,
|
||||
head_node: &ProtoNode,
|
||||
@@ -729,7 +724,6 @@ impl ProtoArray {
|
||||
.nodes
|
||||
.get(block_index)
|
||||
.ok_or(Error::InvalidNodeIndex(block_index))?;
|
||||
// TODO(gloas): handle parent unknown case?
|
||||
let parent_index = block
|
||||
.parent()
|
||||
.ok_or(Error::NodeUnknown(proposer_boost_root))?;
|
||||
@@ -753,7 +747,6 @@ impl ProtoArray {
|
||||
// the parent's slot from the same proposer.
|
||||
let parent_slot = parent.slot();
|
||||
let parent_root = parent.root();
|
||||
// TODO(gloas): handle proposer index for pre-Gloas blocks?
|
||||
let parent_proposer = parent.proposer_index();
|
||||
|
||||
let has_equivocation = self.nodes.iter().any(|node| {
|
||||
@@ -773,12 +766,10 @@ impl ProtoArray {
|
||||
Ok(!has_equivocation)
|
||||
}
|
||||
|
||||
/// Process an execution payload for a Gloas block.
|
||||
/// Process a valid execution payload envelope for a Gloas block.
|
||||
///
|
||||
/// Sets `payload_received` to true, which makes `is_payload_timely` and
|
||||
/// `is_payload_data_available` return true regardless of PTC votes.
|
||||
/// This maps to `store.payload_states[root] = state` in the spec.
|
||||
pub fn on_valid_execution_payload(&mut self, block_root: Hash256) -> Result<(), Error> {
|
||||
/// Sets `payload_received` to true.
|
||||
pub fn on_valid_payload_envelope_received(&mut self, block_root: Hash256) -> Result<(), Error> {
|
||||
let index = *self
|
||||
.indices
|
||||
.get(&block_root)
|
||||
@@ -814,6 +805,8 @@ impl ProtoArray {
|
||||
|
||||
/// Updates the `verified_node_index` and all ancestors to have validated execution payloads.
|
||||
///
|
||||
/// This function is a no-op if called for a Gloas block.
|
||||
///
|
||||
/// Returns an error if:
|
||||
///
|
||||
/// - The `verified_node_index` is unknown.
|
||||
@@ -857,18 +850,10 @@ impl ProtoArray {
|
||||
});
|
||||
}
|
||||
},
|
||||
// Gloas nodes don't carry `ExecutionStatus`. Mark the validated
|
||||
// block as payload-received so that `is_payload_timely` /
|
||||
// `is_payload_data_available` and `index == 1` attestations work.
|
||||
ProtoNode::V29(node) => {
|
||||
if index == verified_node_index {
|
||||
node.payload_received = true;
|
||||
}
|
||||
if let Some(parent_index) = node.parent {
|
||||
parent_index
|
||||
} else {
|
||||
return Ok(());
|
||||
}
|
||||
// Gloas nodes should not be marked valid by this function, which exists only
|
||||
// for pre-Gloas fork choice.
|
||||
ProtoNode::V29(_) => {
|
||||
return Ok(());
|
||||
}
|
||||
};
|
||||
|
||||
@@ -879,6 +864,7 @@ impl ProtoArray {
|
||||
/// Invalidate zero or more blocks, as specified by the `InvalidationOperation`.
|
||||
///
|
||||
/// See the documentation of `InvalidationOperation` for usage.
|
||||
// TODO(gloas): this needs some tests for the mixed Gloas/pre-Gloas case.
|
||||
pub fn propagate_execution_payload_invalidation<E: EthSpec>(
|
||||
&mut self,
|
||||
op: &InvalidationOperation,
|
||||
@@ -978,7 +964,7 @@ impl ProtoArray {
|
||||
// This block is pre-merge, therefore it has no execution status. Nor do its
|
||||
// ancestors.
|
||||
Ok(ExecutionStatus::Irrelevant(_)) => break,
|
||||
Err(_) => (),
|
||||
Err(_) => break,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1087,9 +1073,6 @@ impl ProtoArray {
|
||||
});
|
||||
}
|
||||
|
||||
// In the post-Gloas world, always use a virtual tree walk.
|
||||
//
|
||||
// Best child/best descendant is dead.
|
||||
let best_fc_node = self.find_head_walk::<E>(
|
||||
justified_index,
|
||||
current_slot,
|
||||
@@ -1125,26 +1108,6 @@ impl ProtoArray {
|
||||
Ok((best_fc_node.root, best_fc_node.payload_status))
|
||||
}
|
||||
|
||||
/// Build a parent->children index. Invalid nodes are excluded
|
||||
/// (they aren't in store.blocks in the spec).
|
||||
fn build_children_index(&self) -> Vec<Vec<usize>> {
|
||||
let mut children = vec![vec![]; self.nodes.len()];
|
||||
for (i, node) in self.nodes.iter().enumerate() {
|
||||
if node
|
||||
.execution_status()
|
||||
.is_ok_and(|status| status.is_invalid())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if let Some(parent) = node.parent()
|
||||
&& parent < children.len()
|
||||
{
|
||||
children[parent].push(i);
|
||||
}
|
||||
}
|
||||
children
|
||||
}
|
||||
|
||||
/// Spec: `get_filtered_block_tree`.
|
||||
///
|
||||
/// Returns the set of node indices on viable branches — those with at least
|
||||
@@ -1155,7 +1118,6 @@ impl ProtoArray {
|
||||
current_slot: Slot,
|
||||
best_justified_checkpoint: Checkpoint,
|
||||
best_finalized_checkpoint: Checkpoint,
|
||||
children_index: &[Vec<usize>],
|
||||
) -> HashSet<usize> {
|
||||
let mut viable = HashSet::new();
|
||||
self.filter_block_tree::<E>(
|
||||
@@ -1163,7 +1125,6 @@ impl ProtoArray {
|
||||
current_slot,
|
||||
best_justified_checkpoint,
|
||||
best_finalized_checkpoint,
|
||||
children_index,
|
||||
&mut viable,
|
||||
);
|
||||
viable
|
||||
@@ -1176,17 +1137,25 @@ impl ProtoArray {
|
||||
current_slot: Slot,
|
||||
best_justified_checkpoint: Checkpoint,
|
||||
best_finalized_checkpoint: Checkpoint,
|
||||
children_index: &[Vec<usize>],
|
||||
viable: &mut HashSet<usize>,
|
||||
) -> bool {
|
||||
let Some(node) = self.nodes.get(node_index) else {
|
||||
return false;
|
||||
};
|
||||
|
||||
let children = children_index
|
||||
.get(node_index)
|
||||
.map(|c| c.as_slice())
|
||||
.unwrap_or(&[]);
|
||||
// Skip invalid children — they aren't in store.blocks in the spec.
|
||||
let children: Vec<usize> = self
|
||||
.nodes
|
||||
.iter()
|
||||
.enumerate()
|
||||
.filter(|(_, child)| {
|
||||
child.parent() == Some(node_index)
|
||||
&& !child
|
||||
.execution_status()
|
||||
.is_ok_and(|status| status.is_invalid())
|
||||
})
|
||||
.map(|(i, _)| i)
|
||||
.collect();
|
||||
|
||||
if !children.is_empty() {
|
||||
// Evaluate ALL children (no short-circuit) to mark all viable branches.
|
||||
@@ -1198,7 +1167,6 @@ impl ProtoArray {
|
||||
current_slot,
|
||||
best_justified_checkpoint,
|
||||
best_finalized_checkpoint,
|
||||
children_index,
|
||||
viable,
|
||||
)
|
||||
})
|
||||
@@ -1243,16 +1211,12 @@ impl ProtoArray {
|
||||
payload_status: PayloadStatus::Pending,
|
||||
};
|
||||
|
||||
// Build parent->children index once for O(1) lookups.
|
||||
let children_index = self.build_children_index();
|
||||
|
||||
// Spec: `get_filtered_block_tree`.
|
||||
let viable_nodes = self.get_filtered_block_tree::<E>(
|
||||
start_index,
|
||||
current_slot,
|
||||
best_justified_checkpoint,
|
||||
best_finalized_checkpoint,
|
||||
&children_index,
|
||||
);
|
||||
|
||||
// Compute once rather than per-child per-level.
|
||||
@@ -1261,7 +1225,7 @@ impl ProtoArray {
|
||||
|
||||
loop {
|
||||
let children: Vec<_> = self
|
||||
.get_node_children(&head, &children_index)?
|
||||
.get_node_children(&head)?
|
||||
.into_iter()
|
||||
.filter(|(fc_node, _)| viable_nodes.contains(&fc_node.proto_node_index))
|
||||
.collect();
|
||||
@@ -1272,11 +1236,7 @@ impl ProtoArray {
|
||||
|
||||
head = children
|
||||
.into_iter()
|
||||
.map(|(child, _)| -> Result<_, Error> {
|
||||
let proto_node = self
|
||||
.nodes
|
||||
.get(child.proto_node_index)
|
||||
.ok_or(Error::InvalidNodeIndex(child.proto_node_index))?;
|
||||
.map(|(child, ref proto_node)| -> Result<_, Error> {
|
||||
let weight = self.get_weight::<E>(
|
||||
&child,
|
||||
proto_node,
|
||||
@@ -1424,7 +1384,6 @@ impl ProtoArray {
|
||||
fn get_node_children(
|
||||
&self,
|
||||
node: &IndexedForkChoiceNode,
|
||||
children_index: &[Vec<usize>],
|
||||
) -> Result<Vec<(IndexedForkChoiceNode, ProtoNode)>, Error> {
|
||||
if node.payload_status == PayloadStatus::Pending {
|
||||
let proto_node = self
|
||||
@@ -1451,25 +1410,23 @@ impl ProtoArray {
|
||||
|
||||
Ok(children)
|
||||
} else {
|
||||
let child_indices = children_index
|
||||
.get(node.proto_node_index)
|
||||
.map(|c| c.as_slice())
|
||||
.unwrap_or(&[]);
|
||||
Ok(child_indices
|
||||
Ok(self
|
||||
.nodes
|
||||
.iter()
|
||||
.filter_map(|&child_index| {
|
||||
let child_node = self.nodes.get(child_index)?;
|
||||
if child_node.get_parent_payload_status() != node.payload_status {
|
||||
return None;
|
||||
}
|
||||
Some((
|
||||
.enumerate()
|
||||
.filter(|(_, child_node)| {
|
||||
child_node.parent() == Some(node.proto_node_index)
|
||||
&& child_node.get_parent_payload_status() == node.payload_status
|
||||
})
|
||||
.map(|(child_index, child_node)| {
|
||||
(
|
||||
IndexedForkChoiceNode {
|
||||
root: child_node.root(),
|
||||
proto_node_index: child_index,
|
||||
payload_status: PayloadStatus::Pending,
|
||||
},
|
||||
child_node.clone(),
|
||||
))
|
||||
)
|
||||
})
|
||||
.collect())
|
||||
}
|
||||
|
||||
@@ -2,8 +2,7 @@ use crate::{
|
||||
JustifiedBalances,
|
||||
error::Error,
|
||||
proto_array::{
|
||||
InvalidationOperation, Iter, NodeDelta, ProposerBoost, ProtoArray, ProtoNode,
|
||||
calculate_committee_fraction,
|
||||
InvalidationOperation, Iter, NodeDelta, ProtoArray, ProtoNode, calculate_committee_fraction,
|
||||
},
|
||||
ssz_container::SszContainer,
|
||||
};
|
||||
@@ -74,6 +73,7 @@ impl From<VoteTracker> for VoteTrackerV28 {
|
||||
}
|
||||
}
|
||||
|
||||
/// Spec's `LatestMessage` type. Only used in tests.
|
||||
pub struct LatestMessage {
|
||||
pub slot: Slot,
|
||||
pub root: Hash256,
|
||||
@@ -527,7 +527,6 @@ impl ProtoArrayForkChoice {
|
||||
prune_threshold: DEFAULT_PRUNE_THRESHOLD,
|
||||
nodes: Vec::with_capacity(1),
|
||||
indices: HashMap::with_capacity(1),
|
||||
previous_proposer_boost: ProposerBoost::default(),
|
||||
};
|
||||
|
||||
let block = Block {
|
||||
@@ -569,11 +568,18 @@ impl ProtoArrayForkChoice {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn on_execution_payload(&mut self, block_root: Hash256) -> Result<(), String> {
|
||||
/// Mark a Gloas payload envelope as valid and received.
|
||||
///
|
||||
/// This must only be called for valid Gloas payloads.
|
||||
pub fn on_valid_payload_envelope_received(
|
||||
&mut self,
|
||||
block_root: Hash256,
|
||||
) -> Result<(), String> {
|
||||
self.proto_array
|
||||
.on_valid_execution_payload(block_root)
|
||||
.on_valid_payload_envelope_received(block_root)
|
||||
.map_err(|e| format!("Failed to process execution payload: {:?}", e))
|
||||
}
|
||||
|
||||
/// See `ProtoArray::propagate_execution_payload_validation` for documentation.
|
||||
pub fn process_execution_payload_validation(
|
||||
&mut self,
|
||||
@@ -880,10 +886,7 @@ impl ProtoArrayForkChoice {
|
||||
/// status to be optimistic.
|
||||
///
|
||||
/// In practice this means forgetting any `VALID` or `INVALID` statuses.
|
||||
pub fn set_all_blocks_to_optimistic<E: EthSpec>(
|
||||
&mut self,
|
||||
spec: &ChainSpec,
|
||||
) -> Result<(), String> {
|
||||
pub fn set_all_blocks_to_optimistic<E: EthSpec>(&mut self) -> Result<(), String> {
|
||||
// Iterate backwards through all nodes in the `proto_array`. Whilst it's not strictly
|
||||
// required to do this process in reverse, it seems natural when we consider how LMD votes
|
||||
// are counted.
|
||||
@@ -906,7 +909,7 @@ impl ProtoArrayForkChoice {
|
||||
|
||||
// Restore the weight of the node, it would have been set to `0` in
|
||||
// `apply_score_changes` when it was invalidated.
|
||||
let mut restored_weight: u64 = self
|
||||
let restored_weight: u64 = self
|
||||
.votes
|
||||
.0
|
||||
.iter()
|
||||
@@ -922,26 +925,6 @@ impl ProtoArrayForkChoice {
|
||||
})
|
||||
.sum();
|
||||
|
||||
// If the invalid root was boosted, apply the weight to it and
|
||||
// ancestors.
|
||||
if let Some(proposer_score_boost) = spec.proposer_score_boost
|
||||
&& self.proto_array.previous_proposer_boost.root == node.root()
|
||||
{
|
||||
// Compute the score based upon the current balances. We can't rely on
|
||||
// the `previous_proposr_boost.score` since it is set to zero with an
|
||||
// invalid node.
|
||||
let proposer_score =
|
||||
calculate_committee_fraction::<E>(&self.balances, proposer_score_boost)
|
||||
.ok_or("Failed to compute proposer boost")?;
|
||||
// Store the score we've applied here so it can be removed in
|
||||
// a later call to `apply_score_changes`.
|
||||
self.proto_array.previous_proposer_boost.score = proposer_score;
|
||||
// Apply this boost to this node.
|
||||
restored_weight = restored_weight
|
||||
.checked_add(proposer_score)
|
||||
.ok_or("Overflow when adding boost to weight")?;
|
||||
}
|
||||
|
||||
// Add the restored weight to the node and all ancestors.
|
||||
if restored_weight > 0 {
|
||||
let mut node_or_ancestor = node;
|
||||
@@ -1082,10 +1065,9 @@ impl ProtoArrayForkChoice {
|
||||
.is_finalized_checkpoint_or_descendant::<E>(descendant_root, best_finalized_checkpoint)
|
||||
}
|
||||
|
||||
/// NOTE: only used in tests.
|
||||
pub fn latest_message(&self, validator_index: usize) -> Option<LatestMessage> {
|
||||
if validator_index < self.votes.0.len() {
|
||||
let vote = &self.votes.0[validator_index];
|
||||
|
||||
if let Some(vote) = self.votes.0.get(validator_index) {
|
||||
if *vote == VoteTracker::default() {
|
||||
None
|
||||
} else {
|
||||
|
||||
@@ -38,6 +38,7 @@ pub struct SszContainer {
|
||||
#[superstruct(only(V29))]
|
||||
pub nodes: Vec<ProtoNode>,
|
||||
pub indices: Vec<(Hash256, usize)>,
|
||||
#[superstruct(only(V28))]
|
||||
pub previous_proposer_boost: ProposerBoost,
|
||||
}
|
||||
|
||||
@@ -50,7 +51,6 @@ impl SszContainerV29 {
|
||||
prune_threshold: proto_array.prune_threshold,
|
||||
nodes: proto_array.nodes.clone(),
|
||||
indices: proto_array.indices.iter().map(|(k, v)| (*k, *v)).collect(),
|
||||
previous_proposer_boost: proto_array.previous_proposer_boost,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -63,7 +63,6 @@ impl TryFrom<(SszContainerV29, JustifiedBalances)> for ProtoArrayForkChoice {
|
||||
prune_threshold: from.prune_threshold,
|
||||
nodes: from.nodes,
|
||||
indices: from.indices.into_iter().collect::<HashMap<_, _>>(),
|
||||
previous_proposer_boost: from.previous_proposer_boost,
|
||||
};
|
||||
|
||||
Ok(Self {
|
||||
@@ -92,7 +91,6 @@ impl From<SszContainerV28> for SszContainerV29 {
|
||||
})
|
||||
.collect(),
|
||||
indices: v28.indices,
|
||||
previous_proposer_boost: v28.previous_proposer_boost,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -116,7 +114,8 @@ impl From<SszContainerV29> for SszContainerV28 {
|
||||
})
|
||||
.collect(),
|
||||
indices: v29.indices,
|
||||
previous_proposer_boost: v29.previous_proposer_boost,
|
||||
// Proposer boost is not tracked in V29 (computed on-the-fly), so reset it.
|
||||
previous_proposer_boost: ProposerBoost::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user