Skip to content

Commit

Permalink
Don't request block components until having block (#5774)
Browse files Browse the repository at this point in the history
* Don't request block components until having block

* Update tests

* Resolve todo comment

* Merge branch 'unstable' into request-blocks-first
  • Loading branch information
dapplion committed May 14, 2024
1 parent ce66ab3 commit 683d9df
Show file tree
Hide file tree
Showing 6 changed files with 207 additions and 314 deletions.
31 changes: 9 additions & 22 deletions beacon_node/network/src/sync/block_lookups/mod.rs
Expand Up @@ -7,7 +7,6 @@ use crate::metrics;
use crate::sync::block_lookups::common::{ResponseType, PARENT_DEPTH_TOLERANCE};
use crate::sync::block_lookups::parent_chain::find_oldest_fork_ancestor;
use crate::sync::manager::{Id, SingleLookupReqId};
use crate::sync::network_context::LookupFailure;
use beacon_chain::block_verification_types::AsBlock;
use beacon_chain::data_availability_checker::AvailabilityCheckErrorCategory;
use beacon_chain::{AvailabilityProcessingStatus, BeaconChainTypes, BlockError};
Expand Down Expand Up @@ -325,12 +324,7 @@ impl<T: BeaconChainTypes> BlockLookups<T> {
response: RpcProcessingResult<R::VerifiedResponseType>,
cx: &mut SyncNetworkContext<T>,
) -> Result<LookupResult, LookupRequestError> {
// Downscore peer even if lookup is not known
// Only downscore lookup verify errors. RPC errors are downscored in the network handler.
if let Err(LookupFailure::LookupVerifyError(e)) = &response {
// Note: the error is displayed in full debug form on the match below
cx.report_peer(peer_id, PeerAction::LowToleranceError, e.into());
}
// Note: no need to downscore peers here, already downscored on network context

let response_type = R::response_type();
let Some(lookup) = self.single_block_lookups.get_mut(&id.lookup_id) else {
Expand Down Expand Up @@ -459,23 +453,16 @@ impl<T: BeaconChainTypes> BlockLookups<T> {
// if both components have been processed.
request_state.on_processing_success()?;

// If this was the result of a block request, we can't determined if the block peer did anything
// wrong. If we already had both a block and blobs response processed, we should penalize the
// blobs peer because they did not provide all blobs on the initial request.
if lookup.both_components_processed() {
if let Some(blob_peer) = lookup
.blob_request_state
.state
.on_post_process_validation_failure()?
{
cx.report_peer(
blob_peer,
PeerAction::MidToleranceError,
"sent_incomplete_blobs",
);
}
// We don't request for other block components until being sure that the block has
// data. If we request blobs / columns to a peer we are sure those must exist.
// Therefore if all components are processed and we still receive `MissingComponents`
// it indicates an internal bug.
return Err(LookupRequestError::MissingComponentsAfterAllProcessed);
} else {
// Continue request, potentially request blobs
Action::Retry
}
Action::Retry
}
BlockProcessingResult::Ignored => {
// Beacon processor signalled to ignore the block processing result.
Expand Down
33 changes: 9 additions & 24 deletions beacon_node/network/src/sync/block_lookups/single_block_lookup.rs
Expand Up @@ -39,6 +39,9 @@ pub enum LookupRequestError {
BadState(String),
/// Lookup failed for some other reason and should be dropped
Failed,
/// Received MissingComponents when all components have been processed. This should never
/// happen, and indicates some internal bug
MissingComponentsAfterAllProcessed,
/// Attempted to retrieve a not known lookup id
UnknownLookup,
/// Received a download result for a different request id than the in-flight request.
Expand Down Expand Up @@ -158,7 +161,7 @@ impl<T: BeaconChainTypes> SingleBlockLookup<T> {
}

/// Potentially makes progress on this request if it's in a progress-able state
pub fn continue_request<R: RequestState<T>>(
fn continue_request<R: RequestState<T>>(
&mut self,
cx: &mut SyncNetworkContext<T>,
) -> Result<(), LookupRequestError> {
Expand Down Expand Up @@ -285,10 +288,8 @@ pub enum State<T: Clone> {
AwaitingProcess(DownloadResult<T>),
/// Request is processing, sent by lookup sync
Processing(DownloadResult<T>),
/// Request is processed:
/// - `Processed(Some)` if lookup sync downloaded and sent to process this request
/// - `Processed(None)` if another source (i.e. gossip) sent this component for processing
Processed(Option<PeerId>),
/// Request is processed
Processed,
}

/// Object representing the state of a single block or blob lookup request.
Expand Down Expand Up @@ -463,8 +464,8 @@ impl<T: Clone> SingleLookupRequestState<T> {

pub fn on_processing_success(&mut self) -> Result<(), LookupRequestError> {
match &self.state {
State::Processing(result) => {
self.state = State::Processed(Some(result.peer_id));
State::Processing(_) => {
self.state = State::Processed;
Ok(())
}
other => Err(LookupRequestError::BadState(format!(
Expand All @@ -473,27 +474,11 @@ impl<T: Clone> SingleLookupRequestState<T> {
}
}

pub fn on_post_process_validation_failure(
&mut self,
) -> Result<Option<PeerId>, LookupRequestError> {
match &self.state {
State::Processed(peer_id) => {
let peer_id = *peer_id;
self.failed_processing = self.failed_processing.saturating_add(1);
self.state = State::AwaitingDownload;
Ok(peer_id)
}
other => Err(LookupRequestError::BadState(format!(
"Bad state on_post_process_validation_failure expected Processed got {other}"
))),
}
}

/// Mark a request as complete without any download or processing
pub fn on_completed_request(&mut self) -> Result<(), LookupRequestError> {
match &self.state {
State::AwaitingDownload => {
self.state = State::Processed(None);
self.state = State::Processed;
Ok(())
}
other => Err(LookupRequestError::BadState(format!(
Expand Down

0 comments on commit 683d9df

Please sign in to comment.