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

@@ -14,7 +14,7 @@ use slog::{debug, o, trace, warn};
use ssz::{Decode, DecodeError};
use std::sync::Arc;
use tokio::sync::mpsc;
use types::{Attestation, AttesterSlashing, BeaconBlock, ProposerSlashing, VoluntaryExit};
use types::{Attestation, AttesterSlashing, ProposerSlashing, SignedBeaconBlock, VoluntaryExit};
/// Handles messages received from the network and client and organises syncing. This
/// functionality of this struct is to validate an decode messages from the network before
@@ -319,9 +319,9 @@ impl<T: BeaconChainTypes> MessageHandler<T> {
fn decode_gossip_block(
&self,
beacon_block: Vec<u8>,
) -> Result<BeaconBlock<T::EthSpec>, DecodeError> {
) -> Result<SignedBeaconBlock<T::EthSpec>, DecodeError> {
//TODO: Apply verification before decoding.
BeaconBlock::from_ssz_bytes(&beacon_block)
SignedBeaconBlock::from_ssz_bytes(&beacon_block)
}
fn decode_gossip_attestation(
@@ -355,13 +355,13 @@ impl<T: BeaconChainTypes> MessageHandler<T> {
/* Req/Resp Domain Decoding */
/// Verifies and decodes an ssz-encoded `BeaconBlock`. If `None` is passed, this represents a
/// Verifies and decodes an ssz-encoded `SignedBeaconBlock`. If `None` is passed, this represents a
/// stream termination.
fn decode_beacon_block(
&self,
beacon_block: Vec<u8>,
) -> Result<BeaconBlock<T::EthSpec>, DecodeError> {
) -> Result<SignedBeaconBlock<T::EthSpec>, DecodeError> {
//TODO: Implement faster block verification before decoding entirely
BeaconBlock::from_ssz_bytes(&beacon_block)
SignedBeaconBlock::from_ssz_bytes(&beacon_block)
}
}

View File

@@ -11,8 +11,7 @@ use ssz::Encode;
use std::sync::Arc;
use store::Store;
use tokio::sync::{mpsc, oneshot};
use tree_hash::SignedRoot;
use types::{Attestation, BeaconBlock, Epoch, EthSpec, Hash256, Slot};
use types::{Attestation, Epoch, EthSpec, Hash256, SignedBeaconBlock, Slot};
//TODO: Rate limit requests
@@ -263,7 +262,7 @@ impl<T: BeaconChainTypes> MessageProcessor<T> {
} else if self
.chain
.store
.exists::<BeaconBlock<T::EthSpec>>(&remote.head_root)
.exists::<SignedBeaconBlock<T::EthSpec>>(&remote.head_root)
.unwrap_or_else(|_| false)
{
trace!(
@@ -300,7 +299,7 @@ impl<T: BeaconChainTypes> MessageProcessor<T> {
) {
let mut send_block_count = 0;
for root in request.block_roots.iter() {
if let Ok(Some(block)) = self.chain.store.get::<BeaconBlock<T::EthSpec>>(root) {
if let Ok(Some(block)) = self.chain.store.get_block(root) {
self.network.send_rpc_response(
peer_id.clone(),
request_id,
@@ -380,11 +379,11 @@ impl<T: BeaconChainTypes> MessageProcessor<T> {
let mut blocks_sent = 0;
for root in block_roots {
if let Ok(Some(block)) = self.chain.store.get::<BeaconBlock<T::EthSpec>>(&root) {
if let Ok(Some(block)) = self.chain.store.get_block(&root) {
// Due to skip slots, blocks could be out of the range, we ensure they are in the
// range before sending
if block.slot >= req.start_slot
&& block.slot < req.start_slot + req.count * req.step
if block.slot() >= req.start_slot
&& block.slot() < req.start_slot + req.count * req.step
{
blocks_sent += 1;
self.network.send_rpc_response(
@@ -437,7 +436,7 @@ impl<T: BeaconChainTypes> MessageProcessor<T> {
&mut self,
peer_id: PeerId,
request_id: RequestId,
beacon_block: Option<BeaconBlock<T::EthSpec>>,
beacon_block: Option<SignedBeaconBlock<T::EthSpec>>,
) {
let beacon_block = beacon_block.map(Box::new);
trace!(
@@ -458,7 +457,7 @@ impl<T: BeaconChainTypes> MessageProcessor<T> {
&mut self,
peer_id: PeerId,
request_id: RequestId,
beacon_block: Option<BeaconBlock<T::EthSpec>>,
beacon_block: Option<SignedBeaconBlock<T::EthSpec>>,
) {
let beacon_block = beacon_block.map(Box::new);
trace!(
@@ -479,7 +478,11 @@ impl<T: BeaconChainTypes> MessageProcessor<T> {
/// Attempts to apply to block to the beacon chain. May queue the block for later processing.
///
/// Returns a `bool` which, if `true`, indicates we should forward the block to our peers.
pub fn on_block_gossip(&mut self, peer_id: PeerId, block: BeaconBlock<T::EthSpec>) -> bool {
pub fn on_block_gossip(
&mut self,
peer_id: PeerId,
block: SignedBeaconBlock<T::EthSpec>,
) -> bool {
match self.chain.process_block(block.clone()) {
Ok(outcome) => match outcome {
BlockProcessingOutcome::Processed { .. } => {
@@ -528,8 +531,8 @@ impl<T: BeaconChainTypes> MessageProcessor<T> {
self.log,
"Invalid gossip beacon block";
"outcome" => format!("{:?}", other),
"block root" => format!("{}", Hash256::from_slice(&block.signed_root()[..])),
"block slot" => block.slot
"block root" => format!("{}", block.canonical_root()),
"block slot" => block.slot()
);
trace!(
self.log,

View File

@@ -50,7 +50,7 @@ use std::collections::HashSet;
use std::ops::Sub;
use std::sync::Weak;
use tokio::sync::{mpsc, oneshot};
use types::{BeaconBlock, EthSpec, Hash256};
use types::{EthSpec, Hash256, SignedBeaconBlock};
/// The number of slots ahead of us that is allowed before requesting a long-range (batch) Sync
/// from a peer. If a peer is within this tolerance (forwards or backwards), it is treated as a
@@ -73,18 +73,18 @@ pub enum SyncMessage<T: EthSpec> {
BlocksByRangeResponse {
peer_id: PeerId,
request_id: RequestId,
beacon_block: Option<Box<BeaconBlock<T>>>,
beacon_block: Option<Box<SignedBeaconBlock<T>>>,
},
/// A `BlocksByRoot` response has been received.
BlocksByRootResponse {
peer_id: PeerId,
request_id: RequestId,
beacon_block: Option<Box<BeaconBlock<T>>>,
beacon_block: Option<Box<SignedBeaconBlock<T>>>,
},
/// A block with an unknown parent has been received.
UnknownBlock(PeerId, Box<BeaconBlock<T>>),
UnknownBlock(PeerId, Box<SignedBeaconBlock<T>>),
/// A peer has sent an object that references a block that is unknown. This triggers the
/// manager to attempt to find the block matching the unknown hash.
@@ -107,7 +107,7 @@ pub enum SyncMessage<T: EthSpec> {
/// Maintains a sequential list of parents to lookup and the lookup's current state.
struct ParentRequests<T: EthSpec> {
/// The blocks that have currently been downloaded.
downloaded_blocks: Vec<BeaconBlock<T>>,
downloaded_blocks: Vec<SignedBeaconBlock<T>>,
/// The number of failed attempts to retrieve a parent block. If too many attempts occur, this
/// lookup is failed and rejected.
@@ -290,7 +290,7 @@ impl<T: BeaconChainTypes> SyncManager<T> {
&mut self,
peer_id: PeerId,
request_id: RequestId,
block: Option<BeaconBlock<T::EthSpec>>,
block: Option<SignedBeaconBlock<T::EthSpec>>,
) {
// check if this is a single block lookup - i.e we were searching for a specific hash
if block.is_some() {
@@ -344,7 +344,7 @@ impl<T: BeaconChainTypes> SyncManager<T> {
fn single_block_lookup_response(
&mut self,
peer_id: PeerId,
block: BeaconBlock<T::EthSpec>,
block: SignedBeaconBlock<T::EthSpec>,
expected_block_hash: Hash256,
) {
// verify the hash is correct and try and process the block
@@ -398,7 +398,7 @@ impl<T: BeaconChainTypes> SyncManager<T> {
/// A block has been sent to us that has an unknown parent. This begins a parent lookup search
/// to find the parent or chain of parents that match our current chain.
fn add_unknown_block(&mut self, peer_id: PeerId, block: BeaconBlock<T::EthSpec>) {
fn add_unknown_block(&mut self, peer_id: PeerId, block: SignedBeaconBlock<T::EthSpec>) {
// If we are not in regular sync mode, ignore this block
if self.state != ManagerState::Regular {
return;
@@ -516,7 +516,7 @@ impl<T: BeaconChainTypes> SyncManager<T> {
// fail loudly
}
let previous_index = parent_request.downloaded_blocks.len() - 2;
let expected_hash = parent_request.downloaded_blocks[previous_index].parent_root;
let expected_hash = parent_request.downloaded_blocks[previous_index].parent_root();
// Note: the length must be greater than 2 so this cannot panic.
let block_hash = parent_request
@@ -626,7 +626,7 @@ impl<T: BeaconChainTypes> SyncManager<T> {
.downloaded_blocks
.last()
.expect("The parent queue should never be empty")
.parent_root;
.parent_root();
let request = BlocksByRootRequest {
block_roots: vec![parent_hash],
};

View File

@@ -9,7 +9,7 @@ use std::collections::hash_map::Entry;
use std::collections::{HashMap, HashSet};
use std::hash::{Hash, Hasher};
use std::ops::Sub;
use types::{BeaconBlock, EthSpec, Hash256, Slot};
use types::{EthSpec, Hash256, SignedBeaconBlock, Slot};
#[derive(Copy, Clone, Debug, PartialEq)]
pub struct BatchId(pub u64);
@@ -55,7 +55,7 @@ pub struct Batch<T: EthSpec> {
/// Marks the batch as undergoing a re-process, with a hash of the original blocks it received.
pub original_hash: Option<u64>,
/// The blocks that have been downloaded.
pub downloaded_blocks: Vec<BeaconBlock<T>>,
pub downloaded_blocks: Vec<SignedBeaconBlock<T>>,
}
impl<T: EthSpec> Eq for Batch<T> {}
@@ -164,7 +164,7 @@ impl<T: EthSpec> PendingBatches<T> {
/// Adds a block to the batches if the request id exists. Returns None if there is no batch
/// matching the request id.
pub fn add_block(&mut self, request_id: RequestId, block: BeaconBlock<T>) -> Option<()> {
pub fn add_block(&mut self, request_id: RequestId, block: SignedBeaconBlock<T>) -> Option<()> {
let batch = self.batches.get_mut(&request_id)?;
batch.downloaded_blocks.push(block);
Some(())

View File

@@ -65,7 +65,7 @@ fn process_batch<T: BeaconChainTypes>(
// The block was valid and we processed it successfully.
trace!(
log, "Imported block from network";
"slot" => block.slot,
"slot" => block.slot(),
"block_root" => format!("{}", block_root),
);
successful_block_import = true;
@@ -75,21 +75,21 @@ fn process_batch<T: BeaconChainTypes>(
warn!(
log, "Parent block is unknown";
"parent_root" => format!("{}", parent),
"baby_block_slot" => block.slot,
"baby_block_slot" => block.slot(),
);
if successful_block_import {
run_fork_choice(chain, log);
}
return Err(format!(
"Block at slot {} has an unknown parent.",
block.slot
block.slot()
));
}
BlockProcessingOutcome::BlockIsAlreadyKnown => {
// this block is already known to us, move to the next
debug!(
log, "Imported a block that is already known";
"block_slot" => block.slot,
"block_slot" => block.slot(),
);
}
BlockProcessingOutcome::FutureSlot {
@@ -110,7 +110,7 @@ fn process_batch<T: BeaconChainTypes>(
}
return Err(format!(
"Block at slot {} is too far in the future",
block.slot
block.slot()
));
} else {
// The block is in the future, but not too far.
@@ -144,7 +144,7 @@ fn process_batch<T: BeaconChainTypes>(
if successful_block_import {
run_fork_choice(chain, log);
}
return Err(format!("Invalid block at slot {}", block.slot));
return Err(format!("Invalid block at slot {}", block.slot()));
}
}
} else {

View File

@@ -10,7 +10,7 @@ use slog::{crit, debug, warn};
use std::collections::HashSet;
use std::sync::Weak;
use tokio::sync::mpsc;
use types::{BeaconBlock, Hash256, Slot};
use types::{Hash256, SignedBeaconBlock, Slot};
/// Blocks are downloaded in batches from peers. This constant specifies how many blocks per batch
/// is requested. There is a timeout for each batch request. If this value is too high, we will
@@ -143,7 +143,7 @@ impl<T: BeaconChainTypes> SyncingChain<T> {
&mut self,
network: &mut SyncNetworkContext,
request_id: RequestId,
beacon_block: &Option<BeaconBlock<T::EthSpec>>,
beacon_block: &Option<SignedBeaconBlock<T::EthSpec>>,
) -> Option<()> {
if let Some(block) = beacon_block {
// This is not a stream termination, simply add the block to the request
@@ -171,11 +171,11 @@ impl<T: BeaconChainTypes> SyncingChain<T> {
// verify the range of received blocks
// Note that the order of blocks is verified in block processing
if let Some(last_slot) = batch.downloaded_blocks.last().map(|b| b.slot) {
if let Some(last_slot) = batch.downloaded_blocks.last().map(|b| b.slot()) {
// the batch is non-empty
if batch.start_slot > batch.downloaded_blocks[0].slot || batch.end_slot < last_slot {
warn!(self.log, "BlocksByRange response returned out of range blocks";
"response_initial_slot" => batch.downloaded_blocks[0].slot,
if batch.start_slot > batch.downloaded_blocks[0].slot() || batch.end_slot < last_slot {
warn!(self.log, "BlocksByRange response returned out of range blocks";
"response_initial_slot" => batch.downloaded_blocks[0].slot(),
"requested_initial_slot" => batch.start_slot);
network.downvote_peer(batch.current_peer);
self.to_be_processed_id = batch.id; // reset the id back to here, when incrementing, it will check against completed batches
@@ -274,7 +274,7 @@ impl<T: BeaconChainTypes> SyncingChain<T> {
// double check batches are processed in order TODO: Remove for prod
if batch.id != self.to_be_processed_id {
crit!(self.log, "Batch processed out of order";
"processed_batch_id" => *batch.id,
"processed_batch_id" => *batch.id,
"expected_id" => *self.to_be_processed_id);
}
@@ -298,7 +298,7 @@ impl<T: BeaconChainTypes> SyncingChain<T> {
let processed_batch = self.processed_batches.remove(0);
if *processed_batch.id >= *batch.id {
crit!(self.log, "A processed batch had a greater id than the current process id";
"processed_id" => *processed_batch.id,
"processed_id" => *processed_batch.id,
"current_id" => *batch.id);
}
@@ -313,8 +313,8 @@ impl<T: BeaconChainTypes> SyncingChain<T> {
// If the same peer corrected it's mistake, we allow it.... for
// now.
debug!(self.log, "Re-processed batch validated. Downvoting original peer";
"batch_id" => *processed_batch.id,
"original_peer" => format!("{}",processed_batch.original_peer),
"batch_id" => *processed_batch.id,
"original_peer" => format!("{}",processed_batch.original_peer),
"new_peer" => format!("{}", processed_batch.current_peer));
network.downvote_peer(processed_batch.original_peer);
}
@@ -325,7 +325,7 @@ impl<T: BeaconChainTypes> SyncingChain<T> {
// Add the current batch to processed batches to be verified in the future. We are
// only uncertain about this batch, if it has not returned all blocks.
if batch.downloaded_blocks.last().map(|block| block.slot)
if batch.downloaded_blocks.last().map(|block| block.slot())
!= Some(batch.end_slot.saturating_sub(1u64))
{
self.processed_batches.push(batch);
@@ -436,12 +436,12 @@ impl<T: BeaconChainTypes> SyncingChain<T> {
batch.current_peer = new_peer.clone();
debug!(self.log, "Re-requesting batch";
"start_slot" => batch.start_slot,
debug!(self.log, "Re-requesting batch";
"start_slot" => batch.start_slot,
"end_slot" => batch.end_slot,
"id" => *batch.id,
"peer" => format!("{}", batch.current_peer),
"head_root"=> format!("{}", batch.head_root),
"head_root"=> format!("{}", batch.head_root),
"retries" => batch.retries,
"re-processes" => batch.reprocess_retries);
self.send_batch(network, batch);
@@ -522,9 +522,9 @@ impl<T: BeaconChainTypes> SyncingChain<T> {
request_id: RequestId,
) -> Option<ProcessingResult> {
if let Some(batch) = self.pending_batches.remove(request_id) {
warn!(self.log, "Batch failed. RPC Error";
"id" => *batch.id,
"retries" => batch.retries,
warn!(self.log, "Batch failed. RPC Error";
"id" => *batch.id,
"retries" => batch.retries,
"peer" => format!("{:?}", peer_id));
Some(self.failed_batch(network, batch))
@@ -564,7 +564,7 @@ impl<T: BeaconChainTypes> SyncingChain<T> {
batch.current_peer = new_peer.clone();
debug!(self.log, "Re-Requesting batch";
"start_slot" => batch.start_slot,
"end_slot" => batch.end_slot,
"end_slot" => batch.end_slot,
"id" => *batch.id,
"peer" => format!("{:?}", batch.current_peer),
"head_root"=> format!("{}", batch.head_root));
@@ -587,11 +587,11 @@ impl<T: BeaconChainTypes> SyncingChain<T> {
// find the next pending batch and request it from the peer
if let Some(peer_id) = self.get_next_peer() {
if let Some(batch) = self.get_next_batch(peer_id) {
debug!(self.log, "Requesting batch";
"start_slot" => batch.start_slot,
debug!(self.log, "Requesting batch";
"start_slot" => batch.start_slot,
"end_slot" => batch.end_slot,
"id" => *batch.id,
"peer" => format!("{}", batch.current_peer),
"peer" => format!("{}", batch.current_peer),
"head_root"=> format!("{}", batch.head_root));
// send the batch
self.send_batch(network, batch);

View File

@@ -52,7 +52,7 @@ use slog::{debug, error, trace, warn};
use std::collections::HashSet;
use std::sync::Weak;
use tokio::sync::mpsc;
use types::{BeaconBlock, EthSpec};
use types::{EthSpec, SignedBeaconBlock};
/// The primary object dealing with long range/batch syncing. This contains all the active and
/// non-active chains that need to be processed before the syncing is considered complete. This
@@ -231,7 +231,7 @@ impl<T: BeaconChainTypes> RangeSync<T> {
network: &mut SyncNetworkContext,
peer_id: PeerId,
request_id: RequestId,
beacon_block: Option<BeaconBlock<T::EthSpec>>,
beacon_block: Option<SignedBeaconBlock<T::EthSpec>>,
) {
// Find the request. Most likely the first finalized chain (the syncing chain). If there
// are no finalized chains, then it will be a head chain. At most, there should only be