mirror of
https://github.com/sigp/lighthouse.git
synced 2026-03-06 18:21:45 +00:00
Faster attestation production (#838)
* Start adding interop genesis state to lcli * Use more efficient method to generate genesis state * Remove duplicate int_to_bytes32 * Add lcli command to change state genesis time * Add option to allow VC to start with unsynced BN * Set VC to do parallel key loading * Don't default to dummy eth1 backend * Add endpoint to dump operation pool * Add metrics for op pool * Remove state clone for slot notifier * Add mem size approximation for tree hash cache * Avoid cloning tree hash when getting head * Avoid cloning tree hash when getting head * Add working arena-based cached tree hash * Add another benchmark * Add pre-allocation for caches * Make cache nullable * Fix bugs in cache tree hash * Add validator tree hash optimization * Optimize hash_concat * Make hash32_concat return fixed-len array * Fix failing API tests * Add new beacon state cache struct * Add validator-specific cache * Separate list and values arenas * Add parallel validator registry hashing * Remove MultiTreeHashCache * Remove cached tree hash macro * Fix failing tree hash test * Address Michael's comments * Add CachedTreeHash impl for ef tests * Fix messy merge conflict * Optimize attestation production * Add first basic optimizations * Fix SlotOutOfBounds error * Resolved missed merge conflicts * Fix another missed merge conflict * Fix more merge conflict issues * Add `StateSkipConfig` * Fix test compile errors * Add failing test * Fix bug, make tests pass * Add comment * Delete unused function * Replace deleted comment
This commit is contained in:
@@ -2,7 +2,7 @@ use crate::helpers::*;
|
||||
use crate::response_builder::ResponseBuilder;
|
||||
use crate::validator::get_state_for_epoch;
|
||||
use crate::{ApiError, ApiResult, BoxFut, UrlQuery};
|
||||
use beacon_chain::{BeaconChain, BeaconChainTypes};
|
||||
use beacon_chain::{BeaconChain, BeaconChainTypes, StateSkipConfig};
|
||||
use futures::{Future, Stream};
|
||||
use hyper::{Body, Request};
|
||||
use serde::{Deserialize, Serialize};
|
||||
@@ -381,7 +381,7 @@ pub fn get_committees<T: BeaconChainTypes>(
|
||||
|
||||
let epoch = query.epoch()?;
|
||||
|
||||
let mut state = get_state_for_epoch(&beacon_chain, epoch)?;
|
||||
let mut state = get_state_for_epoch(&beacon_chain, epoch, StateSkipConfig::WithoutStateRoots)?;
|
||||
|
||||
let relative_epoch = RelativeEpoch::from_epoch(state.current_epoch(), epoch).map_err(|e| {
|
||||
ApiError::ServerError(format!("Failed to get state suitable for epoch: {:?}", e))
|
||||
@@ -471,7 +471,7 @@ pub fn get_state_root<T: BeaconChainTypes>(
|
||||
let slot_string = UrlQuery::from_request(&req)?.only_one("slot")?;
|
||||
let slot = parse_slot(&slot_string)?;
|
||||
|
||||
let root = state_root_at_slot(&beacon_chain, slot)?;
|
||||
let root = state_root_at_slot(&beacon_chain, slot, StateSkipConfig::WithStateRoots)?;
|
||||
|
||||
ResponseBuilder::new(&req)?.body(&root)
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use crate::{ApiError, ApiResult};
|
||||
use beacon_chain::{BeaconChain, BeaconChainTypes};
|
||||
use beacon_chain::{BeaconChain, BeaconChainTypes, StateSkipConfig};
|
||||
use bls::PublicKeyBytes;
|
||||
use eth2_libp2p::GossipTopic;
|
||||
use eth2_libp2p::PubsubMessage;
|
||||
@@ -142,7 +142,7 @@ pub fn state_at_slot<T: BeaconChainTypes>(
|
||||
if head.beacon_state.slot == slot {
|
||||
Ok((head.beacon_state_root, head.beacon_state))
|
||||
} else {
|
||||
let root = state_root_at_slot(beacon_chain, slot)?;
|
||||
let root = state_root_at_slot(beacon_chain, slot, StateSkipConfig::WithStateRoots)?;
|
||||
|
||||
let state: BeaconState<T::EthSpec> = beacon_chain
|
||||
.store
|
||||
@@ -161,6 +161,7 @@ pub fn state_at_slot<T: BeaconChainTypes>(
|
||||
pub fn state_root_at_slot<T: BeaconChainTypes>(
|
||||
beacon_chain: &BeaconChain<T>,
|
||||
slot: Slot,
|
||||
config: StateSkipConfig,
|
||||
) -> Result<Hash256, ApiError> {
|
||||
let head_state = &beacon_chain.head()?.beacon_state;
|
||||
let current_slot = beacon_chain
|
||||
@@ -206,11 +207,16 @@ pub fn state_root_at_slot<T: BeaconChainTypes>(
|
||||
let mut state = beacon_chain.head()?.beacon_state;
|
||||
let spec = &T::EthSpec::default_spec();
|
||||
|
||||
let skip_state_root = match config {
|
||||
StateSkipConfig::WithStateRoots => None,
|
||||
StateSkipConfig::WithoutStateRoots => Some(Hash256::zero()),
|
||||
};
|
||||
|
||||
for _ in state.slot.as_u64()..slot.as_u64() {
|
||||
// Ensure the next epoch state caches are built in case of an epoch transition.
|
||||
state.build_committee_cache(RelativeEpoch::Next, spec)?;
|
||||
|
||||
state_processing::per_slot_processing(&mut state, None, spec)?;
|
||||
state_processing::per_slot_processing(&mut state, skip_state_root, spec)?;
|
||||
}
|
||||
|
||||
// Note: this is an expensive operation. Once the tree hash cache is implement it may be
|
||||
|
||||
@@ -21,6 +21,21 @@ lazy_static! {
|
||||
"http_server_success_total",
|
||||
"Total count of HTTP 200 responses sent"
|
||||
);
|
||||
pub static ref VALIDATOR_GET_BLOCK_REQUEST_RESPONSE_TIME: Result<Histogram> =
|
||||
try_create_histogram(
|
||||
"http_server_validator_block_get_request_duration_seconds",
|
||||
"Time taken to respond to GET /validator/block"
|
||||
);
|
||||
pub static ref VALIDATOR_GET_ATTESTATION_REQUEST_RESPONSE_TIME: Result<Histogram> =
|
||||
try_create_histogram(
|
||||
"http_server_validator_attestation_get_request_duration_seconds",
|
||||
"Time taken to respond to GET /validator/attestation"
|
||||
);
|
||||
pub static ref VALIDATOR_GET_DUTIES_REQUEST_RESPONSE_TIME: Result<Histogram> =
|
||||
try_create_histogram(
|
||||
"http_server_validator_duties_get_request_duration_seconds",
|
||||
"Time taken to respond to GET /validator/duties"
|
||||
);
|
||||
}
|
||||
|
||||
/// Returns the full set of Prometheus metrics for the Beacon Node application.
|
||||
|
||||
@@ -10,6 +10,7 @@ use hyper::{Body, Error, Method, Request, Response};
|
||||
use slog::debug;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::Arc;
|
||||
use std::time::Instant;
|
||||
|
||||
fn into_boxfut<F: IntoFuture + 'static>(item: F) -> BoxFut
|
||||
where
|
||||
@@ -33,6 +34,7 @@ pub fn route<T: BeaconChainTypes>(
|
||||
) -> impl Future<Item = Response<Body>, Error = Error> {
|
||||
metrics::inc_counter(&metrics::REQUEST_COUNT);
|
||||
let timer = metrics::start_timer(&metrics::REQUEST_RESPONSE_TIME);
|
||||
let received_instant = Instant::now();
|
||||
|
||||
let path = req.uri().path().to_string();
|
||||
|
||||
@@ -113,7 +115,11 @@ pub fn route<T: BeaconChainTypes>(
|
||||
|
||||
// Methods for Validator
|
||||
(&Method::POST, "/validator/duties") => {
|
||||
validator::post_validator_duties::<T>(req, beacon_chain)
|
||||
let timer =
|
||||
metrics::start_timer(&metrics::VALIDATOR_GET_DUTIES_REQUEST_RESPONSE_TIME);
|
||||
let response = validator::post_validator_duties::<T>(req, beacon_chain);
|
||||
drop(timer);
|
||||
into_boxfut(response)
|
||||
}
|
||||
(&Method::GET, "/validator/duties/all") => {
|
||||
into_boxfut(validator::get_all_validator_duties::<T>(req, beacon_chain))
|
||||
@@ -122,13 +128,21 @@ pub fn route<T: BeaconChainTypes>(
|
||||
validator::get_active_validator_duties::<T>(req, beacon_chain),
|
||||
),
|
||||
(&Method::GET, "/validator/block") => {
|
||||
into_boxfut(validator::get_new_beacon_block::<T>(req, beacon_chain, log))
|
||||
let timer =
|
||||
metrics::start_timer(&metrics::VALIDATOR_GET_BLOCK_REQUEST_RESPONSE_TIME);
|
||||
let response = validator::get_new_beacon_block::<T>(req, beacon_chain, log);
|
||||
drop(timer);
|
||||
into_boxfut(response)
|
||||
}
|
||||
(&Method::POST, "/validator/block") => {
|
||||
validator::publish_beacon_block::<T>(req, beacon_chain, network_channel, log)
|
||||
}
|
||||
(&Method::GET, "/validator/attestation") => {
|
||||
into_boxfut(validator::get_new_attestation::<T>(req, beacon_chain))
|
||||
let timer =
|
||||
metrics::start_timer(&metrics::VALIDATOR_GET_ATTESTATION_REQUEST_RESPONSE_TIME);
|
||||
let response = validator::get_new_attestation::<T>(req, beacon_chain);
|
||||
drop(timer);
|
||||
into_boxfut(response)
|
||||
}
|
||||
(&Method::POST, "/validator/attestation") => {
|
||||
validator::publish_attestation::<T>(req, beacon_chain, network_channel, log)
|
||||
@@ -176,21 +190,34 @@ pub fn route<T: BeaconChainTypes>(
|
||||
// Map the Rust-friendly `Result` in to a http-friendly response. In effect, this ensures that
|
||||
// any `Err` returned from our response handlers becomes a valid http response to the client
|
||||
// (e.g., a response with a 404 or 500 status).
|
||||
request_result.then(move |result| match result {
|
||||
Ok(response) => {
|
||||
debug!(local_log, "HTTP API request successful"; "path" => path);
|
||||
metrics::inc_counter(&metrics::SUCCESS_COUNT);
|
||||
metrics::stop_timer(timer);
|
||||
request_result.then(move |result| {
|
||||
let duration = Instant::now().duration_since(received_instant);
|
||||
match result {
|
||||
Ok(response) => {
|
||||
debug!(
|
||||
local_log,
|
||||
"HTTP API request successful";
|
||||
"path" => path,
|
||||
"duration_ms" => duration.as_millis()
|
||||
);
|
||||
metrics::inc_counter(&metrics::SUCCESS_COUNT);
|
||||
metrics::stop_timer(timer);
|
||||
|
||||
Ok(response)
|
||||
}
|
||||
Err(e) => {
|
||||
let error_response = e.into();
|
||||
Ok(response)
|
||||
}
|
||||
Err(e) => {
|
||||
let error_response = e.into();
|
||||
|
||||
debug!(local_log, "HTTP API request failure"; "path" => path);
|
||||
metrics::stop_timer(timer);
|
||||
debug!(
|
||||
local_log,
|
||||
"HTTP API request failure";
|
||||
"path" => path,
|
||||
"duration_ms" => duration.as_millis()
|
||||
);
|
||||
metrics::stop_timer(timer);
|
||||
|
||||
Ok(error_response)
|
||||
Ok(error_response)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ use crate::response_builder::ResponseBuilder;
|
||||
use crate::{ApiError, ApiResult, BoxFut, NetworkChannel, UrlQuery};
|
||||
use beacon_chain::{
|
||||
AttestationProcessingOutcome, BeaconChain, BeaconChainTypes, BlockProcessingOutcome,
|
||||
StateSkipConfig,
|
||||
};
|
||||
use bls::PublicKeyBytes;
|
||||
use futures::{Future, Stream};
|
||||
@@ -82,7 +83,7 @@ pub fn get_all_validator_duties<T: BeaconChainTypes>(
|
||||
|
||||
let epoch = query.epoch()?;
|
||||
|
||||
let state = get_state_for_epoch(&beacon_chain, epoch)?;
|
||||
let state = get_state_for_epoch(&beacon_chain, epoch, StateSkipConfig::WithoutStateRoots)?;
|
||||
|
||||
let validator_pubkeys = state
|
||||
.validators
|
||||
@@ -104,7 +105,7 @@ pub fn get_active_validator_duties<T: BeaconChainTypes>(
|
||||
|
||||
let epoch = query.epoch()?;
|
||||
|
||||
let state = get_state_for_epoch(&beacon_chain, epoch)?;
|
||||
let state = get_state_for_epoch(&beacon_chain, epoch, StateSkipConfig::WithoutStateRoots)?;
|
||||
|
||||
let validator_pubkeys = state
|
||||
.validators
|
||||
@@ -122,6 +123,7 @@ pub fn get_active_validator_duties<T: BeaconChainTypes>(
|
||||
pub fn get_state_for_epoch<T: BeaconChainTypes>(
|
||||
beacon_chain: &BeaconChain<T>,
|
||||
epoch: Epoch,
|
||||
config: StateSkipConfig,
|
||||
) -> Result<BeaconState<T::EthSpec>, ApiError> {
|
||||
let slots_per_epoch = T::EthSpec::slots_per_epoch();
|
||||
let head_epoch = beacon_chain.head()?.beacon_state.current_epoch();
|
||||
@@ -141,7 +143,7 @@ pub fn get_state_for_epoch<T: BeaconChainTypes>(
|
||||
(epoch + 2).start_slot(slots_per_epoch) - 1
|
||||
};
|
||||
|
||||
beacon_chain.state_at_slot(slot).map_err(|e| {
|
||||
beacon_chain.state_at_slot(slot, config).map_err(|e| {
|
||||
ApiError::ServerError(format!("Unable to load state for epoch {}: {:?}", epoch, e))
|
||||
})
|
||||
}
|
||||
@@ -153,7 +155,7 @@ fn return_validator_duties<T: BeaconChainTypes>(
|
||||
epoch: Epoch,
|
||||
validator_pubkeys: Vec<PublicKeyBytes>,
|
||||
) -> Result<Vec<ValidatorDuty>, ApiError> {
|
||||
let mut state = get_state_for_epoch(&beacon_chain, epoch)?;
|
||||
let mut state = get_state_for_epoch(&beacon_chain, epoch, StateSkipConfig::WithoutStateRoots)?;
|
||||
|
||||
let relative_epoch = RelativeEpoch::from_epoch(state.current_epoch(), epoch)
|
||||
.map_err(|_| ApiError::ServerError(String::from("Loaded state is in the wrong epoch")))?;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#![cfg(test)]
|
||||
|
||||
use beacon_chain::{BeaconChain, BeaconChainTypes};
|
||||
use beacon_chain::{BeaconChain, BeaconChainTypes, StateSkipConfig};
|
||||
use node_test_rig::{
|
||||
environment::{Environment, EnvironmentBuilder},
|
||||
testing_client_config, ClientConfig, ClientGenesis, LocalBeaconNode,
|
||||
@@ -242,7 +242,10 @@ fn check_duties<T: BeaconChainTypes>(
|
||||
);
|
||||
|
||||
let mut state = beacon_chain
|
||||
.state_at_slot(epoch.start_slot(T::EthSpec::slots_per_epoch()))
|
||||
.state_at_slot(
|
||||
epoch.start_slot(T::EthSpec::slots_per_epoch()),
|
||||
StateSkipConfig::WithStateRoots,
|
||||
)
|
||||
.expect("should get state at slot");
|
||||
|
||||
state.build_all_caches(spec).expect("should build caches");
|
||||
@@ -469,7 +472,7 @@ fn beacon_state() {
|
||||
.client
|
||||
.beacon_chain()
|
||||
.expect("client should have beacon chain")
|
||||
.state_at_slot(Slot::new(0))
|
||||
.state_at_slot(Slot::new(0), StateSkipConfig::WithStateRoots)
|
||||
.expect("should find state");
|
||||
db_state.drop_all_caches();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user