Remove CountUnrealized (#4357)

## Issue Addressed

Closes #4332

## Proposed Changes

Remove the `CountUnrealized` type, defaulting unrealized justification to _on_. This fixes the #4332 issue by ensuring that importing the same block to fork choice always results in the same outcome.

Finalized sync speed may be slightly impacted by this change, but that is deemed an acceptable trade-off until the optimisation from #4118 is implemented.

TODO:

- [x] Also check that the block isn't a duplicate before importing
This commit is contained in:
Michael Sproul
2023-06-16 06:44:31 +00:00
parent 77fc511170
commit affea585f4
19 changed files with 229 additions and 266 deletions

View File

@@ -63,7 +63,6 @@ use execution_layer::{
BlockProposalContents, BuilderParams, ChainHealth, ExecutionLayer, FailedCondition,
PayloadAttributes, PayloadStatus,
};
pub use fork_choice::CountUnrealized;
use fork_choice::{
AttestationFromBlock, ExecutionStatus, ForkChoice, ForkchoiceUpdateParameters,
InvalidationOperation, PayloadVerificationStatus, ResetPayloadStatuses,
@@ -2510,7 +2509,6 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
pub async fn process_chain_segment(
self: &Arc<Self>,
chain_segment: Vec<Arc<SignedBeaconBlock<T::EthSpec>>>,
count_unrealized: CountUnrealized,
notify_execution_layer: NotifyExecutionLayer,
) -> ChainSegmentResult<T::EthSpec> {
let mut imported_blocks = 0;
@@ -2579,7 +2577,6 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
.process_block(
signature_verified_block.block_root(),
signature_verified_block,
count_unrealized,
notify_execution_layer,
)
.await
@@ -2668,7 +2665,6 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
self: &Arc<Self>,
block_root: Hash256,
unverified_block: B,
count_unrealized: CountUnrealized,
notify_execution_layer: NotifyExecutionLayer,
) -> Result<Hash256, BlockError<T::EthSpec>> {
// Start the Prometheus timer.
@@ -2689,7 +2685,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
notify_execution_layer,
)?;
chain
.import_execution_pending_block(execution_pending, count_unrealized)
.import_execution_pending_block(execution_pending)
.await
};
@@ -2744,10 +2740,9 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
///
/// An error is returned if the block was unable to be imported. It may be partially imported
/// (i.e., this function is not atomic).
async fn import_execution_pending_block(
pub async fn import_execution_pending_block(
self: Arc<Self>,
execution_pending_block: ExecutionPendingBlock<T>,
count_unrealized: CountUnrealized,
) -> Result<Hash256, BlockError<T::EthSpec>> {
let ExecutionPendingBlock {
block,
@@ -2808,7 +2803,6 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
state,
confirmed_state_roots,
payload_verification_status,
count_unrealized,
parent_block,
parent_eth1_finalization_data,
consensus_context,
@@ -2834,7 +2828,6 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
mut state: BeaconState<T::EthSpec>,
confirmed_state_roots: Vec<Hash256>,
payload_verification_status: PayloadVerificationStatus,
count_unrealized: CountUnrealized,
parent_block: SignedBlindedBeaconBlock<T::EthSpec>,
parent_eth1_finalization_data: Eth1FinalizationData,
mut consensus_context: ConsensusContext<T::EthSpec>,
@@ -2903,7 +2896,6 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
&state,
payload_verification_status,
&self.spec,
count_unrealized,
)
.map_err(|e| BlockError::BeaconChainError(e.into()))?;
}

View File

@@ -18,7 +18,7 @@ use crate::{
};
use eth1::Config as Eth1Config;
use execution_layer::ExecutionLayer;
use fork_choice::{CountUnrealized, ForkChoice, ResetPayloadStatuses};
use fork_choice::{ForkChoice, ResetPayloadStatuses};
use futures::channel::mpsc::Sender;
use operation_pool::{OperationPool, PersistedOperationPool};
use parking_lot::RwLock;
@@ -687,7 +687,6 @@ where
store.clone(),
Some(current_slot),
&self.spec,
CountUnrealized::True,
)?;
}

View File

