mirror of
https://github.com/sigp/lighthouse.git
synced 2026-03-15 10:52:43 +00:00
Remove peer sampling code (#7768)
Peer sampling has been completely removed from the spec. This PR removes our partial implementation from the codebase. https://github.com/ethereum/consensus-specs/pull/4393
This commit is contained in:
@@ -4,8 +4,7 @@ use crate::sync::block_lookups::{
|
||||
};
|
||||
use crate::sync::{
|
||||
manager::{BlockProcessType, BlockProcessingResult, SyncManager},
|
||||
peer_sampling::SamplingConfig,
|
||||
SamplingId, SyncMessage,
|
||||
SyncMessage,
|
||||
};
|
||||
use crate::NetworkMessage;
|
||||
use std::sync::Arc;
|
||||
@@ -33,7 +32,7 @@ use lighthouse_network::{
|
||||
rpc::{RPCError, RequestType, RpcErrorResponse},
|
||||
service::api_types::{
|
||||
AppRequestId, DataColumnsByRootRequestId, DataColumnsByRootRequester, Id,
|
||||
SamplingRequester, SingleLookupReqId, SyncRequestId,
|
||||
SingleLookupReqId, SyncRequestId,
|
||||
},
|
||||
types::SyncState,
|
||||
NetworkConfig, NetworkGlobals, PeerId,
|
||||
@@ -50,7 +49,6 @@ use types::{
|
||||
|
||||
const D: Duration = Duration::new(0, 0);
|
||||
const PARENT_FAIL_TOLERANCE: u8 = SINGLE_BLOCK_LOOKUP_MAX_ATTEMPTS;
|
||||
const SAMPLING_REQUIRED_SUCCESSES: usize = 2;
|
||||
type DCByRootIds = Vec<DCByRootId>;
|
||||
type DCByRootId = (SyncRequestId, Vec<ColumnIndex>);
|
||||
|
||||
@@ -124,9 +122,6 @@ impl TestRig {
|
||||
beacon_processor.into(),
|
||||
// Pass empty recv not tied to any tx
|
||||
mpsc::unbounded_channel().1,
|
||||
SamplingConfig::Custom {
|
||||
required_successes: vec![SAMPLING_REQUIRED_SUCCESSES],
|
||||
},
|
||||
fork_context,
|
||||
),
|
||||
harness,
|
||||
@@ -180,10 +175,6 @@ impl TestRig {
|
||||
));
|
||||
}
|
||||
|
||||
fn trigger_sample_block(&mut self, block_root: Hash256, block_slot: Slot) {
|
||||
self.send_sync_message(SyncMessage::SampleBlock(block_root, block_slot))
|
||||
}
|
||||
|
||||
/// Drain all sync messages in the sync_rx attached to the beacon processor
|
||||
fn drain_sync_rx(&mut self) {
|
||||
while let Ok(sync_message) = self.sync_rx.try_recv() {
|
||||
@@ -260,27 +251,6 @@ impl TestRig {
|
||||
);
|
||||
}
|
||||
|
||||
fn expect_no_active_sampling(&mut self) {
|
||||
assert_eq!(
|
||||
self.sync_manager.active_sampling_requests(),
|
||||
Vec::<Hash256>::new(),
|
||||
"expected no active sampling"
|
||||
);
|
||||
}
|
||||
|
||||
fn expect_active_sampling(&mut self, block_root: &Hash256) {
|
||||
assert!(self
|
||||
.sync_manager
|
||||
.active_sampling_requests()
|
||||
.contains(block_root));
|
||||
}
|
||||
|
||||
fn expect_clean_finished_sampling(&mut self) {
|
||||
self.expect_empty_network();
|
||||
self.expect_sampling_result_work();
|
||||
self.expect_no_active_sampling();
|
||||
}
|
||||
|
||||
fn assert_parent_lookups_count(&self, count: usize) {
|
||||
assert_eq!(
|
||||
self.active_parent_lookups_count(),
|
||||
@@ -613,39 +583,6 @@ impl TestRig {
|
||||
})
|
||||
}
|
||||
|
||||
fn return_empty_sampling_requests(&mut self, ids: DCByRootIds) {
|
||||
for id in ids {
|
||||
self.log(&format!("return empty data column for {id:?}"));
|
||||
self.return_empty_sampling_request(id)
|
||||
}
|
||||
}
|
||||
|
||||
fn return_empty_sampling_request(&mut self, (sync_request_id, _): DCByRootId) {
|
||||
let peer_id = PeerId::random();
|
||||
// Send stream termination
|
||||
self.send_sync_message(SyncMessage::RpcDataColumn {
|
||||
sync_request_id,
|
||||
peer_id,
|
||||
data_column: None,
|
||||
seen_timestamp: timestamp_now(),
|
||||
});
|
||||
}
|
||||
|
||||
fn sampling_requests_failed(
|
||||
&mut self,
|
||||
sampling_ids: DCByRootIds,
|
||||
peer_id: PeerId,
|
||||
error: RPCError,
|
||||
) {
|
||||
for (sync_request_id, _) in sampling_ids {
|
||||
self.send_sync_message(SyncMessage::RpcError {
|
||||
peer_id,
|
||||
sync_request_id,
|
||||
error: error.clone(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn complete_valid_block_request(
|
||||
&mut self,
|
||||
id: SingleLookupReqId,
|
||||
@@ -672,51 +609,6 @@ impl TestRig {
|
||||
)
|
||||
}
|
||||
|
||||
fn complete_valid_sampling_column_requests(
|
||||
&mut self,
|
||||
ids: DCByRootIds,
|
||||
data_columns: Vec<Arc<DataColumnSidecar<E>>>,
|
||||
) {
|
||||
for id in ids {
|
||||
self.log(&format!("return valid data column for {id:?}"));
|
||||
let indices = &id.1;
|
||||
let columns_to_send = indices
|
||||
.iter()
|
||||
.map(|&i| data_columns[i as usize].clone())
|
||||
.collect::<Vec<_>>();
|
||||
self.complete_valid_sampling_column_request(id, &columns_to_send);
|
||||
}
|
||||
}
|
||||
|
||||
fn complete_valid_sampling_column_request(
|
||||
&mut self,
|
||||
id: DCByRootId,
|
||||
data_columns: &[Arc<DataColumnSidecar<E>>],
|
||||
) {
|
||||
let first_dc = data_columns.first().unwrap();
|
||||
let block_root = first_dc.block_root();
|
||||
let sampling_request_id = match id.0 {
|
||||
SyncRequestId::DataColumnsByRoot(DataColumnsByRootRequestId {
|
||||
requester: DataColumnsByRootRequester::Sampling(sampling_id),
|
||||
..
|
||||
}) => sampling_id.sampling_request_id,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
self.complete_data_columns_by_root_request(id, data_columns);
|
||||
|
||||
// Expect work event
|
||||
self.expect_rpc_sample_verify_work_event();
|
||||
|
||||
// Respond with valid result
|
||||
self.send_sync_message(SyncMessage::SampleVerified {
|
||||
id: SamplingId {
|
||||
id: SamplingRequester::ImportedBlock(block_root),
|
||||
sampling_request_id,
|
||||
},
|
||||
result: Ok(()),
|
||||
})
|
||||
}
|
||||
|
||||
fn complete_valid_custody_request(
|
||||
&mut self,
|
||||
ids: DCByRootIds,
|
||||
@@ -1047,28 +939,7 @@ impl TestRig {
|
||||
.unwrap_or_else(|e| panic!("Expected RPC custody column work: {e}"))
|
||||
}
|
||||
|
||||
fn expect_rpc_sample_verify_work_event(&mut self) {
|
||||
self.pop_received_processor_event(|ev| {
|
||||
if ev.work_type() == beacon_processor::WorkType::RpcVerifyDataColumn {
|
||||
Some(())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.unwrap_or_else(|e| panic!("Expected sample verify work: {e}"))
|
||||
}
|
||||
|
||||
fn expect_sampling_result_work(&mut self) {
|
||||
self.pop_received_processor_event(|ev| {
|
||||
if ev.work_type() == beacon_processor::WorkType::SamplingResult {
|
||||
Some(())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
.unwrap_or_else(|e| panic!("Expected sampling result work: {e}"))
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn expect_no_work_event(&mut self) {
|
||||
self.drain_processor_rx();
|
||||
assert!(self.network_rx_queue.is_empty());
|
||||
@@ -1280,46 +1151,6 @@ impl TestRig {
|
||||
imported: false,
|
||||
});
|
||||
}
|
||||
|
||||
fn assert_sampling_request_ongoing(&self, block_root: Hash256, indices: &[ColumnIndex]) {
|
||||
for index in indices {
|
||||
let status = self
|
||||
.sync_manager
|
||||
.get_sampling_request_status(block_root, index)
|
||||
.unwrap_or_else(|| panic!("No request state for {index}"));
|
||||
if !matches!(status, crate::sync::peer_sampling::Status::Sampling { .. }) {
|
||||
panic!("expected {block_root} {index} request to be on going: {status:?}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn assert_sampling_request_nopeers(&self, block_root: Hash256, indices: &[ColumnIndex]) {
|
||||
for index in indices {
|
||||
let status = self
|
||||
.sync_manager
|
||||
.get_sampling_request_status(block_root, index)
|
||||
.unwrap_or_else(|| panic!("No request state for {index}"));
|
||||
if !matches!(status, crate::sync::peer_sampling::Status::NoPeers) {
|
||||
panic!("expected {block_root} {index} request to be no peers: {status:?}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn log_sampling_requests(&self, block_root: Hash256, indices: &[ColumnIndex]) {
|
||||
let statuses = indices
|
||||
.iter()
|
||||
.map(|index| {
|
||||
let status = self
|
||||
.sync_manager
|
||||
.get_sampling_request_status(block_root, index)
|
||||
.unwrap_or_else(|| panic!("No request state for {index}"));
|
||||
(index, status)
|
||||
})
|
||||
.collect::<Vec<_>>();
|
||||
self.log(&format!(
|
||||
"Sampling request status for {block_root}: {statuses:?}"
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -2074,137 +1905,6 @@ fn blobs_in_da_checker_skip_download() {
|
||||
r.expect_no_active_lookups();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sampling_happy_path() {
|
||||
let Some(mut r) = TestRig::test_setup_after_fulu() else {
|
||||
return;
|
||||
};
|
||||
r.new_connected_peers_for_peerdas();
|
||||
let (block, data_columns) = r.rand_block_and_data_columns();
|
||||
let block_root = block.canonical_root();
|
||||
r.trigger_sample_block(block_root, block.slot());
|
||||
// Retrieve all outgoing sample requests for random column indexes
|
||||
let sampling_ids =
|
||||
r.expect_only_data_columns_by_root_requests(block_root, SAMPLING_REQUIRED_SUCCESSES);
|
||||
// Resolve all of them one by one
|
||||
r.complete_valid_sampling_column_requests(sampling_ids, data_columns);
|
||||
r.expect_clean_finished_sampling();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sampling_with_retries() {
|
||||
let Some(mut r) = TestRig::test_setup_after_fulu() else {
|
||||
return;
|
||||
};
|
||||
r.new_connected_peers_for_peerdas();
|
||||
// Add another supernode to ensure that the node can retry.
|
||||
r.new_connected_supernode_peer();
|
||||
let (block, data_columns) = r.rand_block_and_data_columns();
|
||||
let block_root = block.canonical_root();
|
||||
r.trigger_sample_block(block_root, block.slot());
|
||||
// Retrieve all outgoing sample requests for random column indexes, and return empty responses
|
||||
let sampling_ids =
|
||||
r.expect_only_data_columns_by_root_requests(block_root, SAMPLING_REQUIRED_SUCCESSES);
|
||||
r.return_empty_sampling_requests(sampling_ids);
|
||||
// Expect retries for all of them, and resolve them
|
||||
let sampling_ids =
|
||||
r.expect_only_data_columns_by_root_requests(block_root, SAMPLING_REQUIRED_SUCCESSES);
|
||||
r.complete_valid_sampling_column_requests(sampling_ids, data_columns);
|
||||
r.expect_clean_finished_sampling();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sampling_avoid_retrying_same_peer() {
|
||||
let Some(mut r) = TestRig::test_setup_after_fulu() else {
|
||||
return;
|
||||
};
|
||||
let peer_id_1 = r.new_connected_supernode_peer();
|
||||
let peer_id_2 = r.new_connected_supernode_peer();
|
||||
let block_root = Hash256::random();
|
||||
r.trigger_sample_block(block_root, Slot::new(0));
|
||||
// Retrieve all outgoing sample requests for random column indexes, and return empty responses
|
||||
let sampling_ids =
|
||||
r.expect_only_data_columns_by_root_requests(block_root, SAMPLING_REQUIRED_SUCCESSES);
|
||||
r.sampling_requests_failed(sampling_ids, peer_id_1, RPCError::Disconnected);
|
||||
// Should retry the other peer
|
||||
let sampling_ids =
|
||||
r.expect_only_data_columns_by_root_requests(block_root, SAMPLING_REQUIRED_SUCCESSES);
|
||||
r.sampling_requests_failed(sampling_ids, peer_id_2, RPCError::Disconnected);
|
||||
// Expect no more retries
|
||||
r.expect_empty_network();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sampling_batch_requests() {
|
||||
let Some(mut r) = TestRig::test_setup_after_fulu() else {
|
||||
return;
|
||||
};
|
||||
let _supernode = r.new_connected_supernode_peer();
|
||||
let (block, data_columns) = r.rand_block_and_data_columns();
|
||||
let block_root = block.canonical_root();
|
||||
r.trigger_sample_block(block_root, block.slot());
|
||||
|
||||
// Retrieve the sample request, which should be batched.
|
||||
let (sync_request_id, column_indexes) = r
|
||||
.expect_only_data_columns_by_root_requests(block_root, 1)
|
||||
.pop()
|
||||
.unwrap();
|
||||
assert_eq!(column_indexes.len(), SAMPLING_REQUIRED_SUCCESSES);
|
||||
r.assert_sampling_request_ongoing(block_root, &column_indexes);
|
||||
|
||||
// Resolve the request.
|
||||
r.complete_valid_sampling_column_requests(
|
||||
vec![(sync_request_id, column_indexes.clone())],
|
||||
data_columns,
|
||||
);
|
||||
r.expect_clean_finished_sampling();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sampling_batch_requests_not_enough_responses_returned() {
|
||||
let Some(mut r) = TestRig::test_setup_after_fulu() else {
|
||||
return;
|
||||
};
|
||||
let _supernode = r.new_connected_supernode_peer();
|
||||
let (block, data_columns) = r.rand_block_and_data_columns();
|
||||
let block_root = block.canonical_root();
|
||||
r.trigger_sample_block(block_root, block.slot());
|
||||
|
||||
// Retrieve the sample request, which should be batched.
|
||||
let (sync_request_id, column_indexes) = r
|
||||
.expect_only_data_columns_by_root_requests(block_root, 1)
|
||||
.pop()
|
||||
.unwrap();
|
||||
assert_eq!(column_indexes.len(), SAMPLING_REQUIRED_SUCCESSES);
|
||||
|
||||
// The request status should be set to Sampling.
|
||||
r.assert_sampling_request_ongoing(block_root, &column_indexes);
|
||||
|
||||
// Split the indexes to simulate the case where the supernode doesn't have the requested column.
|
||||
let (column_indexes_supernode_does_not_have, column_indexes_to_complete) =
|
||||
column_indexes.split_at(1);
|
||||
|
||||
// Complete the requests but only partially, so a NotEnoughResponsesReturned error occurs.
|
||||
let data_columns_to_complete = data_columns
|
||||
.iter()
|
||||
.filter(|d| column_indexes_to_complete.contains(&d.index))
|
||||
.cloned()
|
||||
.collect::<Vec<_>>();
|
||||
r.complete_data_columns_by_root_request(
|
||||
(sync_request_id, column_indexes.clone()),
|
||||
&data_columns_to_complete,
|
||||
);
|
||||
|
||||
// The request status should be set to NoPeers since the supernode, the only peer, returned not enough responses.
|
||||
r.log_sampling_requests(block_root, &column_indexes);
|
||||
r.assert_sampling_request_nopeers(block_root, column_indexes_supernode_does_not_have);
|
||||
|
||||
// The sampling request stalls.
|
||||
r.expect_empty_network();
|
||||
r.expect_no_work_event();
|
||||
r.expect_active_sampling(&block_root);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn custody_lookup_happy_path() {
|
||||
let Some(mut r) = TestRig::test_setup_after_fulu() else {
|
||||
@@ -2233,9 +1933,6 @@ fn custody_lookup_happy_path() {
|
||||
// - Respond with stream terminator
|
||||
// ^ The stream terminator should be ignored and not close the next retry
|
||||
|
||||
// TODO(das): Test error early a sampling request and it getting drop + then receiving responses
|
||||
// from pending requests.
|
||||
|
||||
mod deneb_only {
|
||||
use super::*;
|
||||
use beacon_chain::{
|
||||
|
||||
Reference in New Issue
Block a user