Skip to content

Commit

Permalink
Add scenario for n + 2
Browse files Browse the repository at this point in the history
  • Loading branch information
realbigsean committed May 12, 2022
1 parent 2ae43cd commit 8a5d9f3
Show file tree
Hide file tree
Showing 2 changed files with 151 additions and 6 deletions.
30 changes: 24 additions & 6 deletions beacon_node/beacon_chain/src/test_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,7 @@ use rayon::prelude::*;
use sensitive_url::SensitiveUrl;
use slog::Logger;
use slot_clock::TestingSlotClock;
use state_processing::{
state_advance::{complete_state_advance, partial_state_advance},
StateRootStrategy,
};
use state_processing::{BlockSignatureStrategy, per_block_processing, state_advance::{complete_state_advance, partial_state_advance}, StateRootStrategy, VerifyBlockRoot};
use std::borrow::Cow;
use std::collections::{HashMap, HashSet};
use std::str::FromStr;
Expand Down Expand Up @@ -1244,11 +1241,32 @@ where
assert_ne!(slot, 0, "can't produce a block at slot 0");
assert!(slot >= state.slot());

let (block, state) = self.make_block_return_pre_state(state, slot);
let (block, pre_state) = self.make_block_return_pre_state(state, slot);
let (mut block, _) = block.deconstruct();

let mut state = pre_state.clone();

block_modifier(&mut block);

// Update the state root of the modified block to make sure it remains valid.
let mut signed_block = SignedBeaconBlock::from_block(
block,
// The block is not signed here, that is the task of a validator client.
Signature::empty(),
);

per_block_processing(
&mut state,
&signed_block,
None,
BlockSignatureStrategy::NoVerification,
VerifyBlockRoot::True,
&self.spec,
).unwrap();

signed_block.message_altair_mut().unwrap().state_root = state.canonical_root();
let (mut block, _) = signed_block.deconstruct();

let proposer_index = state.get_beacon_proposer_index(slot, &self.spec).unwrap();

let signed_block = block.sign(
Expand All @@ -1257,7 +1275,7 @@ where
state.genesis_validators_root(),
&self.spec,
);
(signed_block, state)
(signed_block, pre_state)
}

pub fn make_deposits<'a>(
Expand Down
127 changes: 127 additions & 0 deletions beacon_node/beacon_chain/tests/fork_choice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use beacon_chain::{
test_utils::{AttestationStrategy, BeaconChainHarness, BlockStrategy},
WhenSlotSkipped,
};
use eth2::types::typenum::U16;
use types::*;

const VALIDATOR_COUNT: usize = 24;
Expand Down Expand Up @@ -108,3 +109,129 @@ fn chooses_highest_justified_checkpoint() {
"the fork block has not become the head"
);
}

#[test]
fn chooses_highest_justified_checkpoint_n_plus_2() {
let slots_per_epoch = MainnetEthSpec::slots_per_epoch();
let mut spec = MainnetEthSpec::default_spec();
spec.altair_fork_epoch = Some(Epoch::new(0));
let harness = BeaconChainHarness::builder(MainnetEthSpec)
.spec(spec)
.deterministic_keypairs(VALIDATOR_COUNT)
.fresh_ephemeral_store()
.mock_execution_layer()
.build();

harness.advance_slot();

let head = harness.chain.head().unwrap();
assert_eq!(head.beacon_block.slot(), 0, "the chain head is at genesis");
assert_eq!(
head.beacon_state.finalized_checkpoint().epoch,
0,
"there has been no finalization yet"
);

let slot_a = Slot::from(slots_per_epoch * 4 + slots_per_epoch - 1);

// Extend the chain to the slot before `slot_a`
harness.extend_chain(
slot_a.as_usize() - 1,
BlockStrategy::OnCanonicalHead,
AttestationStrategy::AllValidators,
);

// Make slashings to include in the block at `slot_a`.
let head = harness.chain.head().unwrap();
let mut slashings = vec![];
for i in 0..15 {
slashings.push(harness.make_proposer_slashing(i as u64));
}
let (block, pre_state) = harness.make_block_with_modifier(head.beacon_state, slot_a, |block| {
block.body_altair_mut().unwrap().proposer_slashings = VariableList::<ProposerSlashing, U16>::new(slashings).unwrap();
});

// Process the block containing the slashings at the slot before the epoch transition and attest to it.
harness.process_block(slot_a, block).unwrap();
let head = harness.chain.head().unwrap();
let vals = (15..VALIDATOR_COUNT).collect::<Vec<usize>>();
harness.attest_block( &head.beacon_state, head.beacon_state.canonical_root(), SignedBeaconBlockHash::from(head.beacon_block_root), &head.beacon_block, vals.as_slice());

assert_eq!(head.beacon_block.slot(), slot_a);
assert_eq!(
head.beacon_block.slot() % slots_per_epoch,
slots_per_epoch - 1,
"the chain is at the last slot of the epoch"
);

assert_eq!(
head.beacon_state.current_justified_checkpoint().epoch,
3,
"the chain has justified"
);
assert_eq!(
head.beacon_state.finalized_checkpoint().epoch,
2,
"the chain has finalized"
);
let slot_a_root = head.beacon_block_root;

// Advance a full epoch.
for _ in 0..slots_per_epoch {
harness.advance_slot();
}

let reorg_distance = 9;
let fork_parent_slot = slot_a - reorg_distance;
let fork_parent_block = harness
.chain
.block_at_slot(fork_parent_slot, WhenSlotSkipped::None)
.unwrap()
.unwrap();
let fork_parent_state = harness
.chain
.get_state(&fork_parent_block.state_root(), Some(fork_parent_slot))
.unwrap()
.unwrap();
let (fork_block, fork_state) = harness.make_block(fork_parent_state, slot_a + slots_per_epoch);

assert_eq!(
fork_state.current_justified_checkpoint().epoch,
4,
"the fork block has justifed further"
);
assert_eq!(
fork_state.finalized_checkpoint().epoch,
3,
"the fork block has finalized further"
);

let fork_block_root = fork_block.canonical_root();
assert_eq!(
fork_block_root,
harness
.process_block(fork_block.slot(), fork_block)
.unwrap()
.into()
);

{
let fork_choice = harness.chain.fork_choice.read();
let proto_array = fork_choice.proto_array();
assert_eq!(
proto_array.get_weight(&fork_block_root).unwrap(),
0,
"the fork block should have no votes"
);
assert!(
proto_array.get_weight(&slot_a_root).unwrap() > 0,
"the slot_a block should have some votes"
);
}

let head = harness.chain.head().unwrap();
assert_eq!(
head.beacon_block_root, slot_a_root,
"the fork block has not become the head"
);
}

0 comments on commit 8a5d9f3

Please sign in to comment.