pub(crate) fn with_committee_cache<F, R>(
        &self,
        head_block_root: Hash256,
        shuffling_epoch: Epoch,
        map_fn: F,
    ) -> Result<R, Error>
    where
        F: Fn(&CommitteeCache, Hash256) -> Result<R, Error>,
    {
        let head_block = self
            .fork_choice
            .read()
            .get_block(&head_block_root)
            .ok_or(Error::MissingBeaconBlock(head_block_root))?;

        let shuffling_id = BlockShufflingIds {
            current: head_block.current_epoch_shuffling_id.clone(),
            next: head_block.next_epoch_shuffling_id.clone(),
            block_root: head_block.root,
        }
        .id_for_epoch(shuffling_epoch)
        .ok_or_else(|| Error::InvalidShufflingId {
            shuffling_epoch,
            head_block_epoch: head_block.slot.epoch(T::EthSpec::slots_per_epoch()),
        })?;

        // Obtain the shuffling cache, timing how long we wait.
        let cache_wait_timer =
            metrics::start_timer(&metrics::ATTESTATION_PROCESSING_SHUFFLING_CACHE_WAIT_TIMES);

        let mut shuffling_cache = self
            .shuffling_cache
            .try_write_for(ATTESTATION_CACHE_LOCK_TIMEOUT)
            .ok_or(Error::AttestationCacheLockTimeout)?;

        metrics::stop_timer(cache_wait_timer);

        if let Some(committee_cache) = shuffling_cache.get(&shuffling_id) {
            map_fn(committee_cache, shuffling_id.shuffling_decision_block)
        } else {
            // Drop the shuffling cache to avoid holding the lock for any longer than
            // required.
            drop(shuffling_cache);

            debug!(
                self.log,
                "Committee cache miss";
                "shuffling_id" => ?shuffling_epoch,
                "head_block_root" => head_block_root.to_string(),
            );

            let state_read_timer =
                metrics::start_timer(&metrics::ATTESTATION_PROCESSING_STATE_READ_TIMES);

            // If the head of the chain can serve this request, use it.
            //
            // This code is a little awkward because we need to ensure that the head we read and
            // the head we copy is identical. Taking one lock to read the head values and another
            // to copy the head is liable to race-conditions.
            let head_state_opt = self.with_head(|head| {
                if head.beacon_block_root == head_block_root {
                    Ok(Some((
                        head.beacon_state
                            .clone_with(CloneConfig::committee_caches_only()),
                        head.beacon_state_root(),
                    )))
                } else {
                    Ok::<_, Error>(None)
                }
            })?;

            // If the head state is useful for this request, use it. Otherwise, read a state from
            // disk.
            let (mut state, state_root) = if let Some((state, state_root)) = head_state_opt {
                (state, state_root)
            } else {
                let state_root = head_block.state_root;
                let state = self
                    .store
                    .get_inconsistent_state_for_attestation_verification_only(
                        &state_root,
                        Some(head_block.slot),
                    )?
                    .ok_or(Error::MissingBeaconState(head_block.state_root))?;
                (state, state_root)
            };

            /*
             * IMPORTANT
             *
             * Since it's possible that
             * `Store::get_inconsistent_state_for_attestation_verification_only` was used to obtain
             * the state, we cannot rely upon the following fields:
             *
             * - `state.state_roots`
             * - `state.block_roots`
             *
             * These fields should not be used for the rest of this function.
             */

            metrics::stop_timer(state_read_timer);
            let state_skip_timer =
                metrics::start_timer(&metrics::ATTESTATION_PROCESSING_STATE_SKIP_TIMES);

            // If the state is in an earlier epoch, advance it. If it's from a later epoch, reject
            // it.
            if state.current_epoch() + 1 < shuffling_epoch {
                // Since there's a one-epoch look-ahead on the attester shuffling, it suffices to
                // only advance into the slot prior to the `shuffling_epoch`.
                let target_slot = shuffling_epoch
                    .saturating_sub(1_u64)
                    .start_slot(T::EthSpec::slots_per_epoch());

                // Advance the state into the required slot, using the "partial" method since the state
                // roots are not relevant for the shuffling.
                partial_state_advance(&mut state, Some(state_root), target_slot, &self.spec)?;
            } else if state.current_epoch() > shuffling_epoch {
                return Err(Error::InvalidStateForShuffling {
                    state_epoch: state.current_epoch(),
                    shuffling_epoch,
                });
            }

            metrics::stop_timer(state_skip_timer);
            let committee_building_timer =
                metrics::start_timer(&metrics::ATTESTATION_PROCESSING_COMMITTEE_BUILDING_TIMES);

            let relative_epoch = RelativeEpoch::from_epoch(state.current_epoch(), shuffling_epoch)
                .map_err(Error::IncorrectStateForAttestation)?;

            state.build_committee_cache(relative_epoch, &self.spec)?;

            let committee_cache = state.committee_cache(relative_epoch)?;
            let shuffling_decision_block = shuffling_id.shuffling_decision_block;

            self.shuffling_cache
                .try_write_for(ATTESTATION_CACHE_LOCK_TIMEOUT)
                .ok_or(Error::AttestationCacheLockTimeout)?
                .insert(shuffling_id, committee_cache);

            metrics::stop_timer(committee_building_timer);

            map_fn(&committee_cache, shuffling_decision_block)
        }
    }