@@ -1,5 +1,5 @@
use crate::{BeaconForkChoiceStore, BeaconSnapshot};
use fork_choice::{CountUnrealized, ForkChoice, PayloadVerificationStatus};
use fork_choice::{ForkChoice, PayloadVerificationStatus};
use itertools::process_results;
use slog::{info, warn, Logger};
use state_processing::state_advance::complete_state_advance;
@@ -100,7 +100,6 @@ pub fn reset_fork_choice_to_finalization<E: EthSpec, Hot: ItemStore<E>, Cold: It
store: Arc<HotColdDB<E, Hot, Cold>>,
current_slot: Option<Slot>,
spec: &ChainSpec,
count_unrealized_config: CountUnrealized,
) -> Result<ForkChoice<BeaconForkChoiceStore<E, Hot, Cold>, E>, String> {
// Fetch finalized block.
let finalized_checkpoint = head_state.finalized_checkpoint();
@@ -166,8 +165,7 @@ pub fn reset_fork_choice_to_finalization<E: EthSpec, Hot: ItemStore<E>, Cold: It
.map_err(|e| format!("Error loading blocks to replay for fork choice: {:?}", e))?;
let mut state = finalized_snapshot.beacon_state;
let blocks_len = blocks.len();
for (i, block) in blocks.into_iter().enumerate() {
for block in blocks {
complete_state_advance(&mut state, None, block.slot(), spec)
.map_err(|e| format!("State advance failed: {:?}", e))?;
@@ -190,15 +188,6 @@ pub fn reset_fork_choice_to_finalization<E: EthSpec, Hot: ItemStore<E>, Cold: It
// This scenario is so rare that it seems OK to double-verify some blocks.
let payload_verification_status = PayloadVerificationStatus::Optimistic;
// Because we are replaying a single chain of blocks, we only need to calculate unrealized
// justification for the last block in the chain.
let is_last_block = i + 1 == blocks_len;
let count_unrealized = if is_last_block {
count_unrealized_config
} else {
CountUnrealized::False
};
fork_choice
.on_block(
block.slot(),
@@ -209,7 +198,6 @@ pub fn reset_fork_choice_to_finalization<E: EthSpec, Hot: ItemStore<E>, Cold: It
&state,
payload_verification_status,
spec,
count_unrealized,
)
.map_err(|e| format!("Error applying replayed block to fork choice: {:?}", e))?;
}

View File

@@ -52,8 +52,8 @@ pub mod validator_pubkey_cache;
pub use self::beacon_chain::{
AttestationProcessingOutcome, BeaconChain, BeaconChainTypes, BeaconStore, ChainSegmentResult,
CountUnrealized, ForkChoiceError, OverrideForkchoiceUpdate, ProduceBlockVerification,
StateSkipConfig, WhenSlotSkipped, INVALID_FINALIZED_MERGE_TRANSITION_BLOCK_SHUTDOWN_REASON,
ForkChoiceError, OverrideForkchoiceUpdate, ProduceBlockVerification, StateSkipConfig,
WhenSlotSkipped, INVALID_FINALIZED_MERGE_TRANSITION_BLOCK_SHUTDOWN_REASON,
INVALID_JUSTIFIED_PAYLOAD_SHUTDOWN_REASON, MAXIMUM_GOSSIP_CLOCK_DISPARITY,
};
pub use self::beacon_snapshot::BeaconSnapshot;
@@ -64,6 +64,7 @@ pub use attestation_verification::Error as AttestationError;
pub use beacon_fork_choice_store::{BeaconForkChoiceStore, Error as ForkChoiceStoreError};
pub use block_verification::{
get_block_root, BlockError, ExecutionPayloadError, GossipVerifiedBlock,
IntoExecutionPendingBlock,
};
pub use canonical_head::{CachedHead, CanonicalHead, CanonicalHeadRwLock};
pub use eth1_chain::{Eth1Chain, Eth1ChainBackend};

View File

@@ -22,7 +22,6 @@ use execution_layer::{
},
ExecutionLayer,
};
use fork_choice::CountUnrealized;
use futures::channel::mpsc::Receiver;
pub use genesis::{interop_genesis_state_with_eth1, DEFAULT_ETH1_BLOCK_HASH};
use int_to_bytes::int_to_bytes32;
@@ -1693,12 +1692,7 @@ where
self.set_current_slot(slot);
let block_hash: SignedBeaconBlockHash = self
.chain
.process_block(
block_root,
Arc::new(block),
CountUnrealized::True,
NotifyExecutionLayer::Yes,
)
.process_block(block_root, Arc::new(block), NotifyExecutionLayer::Yes)
.await?
.into();
self.chain.recompute_head_at_current_slot().await;
@@ -1714,7 +1708,6 @@ where
.process_block(
block.canonical_root(),
Arc::new(block),
CountUnrealized::True,
NotifyExecutionLayer::Yes,
)
.await?