diff --git a/beacon_node/rest_api/src/beacon.rs b/beacon_node/rest_api/src/beacon.rs index f5abc51af2..cf540c65a6 100644 --- a/beacon_node/rest_api/src/beacon.rs +++ b/beacon_node/rest_api/src/beacon.rs @@ -203,7 +203,7 @@ pub fn get_state(req: Request) -> BoxFut { try_future!(parse_slot(&value)) )), ("root", value) => { - let root = &try_future!(parse_root(&value)); + let root: &Hash256 = &try_future!(parse_root(&value)); let state = try_future!(try_future!(beacon_chain.store.get(root)) .ok_or_else(|| ApiError::NotFound(format!("No state for root: {:?}", root)))); diff --git a/beacon_node/rest_api/src/helpers.rs b/beacon_node/rest_api/src/helpers.rs index 9eae4a00a6..a3633cfec0 100644 --- a/beacon_node/rest_api/src/helpers.rs +++ b/beacon_node/rest_api/src/helpers.rs @@ -23,6 +23,13 @@ pub fn success_response(req: Request, item: &T) -> }) } +pub fn success_response_2(req: Request, item: &T) -> ApiResult { + ResponseBuilder::new(&req).body(item) +} +pub fn success_response_2_json(req: Request, item: &T) -> ApiResult { + ResponseBuilder::new(&req).body_json(item) +} + pub fn success_response_json(req: Request, item: &T) -> BoxFut { if let Err(e) = check_content_type_for_json(&req) { return Box::new(futures::future::err(e)); @@ -213,11 +220,10 @@ pub fn state_root_at_slot( } } -pub fn implementation_pending_response(_req: Request) -> BoxFut { - ApiError::NotImplemented( +pub fn implementation_pending_response(_req: Request) -> ApiResult { + Err(ApiError::NotImplemented( "API endpoint has not yet been implemented, but is planned to be soon.".to_owned(), - ) - .into() + )) } pub fn get_beacon_chain_from_request( diff --git a/beacon_node/rest_api/src/lib.rs b/beacon_node/rest_api/src/lib.rs index e4f88caf38..bc3d3d1592 100644 --- a/beacon_node/rest_api/src/lib.rs +++ b/beacon_node/rest_api/src/lib.rs @@ -33,6 +33,7 @@ use std::sync::Arc; use tokio::runtime::TaskExecutor; use tokio::sync::mpsc; use url_query::UrlQuery; +use futures::future::IntoFuture; pub use beacon::{BlockResponse, HeadResponse, StateResponse}; pub use config::Config as ApiConfig; @@ -81,9 +82,10 @@ impl Service for ApiService { // Route the request to the correct handler. let result = match (req.method(), path.as_ref()) { // Methods for Client - (&Method::GET, "/node/version") => node::get_version(req), - (&Method::GET, "/node/genesis_time") => node::get_genesis_time::(req), - (&Method::GET, "/node/syncing") => helpers::implementation_pending_response(req), + (&Method::GET, "/node/version") => Box::new(node::get_version(req).into_future()), + (&Method::GET, "/node/genesis_time") => Box::new(node::get_genesis_time::(req).into_future()), + (&Method::GET, "/node/syncing") => Box::new(helpers::implementation_pending_response(req).into_future()), + /* // Methods for Network (&Method::GET, "/network/enr") => network::get_enr::(req), @@ -112,11 +114,12 @@ impl Service for ApiService { helpers::implementation_pending_response(req) } - /* // Methods for Validator (&Method::GET, "/beacon/validator/duties") => validator::get_validator_duties::(req), (&Method::GET, "/beacon/validator/block") => validator::get_new_beacon_block::(req), - //(&Method::POST, "/beacon/validator/block") => validator::publish_beacon_block::(req), + */ + (&Method::POST, "/beacon/validator/block") => validator::publish_beacon_block::(req), + /* (&Method::GET, "/beacon/validator/attestation") => { validator::get_new_attestation::(req) } diff --git a/beacon_node/rest_api/src/node.rs b/beacon_node/rest_api/src/node.rs index 8ca7fb48aa..33b8e055c5 100644 --- a/beacon_node/rest_api/src/node.rs +++ b/beacon_node/rest_api/src/node.rs @@ -5,19 +5,13 @@ use hyper::{Body, Request}; use version; /// Read the version string from the current Lighthouse build. -pub fn get_version(req: Request) -> BoxFut { - success_response_json(req, &version::version()) +pub fn get_version(req: Request) -> ApiResult { + success_response_2_json(req, &version::version()) } /// Read the genesis time from the current beacon chain state. -pub fn get_genesis_time(req: Request) -> BoxFut { - let bc = get_beacon_chain_from_request::(&req); - let (_beacon_chain, head_state) = match bc { - Ok((bc, hs)) => (bc, hs), - Err(e) => { - return e.into(); - } - }; +pub fn get_genesis_time(req: Request) -> ApiResult { + let (_beacon_chain, head_state) = get_beacon_chain_from_request::(&req)?; let gen_time: u64 = head_state.genesis_time; - success_response(req, &gen_time) + success_response_2(req, &gen_time) } diff --git a/beacon_node/rest_api/src/validator.rs b/beacon_node/rest_api/src/validator.rs index 7d236e0cf1..1de1647045 100644 --- a/beacon_node/rest_api/src/validator.rs +++ b/beacon_node/rest_api/src/validator.rs @@ -1,5 +1,6 @@ use crate::helpers::*; -use crate::{ApiError, ApiResult, UrlQuery}; +use crate::response_builder::ResponseBuilder; +use crate::{ApiError, ApiResult, UrlQuery, BoxFut}; use beacon_chain::{BeaconChainTypes, BlockProcessingOutcome}; use bls::{AggregateSignature, PublicKey, Signature}; use futures::future::Future; @@ -204,10 +205,10 @@ pub fn get_new_beacon_block(req: Request) - } /// HTTP Handler to publish a BeaconBlock, which has been signed by a validator. -pub fn publish_beacon_block(req: Request) -> ApiResult { - let _ = check_content_type_for_json(&req)?; +pub fn publish_beacon_block(req: Request) -> BoxFut { + let _ = try_future!(check_content_type_for_json(&req)); let log = get_logger_from_request(&req); - let (beacon_chain, _head_state) = get_beacon_chain_from_request::(&req)?; + let (beacon_chain, _head_state) = try_future!(get_beacon_chain_from_request::(&req)); // Get the network sending channel from the request, for later transmission let network_chan = req .extensions() @@ -215,49 +216,53 @@ pub fn publish_beacon_block(req: Request) - .expect("Should always get the network channel from the request, since we put it in there.") .clone(); + let response_builder = ResponseBuilder::new(&req); + let body = req.into_body(); trace!( log, "Got the request body, now going to parse it into a block." ); - let block_future = body + Box::new(body .concat2() - .map(move |chunk| chunk.iter().cloned().collect::>()) - .map(|chunks| { - let block_result: Result, ApiError> = - serde_json::from_slice(&chunks.as_slice()).map_err(|e| { - ApiError::InvalidQueryParams(format!( - "Unable to deserialize JSON into a BeaconBlock: {:?}", + .map_err(|e| ApiError::ServerError(format!("Unable to get request body: {:?}",e))) + .map(|chunk| chunk.iter().cloned().collect::>()) + .and_then(|chunks| { + serde_json::from_slice(&chunks.as_slice()).map_err(|e| { + ApiError::InvalidQueryParams(format!( + "Unable to deserialize JSON into a BeaconBlock: {:?}", + e + )) + }) + }) + .and_then(move |block: BeaconBlock| { + let slot = block.slot; + match beacon_chain.process_block(block.clone()) { + Ok(BlockProcessingOutcome::Processed { block_root }) => { + // Block was processed, publish via gossipsub + info!(log, "Processed valid block from API, transmitting to network."; "block_slot" => slot, "block_root" => format!("{}", block_root)); + publish_beacon_block_to_network::(network_chan, block) + } + Ok(outcome) => { + warn!(log, "Block could not be processed, but is being sent to the network anyway."; "block_slot" => slot, "outcome" => format!("{:?}", outcome)); + //TODO need to send to network and return http 202 + Err(ApiError::InvalidQueryParams(format!( + "The BeaconBlock could not be processed: {:?}", + outcome + ))) + } + Err(e) => { + Err(ApiError::ServerError(format!( + "Unable to process block: {:?}", e - )) - }); - block_result - }); - let block = block_future.wait()??; - trace!(log, "BeaconBlock successfully parsed from JSON"); - match beacon_chain.process_block(block.clone()) { - Ok(BlockProcessingOutcome::Processed { block_root }) => { - // Block was processed, publish via gossipsub - info!(log, "Processed valid block from API, transmitting to network."; "block_slot" => block.slot, "block_root" => format!("{}", block_root)); - publish_beacon_block_to_network::(network_chan, block)?; - } - Ok(outcome) => { - warn!(log, "Block could not be processed, but is being sent to the network anyway."; "block_slot" => block.slot, "outcome" => format!("{:?}", outcome)); - //TODO need to send to network and return http 202 - return Err(ApiError::InvalidQueryParams(format!( - "The BeaconBlock could not be processed: {:?}", - outcome - ))); - } - Err(e) => { - return Err(ApiError::ServerError(format!( - "Unable to process block: {:?}", - e - ))); - } - } + ))) + } + } + }).and_then(|_| { + response_builder.body_json(&()) + })) + - Ok(success_response_old(Body::empty())) } /// HTTP Handler to produce a new Attestation from the current state, ready to be signed by a validator.