mirror of
https://github.com/sigp/lighthouse.git
synced 2026-05-09 11:25:55 +00:00
Update to Spec v0.10 (#817)
* Start updating types * WIP * Signature hacking * Existing EF tests passing with fake_crypto * Updates * Delete outdated API spec * The refactor continues * It compiles * WIP test fixes * All release tests passing bar genesis state parsing * Update and test YamlConfig * Update to spec v0.10 compatible BLS * Updates to BLS EF tests * Add EF test for AggregateVerify And delete unused hash2curve tests for uncompressed points * Update EF tests to v0.10.1 * Use optional block root correctly in block proc * Use genesis fork in deposit domain. All tests pass * Cargo fmt * Fast aggregate verify test * Update REST API docs * Cargo fmt * Fix unused import * Bump spec tags to v0.10.1 * Add `seconds_per_eth1_block` to chainspec * Update to timestamp based eth1 voting scheme * Return None from `get_votes_to_consider` if block cache is empty * Handle overflows in `is_candidate_block` * Revert to failing tests * Fix eth1 data sets test * Choose default vote according to spec * Fix collect_valid_votes tests * Fix `get_votes_to_consider` to choose all eligible blocks * Uncomment winning_vote tests * Add comments; remove unused code * Reduce seconds_per_eth1_block for simulation * Addressed review comments * Add test for default vote case * Fix logs * Remove unused functions * Meter default eth1 votes * Fix comments * Address review comments; remove unused dependency * Disable/delete two outdated tests * Bump eth1 default vote warn to error * Delete outdated eth1 test Co-authored-by: Pawan Dhananjay <pawandhananjay@gmail.com>
This commit is contained in:
@@ -166,9 +166,9 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
.store
|
||||
.get_block(&beacon_block_root)?
|
||||
.ok_or_else(|| Error::MissingBeaconBlock(beacon_block_root))?;
|
||||
let beacon_state_root = beacon_block.state_root;
|
||||
let beacon_state_root = beacon_block.state_root();
|
||||
let beacon_state = self
|
||||
.get_state(&beacon_state_root, Some(beacon_block.slot))?
|
||||
.get_state(&beacon_state_root, Some(beacon_block.slot()))?
|
||||
.ok_or_else(|| Error::MissingBeaconState(beacon_state_root))?;
|
||||
|
||||
CheckPoint {
|
||||
@@ -216,39 +216,6 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
.map(|slot| slot.epoch(T::EthSpec::slots_per_epoch()))
|
||||
}
|
||||
|
||||
/// Returns the beacon block body for each beacon block root in `roots`.
|
||||
///
|
||||
/// Fails if any root in `roots` does not have a corresponding block.
|
||||
pub fn get_block_bodies(
|
||||
&self,
|
||||
roots: &[Hash256],
|
||||
) -> Result<Vec<BeaconBlockBody<T::EthSpec>>, Error> {
|
||||
let bodies: Result<Vec<_>, _> = roots
|
||||
.iter()
|
||||
.map(|root| match self.block_at_root(*root)? {
|
||||
Some(block) => Ok(block.body),
|
||||
None => Err(Error::DBInconsistent(format!("Missing block: {}", root))),
|
||||
})
|
||||
.collect();
|
||||
|
||||
Ok(bodies?)
|
||||
}
|
||||
|
||||
/// Returns the beacon block header for each beacon block root in `roots`.
|
||||
///
|
||||
/// Fails if any root in `roots` does not have a corresponding block.
|
||||
pub fn get_block_headers(&self, roots: &[Hash256]) -> Result<Vec<BeaconBlockHeader>, Error> {
|
||||
let headers: Result<Vec<BeaconBlockHeader>, _> = roots
|
||||
.iter()
|
||||
.map(|root| match self.block_at_root(*root)? {
|
||||
Some(block) => Ok(block.block_header()),
|
||||
None => Err(Error::DBInconsistent("Missing block".into())),
|
||||
})
|
||||
.collect();
|
||||
|
||||
Ok(headers?)
|
||||
}
|
||||
|
||||
/// Iterates across all `(block_root, slot)` pairs from the head of the chain (inclusive) to
|
||||
/// the earliest reachable ancestor (may or may not be genesis).
|
||||
///
|
||||
@@ -268,7 +235,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
let iter = BlockRootsIterator::owned(self.store.clone(), head.beacon_state);
|
||||
|
||||
Ok(ReverseBlockRootIterator::new(
|
||||
(head.beacon_block_root, head.beacon_block.slot),
|
||||
(head.beacon_block_root, head.beacon_block.slot()),
|
||||
iter,
|
||||
))
|
||||
}
|
||||
@@ -305,11 +272,11 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
.get_block(&block_root)?
|
||||
.ok_or_else(|| Error::MissingBeaconBlock(block_root))?;
|
||||
let state = self
|
||||
.get_state(&block.state_root, Some(block.slot))?
|
||||
.ok_or_else(|| Error::MissingBeaconState(block.state_root))?;
|
||||
.get_state(&block.state_root(), Some(block.slot()))?
|
||||
.ok_or_else(|| Error::MissingBeaconState(block.state_root()))?;
|
||||
let iter = BlockRootsIterator::owned(self.store.clone(), state);
|
||||
Ok(ReverseBlockRootIterator::new(
|
||||
(block_root, block.slot),
|
||||
(block_root, block.slot()),
|
||||
iter,
|
||||
))
|
||||
}
|
||||
@@ -349,24 +316,15 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
))
|
||||
}
|
||||
|
||||
/// Returns the block at the given root, if any.
|
||||
///
|
||||
/// ## Errors
|
||||
///
|
||||
/// May return a database error.
|
||||
pub fn block_at_root(
|
||||
&self,
|
||||
block_root: Hash256,
|
||||
) -> Result<Option<BeaconBlock<T::EthSpec>>, Error> {
|
||||
Ok(self.store.get(&block_root)?)
|
||||
}
|
||||
|
||||
/// Returns the block at the given slot, if any. Only returns blocks in the canonical chain.
|
||||
///
|
||||
/// ## Errors
|
||||
///
|
||||
/// May return a database error.
|
||||
pub fn block_at_slot(&self, slot: Slot) -> Result<Option<BeaconBlock<T::EthSpec>>, Error> {
|
||||
pub fn block_at_slot(
|
||||
&self,
|
||||
slot: Slot,
|
||||
) -> Result<Option<SignedBeaconBlock<T::EthSpec>>, Error> {
|
||||
let root = self
|
||||
.rev_iter_block_roots()?
|
||||
.find(|(_, this_slot)| *this_slot == slot)
|
||||
@@ -387,7 +345,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
pub fn get_block(
|
||||
&self,
|
||||
block_root: &Hash256,
|
||||
) -> Result<Option<BeaconBlock<T::EthSpec>>, Error> {
|
||||
) -> Result<Option<SignedBeaconBlock<T::EthSpec>>, Error> {
|
||||
Ok(self.store.get_block(block_root)?)
|
||||
}
|
||||
|
||||
@@ -448,7 +406,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
.ok_or_else(|| Error::CanonicalHeadLockTimeout)?;
|
||||
|
||||
Ok(HeadInfo {
|
||||
slot: head.beacon_block.slot,
|
||||
slot: head.beacon_block.slot(),
|
||||
block_root: head.beacon_block_root,
|
||||
state_root: head.beacon_state_root,
|
||||
finalized_checkpoint: head.beacon_state.finalized_checkpoint.clone(),
|
||||
@@ -550,7 +508,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
pub fn best_slot(&self) -> Result<Slot, Error> {
|
||||
self.canonical_head
|
||||
.try_read_for(HEAD_LOCK_TIMEOUT)
|
||||
.map(|head| head.beacon_block.slot)
|
||||
.map(|head| head.beacon_block.slot())
|
||||
.ok_or_else(|| Error::CanonicalHeadLockTimeout)
|
||||
}
|
||||
|
||||
@@ -576,19 +534,6 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
.map(|(root, _slot)| root))
|
||||
}
|
||||
|
||||
/// Reads the slot clock (see `self.read_slot_clock()` and returns the number of slots since
|
||||
/// genesis.
|
||||
pub fn slots_since_genesis(&self) -> Option<SlotHeight> {
|
||||
let now = self.slot().ok()?;
|
||||
let genesis_slot = self.spec.genesis_slot;
|
||||
|
||||
if now < genesis_slot {
|
||||
None
|
||||
} else {
|
||||
Some(SlotHeight::from(now.as_u64() - genesis_slot.as_u64()))
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the block proposer for a given slot.
|
||||
///
|
||||
/// Information is read from the present `beacon_state` shuffling, only information from the
|
||||
@@ -669,7 +614,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
let data = self.produce_attestation_data_for_block(
|
||||
index,
|
||||
head.beacon_block_root,
|
||||
head.beacon_block.slot,
|
||||
head.beacon_block.slot(),
|
||||
&state,
|
||||
)?;
|
||||
|
||||
@@ -696,7 +641,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
self.produce_attestation_data_for_block(
|
||||
index,
|
||||
head.beacon_block_root,
|
||||
head.beacon_block.slot,
|
||||
head.beacon_block.slot(),
|
||||
&state,
|
||||
)
|
||||
}
|
||||
@@ -859,22 +804,20 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
// the attestation points to a block in a prior epoch, then it is necessary to
|
||||
// load the full state corresponding to its block, and transition it to the
|
||||
// attestation's epoch.
|
||||
let attestation_block_root = attestation_head_block.state_root();
|
||||
let attestation_epoch = attestation.data.target.epoch;
|
||||
let slots_per_epoch = T::EthSpec::slots_per_epoch();
|
||||
let mut state = if attestation_epoch
|
||||
== attestation_head_block.slot.epoch(slots_per_epoch)
|
||||
== attestation_head_block.slot().epoch(slots_per_epoch)
|
||||
{
|
||||
self.store
|
||||
.load_epoch_boundary_state(&attestation_head_block.state_root)?
|
||||
.ok_or_else(|| Error::MissingBeaconState(attestation_head_block.state_root))?
|
||||
.load_epoch_boundary_state(&attestation_block_root)?
|
||||
.ok_or_else(|| Error::MissingBeaconState(attestation_block_root))?
|
||||
} else {
|
||||
let mut state = self
|
||||
.store
|
||||
.get_state(
|
||||
&attestation_head_block.state_root,
|
||||
Some(attestation_head_block.slot),
|
||||
)?
|
||||
.ok_or_else(|| Error::MissingBeaconState(attestation_head_block.state_root))?;
|
||||
.get_state(&attestation_block_root, Some(attestation_head_block.slot()))?
|
||||
.ok_or_else(|| Error::MissingBeaconState(attestation_block_root))?;
|
||||
|
||||
// Fastforward the state to the epoch in which the attestation was made.
|
||||
// NOTE: this looks like a potential DoS vector, we should probably limit
|
||||
@@ -902,7 +845,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
self.process_attestation_for_state_and_block(
|
||||
attestation,
|
||||
&state,
|
||||
&attestation_head_block,
|
||||
&attestation_head_block.message,
|
||||
)
|
||||
}
|
||||
} else {
|
||||
@@ -1045,7 +988,10 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
}
|
||||
|
||||
/// Accept some exit and queue it for inclusion in an appropriate block.
|
||||
pub fn process_voluntary_exit(&self, exit: VoluntaryExit) -> Result<(), ExitValidationError> {
|
||||
pub fn process_voluntary_exit(
|
||||
&self,
|
||||
exit: SignedVoluntaryExit,
|
||||
) -> Result<(), ExitValidationError> {
|
||||
match self.wall_clock_state() {
|
||||
Ok(state) => self.op_pool.insert_voluntary_exit(exit, &state, &self.spec),
|
||||
Err(e) => {
|
||||
@@ -1109,7 +1055,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
/// Will accept blocks from prior slots, however it will reject any block from a future slot.
|
||||
pub fn process_block(
|
||||
&self,
|
||||
block: BeaconBlock<T::EthSpec>,
|
||||
block: SignedBeaconBlock<T::EthSpec>,
|
||||
) -> Result<BlockProcessingOutcome, Error> {
|
||||
let outcome = self.process_block_internal(block.clone());
|
||||
|
||||
@@ -1120,7 +1066,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
self.log,
|
||||
"Beacon block imported";
|
||||
"block_root" => format!("{:?}", block_root),
|
||||
"block_slot" => format!("{:?}", block.slot.as_u64()),
|
||||
"block_slot" => format!("{:?}", block.slot().as_u64()),
|
||||
);
|
||||
let _ = self.event_handler.register(EventKind::BeaconBlockImported {
|
||||
block_root: *block_root,
|
||||
@@ -1160,11 +1106,13 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
/// Will accept blocks from prior slots, however it will reject any block from a future slot.
|
||||
fn process_block_internal(
|
||||
&self,
|
||||
block: BeaconBlock<T::EthSpec>,
|
||||
signed_block: SignedBeaconBlock<T::EthSpec>,
|
||||
) -> Result<BlockProcessingOutcome, Error> {
|
||||
metrics::inc_counter(&metrics::BLOCK_PROCESSING_REQUESTS);
|
||||
let full_timer = metrics::start_timer(&metrics::BLOCK_PROCESSING_TIMES);
|
||||
|
||||
let block = &signed_block.message;
|
||||
|
||||
let finalized_slot = self
|
||||
.head_info()?
|
||||
.finalized_checkpoint
|
||||
@@ -1246,9 +1194,9 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
|
||||
// Load the parent blocks state from the database, returning an error if it is not found.
|
||||
// It is an error because if we know the parent block we should also know the parent state.
|
||||
let parent_state_root = parent_block.state_root;
|
||||
let parent_state_root = parent_block.state_root();
|
||||
let parent_state = self
|
||||
.get_state(&parent_state_root, Some(parent_block.slot))?
|
||||
.get_state(&parent_state_root, Some(parent_block.slot()))?
|
||||
.ok_or_else(|| {
|
||||
Error::DBInconsistent(format!("Missing state {:?}", parent_state_root))
|
||||
})?;
|
||||
@@ -1268,7 +1216,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
let distance = block.slot.as_u64().saturating_sub(state.slot.as_u64());
|
||||
for i in 0..distance {
|
||||
let state_root = if i == 0 {
|
||||
parent_block.state_root
|
||||
parent_block.state_root()
|
||||
} else {
|
||||
// This is a new state we've reached, so stage it for storage in the DB.
|
||||
// Computing the state root here is time-equivalent to computing it during slot
|
||||
@@ -1302,7 +1250,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
// slot).
|
||||
match per_block_processing(
|
||||
&mut state,
|
||||
&block,
|
||||
&signed_block,
|
||||
Some(block_root),
|
||||
BlockSignatureStrategy::VerifyBulk,
|
||||
&self.spec,
|
||||
@@ -1372,7 +1320,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
// settles down).
|
||||
// See: https://github.com/sigp/lighthouse/issues/692
|
||||
self.store.put_state(&state_root, state)?;
|
||||
self.store.put_block(&block_root, block)?;
|
||||
self.store.put_block(&block_root, signed_block)?;
|
||||
|
||||
metrics::stop_timer(db_write_timer);
|
||||
|
||||
@@ -1450,26 +1398,28 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
.deposits_for_block_inclusion(&state, ð1_data, &self.spec)?
|
||||
.into();
|
||||
|
||||
let mut block = BeaconBlock {
|
||||
slot: state.slot,
|
||||
parent_root,
|
||||
state_root: Hash256::zero(),
|
||||
let mut block = SignedBeaconBlock {
|
||||
message: BeaconBlock {
|
||||
slot: state.slot,
|
||||
parent_root,
|
||||
state_root: Hash256::zero(),
|
||||
body: BeaconBlockBody {
|
||||
randao_reveal,
|
||||
eth1_data,
|
||||
graffiti,
|
||||
proposer_slashings: proposer_slashings.into(),
|
||||
attester_slashings: attester_slashings.into(),
|
||||
attestations: self
|
||||
.op_pool
|
||||
.get_attestations(&state, &self.spec)
|
||||
.map_err(BlockProductionError::OpPoolError)?
|
||||
.into(),
|
||||
deposits,
|
||||
voluntary_exits: self.op_pool.get_voluntary_exits(&state, &self.spec).into(),
|
||||
},
|
||||
},
|
||||
// The block is not signed here, that is the task of a validator client.
|
||||
signature: Signature::empty_signature(),
|
||||
body: BeaconBlockBody {
|
||||
randao_reveal,
|
||||
eth1_data,
|
||||
graffiti,
|
||||
proposer_slashings: proposer_slashings.into(),
|
||||
attester_slashings: attester_slashings.into(),
|
||||
attestations: self
|
||||
.op_pool
|
||||
.get_attestations(&state, &self.spec)
|
||||
.map_err(BlockProductionError::OpPoolError)?
|
||||
.into(),
|
||||
deposits,
|
||||
voluntary_exits: self.op_pool.get_voluntary_exits(&state, &self.spec).into(),
|
||||
},
|
||||
};
|
||||
|
||||
per_block_processing(
|
||||
@@ -1482,7 +1432,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
|
||||
let state_root = state.update_tree_hash_cache()?;
|
||||
|
||||
block.state_root = state_root;
|
||||
block.message.state_root = state_root;
|
||||
|
||||
metrics::inc_counter(&metrics::BLOCK_PRODUCTION_SUCCESSES);
|
||||
metrics::stop_timer(timer);
|
||||
@@ -1490,12 +1440,12 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
trace!(
|
||||
self.log,
|
||||
"Produced beacon block";
|
||||
"parent" => format!("{}", block.parent_root),
|
||||
"attestations" => block.body.attestations.len(),
|
||||
"slot" => block.slot
|
||||
"parent" => format!("{}", block.message.parent_root),
|
||||
"attestations" => block.message.body.attestations.len(),
|
||||
"slot" => block.message.slot
|
||||
);
|
||||
|
||||
Ok((block, state))
|
||||
Ok((block.message, state))
|
||||
}
|
||||
|
||||
/// Execute the fork choice algorithm and enthrone the result as the canonical head.
|
||||
@@ -1516,13 +1466,13 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
.get_block(&beacon_block_root)?
|
||||
.ok_or_else(|| Error::MissingBeaconBlock(beacon_block_root))?;
|
||||
|
||||
let beacon_state_root = beacon_block.state_root;
|
||||
let beacon_state_root = beacon_block.state_root();
|
||||
let beacon_state: BeaconState<T::EthSpec> = self
|
||||
.get_state(&beacon_state_root, Some(beacon_block.slot))?
|
||||
.get_state(&beacon_state_root, Some(beacon_block.slot()))?
|
||||
.ok_or_else(|| Error::MissingBeaconState(beacon_state_root))?;
|
||||
|
||||
let previous_slot = self.head_info()?.slot;
|
||||
let new_slot = beacon_block.slot;
|
||||
let new_slot = beacon_block.slot();
|
||||
|
||||
// Note: this will declare a re-org if we skip `SLOTS_PER_HISTORICAL_ROOT` blocks
|
||||
// between calls to fork choice without swapping between chains. This seems like an
|
||||
@@ -1541,7 +1491,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
"Beacon chain re-org";
|
||||
"previous_head" => format!("{}", self.head_info()?.block_root),
|
||||
"previous_slot" => previous_slot,
|
||||
"new_head_parent" => format!("{}", beacon_block.parent_root),
|
||||
"new_head_parent" => format!("{}", beacon_block.parent_root()),
|
||||
"new_head" => format!("{}", beacon_block_root),
|
||||
"new_slot" => new_slot
|
||||
);
|
||||
@@ -1636,7 +1586,8 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
let finalized_block = self
|
||||
.store
|
||||
.get_block(&finalized_block_root)?
|
||||
.ok_or_else(|| Error::MissingBeaconBlock(finalized_block_root))?;
|
||||
.ok_or_else(|| Error::MissingBeaconBlock(finalized_block_root))?
|
||||
.message;
|
||||
|
||||
let new_finalized_epoch = finalized_block.slot.epoch(T::EthSpec::slots_per_epoch());
|
||||
|
||||
@@ -1678,7 +1629,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
pub fn is_new_block_root(&self, beacon_block_root: &Hash256) -> Result<bool, Error> {
|
||||
Ok(!self
|
||||
.store
|
||||
.exists::<BeaconBlock<T::EthSpec>>(beacon_block_root)?)
|
||||
.exists::<SignedBeaconBlock<T::EthSpec>>(beacon_block_root)?)
|
||||
}
|
||||
|
||||
/// Dumps the entire canonical chain, from the head to genesis to a vector for analysis.
|
||||
@@ -1698,20 +1649,19 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
|
||||
dump.push(last_slot.clone());
|
||||
|
||||
loop {
|
||||
let beacon_block_root = last_slot.beacon_block.parent_root;
|
||||
let beacon_block_root = last_slot.beacon_block.parent_root();
|
||||
|
||||
if beacon_block_root == Hash256::zero() {
|
||||
break; // Genesis has been reached.
|
||||
}
|
||||
|
||||
let beacon_block: BeaconBlock<T::EthSpec> =
|
||||
self.store.get(&beacon_block_root)?.ok_or_else(|| {
|
||||
Error::DBInconsistent(format!("Missing block {}", beacon_block_root))
|
||||
})?;
|
||||
let beacon_state_root = beacon_block.state_root;
|
||||
let beacon_block = self.store.get_block(&beacon_block_root)?.ok_or_else(|| {
|
||||
Error::DBInconsistent(format!("Missing block {}", beacon_block_root))
|
||||
})?;
|
||||
let beacon_state_root = beacon_block.state_root();
|
||||
let beacon_state = self
|
||||
.store
|
||||
.get_state(&beacon_state_root, Some(beacon_block.slot))?
|
||||
.get_state(&beacon_state_root, Some(beacon_block.slot()))?
|
||||
.ok_or_else(|| {
|
||||
Error::DBInconsistent(format!("Missing state {:?}", beacon_state_root))
|
||||
})?;
|
||||
|
||||
Reference in New Issue
Block a user