mirror of
https://github.com/sigp/lighthouse.git
synced 2026-04-19 05:48:31 +00:00
Merge parent and current sync lookups (#5655)
* Drop lookup type trait for a simple arg * Drop reconstructed for processing * Send parent blocks one by one * Merge current and parent lookups * Merge current and parent lookups clean up todos * Merge current and parent lookups tests * Merge remote-tracking branch 'origin/unstable' into sync-merged-lookup * Merge branch 'unstable' of https://github.com/sigp/lighthouse into sync-merged-lookup * fix compile after merge * #5655 pr review (#26) * fix compile after merge * remove todos, fix typos etc * fix compile * stable rng * delete TODO and unfilled out test * make download result a struct * enums instead of bools as params * fix comment * Various fixes * Track ignored child components * Track dropped lookup reason as metric * fix test * add comment describing behavior of avail check error * update ordering
This commit is contained in:
@@ -1,21 +1,21 @@
|
||||
use crate::sync::block_lookups::parent_lookup::PARENT_FAIL_TOLERANCE;
|
||||
use crate::sync::block_lookups::single_block_lookup::{
|
||||
LookupRequestError, SingleBlockLookup, SingleLookupRequestState,
|
||||
};
|
||||
use crate::sync::block_lookups::{
|
||||
BlobRequestState, BlockLookups, BlockRequestState, PeerId, SINGLE_BLOCK_LOOKUP_MAX_ATTEMPTS,
|
||||
BlobRequestState, BlockRequestState, PeerId, SINGLE_BLOCK_LOOKUP_MAX_ATTEMPTS,
|
||||
};
|
||||
use crate::sync::manager::{BlockProcessType, Id, SingleLookupReqId};
|
||||
use crate::sync::manager::{BlockProcessType, Id, SLOT_IMPORT_TOLERANCE};
|
||||
use crate::sync::network_context::{
|
||||
BlobsByRootSingleBlockRequest, BlocksByRootSingleRequest, SyncNetworkContext,
|
||||
};
|
||||
use beacon_chain::block_verification_types::RpcBlock;
|
||||
use beacon_chain::data_availability_checker::ChildComponents;
|
||||
use beacon_chain::BeaconChainTypes;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use types::blob_sidecar::FixedBlobSidecarList;
|
||||
use types::{Hash256, SignedBeaconBlock};
|
||||
use types::SignedBeaconBlock;
|
||||
|
||||
use super::single_block_lookup::DownloadResult;
|
||||
use super::SingleLookupId;
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum ResponseType {
|
||||
@@ -23,20 +23,15 @@ pub enum ResponseType {
|
||||
Blob,
|
||||
}
|
||||
|
||||
#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
|
||||
pub enum LookupType {
|
||||
Current,
|
||||
Parent,
|
||||
}
|
||||
/// The maximum depth we will search for a parent block. In principle we should have sync'd any
|
||||
/// canonical chain to its head once the peer connects. A chain should not appear where it's depth
|
||||
/// is further back than the most recent head slot.
|
||||
pub(crate) const PARENT_DEPTH_TOLERANCE: usize = SLOT_IMPORT_TOLERANCE * 2;
|
||||
|
||||
impl LookupType {
|
||||
fn max_attempts(&self) -> u8 {
|
||||
match self {
|
||||
LookupType::Current => SINGLE_BLOCK_LOOKUP_MAX_ATTEMPTS,
|
||||
LookupType::Parent => PARENT_FAIL_TOLERANCE,
|
||||
}
|
||||
}
|
||||
}
|
||||
/// Wrapper around bool to prevent mixing this argument with `BlockIsProcessed`
|
||||
pub(crate) struct AwaitingParent(pub bool);
|
||||
/// Wrapper around bool to prevent mixing this argument with `AwaitingParent`
|
||||
pub(crate) struct BlockIsProcessed(pub bool);
|
||||
|
||||
/// This trait unifies common single block lookup functionality across blocks and blobs. This
|
||||
/// includes making requests, verifying responses, and handling processing results. A
|
||||
@@ -53,115 +48,68 @@ pub trait RequestState<T: BeaconChainTypes> {
|
||||
/// The type created after validation.
|
||||
type VerifiedResponseType: Clone;
|
||||
|
||||
/// We convert a `VerifiedResponseType` to this type prior to sending it to the beacon processor.
|
||||
type ReconstructedResponseType;
|
||||
|
||||
/* Request building methods */
|
||||
|
||||
/// Construct a new request.
|
||||
fn build_request(
|
||||
&mut self,
|
||||
lookup_type: LookupType,
|
||||
) -> Result<(PeerId, Self::RequestType), LookupRequestError> {
|
||||
// Verify and construct request.
|
||||
self.too_many_attempts(lookup_type)?;
|
||||
let peer = self.get_peer()?;
|
||||
let request = self.new_request();
|
||||
Ok((peer, request))
|
||||
}
|
||||
|
||||
/// Construct a new request and send it.
|
||||
fn build_request_and_send(
|
||||
/// Potentially makes progress on this request if it's in a progress-able state
|
||||
fn continue_request(
|
||||
&mut self,
|
||||
id: Id,
|
||||
lookup_type: LookupType,
|
||||
awaiting_parent: AwaitingParent,
|
||||
downloaded_block_expected_blobs: Option<usize>,
|
||||
block_is_processed: BlockIsProcessed,
|
||||
cx: &mut SyncNetworkContext<T>,
|
||||
) -> Result<(), LookupRequestError> {
|
||||
// Check if request is necessary.
|
||||
if !self.get_state().is_awaiting_download() {
|
||||
return Ok(());
|
||||
// Attempt to progress awaiting downloads
|
||||
if self.get_state().is_awaiting_download() {
|
||||
// Verify the current request has not exceeded the maximum number of attempts.
|
||||
let request_state = self.get_state();
|
||||
if request_state.failed_attempts() >= SINGLE_BLOCK_LOOKUP_MAX_ATTEMPTS {
|
||||
let cannot_process = request_state.more_failed_processing_attempts();
|
||||
return Err(LookupRequestError::TooManyAttempts { cannot_process });
|
||||
}
|
||||
|
||||
let peer_id = self
|
||||
.get_state_mut()
|
||||
.use_rand_available_peer()
|
||||
.ok_or(LookupRequestError::NoPeers)?;
|
||||
|
||||
// make_request returns true only if a request was made
|
||||
if self.make_request(id, peer_id, downloaded_block_expected_blobs, cx)? {
|
||||
self.get_state_mut().on_download_start()?;
|
||||
}
|
||||
|
||||
// Otherwise, attempt to progress awaiting processing
|
||||
// If this request is awaiting a parent lookup to be processed, do not send for processing.
|
||||
// The request will be rejected with unknown parent error.
|
||||
} else if !awaiting_parent.0
|
||||
&& (block_is_processed.0 || matches!(Self::response_type(), ResponseType::Block))
|
||||
{
|
||||
// maybe_start_processing returns Some if state == AwaitingProcess. This pattern is
|
||||
// useful to conditionally access the result data.
|
||||
if let Some(result) = self.get_state_mut().maybe_start_processing() {
|
||||
return Self::send_for_processing(id, result, cx);
|
||||
}
|
||||
}
|
||||
|
||||
// Construct request.
|
||||
let (peer_id, request) = self.build_request(lookup_type)?;
|
||||
|
||||
// Update request state.
|
||||
let req_counter = self.get_state_mut().on_download_start(peer_id);
|
||||
|
||||
// Make request
|
||||
let id = SingleLookupReqId {
|
||||
id,
|
||||
req_counter,
|
||||
lookup_type,
|
||||
};
|
||||
Self::make_request(id, peer_id, request, cx)
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Verify the current request has not exceeded the maximum number of attempts.
|
||||
fn too_many_attempts(&self, lookup_type: LookupType) -> Result<(), LookupRequestError> {
|
||||
let request_state = self.get_state();
|
||||
|
||||
if request_state.failed_attempts() >= lookup_type.max_attempts() {
|
||||
let cannot_process = request_state.more_failed_processing_attempts();
|
||||
Err(LookupRequestError::TooManyAttempts { cannot_process })
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the next peer to request. Draws from the set of peers we think should have both the
|
||||
/// block and blob first. If that fails, we draw from the set of peers that may have either.
|
||||
fn get_peer(&mut self) -> Result<PeerId, LookupRequestError> {
|
||||
self.get_state_mut()
|
||||
.use_rand_available_peer()
|
||||
.ok_or(LookupRequestError::NoPeers)
|
||||
}
|
||||
|
||||
/// Initialize `Self::RequestType`.
|
||||
fn new_request(&self) -> Self::RequestType;
|
||||
|
||||
/// Send the request to the network service.
|
||||
fn make_request(
|
||||
id: SingleLookupReqId,
|
||||
&self,
|
||||
id: Id,
|
||||
peer_id: PeerId,
|
||||
request: Self::RequestType,
|
||||
downloaded_block_expected_blobs: Option<usize>,
|
||||
cx: &mut SyncNetworkContext<T>,
|
||||
) -> Result<(), LookupRequestError>;
|
||||
) -> Result<bool, LookupRequestError>;
|
||||
|
||||
/* Response handling methods */
|
||||
|
||||
/// A getter for the parent root of the response. Returns an `Option` because we won't know
|
||||
/// the blob parent if we don't end up getting any blobs in the response.
|
||||
fn get_parent_root(verified_response: &Self::VerifiedResponseType) -> Option<Hash256>;
|
||||
|
||||
/// Caches the verified response in the lookup if necessary. This is only necessary for lookups
|
||||
/// triggered by `UnknownParent` errors.
|
||||
fn add_to_child_components(
|
||||
verified_response: Self::VerifiedResponseType,
|
||||
components: &mut ChildComponents<T::EthSpec>,
|
||||
);
|
||||
|
||||
/// Convert a verified response to the type we send to the beacon processor.
|
||||
fn verified_to_reconstructed(
|
||||
block_root: Hash256,
|
||||
verified: Self::VerifiedResponseType,
|
||||
) -> Self::ReconstructedResponseType;
|
||||
|
||||
/// Send the response to the beacon processor.
|
||||
fn send_reconstructed_for_processing(
|
||||
fn send_for_processing(
|
||||
id: Id,
|
||||
bl: &BlockLookups<T>,
|
||||
block_root: Hash256,
|
||||
verified: Self::ReconstructedResponseType,
|
||||
duration: Duration,
|
||||
result: DownloadResult<Self::VerifiedResponseType>,
|
||||
cx: &SyncNetworkContext<T>,
|
||||
) -> Result<(), LookupRequestError>;
|
||||
|
||||
/// Register a failure to process the block or blob.
|
||||
fn register_failure_downloading(&mut self) {
|
||||
self.get_state_mut().on_download_failure()
|
||||
}
|
||||
|
||||
/* Utility methods */
|
||||
|
||||
/// Returns the `ResponseType` associated with this trait implementation. Useful in logging.
|
||||
@@ -171,64 +119,49 @@ pub trait RequestState<T: BeaconChainTypes> {
|
||||
fn request_state_mut(request: &mut SingleBlockLookup<T>) -> &mut Self;
|
||||
|
||||
/// A getter for a reference to the `SingleLookupRequestState` associated with this trait.
|
||||
fn get_state(&self) -> &SingleLookupRequestState;
|
||||
fn get_state(&self) -> &SingleLookupRequestState<Self::VerifiedResponseType>;
|
||||
|
||||
/// A getter for a mutable reference to the SingleLookupRequestState associated with this trait.
|
||||
fn get_state_mut(&mut self) -> &mut SingleLookupRequestState;
|
||||
fn get_state_mut(&mut self) -> &mut SingleLookupRequestState<Self::VerifiedResponseType>;
|
||||
}
|
||||
|
||||
impl<T: BeaconChainTypes> RequestState<T> for BlockRequestState {
|
||||
impl<T: BeaconChainTypes> RequestState<T> for BlockRequestState<T::EthSpec> {
|
||||
type RequestType = BlocksByRootSingleRequest;
|
||||
type VerifiedResponseType = Arc<SignedBeaconBlock<T::EthSpec>>;
|
||||
type ReconstructedResponseType = RpcBlock<T::EthSpec>;
|
||||
|
||||
fn new_request(&self) -> Self::RequestType {
|
||||
BlocksByRootSingleRequest(self.requested_block_root)
|
||||
}
|
||||
|
||||
fn make_request(
|
||||
id: SingleLookupReqId,
|
||||
&self,
|
||||
id: SingleLookupId,
|
||||
peer_id: PeerId,
|
||||
request: Self::RequestType,
|
||||
_: Option<usize>,
|
||||
cx: &mut SyncNetworkContext<T>,
|
||||
) -> Result<(), LookupRequestError> {
|
||||
cx.block_lookup_request(id, peer_id, request)
|
||||
.map_err(LookupRequestError::SendFailed)
|
||||
) -> Result<bool, LookupRequestError> {
|
||||
cx.block_lookup_request(
|
||||
id,
|
||||
peer_id,
|
||||
BlocksByRootSingleRequest(self.requested_block_root),
|
||||
)
|
||||
.map_err(LookupRequestError::SendFailed)
|
||||
}
|
||||
|
||||
fn get_parent_root(verified_response: &Arc<SignedBeaconBlock<T::EthSpec>>) -> Option<Hash256> {
|
||||
Some(verified_response.parent_root())
|
||||
}
|
||||
|
||||
fn add_to_child_components(
|
||||
verified_response: Arc<SignedBeaconBlock<T::EthSpec>>,
|
||||
components: &mut ChildComponents<T::EthSpec>,
|
||||
) {
|
||||
components.merge_block(verified_response);
|
||||
}
|
||||
|
||||
fn verified_to_reconstructed(
|
||||
block_root: Hash256,
|
||||
block: Arc<SignedBeaconBlock<T::EthSpec>>,
|
||||
) -> RpcBlock<T::EthSpec> {
|
||||
RpcBlock::new_without_blobs(Some(block_root), block)
|
||||
}
|
||||
|
||||
fn send_reconstructed_for_processing(
|
||||
id: Id,
|
||||
bl: &BlockLookups<T>,
|
||||
block_root: Hash256,
|
||||
constructed: RpcBlock<T::EthSpec>,
|
||||
duration: Duration,
|
||||
fn send_for_processing(
|
||||
id: SingleLookupId,
|
||||
download_result: DownloadResult<Self::VerifiedResponseType>,
|
||||
cx: &SyncNetworkContext<T>,
|
||||
) -> Result<(), LookupRequestError> {
|
||||
bl.send_block_for_processing(
|
||||
let DownloadResult {
|
||||
value,
|
||||
block_root,
|
||||
constructed,
|
||||
duration,
|
||||
seen_timestamp,
|
||||
peer_id: _,
|
||||
} = download_result;
|
||||
cx.send_block_for_processing(
|
||||
block_root,
|
||||
RpcBlock::new_without_blobs(Some(block_root), value),
|
||||
seen_timestamp,
|
||||
BlockProcessType::SingleBlock { id },
|
||||
cx,
|
||||
)
|
||||
.map_err(LookupRequestError::SendFailed)
|
||||
}
|
||||
|
||||
fn response_type() -> ResponseType {
|
||||
@@ -237,73 +170,52 @@ impl<T: BeaconChainTypes> RequestState<T> for BlockRequestState {
|
||||
fn request_state_mut(request: &mut SingleBlockLookup<T>) -> &mut Self {
|
||||
&mut request.block_request_state
|
||||
}
|
||||
fn get_state(&self) -> &SingleLookupRequestState {
|
||||
fn get_state(&self) -> &SingleLookupRequestState<Self::VerifiedResponseType> {
|
||||
&self.state
|
||||
}
|
||||
fn get_state_mut(&mut self) -> &mut SingleLookupRequestState {
|
||||
fn get_state_mut(&mut self) -> &mut SingleLookupRequestState<Self::VerifiedResponseType> {
|
||||
&mut self.state
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: BeaconChainTypes> RequestState<T> for BlobRequestState {
|
||||
impl<T: BeaconChainTypes> RequestState<T> for BlobRequestState<T::EthSpec> {
|
||||
type RequestType = BlobsByRootSingleBlockRequest;
|
||||
type VerifiedResponseType = FixedBlobSidecarList<T::EthSpec>;
|
||||
type ReconstructedResponseType = FixedBlobSidecarList<T::EthSpec>;
|
||||
|
||||
fn new_request(&self) -> Self::RequestType {
|
||||
BlobsByRootSingleBlockRequest {
|
||||
block_root: self.block_root,
|
||||
indices: self.requested_ids.indices(),
|
||||
}
|
||||
}
|
||||
|
||||
fn make_request(
|
||||
id: SingleLookupReqId,
|
||||
peer_id: PeerId,
|
||||
request: Self::RequestType,
|
||||
cx: &mut SyncNetworkContext<T>,
|
||||
) -> Result<(), LookupRequestError> {
|
||||
cx.blob_lookup_request(id, peer_id, request)
|
||||
.map_err(LookupRequestError::SendFailed)
|
||||
}
|
||||
|
||||
fn get_parent_root(verified_response: &FixedBlobSidecarList<T::EthSpec>) -> Option<Hash256> {
|
||||
verified_response
|
||||
.into_iter()
|
||||
.filter_map(|blob| blob.as_ref())
|
||||
.map(|blob| blob.block_parent_root())
|
||||
.next()
|
||||
}
|
||||
|
||||
fn add_to_child_components(
|
||||
verified_response: FixedBlobSidecarList<T::EthSpec>,
|
||||
components: &mut ChildComponents<T::EthSpec>,
|
||||
) {
|
||||
components.merge_blobs(verified_response);
|
||||
}
|
||||
|
||||
fn verified_to_reconstructed(
|
||||
_block_root: Hash256,
|
||||
blobs: FixedBlobSidecarList<T::EthSpec>,
|
||||
) -> FixedBlobSidecarList<T::EthSpec> {
|
||||
blobs
|
||||
}
|
||||
|
||||
fn send_reconstructed_for_processing(
|
||||
&self,
|
||||
id: Id,
|
||||
bl: &BlockLookups<T>,
|
||||
block_root: Hash256,
|
||||
verified: FixedBlobSidecarList<T::EthSpec>,
|
||||
duration: Duration,
|
||||
peer_id: PeerId,
|
||||
downloaded_block_expected_blobs: Option<usize>,
|
||||
cx: &mut SyncNetworkContext<T>,
|
||||
) -> Result<bool, LookupRequestError> {
|
||||
cx.blob_lookup_request(
|
||||
id,
|
||||
peer_id,
|
||||
self.block_root,
|
||||
downloaded_block_expected_blobs,
|
||||
)
|
||||
.map_err(LookupRequestError::SendFailed)
|
||||
}
|
||||
|
||||
fn send_for_processing(
|
||||
id: Id,
|
||||
download_result: DownloadResult<Self::VerifiedResponseType>,
|
||||
cx: &SyncNetworkContext<T>,
|
||||
) -> Result<(), LookupRequestError> {
|
||||
bl.send_blobs_for_processing(
|
||||
let DownloadResult {
|
||||
value,
|
||||
block_root,
|
||||
verified,
|
||||
duration,
|
||||
seen_timestamp,
|
||||
peer_id: _,
|
||||
} = download_result;
|
||||
cx.send_blobs_for_processing(
|
||||
block_root,
|
||||
value,
|
||||
seen_timestamp,
|
||||
BlockProcessType::SingleBlob { id },
|
||||
cx,
|
||||
)
|
||||
.map_err(LookupRequestError::SendFailed)
|
||||
}
|
||||
|
||||
fn response_type() -> ResponseType {
|
||||
@@ -312,10 +224,10 @@ impl<T: BeaconChainTypes> RequestState<T> for BlobRequestState {
|
||||
fn request_state_mut(request: &mut SingleBlockLookup<T>) -> &mut Self {
|
||||
&mut request.blob_request_state
|
||||
}
|
||||
fn get_state(&self) -> &SingleLookupRequestState {
|
||||
fn get_state(&self) -> &SingleLookupRequestState<Self::VerifiedResponseType> {
|
||||
&self.state
|
||||
}
|
||||
fn get_state_mut(&mut self) -> &mut SingleLookupRequestState {
|
||||
fn get_state_mut(&mut self) -> &mut SingleLookupRequestState<Self::VerifiedResponseType> {
|
||||
&mut self.state
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user