diff --git a/beacon_node/beacon_chain/src/canonical_head.rs b/beacon_node/beacon_chain/src/canonical_head.rs index c9bd6db0e67..53e0fbaac95 100644 --- a/beacon_node/beacon_chain/src/canonical_head.rs +++ b/beacon_node/beacon_chain/src/canonical_head.rs @@ -654,11 +654,11 @@ impl BeaconChain { }) }) .and_then(|mut snapshot| { - // Regardless of where we got the state from, attempt to build the committee - // caches. + // Regardless of where we got the state from, attempt to build all the + // caches except the tree hash cache. snapshot .beacon_state - .build_all_committee_caches(&self.spec) + .build_all_caches(&self.spec) .map_err(Into::into) .map(|()| snapshot) })?; diff --git a/beacon_node/http_api/src/lib.rs b/beacon_node/http_api/src/lib.rs index 5b4fa5816d8..51e97c893d0 100644 --- a/beacon_node/http_api/src/lib.rs +++ b/beacon_node/http_api/src/lib.rs @@ -668,9 +668,10 @@ pub fn serve( "Invalid validator ID".to_string(), )) })) + .and(log_filter.clone()) .and(warp::path::end()) .and_then( - |state_id: StateId, chain: Arc>, validator_id: ValidatorId| { + |state_id: StateId, chain: Arc>, validator_id: ValidatorId, log| { blocking_json_task(move || { let (data, execution_optimistic) = state_id .map_state_and_execution_optimistic( @@ -678,7 +679,23 @@ pub fn serve( |state, execution_optimistic| { let index_opt = match &validator_id { ValidatorId::PublicKey(pubkey) => { - state.validators().iter().position(|v| v.pubkey == *pubkey) + // Fast path: use the pubkey cache which is probably + // initialised at the head. + match state.get_validator_index_read_only(pubkey) { + Ok(result) => result, + Err(e) => { + // Slow path, fall back to iteration. + debug!( + log, + "Validator look-up cache miss"; + "reason" => ?e, + ); + state + .validators() + .iter() + .position(|v| v.pubkey == *pubkey) + } + } } ValidatorId::Index(index) => Some(*index as usize), }; diff --git a/beacon_node/http_api/src/state_id.rs b/beacon_node/http_api/src/state_id.rs index 051789c953b..44354217bc4 100644 --- a/beacon_node/http_api/src/state_id.rs +++ b/beacon_node/http_api/src/state_id.rs @@ -155,33 +155,12 @@ impl StateId { Ok((state, execution_optimistic)) } - /* /// Map a function across the `BeaconState` identified by `self`. /// + /// The optimistic status of the requested state is also provided to the `func` closure. + /// /// This function will avoid instantiating/copying a new state when `self` points to the head /// of the chain. - #[allow(dead_code)] - pub fn map_state( - &self, - chain: &BeaconChain, - func: F, - ) -> Result - where - F: Fn(&BeaconState) -> Result, - { - match &self.0 { - CoreStateId::Head => chain - .with_head(|snapshot| Ok(func(&snapshot.beacon_state))) - .map_err(warp_utils::reject::beacon_chain_error)?, - _ => func(&self.state(chain)?), - } - } - */ - - /// Functions the same as `map_state` but additionally computes the value of - /// `execution_optimistic` of the state identified by `self`. - /// - /// This is to avoid re-instantiating `state` unnecessarily. pub fn map_state_and_execution_optimistic( &self, chain: &BeaconChain, diff --git a/consensus/state_processing/src/per_block_processing/verify_deposit.rs b/consensus/state_processing/src/per_block_processing/verify_deposit.rs index 3b43a8b41b6..181b27ca1a6 100644 --- a/consensus/state_processing/src/per_block_processing/verify_deposit.rs +++ b/consensus/state_processing/src/per_block_processing/verify_deposit.rs @@ -29,9 +29,7 @@ pub fn verify_deposit_signature(deposit_data: &DepositData, spec: &ChainSpec) -> /// Returns a `Some(validator index)` if a pubkey already exists in the `validators`, /// otherwise returns `None`. /// -/// ## Errors -/// -/// Errors if the state's `pubkey_cache` is not current. +/// Builds the pubkey cache if it is not already built. pub fn get_existing_validator_index( state: &mut BeaconState, pub_key: &PublicKeyBytes, diff --git a/consensus/types/src/beacon_state.rs b/consensus/types/src/beacon_state.rs index a5d00cdf2dd..46a431d0733 100644 --- a/consensus/types/src/beacon_state.rs +++ b/consensus/types/src/beacon_state.rs @@ -447,6 +447,21 @@ impl BeaconState { Ok(self.pubkey_cache().get(pubkey)) } + /// Immutable variant of `get_validator_index` which errors if the cache is not up to date. + pub fn get_validator_index_read_only( + &self, + pubkey: &PublicKeyBytes, + ) -> Result, Error> { + let pubkey_cache = self.pubkey_cache(); + if pubkey_cache.len() != self.validators().len() { + return Err(Error::PubkeyCacheIncomplete { + cache_len: pubkey_cache.len(), + registry_len: self.validators().len(), + }); + } + Ok(pubkey_cache.get(pubkey)) + } + /// The epoch corresponding to `self.slot()`. pub fn current_epoch(&self) -> Epoch { self.slot().epoch(T::slots_per_epoch())