/// Runs the `map_fn` with the committee cache for `shuffling_epoch` from the chain with head
/// `head_block_root`. The `map_fn` will be supplied two values:
///
/// - `&CommitteeCache`: the committee cache that serves the given parameters.
/// - `Hash256`: the "shuffling decision root" which uniquely identifies the `CommitteeCache`.
///
/// It's not necessary that `head_block_root` matches our current view of the chain, it can be
/// any block that is:
///
/// - Known to us.
/// - The finalized block or a descendant of the finalized block.
///
/// It would be quite common for attestation verification operations to use a `head_block_root`
/// that differs from our view of the head.
///
/// ## Important
///
/// This function is **not** suitable for determining proposer duties (only attester duties).
///
/// ## Notes
///
/// This function exists in this odd "map" pattern because efficiently obtaining a committee
/// can be complex. It might involve reading straight from the `beacon_chain.shuffling_cache`
/// or it might involve reading it from a state from the DB. Due to the complexities of
/// `RwLock`s on the shuffling cache, a simple `Cow` isn't suitable here.
///
/// If the committee for `(head_block_root, shuffling_epoch)` isn't found in the
/// `shuffling_cache`, we will read a state from disk and then update the `shuffling_cache`.


`&CommitteeCache`: the committee cache that serves the given parameters.
`Hash256`: the "shuffling decision root" which uniquely identifies the `CommitteeCache`.

It's not necessary that `head_block_root` matches our current view of the chain, it can be
any block that is.

Known to us.
The finalized block or a descendant of the finalized block.

