Fixed merge conflict, updated calls.

- Fixed function re-names
 - Updated the function which gets the beacon_chain from the request, and makes sure caches are updated.
 - Updated this api-alignment branch with the new code from interop branch.
This commit is contained in:
Luke Anderson
2019-09-04 16:06:14 +10:00
81 changed files with 3515 additions and 1507 deletions

View File

@@ -1,8 +1,9 @@
use super::{success_response, ApiResult};
use super::{success_response, ApiResult, ResponseBuilder};
use crate::{helpers::*, ApiError, UrlQuery};
use beacon_chain::{BeaconChain, BeaconChainTypes};
use hyper::{Body, Request};
use serde::Serialize;
use ssz_derive::Encode;
use std::sync::Arc;
use store::Store;
use types::{BeaconBlock, BeaconState, EthSpec, Hash256, Slot};
@@ -59,7 +60,7 @@ pub fn get_head<T: BeaconChainTypes + 'static>(req: Request<Body>) -> ApiResult
Ok(success_response(Body::from(json)))
}
#[derive(Serialize)]
#[derive(Serialize, Encode)]
#[serde(bound = "T: EthSpec")]
pub struct BlockResponse<T: EthSpec> {
pub root: Hash256,
@@ -103,11 +104,7 @@ pub fn get_block<T: BeaconChainTypes + 'static>(req: Request<Body>) -> ApiResult
beacon_block: block,
};
let json: String = serde_json::to_string(&response).map_err(|e| {
ApiError::ServerError(format!("Unable to serialize BlockResponse: {:?}", e))
})?;
Ok(success_response(Body::from(json)))
ResponseBuilder::new(&req).body(&response)
}
/// HTTP handler to return a `BeaconBlock` root at a given `slot`.
@@ -132,11 +129,7 @@ pub fn get_block_root<T: BeaconChainTypes + 'static>(req: Request<Body>) -> ApiR
/// HTTP handler to return the `Fork` of the current head.
pub fn get_fork<T: BeaconChainTypes + 'static>(req: Request<Body>) -> ApiResult {
let beacon_chain = req
.extensions()
.get::<Arc<BeaconChain<T>>>()
.ok_or_else(|| ApiError::ServerError("Beacon chain extension missing".to_string()))?;
let beacon_chain = get_beacon_chain_from_request::<T>(&req)?;
let chain_head = beacon_chain.head();
let json: String = serde_json::to_string(&chain_head.beacon_state.fork).map_err(|e| {
@@ -146,7 +139,19 @@ pub fn get_fork<T: BeaconChainTypes + 'static>(req: Request<Body>) -> ApiResult
Ok(success_response(Body::from(json)))
}
#[derive(Serialize)]
/// 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<T: BeaconChainTypes + 'static>(req: Request<Body>) -> ApiResult {
let beacon_chain = get_beacon_chain_from_request::<T>(&req)?;
let (_root, state) = state_at_slot(&beacon_chain, Slot::new(0))?;
ResponseBuilder::new(&req).body(&state)
}
#[derive(Serialize, Encode)]
#[serde(bound = "T: EthSpec")]
pub struct StateResponse<T: EthSpec> {
pub root: Hash256,
@@ -207,11 +212,7 @@ pub fn get_state<T: BeaconChainTypes + 'static>(req: Request<Body>) -> ApiResult
beacon_state: state,
};
let json: String = serde_json::to_string(&response).map_err(|e| {
ApiError::ServerError(format!("Unable to serialize StateResponse: {:?}", e))
})?;
Ok(success_response(Body::from(json)))
ResponseBuilder::new(&req).body(&response)
}
/// HTTP handler to return a `BeaconState` root at a given `slot`.

View File

