mirror of
https://github.com/sigp/lighthouse.git
synced 2026-04-17 04:48:21 +00:00
smol bugfixes and moar tests
This commit is contained in:
@@ -88,33 +88,33 @@ pub enum ResponseType {
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy, Display)]
|
||||
pub enum PeerSource {
|
||||
Attestation(PeerId),
|
||||
Gossip(PeerId),
|
||||
pub enum PeerShouldHave {
|
||||
BlockAndBlobs(PeerId),
|
||||
Neither(PeerId),
|
||||
}
|
||||
impl PeerSource {
|
||||
impl PeerShouldHave {
|
||||
fn as_peer_id(&self) -> &PeerId {
|
||||
match self {
|
||||
PeerSource::Attestation(id) => id,
|
||||
PeerSource::Gossip(id) => id,
|
||||
PeerShouldHave::BlockAndBlobs(id) => id,
|
||||
PeerShouldHave::Neither(id) => id,
|
||||
}
|
||||
}
|
||||
fn to_peer_id(self) -> PeerId {
|
||||
match self {
|
||||
PeerSource::Attestation(id) => id,
|
||||
PeerSource::Gossip(id) => id,
|
||||
PeerShouldHave::BlockAndBlobs(id) => id,
|
||||
PeerShouldHave::Neither(id) => id,
|
||||
}
|
||||
}
|
||||
fn should_have_block(&self) -> bool {
|
||||
match self {
|
||||
PeerSource::Attestation(_) => true,
|
||||
PeerSource::Gossip(_) => false,
|
||||
PeerShouldHave::BlockAndBlobs(_) => true,
|
||||
PeerShouldHave::Neither(_) => false,
|
||||
}
|
||||
}
|
||||
fn should_have_blobs(&self) -> bool {
|
||||
match self {
|
||||
PeerSource::Attestation(_) => true,
|
||||
PeerSource::Gossip(_) => false,
|
||||
PeerShouldHave::BlockAndBlobs(_) => true,
|
||||
PeerShouldHave::Neither(_) => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -147,7 +147,7 @@ impl<T: BeaconChainTypes> BlockLookups<T> {
|
||||
pub fn search_block(
|
||||
&mut self,
|
||||
hash: Hash256,
|
||||
peer_source: PeerSource,
|
||||
peer_source: PeerShouldHave,
|
||||
cx: &mut SyncNetworkContext<T>,
|
||||
) {
|
||||
self.search_block_with(|_| {}, hash, peer_source, cx)
|
||||
@@ -159,7 +159,7 @@ impl<T: BeaconChainTypes> BlockLookups<T> {
|
||||
&mut self,
|
||||
cache_fn: impl Fn(&mut SingleBlockLookup<SINGLE_BLOCK_LOOKUP_MAX_ATTEMPTS, T>),
|
||||
hash: Hash256,
|
||||
peer_source: PeerSource,
|
||||
peer_source: PeerShouldHave,
|
||||
cx: &mut SyncNetworkContext<T>,
|
||||
) {
|
||||
// Do not re-request a block that is already being requested
|
||||
@@ -236,7 +236,7 @@ impl<T: BeaconChainTypes> BlockLookups<T> {
|
||||
let _ = request.add_block_wrapper(block_root, block.clone());
|
||||
},
|
||||
block_root,
|
||||
PeerSource::Gossip(peer_id),
|
||||
PeerShouldHave::Neither(peer_id),
|
||||
cx,
|
||||
);
|
||||
}
|
||||
@@ -253,7 +253,7 @@ impl<T: BeaconChainTypes> BlockLookups<T> {
|
||||
let _ = request.add_blob(blob.clone());
|
||||
},
|
||||
block_root,
|
||||
PeerSource::Gossip(peer_id),
|
||||
PeerShouldHave::Neither(peer_id),
|
||||
cx,
|
||||
);
|
||||
}
|
||||
@@ -269,7 +269,7 @@ impl<T: BeaconChainTypes> BlockLookups<T> {
|
||||
cx: &mut SyncNetworkContext<T>,
|
||||
) {
|
||||
// Gossip blocks or blobs shouldn't be propogated if parents are unavailable.
|
||||
let peer_source = PeerSource::Attestation(peer_id);
|
||||
let peer_source = PeerShouldHave::BlockAndBlobs(peer_id);
|
||||
|
||||
// If this block or it's parent is part of a known failed chain, ignore it.
|
||||
if self.failed_chains.contains(&parent_root) || self.failed_chains.contains(&block_root) {
|
||||
@@ -867,17 +867,18 @@ impl<T: BeaconChainTypes> BlockLookups<T> {
|
||||
|
||||
pub fn single_block_processed(
|
||||
&mut self,
|
||||
id: Id,
|
||||
target_id: Id,
|
||||
result: BlockProcessingResult<T::EthSpec>,
|
||||
response_type: ResponseType,
|
||||
cx: &mut SyncNetworkContext<T>,
|
||||
) {
|
||||
let lookup_components_opt = self.single_block_lookups.iter_mut().enumerate().find_map(
|
||||
|(index, (block_id_opt, blob_id_opt, req))| {
|
||||
block_id_opt
|
||||
.as_mut()
|
||||
.or(blob_id_opt.as_mut())
|
||||
.and_then(|id_ref| (*id_ref == id).then_some((index, id_ref, req)))
|
||||
let id_filter = |id: &&mut Id| -> bool { target_id == **id };
|
||||
|
||||
let block_id = block_id_opt.as_mut().filter(id_filter);
|
||||
let blob_id = blob_id_opt.as_mut().filter(id_filter);
|
||||
block_id.or(blob_id).map(|id_ref| (index, id_ref, req))
|
||||
},
|
||||
);
|
||||
let (index, request_id_ref, request_ref) = match lookup_components_opt {
|
||||
@@ -1425,14 +1426,17 @@ fn handle_block_lookup_verify_error<T: BeaconChainTypes>(
|
||||
) -> ShouldRemoveLookup {
|
||||
let msg = if matches!(e, LookupVerifyError::BenignFailure) {
|
||||
match response_type {
|
||||
ResponseType::Block => request_ref
|
||||
.block_request_state
|
||||
.potential_peers
|
||||
.remove(&peer_id),
|
||||
ResponseType::Blob => request_ref
|
||||
.blob_request_state
|
||||
.potential_peers
|
||||
.remove(&peer_id),
|
||||
// Only remove a potential peer if there are better options
|
||||
ResponseType::Block => {
|
||||
request_ref
|
||||
.block_request_state
|
||||
.remove_peer_if_useless(&peer_id);
|
||||
}
|
||||
ResponseType::Blob => {
|
||||
request_ref
|
||||
.blob_request_state
|
||||
.remove_peer_if_useless(&peer_id);
|
||||
}
|
||||
};
|
||||
"peer could not response to request"
|
||||
} else {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use super::single_block_lookup::{LookupRequestError, LookupVerifyError, SingleBlockLookup};
|
||||
use super::{DownloadedBlocks, PeerSource, ResponseType};
|
||||
use super::{DownloadedBlocks, PeerShouldHave, ResponseType};
|
||||
use crate::sync::block_lookups::{single_block_lookup, RootBlobsTuple, RootBlockTuple};
|
||||
use crate::sync::{
|
||||
manager::{Id, SLOT_IMPORT_TOLERANCE},
|
||||
@@ -90,7 +90,7 @@ impl<T: BeaconChainTypes> ParentLookup<T> {
|
||||
pub fn new(
|
||||
block_root: Hash256,
|
||||
parent_root: Hash256,
|
||||
peer_id: PeerSource,
|
||||
peer_id: PeerShouldHave,
|
||||
da_checker: Arc<DataAvailabilityChecker<T::EthSpec, T::SlotClock>>,
|
||||
) -> Self {
|
||||
let current_parent_request = SingleBlockLookup::new(parent_root, peer_id, da_checker);
|
||||
@@ -328,7 +328,11 @@ impl<T: BeaconChainTypes> ParentLookup<T> {
|
||||
.failed_attempts()
|
||||
}
|
||||
|
||||
pub fn add_peer_if_useful(&mut self, block_root: &Hash256, peer_source: PeerSource) -> bool {
|
||||
pub fn add_peer_if_useful(
|
||||
&mut self,
|
||||
block_root: &Hash256,
|
||||
peer_source: PeerShouldHave,
|
||||
) -> bool {
|
||||
self.current_parent_request
|
||||
.add_peer_if_useful(block_root, peer_source)
|
||||
}
|
||||
@@ -352,7 +356,7 @@ impl<T: BeaconChainTypes> ParentLookup<T> {
|
||||
&self,
|
||||
response_type: ResponseType,
|
||||
peer_id: PeerId,
|
||||
) -> Option<PeerSource> {
|
||||
) -> Option<PeerShouldHave> {
|
||||
self.current_parent_request
|
||||
.peer_source(response_type, peer_id)
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ use strum::IntoStaticStr;
|
||||
use types::blob_sidecar::{BlobIdentifier, FixedBlobSidecarList};
|
||||
use types::{BlobSidecar, SignedBeaconBlock};
|
||||
|
||||
use super::{PeerSource, ResponseType};
|
||||
use super::{PeerShouldHave, ResponseType};
|
||||
|
||||
pub struct SingleBlockLookup<const MAX_ATTEMPTS: u8, T: BeaconChainTypes> {
|
||||
pub requested_block_root: Hash256,
|
||||
@@ -49,8 +49,8 @@ pub struct SingleLookupRequestState<const MAX_ATTEMPTS: u8> {
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
pub enum State {
|
||||
AwaitingDownload,
|
||||
Downloading { peer_id: PeerSource },
|
||||
Processing { peer_id: PeerSource },
|
||||
Downloading { peer_id: PeerShouldHave },
|
||||
Processing { peer_id: PeerShouldHave },
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, IntoStaticStr)]
|
||||
@@ -81,7 +81,7 @@ pub enum LookupRequestError {
|
||||
impl<const MAX_ATTEMPTS: u8, T: BeaconChainTypes> SingleBlockLookup<MAX_ATTEMPTS, T> {
|
||||
pub fn new(
|
||||
requested_block_root: Hash256,
|
||||
peer_source: PeerSource,
|
||||
peer_source: PeerShouldHave,
|
||||
da_checker: Arc<DataAvailabilityChecker<T::EthSpec, T::SlotClock>>,
|
||||
) -> Self {
|
||||
Self {
|
||||
@@ -337,7 +337,7 @@ impl<const MAX_ATTEMPTS: u8, T: BeaconChainTypes> SingleBlockLookup<MAX_ATTEMPTS
|
||||
block_roots: VariableList::from(vec![self.requested_block_root]),
|
||||
};
|
||||
self.block_request_state.used_peers.insert(peer_id);
|
||||
let peer_source = PeerSource::Attestation(peer_id);
|
||||
let peer_source = PeerShouldHave::BlockAndBlobs(peer_id);
|
||||
self.block_request_state.state = State::Downloading {
|
||||
peer_id: peer_source,
|
||||
};
|
||||
@@ -352,7 +352,7 @@ impl<const MAX_ATTEMPTS: u8, T: BeaconChainTypes> SingleBlockLookup<MAX_ATTEMPTS
|
||||
block_roots: VariableList::from(vec![self.requested_block_root]),
|
||||
};
|
||||
self.block_request_state.used_peers.insert(peer_id);
|
||||
let peer_source = PeerSource::Gossip(peer_id);
|
||||
let peer_source = PeerShouldHave::Neither(peer_id);
|
||||
self.block_request_state.state = State::Downloading {
|
||||
peer_id: peer_source,
|
||||
};
|
||||
@@ -391,7 +391,7 @@ impl<const MAX_ATTEMPTS: u8, T: BeaconChainTypes> SingleBlockLookup<MAX_ATTEMPTS
|
||||
blob_ids: VariableList::from(missing_ids.clone()),
|
||||
};
|
||||
self.blob_request_state.used_peers.insert(peer_id);
|
||||
let peer_source = PeerSource::Attestation(peer_id);
|
||||
let peer_source = PeerShouldHave::BlockAndBlobs(peer_id);
|
||||
self.requested_ids = missing_ids;
|
||||
self.blob_request_state.state = State::Downloading {
|
||||
peer_id: peer_source,
|
||||
@@ -407,7 +407,7 @@ impl<const MAX_ATTEMPTS: u8, T: BeaconChainTypes> SingleBlockLookup<MAX_ATTEMPTS
|
||||
blob_ids: VariableList::from(missing_ids.clone()),
|
||||
};
|
||||
self.blob_request_state.used_peers.insert(peer_id);
|
||||
let peer_source = PeerSource::Gossip(peer_id);
|
||||
let peer_source = PeerShouldHave::Neither(peer_id);
|
||||
self.requested_ids = missing_ids;
|
||||
self.blob_request_state.state = State::Downloading {
|
||||
peer_id: peer_source,
|
||||
@@ -418,16 +418,20 @@ impl<const MAX_ATTEMPTS: u8, T: BeaconChainTypes> SingleBlockLookup<MAX_ATTEMPTS
|
||||
}
|
||||
}
|
||||
|
||||
pub fn add_peer_if_useful(&mut self, block_root: &Hash256, peer_source: PeerSource) -> bool {
|
||||
pub fn add_peer_if_useful(
|
||||
&mut self,
|
||||
block_root: &Hash256,
|
||||
peer_source: PeerShouldHave,
|
||||
) -> bool {
|
||||
if *block_root != self.requested_block_root {
|
||||
return false;
|
||||
}
|
||||
match peer_source {
|
||||
PeerSource::Attestation(peer_id) => {
|
||||
PeerShouldHave::BlockAndBlobs(peer_id) => {
|
||||
self.block_request_state.add_peer(&peer_id);
|
||||
self.blob_request_state.add_peer(&peer_id);
|
||||
}
|
||||
PeerSource::Gossip(peer_id) => {
|
||||
PeerShouldHave::Neither(peer_id) => {
|
||||
self.block_request_state.add_potential_peer(&peer_id);
|
||||
self.blob_request_state.add_potential_peer(&peer_id);
|
||||
}
|
||||
@@ -435,7 +439,7 @@ impl<const MAX_ATTEMPTS: u8, T: BeaconChainTypes> SingleBlockLookup<MAX_ATTEMPTS
|
||||
true
|
||||
}
|
||||
|
||||
pub fn processing_peer(&self, response_type: ResponseType) -> Result<PeerSource, ()> {
|
||||
pub fn processing_peer(&self, response_type: ResponseType) -> Result<PeerShouldHave, ()> {
|
||||
match response_type {
|
||||
ResponseType::Block => self.block_request_state.processing_peer(),
|
||||
ResponseType::Blob => self.blob_request_state.processing_peer(),
|
||||
@@ -446,22 +450,22 @@ impl<const MAX_ATTEMPTS: u8, T: BeaconChainTypes> SingleBlockLookup<MAX_ATTEMPTS
|
||||
&self,
|
||||
response_type: ResponseType,
|
||||
peer_id: PeerId,
|
||||
) -> Option<PeerSource> {
|
||||
) -> Option<PeerShouldHave> {
|
||||
match response_type {
|
||||
ResponseType::Block => {
|
||||
if self.block_request_state.available_peers.contains(&peer_id) {
|
||||
Some(PeerSource::Attestation(peer_id))
|
||||
Some(PeerShouldHave::BlockAndBlobs(peer_id))
|
||||
} else if self.block_request_state.potential_peers.contains(&peer_id) {
|
||||
Some(PeerSource::Gossip(peer_id))
|
||||
Some(PeerShouldHave::Neither(peer_id))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
ResponseType::Blob => {
|
||||
if self.blob_request_state.available_peers.contains(&peer_id) {
|
||||
Some(PeerSource::Attestation(peer_id))
|
||||
Some(PeerShouldHave::BlockAndBlobs(peer_id))
|
||||
} else if self.blob_request_state.potential_peers.contains(&peer_id) {
|
||||
Some(PeerSource::Gossip(peer_id))
|
||||
Some(PeerShouldHave::Neither(peer_id))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@@ -471,10 +475,12 @@ impl<const MAX_ATTEMPTS: u8, T: BeaconChainTypes> SingleBlockLookup<MAX_ATTEMPTS
|
||||
}
|
||||
|
||||
impl<const MAX_ATTEMPTS: u8> SingleLookupRequestState<MAX_ATTEMPTS> {
|
||||
pub fn new(peer_source: PeerSource) -> Self {
|
||||
pub fn new(peer_source: PeerShouldHave) -> Self {
|
||||
let (available_peers, potential_peers) = match peer_source {
|
||||
PeerSource::Attestation(peer_id) => (HashSet::from([peer_id]), HashSet::default()),
|
||||
PeerSource::Gossip(peer_id) => (HashSet::default(), HashSet::from([peer_id])),
|
||||
PeerShouldHave::BlockAndBlobs(peer_id) => {
|
||||
(HashSet::from([peer_id]), HashSet::default())
|
||||
}
|
||||
PeerShouldHave::Neither(peer_id) => (HashSet::default(), HashSet::from([peer_id])),
|
||||
};
|
||||
Self {
|
||||
state: State::AwaitingDownload,
|
||||
@@ -529,13 +535,19 @@ impl<const MAX_ATTEMPTS: u8> SingleLookupRequestState<MAX_ATTEMPTS> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn processing_peer(&self) -> Result<PeerSource, ()> {
|
||||
pub fn processing_peer(&self) -> Result<PeerShouldHave, ()> {
|
||||
if let State::Processing { peer_id } = &self.state {
|
||||
Ok(*peer_id)
|
||||
} else {
|
||||
Err(())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn remove_peer_if_useless(&mut self, peer_id: &PeerId) {
|
||||
if !self.available_peers.is_empty() || self.potential_peers.len() > 1 {
|
||||
self.potential_peers.remove(peer_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<const MAX_ATTEMPTS: u8, T: BeaconChainTypes> slog::Value
|
||||
@@ -613,7 +625,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_happy_path() {
|
||||
let peer_id = PeerSource::Attestation(PeerId::random());
|
||||
let peer_id = PeerShouldHave::BlockAndBlobs(PeerId::random());
|
||||
let block = rand_block();
|
||||
let spec = E::default_spec();
|
||||
let slot_clock = TestingSlotClock::new(
|
||||
@@ -630,7 +642,7 @@ mod tests {
|
||||
#[test]
|
||||
fn test_block_lookup_failures() {
|
||||
const FAILURES: u8 = 3;
|
||||
let peer_id = PeerSource::Attestation(PeerId::random());
|
||||
let peer_id = PeerShouldHave::BlockAndBlobs(PeerId::random());
|
||||
let block = rand_block();
|
||||
let spec = E::default_spec();
|
||||
let slot_clock = TestingSlotClock::new(
|
||||
|
||||
@@ -268,7 +268,7 @@ fn test_single_block_lookup_happy_path() {
|
||||
let peer_id = PeerId::random();
|
||||
let block_root = block.canonical_root();
|
||||
// Trigger the request
|
||||
bl.search_block(block_root, PeerSource::Attestation(peer_id), &mut cx);
|
||||
bl.search_block(block_root, PeerShouldHave::BlockAndBlobs(peer_id), &mut cx);
|
||||
let id = rig.expect_block_request(response_type);
|
||||
// If we're in deneb, a blob request should have been triggered as well,
|
||||
// we don't require a response because we're generateing 0-blob blocks in this test.
|
||||
@@ -311,7 +311,7 @@ fn test_single_block_lookup_empty_response() {
|
||||
let peer_id = PeerId::random();
|
||||
|
||||
// Trigger the request
|
||||
bl.search_block(block_hash, PeerSource::Attestation(peer_id), &mut cx);
|
||||
bl.search_block(block_hash, PeerShouldHave::BlockAndBlobs(peer_id), &mut cx);
|
||||
let id = rig.expect_block_request(response_type);
|
||||
// If we're in deneb, a blob request should have been triggered as well,
|
||||
// we don't require a response because we're generateing 0-blob blocks in this test.
|
||||
@@ -339,7 +339,7 @@ fn test_single_block_lookup_wrong_response() {
|
||||
let peer_id = PeerId::random();
|
||||
|
||||
// Trigger the request
|
||||
bl.search_block(block_hash, PeerSource::Attestation(peer_id), &mut cx);
|
||||
bl.search_block(block_hash, PeerShouldHave::BlockAndBlobs(peer_id), &mut cx);
|
||||
let id = rig.expect_block_request(response_type);
|
||||
// If we're in deneb, a blob request should have been triggered as well,
|
||||
// we don't require a response because we're generateing 0-blob blocks in this test.
|
||||
@@ -371,7 +371,7 @@ fn test_single_block_lookup_failure() {
|
||||
let peer_id = PeerId::random();
|
||||
|
||||
// Trigger the request
|
||||
bl.search_block(block_hash, PeerSource::Attestation(peer_id), &mut cx);
|
||||
bl.search_block(block_hash, PeerShouldHave::BlockAndBlobs(peer_id), &mut cx);
|
||||
let id = rig.expect_block_request(response_type);
|
||||
// If we're in deneb, a blob request should have been triggered as well,
|
||||
// we don't require a response because we're generateing 0-blob blocks in this test.
|
||||
@@ -400,7 +400,7 @@ fn test_single_block_lookup_becomes_parent_request() {
|
||||
// Trigger the request
|
||||
bl.search_block(
|
||||
block.canonical_root(),
|
||||
PeerSource::Attestation(peer_id),
|
||||
PeerShouldHave::BlockAndBlobs(peer_id),
|
||||
&mut cx,
|
||||
);
|
||||
let id = rig.expect_block_request(response_type);
|
||||
@@ -916,7 +916,7 @@ fn test_single_block_lookup_ignored_response() {
|
||||
// Trigger the request
|
||||
bl.search_block(
|
||||
block.canonical_root(),
|
||||
PeerSource::Attestation(peer_id),
|
||||
PeerShouldHave::BlockAndBlobs(peer_id),
|
||||
&mut cx,
|
||||
);
|
||||
let id = rig.expect_block_request(response_type);
|
||||
@@ -1100,6 +1100,7 @@ fn test_same_chain_race_condition() {
|
||||
|
||||
mod deneb_only {
|
||||
use super::*;
|
||||
use beacon_chain::blob_verification::BlobError;
|
||||
use std::str::FromStr;
|
||||
|
||||
struct DenebTester {
|
||||
@@ -1109,14 +1110,23 @@ mod deneb_only {
|
||||
block: Option<Arc<SignedBeaconBlock<E>>>,
|
||||
blobs: Vec<Arc<BlobSidecar<E>>>,
|
||||
peer_id: PeerId,
|
||||
block_req_id: u32,
|
||||
block_req_id: Option<u32>,
|
||||
parent_block_req_id: Option<u32>,
|
||||
blob_req_id: u32,
|
||||
parent_blob_req_id: Option<u32>,
|
||||
slot: Slot,
|
||||
block_root: Hash256,
|
||||
}
|
||||
|
||||
enum RequestTrigger {
|
||||
AttestationUnknownBlock,
|
||||
GossipUnknownParentBlock,
|
||||
GossipUnknownParentBlob,
|
||||
GossipUnknownBlockOrBlob,
|
||||
}
|
||||
|
||||
impl DenebTester {
|
||||
fn new() -> Option<Self> {
|
||||
fn new(request_trigger: RequestTrigger) -> Option<Self> {
|
||||
let fork_name = get_fork_name();
|
||||
if !matches!(fork_name, ForkName::Deneb) {
|
||||
return None;
|
||||
@@ -1126,6 +1136,7 @@ mod deneb_only {
|
||||
E::slots_per_epoch() * rig.harness.spec.deneb_fork_epoch.unwrap().as_u64(),
|
||||
);
|
||||
let (block, blobs) = rig.rand_block_and_blobs(fork_name, NumBlobs::Random);
|
||||
let block = Arc::new(block);
|
||||
let blobs = blobs.into_iter().map(Arc::new).collect::<Vec<_>>();
|
||||
|
||||
let peer_id = PeerId::random();
|
||||
@@ -1133,19 +1144,71 @@ mod deneb_only {
|
||||
let block_root = block.canonical_root();
|
||||
|
||||
// Trigger the request
|
||||
bl.search_block(block_root, PeerSource::Attestation(peer_id), &mut cx);
|
||||
let block_req_id = rig.expect_block_request(ResponseType::Block);
|
||||
let blob_req_id = rig.expect_block_request(ResponseType::Blob);
|
||||
let (block_req_id, blob_req_id, parent_block_req_id, parent_blob_req_id) =
|
||||
match request_trigger {
|
||||
RequestTrigger::AttestationUnknownBlock => {
|
||||
bl.search_block(
|
||||
block_root,
|
||||
PeerShouldHave::BlockAndBlobs(peer_id),
|
||||
&mut cx,
|
||||
);
|
||||
let block_req_id = rig.expect_block_request(ResponseType::Block);
|
||||
let blob_req_id = rig.expect_block_request(ResponseType::Blob);
|
||||
(Some(block_req_id), blob_req_id, None, None)
|
||||
}
|
||||
RequestTrigger::GossipUnknownParentBlock => {
|
||||
bl.search_current_unknown_parent(
|
||||
block_root,
|
||||
BlockWrapper::Block(block.clone()),
|
||||
peer_id,
|
||||
&mut cx,
|
||||
);
|
||||
let blob_req_id = rig.expect_block_request(ResponseType::Blob);
|
||||
rig.expect_empty_network(); // expect no block request
|
||||
bl.search_parent(slot, block_root, block.parent_root(), peer_id, &mut cx);
|
||||
let parent_block_req_id = rig.expect_parent_request(ResponseType::Block);
|
||||
let parent_blob_req_id = rig.expect_parent_request(ResponseType::Blob);
|
||||
(
|
||||
None,
|
||||
blob_req_id,
|
||||
Some(parent_block_req_id),
|
||||
Some(parent_blob_req_id),
|
||||
)
|
||||
}
|
||||
RequestTrigger::GossipUnknownParentBlob => {
|
||||
let blob = blobs.first().cloned().unwrap();
|
||||
bl.search_current_unknown_blob_parent(blob, peer_id, &mut cx);
|
||||
let block_req_id = rig.expect_block_request(ResponseType::Block);
|
||||
let blob_req_id = rig.expect_block_request(ResponseType::Blob);
|
||||
bl.search_parent(slot, block_root, block.parent_root(), peer_id, &mut cx);
|
||||
let parent_block_req_id = rig.expect_parent_request(ResponseType::Block);
|
||||
let parent_blob_req_id = rig.expect_parent_request(ResponseType::Blob);
|
||||
(
|
||||
Some(block_req_id),
|
||||
blob_req_id,
|
||||
Some(parent_block_req_id),
|
||||
Some(parent_blob_req_id),
|
||||
)
|
||||
}
|
||||
RequestTrigger::GossipUnknownBlockOrBlob => {
|
||||
bl.search_block(block_root, PeerShouldHave::Neither(peer_id), &mut cx);
|
||||
let block_req_id = rig.expect_block_request(ResponseType::Block);
|
||||
let blob_req_id = rig.expect_block_request(ResponseType::Blob);
|
||||
(Some(block_req_id), blob_req_id, None, None)
|
||||
}
|
||||
};
|
||||
|
||||
Some(Self {
|
||||
bl,
|
||||
cx,
|
||||
rig,
|
||||
block: Some(Arc::new(block)),
|
||||
block: Some(block),
|
||||
blobs,
|
||||
peer_id,
|
||||
block_req_id,
|
||||
parent_block_req_id,
|
||||
blob_req_id,
|
||||
parent_blob_req_id,
|
||||
slot,
|
||||
block_root,
|
||||
})
|
||||
@@ -1155,7 +1218,7 @@ mod deneb_only {
|
||||
// The peer provides the correct block, should not be penalized. Now the block should be sent
|
||||
// for processing.
|
||||
self.bl.single_block_lookup_response(
|
||||
self.block_req_id,
|
||||
self.block_req_id.expect("block request id"),
|
||||
self.peer_id,
|
||||
self.block.clone(),
|
||||
D,
|
||||
@@ -1178,7 +1241,6 @@ mod deneb_only {
|
||||
D,
|
||||
&mut self.cx,
|
||||
);
|
||||
self.rig.expect_empty_network();
|
||||
assert_eq!(self.bl.single_block_lookups.len(), 1);
|
||||
}
|
||||
// Send the blob stream termination. Peer should have not been penalized.
|
||||
@@ -1189,6 +1251,10 @@ mod deneb_only {
|
||||
D,
|
||||
&mut self.cx,
|
||||
);
|
||||
self
|
||||
}
|
||||
|
||||
fn blobs_response_was_valid(mut self) -> Self {
|
||||
self.rig.expect_empty_network();
|
||||
self.rig.expect_block_process(ResponseType::Blob);
|
||||
self
|
||||
@@ -1196,7 +1262,7 @@ mod deneb_only {
|
||||
|
||||
fn empty_block_response(mut self) -> Self {
|
||||
self.bl.single_block_lookup_response(
|
||||
self.block_req_id,
|
||||
self.block_req_id.expect("block request id"),
|
||||
self.peer_id,
|
||||
None,
|
||||
D,
|
||||
@@ -1220,7 +1286,7 @@ mod deneb_only {
|
||||
// Missing blobs should be the request is not removed, the outstanding blobs request should
|
||||
// mean we do not send a new request.
|
||||
self.bl.single_block_processed(
|
||||
self.block_req_id,
|
||||
self.block_req_id.expect("block request id"),
|
||||
BlockProcessingResult::Ok(AvailabilityProcessingStatus::Imported(self.block_root)),
|
||||
ResponseType::Block,
|
||||
&mut self.cx,
|
||||
@@ -1230,9 +1296,33 @@ mod deneb_only {
|
||||
self
|
||||
}
|
||||
|
||||
fn missing_components(mut self) -> Self {
|
||||
fn invalid_block_processed(mut self) -> Self {
|
||||
self.bl.single_block_processed(
|
||||
self.block_req_id,
|
||||
self.block_req_id.expect("block request id"),
|
||||
BlockProcessingResult::Err(BlockError::ProposalSignatureInvalid),
|
||||
ResponseType::Block,
|
||||
&mut self.cx,
|
||||
);
|
||||
assert_eq!(self.bl.single_block_lookups.len(), 1);
|
||||
self
|
||||
}
|
||||
|
||||
fn invalid_blob_processed(mut self) -> Self {
|
||||
self.bl.single_block_processed(
|
||||
self.blob_req_id,
|
||||
BlockProcessingResult::Err(BlockError::BlobValidation(
|
||||
BlobError::ProposerSignatureInvalid,
|
||||
)),
|
||||
ResponseType::Blob,
|
||||
&mut self.cx,
|
||||
);
|
||||
assert_eq!(self.bl.single_block_lookups.len(), 1);
|
||||
self
|
||||
}
|
||||
|
||||
fn missing_components_from_block_request(mut self) -> Self {
|
||||
self.bl.single_block_processed(
|
||||
self.block_req_id.expect("block request id"),
|
||||
BlockProcessingResult::Ok(AvailabilityProcessingStatus::MissingComponents(
|
||||
self.slot,
|
||||
self.block_root,
|
||||
@@ -1244,6 +1334,20 @@ mod deneb_only {
|
||||
self
|
||||
}
|
||||
|
||||
fn missing_components_from_blob_request(mut self) -> Self {
|
||||
self.bl.single_block_processed(
|
||||
self.blob_req_id,
|
||||
BlockProcessingResult::Ok(AvailabilityProcessingStatus::MissingComponents(
|
||||
self.slot,
|
||||
self.block_root,
|
||||
)),
|
||||
ResponseType::Blob,
|
||||
&mut self.cx,
|
||||
);
|
||||
assert_eq!(self.bl.single_block_lookups.len(), 1);
|
||||
self
|
||||
}
|
||||
|
||||
fn expect_penalty(mut self) -> Self {
|
||||
self.rig.expect_penalty();
|
||||
self
|
||||
@@ -1268,6 +1372,15 @@ mod deneb_only {
|
||||
self.rig.expect_empty_network();
|
||||
self
|
||||
}
|
||||
fn invalidate_blobs_too_few(mut self) -> Self {
|
||||
self.blobs.pop().expect("blobs");
|
||||
self
|
||||
}
|
||||
fn invalidate_blobs_too_many(mut self) -> Self {
|
||||
let first_blob = self.blobs.get(0).expect("blob").clone();
|
||||
self.blobs.push(first_blob);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
fn get_fork_name() -> ForkName {
|
||||
@@ -1284,26 +1397,34 @@ mod deneb_only {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn single_block_and_blob_lookup_block_returned_first() {
|
||||
let Some(tester) = DenebTester::new() else {
|
||||
fn single_block_and_blob_lookup_block_returned_first_attestation() {
|
||||
let Some(tester) = DenebTester::new(RequestTrigger::AttestationUnknownBlock) else {
|
||||
return;
|
||||
};
|
||||
|
||||
tester.block_response().blobs_response().block_imported();
|
||||
tester
|
||||
.block_response()
|
||||
.blobs_response()
|
||||
.blobs_response_was_valid()
|
||||
.block_imported();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn single_block_and_blob_lookup_blobs_returned_first() {
|
||||
let Some(tester) = DenebTester::new() else {
|
||||
fn single_block_and_blob_lookup_blobs_returned_first_attestation() {
|
||||
let Some(tester) = DenebTester::new(RequestTrigger::AttestationUnknownBlock) else {
|
||||
return;
|
||||
};
|
||||
|
||||
tester.blobs_response().block_response().block_imported();
|
||||
tester
|
||||
.blobs_response()
|
||||
.blobs_response_was_valid()
|
||||
.block_response()
|
||||
.block_imported();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn single_block_and_blob_lookup_empty_response() {
|
||||
let Some(tester) = DenebTester::new() else {
|
||||
fn single_block_and_blob_lookup_empty_response_attestation() {
|
||||
let Some(tester) = DenebTester::new(RequestTrigger::AttestationUnknownBlock) else {
|
||||
return;
|
||||
};
|
||||
|
||||
@@ -1319,12 +1440,172 @@ mod deneb_only {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn single_blob_lookup_empty_response() {
|
||||
let Some(tester) = DenebTester::new() else {
|
||||
fn single_block_response_then_empty_blob_response_attestation() {
|
||||
let Some(tester) = DenebTester::new(RequestTrigger::AttestationUnknownBlock) else {
|
||||
return;
|
||||
};
|
||||
|
||||
tester
|
||||
.block_response()
|
||||
.missing_components_from_block_request()
|
||||
.empty_blobs_response()
|
||||
.expect_penalty()
|
||||
.expect_blobs_request()
|
||||
.expect_no_block_request();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn single_blob_response_then_empty_block_response_attestation() {
|
||||
let Some(tester) = DenebTester::new(RequestTrigger::AttestationUnknownBlock) else {
|
||||
return;
|
||||
};
|
||||
|
||||
tester
|
||||
.blobs_response()
|
||||
.blobs_response_was_valid()
|
||||
.expect_no_penalty()
|
||||
.expect_no_block_request()
|
||||
.expect_no_blobs_request()
|
||||
.missing_components_from_blob_request()
|
||||
.empty_block_response()
|
||||
.expect_penalty()
|
||||
.expect_block_request()
|
||||
.expect_no_blobs_request();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn single_invalid_block_response_then_blob_response_attestation() {
|
||||
let Some(tester) = DenebTester::new(RequestTrigger::AttestationUnknownBlock) else {
|
||||
return;
|
||||
};
|
||||
|
||||
tester
|
||||
.block_response()
|
||||
.invalid_block_processed()
|
||||
.expect_penalty()
|
||||
.expect_block_request()
|
||||
.expect_no_blobs_request()
|
||||
.blobs_response()
|
||||
.missing_components_from_blob_request()
|
||||
.expect_no_penalty()
|
||||
.expect_no_block_request()
|
||||
.expect_no_block_request();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn single_block_response_then_invalid_blob_response_attestation() {
|
||||
let Some(tester) = DenebTester::new(RequestTrigger::AttestationUnknownBlock) else {
|
||||
return;
|
||||
};
|
||||
|
||||
tester
|
||||
.block_response()
|
||||
.missing_components_from_block_request()
|
||||
.blobs_response()
|
||||
.invalid_blob_processed()
|
||||
.expect_penalty()
|
||||
.expect_blobs_request()
|
||||
.expect_no_block_request();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn single_block_response_then_too_few_blobs_response_attestation() {
|
||||
let Some(tester) = DenebTester::new(RequestTrigger::AttestationUnknownBlock) else {
|
||||
return;
|
||||
};
|
||||
|
||||
tester
|
||||
.block_response()
|
||||
.invalidate_blobs_too_few()
|
||||
.blobs_response()
|
||||
.expect_penalty()
|
||||
.expect_blobs_request()
|
||||
.expect_no_block_request();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn single_block_response_then_too_many_blobs_response_attestation() {
|
||||
let Some(tester) = DenebTester::new(RequestTrigger::AttestationUnknownBlock) else {
|
||||
return;
|
||||
};
|
||||
|
||||
tester
|
||||
.block_response()
|
||||
.invalidate_blobs_too_many()
|
||||
.blobs_response()
|
||||
.expect_penalty()
|
||||
.expect_blobs_request()
|
||||
.expect_no_block_request();
|
||||
}
|
||||
#[test]
|
||||
fn too_few_blobs_response_then_block_response_attestation() {
|
||||
let Some(tester) = DenebTester::new(RequestTrigger::AttestationUnknownBlock) else {
|
||||
return;
|
||||
};
|
||||
|
||||
tester
|
||||
.invalidate_blobs_too_few()
|
||||
.blobs_response()
|
||||
// No way to know if the response was valid before we've seen the block.
|
||||
.blobs_response_was_valid()
|
||||
.expect_no_penalty()
|
||||
.expect_no_blobs_request()
|
||||
.expect_no_block_request()
|
||||
.block_response();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn too_many_blobs_response_then_block_response_attestation() {
|
||||
let Some(tester) = DenebTester::new(RequestTrigger::AttestationUnknownBlock) else {
|
||||
return;
|
||||
};
|
||||
|
||||
tester
|
||||
.invalidate_blobs_too_many()
|
||||
.blobs_response()
|
||||
.expect_penalty()
|
||||
.expect_blobs_request()
|
||||
.expect_no_block_request()
|
||||
.block_response();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn single_block_and_blob_lookup_block_returned_first_gossip() {
|
||||
let Some(tester) = DenebTester::new(RequestTrigger::GossipUnknownBlockOrBlob) else {
|
||||
return;
|
||||
};
|
||||
|
||||
tester
|
||||
.block_response()
|
||||
.blobs_response()
|
||||
.blobs_response_was_valid()
|
||||
.block_imported();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn single_block_and_blob_lookup_blobs_returned_first_gossip() {
|
||||
let Some(tester) = DenebTester::new(RequestTrigger::GossipUnknownBlockOrBlob) else {
|
||||
return;
|
||||
};
|
||||
|
||||
tester
|
||||
.blobs_response()
|
||||
.blobs_response_was_valid()
|
||||
.block_response()
|
||||
.block_imported();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn single_block_and_blob_lookup_empty_response_gossip() {
|
||||
let Some(tester) = DenebTester::new(RequestTrigger::GossipUnknownBlockOrBlob) else {
|
||||
return;
|
||||
};
|
||||
|
||||
tester
|
||||
.empty_block_response()
|
||||
.expect_block_request()
|
||||
.expect_no_penalty()
|
||||
.expect_no_blobs_request()
|
||||
.empty_blobs_response()
|
||||
.expect_no_penalty()
|
||||
.expect_no_block_request()
|
||||
@@ -1332,17 +1613,133 @@ mod deneb_only {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn single_block_response_then_empty_blob_response() {
|
||||
let Some(tester) = DenebTester::new() else {
|
||||
fn single_block_response_then_empty_blob_response_gossip() {
|
||||
let Some(tester) = DenebTester::new(RequestTrigger::GossipUnknownBlockOrBlob) else {
|
||||
return;
|
||||
};
|
||||
|
||||
tester
|
||||
.block_response()
|
||||
.missing_components()
|
||||
.missing_components_from_block_request()
|
||||
.empty_blobs_response()
|
||||
.expect_blobs_request()
|
||||
.expect_no_penalty()
|
||||
.expect_no_block_request();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn single_blob_response_then_empty_block_response_gossip() {
|
||||
let Some(tester) = DenebTester::new(RequestTrigger::GossipUnknownBlockOrBlob) else {
|
||||
return;
|
||||
};
|
||||
|
||||
tester
|
||||
.blobs_response()
|
||||
.blobs_response_was_valid()
|
||||
.expect_no_penalty()
|
||||
.expect_no_block_request()
|
||||
.expect_no_blobs_request()
|
||||
.missing_components_from_blob_request()
|
||||
.empty_block_response()
|
||||
.expect_block_request()
|
||||
// No penalty because the blob was seen over gossip
|
||||
.expect_no_penalty()
|
||||
.expect_no_blobs_request();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn single_invalid_block_response_then_blob_response_gossip() {
|
||||
let Some(tester) = DenebTester::new(RequestTrigger::GossipUnknownBlockOrBlob) else {
|
||||
return;
|
||||
};
|
||||
|
||||
tester
|
||||
.block_response()
|
||||
.invalid_block_processed()
|
||||
.expect_penalty()
|
||||
.expect_block_request()
|
||||
.expect_no_blobs_request()
|
||||
.blobs_response()
|
||||
.missing_components_from_blob_request()
|
||||
.expect_no_penalty()
|
||||
.expect_no_block_request()
|
||||
.expect_no_block_request();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn single_block_response_then_invalid_blob_response_gossip() {
|
||||
let Some(tester) = DenebTester::new(RequestTrigger::GossipUnknownBlockOrBlob) else {
|
||||
return;
|
||||
};
|
||||
|
||||
tester
|
||||
.block_response()
|
||||
.missing_components_from_block_request()
|
||||
.blobs_response()
|
||||
.invalid_blob_processed()
|
||||
.expect_penalty()
|
||||
.expect_blobs_request()
|
||||
.expect_no_block_request();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn single_block_response_then_too_few_blobs_response_gossip() {
|
||||
let Some(tester) = DenebTester::new(RequestTrigger::GossipUnknownBlockOrBlob) else {
|
||||
return;
|
||||
};
|
||||
|
||||
tester
|
||||
.block_response()
|
||||
.invalidate_blobs_too_few()
|
||||
.blobs_response()
|
||||
.expect_blobs_request()
|
||||
.expect_no_penalty()
|
||||
.expect_no_block_request();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn single_block_response_then_too_many_blobs_response_gossip() {
|
||||
let Some(tester) = DenebTester::new(RequestTrigger::GossipUnknownBlockOrBlob) else {
|
||||
return;
|
||||
};
|
||||
|
||||
tester
|
||||
.block_response()
|
||||
.invalidate_blobs_too_many()
|
||||
.blobs_response()
|
||||
.expect_penalty()
|
||||
.expect_blobs_request()
|
||||
.expect_no_block_request();
|
||||
}
|
||||
#[test]
|
||||
fn too_few_blobs_response_then_block_response_gossip() {
|
||||
let Some(tester) = DenebTester::new(RequestTrigger::GossipUnknownBlockOrBlob) else {
|
||||
return;
|
||||
};
|
||||
|
||||
tester
|
||||
.invalidate_blobs_too_few()
|
||||
.blobs_response()
|
||||
// No way to know if the response was valid before we've seen the block.
|
||||
.blobs_response_was_valid()
|
||||
.expect_no_penalty()
|
||||
.expect_no_blobs_request()
|
||||
.expect_no_block_request()
|
||||
.block_response();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn too_many_blobs_response_then_block_response_gossip() {
|
||||
let Some(tester) = DenebTester::new(RequestTrigger::GossipUnknownBlockOrBlob) else {
|
||||
return;
|
||||
};
|
||||
|
||||
tester
|
||||
.invalidate_blobs_too_many()
|
||||
.blobs_response()
|
||||
.expect_penalty()
|
||||
.expect_blobs_request()
|
||||
.expect_no_block_request()
|
||||
.block_response();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
//! search for the block and subsequently search for parents if needed.
|
||||
|
||||
use super::backfill_sync::{BackFillSync, ProcessResult, SyncStart};
|
||||
use super::block_lookups::{BlockLookups, PeerSource};
|
||||
use super::block_lookups::{BlockLookups, PeerShouldHave};
|
||||
use super::network_context::{BlockOrBlob, SyncNetworkContext};
|
||||
use super::peer_sync_info::{remote_sync_type, PeerSyncType};
|
||||
use super::range_sync::{RangeSync, RangeSyncType, EPOCHS_PER_BATCH};
|
||||
@@ -700,7 +700,7 @@ impl<T: BeaconChainTypes> SyncManager<T> {
|
||||
if self.synced_and_connected(&peer_id) {
|
||||
self.block_lookups.search_block(
|
||||
block_hash,
|
||||
PeerSource::Attestation(peer_id),
|
||||
PeerShouldHave::BlockAndBlobs(peer_id),
|
||||
&mut self.network,
|
||||
);
|
||||
}
|
||||
@@ -718,7 +718,7 @@ impl<T: BeaconChainTypes> SyncManager<T> {
|
||||
} else {
|
||||
self.block_lookups.search_block(
|
||||
block_hash,
|
||||
PeerSource::Gossip(peer_id),
|
||||
PeerShouldHave::Neither(peer_id),
|
||||
&mut self.network,
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user