It would be quite common for attestation verification operations to use a `head_block_root`
that differs from our view of the head.
` &CommitteeCache ` : the committee cache that serves the given parameters . ` Hash256 ` : the " shuffling decision root " which uniquely identifies the ` CommitteeCache ` . It ' s not necessary that ` head_block_root ` matches our current view of the chain it can be any block that is . Known to us . The finalized block or a descendant of the finalized block . It would be quite common for attestation verification operations to use a ` head_block_root ` that differs from our view of the head .
pub(crate) fn with_committee_cache<F, R>(
        &self,
        head_block_root: Hash256,
        shuffling_epoch: Epoch,
        map_fn: F,
    ) -> Result<R, Error>
    where
        F: Fn(&CommitteeCache, Hash256) -> Result<R, Error>,
    {
        let head_block = self
            .fork_choice
            .read()
            .get_block(&head_block_root)
            .ok_or(Error::MissingBeaconBlock(head_block_root))?;
        let shuffling_id = BlockShufflingIds {
            current: head_block.current_epoch_shuffling_id.clone(),
            next: head_block.next_epoch_shuffling_id.clone(),
            block_root: head_block.root,
        }
        .id_for_epoch(shuffling_epoch)
        .ok_or_else(|| Error::InvalidShufflingId {
            shuffling_epoch,
            head_block_epoch: head_block.slot.epoch(T::EthSpec::slots_per_epoch()),
        })?;
        // Obtain the shuffling cache, timing how long we wait.
        let cache_wait_timer =
            metrics::start_timer(&metrics::ATTESTATION_PROCESSING_SHUFFLING_CACHE_WAIT_TIMES);
        let mut shuffling_cache = self
            .shuffling_cache
            .try_write_for(ATTESTATION_CACHE_LOCK_TIMEOUT)
            .ok_or(Error::AttestationCacheLockTimeout)?;
        metrics::stop_timer(cache_wait_timer);
        if let Some(committee_cache) = shuffling_cache.get(&shuffling_id) {
            map_fn(committee_cache, shuffling_id.shuffling_decision_block)
        } else {
            // Drop the shuffling cache to avoid holding the lock for any longer than
            // required.
            drop(shuffling_cache);
            debug!(
                self.log,
                "Committee cache miss";
                "shuffling_id" => ?shuffling_epoch,
                "head_block_root" => head_block_root.to_string(),
            );
            let state_read_timer =
                metrics::start_timer(&metrics::ATTESTATION_PROCESSING_STATE_READ_TIMES);
            // If the head of the chain can serve this request, use it.
            //
            // This code is a little awkward because we need to ensure that the head we read and
            // the head we copy is identical. Taking one lock to read the head values and another
            // to copy the head is liable to race-conditions.
            let head_state_opt = self.with_head(|head| {
                if head.beacon_block_root == head_block_root {
                    Ok(Some((
                        head.beacon_state
                            .clone_with(CloneConfig::committee_caches_only()),
                        head.beacon_state_root(),
                    )))
                } else {
                    Ok::<_, Error>(None)
                }
            })?;
            // If the head state is useful for this request, use it. Otherwise, read a state from
            // disk.
            let (mut state, state_root) = if let Some((state, state_root)) = head_state_opt {
                (state, state_root)
            } else {
                let state_root = head_block.state_root;
                let state = self
                    .store
                    .get_inconsistent_state_for_attestation_verification_only(
                        &state_root,
                        Some(head_block.slot),
                    )?
                    .ok_or(Error::MissingBeaconState(head_block.state_root))?;
                (state, state_root)
            };
            /*
             * IMPORTANT
             *
             * Since it's possible that
             * `Store::get_inconsistent_state_for_attestation_verification_only` was used to obtain
             * the state, we cannot rely upon the following fields:
             *
             * - `state.state_roots`
             * - `state.block_roots`
             *
             * These fields should not be used for the rest of this function.
             */
            metrics::stop_timer(state_read_timer);
            let state_skip_timer =
                metrics::start_timer(&metrics::ATTESTATION_PROCESSING_STATE_SKIP_TIMES);
            // If the state is in an earlier epoch, advance it. If it's from a later epoch, reject
            // it.
            if state.current_epoch() + 1 < shuffling_epoch {
                // Since there's a one-epoch look-ahead on the attester shuffling, it suffices to
                // only advance into the slot prior to the `shuffling_epoch`.
                let target_slot = shuffling_epoch
                    .saturating_sub(1_u64)
                    .start_slot(T::EthSpec::slots_per_epoch());
                // Advance the state into the required slot, using the "partial" method since the state
                // roots are not relevant for the shuffling.
                partial_state_advance(&mut state, Some(state_root), target_slot, &self.spec)?;
            } else if state.current_epoch() > shuffling_epoch {
                return Err(Error::InvalidStateForShuffling {
                    state_epoch: state.current_epoch(),
                    shuffling_epoch,
                });
            }
            metrics::stop_timer(state_skip_timer);
            let committee_building_timer =
                metrics::start_timer(&metrics::ATTESTATION_PROCESSING_COMMITTEE_BUILDING_TIMES);
            let relative_epoch = RelativeEpoch::from_epoch(state.current_epoch(), shuffling_epoch)
                .map_err(Error::IncorrectStateForAttestation)?;
            state.build_committee_cache(relative_epoch, &self.spec)?;
            let committee_cache = state.committee_cache(relative_epoch)?;
            let shuffling_decision_block = shuffling_id.shuffling_decision_block;
            self.shuffling_cache
                .try_write_for(ATTESTATION_CACHE_LOCK_TIMEOUT)
                .ok_or(Error::AttestationCacheLockTimeout)?
                .insert(shuffling_id, committee_cache);
            metrics::stop_timer(committee_building_timer);
            map_fn(&committee_cache, shuffling_decision_block)
        }
    }
