Refactor block prod. to produce for forks

This commit is contained in:
Paul Hauner 2019-06-19 03:01:58 +10:00
parent 55196dff64
commit 55818e285a
No known key found for this signature in database
GPG Key ID: 303E4494BB28068C
4 changed files with 100 additions and 36 deletions

View File

@ -23,6 +23,12 @@ use store::{Error as DBError, Store};
use tree_hash::TreeHash;
use types::*;
// Text included in blocks.
// Must be 32-bytes or panic.
//
// |-------must be this long------|
pub const GRAFFITI: &str = "sigp/lighthouse-0.0.0-prerelease";
#[derive(Debug, PartialEq)]
pub enum BlockProcessingOutcome {
/// Block was valid and imported into the block graph.
@ -657,16 +663,41 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
&self,
randao_reveal: Signature,
) -> Result<(BeaconBlock, BeaconState<T::EthSpec>), BlockProductionError> {
debug!("Producing block at slot {}...", self.state.read().slot);
let state = self.state.read().clone();
let slot = self
.read_slot_clock()
.ok_or_else(|| BlockProductionError::UnableToReadSlot)?;
self.produce_block_on_state(state, slot, randao_reveal)
}
/// Produce a block for some `slot` upon the given `state`.
///
/// Typically the `self.produce_block()` function should be used, instead of calling this
/// function directly. This function is useful for purposefully creating forks or blocks at
/// non-current slots.
///
/// The given state will be advanced to the given `produce_at_slot`, then a block will be
/// produced at that slot height.
pub fn produce_block_on_state(
&self,
mut state: BeaconState<T::EthSpec>,
produce_at_slot: Slot,
randao_reveal: Signature,
) -> Result<(BeaconBlock, BeaconState<T::EthSpec>), BlockProductionError> {
self.metrics.block_production_requests.inc();
let timer = self.metrics.block_production_times.start_timer();
let mut state = self.state.read().clone();
// If required, transition the new state to the present slot.
for _ in state.slot.as_u64()..produce_at_slot.as_u64() {
// Ensure the next epoch state caches are built in case of an epoch transition.
state.build_committee_cache(RelativeEpoch::Next, &self.spec)?;
per_slot_processing(&mut state, &self.spec)?;
}
state.build_committee_cache(RelativeEpoch::Current, &self.spec)?;
trace!("Finding attestations for new block...");
let previous_block_root = if state.slot > 0 {
*state
.get_block_root(state.slot - 1)
@ -675,8 +706,11 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
state.latest_block_header.canonical_root()
};
let mut graffiti: [u8; 32] = [0; 32];
graffiti.copy_from_slice(GRAFFITI.as_bytes());
let (proposer_slashings, attester_slashings) =
self.op_pool.get_slashings(&*self.state.read(), &self.spec);
self.op_pool.get_slashings(&state, &self.spec);
let mut block = BeaconBlock {
slot: state.slot,
@ -691,8 +725,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
deposit_root: Hash256::zero(),
block_hash: Hash256::zero(),
},
// TODO: badass Lighthouse graffiti
graffiti: [0; 32],
graffiti,
proposer_slashings,
attester_slashings,
attestations: self

View File

@ -40,9 +40,12 @@ impl From<MetricsError> for BeaconChainError {
#[derive(Debug, PartialEq)]
pub enum BlockProductionError {
UnableToGetBlockRootFromState,
UnableToReadSlot,
SlotProcessingError(SlotProcessingError),
BlockProcessingError(BlockProcessingError),
BeaconStateError(BeaconStateError),
}
easy_from_to!(BlockProcessingError, BlockProductionError);
easy_from_to!(BeaconStateError, BlockProductionError);
easy_from_to!(SlotProcessingError, BlockProductionError);

View File

@ -5,13 +5,20 @@ use slot_clock::TestingSlotClock;
use std::marker::PhantomData;
use std::sync::Arc;
use store::MemoryStore;
use store::Store;
use tree_hash::{SignedRoot, TreeHash};
use types::{
test_utils::TestingBeaconStateBuilder, AggregateSignature, Attestation,
AttestationDataAndCustodyBit, BeaconBlock, Bitfield, ChainSpec, Domain, EthSpec, Hash256,
Keypair, SecretKey, Signature,
AttestationDataAndCustodyBit, BeaconBlock, BeaconState, Bitfield, ChainSpec, Domain, EthSpec,
Hash256, Keypair, RelativeEpoch, SecretKey, Signature, Slot,
};
#[derive(Clone, Copy)]
pub enum BuildStrategy {
OnCanonicalHead,
ForkCanonicalChainAt(Slot),
}
pub struct CommonTypes<L, E>
where
L: LmdGhost<MemoryStore, E>,
@ -82,11 +89,11 @@ where
}
}
pub fn extend_canonical_chain(&self) {
pub fn extend_chain(&self, build_strategy: BuildStrategy) {
self.chain.slot_clock.advance_slot();
self.chain.catchup_state().expect("should catchup state");
let block = self.build_block();
let block = self.build_block(build_strategy);
let outcome = self
.chain
.process_block(block)
@ -96,18 +103,47 @@ where
self.add_attestations_to_op_pool();
}
fn build_block(&self) -> BeaconBlock {
let slot = self.chain.read_slot_clock().unwrap();
fn get_state(&self, build_strategy: BuildStrategy) -> BeaconState<E> {
match build_strategy {
BuildStrategy::OnCanonicalHead => self.chain.current_state().clone(),
BuildStrategy::ForkCanonicalChainAt(fork_slot) => {
let state_root = self
.chain
.rev_iter_state_roots(self.chain.head().beacon_state.slot - 1)
.find(|(_hash, slot)| *slot == fork_slot)
.map(|(hash, _slot)| hash)
.expect("could not find state root for fork");
let sk = {
let proposer = self
.chain
.block_proposer(slot)
.expect("should get block propoer");
&self.keypairs[proposer].sk
self.chain
.store
.get(&state_root)
.expect("should read db")
.expect("should find state root")
}
}
}
fn build_block(&self, build_strategy: BuildStrategy) -> BeaconBlock {
let mut state = self.get_state(build_strategy);
state.build_all_caches(&self.spec).unwrap();
let slot = match build_strategy {
BuildStrategy::OnCanonicalHead => self.chain.read_slot_clock().unwrap(),
BuildStrategy::ForkCanonicalChainAt(slot) => slot,
};
let fork = &self.chain.head().beacon_state.fork;
let proposer_index = match build_strategy {
BuildStrategy::OnCanonicalHead => self
.chain
.block_proposer(slot)
.expect("should get block proposer from chain"),
_ => state
.get_beacon_proposer_index(slot, RelativeEpoch::Current, &self.spec)
.expect("should get block proposer from state"),
};
let sk = &self.keypairs[proposer_index].sk;
let fork = &state.fork.clone();
let randao_reveal = {
let epoch = slot.epoch(E::slots_per_epoch());
@ -118,8 +154,8 @@ where
let (mut block, _state) = self
.chain
.produce_block(randao_reveal)
.expect("should producer block");
.produce_block_on_state(state, slot, randao_reveal)
.expect("should produce block");
block.signature = {
let message = block.signed_root();
@ -195,7 +231,7 @@ where
}
#[cfg(test)]
#[cfg(not(debug_assertions))]
// #[cfg(not(debug_assertions))]
mod test {
use super::*;
use lmd_ghost::ThreadSafeReducedTree;
@ -213,7 +249,7 @@ mod test {
> = BeaconChainHarness::new(VALIDATOR_COUNT);
for _ in 0..num_blocks_produced {
harness.extend_canonical_chain();
harness.extend_chain(BuildStrategy::OnCanonicalHead);
}
let state = &harness.chain.head().beacon_state;

View File

@ -182,7 +182,7 @@ impl<T: BeaconChainTypes> SimpleSync<T> {
&& (!self
.chain
.rev_iter_block_roots(local.best_slot)
.any(|root| root == remote.latest_finalized_root))
.any(|(root, _slot)| root == remote.latest_finalized_root))
&& (local.latest_finalized_root != spec.zero_hash)
&& (remote.latest_finalized_root != spec.zero_hash)
{
@ -266,11 +266,12 @@ impl<T: BeaconChainTypes> SimpleSync<T> {
"start_slot" => req.start_slot,
);
let mut roots: Vec<Hash256> = self
let mut roots: Vec<BlockRootSlot> = self
.chain
.rev_iter_block_roots(req.start_slot + req.count)
.skip(1)
.take(req.count as usize)
.map(|(block_root, slot)| BlockRootSlot { slot, block_root })
.collect();
if roots.len() as u64 != req.count {
@ -285,16 +286,6 @@ impl<T: BeaconChainTypes> SimpleSync<T> {
}
roots.reverse();
let mut roots: Vec<BlockRootSlot> = roots
.iter()
.enumerate()
.map(|(i, block_root)| BlockRootSlot {
slot: req.start_slot + Slot::from(i),
block_root: *block_root,
})
.collect();
roots.dedup_by_key(|brs| brs.block_root);
network.send_rpc_response(
@ -392,6 +383,7 @@ impl<T: BeaconChainTypes> SimpleSync<T> {
.chain
.rev_iter_block_roots(req.start_slot + (count - 1))
.take(count as usize)
.map(|(root, _slot)| root)
.collect();
roots.reverse();