Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions beacon_node/beacon_chain/src/block_verification.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ use std::fs;
use std::io::Write;
use std::sync::Arc;
use store::{Error as DBError, KeyValueStore};
use strum::AsRefStr;
use strum::{AsRefStr, IntoStaticStr};
use task_executor::JoinHandle;
use tracing::{Instrument, Span, debug, debug_span, error, info_span, instrument};
use types::{
Expand Down Expand Up @@ -138,7 +138,7 @@ const WRITE_BLOCK_PROCESSING_SSZ: bool = cfg!(feature = "write_ssz_files");
///
/// - The block is malformed/invalid (indicated by all results other than `BeaconChainError`.
/// - We encountered an error whilst trying to verify the block (a `BeaconChainError`).
#[derive(Debug, AsRefStr)]
#[derive(Debug, AsRefStr, IntoStaticStr)]
pub enum BlockError {
/// The parent block was unknown.
///
Expand Down
186 changes: 78 additions & 108 deletions beacon_node/network/src/network_beacon_processor/gossip_methods.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1262,114 +1262,84 @@ impl<T: BeaconChainTypes> NetworkBeaconProcessor<T> {

verified_block
}
Err(e @ BlockError::Slashable) => {
warn!(
error = ?e,
"Received equivocating block from peer"
);
/* punish peer for submitting an equivocation, but not too harshly as honest peers may conceivably forward equivocating blocks to us from time to time */
self.gossip_penalize_peer(
peer_id,
PeerAction::MidToleranceError,
"gossip_block_mid",
);
return None;
}
Err(BlockError::ParentUnknown { .. }) => {
debug!(?block_root, "Unknown parent for gossip block");
self.send_sync_message(SyncMessage::UnknownParentBlock(peer_id, block, block_root));
return None;
}
Err(e @ BlockError::BeaconChainError(_)) => {
debug!(
error = ?e,
"Gossip block beacon chain error"
);
self.propagate_validation_result(message_id, peer_id, MessageAcceptance::Ignore);
return None;
}
Err(
BlockError::DuplicateFullyImported(_)
| BlockError::DuplicateImportStatusUnknown(..),
) => {
debug!(
%block_root,
"Gossip block is already known"
);
self.propagate_validation_result(message_id, peer_id, MessageAcceptance::Ignore);
return None;
}
Err(e @ BlockError::FutureSlot { .. }) => {
debug!(
error = %e,
"Could not verify block for gossip. Ignoring the block"
);
// Prevent recurring behaviour by penalizing the peer slightly.
self.gossip_penalize_peer(
peer_id,
PeerAction::HighToleranceError,
"gossip_block_high",
);
self.propagate_validation_result(message_id, peer_id, MessageAcceptance::Ignore);
return None;
}
Err(e @ BlockError::WouldRevertFinalizedSlot { .. })
| Err(e @ BlockError::NotFinalizedDescendant { .. }) => {
debug!(
error = %e,
"Could not verify block for gossip. Ignoring the block"
);
// The spec says we must IGNORE these blocks but there's no reason for an honest
// and non-buggy client to be gossiping blocks that blatantly conflict with
// finalization. Old versions of Erigon/Caplin are known to gossip pre-finalization
// blocks and we want to isolate them to encourage an update.
self.gossip_penalize_peer(
peer_id,
PeerAction::LowToleranceError,
"gossip_block_low",
);
self.propagate_validation_result(message_id, peer_id, MessageAcceptance::Ignore);
return None;
}
Err(ref e @ BlockError::ExecutionPayloadError(ref epe)) if !epe.penalize_peer() => {
debug!(error = %e, "Could not verify block for gossip. Ignoring the block");
self.propagate_validation_result(message_id, peer_id, MessageAcceptance::Ignore);
return None;
}
Err(e @ BlockError::StateRootMismatch { .. })
| Err(e @ BlockError::IncorrectBlockProposer { .. })
| Err(e @ BlockError::BlockSlotLimitReached)
| Err(e @ BlockError::NonLinearSlots)
| Err(e @ BlockError::UnknownValidator(_))
| Err(e @ BlockError::PerBlockProcessingError(_))
| Err(e @ BlockError::NonLinearParentRoots)
| Err(e @ BlockError::BlockIsNotLaterThanParent { .. })
| Err(e @ BlockError::InvalidSignature(_))
| Err(e @ BlockError::WeakSubjectivityConflict)
| Err(e @ BlockError::InconsistentFork(_))
| Err(e @ BlockError::ExecutionPayloadError(_))
| Err(e @ BlockError::ParentExecutionPayloadInvalid { .. })
| Err(e @ BlockError::KnownInvalidExecutionPayload(_))
| Err(e @ BlockError::GenesisBlock)
| Err(e @ BlockError::InvalidBlobCount { .. }) => {
warn!(error = %e, "Could not verify block for gossip. Rejecting the block");
self.propagate_validation_result(message_id, peer_id, MessageAcceptance::Reject);
self.gossip_penalize_peer(
peer_id,
PeerAction::LowToleranceError,
"gossip_block_low",
);
return None;
}
// Note: This error variant cannot be reached when doing gossip validation
// as we do not do availability checks here.
Err(e @ BlockError::AvailabilityCheck(_)) => {
crit!(error = %e, "Internal block gossip validation error. Availability check during gossip validation");
return None;
}
// BlobNotRequired is unreachable. Only constructed in `process_gossip_blob`
Err(e @ BlockError::InternalError(_)) | Err(e @ BlockError::BlobNotRequired(_)) => {
error!(error = %e, "Internal block gossip validation error");
Err(e) => {
let (penalty, acceptance) = match e {
BlockError::Slashable => {
warn!(
error = ?e,
"Received equivocating block from peer"
);
/* punish peer for submitting an equivocation, but not too harshly as honest peers may conceivably forward equivocating blocks to us from time to time */
(
Some(PeerAction::MidToleranceError),
MessageAcceptance::Ignore,
)
}
BlockError::ParentUnknown { .. } => {
self.send_sync_message(SyncMessage::UnknownParentBlock(
peer_id, block, block_root,
));
(None, MessageAcceptance::Ignore)
}
BlockError::BeaconChainError(_) => (None, MessageAcceptance::Ignore),
BlockError::DuplicateFullyImported(_)
| BlockError::DuplicateImportStatusUnknown(..) => {
(None, MessageAcceptance::Ignore)
}
BlockError::FutureSlot { .. } => {
// Prevent recurring behaviour by penalizing the peer slightly.
(
Some(PeerAction::HighToleranceError),
MessageAcceptance::Ignore,
)
}
BlockError::WouldRevertFinalizedSlot { .. }
| BlockError::NotFinalizedDescendant { .. } => {
// The spec says we must IGNORE these blocks but there's no reason for an honest
// and non-buggy client to be gossiping blocks that blatantly conflict with
// finalization. Old versions of Erigon/Caplin are known to gossip pre-finalization
// blocks and we want to isolate them to encourage an update.
(
Some(PeerAction::LowToleranceError),
MessageAcceptance::Ignore,
)
}
BlockError::ExecutionPayloadError(ref epe) if !epe.penalize_peer() => {
(None, MessageAcceptance::Ignore)
}
BlockError::StateRootMismatch { .. }
| BlockError::IncorrectBlockProposer { .. }
| BlockError::BlockSlotLimitReached
| BlockError::NonLinearSlots
| BlockError::UnknownValidator(_)
| BlockError::PerBlockProcessingError(_)
| BlockError::NonLinearParentRoots
| BlockError::BlockIsNotLaterThanParent { .. }
| BlockError::InvalidSignature(_)
| BlockError::WeakSubjectivityConflict
| BlockError::InconsistentFork(_)
| BlockError::ExecutionPayloadError(_)
| BlockError::ParentExecutionPayloadInvalid { .. }
| BlockError::KnownInvalidExecutionPayload(_)
| BlockError::GenesisBlock
| BlockError::InvalidBlobCount { .. } => (
Some(PeerAction::LowToleranceError),
MessageAcceptance::Reject,
),
// Note: The AvailabilityCheck variant is unreachable when doing gossip validation
// as we do not do availability checks here.
BlockError::AvailabilityCheck(_)
| BlockError::InternalError(_)
| BlockError::BlobNotRequired(_) => {
error!(error = %e, "Internal block gossip validation error");
(None, MessageAcceptance::Ignore)
}
};
debug!(?block_root, ?acceptance, error = ?e, "Received invalid gossip block");
self.propagate_validation_result(message_id, peer_id, acceptance);
if let Some(penalty) = penalty {
self.gossip_penalize_peer(peer_id, penalty, e.into());
}
return None;
}
};
Expand Down