pub ( crate ) fn with_committee_cache < F , R > ( & self , head_block_root : Hash256 , shuffling_epoch : Epoch , map_fn : F , ) -> Result < R , Error > where F : Fn ( & CommitteeCache , Hash256 ) -> Result < R , Error > , { let head_block = self . fork_choice . read ( ) . get_block ( & head_block_root ) . ok_or ( Error :: MissingBeaconBlock ( head_block_root ) ) ? ; let shuffling_id = BlockShufflingIds { current : head_block . current_epoch_shuffling_id . clone ( ) , next : head_block . next_epoch_shuffling_id . clone ( ) , block_root : head_block . root , } . id_for_epoch ( shuffling_epoch ) . ok_or_else ( | | Error :: InvalidShufflingId { shuffling_epoch , head_block_epoch : head_block . slot . epoch ( T :: EthSpec :: slots_per_epoch ( ) ) , } ) ? ; // Obtain the shuffling cache, timing how long we wait. let cache_wait_timer = metrics :: start_timer ( & metrics :: ATTESTATION_PROCESSING_SHUFFLING_CACHE_WAIT_TIMES ) ; let mut shuffling_cache = self . shuffling_cache . try_write_for ( ATTESTATION_CACHE_LOCK_TIMEOUT ) . ok_or ( Error :: AttestationCacheLockTimeout ) ? ; metrics :: stop_timer ( cache_wait_timer ) ; if let Some ( committee_cache ) = shuffling_cache . get ( & shuffling_id ) { map_fn ( committee_cache , shuffling_id . shuffling_decision_block ) } else { // Drop the shuffling cache to avoid holding the lock for any longer than // required. drop ( shuffling_cache ) ; debug ! ( self log " " " " shuffling_epoch " " head_block_root to_string ( ) ) ; let state_read_timer = metrics :: start_timer ( & metrics :: ATTESTATION_PROCESSING_STATE_READ_TIMES ) ; // If the head of the chain can serve this request, use it. // // This code is a little awkward because we need to ensure that the head we read and // the head we copy is identical. Taking one lock to read the head values and another // to copy the head is liable to race-conditions. let head_state_opt = self . with_head ( | head | { if head . beacon_block_root == head_block_root { Ok ( Some ( ( head . beacon_state . clone_with ( CloneConfig :: committee_caches_only ( ) ) , head . beacon_state_root ( ) , ) ) ) } else { Ok :: < _ , Error > ( None ) } } ) ? ; // If the head state is useful for this request, use it. Otherwise, read a state from // disk. let ( mut state , state_root ) = if let Some ( ( state , state_root ) ) = head_state_opt { ( state , state_root ) } else { let state_root = head_block . state_root ; let state = self . store . get_inconsistent_state_for_attestation_verification_only ( & state_root , Some ( head_block . slot ) , ) ? . ok_or ( Error :: MissingBeaconState ( head_block . state_root ) ) ? ; ( state , state_root ) } ; /*
             * IMPORTANT
             *
             * Since it's possible that
             * `Store::get_inconsistent_state_for_attestation_verification_only` was used to obtain
             * the state, we cannot rely upon the following fields:
             *
             * - `state.state_roots`
             * - `state.block_roots`
             *
             * These fields should not be used for the rest of this function.
             */ metrics :: stop_timer ( state_read_timer ) ; let state_skip_timer = metrics :: start_timer ( & metrics :: ATTESTATION_PROCESSING_STATE_SKIP_TIMES ) ; // If the state is in an earlier epoch, advance it. If it's from a later epoch, reject // it. if state . current_epoch ( ) + 1 < shuffling_epoch { // Since there's a one-epoch look-ahead on the attester shuffling, it suffices to // only advance into the slot prior to the `shuffling_epoch`. let target_slot = shuffling_epoch . saturating_sub ( 1_u64 ) . start_slot ( T :: EthSpec :: slots_per_epoch ( ) ) ; // Advance the state into the required slot, using the "partial" method since the state // roots are not relevant for the shuffling. partial_state_advance ( & mut state , Some ( state_root ) , target_slot , & self . spec ) ? ; } else if state . current_epoch ( ) > shuffling_epoch { return Err ( Error :: InvalidStateForShuffling { state_epoch : state . current_epoch ( ) , shuffling_epoch , } ) ; } metrics :: stop_timer ( state_skip_timer ) ; let committee_building_timer = metrics :: start_timer ( & metrics :: ATTESTATION_PROCESSING_COMMITTEE_BUILDING_TIMES ) ; let relative_epoch = RelativeEpoch :: from_epoch ( state . current_epoch ( ) , shuffling_epoch ) . map_err ( Error :: IncorrectStateForAttestation ) ? ; state . build_committee_cache ( relative_epoch , & self . spec ) ? ; let committee_cache = state . committee_cache ( relative_epoch ) ? ; let shuffling_decision_block = shuffling_id . shuffling_decision_block ; self . shuffling_cache . try_write_for ( ATTESTATION_CACHE_LOCK_TIMEOUT ) . ok_or ( Error :: AttestationCacheLockTimeout ) ? . insert ( shuffling_id , committee_cache ) ; metrics :: stop_timer ( committee_building_timer ) ; map_fn ( & committee_cache , shuffling_decision_block ) } }
Runs the `map_fn` with the committee cache for `shuffling_epoch` from the chain with head
`head_block_root`.
Runs the ` map_fn ` with the committee cache for ` shuffling_epoch ` from the chain with head ` head_block_root ` .
&self
head_block_root
Hash256
shuffling_epoch
Epoch
map_fn
F
important
This function is **not** suitable for determining proposer duties (only attester duties).
This function is ** not ** suitable for determining proposer duties ( only attester duties ) .
notes
This function exists in this odd "map" pattern because efficiently obtaining a committee
can be complex. It might involve reading straight from the `beacon_chain.shuffling_cache`
or it might involve reading it from a state from the DB. Due to the complexities of
`RwLock`s on the shuffling cache, a simple `Cow` isn't suitable here.

If the committee for `(head_block_root, shuffling_epoch)` isn't found in the
`shuffling_cache`, we will read a state from disk and then update the `shuffling_cache`.
This function exists in this odd " map " pattern because efficiently obtaining a committee can be complex . It might involve reading straight from the ` beacon_chain . shuffling_cache ` or it might involve reading it from a state from the DB . Due to the complexities of ` RwLock ` s on the shuffling cache a simple ` Cow ` isn ' t suitable here . If the committee for ` ( head_block_root shuffling_epoch ) ` isn ' t found in the ` shuffling_cache ` we will read a state from disk and then update the ` shuffling_cache ` .