diff --git a/beacon_node/beacon_chain/src/beacon_chain.rs b/beacon_node/beacon_chain/src/beacon_chain.rs index 56923ab6a..f6cef7dac 100644 --- a/beacon_node/beacon_chain/src/beacon_chain.rs +++ b/beacon_node/beacon_chain/src/beacon_chain.rs @@ -90,6 +90,15 @@ impl<'a, T: EthSpec> AsRef> for StateCow<'a, T> { } } +impl<'a, T: EthSpec> StateCow<'a, T> { + pub fn as_mut_ref(&mut self) -> Option<&mut BeaconState> { + match self { + StateCow::Borrowed(_) => None, + StateCow::Owned(ref mut state) => Some(state), + } + } +} + pub trait BeaconChainTypes: Send + Sync + 'static { type Store: store::Store; type SlotClock: slot_clock::SlotClock; @@ -447,12 +456,16 @@ impl BeaconChain { let epoch = |slot: Slot| slot.epoch(T::EthSpec::slots_per_epoch()); let head_state = &self.head().beacon_state; - let state = if epoch(slot) == epoch(head_state.slot) { + let mut state = if epoch(slot) == epoch(head_state.slot) { StateCow::Borrowed(self.head()) } else { self.state_at_slot(slot)? }; + if let Some(state) = state.as_mut_ref() { + state.build_committee_cache(RelativeEpoch::Current, &self.spec)?; + } + state .as_ref() .get_beacon_proposer_index(slot, RelativeEpoch::Current, &self.spec) @@ -471,12 +484,16 @@ impl BeaconChain { let as_epoch = |slot: Slot| slot.epoch(T::EthSpec::slots_per_epoch()); let head_state = &self.head().beacon_state; - let state = if epoch == as_epoch(head_state.slot) { + let mut state = if epoch == as_epoch(head_state.slot) { StateCow::Borrowed(self.head()) } else { self.state_at_slot(epoch.start_slot(T::EthSpec::slots_per_epoch()))? }; + if let Some(state) = state.as_mut_ref() { + state.build_committee_cache(RelativeEpoch::Current, &self.spec)?; + } + if let Some(attestation_duty) = state .as_ref() .get_attestation_duties(validator_index, RelativeEpoch::Current)? diff --git a/beacon_node/rpc/src/validator.rs b/beacon_node/rpc/src/validator.rs index fd6d7f3d1..afe173318 100644 --- a/beacon_node/rpc/src/validator.rs +++ b/beacon_node/rpc/src/validator.rs @@ -28,9 +28,33 @@ impl ValidatorService for ValidatorServiceInstance { let validators = req.get_validators(); trace!(self.log, "RPC request"; "endpoint" => "GetValidatorDuties", "epoch" => req.get_epoch()); + let slot = if let Ok(slot) = self.chain.slot() { + slot + } else { + let log_clone = self.log.clone(); + let f = sink + .fail(RpcStatus::new( + RpcStatusCode::FailedPrecondition, + Some("No slot for chain".to_string()), + )) + .map_err(move |e| warn!(log_clone, "failed to reply {:?}: {:?}", req, e)); + return ctx.spawn(f); + }; + let state_cow = if let Ok(state) = self.chain.state_at_slot(slot) { + state + } else { + let log_clone = self.log.clone(); + let f = sink + .fail(RpcStatus::new( + RpcStatusCode::FailedPrecondition, + Some("No state".to_string()), + )) + .map_err(move |e| warn!(log_clone, "failed to reply {:?}: {:?}", req, e)); + return ctx.spawn(f); + }; + let state = state_cow.as_ref(); + let spec = &self.chain.spec; - // TODO: this whole module is legacy and not maintained well. - let state = &self.chain.head().beacon_state; let epoch = Epoch::from(req.get_epoch()); let mut resp = GetDutiesResponse::new(); let resp_validators = resp.mut_active_validators();