Add progress on debugging fork choice
This commit is contained in:
parent
5a8cde0598
commit
d0037f49d8
@ -32,7 +32,7 @@ pub const GRAFFITI: &str = "sigp/lighthouse-0.0.0-prerelease";
|
|||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub enum BlockProcessingOutcome {
|
pub enum BlockProcessingOutcome {
|
||||||
/// Block was valid and imported into the block graph.
|
/// Block was valid and imported into the block graph.
|
||||||
Processed,
|
Processed { block_root: Hash256 },
|
||||||
/// The blocks parent_root is unknown.
|
/// The blocks parent_root is unknown.
|
||||||
ParentUnknown { parent: Hash256 },
|
ParentUnknown { parent: Hash256 },
|
||||||
/// The block slot is greater than the present slot.
|
/// The block slot is greater than the present slot.
|
||||||
@ -426,6 +426,12 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
|||||||
|
|
||||||
/// Produce an `AttestationData` that is valid for the present `slot` and given `shard`.
|
/// Produce an `AttestationData` that is valid for the present `slot` and given `shard`.
|
||||||
pub fn produce_attestation_data(&self, shard: u64) -> Result<AttestationData, Error> {
|
pub fn produce_attestation_data(&self, shard: u64) -> Result<AttestationData, Error> {
|
||||||
|
let state = self.state.read();
|
||||||
|
let head_block_root = self.head().beacon_block_root;
|
||||||
|
let head_block_slot = self.head().beacon_block.slot;
|
||||||
|
|
||||||
|
self.produce_attestation_data_for_block(shard, head_block_root, head_block_slot, &*state)
|
||||||
|
/*
|
||||||
let slots_per_epoch = T::EthSpec::slots_per_epoch();
|
let slots_per_epoch = T::EthSpec::slots_per_epoch();
|
||||||
|
|
||||||
self.metrics.attestation_production_requests.inc();
|
self.metrics.attestation_production_requests.inc();
|
||||||
@ -474,6 +480,65 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
|||||||
previous_crosslink_root,
|
previous_crosslink_root,
|
||||||
crosslink_data_root: Hash256::zero(),
|
crosslink_data_root: Hash256::zero(),
|
||||||
})
|
})
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Produce an `AttestationData` that attests to the chain denoted by `block_root` and `state`.
|
||||||
|
pub fn produce_attestation_data_for_block(
|
||||||
|
&self,
|
||||||
|
shard: u64,
|
||||||
|
head_block_root: Hash256,
|
||||||
|
head_block_slot: Slot,
|
||||||
|
state: &BeaconState<T::EthSpec>,
|
||||||
|
) -> Result<AttestationData, Error> {
|
||||||
|
// Collect some metrics.
|
||||||
|
self.metrics.attestation_production_requests.inc();
|
||||||
|
let timer = self.metrics.attestation_production_times.start_timer();
|
||||||
|
|
||||||
|
let slots_per_epoch = T::EthSpec::slots_per_epoch();
|
||||||
|
let current_epoch_start_slot = state.current_epoch().start_slot(slots_per_epoch);
|
||||||
|
|
||||||
|
// The `target_root` is the root of the first block of the current epoch.
|
||||||
|
//
|
||||||
|
// The `state` does not know the root of the block for it's current slot (it only knows
|
||||||
|
// about blocks from prior slots). This creates an edge-case when the state is on the first
|
||||||
|
// slot of the epoch -- we're unable to obtain the `target_root` because it is not a prior
|
||||||
|
// root.
|
||||||
|
//
|
||||||
|
// This edge case is handled in two ways:
|
||||||
|
//
|
||||||
|
// - If the head block is on the same slot as the state, we use it's root.
|
||||||
|
// - Otherwise, assume the current slot has been skipped and use the block root from the
|
||||||
|
// prior slot.
|
||||||
|
//
|
||||||
|
// For all other cases, we simply read the `target_root` from `state.latest_block_roots`.
|
||||||
|
let target_root = if state.slot == current_epoch_start_slot {
|
||||||
|
if head_block_slot == current_epoch_start_slot {
|
||||||
|
head_block_root
|
||||||
|
} else {
|
||||||
|
*state.get_block_root(current_epoch_start_slot - 1)?
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
*state.get_block_root(current_epoch_start_slot)?
|
||||||
|
};
|
||||||
|
|
||||||
|
let previous_crosslink_root =
|
||||||
|
Hash256::from_slice(&state.get_current_crosslink(shard)?.tree_hash_root());
|
||||||
|
|
||||||
|
// Collect some metrics.
|
||||||
|
self.metrics.attestation_production_successes.inc();
|
||||||
|
timer.observe_duration();
|
||||||
|
|
||||||
|
Ok(AttestationData {
|
||||||
|
beacon_block_root: head_block_root,
|
||||||
|
source_epoch: state.current_justified_epoch,
|
||||||
|
source_root: state.current_justified_root,
|
||||||
|
target_epoch: state.current_epoch(),
|
||||||
|
target_root,
|
||||||
|
shard,
|
||||||
|
previous_crosslink_root,
|
||||||
|
crosslink_data_root: Hash256::zero(),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Accept a new attestation from the network.
|
/// Accept a new attestation from the network.
|
||||||
@ -612,9 +677,6 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
|||||||
.get(&parent_state_root)?
|
.get(&parent_state_root)?
|
||||||
.ok_or_else(|| Error::DBInconsistent(format!("Missing state {}", parent_state_root)))?;
|
.ok_or_else(|| Error::DBInconsistent(format!("Missing state {}", parent_state_root)))?;
|
||||||
|
|
||||||
// TODO: check the block proposer signature BEFORE doing a state transition. This will
|
|
||||||
// significantly lower exposure surface to DoS attacks.
|
|
||||||
|
|
||||||
// Transition the parent state to the block slot.
|
// Transition the parent state to the block slot.
|
||||||
let mut state: BeaconState<T::EthSpec> = parent_state;
|
let mut state: BeaconState<T::EthSpec> = parent_state;
|
||||||
for _ in state.slot.as_u64()..block.slot.as_u64() {
|
for _ in state.slot.as_u64()..block.slot.as_u64() {
|
||||||
@ -658,7 +720,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
|||||||
.observe(block.body.attestations.len() as f64);
|
.observe(block.body.attestations.len() as f64);
|
||||||
timer.observe_duration();
|
timer.observe_duration();
|
||||||
|
|
||||||
Ok(BlockProcessingOutcome::Processed)
|
Ok(BlockProcessingOutcome::Processed { block_root })
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Produce a new block at the present slot.
|
/// Produce a new block at the present slot.
|
||||||
@ -695,10 +757,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
|||||||
let timer = self.metrics.block_production_times.start_timer();
|
let timer = self.metrics.block_production_times.start_timer();
|
||||||
|
|
||||||
// If required, transition the new state to the present slot.
|
// If required, transition the new state to the present slot.
|
||||||
for _ in state.slot.as_u64()..produce_at_slot.as_u64() {
|
while state.slot < produce_at_slot {
|
||||||
// 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)?;
|
per_slot_processing(&mut state, &self.spec)?;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -711,6 +770,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
|||||||
} else {
|
} else {
|
||||||
state.latest_block_header.canonical_root()
|
state.latest_block_header.canonical_root()
|
||||||
};
|
};
|
||||||
|
dbg!(previous_block_root);
|
||||||
|
|
||||||
let mut graffiti: [u8; 32] = [0; 32];
|
let mut graffiti: [u8; 32] = [0; 32];
|
||||||
graffiti.copy_from_slice(GRAFFITI.as_bytes());
|
graffiti.copy_from_slice(GRAFFITI.as_bytes());
|
||||||
@ -754,6 +814,8 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
|||||||
self.metrics.block_production_successes.inc();
|
self.metrics.block_production_successes.inc();
|
||||||
timer.observe_duration();
|
timer.observe_duration();
|
||||||
|
|
||||||
|
dbg!(block.canonical_root());
|
||||||
|
|
||||||
Ok((block, state))
|
Ok((block, state))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -787,6 +849,9 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
|||||||
|
|
||||||
// If we switched to a new chain (instead of building atop the present chain).
|
// If we switched to a new chain (instead of building atop the present chain).
|
||||||
if self.head().beacon_block_root != beacon_block.previous_block_root {
|
if self.head().beacon_block_root != beacon_block.previous_block_root {
|
||||||
|
dbg!("switched head");
|
||||||
|
dbg!(self.head().beacon_block.slot);
|
||||||
|
dbg!(beacon_block.slot);
|
||||||
self.metrics.fork_choice_reorg_count.inc();
|
self.metrics.fork_choice_reorg_count.inc();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -131,15 +131,19 @@ where
|
|||||||
let outcome = self
|
let outcome = self
|
||||||
.chain
|
.chain
|
||||||
.process_block(block)
|
.process_block(block)
|
||||||
.expect("should process block");
|
.expect("should not error during block processing");
|
||||||
|
|
||||||
assert_eq!(outcome, BlockProcessingOutcome::Processed);
|
if let BlockProcessingOutcome::Processed { block_root } = outcome {
|
||||||
|
//
|
||||||
|
} else {
|
||||||
|
panic!("block should be successfully processed");
|
||||||
|
}
|
||||||
|
|
||||||
|
self.add_attestations_to_op_pool();
|
||||||
|
|
||||||
state = new_state;
|
state = new_state;
|
||||||
slot += 1;
|
slot += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.add_attestations_to_op_pool();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_block(
|
fn build_block(
|
||||||
@ -152,41 +156,13 @@ where
|
|||||||
panic!("produce slot cannot be prior to the state slot");
|
panic!("produce slot cannot be prior to the state slot");
|
||||||
}
|
}
|
||||||
|
|
||||||
for _ in 0..slot.as_u64() - state.slot.as_u64() {
|
while state.slot < slot {
|
||||||
// Ensure the next epoch state caches are built in case of an epoch transition.
|
|
||||||
state
|
|
||||||
.build_committee_cache(RelativeEpoch::Next, &self.spec)
|
|
||||||
.expect("should be able to build caches");
|
|
||||||
|
|
||||||
per_slot_processing(&mut state, &self.spec)
|
per_slot_processing(&mut state, &self.spec)
|
||||||
.expect("should be able to advance state to slot");
|
.expect("should be able to advance state to slot");
|
||||||
}
|
}
|
||||||
|
|
||||||
state.drop_all_caches();
|
|
||||||
state.build_all_caches(&self.spec).unwrap();
|
state.build_all_caches(&self.spec).unwrap();
|
||||||
|
|
||||||
// dbg!(slot);
|
|
||||||
// dbg!(state.generate_seed(state.current_epoch(), &self.spec));
|
|
||||||
dbg!(state.generate_seed(state.next_epoch(), &self.spec));
|
|
||||||
/*
|
|
||||||
dbg!(self
|
|
||||||
.chain
|
|
||||||
.current_state()
|
|
||||||
.generate_seed(state.current_epoch(), &self.spec));
|
|
||||||
// dbg!(state.generate_seed(state.next_epoch(), &self.spec));
|
|
||||||
dbg!(state.canonical_root());
|
|
||||||
dbg!(&state.committee_caches[0]);
|
|
||||||
dbg!(self.chain.current_state().canonical_root());
|
|
||||||
dbg!(&self.chain.current_state().committee_caches[0]);
|
|
||||||
|
|
||||||
dbg!(state.get_beacon_proposer_index(slot, RelativeEpoch::Current, &self.spec));
|
|
||||||
dbg!(self.chain.current_state().get_beacon_proposer_index(
|
|
||||||
slot,
|
|
||||||
RelativeEpoch::Current,
|
|
||||||
&self.spec
|
|
||||||
));
|
|
||||||
*/
|
|
||||||
|
|
||||||
let proposer_index = match build_strategy {
|
let proposer_index = match build_strategy {
|
||||||
BuildStrategy::OnCanonicalHead => self
|
BuildStrategy::OnCanonicalHead => self
|
||||||
.chain
|
.chain
|
||||||
@ -308,7 +284,7 @@ mod test {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn can_finalize() {
|
fn can_finalize() {
|
||||||
let num_blocks_produced = MinimalEthSpec::slots_per_epoch() * 5;
|
let num_blocks_produced = MinimalEthSpec::slots_per_epoch() * 1 + 2;
|
||||||
|
|
||||||
let harness = get_harness(VALIDATOR_COUNT);
|
let harness = get_harness(VALIDATOR_COUNT);
|
||||||
|
|
||||||
@ -340,5 +316,7 @@ mod test {
|
|||||||
state.current_epoch() - 2,
|
state.current_epoch() - 2,
|
||||||
"the head should be finalized two behind the current epoch"
|
"the head should be finalized two behind the current epoch"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
panic!();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -210,6 +210,8 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn find_head_from<'a>(&'a self, start_node: &'a Node) -> Result<&'a Node> {
|
fn find_head_from<'a>(&'a self, start_node: &'a Node) -> Result<&'a Node> {
|
||||||
|
dbg!(&self.nodes);
|
||||||
|
|
||||||
if start_node.does_not_have_children() {
|
if start_node.does_not_have_children() {
|
||||||
Ok(start_node)
|
Ok(start_node)
|
||||||
} else {
|
} else {
|
||||||
@ -585,7 +587,7 @@ pub struct Vote {
|
|||||||
///
|
///
|
||||||
/// E.g., a `get` or `insert` to an out-of-bounds element will cause the Vec to grow (using
|
/// E.g., a `get` or `insert` to an out-of-bounds element will cause the Vec to grow (using
|
||||||
/// Default) to the smallest size required to fulfill the request.
|
/// Default) to the smallest size required to fulfill the request.
|
||||||
#[derive(Default, Clone)]
|
#[derive(Default, Clone, Debug)]
|
||||||
pub struct ElasticList<T>(Vec<T>);
|
pub struct ElasticList<T>(Vec<T>);
|
||||||
|
|
||||||
impl<T> ElasticList<T>
|
impl<T> ElasticList<T>
|
||||||
|
@ -5,7 +5,7 @@ use bls::Signature;
|
|||||||
use serde_derive::{Deserialize, Serialize};
|
use serde_derive::{Deserialize, Serialize};
|
||||||
use ssz_derive::{Decode, Encode};
|
use ssz_derive::{Decode, Encode};
|
||||||
use test_random_derive::TestRandom;
|
use test_random_derive::TestRandom;
|
||||||
use tree_hash::TreeHash;
|
use tree_hash::{SignedRoot, TreeHash};
|
||||||
use tree_hash_derive::{CachedTreeHash, SignedRoot, TreeHash};
|
use tree_hash_derive::{CachedTreeHash, SignedRoot, TreeHash};
|
||||||
|
|
||||||
/// A block of the `BeaconChain`.
|
/// A block of the `BeaconChain`.
|
||||||
|
@ -703,9 +703,6 @@ impl<T: EthSpec> BeaconState<T> {
|
|||||||
let active_index_root = self.get_active_index_root(epoch, spec)?;
|
let active_index_root = self.get_active_index_root(epoch, spec)?;
|
||||||
let epoch_bytes = int_to_bytes32(epoch.as_u64());
|
let epoch_bytes = int_to_bytes32(epoch.as_u64());
|
||||||
|
|
||||||
dbg!(randao);
|
|
||||||
dbg!(active_index_root);
|
|
||||||
|
|
||||||
let mut preimage = [0; 32 * 3];
|
let mut preimage = [0; 32 * 3];
|
||||||
preimage[0..32].copy_from_slice(&randao[..]);
|
preimage[0..32].copy_from_slice(&randao[..]);
|
||||||
preimage[32..64].copy_from_slice(&active_index_root[..]);
|
preimage[32..64].copy_from_slice(&active_index_root[..]);
|
||||||
@ -838,10 +835,12 @@ impl<T: EthSpec> BeaconState<T> {
|
|||||||
/// Note: whilst this function will preserve already-built caches, it will not build any.
|
/// Note: whilst this function will preserve already-built caches, it will not build any.
|
||||||
pub fn advance_caches(&mut self) {
|
pub fn advance_caches(&mut self) {
|
||||||
let next = Self::cache_index(RelativeEpoch::Previous);
|
let next = Self::cache_index(RelativeEpoch::Previous);
|
||||||
|
let current = Self::cache_index(RelativeEpoch::Current);
|
||||||
|
|
||||||
let caches = &mut self.committee_caches[..];
|
let caches = &mut self.committee_caches[..];
|
||||||
caches.rotate_left(1);
|
caches.rotate_left(1);
|
||||||
caches[next] = CommitteeCache::default();
|
caches[next] = CommitteeCache::default();
|
||||||
|
caches[current] = CommitteeCache::default();
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cache_index(relative_epoch: RelativeEpoch) -> usize {
|
fn cache_index(relative_epoch: RelativeEpoch) -> usize {
|
||||||
|
Loading…
Reference in New Issue
Block a user