Single lookup improvements (#5488)
* Fix unexpected `UnrequestedBlobId` and `ExtraBlocksReturned` errors due to race conditions. * Continue chain segment processing and skip any blocks that are already known, rather than returning an error. * more de-dup checking * ensure we don't reset `requested_ids` during rpc download * better fix * Merge branch 'unstable' of https://github.com/sigp/lighthouse into more-dup-lookup-fixes * remove chain hash check * Merge branch 'fix-block-lookup-race' of https://github.com/jimmygchen/lighthouse into sean-test-lookups * remove block check * add back tests * Log and CI fixes * undue extra check * Merge branch 'sean-test-lookups' of https://github.com/realbigsean/lighthouse into sean-test-lookups * log improvements * Improve logging
This commit is contained in:
parent
250a5bdc27
commit
334aa2eabd
@ -2796,6 +2796,12 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Err(BlockError::BlockIsAlreadyKnown(block_root)) => {
|
||||||
|
debug!(self.log,
|
||||||
|
"Ignoring already known blocks while processing chain segment";
|
||||||
|
"block_root" => ?block_root);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
return ChainSegmentResult::Failed {
|
return ChainSegmentResult::Failed {
|
||||||
imported_blocks,
|
imported_blocks,
|
||||||
@ -3032,7 +3038,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
|||||||
match import_block.await {
|
match import_block.await {
|
||||||
// The block was successfully verified and imported. Yay.
|
// The block was successfully verified and imported. Yay.
|
||||||
Ok(status @ AvailabilityProcessingStatus::Imported(block_root)) => {
|
Ok(status @ AvailabilityProcessingStatus::Imported(block_root)) => {
|
||||||
trace!(
|
debug!(
|
||||||
self.log,
|
self.log,
|
||||||
"Beacon block imported";
|
"Beacon block imported";
|
||||||
"block_root" => ?block_root,
|
"block_root" => ?block_root,
|
||||||
@ -3045,7 +3051,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
|||||||
Ok(status)
|
Ok(status)
|
||||||
}
|
}
|
||||||
Ok(status @ AvailabilityProcessingStatus::MissingComponents(slot, block_root)) => {
|
Ok(status @ AvailabilityProcessingStatus::MissingComponents(slot, block_root)) => {
|
||||||
trace!(
|
debug!(
|
||||||
self.log,
|
self.log,
|
||||||
"Beacon block awaiting blobs";
|
"Beacon block awaiting blobs";
|
||||||
"block_root" => ?block_root,
|
"block_root" => ?block_root,
|
||||||
|
@ -7,6 +7,7 @@ use crate::{get_block_root, GossipVerifiedBlock, PayloadVerificationOutcome};
|
|||||||
use derivative::Derivative;
|
use derivative::Derivative;
|
||||||
use ssz_types::VariableList;
|
use ssz_types::VariableList;
|
||||||
use state_processing::ConsensusContext;
|
use state_processing::ConsensusContext;
|
||||||
|
use std::fmt::{Debug, Formatter};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use types::blob_sidecar::{BlobIdentifier, BlobSidecarError, FixedBlobSidecarList};
|
use types::blob_sidecar::{BlobIdentifier, BlobSidecarError, FixedBlobSidecarList};
|
||||||
use types::{
|
use types::{
|
||||||
@ -27,13 +28,19 @@ use types::{
|
|||||||
/// Note: We make a distinction over blocks received over gossip because
|
/// Note: We make a distinction over blocks received over gossip because
|
||||||
/// in a post-deneb world, the blobs corresponding to a given block that are received
|
/// in a post-deneb world, the blobs corresponding to a given block that are received
|
||||||
/// over rpc do not contain the proposer signature for dos resistance.
|
/// over rpc do not contain the proposer signature for dos resistance.
|
||||||
#[derive(Debug, Clone, Derivative)]
|
#[derive(Clone, Derivative)]
|
||||||
#[derivative(Hash(bound = "E: EthSpec"))]
|
#[derivative(Hash(bound = "E: EthSpec"))]
|
||||||
pub struct RpcBlock<E: EthSpec> {
|
pub struct RpcBlock<E: EthSpec> {
|
||||||
block_root: Hash256,
|
block_root: Hash256,
|
||||||
block: RpcBlockInner<E>,
|
block: RpcBlockInner<E>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<E: EthSpec> Debug for RpcBlock<E> {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "RpcBlock({:?})", self.block_root)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<E: EthSpec> RpcBlock<E> {
|
impl<E: EthSpec> RpcBlock<E> {
|
||||||
pub fn block_root(&self) -> Hash256 {
|
pub fn block_root(&self) -> Hash256 {
|
||||||
self.block_root
|
self.block_root
|
||||||
|
@ -110,8 +110,6 @@ impl<T: BeaconChainTypes> DataAvailabilityChecker<T> {
|
|||||||
self.processing_cache.read().get(&block_root).cloned()
|
self.processing_cache.read().get(&block_root).cloned()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A `None` indicates blobs are not required.
|
|
||||||
///
|
|
||||||
/// If there's no block, all possible ids will be returned that don't exist in the given blobs.
|
/// If there's no block, all possible ids will be returned that don't exist in the given blobs.
|
||||||
/// If there no blobs, all possible ids will be returned.
|
/// If there no blobs, all possible ids will be returned.
|
||||||
pub fn get_missing_blob_ids<V: AvailabilityView<T::EthSpec>>(
|
pub fn get_missing_blob_ids<V: AvailabilityView<T::EthSpec>>(
|
||||||
|
@ -117,6 +117,7 @@ impl<T: BeaconChainTypes> NetworkBeaconProcessor<T> {
|
|||||||
"Gossip block is being processed";
|
"Gossip block is being processed";
|
||||||
"action" => "sending rpc block to reprocessing queue",
|
"action" => "sending rpc block to reprocessing queue",
|
||||||
"block_root" => %block_root,
|
"block_root" => %block_root,
|
||||||
|
"process_type" => ?process_type,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Send message to work reprocess queue to retry the block
|
// Send message to work reprocess queue to retry the block
|
||||||
@ -149,6 +150,7 @@ impl<T: BeaconChainTypes> NetworkBeaconProcessor<T> {
|
|||||||
"proposer" => block.message().proposer_index(),
|
"proposer" => block.message().proposer_index(),
|
||||||
"slot" => block.slot(),
|
"slot" => block.slot(),
|
||||||
"commitments" => commitments_formatted,
|
"commitments" => commitments_formatted,
|
||||||
|
"process_type" => ?process_type,
|
||||||
);
|
);
|
||||||
|
|
||||||
let result = self
|
let result = self
|
||||||
@ -418,7 +420,11 @@ impl<T: BeaconChainTypes> NetworkBeaconProcessor<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
(imported_blocks, Ok(_)) => {
|
(imported_blocks, Ok(_)) => {
|
||||||
debug!(self.log, "Parent lookup processed successfully");
|
debug!(
|
||||||
|
self.log, "Parent lookup processed successfully";
|
||||||
|
"chain_hash" => %chain_head,
|
||||||
|
"imported_blocks" => imported_blocks
|
||||||
|
);
|
||||||
BatchProcessResult::Success {
|
BatchProcessResult::Success {
|
||||||
was_non_empty: imported_blocks > 0,
|
was_non_empty: imported_blocks > 0,
|
||||||
}
|
}
|
||||||
|
@ -380,7 +380,7 @@ impl<L: Lookup, T: BeaconChainTypes> RequestState<L, T> for BlobRequestState<L,
|
|||||||
let received_id = blob.id();
|
let received_id = blob.id();
|
||||||
if !self.requested_ids.contains(&received_id) {
|
if !self.requested_ids.contains(&received_id) {
|
||||||
self.state.register_failure_downloading();
|
self.state.register_failure_downloading();
|
||||||
Err(LookupVerifyError::UnrequestedBlobId)
|
Err(LookupVerifyError::UnrequestedBlobId(received_id))
|
||||||
} else {
|
} else {
|
||||||
// State should remain downloading until we receive the stream terminator.
|
// State should remain downloading until we receive the stream terminator.
|
||||||
self.requested_ids.remove(&received_id);
|
self.requested_ids.remove(&received_id);
|
||||||
|
@ -152,6 +152,7 @@ impl<T: BeaconChainTypes> BlockLookups<T> {
|
|||||||
if let Some(components) = child_components {
|
if let Some(components) = child_components {
|
||||||
lookup.add_child_components(components);
|
lookup.add_child_components(components);
|
||||||
}
|
}
|
||||||
|
debug!(self.log, "Already searching for block"; "block_root" => ?block_root);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -162,6 +163,7 @@ impl<T: BeaconChainTypes> BlockLookups<T> {
|
|||||||
|
|
||||||
// If the block was already downloaded, or is being downloaded in this moment, do not
|
// If the block was already downloaded, or is being downloaded in this moment, do not
|
||||||
// request it.
|
// request it.
|
||||||
|
debug!(self.log, "Already searching for block in a parent lookup request"; "block_root" => ?block_root);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -171,6 +173,7 @@ impl<T: BeaconChainTypes> BlockLookups<T> {
|
|||||||
.any(|(hashes, _last_parent_request)| hashes.contains(&block_root))
|
.any(|(hashes, _last_parent_request)| hashes.contains(&block_root))
|
||||||
{
|
{
|
||||||
// we are already processing this block, ignore it.
|
// we are already processing this block, ignore it.
|
||||||
|
debug!(self.log, "Already processing block in a parent request"; "block_root" => ?block_root);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -221,15 +224,23 @@ impl<T: BeaconChainTypes> BlockLookups<T> {
|
|||||||
}) {
|
}) {
|
||||||
parent_lookup.add_peer(peer_id);
|
parent_lookup.add_peer(peer_id);
|
||||||
// we are already searching for this block, ignore it
|
// we are already searching for this block, ignore it
|
||||||
|
debug!(self.log, "Already searching for parent block";
|
||||||
|
"block_root" => ?block_root, "parent_root" => ?parent_root);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if self
|
if self
|
||||||
.processing_parent_lookups
|
.processing_parent_lookups
|
||||||
.values()
|
.iter()
|
||||||
.any(|(hashes, _peers)| hashes.contains(&block_root) || hashes.contains(&parent_root))
|
.any(|(chain_hash, (hashes, _peers))| {
|
||||||
|
chain_hash == &block_root
|
||||||
|
|| hashes.contains(&block_root)
|
||||||
|
|| hashes.contains(&parent_root)
|
||||||
|
})
|
||||||
{
|
{
|
||||||
// we are already processing this block, ignore it.
|
// we are already processing this block, ignore it.
|
||||||
|
debug!(self.log, "Already processing parent block";
|
||||||
|
"block_root" => ?block_root, "parent_root" => ?parent_root);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let parent_lookup = ParentLookup::new(
|
let parent_lookup = ParentLookup::new(
|
||||||
@ -298,6 +309,12 @@ impl<T: BeaconChainTypes> BlockLookups<T> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let expected_block_root = lookup.block_root();
|
let expected_block_root = lookup.block_root();
|
||||||
|
debug!(self.log,
|
||||||
|
"Peer returned block for single lookup";
|
||||||
|
"peer_id" => %peer_id ,
|
||||||
|
"id" => ?id,
|
||||||
|
"block_root" => ?expected_block_root,
|
||||||
|
);
|
||||||
|
|
||||||
match self.single_lookup_response_inner::<R>(peer_id, response, seen_timestamp, cx, lookup)
|
match self.single_lookup_response_inner::<R>(peer_id, response, seen_timestamp, cx, lookup)
|
||||||
{
|
{
|
||||||
@ -478,6 +495,13 @@ impl<T: BeaconChainTypes> BlockLookups<T> {
|
|||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
debug!(self.log,
|
||||||
|
"Peer returned block for parent lookup";
|
||||||
|
"peer_id" => %peer_id ,
|
||||||
|
"id" => ?id,
|
||||||
|
"block_root" => ?parent_lookup.current_parent_request.block_request_state.requested_block_root,
|
||||||
|
);
|
||||||
|
|
||||||
match self.parent_lookup_response_inner::<R>(
|
match self.parent_lookup_response_inner::<R>(
|
||||||
peer_id,
|
peer_id,
|
||||||
response,
|
response,
|
||||||
@ -540,7 +564,7 @@ impl<T: BeaconChainTypes> BlockLookups<T> {
|
|||||||
| ParentVerifyError::NoBlockReturned
|
| ParentVerifyError::NoBlockReturned
|
||||||
| ParentVerifyError::NotEnoughBlobsReturned
|
| ParentVerifyError::NotEnoughBlobsReturned
|
||||||
| ParentVerifyError::ExtraBlocksReturned
|
| ParentVerifyError::ExtraBlocksReturned
|
||||||
| ParentVerifyError::UnrequestedBlobId
|
| ParentVerifyError::UnrequestedBlobId(_)
|
||||||
| ParentVerifyError::ExtraBlobsReturned
|
| ParentVerifyError::ExtraBlobsReturned
|
||||||
| ParentVerifyError::InvalidIndex(_) => {
|
| ParentVerifyError::InvalidIndex(_) => {
|
||||||
let e = e.into();
|
let e = e.into();
|
||||||
@ -728,6 +752,8 @@ impl<T: BeaconChainTypes> BlockLookups<T> {
|
|||||||
"Block component processed for lookup";
|
"Block component processed for lookup";
|
||||||
"response_type" => ?R::response_type(),
|
"response_type" => ?R::response_type(),
|
||||||
"block_root" => ?root,
|
"block_root" => ?root,
|
||||||
|
"result" => ?result,
|
||||||
|
"id" => target_id,
|
||||||
);
|
);
|
||||||
|
|
||||||
match result {
|
match result {
|
||||||
@ -1223,7 +1249,7 @@ impl<T: BeaconChainTypes> BlockLookups<T> {
|
|||||||
) -> Result<(), LookupRequestError> {
|
) -> Result<(), LookupRequestError> {
|
||||||
match cx.beacon_processor_if_enabled() {
|
match cx.beacon_processor_if_enabled() {
|
||||||
Some(beacon_processor) => {
|
Some(beacon_processor) => {
|
||||||
trace!(self.log, "Sending block for processing"; "block" => ?block_root, "process" => ?process_type);
|
debug!(self.log, "Sending block for processing"; "block" => ?block_root, "process" => ?process_type);
|
||||||
if let Err(e) = beacon_processor.send_rpc_beacon_block(
|
if let Err(e) = beacon_processor.send_rpc_beacon_block(
|
||||||
block_root,
|
block_root,
|
||||||
block,
|
block,
|
||||||
|
@ -12,6 +12,7 @@ use std::collections::VecDeque;
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use store::Hash256;
|
use store::Hash256;
|
||||||
use strum::IntoStaticStr;
|
use strum::IntoStaticStr;
|
||||||
|
use types::blob_sidecar::BlobIdentifier;
|
||||||
|
|
||||||
/// How many attempts we try to find a parent of a block before we give up trying.
|
/// How many attempts we try to find a parent of a block before we give up trying.
|
||||||
pub(crate) const PARENT_FAIL_TOLERANCE: u8 = 5;
|
pub(crate) const PARENT_FAIL_TOLERANCE: u8 = 5;
|
||||||
@ -36,7 +37,7 @@ pub enum ParentVerifyError {
|
|||||||
NoBlockReturned,
|
NoBlockReturned,
|
||||||
NotEnoughBlobsReturned,
|
NotEnoughBlobsReturned,
|
||||||
ExtraBlocksReturned,
|
ExtraBlocksReturned,
|
||||||
UnrequestedBlobId,
|
UnrequestedBlobId(BlobIdentifier),
|
||||||
ExtraBlobsReturned,
|
ExtraBlobsReturned,
|
||||||
InvalidIndex(u64),
|
InvalidIndex(u64),
|
||||||
PreviousFailure { parent_root: Hash256 },
|
PreviousFailure { parent_root: Hash256 },
|
||||||
@ -242,7 +243,7 @@ impl From<LookupVerifyError> for ParentVerifyError {
|
|||||||
E::RootMismatch => ParentVerifyError::RootMismatch,
|
E::RootMismatch => ParentVerifyError::RootMismatch,
|
||||||
E::NoBlockReturned => ParentVerifyError::NoBlockReturned,
|
E::NoBlockReturned => ParentVerifyError::NoBlockReturned,
|
||||||
E::ExtraBlocksReturned => ParentVerifyError::ExtraBlocksReturned,
|
E::ExtraBlocksReturned => ParentVerifyError::ExtraBlocksReturned,
|
||||||
E::UnrequestedBlobId => ParentVerifyError::UnrequestedBlobId,
|
E::UnrequestedBlobId(blob_id) => ParentVerifyError::UnrequestedBlobId(blob_id),
|
||||||
E::ExtraBlobsReturned => ParentVerifyError::ExtraBlobsReturned,
|
E::ExtraBlobsReturned => ParentVerifyError::ExtraBlobsReturned,
|
||||||
E::InvalidIndex(index) => ParentVerifyError::InvalidIndex(index),
|
E::InvalidIndex(index) => ParentVerifyError::InvalidIndex(index),
|
||||||
E::NotEnoughBlobsReturned => ParentVerifyError::NotEnoughBlobsReturned,
|
E::NotEnoughBlobsReturned => ParentVerifyError::NotEnoughBlobsReturned,
|
||||||
|
@ -16,7 +16,7 @@ use std::marker::PhantomData;
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use store::Hash256;
|
use store::Hash256;
|
||||||
use strum::IntoStaticStr;
|
use strum::IntoStaticStr;
|
||||||
use types::blob_sidecar::FixedBlobSidecarList;
|
use types::blob_sidecar::{BlobIdentifier, FixedBlobSidecarList};
|
||||||
use types::EthSpec;
|
use types::EthSpec;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq)]
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
@ -31,7 +31,7 @@ pub enum LookupVerifyError {
|
|||||||
RootMismatch,
|
RootMismatch,
|
||||||
NoBlockReturned,
|
NoBlockReturned,
|
||||||
ExtraBlocksReturned,
|
ExtraBlocksReturned,
|
||||||
UnrequestedBlobId,
|
UnrequestedBlobId(BlobIdentifier),
|
||||||
ExtraBlobsReturned,
|
ExtraBlobsReturned,
|
||||||
NotEnoughBlobsReturned,
|
NotEnoughBlobsReturned,
|
||||||
InvalidIndex(u64),
|
InvalidIndex(u64),
|
||||||
@ -257,7 +257,9 @@ impl<L: Lookup, T: BeaconChainTypes> SingleBlockLookup<L, T> {
|
|||||||
/// of which blobs still need to be requested. Returns `true` if there are no more blobs to
|
/// of which blobs still need to be requested. Returns `true` if there are no more blobs to
|
||||||
/// request.
|
/// request.
|
||||||
pub(crate) fn blobs_already_downloaded(&mut self) -> bool {
|
pub(crate) fn blobs_already_downloaded(&mut self) -> bool {
|
||||||
|
if matches!(self.blob_request_state.state.state, State::AwaitingDownload) {
|
||||||
self.update_blobs_request();
|
self.update_blobs_request();
|
||||||
|
}
|
||||||
self.blob_request_state.requested_ids.is_empty()
|
self.blob_request_state.requested_ids.is_empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1803,6 +1803,7 @@ mod deneb_only {
|
|||||||
.expect_blobs_request()
|
.expect_blobs_request()
|
||||||
.expect_no_block_request();
|
.expect_no_block_request();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn too_few_blobs_response_then_block_response_attestation() {
|
fn too_few_blobs_response_then_block_response_attestation() {
|
||||||
let Some(tester) = DenebTester::new(RequestTrigger::AttestationUnknownBlock) else {
|
let Some(tester) = DenebTester::new(RequestTrigger::AttestationUnknownBlock) else {
|
||||||
|
Loading…
Reference in New Issue
Block a user