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:
Michael Sproul
2020-02-11 10:19:36 +11:00
committed by GitHub
parent 03e77390a3
commit 371e5adcf8
145 changed files with 1666 additions and 4437 deletions

View File

@@ -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, &eth1_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))
})?;