mirror of
https://github.com/sigp/lighthouse.git
synced 2026-03-14 10:22:38 +00:00
Implement Subnet Sampling for PeerDAS (#6410)
* Add `SAMPLES_PER_SLOT` config. * Rename `sampling` module to `peer_sampling` * Implement subnet sampling. * Update lookup test. * Merge branch 'unstable' into subnet-sampling * Merge branch 'unstable' into subnet-sampling # Conflicts: # beacon_node/beacon_chain/src/data_availability_checker.rs # beacon_node/http_api/src/publish_blocks.rs # beacon_node/lighthouse_network/src/types/globals.rs # beacon_node/network/src/sync/manager.rs * Merge branch 'unstable' into subnet-sampling
This commit is contained in:
@@ -3851,6 +3851,8 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
}
|
||||
|
||||
if let Some(data_columns) = data_columns {
|
||||
// TODO(das): `available_block includes all sampled columns, but we only need to store
|
||||
// custody columns. To be clarified in spec.
|
||||
if !data_columns.is_empty() {
|
||||
debug!(
|
||||
self.log, "Writing data_columns to store";
|
||||
|
||||
@@ -108,13 +108,15 @@ impl<T: BeaconChainTypes> DataAvailabilityChecker<T> {
|
||||
spec.custody_requirement as usize
|
||||
};
|
||||
|
||||
let custody_column_count =
|
||||
custody_subnet_count.saturating_mul(spec.data_columns_per_subnet());
|
||||
let subnet_sampling_size =
|
||||
std::cmp::max(custody_subnet_count, spec.samples_per_slot as usize);
|
||||
let sampling_column_count =
|
||||
subnet_sampling_size.saturating_mul(spec.data_columns_per_subnet());
|
||||
|
||||
let inner = DataAvailabilityCheckerInner::new(
|
||||
OVERFLOW_LRU_CAPACITY,
|
||||
store,
|
||||
custody_column_count,
|
||||
sampling_column_count,
|
||||
spec.clone(),
|
||||
)?;
|
||||
Ok(Self {
|
||||
@@ -125,10 +127,8 @@ impl<T: BeaconChainTypes> DataAvailabilityChecker<T> {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn get_custody_columns_count(&self) -> usize {
|
||||
self.availability_cache
|
||||
.custody_subnet_count()
|
||||
.saturating_mul(self.spec.data_columns_per_subnet())
|
||||
pub fn get_sampling_column_count(&self) -> usize {
|
||||
self.availability_cache.sampling_column_count()
|
||||
}
|
||||
|
||||
/// Checks if the block root is currenlty in the availability cache awaiting import because
|
||||
@@ -141,9 +141,9 @@ impl<T: BeaconChainTypes> DataAvailabilityChecker<T> {
|
||||
.get_execution_valid_block(block_root)
|
||||
}
|
||||
|
||||
/// Return the set of imported blob indexes for `block_root`. Returns None if there is no block
|
||||
/// Return the set of cached blob indexes for `block_root`. Returns None if there is no block
|
||||
/// component for `block_root`.
|
||||
pub fn imported_blob_indexes(&self, block_root: &Hash256) -> Option<Vec<u64>> {
|
||||
pub fn cached_blob_indexes(&self, block_root: &Hash256) -> Option<Vec<u64>> {
|
||||
self.availability_cache
|
||||
.peek_pending_components(block_root, |components| {
|
||||
components.map(|components| {
|
||||
@@ -156,9 +156,9 @@ impl<T: BeaconChainTypes> DataAvailabilityChecker<T> {
|
||||
})
|
||||
}
|
||||
|
||||
/// Return the set of imported custody column indexes for `block_root`. Returns None if there is
|
||||
/// Return the set of cached custody column indexes for `block_root`. Returns None if there is
|
||||
/// no block component for `block_root`.
|
||||
pub fn imported_custody_column_indexes(&self, block_root: &Hash256) -> Option<Vec<u64>> {
|
||||
pub fn cached_data_column_indexes(&self, block_root: &Hash256) -> Option<Vec<u64>> {
|
||||
self.availability_cache
|
||||
.peek_pending_components(block_root, |components| {
|
||||
components.map(|components| components.get_cached_data_columns_indices())
|
||||
|
||||
@@ -40,7 +40,7 @@ pub struct PendingComponents<E: EthSpec> {
|
||||
|
||||
pub enum BlockImportRequirement {
|
||||
AllBlobs,
|
||||
CustodyColumns(usize),
|
||||
ColumnSampling(usize),
|
||||
}
|
||||
|
||||
impl<E: EthSpec> PendingComponents<E> {
|
||||
@@ -210,7 +210,7 @@ impl<E: EthSpec> PendingComponents<E> {
|
||||
.map_or(false, |num_expected_blobs| {
|
||||
num_expected_blobs == self.num_received_blobs()
|
||||
}),
|
||||
BlockImportRequirement::CustodyColumns(num_expected_columns) => {
|
||||
BlockImportRequirement::ColumnSampling(num_expected_columns) => {
|
||||
let num_received_data_columns = self.num_received_data_columns();
|
||||
// No data columns when there are 0 blobs
|
||||
self.num_expected_blobs()
|
||||
@@ -281,7 +281,7 @@ impl<E: EthSpec> PendingComponents<E> {
|
||||
};
|
||||
(Some(VariableList::new(verified_blobs)?), None)
|
||||
}
|
||||
BlockImportRequirement::CustodyColumns(_) => {
|
||||
BlockImportRequirement::ColumnSampling(_) => {
|
||||
let verified_data_columns = verified_data_columns
|
||||
.into_iter()
|
||||
.map(|d| d.into_inner())
|
||||
@@ -353,8 +353,8 @@ pub struct DataAvailabilityCheckerInner<T: BeaconChainTypes> {
|
||||
/// This cache holds a limited number of states in memory and reconstructs them
|
||||
/// from disk when necessary. This is necessary until we merge tree-states
|
||||
state_cache: StateLRUCache<T>,
|
||||
/// The number of data columns the node is custodying.
|
||||
custody_column_count: usize,
|
||||
/// The number of data columns the node is sampling via subnet sampling.
|
||||
sampling_column_count: usize,
|
||||
spec: Arc<ChainSpec>,
|
||||
}
|
||||
|
||||
@@ -362,19 +362,19 @@ impl<T: BeaconChainTypes> DataAvailabilityCheckerInner<T> {
|
||||
pub fn new(
|
||||
capacity: NonZeroUsize,
|
||||
beacon_store: BeaconStore<T>,
|
||||
custody_column_count: usize,
|
||||
sampling_column_count: usize,
|
||||
spec: Arc<ChainSpec>,
|
||||
) -> Result<Self, AvailabilityCheckError> {
|
||||
Ok(Self {
|
||||
critical: RwLock::new(LruCache::new(capacity)),
|
||||
state_cache: StateLRUCache::new(beacon_store, spec.clone()),
|
||||
custody_column_count,
|
||||
sampling_column_count,
|
||||
spec,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn custody_subnet_count(&self) -> usize {
|
||||
self.custody_column_count
|
||||
pub fn sampling_column_count(&self) -> usize {
|
||||
self.sampling_column_count
|
||||
}
|
||||
|
||||
/// Returns true if the block root is known, without altering the LRU ordering
|
||||
@@ -440,8 +440,8 @@ impl<T: BeaconChainTypes> DataAvailabilityCheckerInner<T> {
|
||||
) -> Result<BlockImportRequirement, AvailabilityCheckError> {
|
||||
let peer_das_enabled = self.spec.is_peer_das_enabled_for_epoch(epoch);
|
||||
if peer_das_enabled {
|
||||
Ok(BlockImportRequirement::CustodyColumns(
|
||||
self.custody_column_count,
|
||||
Ok(BlockImportRequirement::ColumnSampling(
|
||||
self.sampling_column_count,
|
||||
))
|
||||
} else {
|
||||
Ok(BlockImportRequirement::AllBlobs)
|
||||
@@ -456,7 +456,7 @@ impl<T: BeaconChainTypes> DataAvailabilityCheckerInner<T> {
|
||||
block_import_requirement: &BlockImportRequirement,
|
||||
pending_components: &PendingComponents<T::EthSpec>,
|
||||
) -> bool {
|
||||
let BlockImportRequirement::CustodyColumns(num_expected_columns) = block_import_requirement
|
||||
let BlockImportRequirement::ColumnSampling(num_expected_columns) = block_import_requirement
|
||||
else {
|
||||
return false;
|
||||
};
|
||||
|
||||
@@ -94,7 +94,9 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
|
||||
// Blobs are stored per block, and data columns are each stored individually
|
||||
let n_blob_ops_per_block = if self.spec.is_peer_das_scheduled() {
|
||||
self.data_availability_checker.get_custody_columns_count()
|
||||
// TODO(das): `available_block includes all sampled columns, but we only need to store
|
||||
// custody columns. To be clarified in spec PR.
|
||||
self.data_availability_checker.get_sampling_column_count()
|
||||
} else {
|
||||
1
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user