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

@@ -1,7 +1,8 @@
use super::*;
use beacon_chain::test_utils::{BeaconChainHarness, EphemeralHarnessType};
use state_processing::{
per_block_processing, per_block_processing::errors::ExitInvalid,
test_utils::BlockProcessingBuilder, BlockProcessingError, BlockSignatureStrategy,
per_block_processing, per_block_processing::errors::ExitInvalid, BlockProcessingError,
BlockSignatureStrategy,
};
use types::{BeaconBlock, BeaconState, Epoch, EthSpec, SignedBeaconBlock};
@@ -14,8 +15,10 @@ struct ExitTest {
validator_index: u64,
exit_epoch: Epoch,
state_epoch: Epoch,
block_modifier: Box<dyn FnOnce(&mut BeaconBlock<E>)>,
builder_modifier: Box<dyn FnOnce(BlockProcessingBuilder<E>) -> BlockProcessingBuilder<E>>,
state_modifier: Box<dyn FnOnce(&mut BeaconState<E>)>,
#[allow(clippy::type_complexity)]
block_modifier:
Box<dyn FnOnce(&BeaconChainHarness<EphemeralHarnessType<E>>, &mut BeaconBlock<E>)>,
#[allow(dead_code)]
expected: Result<(), BlockProcessingError>,
}
@@ -26,8 +29,8 @@ impl Default for ExitTest {
validator_index: VALIDATOR_INDEX,
exit_epoch: STATE_EPOCH,
state_epoch: STATE_EPOCH,
block_modifier: Box::new(|_| ()),
builder_modifier: Box::new(|x| x),
state_modifier: Box::new(|_| ()),
block_modifier: Box::new(|_, _| ()),
expected: Ok(()),
}
}
@@ -35,14 +38,23 @@ impl Default for ExitTest {
impl ExitTest {
fn block_and_pre_state(self) -> (SignedBeaconBlock<E>, BeaconState<E>) {
let spec = &E::default_spec();
let harness = get_harness::<E>(
self.state_epoch.start_slot(E::slots_per_epoch()),
VALIDATOR_COUNT,
);
let mut state = harness.get_current_state();
(self.state_modifier)(&mut state);
(self.builder_modifier)(
get_builder(spec, self.state_epoch.as_u64(), VALIDATOR_COUNT)
.insert_exit(self.validator_index, self.exit_epoch)
.modify(self.block_modifier),
)
.build(None, None)
let block_modifier = self.block_modifier;
let validator_index = self.validator_index;
let exit_epoch = self.exit_epoch;
let (signed_block, state) =
harness.make_block_with_modifier(state.clone(), state.slot() + 1, |block| {
harness.add_voluntary_exit(block, validator_index, exit_epoch);
block_modifier(&harness, block);
});
(signed_block, state)
}
fn process(
@@ -58,7 +70,7 @@ impl ExitTest {
)
}
#[cfg(test)]
#[cfg(all(test, not(debug_assertions)))]
fn run(self) -> BeaconState<E> {
let spec = &E::default_spec();
let expected = self.expected.clone();
@@ -95,23 +107,22 @@ vectors_and_tests!(
// Ensures we can process a valid exit,
valid_single_exit,
ExitTest::default(),
// Tests three exists in the same block.
// Tests three exits in the same block.
valid_three_exits,
ExitTest {
builder_modifier: Box::new(|builder| {
builder
.insert_exit(1, STATE_EPOCH)
.insert_exit(2, STATE_EPOCH)
block_modifier: Box::new(|harness, block| {
harness.add_voluntary_exit(block, 1, STATE_EPOCH);
harness.add_voluntary_exit(block, 2, STATE_EPOCH);
}),
..ExitTest::default()
},
// Ensures that a validator cannot be exited twice in the same block.
invalid_duplicate,
ExitTest {
block_modifier: Box::new(|block| {
block_modifier: Box::new(|_, block| {
// Duplicate the exit
let exit = block.body.voluntary_exits[0].clone();
block.body.voluntary_exits.push(exit).unwrap();
let exit = block.body().voluntary_exits()[0].clone();
block.body_mut().voluntary_exits_mut().push(exit).unwrap();
}),
expected: Err(BlockProcessingError::ExitInvalid {
index: 1,
@@ -128,8 +139,10 @@ vectors_and_tests!(
// ```
invalid_validator_unknown,
ExitTest {
block_modifier: Box::new(|block| {
block.body.voluntary_exits[0].message.validator_index = VALIDATOR_COUNT as u64;
block_modifier: Box::new(|_, block| {
block.body_mut().voluntary_exits_mut()[0]
.message
.validator_index = VALIDATOR_COUNT as u64;
}),
expected: Err(BlockProcessingError::ExitInvalid {
index: 0,
@@ -147,9 +160,8 @@ vectors_and_tests!(
// ```
invalid_exit_already_initiated,
ExitTest {
builder_modifier: Box::new(|mut builder| {
builder.state.validators[0].exit_epoch = STATE_EPOCH + 1;
builder
state_modifier: Box::new(|state| {
state.validators_mut()[0].exit_epoch = STATE_EPOCH + 1;
}),
expected: Err(BlockProcessingError::ExitInvalid {
index: 0,
@@ -167,9 +179,8 @@ vectors_and_tests!(
// ```
invalid_not_active_before_activation_epoch,
ExitTest {
builder_modifier: Box::new(|mut builder| {
builder.state.validators[0].activation_epoch = builder.spec.far_future_epoch;
builder
state_modifier: Box::new(|state| {
state.validators_mut()[0].activation_epoch = E::default_spec().far_future_epoch;
}),
expected: Err(BlockProcessingError::ExitInvalid {
index: 0,
@@ -187,9 +198,8 @@ vectors_and_tests!(
// ```
invalid_not_active_after_exit_epoch,
ExitTest {
builder_modifier: Box::new(|mut builder| {
builder.state.validators[0].exit_epoch = STATE_EPOCH;
builder
state_modifier: Box::new(|state| {
state.validators_mut()[0].exit_epoch = STATE_EPOCH;
}),
expected: Err(BlockProcessingError::ExitInvalid {
index: 0,
@@ -286,10 +296,12 @@ vectors_and_tests!(
// ```
invalid_bad_signature,
ExitTest {
block_modifier: Box::new(|block| {
block_modifier: Box::new(|_, block| {
// Shift the validator index by 1 so that it's mismatched from the key that was
// used to sign.
block.body.voluntary_exits[0].message.validator_index = VALIDATOR_INDEX + 1;
block.body_mut().voluntary_exits_mut()[0]
.message
.validator_index = VALIDATOR_INDEX + 1;
}),
expected: Err(BlockProcessingError::ExitInvalid {
index: 0,
@@ -299,14 +311,14 @@ vectors_and_tests!(
}
);
#[cfg(test)]
#[cfg(all(test, not(debug_assertions)))]
mod custom_tests {
use super::*;
fn assert_exited(state: &BeaconState<E>, validator_index: usize) {
let spec = E::default_spec();
let validator = &state.validators[validator_index];
let validator = &state.validators()[validator_index];
assert_eq!(
validator.exit_epoch,
// This is correct until we exceed the churn limit. If that happens, we
@@ -330,10 +342,9 @@ mod custom_tests {
#[test]
fn valid_three() {
let state = ExitTest {
builder_modifier: Box::new(|builder| {
builder
.insert_exit(1, STATE_EPOCH)
.insert_exit(2, STATE_EPOCH)
block_modifier: Box::new(|harness, block| {
harness.add_voluntary_exit(block, 1, STATE_EPOCH);
harness.add_voluntary_exit(block, 2, STATE_EPOCH);
}),
..ExitTest::default()
}