mirror of
https://github.com/sigp/lighthouse.git
synced 2026-05-07 08:52:54 +00:00
Altair consensus changes and refactors (#2279)
## Proposed Changes Implement the consensus changes necessary for the upcoming Altair hard fork. ## Additional Info This is quite a heavy refactor, with pivotal types like the `BeaconState` and `BeaconBlock` changing from structs to enums. This ripples through the whole codebase with field accesses changing to methods, e.g. `state.slot` => `state.slot()`. Co-authored-by: realbigsean <seananderson33@gmail.com>
This commit is contained in:
@@ -6,16 +6,12 @@ edition = "2018"
|
||||
license = "Apache-2.0"
|
||||
description = "Efficient Merkle-hashing as used in Ethereum 2.0"
|
||||
|
||||
[[bench]]
|
||||
name = "benches"
|
||||
harness = false
|
||||
|
||||
[dev-dependencies]
|
||||
criterion = "0.3.3"
|
||||
rand = "0.7.3"
|
||||
tree_hash_derive = "0.2.0"
|
||||
types = { path = "../types" }
|
||||
lazy_static = "1.4.0"
|
||||
beacon_chain = { path = "../../beacon_node/beacon_chain" }
|
||||
|
||||
[dependencies]
|
||||
ethereum-types = "0.9.2"
|
||||
|
||||
@@ -1,96 +0,0 @@
|
||||
#![allow(deprecated)]
|
||||
|
||||
use criterion::Criterion;
|
||||
use criterion::{black_box, criterion_group, criterion_main, Benchmark};
|
||||
use lazy_static::lazy_static;
|
||||
use types::test_utils::{generate_deterministic_keypairs, TestingBeaconStateBuilder};
|
||||
use types::{BeaconState, EthSpec, Keypair, MainnetEthSpec, MinimalEthSpec};
|
||||
|
||||
lazy_static! {
|
||||
static ref KEYPAIRS: Vec<Keypair> = generate_deterministic_keypairs(300_000);
|
||||
}
|
||||
|
||||
fn build_state<T: EthSpec>(validator_count: usize) -> BeaconState<T> {
|
||||
let (state, _keypairs) = TestingBeaconStateBuilder::from_keypairs(
|
||||
KEYPAIRS[0..validator_count].to_vec(),
|
||||
&T::default_spec(),
|
||||
)
|
||||
.build();
|
||||
|
||||
assert_eq!(state.validators.len(), validator_count);
|
||||
assert_eq!(state.balances.len(), validator_count);
|
||||
assert!(state.previous_epoch_attestations.is_empty());
|
||||
assert!(state.current_epoch_attestations.is_empty());
|
||||
assert!(state.eth1_data_votes.is_empty());
|
||||
assert!(state.historical_roots.is_empty());
|
||||
|
||||
state
|
||||
}
|
||||
|
||||
// Note: `state.canonical_root()` uses whatever `tree_hash` that the `types` crate
|
||||
// uses, which is not necessarily this crate. If you want to ensure that types is
|
||||
// using this local version of `tree_hash`, ensure you add a workspace-level
|
||||
// [dependency
|
||||
// patch](https://doc.rust-lang.org/cargo/reference/manifest.html#the-patch-section).
|
||||
fn bench_suite<T: EthSpec>(c: &mut Criterion, spec_desc: &str, validator_count: usize) {
|
||||
let state1 = build_state::<T>(validator_count);
|
||||
let state2 = state1.clone();
|
||||
let mut state3 = state1.clone();
|
||||
state3.update_tree_hash_cache().unwrap();
|
||||
|
||||
c.bench(
|
||||
&format!("{}/{}_validators/no_cache", spec_desc, validator_count),
|
||||
Benchmark::new("genesis_state", move |b| {
|
||||
b.iter_batched_ref(
|
||||
|| state1.clone(),
|
||||
|state| black_box(state.canonical_root()),
|
||||
criterion::BatchSize::SmallInput,
|
||||
)
|
||||
})
|
||||
.sample_size(10),
|
||||
);
|
||||
|
||||
c.bench(
|
||||
&format!("{}/{}_validators/empty_cache", spec_desc, validator_count),
|
||||
Benchmark::new("genesis_state", move |b| {
|
||||
b.iter_batched_ref(
|
||||
|| state2.clone(),
|
||||
|state| {
|
||||
assert!(state.tree_hash_cache.is_none());
|
||||
black_box(state.update_tree_hash_cache().unwrap())
|
||||
},
|
||||
criterion::BatchSize::SmallInput,
|
||||
)
|
||||
})
|
||||
.sample_size(10),
|
||||
);
|
||||
|
||||
c.bench(
|
||||
&format!(
|
||||
"{}/{}_validators/up_to_date_cache",
|
||||
spec_desc, validator_count
|
||||
),
|
||||
Benchmark::new("genesis_state", move |b| {
|
||||
b.iter_batched_ref(
|
||||
|| state3.clone(),
|
||||
|state| {
|
||||
assert!(state.tree_hash_cache.is_some());
|
||||
black_box(state.update_tree_hash_cache().unwrap())
|
||||
},
|
||||
criterion::BatchSize::SmallInput,
|
||||
)
|
||||
})
|
||||
.sample_size(10),
|
||||
);
|
||||
}
|
||||
|
||||
fn all_benches(c: &mut Criterion) {
|
||||
bench_suite::<MinimalEthSpec>(c, "minimal", 100_000);
|
||||
bench_suite::<MinimalEthSpec>(c, "minimal", 300_000);
|
||||
|
||||
bench_suite::<MainnetEthSpec>(c, "mainnet", 100_000);
|
||||
bench_suite::<MainnetEthSpec>(c, "mainnet", 300_000);
|
||||
}
|
||||
|
||||
criterion_group!(benches, all_benches,);
|
||||
criterion_main!(benches);
|
||||
@@ -1,26 +1,46 @@
|
||||
use types::test_utils::TestingBeaconStateBuilder;
|
||||
use beacon_chain::store::StoreConfig;
|
||||
use beacon_chain::test_utils::{BeaconChainHarness, EphemeralHarnessType};
|
||||
use types::{BeaconState, EthSpec, MainnetEthSpec};
|
||||
|
||||
const TREE_HASH_LOOPS: usize = 1_000;
|
||||
const VALIDATOR_COUNT: usize = 1_000;
|
||||
|
||||
fn build_state<T: EthSpec>(validator_count: usize) -> BeaconState<T> {
|
||||
let (state, _keypairs) =
|
||||
TestingBeaconStateBuilder::from_deterministic_keypairs(validator_count, &T::default_spec())
|
||||
.build();
|
||||
fn get_harness<T: EthSpec>() -> BeaconChainHarness<EphemeralHarnessType<T>> {
|
||||
let harness = BeaconChainHarness::new_with_store_config(
|
||||
T::default(),
|
||||
None,
|
||||
types::test_utils::generate_deterministic_keypairs(VALIDATOR_COUNT),
|
||||
StoreConfig::default(),
|
||||
);
|
||||
|
||||
assert_eq!(state.validators.len(), validator_count);
|
||||
assert_eq!(state.balances.len(), validator_count);
|
||||
assert!(state.previous_epoch_attestations.is_empty());
|
||||
assert!(state.current_epoch_attestations.is_empty());
|
||||
assert!(state.eth1_data_votes.is_empty());
|
||||
assert!(state.historical_roots.is_empty());
|
||||
harness.advance_slot();
|
||||
|
||||
harness
|
||||
}
|
||||
|
||||
fn build_state<T: EthSpec>() -> BeaconState<T> {
|
||||
let state = get_harness::<T>().chain.head_beacon_state().unwrap();
|
||||
|
||||
assert_eq!(state.as_base().unwrap().validators.len(), VALIDATOR_COUNT);
|
||||
assert_eq!(state.as_base().unwrap().balances.len(), VALIDATOR_COUNT);
|
||||
assert!(state
|
||||
.as_base()
|
||||
.unwrap()
|
||||
.previous_epoch_attestations
|
||||
.is_empty());
|
||||
assert!(state
|
||||
.as_base()
|
||||
.unwrap()
|
||||
.current_epoch_attestations
|
||||
.is_empty());
|
||||
assert!(state.as_base().unwrap().eth1_data_votes.is_empty());
|
||||
assert!(state.as_base().unwrap().historical_roots.is_empty());
|
||||
|
||||
state
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let state = build_state::<MainnetEthSpec>(VALIDATOR_COUNT);
|
||||
let state = build_state::<MainnetEthSpec>();
|
||||
|
||||
// This vec is an attempt to ensure the compiler doesn't optimize-out the hashing.
|
||||
let mut vec = Vec::with_capacity(TREE_HASH_LOOPS);
|
||||
|
||||
@@ -95,6 +95,28 @@ pub trait TreeHash {
|
||||
fn tree_hash_root(&self) -> Hash256;
|
||||
}
|
||||
|
||||
/// Punch through references.
|
||||
impl<'a, T> TreeHash for &'a T
|
||||
where
|
||||
T: TreeHash,
|
||||
{
|
||||
fn tree_hash_type() -> TreeHashType {
|
||||
T::tree_hash_type()
|
||||
}
|
||||
|
||||
fn tree_hash_packed_encoding(&self) -> Vec<u8> {
|
||||
T::tree_hash_packed_encoding(*self)
|
||||
}
|
||||
|
||||
fn tree_hash_packing_factor() -> usize {
|
||||
T::tree_hash_packing_factor()
|
||||
}
|
||||
|
||||
fn tree_hash_root(&self) -> Hash256 {
|
||||
T::tree_hash_root(*self)
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! tree_hash_ssz_encoding_as_vector {
|
||||
($type: ident) => {
|
||||
|
||||
Reference in New Issue
Block a user