mirror of
https://github.com/sigp/lighthouse.git
synced 2026-05-30 04:37:13 +00:00
Gloas alpha spec 8 (#9315)
https://github.com/ethereum/consensus-specs/releases/tag/v1.7.0-alpha.8 Co-Authored-By: Eitan Seri-Levi <eserilev@ucsc.edu> Co-Authored-By: Michael Sproul <michael@sigmaprime.io>
This commit is contained in:
@@ -155,6 +155,10 @@ pub struct ProtoNode {
|
||||
/// Tiebreak derived as: `num_set_bits() > ptc_size / 2`.
|
||||
#[superstruct(only(V29))]
|
||||
pub payload_data_availability_votes: BitVector<U512>,
|
||||
/// Tracks which PTC members have cast a vote.
|
||||
/// Bit i set means PTC member i has submitted a payload attestation.
|
||||
#[superstruct(only(V29))]
|
||||
pub ptc_participation: 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.
|
||||
#[superstruct(only(V29), partial_getter(copy))]
|
||||
@@ -193,31 +197,60 @@ impl ProtoNode {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_payload_timely<E: EthSpec>(&self) -> bool {
|
||||
/// Checks if `timely` matches our view of payload timeliness.
|
||||
/// Returns whether the execution payload for the node is considered `timely`
|
||||
/// (or not `timely` when `timely` is `false`), taking into consideration local
|
||||
/// availability and PTC votes.
|
||||
pub fn payload_timeliness<E: EthSpec>(&self, timely: bool) -> Result<bool, Error> {
|
||||
let Ok(node) = self.as_v29() else {
|
||||
return false;
|
||||
return Err(Error::InvalidNodeVariant {
|
||||
block_root: self.root(),
|
||||
});
|
||||
};
|
||||
|
||||
// Equivalent to `if root not in store.payload_states` in the spec.
|
||||
// Equivalent to `if not is_payload_verified(store, root)` in the spec.
|
||||
if !node.payload_received {
|
||||
return false;
|
||||
return Ok(!timely);
|
||||
}
|
||||
|
||||
node.payload_timeliness_votes.num_set_bits() > E::payload_timely_threshold()
|
||||
let matching_votes = if timely {
|
||||
node.payload_timeliness_votes.num_set_bits()
|
||||
} else {
|
||||
// We take into consideration only participating ptc votes. An unset bit
|
||||
// in `payload_timeliness_votes` could be an absent vote or a no vote.
|
||||
node.ptc_participation
|
||||
.num_set_bits()
|
||||
.saturating_sub(node.payload_timeliness_votes.num_set_bits())
|
||||
};
|
||||
Ok(matching_votes > E::payload_timely_threshold())
|
||||
}
|
||||
|
||||
pub fn is_payload_data_available<E: EthSpec>(&self) -> bool {
|
||||
/// Checks if `available` matches our view of payload data availability.
|
||||
/// Return whether the blob data for the node is considered `available`
|
||||
/// (or not, when `available` is `False`), taking into consideration local
|
||||
/// availability and PTC votes.
|
||||
pub fn payload_data_availability<E: EthSpec>(&self, available: bool) -> Result<bool, Error> {
|
||||
let Ok(node) = self.as_v29() else {
|
||||
return false;
|
||||
return Err(Error::InvalidNodeVariant {
|
||||
block_root: self.root(),
|
||||
});
|
||||
};
|
||||
|
||||
// Equivalent to `if root not in store.payload_states` in the spec.
|
||||
// Equivalent to `if not is_payload_verified(store, root)` in the spec.
|
||||
if !node.payload_received {
|
||||
return false;
|
||||
return Ok(!available);
|
||||
}
|
||||
|
||||
node.payload_data_availability_votes.num_set_bits()
|
||||
> E::data_availability_timely_threshold()
|
||||
let matching_votes = if available {
|
||||
node.payload_data_availability_votes.num_set_bits()
|
||||
} else {
|
||||
// We take into consideration only participating ptc votes. An unset bit
|
||||
// in `payload_data_availability_votes` could be an absent vote or a no vote.
|
||||
node.ptc_participation
|
||||
.num_set_bits()
|
||||
.saturating_sub(node.payload_data_availability_votes.num_set_bits())
|
||||
};
|
||||
Ok(matching_votes > E::data_availability_timely_threshold())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -605,6 +638,7 @@ impl ProtoArray {
|
||||
execution_payload_parent_hash,
|
||||
payload_timeliness_votes: BitVector::default(),
|
||||
payload_data_availability_votes: BitVector::default(),
|
||||
ptc_participation: BitVector::default(),
|
||||
payload_received: false,
|
||||
proposer_index,
|
||||
// Spec: `record_block_timeliness` + `get_forkchoice_store`.
|
||||
@@ -1501,12 +1535,46 @@ impl ProtoArray {
|
||||
}
|
||||
}
|
||||
|
||||
/// Called by the proposer to decide whether to build on the full or empty
|
||||
/// parent pending node. Returns false if the PTC has voted the data as unavailable.
|
||||
pub fn should_build_on_full<E: EthSpec>(
|
||||
&self,
|
||||
fc_node: &IndexedForkChoiceNode,
|
||||
proto_node: &ProtoNode,
|
||||
) -> Result<bool, Error> {
|
||||
if fc_node.payload_status == PayloadStatus::Pending {
|
||||
return Err(Error::InvalidPayloadStatus {
|
||||
block_root: proto_node.root(),
|
||||
payload_status: fc_node.payload_status,
|
||||
});
|
||||
}
|
||||
|
||||
if fc_node.payload_status == PayloadStatus::Empty {
|
||||
return Ok(false);
|
||||
}
|
||||
// Check that false votes have not achieved an absolute majority. This allows the payload to be
|
||||
// considered available when either a majority have voted true or not enough votes have
|
||||
// been cast either way.
|
||||
Ok(!proto_node.payload_data_availability::<E>(false)?)
|
||||
}
|
||||
|
||||
pub fn should_extend_payload<E: EthSpec>(
|
||||
&self,
|
||||
fc_node: &IndexedForkChoiceNode,
|
||||
proto_node: &ProtoNode,
|
||||
proposer_boost_root: Hash256,
|
||||
) -> Result<bool, Error> {
|
||||
let Ok(node) = proto_node.as_v29() else {
|
||||
return Err(Error::InvalidNodeVariant {
|
||||
block_root: fc_node.root,
|
||||
});
|
||||
};
|
||||
|
||||
// Spec equivalent to `if not is_payload_verified(store, root): return False`
|
||||
if !node.payload_received {
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
// Per spec: `proposer_root == Root()` is one of the `or` conditions that
|
||||
// makes `should_extend_payload` return True.
|
||||
if proposer_boost_root.is_zero() {
|
||||
@@ -1531,11 +1599,10 @@ impl ProtoArray {
|
||||
.ok_or(Error::InvalidNodeIndex(parent_index))?
|
||||
.root();
|
||||
|
||||
Ok(
|
||||
(proto_node.is_payload_timely::<E>() && proto_node.is_payload_data_available::<E>())
|
||||
|| proposer_boost_parent_root != fc_node.root
|
||||
|| proposer_boost_node.is_parent_node_full(),
|
||||
)
|
||||
Ok((proto_node.payload_timeliness::<E>(true)?
|
||||
&& proto_node.payload_data_availability::<E>(true)?)
|
||||
|| proposer_boost_parent_root != fc_node.root
|
||||
|| proposer_boost_node.is_parent_node_full())
|
||||
}
|
||||
|
||||
/// Update the tree with new finalization information. The tree is only actually pruned if both
|
||||
|
||||
Reference in New Issue
Block a user