mirror of
https://github.com/sigp/lighthouse.git
synced 2026-03-10 12:11:59 +00:00
Optimizations, disable val client sync check & additional lcli tools (#834)
* 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 * Fix failing API tests * Address Michael's comments * Add HashMap::from_par_iter
This commit is contained in:
@@ -475,7 +475,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
self.canonical_head
|
||||
.try_read_for(HEAD_LOCK_TIMEOUT)
|
||||
.ok_or_else(|| Error::CanonicalHeadLockTimeout)
|
||||
.map(|v| v.clone())
|
||||
.map(|v| v.clone_with_only_committee_caches())
|
||||
}
|
||||
|
||||
/// Returns info representing the head block and state.
|
||||
|
||||
@@ -41,4 +41,13 @@ impl<E: EthSpec> CheckPoint<E> {
|
||||
self.beacon_state = beacon_state;
|
||||
self.beacon_state_root = beacon_state_root;
|
||||
}
|
||||
|
||||
pub fn clone_with_only_committee_caches(&self) -> Self {
|
||||
Self {
|
||||
beacon_block: self.beacon_block.clone(),
|
||||
beacon_block_root: self.beacon_block_root,
|
||||
beacon_state: self.beacon_state.clone_with_only_committee_caches(),
|
||||
beacon_state_root: self.beacon_state_root,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -198,6 +198,18 @@ lazy_static! {
|
||||
try_create_int_gauge("beacon_head_state_withdrawn_validators_total", "Sum of all validator balances at the head of the chain");
|
||||
pub static ref HEAD_STATE_ETH1_DEPOSIT_INDEX: Result<IntGauge> =
|
||||
try_create_int_gauge("beacon_head_state_eth1_deposit_index", "Eth1 deposit index at the head of the chain");
|
||||
|
||||
/*
|
||||
* Operation Pool
|
||||
*/
|
||||
pub static ref OP_POOL_NUM_ATTESTATIONS: Result<IntGauge> =
|
||||
try_create_int_gauge("beacon_op_pool_attestations_total", "Count of attestations in the op pool");
|
||||
pub static ref OP_POOL_NUM_ATTESTER_SLASHINGS: Result<IntGauge> =
|
||||
try_create_int_gauge("beacon_op_pool_attester_slashings_total", "Count of attester slashings in the op pool");
|
||||
pub static ref OP_POOL_NUM_PROPOSER_SLASHINGS: Result<IntGauge> =
|
||||
try_create_int_gauge("beacon_op_pool_proposer_slashings_total", "Count of proposer slashings in the op pool");
|
||||
pub static ref OP_POOL_NUM_VOLUNTARY_EXITS: Result<IntGauge> =
|
||||
try_create_int_gauge("beacon_op_pool_voluntary_exits_total", "Count of voluntary exits in the op pool");
|
||||
}
|
||||
|
||||
/// Scrape the `beacon_chain` for metrics that are not constantly updated (e.g., the present slot,
|
||||
@@ -206,6 +218,23 @@ pub fn scrape_for_metrics<T: BeaconChainTypes>(beacon_chain: &BeaconChain<T>) {
|
||||
if let Ok(head) = beacon_chain.head() {
|
||||
scrape_head_state::<T>(&head.beacon_state, head.beacon_state_root)
|
||||
}
|
||||
|
||||
set_gauge_by_usize(
|
||||
&OP_POOL_NUM_ATTESTATIONS,
|
||||
beacon_chain.op_pool.num_attestations(),
|
||||
);
|
||||
set_gauge_by_usize(
|
||||
&OP_POOL_NUM_ATTESTER_SLASHINGS,
|
||||
beacon_chain.op_pool.num_attester_slashings(),
|
||||
);
|
||||
set_gauge_by_usize(
|
||||
&OP_POOL_NUM_PROPOSER_SLASHINGS,
|
||||
beacon_chain.op_pool.num_proposer_slashings(),
|
||||
);
|
||||
set_gauge_by_usize(
|
||||
&OP_POOL_NUM_VOLUNTARY_EXITS,
|
||||
beacon_chain.op_pool.num_voluntary_exits(),
|
||||
);
|
||||
}
|
||||
|
||||
/// Scrape the given `state` assuming it's the head state, updating the `DEFAULT_REGISTRY`.
|
||||
|
||||
@@ -70,14 +70,14 @@ pub fn spawn_notifier<T: BeaconChainTypes>(
|
||||
usize::max_value()
|
||||
};
|
||||
|
||||
let head = beacon_chain.head()
|
||||
let head_info = beacon_chain.head_info()
|
||||
.map_err(|e| error!(
|
||||
log,
|
||||
"Failed to get beacon chain head";
|
||||
"Failed to get beacon chain head info";
|
||||
"error" => format!("{:?}", e)
|
||||
))?;
|
||||
|
||||
let head_slot = head.beacon_block.slot;
|
||||
let head_slot = head_info.slot;
|
||||
let head_epoch = head_slot.epoch(T::EthSpec::slots_per_epoch());
|
||||
let current_slot = beacon_chain.slot().map_err(|e| {
|
||||
error!(
|
||||
@@ -87,9 +87,9 @@ pub fn spawn_notifier<T: BeaconChainTypes>(
|
||||
)
|
||||
})?;
|
||||
let current_epoch = current_slot.epoch(T::EthSpec::slots_per_epoch());
|
||||
let finalized_epoch = head.beacon_state.finalized_checkpoint.epoch;
|
||||
let finalized_root = head.beacon_state.finalized_checkpoint.root;
|
||||
let head_root = head.beacon_block_root;
|
||||
let finalized_epoch = head_info.finalized_checkpoint.epoch;
|
||||
let finalized_root = head_info.finalized_checkpoint.root;
|
||||
let head_root = head_info.block_root;
|
||||
|
||||
let mut speedo = speedo.lock();
|
||||
speedo.observe(head_slot, Instant::now());
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use crate::DepositLog;
|
||||
use eth2_hashing::hash;
|
||||
use ssz_derive::{Decode, Encode};
|
||||
use state_processing::common::DepositDataTree;
|
||||
use std::cmp::Ordering;
|
||||
use tree_hash::TreeHash;
|
||||
use types::{Deposit, Hash256, DEPOSIT_TREE_DEPTH};
|
||||
@@ -31,56 +31,6 @@ pub enum Error {
|
||||
InternalError(String),
|
||||
}
|
||||
|
||||
/// Emulates the eth1 deposit contract merkle tree.
|
||||
pub struct DepositDataTree {
|
||||
tree: merkle_proof::MerkleTree,
|
||||
mix_in_length: usize,
|
||||
depth: usize,
|
||||
}
|
||||
|
||||
impl DepositDataTree {
|
||||
/// Create a new Merkle tree from a list of leaves (`DepositData::tree_hash_root`) and a fixed depth.
|
||||
pub fn create(leaves: &[Hash256], mix_in_length: usize, depth: usize) -> Self {
|
||||
Self {
|
||||
tree: merkle_proof::MerkleTree::create(leaves, depth),
|
||||
mix_in_length,
|
||||
depth,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns 32 bytes representing the "mix in length" for the merkle root of this tree.
|
||||
fn length_bytes(&self) -> Vec<u8> {
|
||||
int_to_bytes32(self.mix_in_length)
|
||||
}
|
||||
|
||||
/// Retrieve the root hash of this Merkle tree with the length mixed in.
|
||||
pub fn root(&self) -> Hash256 {
|
||||
let mut preimage = [0; 64];
|
||||
preimage[0..32].copy_from_slice(&self.tree.hash()[..]);
|
||||
preimage[32..64].copy_from_slice(&self.length_bytes());
|
||||
Hash256::from_slice(&hash(&preimage))
|
||||
}
|
||||
|
||||
/// Return the leaf at `index` and a Merkle proof of its inclusion.
|
||||
///
|
||||
/// The Merkle proof is in "bottom-up" order, starting with a leaf node
|
||||
/// and moving up the tree. Its length will be exactly equal to `depth + 1`.
|
||||
pub fn generate_proof(&self, index: usize) -> (Hash256, Vec<Hash256>) {
|
||||
let (root, mut proof) = self.tree.generate_proof(index, self.depth);
|
||||
proof.push(Hash256::from_slice(&self.length_bytes()));
|
||||
(root, proof)
|
||||
}
|
||||
|
||||
/// Add a deposit to the merkle tree.
|
||||
pub fn push_leaf(&mut self, leaf: Hash256) -> Result<(), Error> {
|
||||
self.tree
|
||||
.push_leaf(leaf, self.depth)
|
||||
.map_err(Error::DepositTreeError)?;
|
||||
self.mix_in_length += 1;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Encode, Decode, Clone)]
|
||||
pub struct SszDepositCache {
|
||||
logs: Vec<DepositLog>,
|
||||
@@ -202,7 +152,9 @@ impl DepositCache {
|
||||
let deposit = Hash256::from_slice(&log.deposit_data.tree_hash_root());
|
||||
self.leaves.push(deposit);
|
||||
self.logs.push(log);
|
||||
self.deposit_tree.push_leaf(deposit)?;
|
||||
self.deposit_tree
|
||||
.push_leaf(deposit)
|
||||
.map_err(Error::DepositTreeError)?;
|
||||
self.deposit_roots.push(self.deposit_tree.root());
|
||||
Ok(())
|
||||
}
|
||||
@@ -334,13 +286,6 @@ impl DepositCache {
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `int` as little-endian bytes with a length of 32.
|
||||
fn int_to_bytes32(int: usize) -> Vec<u8> {
|
||||
let mut vec = int.to_le_bytes().to_vec();
|
||||
vec.resize(32, 0);
|
||||
vec
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub mod tests {
|
||||
use super::*;
|
||||
|
||||
@@ -34,6 +34,7 @@ slot_clock = { path = "../../eth2/utils/slot_clock" }
|
||||
hex = "0.3"
|
||||
parking_lot = "0.9"
|
||||
futures = "0.1.29"
|
||||
operation_pool = { path = "../../eth2/operation_pool" }
|
||||
|
||||
[dev-dependencies]
|
||||
remote_beacon_node = { path = "../../eth2/utils/remote_beacon_node" }
|
||||
|
||||
@@ -2,6 +2,7 @@ use crate::response_builder::ResponseBuilder;
|
||||
use crate::ApiResult;
|
||||
use beacon_chain::{BeaconChain, BeaconChainTypes};
|
||||
use hyper::{Body, Request};
|
||||
use operation_pool::PersistedOperationPool;
|
||||
use std::sync::Arc;
|
||||
|
||||
/// Returns the `proto_array` fork choice struct, encoded as JSON.
|
||||
@@ -13,3 +14,15 @@ pub fn get_fork_choice<T: BeaconChainTypes>(
|
||||
) -> ApiResult {
|
||||
ResponseBuilder::new(&req)?.body_no_ssz(&*beacon_chain.fork_choice.core_proto_array())
|
||||
}
|
||||
|
||||
/// Returns the `PersistedOperationPool` struct.
|
||||
///
|
||||
/// Useful for debugging or advanced inspection of the stored operations.
|
||||
pub fn get_operation_pool<T: BeaconChainTypes>(
|
||||
req: Request<Body>,
|
||||
beacon_chain: Arc<BeaconChain<T>>,
|
||||
) -> ApiResult {
|
||||
ResponseBuilder::new(&req)?.body(&PersistedOperationPool::from_operation_pool(
|
||||
&beacon_chain.op_pool,
|
||||
))
|
||||
}
|
||||
|
||||
@@ -137,16 +137,10 @@ pub fn state_at_slot<T: BeaconChainTypes>(
|
||||
beacon_chain: &BeaconChain<T>,
|
||||
slot: Slot,
|
||||
) -> Result<(Hash256, BeaconState<T::EthSpec>), ApiError> {
|
||||
let head_state = &beacon_chain.head()?.beacon_state;
|
||||
let head = beacon_chain.head()?;
|
||||
|
||||
if head_state.slot == slot {
|
||||
// The request slot is the same as the best block (head) slot.
|
||||
|
||||
// I'm not sure if this `.clone()` will be optimized out. If not, it seems unnecessary.
|
||||
Ok((
|
||||
beacon_chain.head()?.beacon_state_root,
|
||||
beacon_chain.head()?.beacon_state,
|
||||
))
|
||||
if head.beacon_state.slot == slot {
|
||||
Ok((head.beacon_state_root, head.beacon_state))
|
||||
} else {
|
||||
let root = state_root_at_slot(beacon_chain, slot)?;
|
||||
|
||||
|
||||
@@ -151,6 +151,9 @@ pub fn route<T: BeaconChainTypes>(
|
||||
(&Method::GET, "/advanced/fork_choice") => {
|
||||
into_boxfut(advanced::get_fork_choice::<T>(req, beacon_chain))
|
||||
}
|
||||
(&Method::GET, "/advanced/operation_pool") => {
|
||||
into_boxfut(advanced::get_operation_pool::<T>(req, beacon_chain))
|
||||
}
|
||||
|
||||
(&Method::GET, "/metrics") => into_boxfut(metrics::get_prometheus::<T>(
|
||||
req,
|
||||
|
||||
@@ -156,6 +156,7 @@ fn return_validator_duties<T: BeaconChainTypes>(
|
||||
let relative_epoch = RelativeEpoch::from_epoch(state.current_epoch(), epoch)
|
||||
.map_err(|_| ApiError::ServerError(String::from("Loaded state is in the wrong epoch")))?;
|
||||
|
||||
state.update_pubkey_cache()?;
|
||||
state
|
||||
.build_committee_cache(relative_epoch, &beacon_chain.spec)
|
||||
.map_err(|e| ApiError::ServerError(format!("Unable to build committee cache: {:?}", e)))?;
|
||||
|
||||
@@ -6,7 +6,8 @@ use node_test_rig::{
|
||||
testing_client_config, ClientConfig, ClientGenesis, LocalBeaconNode,
|
||||
};
|
||||
use remote_beacon_node::{
|
||||
Committee, HeadBeaconBlock, PublishStatus, ValidatorDuty, ValidatorResponse,
|
||||
Committee, HeadBeaconBlock, PersistedOperationPool, PublishStatus, ValidatorDuty,
|
||||
ValidatorResponse,
|
||||
};
|
||||
use std::convert::TryInto;
|
||||
use std::sync::Arc;
|
||||
@@ -237,10 +238,12 @@ fn check_duties<T: BeaconChainTypes>(
|
||||
"there should be a duty for each validator"
|
||||
);
|
||||
|
||||
let state = beacon_chain
|
||||
let mut state = beacon_chain
|
||||
.state_at_slot(epoch.start_slot(T::EthSpec::slots_per_epoch()))
|
||||
.expect("should get state at slot");
|
||||
|
||||
state.build_all_caches(spec).expect("should build caches");
|
||||
|
||||
validators
|
||||
.iter()
|
||||
.zip(duties.iter())
|
||||
@@ -816,6 +819,29 @@ fn get_fork_choice() {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn get_operation_pool() {
|
||||
let mut env = build_env();
|
||||
|
||||
let node = build_node(&mut env, testing_client_config());
|
||||
let remote_node = node.remote_node().expect("should produce remote node");
|
||||
|
||||
let result = env
|
||||
.runtime()
|
||||
.block_on(remote_node.http.advanced().get_operation_pool())
|
||||
.expect("should not error when getting fork choice");
|
||||
|
||||
let expected = PersistedOperationPool::from_operation_pool(
|
||||
&node
|
||||
.client
|
||||
.beacon_chain()
|
||||
.expect("node should have chain")
|
||||
.op_pool,
|
||||
);
|
||||
|
||||
assert_eq!(result, expected, "result should be as expected");
|
||||
}
|
||||
|
||||
fn compare_validator_response<T: EthSpec>(
|
||||
state: &BeaconState<T>,
|
||||
response: &ValidatorResponse,
|
||||
|
||||
@@ -377,7 +377,6 @@ fn init_new_client<E: EthSpec>(
|
||||
eth2_testnet_config.deposit_contract_deploy_block;
|
||||
|
||||
client_config.eth1.follow_distance = spec.eth1_follow_distance / 2;
|
||||
client_config.dummy_eth1_backend = false;
|
||||
client_config.eth1.lowest_cached_block_number = client_config
|
||||
.eth1
|
||||
.deposit_contract_deploy_block
|
||||
|
||||
Reference in New Issue
Block a user