diff --git a/Cargo.lock b/Cargo.lock index 3084e9b01af..e6285fbb408 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -569,16 +569,6 @@ dependencies = [ "serde", ] -[[package]] -name = "buf_redux" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b953a6887648bb07a535631f2bc00fbdb2a2216f135552cb3f534ed136b9c07f" -dependencies = [ - "memchr", - "safemem", -] - [[package]] name = "bumpalo" version = "3.4.0" @@ -750,7 +740,6 @@ dependencies = [ "eth2_ssz", "futures 0.3.5", "genesis", - "http_api", "lazy_static", "lighthouse_metrics", "network", @@ -2136,31 +2125,6 @@ dependencies = [ "tokio 0.2.22", ] -[[package]] -name = "headers" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed18eb2459bf1a09ad2d6b1547840c3e5e62882fa09b9a6a20b1de8e3228848f" -dependencies = [ - "base64 0.12.3", - "bitflags 1.2.1", - "bytes 0.5.6", - "headers-core", - "http 0.2.1", - "mime 0.3.16", - "sha-1", - "time 0.1.43", -] - -[[package]] -name = "headers-core" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429" -dependencies = [ - "http 0.2.1", -] - [[package]] name = "heck" version = "0.3.1" @@ -2282,19 +2246,6 @@ dependencies = [ "http 0.2.1", ] -[[package]] -name = "http_api" -version = "0.1.0" -dependencies = [ - "beacon_chain", - "hex 0.4.2", - "parking_lot 0.11.0", - "serde", - "tokio 0.2.22", - "types", - "warp", -] - [[package]] name = "httparse" version = "1.3.4" @@ -2468,15 +2419,6 @@ dependencies = [ "hashbrown 0.8.2", ] -[[package]] -name = "input_buffer" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19a8a95243d5a0398cae618ec29477c6e3cb631152be5c19481f80bc71559754" -dependencies = [ - "bytes 0.5.6", -] - [[package]] name = "instant" version = "0.1.6" @@ -3162,18 +3104,6 @@ version = "0.3.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" -[[package]] -name = "mime_guess" -version = "1.8.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "216929a5ee4dd316b1702eedf5e74548c123d370f47841ceaac38ca154690ca3" -dependencies = [ - "mime 0.2.6", - "phf", - "phf_codegen", - "unicase 1.4.2", -] - [[package]] name = "mime_guess" version = "2.0.3" @@ -3290,24 +3220,6 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1255076139a83bb467426e7f8d0134968a8118844faa755985e077cf31850333" -[[package]] -name = "multipart" -version = "0.16.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "136eed74cadb9edd2651ffba732b19a450316b680e4f48d6c79e905799e19d01" -dependencies = [ - "buf_redux", - "httparse", - "log 0.4.11", - "mime 0.2.6", - "mime_guess 1.8.8", - "quick-error 1.2.3", - "rand 0.6.5", - "safemem", - "tempfile", - "twoway", -] - [[package]] name = "multistream-select" version = "0.8.2" @@ -3809,45 +3721,6 @@ dependencies = [ "indexmap", ] -[[package]] -name = "phf" -version = "0.7.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3da44b85f8e8dfaec21adae67f95d93244b2ecf6ad2a692320598dcc8e6dd18" -dependencies = [ - "phf_shared", -] - -[[package]] -name = "phf_codegen" -version = "0.7.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b03e85129e324ad4166b06b2c7491ae27fe3ec353af72e72cd1654c7225d517e" -dependencies = [ - "phf_generator", - "phf_shared", -] - -[[package]] -name = "phf_generator" -version = "0.7.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09364cc93c159b8b06b1f4dd8a4398984503483891b0c26b867cf431fb132662" -dependencies = [ - "phf_shared", - "rand 0.6.5", -] - -[[package]] -name = "phf_shared" -version = "0.7.24" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "234f71a15de2288bcb7e3b6515828d22af7ec8598ee6d24c3b526fa0a80b67a0" -dependencies = [ - "siphasher", - "unicase 1.4.2", -] - [[package]] name = "pin-project" version = "0.4.23" @@ -4185,25 +4058,6 @@ dependencies = [ "winapi 0.3.9", ] -[[package]] -name = "rand" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" -dependencies = [ - "autocfg 0.1.7", - "libc", - "rand_chacha 0.1.1", - "rand_core 0.4.2", - "rand_hc 0.1.0", - "rand_isaac", - "rand_jitter", - "rand_os", - "rand_pcg", - "rand_xorshift 0.1.1", - "winapi 0.3.9", -] - [[package]] name = "rand" version = "0.7.3" @@ -4212,19 +4066,9 @@ checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" dependencies = [ "getrandom", "libc", - "rand_chacha 0.2.2", + "rand_chacha", "rand_core 0.5.1", - "rand_hc 0.2.0", -] - -[[package]] -name = "rand_chacha" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" -dependencies = [ - "autocfg 0.1.7", - "rand_core 0.3.1", + "rand_hc", ] [[package]] @@ -4261,15 +4105,6 @@ dependencies = [ "getrandom", ] -[[package]] -name = "rand_hc" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" -dependencies = [ - "rand_core 0.3.1", -] - [[package]] name = "rand_hc" version = "0.2.0" @@ -4279,59 +4114,6 @@ dependencies = [ "rand_core 0.5.1", ] -[[package]] -name = "rand_isaac" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" -dependencies = [ - "rand_core 0.3.1", -] - -[[package]] -name = "rand_jitter" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b" -dependencies = [ - "libc", - "rand_core 0.4.2", - "winapi 0.3.9", -] - -[[package]] -name = "rand_os" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" -dependencies = [ - "cloudabi 0.0.3", - "fuchsia-cprng", - "libc", - "rand_core 0.4.2", - "rdrand", - "winapi 0.3.9", -] - -[[package]] -name = "rand_pcg" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" -dependencies = [ - "autocfg 0.1.7", - "rand_core 0.4.2", -] - -[[package]] -name = "rand_xorshift" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" -dependencies = [ - "rand_core 0.3.1", -] - [[package]] name = "rand_xorshift" version = "0.2.0" @@ -4466,7 +4248,7 @@ dependencies = [ "lazy_static", "log 0.4.11", "mime 0.3.16", - "mime_guess 2.0.3", + "mime_guess", "native-tls", "percent-encoding 2.1.0", "pin-project-lite", @@ -5011,12 +4793,6 @@ dependencies = [ "validator_client", ] -[[package]] -name = "siphasher" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b8de496cf83d4ed58b6be86c3a275b8602f6ffe98d3024a869e124147a9a3ac" - [[package]] name = "slab" version = "0.3.0" @@ -5914,19 +5690,6 @@ dependencies = [ "tokio 0.2.22", ] -[[package]] -name = "tokio-tungstenite" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8b8fe88007ebc363512449868d7da4389c9400072a3f666f212c7280082882a" -dependencies = [ - "futures 0.3.5", - "log 0.4.11", - "pin-project", - "tokio 0.2.22", - "tungstenite", -] - [[package]] name = "tokio-udp" version = "0.1.6" @@ -6027,16 +5790,6 @@ dependencies = [ "lazy_static", ] -[[package]] -name = "tracing-futures" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab7bb6f14721aa00656086e9335d363c5c8747bae02ebe32ea2c7dece5689b4c" -dependencies = [ - "pin-project", - "tracing", -] - [[package]] name = "trackable" version = "1.0.0" @@ -6090,34 +5843,6 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" -[[package]] -name = "tungstenite" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfea31758bf674f990918962e8e5f07071a3161bd7c4138ed23e416e1ac4264e" -dependencies = [ - "base64 0.11.0", - "byteorder", - "bytes 0.5.6", - "http 0.2.1", - "httparse", - "input_buffer", - "log 0.4.11", - "rand 0.7.3", - "sha-1", - "url 2.1.1", - "utf-8", -] - -[[package]] -name = "twoway" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59b11b2b5241ba34be09c3cc85a36e56e48f9888862e19cedf23336d35316ed1" -dependencies = [ - "memchr", -] - [[package]] name = "typeable" version = "0.1.2" @@ -6153,7 +5878,7 @@ dependencies = [ "log 0.4.11", "merkle_proof", "rand 0.7.3", - "rand_xorshift 0.2.0", + "rand_xorshift", "rayon", "rusqlite", "safe_arith", @@ -6321,18 +6046,6 @@ dependencies = [ "percent-encoding 2.1.0", ] -[[package]] -name = "urlencoding" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9232eb53352b4442e40d7900465dfc534e8cb2dc8f18656fcb2ac16112b5593" - -[[package]] -name = "utf-8" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05e42f7c18b8f902290b009cde6d651262f956c98bc51bca4cd1d511c9cd85c7" - [[package]] name = "uuid" version = "0.8.1" @@ -6462,34 +6175,6 @@ dependencies = [ "try-lock", ] -[[package]] -name = "warp" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df341dee97c9ae29dfa5e0b0fbbbf620e0d6a36686389bedf83b3daeb8b0d0ac" -dependencies = [ - "bytes 0.5.6", - "futures 0.3.5", - "headers", - "http 0.2.1", - "hyper 0.13.7", - "log 0.4.11", - "mime 0.3.16", - "mime_guess 2.0.3", - "multipart", - "pin-project", - "scoped-tls 1.0.0", - "serde", - "serde_json", - "serde_urlencoded", - "tokio 0.2.22", - "tokio-tungstenite", - "tower-service", - "tracing", - "tracing-futures", - "urlencoding", -] - [[package]] name = "wasi" version = "0.9.0+wasi-snapshot-preview1" diff --git a/Cargo.toml b/Cargo.toml index 449c18806da..044b6d2f818 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -26,6 +26,7 @@ members = [ "common/eth2_testnet_config", "common/eth2_wallet_manager", "common/hashset_delay", + "common/http_api_common", "common/lighthouse_metrics", "common/lighthouse_version", "common/logging", diff --git a/beacon_node/beacon_chain/src/beacon_chain.rs b/beacon_node/beacon_chain/src/beacon_chain.rs index 40a441a2d79..c6b81cea39f 100644 --- a/beacon_node/beacon_chain/src/beacon_chain.rs +++ b/beacon_node/beacon_chain/src/beacon_chain.rs @@ -519,6 +519,20 @@ impl BeaconChain { f(&head_lock) } + /// Returns the beacon block at the head of the canonical chain. + /// + /// See `Self::head` for more information. + pub fn head_beacon_block(&self) -> Result, Error> { + self.with_head(|s| s.beacon_block.clone()) + } + + /// Returns the beacon state at the head of the canonical chain. + /// + /// See `Self::head` for more information. + pub fn head_beacon_state(&self) -> Result, Error> { + self.with_head(|s| s.beacon_state.clone()) + } + /// Returns info representing the head block and state. /// /// A summarized version of `Self::head` that involves less cloning. diff --git a/beacon_node/http_api/Cargo.toml b/beacon_node/http_api/Cargo.toml index cb21078ba03..ed83f1919a1 100644 --- a/beacon_node/http_api/Cargo.toml +++ b/beacon_node/http_api/Cargo.toml @@ -14,3 +14,4 @@ parking_lot = "0.11.0" types = { path = "../../consensus/types" } hex = "0.4.2" beacon_chain = { path = "../beacon_chain" } +http_api_common = { path = "../../common/http_api_common" } diff --git a/beacon_node/http_api/src/block_id.rs b/beacon_node/http_api/src/block_id.rs index 401f8f1d059..74e3cdfbc28 100644 --- a/beacon_node/http_api/src/block_id.rs +++ b/beacon_node/http_api/src/block_id.rs @@ -1,6 +1,6 @@ use beacon_chain::{BeaconChain, BeaconChainTypes}; use std::str::FromStr; -use types::{Hash256, Slot}; +use types::{Hash256, SignedBeaconBlock, Slot}; #[derive(Debug)] pub enum BlockId { @@ -38,6 +38,25 @@ impl BlockId { BlockId::Root(root) => Ok(*root), } } + + pub fn block( + &self, + chain: &BeaconChain, + ) -> Result, warp::Rejection> { + let block_root = match self { + BlockId::Head => { + return chain + .head_beacon_block() + .map_err(crate::reject::beacon_chain_error) + } + other => other.root(chain), + }?; + + chain + .get_block(&block_root) + .map_err(crate::reject::beacon_chain_error) + .and_then(|root_opt| root_opt.ok_or_else(|| warp::reject::not_found())) + } } impl FromStr for BlockId { diff --git a/beacon_node/http_api/src/lib.rs b/beacon_node/http_api/src/lib.rs index f2e0eb7785c..74807b0b636 100644 --- a/beacon_node/http_api/src/lib.rs +++ b/beacon_node/http_api/src/lib.rs @@ -4,6 +4,8 @@ mod state_id; use beacon_chain::{BeaconChain, BeaconChainTypes}; use block_id::BlockId; +use http_api_common as api; +use serde::Serialize; use state_id::StateId; use std::sync::Arc; use warp::Filter; @@ -40,16 +42,39 @@ pub async fn serve(ctx: Arc>) { .clone() .and(warp::path("root")) .and(warp::path::end()) - .and_then(|state_id: StateId, chain: Arc>| async move { - state_id.root(&chain).map(|resp| warp::reply::json(&resp)) + .and_then(|state_id: StateId, chain: Arc>| { + blocking_json_task(move || { + state_id + .root(&chain) + .map(api::RootData::from) + .map(api::GenericResponse::from) + }) }); let beacon_state_fork = beacon_states_path .clone() .and(warp::path("fork")) .and(warp::path::end()) - .and_then(|state_id: StateId, chain: Arc>| async move { - state_id.root(&chain).map(|resp| warp::reply::json(&resp)) + .and_then(|state_id: StateId, chain: Arc>| { + blocking_json_task(move || state_id.fork(&chain).map(api::GenericResponse::from)) + }); + + let beacon_state_finality_checkpoints = beacon_states_path + .clone() + .and(warp::path("finality_checkpoints")) + .and(warp::path::end()) + .and_then(|state_id: StateId, chain: Arc>| { + blocking_json_task(move || { + state_id + .map_state(&chain, |state| { + Ok(api::FinalityCheckpointsData { + previous_justified: state.previous_justified_checkpoint, + current_justified: state.current_justified_checkpoint, + finalized: state.finalized_checkpoint, + }) + }) + .map(api::GenericResponse::from) + }) }); /* @@ -66,13 +91,36 @@ pub async fn serve(ctx: Arc>) { .clone() .and(warp::path("root")) .and(warp::path::end()) - .and_then(|block_id: BlockId, chain: Arc>| async move { - block_id.root(&chain).map(|resp| warp::reply::json(&resp)) + .and_then(|block_id: BlockId, chain: Arc>| { + blocking_json_task(move || { + block_id + .root(&chain) + .map(api::RootData::from) + .map(api::GenericResponse::from) + }) }); let routes = beacon_state_root .or(beacon_state_fork) + .or(beacon_state_finality_checkpoints) .or(beacon_block_root); warp::serve(routes).run(([127, 0, 0, 1], 3030)).await; } + +async fn blocking_task(func: F) -> T +where + F: Fn() -> T, +{ + tokio::task::block_in_place(func) +} + +async fn blocking_json_task(func: F) -> Result +where + F: Fn() -> Result, + T: Serialize, +{ + blocking_task(func) + .await + .map(|resp| warp::reply::json(&resp)) +} diff --git a/beacon_node/http_api/src/state_id.rs b/beacon_node/http_api/src/state_id.rs index b1553cc3849..580a4086a7e 100644 --- a/beacon_node/http_api/src/state_id.rs +++ b/beacon_node/http_api/src/state_id.rs @@ -1,6 +1,7 @@ +use crate::BlockId; use beacon_chain::{BeaconChain, BeaconChainTypes}; use std::str::FromStr; -use types::{Hash256, Slot}; +use types::{BeaconState, Fork, Hash256, Slot}; #[derive(Debug)] pub enum StateId { @@ -17,17 +18,68 @@ impl StateId { &self, chain: &BeaconChain, ) -> Result { - match self { - StateId::Head => chain - .head_info() - .map(|head| head.state_root) - .map_err(crate::reject::beacon_chain_error), - StateId::Genesis => Ok(chain.genesis_state_root), - StateId::Finalized => todo!(), - StateId::Justified => todo!(), - StateId::Slot(_) => todo!(), - StateId::Root(root) => Ok(*root), - } + let block = match self { + StateId::Head => { + return chain + .head_info() + .map(|head| head.state_root) + .map_err(crate::reject::beacon_chain_error) + } + StateId::Genesis => return Ok(chain.genesis_state_root), + StateId::Finalized => BlockId::Finalized.block(chain), + StateId::Justified => BlockId::Justified.block(chain), + StateId::Slot(slot) => BlockId::Slot(*slot).block(chain), + StateId::Root(root) => return Ok(*root), + }?; + + Ok(block.state_root()) + } + + pub fn fork( + &self, + chain: &BeaconChain, + ) -> Result { + self.map_state(chain, |state| Ok(state.fork.clone())) + } + + pub fn state( + &self, + chain: &BeaconChain, + ) -> Result, warp::Rejection> { + let (state_root, slot_opt) = match self { + StateId::Head => { + return chain + .head_beacon_state() + .map_err(crate::reject::beacon_chain_error) + } + StateId::Slot(slot) => (self.root(chain)?, Some(*slot)), + other => (other.root(chain)?, None), + }; + + chain + .get_state(&state_root, slot_opt) + .map_err(crate::reject::beacon_chain_error) + .and_then(|opt| opt.ok_or_else(|| warp::reject::not_found())) + } + + pub fn map_state( + &self, + chain: &BeaconChain, + func: F, + ) -> Result + where + F: Fn(&BeaconState) -> Result, + { + let state = match self { + StateId::Head => { + return chain + .map_head(|snapshot| func(&snapshot.beacon_state)) + .map_err(crate::reject::beacon_chain_error)? + } + other => other.state(chain)?, + }; + + func(&state) } } diff --git a/common/http_api_common/Cargo.toml b/common/http_api_common/Cargo.toml new file mode 100644 index 00000000000..d63e19d8ed8 --- /dev/null +++ b/common/http_api_common/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "http_api_common" +version = "0.1.0" +authors = ["Paul Hauner "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +serde = { version = "1.0.110", features = ["derive"] } +types = { path = "../../consensus/types" } +hex = "0.4.2" diff --git a/common/http_api_common/src/lib.rs b/common/http_api_common/src/lib.rs new file mode 100644 index 00000000000..b1f92ebe541 --- /dev/null +++ b/common/http_api_common/src/lib.rs @@ -0,0 +1,31 @@ +use serde::{Deserialize, Serialize}; +use types::{Checkpoint, Hash256}; + +#[derive(Serialize)] +pub struct GenericResponse { + pub data: T, +} + +impl From for GenericResponse { + fn from(data: T) -> Self { + Self { data } + } +} + +#[derive(Serialize, Deserialize)] +pub struct RootData { + pub root: Hash256, +} + +impl From for RootData { + fn from(root: Hash256) -> Self { + Self { root } + } +} + +#[derive(Serialize, Deserialize)] +pub struct FinalityCheckpointsData { + pub previous_justified: Checkpoint, + pub current_justified: Checkpoint, + pub finalized: Checkpoint, +}