mirror of
https://github.com/sigp/lighthouse.git
synced 2026-04-22 07:18:25 +00:00
Merge branch 'eip4844' into deneb-free-blobs
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
use crate::{ForkChoiceStore, InvalidationOperation};
|
||||
use proto_array::{
|
||||
Block as ProtoBlock, CountUnrealizedFull, ExecutionStatus, ProposerHeadError, ProposerHeadInfo,
|
||||
Block as ProtoBlock, ExecutionStatus, ProposerHeadError, ProposerHeadInfo,
|
||||
ProtoArrayForkChoice, ReOrgThreshold,
|
||||
};
|
||||
use slog::{crit, debug, warn, Logger};
|
||||
@@ -187,51 +187,6 @@ impl CountUnrealized {
|
||||
pub fn is_true(&self) -> bool {
|
||||
matches!(self, CountUnrealized::True)
|
||||
}
|
||||
|
||||
pub fn and(&self, other: CountUnrealized) -> CountUnrealized {
|
||||
if self.is_true() && other.is_true() {
|
||||
CountUnrealized::True
|
||||
} else {
|
||||
CountUnrealized::False
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<bool> for CountUnrealized {
|
||||
fn from(count_unrealized: bool) -> Self {
|
||||
if count_unrealized {
|
||||
CountUnrealized::True
|
||||
} else {
|
||||
CountUnrealized::False
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
enum UpdateJustifiedCheckpointSlots {
|
||||
OnTick {
|
||||
current_slot: Slot,
|
||||
},
|
||||
OnBlock {
|
||||
state_slot: Slot,
|
||||
current_slot: Slot,
|
||||
},
|
||||
}
|
||||
|
||||
impl UpdateJustifiedCheckpointSlots {
|
||||
fn current_slot(&self) -> Slot {
|
||||
match self {
|
||||
UpdateJustifiedCheckpointSlots::OnTick { current_slot } => *current_slot,
|
||||
UpdateJustifiedCheckpointSlots::OnBlock { current_slot, .. } => *current_slot,
|
||||
}
|
||||
}
|
||||
|
||||
fn state_slot(&self) -> Option<Slot> {
|
||||
match self {
|
||||
UpdateJustifiedCheckpointSlots::OnTick { .. } => None,
|
||||
UpdateJustifiedCheckpointSlots::OnBlock { state_slot, .. } => Some(*state_slot),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Indicates if a block has been verified by an execution payload.
|
||||
@@ -393,7 +348,6 @@ where
|
||||
anchor_block: &SignedBeaconBlock<E>,
|
||||
anchor_state: &BeaconState<E>,
|
||||
current_slot: Option<Slot>,
|
||||
count_unrealized_full_config: CountUnrealizedFull,
|
||||
spec: &ChainSpec,
|
||||
) -> Result<Self, Error<T::Error>> {
|
||||
// Sanity check: the anchor must lie on an epoch boundary.
|
||||
@@ -440,7 +394,6 @@ where
|
||||
current_epoch_shuffling_id,
|
||||
next_epoch_shuffling_id,
|
||||
execution_status,
|
||||
count_unrealized_full_config,
|
||||
)?;
|
||||
|
||||
let mut fork_choice = Self {
|
||||
@@ -533,7 +486,7 @@ where
|
||||
// Provide the slot (as per the system clock) to the `fc_store` and then return its view of
|
||||
// the current slot. The `fc_store` will ensure that the `current_slot` is never
|
||||
// decreasing, a property which we must maintain.
|
||||
let current_slot = self.update_time(system_time_current_slot, spec)?;
|
||||
let current_slot = self.update_time(system_time_current_slot)?;
|
||||
|
||||
let store = &mut self.fc_store;
|
||||
|
||||
@@ -654,58 +607,6 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if the given `store` should be updated to set
|
||||
/// `state.current_justified_checkpoint` its `justified_checkpoint`.
|
||||
///
|
||||
/// ## Specification
|
||||
///
|
||||
/// Is equivalent to:
|
||||
///
|
||||
/// https://github.com/ethereum/eth2.0-specs/blob/v0.12.1/specs/phase0/fork-choice.md#should_update_justified_checkpoint
|
||||
fn should_update_justified_checkpoint(
|
||||
&mut self,
|
||||
new_justified_checkpoint: Checkpoint,
|
||||
slots: UpdateJustifiedCheckpointSlots,
|
||||
spec: &ChainSpec,
|
||||
) -> Result<bool, Error<T::Error>> {
|
||||
self.update_time(slots.current_slot(), spec)?;
|
||||
|
||||
if compute_slots_since_epoch_start::<E>(self.fc_store.get_current_slot())
|
||||
< spec.safe_slots_to_update_justified
|
||||
{
|
||||
return Ok(true);
|
||||
}
|
||||
|
||||
let justified_slot =
|
||||
compute_start_slot_at_epoch::<E>(self.fc_store.justified_checkpoint().epoch);
|
||||
|
||||
// This sanity check is not in the spec, but the invariant is implied.
|
||||
if let Some(state_slot) = slots.state_slot() {
|
||||
if justified_slot >= state_slot {
|
||||
return Err(Error::AttemptToRevertJustification {
|
||||
store: justified_slot,
|
||||
state: state_slot,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// We know that the slot for `new_justified_checkpoint.root` is not greater than
|
||||
// `state.slot`, since a state cannot justify its own slot.
|
||||
//
|
||||
// We know that `new_justified_checkpoint.root` is an ancestor of `state`, since a `state`
|
||||
// only ever justifies ancestors.
|
||||
//
|
||||
// A prior `if` statement protects against a justified_slot that is greater than
|
||||
// `state.slot`
|
||||
let justified_ancestor =
|
||||
self.get_ancestor(new_justified_checkpoint.root, justified_slot)?;
|
||||
if justified_ancestor != Some(self.fc_store.justified_checkpoint().root) {
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
/// See `ProtoArrayForkChoice::process_execution_payload_validation` for documentation.
|
||||
pub fn on_valid_execution_payload(
|
||||
&mut self,
|
||||
@@ -759,7 +660,7 @@ where
|
||||
// Provide the slot (as per the system clock) to the `fc_store` and then return its view of
|
||||
// the current slot. The `fc_store` will ensure that the `current_slot` is never
|
||||
// decreasing, a property which we must maintain.
|
||||
let current_slot = self.update_time(system_time_current_slot, spec)?;
|
||||
let current_slot = self.update_time(system_time_current_slot)?;
|
||||
|
||||
// Parent block must be known.
|
||||
let parent_block = self
|
||||
@@ -814,17 +715,10 @@ where
|
||||
self.fc_store.set_proposer_boost_root(block_root);
|
||||
}
|
||||
|
||||
let update_justified_checkpoint_slots = UpdateJustifiedCheckpointSlots::OnBlock {
|
||||
state_slot: state.slot(),
|
||||
current_slot,
|
||||
};
|
||||
|
||||
// Update store with checkpoints if necessary
|
||||
self.update_checkpoints(
|
||||
state.current_justified_checkpoint(),
|
||||
state.finalized_checkpoint(),
|
||||
update_justified_checkpoint_slots,
|
||||
spec,
|
||||
)?;
|
||||
|
||||
// Update unrealized justified/finalized checkpoints.
|
||||
@@ -908,11 +802,9 @@ where
|
||||
|
||||
// If block is from past epochs, try to update store's justified & finalized checkpoints right away
|
||||
if block.slot().epoch(E::slots_per_epoch()) < current_slot.epoch(E::slots_per_epoch()) {
|
||||
self.update_checkpoints(
|
||||
self.pull_up_store_checkpoints(
|
||||
unrealized_justified_checkpoint,
|
||||
unrealized_finalized_checkpoint,
|
||||
update_justified_checkpoint_slots,
|
||||
spec,
|
||||
)?;
|
||||
}
|
||||
|
||||
@@ -1007,29 +899,19 @@ where
|
||||
&mut self,
|
||||
justified_checkpoint: Checkpoint,
|
||||
finalized_checkpoint: Checkpoint,
|
||||
slots: UpdateJustifiedCheckpointSlots,
|
||||
spec: &ChainSpec,
|
||||
) -> Result<(), Error<T::Error>> {
|
||||
// Update justified checkpoint.
|
||||
if justified_checkpoint.epoch > self.fc_store.justified_checkpoint().epoch {
|
||||
if justified_checkpoint.epoch > self.fc_store.best_justified_checkpoint().epoch {
|
||||
self.fc_store
|
||||
.set_best_justified_checkpoint(justified_checkpoint);
|
||||
}
|
||||
if self.should_update_justified_checkpoint(justified_checkpoint, slots, spec)? {
|
||||
self.fc_store
|
||||
.set_justified_checkpoint(justified_checkpoint)
|
||||
.map_err(Error::UnableToSetJustifiedCheckpoint)?;
|
||||
}
|
||||
self.fc_store
|
||||
.set_justified_checkpoint(justified_checkpoint)
|
||||
.map_err(Error::UnableToSetJustifiedCheckpoint)?;
|
||||
}
|
||||
|
||||
// Update finalized checkpoint.
|
||||
if finalized_checkpoint.epoch > self.fc_store.finalized_checkpoint().epoch {
|
||||
self.fc_store.set_finalized_checkpoint(finalized_checkpoint);
|
||||
self.fc_store
|
||||
.set_justified_checkpoint(justified_checkpoint)
|
||||
.map_err(Error::UnableToSetJustifiedCheckpoint)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1170,9 +1052,8 @@ where
|
||||
system_time_current_slot: Slot,
|
||||
attestation: &IndexedAttestation<E>,
|
||||
is_from_block: AttestationFromBlock,
|
||||
spec: &ChainSpec,
|
||||
) -> Result<(), Error<T::Error>> {
|
||||
self.update_time(system_time_current_slot, spec)?;
|
||||
self.update_time(system_time_current_slot)?;
|
||||
|
||||
// Ignore any attestations to the zero hash.
|
||||
//
|
||||
@@ -1233,16 +1114,12 @@ where
|
||||
|
||||
/// Call `on_tick` for all slots between `fc_store.get_current_slot()` and the provided
|
||||
/// `current_slot`. Returns the value of `self.fc_store.get_current_slot`.
|
||||
pub fn update_time(
|
||||
&mut self,
|
||||
current_slot: Slot,
|
||||
spec: &ChainSpec,
|
||||
) -> Result<Slot, Error<T::Error>> {
|
||||
pub fn update_time(&mut self, current_slot: Slot) -> Result<Slot, Error<T::Error>> {
|
||||
while self.fc_store.get_current_slot() < current_slot {
|
||||
let previous_slot = self.fc_store.get_current_slot();
|
||||
// Note: we are relying upon `on_tick` to update `fc_store.time` to ensure we don't
|
||||
// get stuck in a loop.
|
||||
self.on_tick(previous_slot + 1, spec)?
|
||||
self.on_tick(previous_slot + 1)?
|
||||
}
|
||||
|
||||
// Process any attestations that might now be eligible.
|
||||
@@ -1258,7 +1135,7 @@ where
|
||||
/// Equivalent to:
|
||||
///
|
||||
/// https://github.com/ethereum/eth2.0-specs/blob/v0.12.1/specs/phase0/fork-choice.md#on_tick
|
||||
fn on_tick(&mut self, time: Slot, spec: &ChainSpec) -> Result<(), Error<T::Error>> {
|
||||
fn on_tick(&mut self, time: Slot) -> Result<(), Error<T::Error>> {
|
||||
let store = &mut self.fc_store;
|
||||
let previous_slot = store.get_current_slot();
|
||||
|
||||
@@ -1286,26 +1163,27 @@ where
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
if store.best_justified_checkpoint().epoch > store.justified_checkpoint().epoch {
|
||||
let store = &self.fc_store;
|
||||
if self.is_finalized_checkpoint_or_descendant(store.best_justified_checkpoint().root) {
|
||||
let store = &mut self.fc_store;
|
||||
store
|
||||
.set_justified_checkpoint(*store.best_justified_checkpoint())
|
||||
.map_err(Error::ForkChoiceStoreError)?;
|
||||
}
|
||||
}
|
||||
|
||||
// Update store.justified_checkpoint if a better unrealized justified checkpoint is known
|
||||
// Update the justified/finalized checkpoints based upon the
|
||||
// best-observed unrealized justification/finality.
|
||||
let unrealized_justified_checkpoint = *self.fc_store.unrealized_justified_checkpoint();
|
||||
let unrealized_finalized_checkpoint = *self.fc_store.unrealized_finalized_checkpoint();
|
||||
self.pull_up_store_checkpoints(
|
||||
unrealized_justified_checkpoint,
|
||||
unrealized_finalized_checkpoint,
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn pull_up_store_checkpoints(
|
||||
&mut self,
|
||||
unrealized_justified_checkpoint: Checkpoint,
|
||||
unrealized_finalized_checkpoint: Checkpoint,
|
||||
) -> Result<(), Error<T::Error>> {
|
||||
self.update_checkpoints(
|
||||
unrealized_justified_checkpoint,
|
||||
unrealized_finalized_checkpoint,
|
||||
UpdateJustifiedCheckpointSlots::OnTick { current_slot },
|
||||
spec,
|
||||
)?;
|
||||
Ok(())
|
||||
)
|
||||
}
|
||||
|
||||
/// Processes and removes from the queue any queued attestations which may now be eligible for
|
||||
@@ -1471,16 +1349,6 @@ where
|
||||
*self.fc_store.justified_checkpoint()
|
||||
}
|
||||
|
||||
/// Return the best justified checkpoint.
|
||||
///
|
||||
/// ## Warning
|
||||
///
|
||||
/// This is distinct to the "justified checkpoint" or the "current justified checkpoint". This
|
||||
/// "best justified checkpoint" value should only be used internally or for testing.
|
||||
pub fn best_justified_checkpoint(&self) -> Checkpoint {
|
||||
*self.fc_store.best_justified_checkpoint()
|
||||
}
|
||||
|
||||
pub fn unrealized_justified_checkpoint(&self) -> Checkpoint {
|
||||
*self.fc_store.unrealized_justified_checkpoint()
|
||||
}
|
||||
@@ -1541,13 +1409,11 @@ where
|
||||
pub fn proto_array_from_persisted(
|
||||
persisted: &PersistedForkChoice,
|
||||
reset_payload_statuses: ResetPayloadStatuses,
|
||||
count_unrealized_full: CountUnrealizedFull,
|
||||
spec: &ChainSpec,
|
||||
log: &Logger,
|
||||
) -> Result<ProtoArrayForkChoice, Error<T::Error>> {
|
||||
let mut proto_array =
|
||||
ProtoArrayForkChoice::from_bytes(&persisted.proto_array_bytes, count_unrealized_full)
|
||||
.map_err(Error::InvalidProtoArrayBytes)?;
|
||||
let mut proto_array = ProtoArrayForkChoice::from_bytes(&persisted.proto_array_bytes)
|
||||
.map_err(Error::InvalidProtoArrayBytes)?;
|
||||
let contains_invalid_payloads = proto_array.contains_invalid_payloads();
|
||||
|
||||
debug!(
|
||||
@@ -1578,7 +1444,7 @@ where
|
||||
"error" => e,
|
||||
"info" => "please report this error",
|
||||
);
|
||||
ProtoArrayForkChoice::from_bytes(&persisted.proto_array_bytes, count_unrealized_full)
|
||||
ProtoArrayForkChoice::from_bytes(&persisted.proto_array_bytes)
|
||||
.map_err(Error::InvalidProtoArrayBytes)
|
||||
} else {
|
||||
debug!(
|
||||
@@ -1595,17 +1461,11 @@ where
|
||||
persisted: PersistedForkChoice,
|
||||
reset_payload_statuses: ResetPayloadStatuses,
|
||||
fc_store: T,
|
||||
count_unrealized_full: CountUnrealizedFull,
|
||||
spec: &ChainSpec,
|
||||
log: &Logger,
|
||||
) -> Result<Self, Error<T::Error>> {
|
||||
let proto_array = Self::proto_array_from_persisted(
|
||||
&persisted,
|
||||
reset_payload_statuses,
|
||||
count_unrealized_full,
|
||||
spec,
|
||||
log,
|
||||
)?;
|
||||
let proto_array =
|
||||
Self::proto_array_from_persisted(&persisted, reset_payload_statuses, spec, log)?;
|
||||
|
||||
let current_slot = fc_store.get_current_slot();
|
||||
|
||||
|
||||
@@ -47,9 +47,6 @@ pub trait ForkChoiceStore<T: EthSpec>: Sized {
|
||||
/// Returns balances from the `state` identified by `justified_checkpoint.root`.
|
||||
fn justified_balances(&self) -> &JustifiedBalances;
|
||||
|
||||
/// Returns the `best_justified_checkpoint`.
|
||||
fn best_justified_checkpoint(&self) -> &Checkpoint;
|
||||
|
||||
/// Returns the `finalized_checkpoint`.
|
||||
fn finalized_checkpoint(&self) -> &Checkpoint;
|
||||
|
||||
@@ -68,9 +65,6 @@ pub trait ForkChoiceStore<T: EthSpec>: Sized {
|
||||
/// Sets the `justified_checkpoint`.
|
||||
fn set_justified_checkpoint(&mut self, checkpoint: Checkpoint) -> Result<(), Self::Error>;
|
||||
|
||||
/// Sets the `best_justified_checkpoint`.
|
||||
fn set_best_justified_checkpoint(&mut self, checkpoint: Checkpoint);
|
||||
|
||||
/// Sets the `unrealized_justified_checkpoint`.
|
||||
fn set_unrealized_justified_checkpoint(&mut self, checkpoint: Checkpoint);
|
||||
|
||||
|
||||
@@ -7,6 +7,4 @@ pub use crate::fork_choice::{
|
||||
PersistedForkChoice, QueuedAttestation, ResetPayloadStatuses,
|
||||
};
|
||||
pub use fork_choice_store::ForkChoiceStore;
|
||||
pub use proto_array::{
|
||||
Block as ProtoBlock, CountUnrealizedFull, ExecutionStatus, InvalidationOperation,
|
||||
};
|
||||
pub use proto_array::{Block as ProtoBlock, ExecutionStatus, InvalidationOperation};
|
||||
|
||||
@@ -104,16 +104,6 @@ impl ForkChoiceTest {
|
||||
self
|
||||
}
|
||||
|
||||
/// Assert the epochs match.
|
||||
pub fn assert_best_justified_epoch(self, epoch: u64) -> Self {
|
||||
assert_eq!(
|
||||
self.get(|fc_store| fc_store.best_justified_checkpoint().epoch),
|
||||
Epoch::new(epoch),
|
||||
"best_justified_epoch"
|
||||
);
|
||||
self
|
||||
}
|
||||
|
||||
/// Assert the given slot is greater than the head slot.
|
||||
pub fn assert_finalized_epoch_is_less_than(self, epoch: Epoch) -> Self {
|
||||
assert!(self.harness.finalized_checkpoint().epoch < epoch);
|
||||
@@ -151,7 +141,7 @@ impl ForkChoiceTest {
|
||||
.chain
|
||||
.canonical_head
|
||||
.fork_choice_write_lock()
|
||||
.update_time(self.harness.chain.slot().unwrap(), &self.harness.spec)
|
||||
.update_time(self.harness.chain.slot().unwrap())
|
||||
.unwrap();
|
||||
func(
|
||||
self.harness
|
||||
@@ -241,6 +231,11 @@ impl ForkChoiceTest {
|
||||
///
|
||||
/// If the chain is presently in an unsafe period, transition through it and the following safe
|
||||
/// period.
|
||||
///
|
||||
/// Note: the `SAFE_SLOTS_TO_UPDATE_JUSTIFIED` variable has been removed
|
||||
/// from the fork choice spec in Q1 2023. We're still leaving references to
|
||||
/// it in our tests because (a) it's easier and (b) it allows us to easily
|
||||
/// test for the absence of that parameter.
|
||||
pub fn move_to_next_unsafe_period(self) -> Self {
|
||||
self.move_inside_safe_to_update()
|
||||
.move_outside_safe_to_update()
|
||||
@@ -534,7 +529,6 @@ async fn justified_checkpoint_updates_with_descendent_outside_safe_slots() {
|
||||
.unwrap()
|
||||
.move_outside_safe_to_update()
|
||||
.assert_justified_epoch(2)
|
||||
.assert_best_justified_epoch(2)
|
||||
.apply_blocks(1)
|
||||
.await
|
||||
.assert_justified_epoch(3);
|
||||
@@ -551,11 +545,9 @@ async fn justified_checkpoint_updates_first_justification_outside_safe_to_update
|
||||
.unwrap()
|
||||
.move_to_next_unsafe_period()
|
||||
.assert_justified_epoch(0)
|
||||
.assert_best_justified_epoch(0)
|
||||
.apply_blocks(1)
|
||||
.await
|
||||
.assert_justified_epoch(2)
|
||||
.assert_best_justified_epoch(2);
|
||||
.assert_justified_epoch(2);
|
||||
}
|
||||
|
||||
/// - The new justified checkpoint **does not** descend from the current.
|
||||
@@ -583,8 +575,7 @@ async fn justified_checkpoint_updates_with_non_descendent_inside_safe_slots_with
|
||||
.unwrap();
|
||||
})
|
||||
.await
|
||||
.assert_justified_epoch(3)
|
||||
.assert_best_justified_epoch(3);
|
||||
.assert_justified_epoch(3);
|
||||
}
|
||||
|
||||
/// - The new justified checkpoint **does not** descend from the current.
|
||||
@@ -612,8 +603,9 @@ async fn justified_checkpoint_updates_with_non_descendent_outside_safe_slots_wit
|
||||
.unwrap();
|
||||
})
|
||||
.await
|
||||
.assert_justified_epoch(2)
|
||||
.assert_best_justified_epoch(3);
|
||||
// Now that `SAFE_SLOTS_TO_UPDATE_JUSTIFIED` has been removed, the new
|
||||
// block should have updated the justified checkpoint.
|
||||
.assert_justified_epoch(3);
|
||||
}
|
||||
|
||||
/// - The new justified checkpoint **does not** descend from the current.
|
||||
@@ -641,8 +633,7 @@ async fn justified_checkpoint_updates_with_non_descendent_outside_safe_slots_wit
|
||||
.unwrap();
|
||||
})
|
||||
.await
|
||||
.assert_justified_epoch(3)
|
||||
.assert_best_justified_epoch(3);
|
||||
.assert_justified_epoch(3);
|
||||
}
|
||||
|
||||
/// Check that the balances are obtained correctly.
|
||||
|
||||
@@ -3,7 +3,6 @@ mod ffg_updates;
|
||||
mod no_votes;
|
||||
mod votes;
|
||||
|
||||
use crate::proto_array::CountUnrealizedFull;
|
||||
use crate::proto_array_fork_choice::{Block, ExecutionStatus, ProtoArrayForkChoice};
|
||||
use crate::{InvalidationOperation, JustifiedBalances};
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
@@ -88,7 +87,6 @@ impl ForkChoiceTestDefinition {
|
||||
junk_shuffling_id.clone(),
|
||||
junk_shuffling_id,
|
||||
ExecutionStatus::Optimistic(ExecutionBlockHash::zero()),
|
||||
CountUnrealizedFull::default(),
|
||||
)
|
||||
.expect("should create fork choice struct");
|
||||
let equivocating_indices = BTreeSet::new();
|
||||
@@ -307,8 +305,8 @@ fn get_checkpoint(i: u64) -> Checkpoint {
|
||||
|
||||
fn check_bytes_round_trip(original: &ProtoArrayForkChoice) {
|
||||
let bytes = original.as_bytes();
|
||||
let decoded = ProtoArrayForkChoice::from_bytes(&bytes, CountUnrealizedFull::default())
|
||||
.expect("fork choice should decode from bytes");
|
||||
let decoded =
|
||||
ProtoArrayForkChoice::from_bytes(&bytes).expect("fork choice should decode from bytes");
|
||||
assert!(
|
||||
*original == decoded,
|
||||
"fork choice should encode and decode without change"
|
||||
|
||||
@@ -24,7 +24,7 @@ impl JustifiedBalances {
|
||||
.validators()
|
||||
.iter()
|
||||
.map(|validator| {
|
||||
if validator.is_active_at(current_epoch) {
|
||||
if !validator.slashed && validator.is_active_at(current_epoch) {
|
||||
total_effective_balance.safe_add_assign(validator.effective_balance)?;
|
||||
num_active_validators.safe_add_assign(1)?;
|
||||
|
||||
|
||||
@@ -6,9 +6,7 @@ mod proto_array_fork_choice;
|
||||
mod ssz_container;
|
||||
|
||||
pub use crate::justified_balances::JustifiedBalances;
|
||||
pub use crate::proto_array::{
|
||||
calculate_committee_fraction, CountUnrealizedFull, InvalidationOperation,
|
||||
};
|
||||
pub use crate::proto_array::{calculate_committee_fraction, InvalidationOperation};
|
||||
pub use crate::proto_array_fork_choice::{
|
||||
Block, DoNotReOrg, ExecutionStatus, ProposerHeadError, ProposerHeadInfo, ProtoArrayForkChoice,
|
||||
ReOrgThreshold,
|
||||
|
||||
@@ -118,24 +118,6 @@ impl Default for ProposerBoost {
|
||||
}
|
||||
}
|
||||
|
||||
/// Indicate whether we should strictly count unrealized justification/finalization votes.
|
||||
#[derive(Default, PartialEq, Eq, Debug, Serialize, Deserialize, Copy, Clone)]
|
||||
pub enum CountUnrealizedFull {
|
||||
True,
|
||||
#[default]
|
||||
False,
|
||||
}
|
||||
|
||||
impl From<bool> for CountUnrealizedFull {
|
||||
fn from(b: bool) -> Self {
|
||||
if b {
|
||||
CountUnrealizedFull::True
|
||||
} else {
|
||||
CountUnrealizedFull::False
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Debug, Serialize, Deserialize, Clone)]
|
||||
pub struct ProtoArray {
|
||||
/// Do not attempt to prune the tree unless it has at least this many nodes. Small prunes
|
||||
@@ -146,7 +128,6 @@ pub struct ProtoArray {
|
||||
pub nodes: Vec<ProtoNode>,
|
||||
pub indices: HashMap<Hash256, usize>,
|
||||
pub previous_proposer_boost: ProposerBoost,
|
||||
pub count_unrealized_full: CountUnrealizedFull,
|
||||
}
|
||||
|
||||
impl ProtoArray {
|
||||
@@ -684,9 +665,9 @@ impl ProtoArray {
|
||||
start_root: *justified_root,
|
||||
justified_checkpoint: self.justified_checkpoint,
|
||||
finalized_checkpoint: self.finalized_checkpoint,
|
||||
head_root: justified_node.root,
|
||||
head_justified_checkpoint: justified_node.justified_checkpoint,
|
||||
head_finalized_checkpoint: justified_node.finalized_checkpoint,
|
||||
head_root: best_node.root,
|
||||
head_justified_checkpoint: best_node.justified_checkpoint,
|
||||
head_finalized_checkpoint: best_node.finalized_checkpoint,
|
||||
})));
|
||||
}
|
||||
|
||||
@@ -900,55 +881,44 @@ impl ProtoArray {
|
||||
}
|
||||
|
||||
let genesis_epoch = Epoch::new(0);
|
||||
|
||||
let checkpoint_match_predicate =
|
||||
|node_justified_checkpoint: Checkpoint, node_finalized_checkpoint: Checkpoint| {
|
||||
let correct_justified = node_justified_checkpoint == self.justified_checkpoint
|
||||
|| self.justified_checkpoint.epoch == genesis_epoch;
|
||||
let correct_finalized = node_finalized_checkpoint == self.finalized_checkpoint
|
||||
|| self.finalized_checkpoint.epoch == genesis_epoch;
|
||||
correct_justified && correct_finalized
|
||||
let current_epoch = current_slot.epoch(E::slots_per_epoch());
|
||||
let node_epoch = node.slot.epoch(E::slots_per_epoch());
|
||||
let node_justified_checkpoint =
|
||||
if let Some(justified_checkpoint) = node.justified_checkpoint {
|
||||
justified_checkpoint
|
||||
} else {
|
||||
// The node does not have any information about the justified
|
||||
// checkpoint. This indicates an inconsistent proto-array.
|
||||
return false;
|
||||
};
|
||||
|
||||
if let (
|
||||
Some(unrealized_justified_checkpoint),
|
||||
Some(unrealized_finalized_checkpoint),
|
||||
Some(justified_checkpoint),
|
||||
Some(finalized_checkpoint),
|
||||
) = (
|
||||
node.unrealized_justified_checkpoint,
|
||||
node.unrealized_finalized_checkpoint,
|
||||
node.justified_checkpoint,
|
||||
node.finalized_checkpoint,
|
||||
) {
|
||||
let current_epoch = current_slot.epoch(E::slots_per_epoch());
|
||||
|
||||
// If previous epoch is justified, pull up all tips to at least the previous epoch
|
||||
if CountUnrealizedFull::True == self.count_unrealized_full
|
||||
&& (current_epoch > genesis_epoch
|
||||
&& self.justified_checkpoint.epoch + 1 == current_epoch)
|
||||
{
|
||||
unrealized_justified_checkpoint.epoch + 1 >= current_epoch
|
||||
// If previous epoch is not justified, pull up only tips from past epochs up to the current epoch
|
||||
} else {
|
||||
// If block is from a previous epoch, filter using unrealized justification & finalization information
|
||||
if node.slot.epoch(E::slots_per_epoch()) < current_epoch {
|
||||
checkpoint_match_predicate(
|
||||
unrealized_justified_checkpoint,
|
||||
unrealized_finalized_checkpoint,
|
||||
)
|
||||
// If block is from the current epoch, filter using the head state's justification & finalization information
|
||||
} else {
|
||||
checkpoint_match_predicate(justified_checkpoint, finalized_checkpoint)
|
||||
}
|
||||
}
|
||||
} else if let (Some(justified_checkpoint), Some(finalized_checkpoint)) =
|
||||
(node.justified_checkpoint, node.finalized_checkpoint)
|
||||
{
|
||||
checkpoint_match_predicate(justified_checkpoint, finalized_checkpoint)
|
||||
let voting_source = if current_epoch > node_epoch {
|
||||
// The block is from a prior epoch, the voting source will be pulled-up.
|
||||
node.unrealized_justified_checkpoint
|
||||
// Sometimes we don't track the unrealized justification. In
|
||||
// that case, just use the fully-realized justified checkpoint.
|
||||
.unwrap_or(node_justified_checkpoint)
|
||||
} else {
|
||||
false
|
||||
// The block is not from a prior epoch, therefore the voting source
|
||||
// is not pulled up.
|
||||
node_justified_checkpoint
|
||||
};
|
||||
|
||||
let mut correct_justified = self.justified_checkpoint.epoch == genesis_epoch
|
||||
|| voting_source.epoch == self.justified_checkpoint.epoch;
|
||||
|
||||
if let Some(node_unrealized_justified_checkpoint) = node.unrealized_justified_checkpoint {
|
||||
if !correct_justified && self.justified_checkpoint.epoch + 1 == current_epoch {
|
||||
correct_justified = node_unrealized_justified_checkpoint.epoch
|
||||
>= self.justified_checkpoint.epoch
|
||||
&& voting_source.epoch + 2 >= current_epoch;
|
||||
}
|
||||
}
|
||||
|
||||
let correct_finalized = self.finalized_checkpoint.epoch == genesis_epoch
|
||||
|| self.is_finalized_checkpoint_or_descendant::<E>(node.root);
|
||||
|
||||
correct_justified && correct_finalized
|
||||
}
|
||||
|
||||
/// Return a reverse iterator over the nodes which comprise the chain ending at `block_root`.
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
use crate::{
|
||||
error::Error,
|
||||
proto_array::{
|
||||
calculate_committee_fraction, CountUnrealizedFull, InvalidationOperation, Iter,
|
||||
ProposerBoost, ProtoArray, ProtoNode,
|
||||
calculate_committee_fraction, InvalidationOperation, Iter, ProposerBoost, ProtoArray,
|
||||
ProtoNode,
|
||||
},
|
||||
ssz_container::SszContainer,
|
||||
JustifiedBalances,
|
||||
@@ -307,7 +307,6 @@ impl ProtoArrayForkChoice {
|
||||
current_epoch_shuffling_id: AttestationShufflingId,
|
||||
next_epoch_shuffling_id: AttestationShufflingId,
|
||||
execution_status: ExecutionStatus,
|
||||
count_unrealized_full: CountUnrealizedFull,
|
||||
) -> Result<Self, String> {
|
||||
let mut proto_array = ProtoArray {
|
||||
prune_threshold: DEFAULT_PRUNE_THRESHOLD,
|
||||
@@ -316,7 +315,6 @@ impl ProtoArrayForkChoice {
|
||||
nodes: Vec::with_capacity(1),
|
||||
indices: HashMap::with_capacity(1),
|
||||
previous_proposer_boost: ProposerBoost::default(),
|
||||
count_unrealized_full,
|
||||
};
|
||||
|
||||
let block = Block {
|
||||
@@ -780,13 +778,10 @@ impl ProtoArrayForkChoice {
|
||||
SszContainer::from(self).as_ssz_bytes()
|
||||
}
|
||||
|
||||
pub fn from_bytes(
|
||||
bytes: &[u8],
|
||||
count_unrealized_full: CountUnrealizedFull,
|
||||
) -> Result<Self, String> {
|
||||
pub fn from_bytes(bytes: &[u8]) -> Result<Self, String> {
|
||||
let container = SszContainer::from_ssz_bytes(bytes)
|
||||
.map_err(|e| format!("Failed to decode ProtoArrayForkChoice: {:?}", e))?;
|
||||
(container, count_unrealized_full)
|
||||
container
|
||||
.try_into()
|
||||
.map_err(|e| format!("Failed to initialize ProtoArrayForkChoice: {e:?}"))
|
||||
}
|
||||
@@ -950,7 +945,6 @@ mod test_compute_deltas {
|
||||
junk_shuffling_id.clone(),
|
||||
junk_shuffling_id.clone(),
|
||||
execution_status,
|
||||
CountUnrealizedFull::default(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
@@ -1076,7 +1070,6 @@ mod test_compute_deltas {
|
||||
junk_shuffling_id.clone(),
|
||||
junk_shuffling_id.clone(),
|
||||
execution_status,
|
||||
CountUnrealizedFull::default(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use crate::proto_array::ProposerBoost;
|
||||
use crate::{
|
||||
proto_array::{CountUnrealizedFull, ProtoArray, ProtoNode},
|
||||
proto_array::{ProtoArray, ProtoNode},
|
||||
proto_array_fork_choice::{ElasticList, ProtoArrayForkChoice, VoteTracker},
|
||||
Error, JustifiedBalances,
|
||||
};
|
||||
@@ -43,12 +43,10 @@ impl From<&ProtoArrayForkChoice> for SszContainer {
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<(SszContainer, CountUnrealizedFull)> for ProtoArrayForkChoice {
|
||||
impl TryFrom<SszContainer> for ProtoArrayForkChoice {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(
|
||||
(from, count_unrealized_full): (SszContainer, CountUnrealizedFull),
|
||||
) -> Result<Self, Error> {
|
||||
fn try_from(from: SszContainer) -> Result<Self, Error> {
|
||||
let proto_array = ProtoArray {
|
||||
prune_threshold: from.prune_threshold,
|
||||
justified_checkpoint: from.justified_checkpoint,
|
||||
@@ -56,7 +54,6 @@ impl TryFrom<(SszContainer, CountUnrealizedFull)> for ProtoArrayForkChoice {
|
||||
nodes: from.nodes,
|
||||
indices: from.indices.into_iter().collect::<HashMap<_, _>>(),
|
||||
previous_proposer_boost: from.previous_proposer_boost,
|
||||
count_unrealized_full,
|
||||
};
|
||||
|
||||
Ok(Self {
|
||||
|
||||
@@ -633,7 +633,7 @@ impl ChainSpec {
|
||||
* Capella hard fork params
|
||||
*/
|
||||
capella_fork_version: [0x03, 00, 00, 00],
|
||||
capella_fork_epoch: None,
|
||||
capella_fork_epoch: Some(Epoch::new(194048)),
|
||||
max_validators_per_withdrawals_sweep: 16384,
|
||||
|
||||
/*
|
||||
|
||||
@@ -171,3 +171,13 @@ impl<T: EthSpec> ForkVersionDeserialize for ExecutionPayload<T> {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: EthSpec> ExecutionPayload<T> {
|
||||
pub fn fork_name(&self) -> ForkName {
|
||||
match self {
|
||||
ExecutionPayload::Merge(_) => ForkName::Merge,
|
||||
ExecutionPayload::Capella(_) => ForkName::Capella,
|
||||
ExecutionPayload::Eip4844(_) => ForkName::Eip4844,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user