mirror of
https://github.com/sigp/lighthouse.git
synced 2026-03-16 19:32:55 +00:00
Add validator changes from validator-to-rest
This commit is contained in:
@@ -2,6 +2,37 @@ use clap::ArgMatches;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::net::Ipv4Addr;
|
||||
|
||||
/// Defines the encoding for the API
|
||||
///
|
||||
/// The validator client can speak to the beacon node in a number of encodings. Currently both JSON
|
||||
/// and YAML are supported.
|
||||
#[derive(Clone, Serialize, Deserialize, Copy)]
|
||||
pub enum ApiEncodingFormat {
|
||||
JSON,
|
||||
YAML,
|
||||
SSZ,
|
||||
}
|
||||
|
||||
impl ApiEncodingFormat {
|
||||
pub fn get_content_type(&self) -> &str {
|
||||
match self {
|
||||
ApiEncodingFormat::JSON => "application/json",
|
||||
ApiEncodingFormat::YAML => "application/yaml",
|
||||
ApiEncodingFormat::SSZ => "application/ssz",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&str> for ApiEncodingFormat {
|
||||
fn from(f: &str) -> ApiEncodingFormat {
|
||||
match f {
|
||||
"application/yaml" => ApiEncodingFormat::YAML,
|
||||
"application/ssz" => ApiEncodingFormat::SSZ,
|
||||
_ => ApiEncodingFormat::JSON,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// HTTP REST API Configuration
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct Config {
|
||||
|
||||
@@ -5,9 +5,9 @@ extern crate lazy_static;
|
||||
extern crate network as client_network;
|
||||
|
||||
mod beacon;
|
||||
mod config;
|
||||
pub mod config;
|
||||
mod error;
|
||||
mod helpers;
|
||||
pub mod helpers;
|
||||
mod metrics;
|
||||
mod network;
|
||||
mod node;
|
||||
@@ -19,6 +19,7 @@ mod validator;
|
||||
use beacon_chain::{BeaconChain, BeaconChainTypes};
|
||||
use client_network::NetworkMessage;
|
||||
use client_network::Service as NetworkService;
|
||||
pub use config::ApiEncodingFormat;
|
||||
use error::{ApiError, ApiResult};
|
||||
use eth2_config::Eth2Config;
|
||||
use futures::future::IntoFuture;
|
||||
@@ -26,8 +27,7 @@ use hyper::rt::Future;
|
||||
use hyper::service::Service;
|
||||
use hyper::{Body, Method, Request, Response, Server};
|
||||
use parking_lot::RwLock;
|
||||
use slog::{info, warn};
|
||||
use std::net::SocketAddr;
|
||||
use slog::{info, o, warn};
|
||||
use std::ops::Deref;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
@@ -35,8 +35,10 @@ use tokio::runtime::TaskExecutor;
|
||||
use tokio::sync::mpsc;
|
||||
use url_query::UrlQuery;
|
||||
|
||||
pub use crate::helpers::parse_pubkey;
|
||||
pub use beacon::{BlockResponse, HeadResponse, StateResponse};
|
||||
pub use config::Config;
|
||||
pub use config::Config as ApiConfig;
|
||||
pub use validator::ValidatorDuty;
|
||||
|
||||
type BoxFut = Box<dyn Future<Item = Response<Body>, Error = ApiError> + Send>;
|
||||
|
||||
@@ -197,14 +199,16 @@ impl<T: BeaconChainTypes> Service for ApiService<T> {
|
||||
}
|
||||
|
||||
pub fn start_server<T: BeaconChainTypes>(
|
||||
config: &Config,
|
||||
config: &ApiConfig,
|
||||
executor: &TaskExecutor,
|
||||
beacon_chain: Arc<BeaconChain<T>>,
|
||||
network_info: NetworkInfo<T>,
|
||||
db_path: PathBuf,
|
||||
eth2_config: Eth2Config,
|
||||
log: slog::Logger,
|
||||
) -> Result<(exit_future::Signal, SocketAddr), hyper::Error> {
|
||||
log: &slog::Logger,
|
||||
) -> Result<exit_future::Signal, hyper::Error> {
|
||||
let log = log.new(o!("Service" => "Api"));
|
||||
|
||||
// build a channel to kill the HTTP server
|
||||
let (exit_signal, exit) = exit_future::signal();
|
||||
|
||||
@@ -236,11 +240,8 @@ pub fn start_server<T: BeaconChainTypes>(
|
||||
};
|
||||
|
||||
let log_clone = log.clone();
|
||||
let server = Server::bind(&bind_addr).serve(service);
|
||||
|
||||
let actual_listen_addr = server.local_addr();
|
||||
|
||||
let server_future = server
|
||||
let server = Server::bind(&bind_addr)
|
||||
.serve(service)
|
||||
.with_graceful_shutdown(server_exit)
|
||||
.map_err(move |e| {
|
||||
warn!(
|
||||
@@ -250,15 +251,15 @@ pub fn start_server<T: BeaconChainTypes>(
|
||||
});
|
||||
|
||||
info!(
|
||||
log,
|
||||
"REST API started";
|
||||
"address" => format!("{}", actual_listen_addr.ip()),
|
||||
"port" => actual_listen_addr.port(),
|
||||
log,
|
||||
"REST API started";
|
||||
"address" => format!("{}", config.listen_address),
|
||||
"port" => config.port,
|
||||
);
|
||||
|
||||
executor.spawn(server_future);
|
||||
executor.spawn(server);
|
||||
|
||||
Ok((exit_signal, actual_listen_addr))
|
||||
Ok(exit_signal)
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
|
||||
@@ -1,47 +1,36 @@
|
||||
use super::{ApiError, ApiResult};
|
||||
use crate::config::ApiEncodingFormat;
|
||||
use http::header;
|
||||
use hyper::{Body, Request, Response, StatusCode};
|
||||
use serde::Serialize;
|
||||
use ssz::Encode;
|
||||
|
||||
pub enum Encoding {
|
||||
JSON,
|
||||
SSZ,
|
||||
YAML,
|
||||
TEXT,
|
||||
}
|
||||
|
||||
pub struct ResponseBuilder {
|
||||
encoding: Encoding,
|
||||
encoding: ApiEncodingFormat,
|
||||
}
|
||||
|
||||
impl ResponseBuilder {
|
||||
pub fn new(req: &Request<Body>) -> Result<Self, ApiError> {
|
||||
let content_header: String = req
|
||||
let accept_header: String = req
|
||||
.headers()
|
||||
.get(header::CONTENT_TYPE)
|
||||
.get(header::ACCEPT)
|
||||
.map_or(Ok(""), |h| h.to_str())
|
||||
.map_err(|e| {
|
||||
ApiError::BadRequest(format!(
|
||||
"The content-type header contains invalid characters: {:?}",
|
||||
"The Accept header contains invalid characters: {:?}",
|
||||
e
|
||||
))
|
||||
})
|
||||
.map(String::from)?;
|
||||
|
||||
// JSON is our default encoding, unless something else is requested.
|
||||
let encoding = match content_header {
|
||||
ref h if h.starts_with("application/ssz") => Encoding::SSZ,
|
||||
ref h if h.starts_with("application/yaml") => Encoding::YAML,
|
||||
ref h if h.starts_with("text/") => Encoding::TEXT,
|
||||
_ => Encoding::JSON,
|
||||
};
|
||||
let encoding = ApiEncodingFormat::from(accept_header.as_str());
|
||||
Ok(Self { encoding })
|
||||
}
|
||||
|
||||
pub fn body<T: Serialize + Encode>(self, item: &T) -> ApiResult {
|
||||
match self.encoding {
|
||||
Encoding::SSZ => Response::builder()
|
||||
ApiEncodingFormat::SSZ => Response::builder()
|
||||
.status(StatusCode::OK)
|
||||
.header("content-type", "application/ssz")
|
||||
.body(Body::from(item.as_ssz_bytes()))
|
||||
@@ -52,7 +41,7 @@ impl ResponseBuilder {
|
||||
|
||||
pub fn body_no_ssz<T: Serialize>(self, item: &T) -> ApiResult {
|
||||
let (body, content_type) = match self.encoding {
|
||||
Encoding::JSON => (
|
||||
ApiEncodingFormat::JSON => (
|
||||
Body::from(serde_json::to_string(&item).map_err(|e| {
|
||||
ApiError::ServerError(format!(
|
||||
"Unable to serialize response body as JSON: {:?}",
|
||||
@@ -61,12 +50,12 @@ impl ResponseBuilder {
|
||||
})?),
|
||||
"application/json",
|
||||
),
|
||||
Encoding::SSZ => {
|
||||
ApiEncodingFormat::SSZ => {
|
||||
return Err(ApiError::UnsupportedType(
|
||||
"Response cannot be encoded as SSZ.".into(),
|
||||
));
|
||||
}
|
||||
Encoding::YAML => (
|
||||
ApiEncodingFormat::YAML => (
|
||||
Body::from(serde_yaml::to_string(&item).map_err(|e| {
|
||||
ApiError::ServerError(format!(
|
||||
"Unable to serialize response body as YAML: {:?}",
|
||||
@@ -75,11 +64,6 @@ impl ResponseBuilder {
|
||||
})?),
|
||||
"application/yaml",
|
||||
),
|
||||
Encoding::TEXT => {
|
||||
return Err(ApiError::UnsupportedType(
|
||||
"Response cannot be encoded as plain text.".into(),
|
||||
));
|
||||
}
|
||||
};
|
||||
|
||||
Response::builder()
|
||||
|
||||
@@ -5,7 +5,7 @@ use crate::helpers::{
|
||||
use crate::response_builder::ResponseBuilder;
|
||||
use crate::{ApiError, ApiResult, BoxFut, UrlQuery};
|
||||
use beacon_chain::{AttestationProcessingOutcome, BeaconChainTypes, BlockProcessingOutcome};
|
||||
use bls::{AggregateSignature, PublicKey, Signature};
|
||||
use bls::{AggregateSignature, PublicKey, Signature, BLS_PUBLIC_KEY_BYTE_SIZE};
|
||||
use futures::future::Future;
|
||||
use futures::stream::Stream;
|
||||
use hyper::{Body, Request};
|
||||
@@ -22,7 +22,7 @@ use types::{Attestation, BeaconBlock, BitList, Epoch, RelativeEpoch, Shard, Slot
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct ValidatorDuty {
|
||||
/// The validator's BLS public key, uniquely identifying them. _48-bytes, hex encoded with 0x prefix, case insensitive._
|
||||
pub validator_pubkey: String,
|
||||
pub validator_pubkey: PublicKey,
|
||||
/// The slot at which the validator must attest.
|
||||
pub attestation_slot: Option<Slot>,
|
||||
/// The shard in which the validator must attest.
|
||||
@@ -34,7 +34,8 @@ pub struct ValidatorDuty {
|
||||
impl ValidatorDuty {
|
||||
pub fn new() -> ValidatorDuty {
|
||||
ValidatorDuty {
|
||||
validator_pubkey: "".to_string(),
|
||||
validator_pubkey: PublicKey::from_bytes(vec![0; BLS_PUBLIC_KEY_BYTE_SIZE].as_slice())
|
||||
.expect("Should always be able to create a 'zero' BLS public key."),
|
||||
attestation_slot: None,
|
||||
attestation_shard: None,
|
||||
block_proposal_slot: None,
|
||||
@@ -103,7 +104,7 @@ pub fn get_validator_duties<T: BeaconChainTypes + 'static>(req: Request<Body>) -
|
||||
// Look up duties for each validator
|
||||
for val_pk in validators {
|
||||
let mut duty = ValidatorDuty::new();
|
||||
duty.validator_pubkey = val_pk.as_hex_string();
|
||||
duty.validator_pubkey = val_pk.clone();
|
||||
|
||||
// Get the validator index
|
||||
// If it does not exist in the index, just add a null duty and move on.
|
||||
@@ -210,14 +211,8 @@ pub fn publish_beacon_block<T: BeaconChainTypes + 'static>(req: Request<Body>) -
|
||||
Box::new(body
|
||||
.concat2()
|
||||
.map_err(|e| ApiError::ServerError(format!("Unable to get request body: {:?}",e)))
|
||||
.map(|chunk| chunk.iter().cloned().collect::<Vec<u8>>())
|
||||
.and_then(|chunks| {
|
||||
serde_json::from_slice(&chunks.as_slice()).map_err(|e| {
|
||||
ApiError::BadRequest(format!(
|
||||
"Unable to deserialize JSON into a BeaconBlock: {:?}",
|
||||
e
|
||||
))
|
||||
})
|
||||
serde_json::from_slice(&chunks).map_err(|e| ApiError::BadRequest(format!("Unable to parse JSON into BeaconBlock: {:?}",e)))
|
||||
})
|
||||
.and_then(move |block: BeaconBlock<T::EthSpec>| {
|
||||
let slot = block.slot;
|
||||
|
||||
Reference in New Issue
Block a user