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:
Michael Sproul
2021-07-09 06:15:32 +00:00
parent 89361573d4
commit b4689e20c6
271 changed files with 9652 additions and 8444 deletions

View File

@@ -2,6 +2,7 @@ use crate::metrics;
use eth1::{Config as Eth1Config, Eth1Block, Service as HttpService};
use eth2::lighthouse::Eth1SyncStatusData;
use eth2_hashing::hash;
use int_to_bytes::int_to_bytes32;
use slog::{debug, error, trace, Logger};
use ssz::{Decode, Encode};
use ssz_derive::{Decode, Encode};
@@ -364,7 +365,7 @@ impl<T: EthSpec> Eth1ChainBackend<T> for DummyEth1ChainBackend<T> {
Ok(Eth1Data {
deposit_root: Hash256::from_slice(&deposit_root),
deposit_count: state.eth1_deposit_index,
deposit_count: state.eth1_deposit_index(),
block_hash: Hash256::from_slice(&block_hash),
})
}
@@ -451,9 +452,9 @@ impl<T: EthSpec> CachingEth1Backend<T> {
impl<T: EthSpec> Eth1ChainBackend<T> for CachingEth1Backend<T> {
fn eth1_data(&self, state: &BeaconState<T>, spec: &ChainSpec) -> Result<Eth1Data, Error> {
let period = T::SlotsPerEth1VotingPeriod::to_u64();
let voting_period_start_slot = (state.slot / period) * period;
let voting_period_start_slot = (state.slot() / period) * period;
let voting_period_start_seconds = slot_start_seconds::<T>(
state.genesis_time,
state.genesis_time(),
spec.seconds_per_slot,
voting_period_start_slot,
);
@@ -491,13 +492,13 @@ impl<T: EthSpec> Eth1ChainBackend<T> for CachingEth1Backend<T> {
vote
})
.unwrap_or_else(|| {
let vote = state.eth1_data.clone();
let vote = state.eth1_data().clone();
error!(
self.log,
"No valid eth1_data votes, `votes_to_consider` empty";
"lowest_block_number" => self.core.lowest_block_number(),
"earliest_block_timestamp" => self.core.earliest_block_timestamp(),
"genesis_time" => state.genesis_time,
"genesis_time" => state.genesis_time(),
"outcome" => "casting `state.eth1_data` as eth1 vote"
);
metrics::inc_counter(&metrics::DEFAULT_ETH1_VOTES);
@@ -522,11 +523,11 @@ impl<T: EthSpec> Eth1ChainBackend<T> for CachingEth1Backend<T> {
eth1_data_vote: &Eth1Data,
_spec: &ChainSpec,
) -> Result<Vec<Deposit>, Error> {
let deposit_index = state.eth1_deposit_index;
let deposit_index = state.eth1_deposit_index();
let deposit_count = if let Some(new_eth1_data) = get_new_eth1_data(state, eth1_data_vote)? {
new_eth1_data.deposit_count
} else {
state.eth1_data.deposit_count
state.eth1_data().deposit_count
};
match deposit_index.cmp(&deposit_count) {
@@ -609,7 +610,7 @@ fn collect_valid_votes<T: EthSpec>(
) -> Eth1DataVoteCount {
let mut valid_votes = HashMap::new();
state
.eth1_data_votes
.eth1_data_votes()
.iter()
.filter_map(|vote| {
votes_to_consider
@@ -633,13 +634,6 @@ fn find_winning_vote(valid_votes: Eth1DataVoteCount) -> Option<Eth1Data> {
.map(|((eth1_data, _), _)| eth1_data.clone())
}
/// Returns `int` as little-endian bytes with a length of 32.
fn int_to_bytes32(int: u64) -> Vec<u8> {
let mut vec = int.to_le_bytes().to_vec();
vec.resize(32, 0);
vec
}
/// Returns the unix-epoch seconds at the start of the given `slot`.
fn slot_start_seconds<T: EthSpec>(
genesis_unix_seconds: u64,
@@ -666,7 +660,7 @@ fn is_candidate_block(block: &Eth1Block, period_start: u64, spec: &ChainSpec) ->
mod test {
use super::*;
use environment::null_logger;
use types::{test_utils::DepositTestTask, MinimalEthSpec};
use types::{DepositData, MinimalEthSpec, Signature};
type E = MinimalEthSpec;
@@ -680,9 +674,9 @@ mod test {
fn get_voting_period_start_seconds(state: &BeaconState<E>, spec: &ChainSpec) -> u64 {
let period = <E as EthSpec>::SlotsPerEth1VotingPeriod::to_u64();
let voting_period_start_slot = (state.slot / period) * period;
let voting_period_start_slot = (state.slot() / period) * period;
slot_start_seconds::<E>(
state.genesis_time,
state.genesis_time(),
spec.seconds_per_slot,
voting_period_start_slot,
)
@@ -723,10 +717,7 @@ mod test {
mod eth1_chain_json_backend {
use super::*;
use eth1::DepositLog;
use types::{
test_utils::{generate_deterministic_keypair, TestingDepositBuilder},
EthSpec, MainnetEthSpec,
};
use types::{test_utils::generate_deterministic_keypair, EthSpec, MainnetEthSpec};
fn get_eth1_chain() -> Eth1Chain<CachingEth1Backend<E>, E> {
let eth1_config = Eth1Config {
@@ -743,13 +734,17 @@ mod test {
fn get_deposit_log(i: u64, spec: &ChainSpec) -> DepositLog {
let keypair = generate_deterministic_keypair(i as usize);
let mut builder =
TestingDepositBuilder::new(keypair.pk.clone(), spec.max_effective_balance);
builder.sign(DepositTestTask::Valid, &keypair, spec);
let deposit_data = builder.build().data;
let mut deposit = DepositData {
pubkey: keypair.pk.into(),
withdrawal_credentials: Hash256::zero(),
amount: spec.max_effective_balance,
signature: Signature::empty().into(),
};
deposit.signature = deposit.create_signature(&keypair.sk, &E::default_spec());
DepositLog {
deposit_data,
deposit_data: deposit,
block_number: i,
index: i,
signature_is_valid: true,
@@ -768,8 +763,8 @@ mod test {
);
let mut state: BeaconState<E> = BeaconState::new(0, get_eth1_data(0), &spec);
state.eth1_deposit_index = 0;
state.eth1_data.deposit_count = 0;
*state.eth1_deposit_index_mut() = 0;
state.eth1_data_mut().deposit_count = 0;
assert!(
eth1_chain
@@ -778,7 +773,7 @@ mod test {
"should succeed if cache is empty but no deposits are required"
);
state.eth1_data.deposit_count = 1;
state.eth1_data_mut().deposit_count = 1;
assert!(
eth1_chain
@@ -821,8 +816,8 @@ mod test {
);
let mut state: BeaconState<E> = BeaconState::new(0, get_eth1_data(0), &spec);
state.eth1_deposit_index = 0;
state.eth1_data.deposit_count = 0;
*state.eth1_deposit_index_mut() = 0;
state.eth1_data_mut().deposit_count = 0;
assert!(
eth1_chain
@@ -832,10 +827,10 @@ mod test {
);
(0..3).for_each(|initial_deposit_index| {
state.eth1_deposit_index = initial_deposit_index as u64;
*state.eth1_deposit_index_mut() = initial_deposit_index as u64;
(initial_deposit_index..deposits.len()).for_each(|i| {
state.eth1_data.deposit_count = i as u64;
state.eth1_data_mut().deposit_count = i as u64;
let deposits_for_inclusion = eth1_chain
.deposits_for_block_inclusion(&state, &Eth1Data::default(), spec)
@@ -888,7 +883,8 @@ mod test {
.eth1_data_for_block_production(&state, &spec)
.expect("should produce default eth1 data vote");
assert_eq!(
a, state.eth1_data,
a,
*state.eth1_data(),
"default vote should be same as state.eth1_data"
);
}
@@ -908,7 +904,7 @@ mod test {
let mut state: BeaconState<E> = BeaconState::new(0, get_eth1_data(0), &spec);
state.slot = Slot::from(slots_per_eth1_voting_period * 10);
*state.slot_mut() = Slot::from(slots_per_eth1_voting_period * 10);
let follow_distance_seconds = eth1_follow_distance * spec.seconds_per_eth1_block;
let voting_period_start = get_voting_period_start_seconds(&state, &spec);
let start_eth1_block = voting_period_start - follow_distance_seconds * 2;
@@ -974,8 +970,8 @@ mod test {
let eth1_follow_distance = spec.eth1_follow_distance;
let mut state: BeaconState<E> = BeaconState::new(0, get_eth1_data(0), &spec);
state.genesis_time = 0;
state.slot = Slot::from(slots_per_eth1_voting_period * 10);
*state.genesis_time_mut() = 0;
*state.slot_mut() = Slot::from(slots_per_eth1_voting_period * 10);
let follow_distance_seconds = eth1_follow_distance * spec.seconds_per_eth1_block;
let voting_period_start = get_voting_period_start_seconds(&state, &spec);
@@ -1055,7 +1051,7 @@ mod test {
let votes_to_consider = get_eth1_data_vec(slots, 0);
state.eth1_data_votes = votes_to_consider[0..slots as usize / 4]
*state.eth1_data_votes_mut() = votes_to_consider[0..slots as usize / 4]
.iter()
.map(|(eth1_data, _)| eth1_data)
.cloned()
@@ -1084,7 +1080,7 @@ mod test {
.expect("should have some eth1 data")
.clone();
state.eth1_data_votes = vec![duplicate_eth1_data.clone(); 4]
*state.eth1_data_votes_mut() = vec![duplicate_eth1_data.clone(); 4]
.iter()
.map(|(eth1_data, _)| eth1_data)
.cloned()