@@ -16,7 +16,7 @@ pub struct Config {
impl Default for Config {
fn default() -> Self {
Config {
enabled: true, // rest_api enabled by default
enabled: true,
listen_address: Ipv4Addr::new(127, 0, 0, 1),
port: 5052,
}
@@ -25,8 +25,8 @@ impl Default for Config {
impl Config {
pub fn apply_cli_args(&mut self, args: &ArgMatches) -> Result<(), &'static str> {
if args.is_present("api") {
self.enabled = true;
if args.is_present("no-api") {
self.enabled = false;
}
if let Some(rpc_address) = args.value_of("api-address") {

View File

@@ -109,8 +109,8 @@ pub fn state_root_at_slot<T: BeaconChainTypes>(
) -> Result<Hash256, ApiError> {
let head_state = &beacon_chain.head().beacon_state;
let current_slot = beacon_chain
.read_slot_clock()
.ok_or_else(|| ApiError::ServerError("Unable to read slot clock".to_string()))?;
.slot()
.map_err(|_| ApiError::ServerError("Unable to read slot clock".to_string()))?;
// There are four scenarios when obtaining a state for a given slot:
//
@@ -177,12 +177,18 @@ pub fn get_beacon_chain_from_request<T: BeaconChainTypes + 'static>(
let beacon_chain = req
.extensions()
.get::<Arc<BeaconChain<T>>>()
.ok_or_else(|| {
ApiError::ServerError("Request is missing the beacon chain extension".into())
})?;
let _ = beacon_chain
.ensure_state_caches_are_built()
.ok_or_else(|| ApiError::ServerError("Beacon chain extension missing".into()))?;
let _state_now = 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_all_caches(&beacon_chain.spec)
.map_err(|e| ApiError::ServerError(format!("Unable to build state caches: {:?}", e)))?;
Ok(beacon_chain.clone())
}

View File

@@ -8,15 +8,18 @@ mod helpers;
mod metrics;
mod network;
mod node;
mod response_builder;
mod spec;
mod url_query;
mod validator;
use beacon_chain::{BeaconChain, BeaconChainTypes};
use client_network::Service as NetworkService;
use eth2_config::Eth2Config;
use hyper::rt::Future;
use hyper::service::service_fn_ok;
use hyper::{Body, Method, Response, Server, StatusCode};
use response_builder::ResponseBuilder;
use slog::{info, o, warn};
use std::ops::Deref;
use std::path::PathBuf;
@@ -80,6 +83,7 @@ pub fn start_server<T: BeaconChainTypes>(
beacon_chain: Arc<BeaconChain<T>>,
network_service: Arc<NetworkService<T>>,
db_path: PathBuf,
eth2_config: Eth2Config,
log: &slog::Logger,
) -> Result<exit_future::Signal, hyper::Error> {
let log = log.new(o!("Service" => "Api"));
@@ -101,12 +105,14 @@ pub fn start_server<T: BeaconChainTypes>(
// Clone our stateful objects, for use in service closure.
let server_log = log.clone();
let server_bc = beacon_chain.clone();
let eth2_config = Arc::new(eth2_config);
let service = move || {
let log = server_log.clone();
let beacon_chain = server_bc.clone();
let db_path = db_path.clone();
let network_service = network_service.clone();
let eth2_config = eth2_config.clone();
// Create a simple handler for the router, inject our stateful objects into the request.
service_fn_ok(move |mut req| {
@@ -119,6 +125,8 @@ pub fn start_server<T: BeaconChainTypes>(
req.extensions_mut().insert::<DBPath>(db_path.clone());
req.extensions_mut()
.insert::<Arc<NetworkService<T>>>(network_service.clone());
req.extensions_mut()
.insert::<Arc<Eth2Config>>(eth2_config.clone());
let path = req.uri().path().to_string();
@@ -184,6 +192,7 @@ pub fn start_server<T: BeaconChainTypes>(
(&Method::GET, "/beacon/state/current_finalized_checkpoint") => {
beacon::get_current_finalized_checkpoint::<T>(req)
}
(&Method::GET, "/beacon/state/genesis") => beacon::get_genesis_state::<T>(req),
//TODO: Add aggreggate/filtered state lookups here, e.g. /beacon/validators/balances
// Methods for bootstrap and checking configuration
@@ -192,6 +201,7 @@ pub fn start_server<T: BeaconChainTypes>(
(&Method::GET, "/spec/deposit_contract") => {
helpers::implementation_pending_response(req)
}
(&Method::GET, "/spec/eth2_config") => spec::get_eth2_config::<T>(req),
(&Method::GET, "/metrics") => metrics::get_prometheus::<T>(req),

View File

@@ -0,0 +1,50 @@
use super::{ApiError, ApiResult};
use http::header;
use hyper::{Body, Request, Response, StatusCode};
use serde::Serialize;
use ssz::Encode;
pub enum Encoding {
JSON,
SSZ,
YAML,
}
pub struct ResponseBuilder {
encoding: Encoding,
}
impl ResponseBuilder {
pub fn new(req: &Request<Body>) -> Self {
let encoding = match req.headers().get(header::CONTENT_TYPE) {
Some(h) if h == "application/ssz" => Encoding::SSZ,
Some(h) if h == "application/yaml" => Encoding::YAML,
_ => Encoding::JSON,
};
Self { encoding }
}
pub fn body<T: Serialize + Encode>(self, item: &T) -> ApiResult {
let body: Body = match self.encoding {
Encoding::JSON => Body::from(serde_json::to_string(&item).map_err(|e| {
ApiError::ServerError(format!(
"Unable to serialize response body as JSON: {:?}",
e
))
})?),
Encoding::SSZ => Body::from(item.as_ssz_bytes()),
Encoding::YAML => Body::from(serde_yaml::to_string(&item).map_err(|e| {
ApiError::ServerError(format!(
"Unable to serialize response body as YAML: {:?}",
e
))
})?),
};
Response::builder()
.status(StatusCode::OK)
.body(Body::from(body))
.map_err(|e| ApiError::ServerError(format!("Failed to build response: {:?}", e)))
}
}

View File

@@ -1,6 +1,7 @@
use super::{success_response, ApiResult};
use crate::ApiError;
use beacon_chain::{BeaconChain, BeaconChainTypes};
use eth2_config::Eth2Config;
use hyper::{Body, Request};
use std::sync::Arc;
use types::EthSpec;
@@ -18,6 +19,19 @@ pub fn get_spec<T: BeaconChainTypes + 'static>(req: Request<Body>) -> ApiResult
Ok(success_response(Body::from(json)))
}
/// HTTP handler to return the full Eth2Config object.
pub fn get_eth2_config<T: BeaconChainTypes + 'static>(req: Request<Body>) -> ApiResult {
let eth2_config = req
.extensions()
.get::<Arc<Eth2Config>>()
.ok_or_else(|| ApiError::ServerError("Eth2Config extension missing".to_string()))?;
let json: String = serde_json::to_string(eth2_config.as_ref())
.map_err(|e| ApiError::ServerError(format!("Unable to serialize Eth2Config: {:?}", e)))?;
Ok(success_response(Body::from(json)))
}
/// HTTP handler to return the full spec object.
pub fn get_slots_per_epoch<T: BeaconChainTypes + 'static>(_req: Request<Body>) -> ApiResult {
let json: String = serde_json::to_string(&T::EthSpec::slots_per_epoch())

View File

@@ -206,8 +206,8 @@ pub fn get_new_attestation<T: BeaconChainTypes + 'static>(req: Request<Body>) ->
.ok_or(ApiError::InvalidQueryParams("No validator duties could be found for the requested validator. Cannot provide valid attestation.".into()))?;
// Check that we are requesting an attestation during the slot where it is relevant.
let present_slot = beacon_chain.read_slot_clock().ok_or(ApiError::ServerError(
"Beacon node is unable to determine present slot, either the state isn't generated or the chain hasn't begun.".into()
let present_slot = beacon_chain.slot().map_err(|e| ApiError::ServerError(
format!("Beacon node is unable to determine present slot, either the state isn't generated or the chain hasn't begun. {:?}", e)
))?;
if val_duty.slot != present_slot {
return Err(ApiError::InvalidQueryParams(format!("Validator is only able to request an attestation during the slot they are allocated. Current slot: {:?}, allocated slot: {:?}", head_state.slot, val_duty.slot)));
@@ -257,7 +257,7 @@ pub fn get_new_attestation<T: BeaconChainTypes + 'static>(req: Request<Body>) ->
})?;
let attestation_data = beacon_chain
.produce_attestation_data(shard)
.produce_attestation_data(shard, current_slot.into())
.map_err(|e| ApiError::ServerError(format!("Could not produce an attestation: {:?}", e)))?;
let attestation: Attestation<T::EthSpec> = Attestation {