Document beacon chain harness
This commit is contained in:
parent
723283bd01
commit
299b4cb207
@ -14,17 +14,25 @@ use types::{
|
|||||||
Hash256, Keypair, RelativeEpoch, SecretKey, Signature, Slot,
|
Hash256, Keypair, RelativeEpoch, SecretKey, Signature, Slot,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// Indicates how the `BeaconChainHarness` should produce blocks.
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub enum BuildStrategy {
|
pub enum BlockStrategy {
|
||||||
|
/// Produce blocks upon the canonical head (normal case).
|
||||||
OnCanonicalHead,
|
OnCanonicalHead,
|
||||||
|
/// Ignore the canonical head and produce blocks upon the block at the given slot.
|
||||||
|
///
|
||||||
|
/// Useful for simulating forks.
|
||||||
ForkCanonicalChainAt(Slot),
|
ForkCanonicalChainAt(Slot),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Indicates how the `BeaconChainHarness` should produce attestations.
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub enum AttestationStrategy {
|
pub enum AttestationStrategy {
|
||||||
|
/// All validators attest to whichever block the `BeaconChainHarness` has produced.
|
||||||
AllValidators,
|
AllValidators,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Used to make the `BeaconChainHarness` generic over some types.
|
||||||
pub struct CommonTypes<L, E>
|
pub struct CommonTypes<L, E>
|
||||||
where
|
where
|
||||||
L: LmdGhost<MemoryStore, E>,
|
L: LmdGhost<MemoryStore, E>,
|
||||||
@ -45,6 +53,8 @@ where
|
|||||||
type EthSpec = E;
|
type EthSpec = E;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A testing harness which can instantiate a `BeaconChain` and populate it with blocks and
|
||||||
|
/// attestations.
|
||||||
pub struct BeaconChainHarness<L, E>
|
pub struct BeaconChainHarness<L, E>
|
||||||
where
|
where
|
||||||
L: LmdGhost<MemoryStore, E>,
|
L: LmdGhost<MemoryStore, E>,
|
||||||
@ -60,6 +70,7 @@ where
|
|||||||
L: LmdGhost<MemoryStore, E>,
|
L: LmdGhost<MemoryStore, E>,
|
||||||
E: EthSpec,
|
E: EthSpec,
|
||||||
{
|
{
|
||||||
|
/// Instantiate a new harness with `validator_count` initial validators.
|
||||||
pub fn new(validator_count: usize) -> Self {
|
pub fn new(validator_count: usize) -> Self {
|
||||||
let spec = E::default_spec();
|
let spec = E::default_spec();
|
||||||
|
|
||||||
@ -95,21 +106,32 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Advance the slot of the `BeaconChain`.
|
||||||
|
///
|
||||||
|
/// Does not produce blocks or attestations.
|
||||||
pub fn advance_slot(&self) {
|
pub fn advance_slot(&self) {
|
||||||
self.chain.slot_clock.advance_slot();
|
self.chain.slot_clock.advance_slot();
|
||||||
self.chain.catchup_state().expect("should catchup state");
|
self.chain.catchup_state().expect("should catchup state");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Extend the `BeaconChain` with some blocks and attestations.
|
||||||
|
///
|
||||||
|
/// Chain will be extended by `num_blocks` blocks.
|
||||||
|
///
|
||||||
|
/// The `block_strategy` dictates where the new blocks will be placed.
|
||||||
|
///
|
||||||
|
/// The `attestation_strategy` dictates which validators will attest to the newly created
|
||||||
|
/// blocks.
|
||||||
pub fn extend_chain(
|
pub fn extend_chain(
|
||||||
&self,
|
&self,
|
||||||
build_strategy: BuildStrategy,
|
num_blocks: usize,
|
||||||
blocks: usize,
|
block_strategy: BlockStrategy,
|
||||||
attestation_strategy: AttestationStrategy,
|
attestation_strategy: AttestationStrategy,
|
||||||
) {
|
) {
|
||||||
// Get an initial state to build the block upon, based on the build strategy.
|
// Get an initial state to build the block upon, based on the build strategy.
|
||||||
let mut state = match build_strategy {
|
let mut state = match block_strategy {
|
||||||
BuildStrategy::OnCanonicalHead => self.chain.current_state().clone(),
|
BlockStrategy::OnCanonicalHead => self.chain.current_state().clone(),
|
||||||
BuildStrategy::ForkCanonicalChainAt(fork_slot) => {
|
BlockStrategy::ForkCanonicalChainAt(fork_slot) => {
|
||||||
let state_root = self
|
let state_root = self
|
||||||
.chain
|
.chain
|
||||||
.rev_iter_state_roots(self.chain.head().beacon_state.slot - 1)
|
.rev_iter_state_roots(self.chain.head().beacon_state.slot - 1)
|
||||||
@ -126,17 +148,17 @@ where
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Get an initial slot to build upon, based on the build strategy.
|
// Get an initial slot to build upon, based on the build strategy.
|
||||||
let mut slot = match build_strategy {
|
let mut slot = match block_strategy {
|
||||||
BuildStrategy::OnCanonicalHead => self.chain.read_slot_clock().unwrap(),
|
BlockStrategy::OnCanonicalHead => self.chain.read_slot_clock().unwrap(),
|
||||||
BuildStrategy::ForkCanonicalChainAt(slot) => slot,
|
BlockStrategy::ForkCanonicalChainAt(slot) => slot,
|
||||||
};
|
};
|
||||||
|
|
||||||
for _ in 0..blocks {
|
for _ in 0..num_blocks {
|
||||||
while self.chain.read_slot_clock().expect("should have a slot") < slot {
|
while self.chain.read_slot_clock().expect("should have a slot") < slot {
|
||||||
self.advance_slot();
|
self.advance_slot();
|
||||||
}
|
}
|
||||||
|
|
||||||
let (block, new_state) = self.build_block(state.clone(), slot, build_strategy);
|
let (block, new_state) = self.build_block(state.clone(), slot, block_strategy);
|
||||||
|
|
||||||
let outcome = self
|
let outcome = self
|
||||||
.chain
|
.chain
|
||||||
@ -159,11 +181,12 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns a newly created block, signed by the proposer for the given slot.
|
||||||
fn build_block(
|
fn build_block(
|
||||||
&self,
|
&self,
|
||||||
mut state: BeaconState<E>,
|
mut state: BeaconState<E>,
|
||||||
slot: Slot,
|
slot: Slot,
|
||||||
build_strategy: BuildStrategy,
|
block_strategy: BlockStrategy,
|
||||||
) -> (BeaconBlock, BeaconState<E>) {
|
) -> (BeaconBlock, BeaconState<E>) {
|
||||||
if slot < state.slot {
|
if slot < state.slot {
|
||||||
panic!("produce slot cannot be prior to the state slot");
|
panic!("produce slot cannot be prior to the state slot");
|
||||||
@ -176,8 +199,8 @@ where
|
|||||||
|
|
||||||
state.build_all_caches(&self.spec).unwrap();
|
state.build_all_caches(&self.spec).unwrap();
|
||||||
|
|
||||||
let proposer_index = match build_strategy {
|
let proposer_index = match block_strategy {
|
||||||
BuildStrategy::OnCanonicalHead => self
|
BlockStrategy::OnCanonicalHead => self
|
||||||
.chain
|
.chain
|
||||||
.block_proposer(slot)
|
.block_proposer(slot)
|
||||||
.expect("should get block proposer from chain"),
|
.expect("should get block proposer from chain"),
|
||||||
@ -211,6 +234,9 @@ where
|
|||||||
(block, state)
|
(block, state)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Adds attestations to the `BeaconChain` operations pool to be included in future blocks.
|
||||||
|
///
|
||||||
|
/// The `attestation_strategy` dictates which validators should attest.
|
||||||
fn add_attestations_to_op_pool(
|
fn add_attestations_to_op_pool(
|
||||||
&self,
|
&self,
|
||||||
attestation_strategy: AttestationStrategy,
|
attestation_strategy: AttestationStrategy,
|
||||||
@ -288,6 +314,7 @@ where
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the secret key for the given validator index.
|
||||||
fn get_sk(&self, validator_index: usize) -> &SecretKey {
|
fn get_sk(&self, validator_index: usize) -> &SecretKey {
|
||||||
&self.keypairs[validator_index].sk
|
&self.keypairs[validator_index].sk
|
||||||
}
|
}
|
||||||
@ -321,8 +348,8 @@ mod test {
|
|||||||
let harness = get_harness(VALIDATOR_COUNT);
|
let harness = get_harness(VALIDATOR_COUNT);
|
||||||
|
|
||||||
harness.extend_chain(
|
harness.extend_chain(
|
||||||
BuildStrategy::OnCanonicalHead,
|
|
||||||
num_blocks_produced as usize,
|
num_blocks_produced as usize,
|
||||||
|
BlockStrategy::OnCanonicalHead,
|
||||||
AttestationStrategy::AllValidators,
|
AttestationStrategy::AllValidators,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user