diff --git a/beacon_node/rest_api/src/beacon.rs b/beacon_node/rest_api/src/beacon.rs index 9353688926..ae112883e9 100644 --- a/beacon_node/rest_api/src/beacon.rs +++ b/beacon_node/rest_api/src/beacon.rs @@ -6,7 +6,7 @@ use serde::Serialize; use ssz_derive::Encode; use std::sync::Arc; use store::Store; -use types::{BeaconBlock, BeaconState, EthSpec, Hash256, Slot}; +use types::{BeaconBlock, BeaconState, Epoch, EthSpec, Hash256, Slot}; #[derive(Serialize)] pub struct HeadResponse { @@ -136,16 +136,47 @@ pub fn get_fork(req: Request) -> ApiResult Ok(success_response(Body::from(json))) } -/// HTTP handler to return a `BeaconState` at a given `root` or `slot`. +/// HTTP handler to return the set of validators for an `Epoch` /// -/// Will not return a state if the request slot is in the future. Will return states higher than -/// the current head by skipping slots. -pub fn get_genesis_state(req: Request) -> ApiResult { +/// The `Epoch` parameter can be any epoch number. If it is not specified, +/// the current epoch is assumed. +pub fn get_validators(req: Request) -> ApiResult { let beacon_chain = get_beacon_chain_from_request::(&req)?; - let (_root, state) = state_at_slot(&beacon_chain, Slot::new(0))?; + let epoch = match UrlQuery::from_request(&req) { + // We have some parameters, so make sure it's the epoch one and parse it + Ok(query) => query + .only_one("epoch")? + .parse::() + .map(Epoch::from) + .map_err(|e| { + ApiError::InvalidQueryParams(format!( + "Invalid epoch parameter, must be a u64. {:?}", + e + )) + })?, + // In this case, our url query did not contain any parameters, so we take the default + Err(_) => beacon_chain.epoch().map_err(|e| { + ApiError::ServerError(format!("Unable to determine current epoch: {:?}", e)) + })?, + }; - ResponseBuilder::new(&req).body(&state) + let all_validators = &beacon_chain.head().beacon_state.validators; + let mut active_validators = Vec::with_capacity(all_validators.len()); + for (_index, validator) in all_validators.iter().enumerate() { + if validator.is_active_at(epoch) { + active_validators.push(validator) + } + } + active_validators.shrink_to_fit(); + let json: String = serde_json::to_string(&active_validators).map_err(|e| { + ApiError::ServerError(format!( + "Unable to serialize list of active validators: {:?}", + e + )) + })?; + + Ok(success_response(Body::from(json))) } #[derive(Serialize, Encode)] @@ -244,3 +275,15 @@ pub fn get_current_finalized_checkpoint( Ok(success_response(Body::from(json))) } + +/// HTTP handler to return a `BeaconState` at a given `root` or `slot`. +/// +/// Will not return a state if the request slot is in the future. Will return states higher than +/// the current head by skipping slots. +pub fn get_genesis_state(req: Request) -> ApiResult { + let beacon_chain = get_beacon_chain_from_request::(&req)?; + + let (_root, state) = state_at_slot(&beacon_chain, Slot::new(0))?; + + ResponseBuilder::new(&req).body(&state) +} diff --git a/beacon_node/rest_api/src/lib.rs b/beacon_node/rest_api/src/lib.rs index 4dbbdda515..02c68c6394 100644 --- a/beacon_node/rest_api/src/lib.rs +++ b/beacon_node/rest_api/src/lib.rs @@ -54,6 +54,7 @@ impl Into> for ApiError { }; Response::builder() .status(status_code.0) + .header("content-type", "text/plain") .body(Body::from(status_code.1)) .expect("Response should always be created.") } @@ -160,9 +161,7 @@ pub fn start_server( helpers::implementation_pending_response(req) } - (&Method::GET, "/beacon/validators") => { - helpers::implementation_pending_response(req) - } + (&Method::GET, "/beacon/validators") => beacon::get_validators::(req), (&Method::GET, "/beacon/validators/indicies") => { helpers::implementation_pending_response(req) } diff --git a/beacon_node/rest_api/src/validator.rs b/beacon_node/rest_api/src/validator.rs index 010e49305b..2374373bdf 100644 --- a/beacon_node/rest_api/src/validator.rs +++ b/beacon_node/rest_api/src/validator.rs @@ -60,6 +60,18 @@ pub fn get_validator_duties(req: Request) - .collect::, _>>()?; let mut duties: Vec = Vec::new(); + // Update the committee cache + // TODO: Do we need to update the cache on the state, for the epoch which has been specified? + beacon_chain + .state_now() + .map_err(|e| ApiError::ServerError(format!("Unable to get current BeaconState {:?}", e)))? + .maybe_as_mut_ref() + .ok_or(ApiError::ServerError( + "Unable to get mutable BeaconState".into(), + ))? + .build_committee_cache(relative_epoch, &beacon_chain.spec) + .map_err(|e| ApiError::ServerError(format!("Unable to build state caches: {:?}", e)))?; + // Get a list of all validators for this epoch let validator_proposers: Vec = epoch .slot_iter(T::EthSpec::slots_per_epoch()) @@ -67,6 +79,7 @@ pub fn get_validator_duties(req: Request) - head_state .get_beacon_proposer_index(slot, relative_epoch, &beacon_chain.spec) .map_err(|e| { + // TODO: why are we getting an uninitialized state error here??? ApiError::ServerError(format!( "Unable to get proposer index for validator: {:?}", e