Update to frozen spec ❄️ (v0.8.1) (#444)

* types: first updates for v0.8

* state_processing: epoch processing v0.8.0

* state_processing: block processing v0.8.0

* tree_hash_derive: support generics in SignedRoot

* types v0.8: update to use ssz_types

* state_processing v0.8: use ssz_types

* ssz_types: add bitwise methods and from_elem

* types: fix v0.8 FIXMEs

* ssz_types: add bitfield shift_up

* ssz_types: iterators and DerefMut for VariableList

* types,state_processing: use VariableList

* ssz_types: fix BitVector Decode impl

Fixed a typo in the implementation of ssz::Decode for BitVector, which caused it
to be considered variable length!

* types: fix test modules for v0.8 update

* types: remove slow type-level arithmetic

* state_processing: fix tests for v0.8

* op_pool: update for v0.8

* ssz_types: Bitfield difference length-independent

Allow computing the difference of two bitfields of different lengths.

* Implement compact committee support

* epoch_processing: committee & active index roots

* state_processing: genesis state builder v0.8

* state_processing: implement v0.8.1

* Further improve tree_hash

* Strip examples, tests from cached_tree_hash

* Update TreeHash, un-impl CachedTreeHash

* Update bitfield TreeHash, un-impl CachedTreeHash

* Update FixedLenVec TreeHash, unimpl CachedTreeHash

* Update update tree_hash_derive for new TreeHash

* Fix TreeHash, un-impl CachedTreeHash for ssz_types

* Remove fixed_len_vec, ssz benches

SSZ benches relied upon fixed_len_vec -- it is easier to just delete
them and rebuild them later (when necessary)

* Remove boolean_bitfield crate

* Fix fake_crypto BLS compile errors

* Update ef_tests for new v.8 type params

* Update ef_tests submodule to v0.8.1 tag

* Make fixes to support parsing ssz ef_tests

* `compact_committee...` to `compact_committees...`

* Derive more traits for `CompactCommittee`

* Flip bitfield byte-endianness

* Fix tree_hash for bitfields

* Modify CLI output for ef_tests

* Bump ssz crate version

* Update ssz_types doc comment

* Del cached tree hash tests from ssz_static tests

* Tidy SSZ dependencies

* Rename ssz_types crate to eth2_ssz_types

* validator_client: update for v0.8

* ssz_types: update union/difference for bit order swap

* beacon_node: update for v0.8, EthSpec

* types: disable cached tree hash, update min spec

* state_processing: fix slot bug in committee update

* tests: temporarily disable fork choice harness test

See #447

* committee cache: prevent out-of-bounds access

In the case where we tried to access the committee of a shard that didn't have a committee in the
current epoch, we were accessing elements beyond the end of the shuffling vector and panicking! This
commit adds a check to make the failure safe and explicit.

* fix bug in get_indexed_attestation and simplify

There was a bug in our implementation of get_indexed_attestation whereby
incorrect "committee indices" were used to index into the custody bitfield. The
bug was only observable in the case where some bits of the custody bitfield were
set to 1. The implementation has been simplified to remove the bug, and a test
added.

* state_proc: workaround for compact committees bug

https://github.com/ethereum/eth2.0-specs/issues/1315

* v0.8: updates to make the EF tests pass

* Remove redundant max operation checks.
* Always supply both messages when checking attestation signatures -- allowing
  verification of an attestation with no signatures.
* Swap the order of the fork and domain constant in `get_domain`, to match
  the spec.

* rustfmt

* ef_tests: add new epoch processing tests

* Integrate v0.8 into master (compiles)

* Remove unused crates, fix clippy lints

* Replace v0.6.3 tags w/ v0.8.1

* Remove old comment

* Ensure lmd ghost tests only run in release

* Update readme
This commit is contained in:
Michael Sproul
2019-07-30 12:44:51 +10:00
committed by Paul Hauner
parent 177df12149
commit a236003a7b
184 changed files with 3332 additions and 4542 deletions
+71 -56
View File
@@ -94,7 +94,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
store: Arc<T::Store>,
slot_clock: T::SlotClock,
mut genesis_state: BeaconState<T::EthSpec>,
genesis_block: BeaconBlock,
genesis_block: BeaconBlock<T::EthSpec>,
spec: ChainSpec,
log: Logger,
) -> Result<Self, Error> {
@@ -108,7 +108,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
// Also store the genesis block under the `ZERO_HASH` key.
let genesis_block_root = genesis_block.block_header().canonical_root();
store.put(&spec.zero_hash, &genesis_block)?;
store.put(&Hash256::zero(), &genesis_block)?;
let canonical_head = RwLock::new(CheckPoint::new(
genesis_block.clone(),
@@ -150,7 +150,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
spec.seconds_per_slot,
);
let last_finalized_root = p.canonical_head.beacon_state.finalized_root;
let last_finalized_root = p.canonical_head.beacon_state.finalized_checkpoint.root;
let last_finalized_block = &p.canonical_head.beacon_block;
let op_pool = p.op_pool.into_operation_pool(&p.state, &spec);
@@ -187,8 +187,11 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
/// 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>, Error> {
let bodies: Result<Vec<BeaconBlockBody>, _> = roots
pub fn get_block_bodies(
&self,
roots: &[Hash256],
) -> Result<Vec<BeaconBlockBody<T::EthSpec>>, Error> {
let bodies: Result<Vec<_>, _> = roots
.iter()
.map(|root| match self.get_block(root)? {
Some(block) => Ok(block.body),
@@ -259,7 +262,10 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
/// ## Errors
///
/// May return a database error.
pub fn get_block(&self, block_root: &Hash256) -> Result<Option<BeaconBlock>, Error> {
pub fn get_block(
&self,
block_root: &Hash256,
) -> Result<Option<BeaconBlock<T::EthSpec>>, Error> {
Ok(self.store.get(block_root)?)
}
@@ -321,15 +327,9 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
/// Returns the validator index (if any) for the given public key.
///
/// Information is retrieved from the present `beacon_state.validator_registry`.
/// Information is retrieved from the present `beacon_state.validators`.
pub fn validator_index(&self, pubkey: &PublicKey) -> Option<usize> {
for (i, validator) in self
.head()
.beacon_state
.validator_registry
.iter()
.enumerate()
{
for (i, validator) in self.head().beacon_state.validators.iter().enumerate() {
if validator.pubkey == *pubkey {
return Some(i);
}
@@ -469,9 +469,22 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
} else {
*state.get_block_root(current_epoch_start_slot)?
};
let target = Checkpoint {
epoch: state.current_epoch(),
root: target_root,
};
let previous_crosslink_root =
Hash256::from_slice(&state.get_current_crosslink(shard)?.tree_hash_root());
let parent_crosslink = state.get_current_crosslink(shard)?;
let crosslink = Crosslink {
shard,
parent_root: Hash256::from_slice(&parent_crosslink.tree_hash_root()),
start_epoch: parent_crosslink.end_epoch,
end_epoch: std::cmp::min(
target.epoch,
parent_crosslink.end_epoch + self.spec.max_epochs_per_crosslink,
),
data_root: Hash256::zero(),
};
// Collect some metrics.
self.metrics.attestation_production_successes.inc();
@@ -479,13 +492,9 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
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(),
source: state.current_justified_checkpoint.clone(),
target,
crosslink,
})
}
@@ -495,7 +504,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
/// if possible.
pub fn process_attestation(
&self,
attestation: Attestation,
attestation: Attestation<T::EthSpec>,
) -> Result<(), AttestationValidationError> {
self.metrics.attestation_processing_requests.inc();
let timer = self.metrics.attestation_processing_times.start_timer();
@@ -527,9 +536,10 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
/// Accept some deposit and queue it for inclusion in an appropriate block.
pub fn process_deposit(
&self,
index: u64,
deposit: Deposit,
) -> Result<DepositInsertStatus, DepositValidationError> {
self.op_pool.insert_deposit(deposit)
self.op_pool.insert_deposit(index, deposit)
}
/// Accept some exit and queue it for inclusion in an appropriate block.
@@ -556,7 +566,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
/// Accept some attester slashing and queue it for inclusion in an appropriate block.
pub fn process_attester_slashing(
&self,
attester_slashing: AttesterSlashing,
attester_slashing: AttesterSlashing<T::EthSpec>,
) -> Result<(), AttesterSlashingValidationError> {
self.op_pool
.insert_attester_slashing(attester_slashing, &*self.state.read(), &self.spec)
@@ -565,14 +575,18 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
/// Accept some block and attempt to add it to block DAG.
///
/// Will accept blocks from prior slots, however it will reject any block from a future slot.
pub fn process_block(&self, block: BeaconBlock) -> Result<BlockProcessingOutcome, Error> {
pub fn process_block(
&self,
block: BeaconBlock<T::EthSpec>,
) -> Result<BlockProcessingOutcome, Error> {
self.metrics.block_processing_requests.inc();
let timer = self.metrics.block_processing_times.start_timer();
let finalized_slot = self
.state
.read()
.finalized_epoch
.finalized_checkpoint
.epoch
.start_slot(T::EthSpec::slots_per_epoch());
if block.slot <= finalized_slot {
@@ -600,18 +614,17 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
});
}
if self.store.exists::<BeaconBlock>(&block_root)? {
if self.store.exists::<BeaconBlock<T::EthSpec>>(&block_root)? {
return Ok(BlockProcessingOutcome::BlockIsAlreadyKnown);
}
// Load the blocks parent block from the database, returning invalid if that block is not
// found.
let parent_block_root = block.previous_block_root;
let parent_block: BeaconBlock = match self.store.get(&parent_block_root)? {
Some(previous_block_root) => previous_block_root,
let parent_block: BeaconBlock<T::EthSpec> = match self.store.get(&block.parent_root)? {
Some(block) => block,
None => {
return Ok(BlockProcessingOutcome::ParentUnknown {
parent: parent_block_root,
parent: block.parent_root,
});
}
};
@@ -691,7 +704,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
pub fn produce_block(
&self,
randao_reveal: Signature,
) -> Result<(BeaconBlock, BeaconState<T::EthSpec>), BlockProductionError> {
) -> Result<(BeaconBlock<T::EthSpec>, BeaconState<T::EthSpec>), BlockProductionError> {
let state = self.state.read().clone();
let slot = self
.read_slot_clock()
@@ -713,7 +726,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
mut state: BeaconState<T::EthSpec>,
produce_at_slot: Slot,
randao_reveal: Signature,
) -> Result<(BeaconBlock, BeaconState<T::EthSpec>), BlockProductionError> {
) -> Result<(BeaconBlock<T::EthSpec>, BeaconState<T::EthSpec>), BlockProductionError> {
self.metrics.block_production_requests.inc();
let timer = self.metrics.block_production_times.start_timer();
@@ -724,7 +737,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
state.build_committee_cache(RelativeEpoch::Current, &self.spec)?;
let previous_block_root = if state.slot > 0 {
let parent_root = if state.slot > 0 {
*state
.get_block_root(state.slot - 1)
.map_err(|_| BlockProductionError::UnableToGetBlockRootFromState)?
@@ -740,7 +753,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
let mut block = BeaconBlock {
slot: state.slot,
previous_block_root,
parent_root,
state_root: Hash256::zero(), // Updated after the state is calculated.
signature: Signature::empty_signature(), // To be completed by a validator.
body: BeaconBlockBody {
@@ -752,12 +765,12 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
block_hash: Hash256::zero(),
},
graffiti,
proposer_slashings,
attester_slashings,
attestations: self.op_pool.get_attestations(&state, &self.spec),
deposits: self.op_pool.get_deposits(&state, &self.spec),
voluntary_exits: self.op_pool.get_voluntary_exits(&state, &self.spec),
transfers: self.op_pool.get_transfers(&state, &self.spec),
proposer_slashings: proposer_slashings.into(),
attester_slashings: attester_slashings.into(),
attestations: self.op_pool.get_attestations(&state, &self.spec).into(),
deposits: self.op_pool.get_deposits(&state).into(),
voluntary_exits: self.op_pool.get_voluntary_exits(&state, &self.spec).into(),
transfers: self.op_pool.get_transfers(&state, &self.spec).into(),
},
};
@@ -790,7 +803,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
if beacon_block_root != self.head().beacon_block_root {
self.metrics.fork_choice_changed_head.inc();
let beacon_block: BeaconBlock = self
let beacon_block: BeaconBlock<T::EthSpec> = self
.store
.get(&beacon_block_root)?
.ok_or_else(|| Error::MissingBeaconBlock(beacon_block_root))?;
@@ -805,7 +818,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
let new_slot = beacon_block.slot;
// 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.parent_root {
self.metrics.fork_choice_reorg_count.inc();
warn!(
self.log,
@@ -817,16 +830,16 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
info!(
self.log,
"new head block";
"justified_root" => format!("{}", beacon_state.current_justified_root),
"finalized_root" => format!("{}", beacon_state.finalized_root),
"justified_root" => format!("{}", beacon_state.current_justified_checkpoint.root),
"finalized_root" => format!("{}", beacon_state.finalized_checkpoint.root),
"root" => format!("{}", beacon_block_root),
"slot" => new_slot,
);
};
let old_finalized_epoch = self.head().beacon_state.finalized_epoch;
let new_finalized_epoch = beacon_state.finalized_epoch;
let finalized_root = beacon_state.finalized_root;
let old_finalized_epoch = self.head().beacon_state.finalized_checkpoint.epoch;
let new_finalized_epoch = beacon_state.finalized_checkpoint.epoch;
let finalized_root = beacon_state.finalized_checkpoint.root;
// Never revert back past a finalized epoch.
if new_finalized_epoch < old_finalized_epoch {
@@ -836,7 +849,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
})
} else {
self.update_canonical_head(CheckPoint {
beacon_block: beacon_block,
beacon_block,
beacon_block_root,
beacon_state,
beacon_state_root,
@@ -894,7 +907,7 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
) -> Result<(), Error> {
let finalized_block = self
.store
.get::<BeaconBlock>(&finalized_block_root)?
.get::<BeaconBlock<T::EthSpec>>(&finalized_block_root)?
.ok_or_else(|| Error::MissingBeaconBlock(finalized_block_root))?;
let new_finalized_epoch = finalized_block.slot.epoch(T::EthSpec::slots_per_epoch());
@@ -914,7 +927,9 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
/// Returns `true` if the given block root has not been processed.
pub fn is_new_block_root(&self, beacon_block_root: &Hash256) -> Result<bool, Error> {
Ok(!self.store.exists::<BeaconBlock>(beacon_block_root)?)
Ok(!self
.store
.exists::<BeaconBlock<T::EthSpec>>(beacon_block_root)?)
}
/// Dumps the entire canonical chain, from the head to genesis to a vector for analysis.
@@ -934,13 +949,13 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
dump.push(last_slot.clone());
loop {
let beacon_block_root = last_slot.beacon_block.previous_block_root;
let beacon_block_root = last_slot.beacon_block.parent_root;
if beacon_block_root == self.spec.zero_hash {
if beacon_block_root == Hash256::zero() {
break; // Genesis has been reached.
}
let beacon_block: BeaconBlock =
let beacon_block: BeaconBlock<T::EthSpec> =
self.store.get(&beacon_block_root)?.ok_or_else(|| {
Error::DBInconsistent(format!("Missing block {}", beacon_block_root))
})?;
+3 -3
View File
@@ -6,7 +6,7 @@ use types::{BeaconBlock, BeaconState, EthSpec, Hash256};
/// head, justified head and finalized head.
#[derive(Clone, Serialize, PartialEq, Debug, Encode, Decode)]
pub struct CheckPoint<E: EthSpec> {
pub beacon_block: BeaconBlock,
pub beacon_block: BeaconBlock<E>,
pub beacon_block_root: Hash256,
pub beacon_state: BeaconState<E>,
pub beacon_state_root: Hash256,
@@ -15,7 +15,7 @@ pub struct CheckPoint<E: EthSpec> {
impl<E: EthSpec> CheckPoint<E> {
/// Create a new checkpoint.
pub fn new(
beacon_block: BeaconBlock,
beacon_block: BeaconBlock<E>,
beacon_block_root: Hash256,
beacon_state: BeaconState<E>,
beacon_state_root: Hash256,
@@ -31,7 +31,7 @@ impl<E: EthSpec> CheckPoint<E> {
/// Update all fields of the checkpoint.
pub fn update(
&mut self,
beacon_block: BeaconBlock,
beacon_block: BeaconBlock<E>,
beacon_block_root: Hash256,
beacon_state: BeaconState<E>,
beacon_state_root: Hash256,
+18 -18
View File
@@ -1,6 +1,6 @@
use crate::{BeaconChain, BeaconChainTypes};
use lmd_ghost::LmdGhost;
use state_processing::common::get_attesting_indices_unsorted;
use state_processing::common::get_attesting_indices;
use std::sync::Arc;
use store::{Error as StoreError, Store};
use types::{Attestation, BeaconBlock, BeaconState, BeaconStateError, Epoch, EthSpec, Hash256};
@@ -33,7 +33,7 @@ impl<T: BeaconChainTypes> ForkChoice<T> {
/// block.
pub fn new(
store: Arc<T::Store>,
genesis_block: &BeaconBlock,
genesis_block: &BeaconBlock<T::EthSpec>,
genesis_block_root: Hash256,
) -> Self {
Self {
@@ -55,18 +55,21 @@ impl<T: BeaconChainTypes> ForkChoice<T> {
let state = chain.current_state();
let (block_root, block_slot) =
if state.current_epoch() + 1 > state.current_justified_epoch {
if state.current_epoch() + 1 > state.current_justified_checkpoint.epoch {
(
state.current_justified_root,
start_slot(state.current_justified_epoch),
state.current_justified_checkpoint.root,
start_slot(state.current_justified_checkpoint.epoch),
)
} else {
(state.finalized_root, start_slot(state.finalized_epoch))
(
state.finalized_checkpoint.root,
start_slot(state.finalized_checkpoint.epoch),
)
};
let block = chain
.store
.get::<BeaconBlock>(&block_root)?
.get::<BeaconBlock<T::EthSpec>>(&block_root)?
.ok_or_else(|| Error::MissingBlock(block_root))?;
// Resolve the `0x00.. 00` alias back to genesis
@@ -87,7 +90,7 @@ impl<T: BeaconChainTypes> ForkChoice<T> {
// A function that returns the weight for some validator index.
let weight = |validator_index: usize| -> Option<u64> {
start_state
.validator_registry
.validators
.get(validator_index)
.map(|v| v.effective_balance)
};
@@ -104,7 +107,7 @@ impl<T: BeaconChainTypes> ForkChoice<T> {
pub fn process_block(
&self,
state: &BeaconState<T::EthSpec>,
block: &BeaconBlock,
block: &BeaconBlock<T::EthSpec>,
block_root: Hash256,
) -> Result<()> {
// Note: we never count the block as a latest message, only attestations.
@@ -125,7 +128,7 @@ impl<T: BeaconChainTypes> ForkChoice<T> {
fn process_attestation_from_block(
&self,
state: &BeaconState<T::EthSpec>,
attestation: &Attestation,
attestation: &Attestation<T::EthSpec>,
) -> Result<()> {
let block_hash = attestation.data.beacon_block_root;
@@ -147,16 +150,13 @@ impl<T: BeaconChainTypes> ForkChoice<T> {
if block_hash != Hash256::zero()
&& self
.store
.exists::<BeaconBlock>(&block_hash)
.exists::<BeaconBlock<T::EthSpec>>(&block_hash)
.unwrap_or(false)
{
let validator_indices = get_attesting_indices_unsorted(
state,
&attestation.data,
&attestation.aggregation_bitfield,
)?;
let validator_indices =
get_attesting_indices(state, &attestation.data, &attestation.aggregation_bits)?;
let block_slot = state.get_attestation_slot(&attestation.data)?;
let block_slot = state.get_attestation_data_slot(&attestation.data)?;
for validator_index in validator_indices {
self.backend
@@ -173,7 +173,7 @@ impl<T: BeaconChainTypes> ForkChoice<T> {
/// `finalized_block_root` must be the root of `finalized_block`.
pub fn process_finalization(
&self,
finalized_block: &BeaconBlock,
finalized_block: &BeaconBlock<T::EthSpec>,
finalized_block_root: Hash256,
) -> Result<()> {
self.backend
@@ -11,7 +11,7 @@ pub const BEACON_CHAIN_DB_KEY: &str = "PERSISTEDBEACONCHAINPERSISTEDBEA";
#[derive(Encode, Decode)]
pub struct PersistedBeaconChain<T: BeaconChainTypes> {
pub canonical_head: CheckPoint<T::EthSpec>,
pub op_pool: PersistedOperationPool,
pub op_pool: PersistedOperationPool<T::EthSpec>,
pub genesis_block_root: Hash256,
pub state: BeaconState<T::EthSpec>,
}
+10 -13
View File
@@ -11,7 +11,7 @@ use store::Store;
use tree_hash::{SignedRoot, TreeHash};
use types::{
test_utils::TestingBeaconStateBuilder, AggregateSignature, Attestation,
AttestationDataAndCustodyBit, BeaconBlock, BeaconState, Bitfield, ChainSpec, Domain, EthSpec,
AttestationDataAndCustodyBit, BeaconBlock, BeaconState, BitList, ChainSpec, Domain, EthSpec,
Hash256, Keypair, RelativeEpoch, SecretKey, Signature, Slot,
};
@@ -216,7 +216,7 @@ where
mut state: BeaconState<E>,
slot: Slot,
block_strategy: BlockStrategy,
) -> (BeaconBlock, BeaconState<E>) {
) -> (BeaconBlock<E>, BeaconState<E>) {
if slot < state.slot {
panic!("produce slot cannot be prior to the state slot");
}
@@ -302,12 +302,9 @@ where
)
.expect("should produce attestation data");
let mut aggregation_bitfield = Bitfield::new();
aggregation_bitfield.set(i, true);
aggregation_bitfield.set(committee_size, false);
let mut custody_bitfield = Bitfield::new();
custody_bitfield.set(committee_size, false);
let mut aggregation_bits = BitList::with_capacity(committee_size).unwrap();
aggregation_bits.set(i, true).unwrap();
let custody_bits = BitList::with_capacity(committee_size).unwrap();
let signature = {
let message = AttestationDataAndCustodyBit {
@@ -317,7 +314,7 @@ where
.tree_hash_root();
let domain =
spec.get_domain(data.target_epoch, Domain::Attestation, fork);
spec.get_domain(data.target.epoch, Domain::Attestation, fork);
let mut agg_sig = AggregateSignature::new();
agg_sig.add(&Signature::new(
@@ -330,9 +327,9 @@ where
};
let attestation = Attestation {
aggregation_bitfield,
aggregation_bits,
data,
custody_bitfield,
custody_bits,
signature,
};
@@ -376,9 +373,9 @@ where
let faulty_head = self.extend_chain(
faulty_fork_blocks,
BlockStrategy::ForkCanonicalChainAt {
previous_slot: Slot::from(initial_head_slot),
previous_slot: initial_head_slot,
// `initial_head_slot + 2` means one slot is skipped.
first_slot: Slot::from(initial_head_slot + 2),
first_slot: initial_head_slot + 2,
},
AttestationStrategy::SomeValidators(faulty_validators.to_vec()),
);
+10 -10
View File
@@ -93,12 +93,12 @@ fn finalizes_with_full_participation() {
"head should be at the expected epoch"
);
assert_eq!(
state.current_justified_epoch,
state.current_justified_checkpoint.epoch,
state.current_epoch() - 1,
"the head should be justified one behind the current epoch"
);
assert_eq!(
state.finalized_epoch,
state.finalized_checkpoint.epoch,
state.current_epoch() - 2,
"the head should be finalized two behind the current epoch"
);
@@ -136,12 +136,12 @@ fn finalizes_with_two_thirds_participation() {
// included in blocks during that epoch.
assert_eq!(
state.current_justified_epoch,
state.current_justified_checkpoint.epoch,
state.current_epoch() - 2,
"the head should be justified two behind the current epoch"
);
assert_eq!(
state.finalized_epoch,
state.finalized_checkpoint.epoch,
state.current_epoch() - 4,
"the head should be finalized three behind the current epoch"
);
@@ -175,11 +175,11 @@ fn does_not_finalize_with_less_than_two_thirds_participation() {
"head should be at the expected epoch"
);
assert_eq!(
state.current_justified_epoch, 0,
state.current_justified_checkpoint.epoch, 0,
"no epoch should have been justified"
);
assert_eq!(
state.finalized_epoch, 0,
state.finalized_checkpoint.epoch, 0,
"no epoch should have been finalized"
);
}
@@ -208,11 +208,11 @@ fn does_not_finalize_without_attestation() {
"head should be at the expected epoch"
);
assert_eq!(
state.current_justified_epoch, 0,
state.current_justified_checkpoint.epoch, 0,
"no epoch should have been justified"
);
assert_eq!(
state.finalized_epoch, 0,
state.finalized_checkpoint.epoch, 0,
"no epoch should have been finalized"
);
}
@@ -233,10 +233,10 @@ fn roundtrip_operation_pool() {
// Add some deposits
let rng = &mut XorShiftRng::from_seed([66; 16]);
for _ in 0..rng.gen_range(1, VALIDATOR_COUNT) {
for i in 0..rng.gen_range(1, VALIDATOR_COUNT) {
harness
.chain
.process_deposit(Deposit::random_for_test(rng))
.process_deposit(i as u64, Deposit::random_for_test(rng))
.unwrap();
}
+28 -26
View File
@@ -18,31 +18,31 @@ use slog::{o, trace, warn};
use ssz::{ssz_encode, Decode, DecodeError, Encode};
use std::num::NonZeroU32;
use std::time::Duration;
use types::{Attestation, BeaconBlock};
use types::{Attestation, BeaconBlock, EthSpec};
/// Builds the network behaviour that manages the core protocols of eth2.
/// This core behaviour is managed by `Behaviour` which adds peer management to all core
/// behaviours.
#[derive(NetworkBehaviour)]
#[behaviour(out_event = "BehaviourEvent", poll_method = "poll")]
pub struct Behaviour<TSubstream: AsyncRead + AsyncWrite> {
#[behaviour(out_event = "BehaviourEvent<E>", poll_method = "poll")]
pub struct Behaviour<TSubstream: AsyncRead + AsyncWrite, E: EthSpec> {
/// The routing pub-sub mechanism for eth2.
gossipsub: Gossipsub<TSubstream>,
/// The serenity RPC specified in the wire-0 protocol.
serenity_rpc: RPC<TSubstream>,
serenity_rpc: RPC<TSubstream, E>,
/// Keep regular connection to peers and disconnect if absent.
ping: Ping<TSubstream>,
/// Kademlia for peer discovery.
discovery: Discovery<TSubstream>,
#[behaviour(ignore)]
/// The events generated by this behaviour to be consumed in the swarm poll.
events: Vec<BehaviourEvent>,
events: Vec<BehaviourEvent<E>>,
/// Logger for behaviour actions.
#[behaviour(ignore)]
log: slog::Logger,
}
impl<TSubstream: AsyncRead + AsyncWrite> Behaviour<TSubstream> {
impl<TSubstream: AsyncRead + AsyncWrite, E: EthSpec> Behaviour<TSubstream, E> {
pub fn new(
local_key: &Keypair,
net_conf: &NetworkConfig,
@@ -68,8 +68,8 @@ impl<TSubstream: AsyncRead + AsyncWrite> Behaviour<TSubstream> {
}
// Implement the NetworkBehaviourEventProcess trait so that we can derive NetworkBehaviour for Behaviour
impl<TSubstream: AsyncRead + AsyncWrite> NetworkBehaviourEventProcess<GossipsubEvent>
for Behaviour<TSubstream>
impl<TSubstream: AsyncRead + AsyncWrite, E: EthSpec> NetworkBehaviourEventProcess<GossipsubEvent>
for Behaviour<TSubstream, E>
{
fn inject_event(&mut self, event: GossipsubEvent) {
match event {
@@ -101,8 +101,8 @@ impl<TSubstream: AsyncRead + AsyncWrite> NetworkBehaviourEventProcess<GossipsubE
}
}
impl<TSubstream: AsyncRead + AsyncWrite> NetworkBehaviourEventProcess<RPCMessage>
for Behaviour<TSubstream>
impl<TSubstream: AsyncRead + AsyncWrite, E: EthSpec> NetworkBehaviourEventProcess<RPCMessage>
for Behaviour<TSubstream, E>
{
fn inject_event(&mut self, event: RPCMessage) {
match event {
@@ -119,19 +119,19 @@ impl<TSubstream: AsyncRead + AsyncWrite> NetworkBehaviourEventProcess<RPCMessage
}
}
impl<TSubstream: AsyncRead + AsyncWrite> NetworkBehaviourEventProcess<PingEvent>
for Behaviour<TSubstream>
impl<TSubstream: AsyncRead + AsyncWrite, E: EthSpec> NetworkBehaviourEventProcess<PingEvent>
for Behaviour<TSubstream, E>
{
fn inject_event(&mut self, _event: PingEvent) {
// not interested in ping responses at the moment.
}
}
impl<TSubstream: AsyncRead + AsyncWrite> Behaviour<TSubstream> {
impl<TSubstream: AsyncRead + AsyncWrite, E: EthSpec> Behaviour<TSubstream, E> {
/// Consumes the events list when polled.
fn poll<TBehaviourIn>(
&mut self,
) -> Async<NetworkBehaviourAction<TBehaviourIn, BehaviourEvent>> {
) -> Async<NetworkBehaviourAction<TBehaviourIn, BehaviourEvent<E>>> {
if !self.events.is_empty() {
return Async::Ready(NetworkBehaviourAction::GenerateEvent(self.events.remove(0)));
}
@@ -140,8 +140,8 @@ impl<TSubstream: AsyncRead + AsyncWrite> Behaviour<TSubstream> {
}
}
impl<TSubstream: AsyncRead + AsyncWrite> NetworkBehaviourEventProcess<Discv5Event>
for Behaviour<TSubstream>
impl<TSubstream: AsyncRead + AsyncWrite, E: EthSpec> NetworkBehaviourEventProcess<Discv5Event>
for Behaviour<TSubstream, E>
{
fn inject_event(&mut self, _event: Discv5Event) {
// discv5 has no events to inject
@@ -149,7 +149,7 @@ impl<TSubstream: AsyncRead + AsyncWrite> NetworkBehaviourEventProcess<Discv5Even
}
/// Implements the combined behaviour for the libp2p service.
impl<TSubstream: AsyncRead + AsyncWrite> Behaviour<TSubstream> {
impl<TSubstream: AsyncRead + AsyncWrite, E: EthSpec> Behaviour<TSubstream, E> {
/* Pubsub behaviour functions */
/// Subscribes to a gossipsub topic.
@@ -158,7 +158,7 @@ impl<TSubstream: AsyncRead + AsyncWrite> Behaviour<TSubstream> {
}
/// Publishes a message on the pubsub (gossipsub) behaviour.
pub fn publish(&mut self, topics: Vec<Topic>, message: PubsubMessage) {
pub fn publish(&mut self, topics: Vec<Topic>, message: PubsubMessage<E>) {
let message_bytes = ssz_encode(&message);
for topic in topics {
self.gossipsub.publish(topic, message_bytes.clone());
@@ -179,28 +179,28 @@ impl<TSubstream: AsyncRead + AsyncWrite> Behaviour<TSubstream> {
}
/// The types of events than can be obtained from polling the behaviour.
pub enum BehaviourEvent {
pub enum BehaviourEvent<E: EthSpec> {
RPC(PeerId, RPCEvent),
PeerDialed(PeerId),
PeerDisconnected(PeerId),
GossipMessage {
source: PeerId,
topics: Vec<TopicHash>,
message: Box<PubsubMessage>,
message: Box<PubsubMessage<E>>,
},
}
/// Messages that are passed to and from the pubsub (Gossipsub) behaviour.
#[derive(Debug, Clone, PartialEq)]
pub enum PubsubMessage {
pub enum PubsubMessage<E: EthSpec> {
/// Gossipsub message providing notification of a new block.
Block(BeaconBlock),
Block(BeaconBlock<E>),
/// Gossipsub message providing notification of a new attestation.
Attestation(Attestation),
Attestation(Attestation<E>),
}
//TODO: Correctly encode/decode enums. Prefixing with integer for now.
impl Encode for PubsubMessage {
impl<E: EthSpec> Encode for PubsubMessage<E> {
fn is_ssz_fixed_len() -> bool {
false
}
@@ -229,7 +229,7 @@ impl Encode for PubsubMessage {
}
}
impl Decode for PubsubMessage {
impl<E: EthSpec> Decode for PubsubMessage<E> {
fn is_ssz_fixed_len() -> bool {
false
}
@@ -264,7 +264,9 @@ mod test {
#[test]
fn ssz_encoding() {
let original = PubsubMessage::Block(BeaconBlock::empty(&MainnetEthSpec::default_spec()));
let original = PubsubMessage::Block(BeaconBlock::<MainnetEthSpec>::empty(
&MainnetEthSpec::default_spec(),
));
let encoded = ssz_encode(&original);
+2 -2
View File
@@ -271,7 +271,7 @@ fn load_enr(
// Note: Discovery should update the ENR record's IP to the external IP as seen by the
// majority of our peers.
let mut local_enr = EnrBuilder::new()
.ip(config.discovery_address.into())
.ip(config.discovery_address)
.tcp(config.libp2p_port)
.udp(config.discovery_port)
.build(&local_key)
@@ -318,7 +318,7 @@ fn load_enr(
Ok(local_enr)
}
fn save_enr_to_disc(dir: &Path, enr: &Enr, log: &slog::Logger) -> () {
fn save_enr_to_disc(dir: &Path, enr: &Enr, log: &slog::Logger) {
let _ = std::fs::create_dir_all(dir);
match File::create(dir.join(Path::new(ENR_FILENAME)))
.and_then(|mut f| f.write_all(&enr.to_base64().as_bytes()))
@@ -65,7 +65,7 @@ where
dst.clear();
dst.reserve(1);
dst.put_u8(item.as_u8());
return self.inner.encode(item, dst);
self.inner.encode(item, dst)
}
}
@@ -120,16 +120,14 @@ where
if RPCErrorResponse::is_response(response_code) {
// decode an actual response
return self
.inner
self.inner
.decode(src)
.map(|r| r.map(|resp| RPCErrorResponse::Success(resp)));
.map(|r| r.map(RPCErrorResponse::Success))
} else {
// decode an error
return self
.inner
self.inner
.decode_error(src)
.map(|r| r.map(|resp| RPCErrorResponse::from_error(response_code, resp)));
.map(|r| r.map(|resp| RPCErrorResponse::from_error(response_code, resp)))
}
}
}
+17 -12
View File
@@ -2,6 +2,7 @@ use super::methods::{RPCErrorResponse, RPCResponse, RequestId};
use super::protocol::{RPCError, RPCProtocol, RPCRequest};
use super::RPCEvent;
use crate::rpc::protocol::{InboundFramed, OutboundFramed};
use core::marker::PhantomData;
use fnv::FnvHashMap;
use futures::prelude::*;
use libp2p::core::protocols_handler::{
@@ -11,14 +12,16 @@ use libp2p::core::upgrade::{InboundUpgrade, OutboundUpgrade};
use smallvec::SmallVec;
use std::time::{Duration, Instant};
use tokio_io::{AsyncRead, AsyncWrite};
use types::EthSpec;
/// The time (in seconds) before a substream that is awaiting a response times out.
pub const RESPONSE_TIMEOUT: u64 = 9;
/// Implementation of `ProtocolsHandler` for the RPC protocol.
pub struct RPCHandler<TSubstream>
pub struct RPCHandler<TSubstream, E>
where
TSubstream: AsyncRead + AsyncWrite,
E: EthSpec,
{
/// The upgrade for inbound substreams.
listen_protocol: SubstreamProtocol<RPCProtocol>,
@@ -52,6 +55,9 @@ where
/// After the given duration has elapsed, an inactive connection will shutdown.
inactive_timeout: Duration,
/// Phantom EthSpec.
_phantom: PhantomData<E>,
}
/// An outbound substream is waiting a response from the user.
@@ -84,9 +90,10 @@ where
},
}
impl<TSubstream> RPCHandler<TSubstream>
impl<TSubstream, E> RPCHandler<TSubstream, E>
where
TSubstream: AsyncRead + AsyncWrite,
E: EthSpec,
{
pub fn new(
listen_protocol: SubstreamProtocol<RPCProtocol>,
@@ -104,6 +111,7 @@ where
max_dial_negotiated: 8,
keep_alive: KeepAlive::Yes,
inactive_timeout,
_phantom: PhantomData,
}
}
@@ -137,18 +145,20 @@ where
}
}
impl<TSubstream> Default for RPCHandler<TSubstream>
impl<TSubstream, E> Default for RPCHandler<TSubstream, E>
where
TSubstream: AsyncRead + AsyncWrite,
E: EthSpec,
{
fn default() -> Self {
RPCHandler::new(SubstreamProtocol::new(RPCProtocol), Duration::from_secs(30))
}
}
impl<TSubstream> ProtocolsHandler for RPCHandler<TSubstream>
impl<TSubstream, E> ProtocolsHandler for RPCHandler<TSubstream, E>
where
TSubstream: AsyncRead + AsyncWrite,
E: EthSpec,
{
type InEvent = RPCEvent;
type OutEvent = RPCEvent;
@@ -276,13 +286,8 @@ where
}
// remove any streams that have expired
self.waiting_substreams.retain(|_k, waiting_stream| {
if Instant::now() > waiting_stream.timeout {
false
} else {
true
}
});
self.waiting_substreams
.retain(|_k, waiting_stream| Instant::now() <= waiting_stream.timeout);
// drive streams that need to be processed
for n in (0..self.substreams.len()).rev() {
@@ -334,7 +339,7 @@ where
}
Err(e) => {
return Ok(Async::Ready(ProtocolsHandlerEvent::Custom(
RPCEvent::Error(rpc_event.id(), e.into()),
RPCEvent::Error(rpc_event.id(), e),
)))
}
},
+3 -3
View File
@@ -2,7 +2,7 @@
use ssz::{impl_decode_via_from, impl_encode_via_from};
use ssz_derive::{Decode, Encode};
use types::{BeaconBlockBody, Epoch, Hash256, Slot};
use types::{BeaconBlockBody, Epoch, EthSpec, Hash256, Slot};
/* Request/Response data structures for RPC methods */
@@ -154,11 +154,11 @@ pub struct BeaconBlockBodiesResponse {
}
/// The decoded version of `BeaconBlockBodiesResponse` which is expected in `SimpleSync`.
pub struct DecodedBeaconBlockBodiesResponse {
pub struct DecodedBeaconBlockBodiesResponse<E: EthSpec> {
/// The list of hashes sent in the request to get this response.
pub block_roots: Vec<Hash256>,
/// The valid decoded block bodies.
pub block_bodies: Vec<BeaconBlockBody>,
pub block_bodies: Vec<BeaconBlockBody<E>>,
}
/// Request values for tree hashes which yield a blocks `state_root`.
+7 -5
View File
@@ -16,6 +16,7 @@ pub use protocol::{RPCError, RPCProtocol, RPCRequest};
use slog::o;
use std::marker::PhantomData;
use tokio::io::{AsyncRead, AsyncWrite};
use types::EthSpec;
pub(crate) mod codec;
mod handler;
@@ -49,16 +50,16 @@ impl RPCEvent {
/// Implements the libp2p `NetworkBehaviour` trait and therefore manages network-level
/// logic.
pub struct RPC<TSubstream> {
pub struct RPC<TSubstream, E: EthSpec> {
/// Queue of events to processed.
events: Vec<NetworkBehaviourAction<RPCEvent, RPCMessage>>,
/// Pins the generic substream.
marker: PhantomData<TSubstream>,
marker: PhantomData<(TSubstream, E)>,
/// Slog logger for RPC behaviour.
_log: slog::Logger,
}
impl<TSubstream> RPC<TSubstream> {
impl<TSubstream, E: EthSpec> RPC<TSubstream, E> {
pub fn new(log: &slog::Logger) -> Self {
let log = log.new(o!("Service" => "Libp2p-RPC"));
RPC {
@@ -79,11 +80,12 @@ impl<TSubstream> RPC<TSubstream> {
}
}
impl<TSubstream> NetworkBehaviour for RPC<TSubstream>
impl<TSubstream, E> NetworkBehaviour for RPC<TSubstream, E>
where
TSubstream: AsyncRead + AsyncWrite,
E: EthSpec,
{
type ProtocolsHandler = RPCHandler<TSubstream>;
type ProtocolsHandler = RPCHandler<TSubstream, E>;
type OutEvent = RPCMessage;
fn new_handler(&mut self) -> Self::ProtocolsHandler {
+9 -8
View File
@@ -21,24 +21,25 @@ use std::fs::File;
use std::io::prelude::*;
use std::io::{Error, ErrorKind};
use std::time::Duration;
use types::EthSpec;
type Libp2pStream = Boxed<(PeerId, StreamMuxerBox), Error>;
type Libp2pBehaviour = Behaviour<Substream<StreamMuxerBox>>;
type Libp2pBehaviour<E> = Behaviour<Substream<StreamMuxerBox>, E>;
const NETWORK_KEY_FILENAME: &str = "key";
/// The configuration and state of the libp2p components for the beacon node.
pub struct Service {
pub struct Service<E: EthSpec> {
/// The libp2p Swarm handler.
//TODO: Make this private
pub swarm: Swarm<Libp2pStream, Libp2pBehaviour>,
pub swarm: Swarm<Libp2pStream, Libp2pBehaviour<E>>,
/// This node's PeerId.
_local_peer_id: PeerId,
/// The libp2p logger handle.
pub log: slog::Logger,
}
impl Service {
impl<E: EthSpec> Service<E> {
pub fn new(config: NetworkConfig, log: slog::Logger) -> error::Result<Self> {
debug!(log, "Network-libp2p Service starting");
@@ -103,8 +104,8 @@ impl Service {
}
}
impl Stream for Service {
type Item = Libp2pEvent;
impl<E: EthSpec> Stream for Service<E> {
type Item = Libp2pEvent<E>;
type Error = crate::error::Error;
fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
@@ -178,7 +179,7 @@ fn build_transport(local_private_key: Keypair) -> Boxed<(PeerId, StreamMuxerBox)
}
/// Events that can be obtained from polling the Libp2p Service.
pub enum Libp2pEvent {
pub enum Libp2pEvent<E: EthSpec> {
/// An RPC response request has been received on the swarm.
RPC(PeerId, RPCEvent),
/// Initiated the connection to a new peer.
@@ -189,7 +190,7 @@ pub enum Libp2pEvent {
PubsubMessage {
source: PeerId,
topics: Vec<TopicHash>,
message: Box<PubsubMessage>,
message: Box<PubsubMessage<E>>,
},
}
+1 -1
View File
@@ -76,7 +76,7 @@ pub fn create_iron_http_server<T: BeaconChainTypes + 'static>(
pub fn start_service<T: BeaconChainTypes + 'static>(
config: &HttpServerConfig,
executor: &TaskExecutor,
_network_chan: mpsc::UnboundedSender<NetworkMessage>,
_network_chan: mpsc::UnboundedSender<NetworkMessage<T::EthSpec>>,
beacon_chain: Arc<BeaconChain<T>>,
db_path: PathBuf,
metrics_registry: Registry,
@@ -117,22 +117,23 @@ impl LocalMetrics {
beacon_chain
.head()
.beacon_state
.current_justified_root
.current_justified_checkpoint
.root
.to_low_u64_le() as i64,
);
self.finalized_beacon_block_root.set(
beacon_chain
.head()
.beacon_state
.finalized_root
.finalized_checkpoint
.root
.to_low_u64_le() as i64,
);
self.validator_count
.set(state.validator_registry.len() as i64);
self.validator_count.set(state.validators.len() as i64);
self.justified_epoch
.set(state.current_justified_epoch.as_u64() as i64);
.set(state.current_justified_checkpoint.epoch.as_u64() as i64);
self.finalized_epoch
.set(state.finalized_epoch.as_u64() as i64);
.set(state.finalized_checkpoint.epoch.as_u64() as i64);
if SHOULD_SUM_VALIDATOR_BALANCES {
self.validator_balances_sum
.set(state.balances.iter().sum::<u64>() as i64);
+13 -13
View File
@@ -14,7 +14,7 @@ use slog::{debug, warn};
use ssz::{Decode, DecodeError};
use std::sync::Arc;
use tokio::sync::mpsc;
use types::BeaconBlockHeader;
use types::{BeaconBlockHeader, EthSpec};
/// Handles messages received from the network and client and organises syncing.
pub struct MessageHandler<T: BeaconChainTypes> {
@@ -23,14 +23,14 @@ pub struct MessageHandler<T: BeaconChainTypes> {
/// The syncing framework.
sync: SimpleSync<T>,
/// The context required to send messages to, and process messages from peers.
network_context: NetworkContext,
network_context: NetworkContext<T::EthSpec>,
/// The `MessageHandler` logger.
log: slog::Logger,
}
/// Types of messages the handler can receive.
#[derive(Debug)]
pub enum HandlerMessage {
pub enum HandlerMessage<E: EthSpec> {
/// We have initiated a connection to a new peer.
PeerDialed(PeerId),
/// Peer has disconnected,
@@ -38,17 +38,17 @@ pub enum HandlerMessage {
/// An RPC response/request has been received.
RPC(PeerId, RPCEvent),
/// A gossip message has been received.
PubsubMessage(PeerId, Box<PubsubMessage>),
PubsubMessage(PeerId, Box<PubsubMessage<E>>),
}
impl<T: BeaconChainTypes + 'static> MessageHandler<T> {
/// Initializes and runs the MessageHandler.
pub fn spawn(
beacon_chain: Arc<BeaconChain<T>>,
network_send: mpsc::UnboundedSender<NetworkMessage>,
network_send: mpsc::UnboundedSender<NetworkMessage<T::EthSpec>>,
executor: &tokio::runtime::TaskExecutor,
log: slog::Logger,
) -> error::Result<mpsc::UnboundedSender<HandlerMessage>> {
) -> error::Result<mpsc::UnboundedSender<HandlerMessage<T::EthSpec>>> {
debug!(log, "Service starting");
let (handler_send, handler_recv) = mpsc::unbounded_channel();
@@ -78,7 +78,7 @@ impl<T: BeaconChainTypes + 'static> MessageHandler<T> {
}
/// Handle all messages incoming from the network service.
fn handle_message(&mut self, message: HandlerMessage) {
fn handle_message(&mut self, message: HandlerMessage<T::EthSpec>) {
match message {
// we have initiated a connection to a peer
HandlerMessage::PeerDialed(peer_id) => {
@@ -222,7 +222,7 @@ impl<T: BeaconChainTypes + 'static> MessageHandler<T> {
fn decode_block_bodies(
&self,
bodies_response: BeaconBlockBodiesResponse,
) -> Result<DecodedBeaconBlockBodiesResponse, DecodeError> {
) -> Result<DecodedBeaconBlockBodiesResponse<T::EthSpec>, DecodeError> {
//TODO: Implement faster block verification before decoding entirely
let block_bodies = Vec::from_ssz_bytes(&bodies_response.block_bodies)?;
Ok(DecodedBeaconBlockBodiesResponse {
@@ -249,7 +249,7 @@ impl<T: BeaconChainTypes + 'static> MessageHandler<T> {
}
/// Handle RPC messages
fn handle_gossip(&mut self, peer_id: PeerId, gossip_message: PubsubMessage) {
fn handle_gossip(&mut self, peer_id: PeerId, gossip_message: PubsubMessage<T::EthSpec>) {
match gossip_message {
PubsubMessage::Block(message) => {
let _should_forward_on =
@@ -265,15 +265,15 @@ impl<T: BeaconChainTypes + 'static> MessageHandler<T> {
}
// TODO: RPC Rewrite makes this struct fairly pointless
pub struct NetworkContext {
pub struct NetworkContext<E: EthSpec> {
/// The network channel to relay messages to the Network service.
network_send: mpsc::UnboundedSender<NetworkMessage>,
network_send: mpsc::UnboundedSender<NetworkMessage<E>>,
/// The `MessageHandler` logger.
log: slog::Logger,
}
impl NetworkContext {
pub fn new(network_send: mpsc::UnboundedSender<NetworkMessage>, log: slog::Logger) -> Self {
impl<E: EthSpec> NetworkContext<E> {
pub fn new(network_send: mpsc::UnboundedSender<NetworkMessage<E>>, log: slog::Logger) -> Self {
Self { network_send, log }
}
+17 -16
View File
@@ -2,6 +2,7 @@ use crate::error;
use crate::message_handler::{HandlerMessage, MessageHandler};
use crate::NetworkConfig;
use beacon_chain::{BeaconChain, BeaconChainTypes};
use core::marker::PhantomData;
use eth2_libp2p::Service as LibP2PService;
use eth2_libp2p::Topic;
use eth2_libp2p::{Libp2pEvent, PeerId};
@@ -10,16 +11,16 @@ use futures::prelude::*;
use futures::Stream;
use parking_lot::Mutex;
use slog::{debug, info, o, trace};
use std::marker::PhantomData;
use std::sync::Arc;
use tokio::runtime::TaskExecutor;
use tokio::sync::{mpsc, oneshot};
use types::EthSpec;
/// Service that handles communication between internal services and the eth2_libp2p network service.
pub struct Service<T: BeaconChainTypes> {
libp2p_service: Arc<Mutex<LibP2PService>>,
libp2p_service: Arc<Mutex<LibP2PService<T::EthSpec>>>,
_libp2p_exit: oneshot::Sender<()>,
_network_send: mpsc::UnboundedSender<NetworkMessage>,
_network_send: mpsc::UnboundedSender<NetworkMessage<T::EthSpec>>,
_phantom: PhantomData<T>, //message_handler: MessageHandler,
//message_handler_send: Sender<HandlerMessage>
}
@@ -30,9 +31,9 @@ impl<T: BeaconChainTypes + 'static> Service<T> {
config: &NetworkConfig,
executor: &TaskExecutor,
log: slog::Logger,
) -> error::Result<(Arc<Self>, mpsc::UnboundedSender<NetworkMessage>)> {
) -> error::Result<(Arc<Self>, mpsc::UnboundedSender<NetworkMessage<T::EthSpec>>)> {
// build the network channel
let (network_send, network_recv) = mpsc::unbounded_channel::<NetworkMessage>();
let (network_send, network_recv) = mpsc::unbounded_channel::<NetworkMessage<_>>();
// launch message handler thread
let message_handler_log = log.new(o!("Service" => "MessageHandler"));
let message_handler_send = MessageHandler::spawn(
@@ -64,15 +65,15 @@ impl<T: BeaconChainTypes + 'static> Service<T> {
Ok((Arc::new(network_service), network_send))
}
pub fn libp2p_service(&self) -> Arc<Mutex<LibP2PService>> {
pub fn libp2p_service(&self) -> Arc<Mutex<LibP2PService<T::EthSpec>>> {
self.libp2p_service.clone()
}
}
fn spawn_service(
libp2p_service: Arc<Mutex<LibP2PService>>,
network_recv: mpsc::UnboundedReceiver<NetworkMessage>,
message_handler_send: mpsc::UnboundedSender<HandlerMessage>,
fn spawn_service<E: EthSpec>(
libp2p_service: Arc<Mutex<LibP2PService<E>>>,
network_recv: mpsc::UnboundedReceiver<NetworkMessage<E>>,
message_handler_send: mpsc::UnboundedSender<HandlerMessage<E>>,
executor: &TaskExecutor,
log: slog::Logger,
) -> error::Result<tokio::sync::oneshot::Sender<()>> {
@@ -98,10 +99,10 @@ fn spawn_service(
}
//TODO: Potentially handle channel errors
fn network_service(
libp2p_service: Arc<Mutex<LibP2PService>>,
mut network_recv: mpsc::UnboundedReceiver<NetworkMessage>,
mut message_handler_send: mpsc::UnboundedSender<HandlerMessage>,
fn network_service<E: EthSpec>(
libp2p_service: Arc<Mutex<LibP2PService<E>>>,
mut network_recv: mpsc::UnboundedReceiver<NetworkMessage<E>>,
mut message_handler_send: mpsc::UnboundedSender<HandlerMessage<E>>,
log: slog::Logger,
) -> impl futures::Future<Item = (), Error = eth2_libp2p::error::Error> {
futures::future::poll_fn(move || -> Result<_, eth2_libp2p::error::Error> {
@@ -175,14 +176,14 @@ fn network_service(
/// Types of messages that the network service can receive.
#[derive(Debug)]
pub enum NetworkMessage {
pub enum NetworkMessage<E: EthSpec> {
/// Send a message to libp2p service.
//TODO: Define typing for messages across the wire
Send(PeerId, OutgoingMessage),
/// Publish a message to pubsub mechanism.
Publish {
topics: Vec<Topic>,
message: Box<PubsubMessage>,
message: Box<PubsubMessage<E>>,
},
}
+28 -21
View File
@@ -6,7 +6,7 @@ use std::collections::HashMap;
use std::sync::Arc;
use std::time::{Duration, Instant};
use tree_hash::TreeHash;
use types::{BeaconBlock, BeaconBlockBody, BeaconBlockHeader, Hash256, Slot};
use types::{BeaconBlock, BeaconBlockBody, BeaconBlockHeader, EthSpec, Hash256, Slot};
/// Provides a queue for fully and partially built `BeaconBlock`s.
///
@@ -23,7 +23,7 @@ use types::{BeaconBlock, BeaconBlockBody, BeaconBlockHeader, Hash256, Slot};
pub struct ImportQueue<T: BeaconChainTypes> {
pub chain: Arc<BeaconChain<T>>,
/// Partially imported blocks, keyed by the root of `BeaconBlockBody`.
partials: HashMap<Hash256, PartialBeaconBlock>,
partials: HashMap<Hash256, PartialBeaconBlock<T::EthSpec>>,
/// Time before a queue entry is considered state.
pub stale_time: Duration,
/// Logging
@@ -50,7 +50,10 @@ impl<T: BeaconChainTypes> ImportQueue<T> {
///
/// Returns an Enum with a `PartialBeaconBlockCompletion`.
/// Does not remove the `block_root` from the `import_queue`.
pub fn attempt_complete_block(&self, block_root: Hash256) -> PartialBeaconBlockCompletion {
pub fn attempt_complete_block(
&self,
block_root: Hash256,
) -> PartialBeaconBlockCompletion<T::EthSpec> {
if let Some(partial) = self.partials.get(&block_root) {
partial.attempt_complete()
} else {
@@ -60,7 +63,7 @@ impl<T: BeaconChainTypes> ImportQueue<T> {
/// Removes the first `PartialBeaconBlock` with a matching `block_root`, returning the partial
/// if it exists.
pub fn remove(&mut self, block_root: Hash256) -> Option<PartialBeaconBlock> {
pub fn remove(&mut self, block_root: Hash256) -> Option<PartialBeaconBlock<T::EthSpec>> {
self.partials.remove(&block_root)
}
@@ -141,11 +144,11 @@ impl<T: BeaconChainTypes> ImportQueue<T> {
for header in headers {
let block_root = Hash256::from_slice(&header.canonical_root()[..]);
if self.chain_has_not_seen_block(&block_root) {
if !self.insert_header(block_root, header, sender.clone()) {
// If a body is empty
required_bodies.push(block_root);
}
if self.chain_has_not_seen_block(&block_root)
&& !self.insert_header(block_root, header, sender.clone())
{
// If a body is empty
required_bodies.push(block_root);
}
}
@@ -157,7 +160,7 @@ impl<T: BeaconChainTypes> ImportQueue<T> {
/// If there is no `header` for the `body`, the body is simply discarded.
pub fn enqueue_bodies(
&mut self,
bodies: Vec<BeaconBlockBody>,
bodies: Vec<BeaconBlockBody<T::EthSpec>>,
sender: PeerId,
) -> Option<Hash256> {
let mut last_block_hash = None;
@@ -168,7 +171,7 @@ impl<T: BeaconChainTypes> ImportQueue<T> {
last_block_hash
}
pub fn enqueue_full_blocks(&mut self, blocks: Vec<BeaconBlock>, sender: PeerId) {
pub fn enqueue_full_blocks(&mut self, blocks: Vec<BeaconBlock<T::EthSpec>>, sender: PeerId) {
for block in blocks {
self.insert_full_block(block, sender.clone());
}
@@ -211,13 +214,17 @@ impl<T: BeaconChainTypes> ImportQueue<T> {
/// If the body already existed, the `inserted` time is set to `now`.
///
/// Returns the block hash of the inserted body
fn insert_body(&mut self, body: BeaconBlockBody, sender: PeerId) -> Option<Hash256> {
fn insert_body(
&mut self,
body: BeaconBlockBody<T::EthSpec>,
sender: PeerId,
) -> Option<Hash256> {
let body_root = Hash256::from_slice(&body.tree_hash_root()[..]);
let mut last_root = None;
self.partials.iter_mut().for_each(|(root, mut p)| {
if let Some(header) = &mut p.header {
if body_root == header.block_body_root {
if body_root == header.body_root {
p.inserted = Instant::now();
p.body = Some(body.clone());
p.sender = sender.clone();
@@ -232,7 +239,7 @@ impl<T: BeaconChainTypes> ImportQueue<T> {
/// Updates an existing `partial` with the completed block, or adds a new (complete) partial.
///
/// If the partial already existed, the `inserted` time is set to `now`.
fn insert_full_block(&mut self, block: BeaconBlock, sender: PeerId) {
fn insert_full_block(&mut self, block: BeaconBlock<T::EthSpec>, sender: PeerId) {
let block_root = Hash256::from_slice(&block.canonical_root()[..]);
let partial = PartialBeaconBlock {
@@ -254,12 +261,12 @@ impl<T: BeaconChainTypes> ImportQueue<T> {
/// Individual components of a `BeaconBlock`, potentially all that are required to form a full
/// `BeaconBlock`.
#[derive(Clone, Debug)]
pub struct PartialBeaconBlock {
pub struct PartialBeaconBlock<E: EthSpec> {
pub slot: Slot,
/// `BeaconBlock` root.
pub block_root: Hash256,
pub header: Option<BeaconBlockHeader>,
pub body: Option<BeaconBlockBody>,
pub body: Option<BeaconBlockBody<E>>,
/// The instant at which this record was created or last meaningfully modified. Used to
/// determine if an entry is stale and should be removed.
pub inserted: Instant,
@@ -267,11 +274,11 @@ pub struct PartialBeaconBlock {
pub sender: PeerId,
}
impl PartialBeaconBlock {
impl<E: EthSpec> PartialBeaconBlock<E> {
/// Attempts to build a block.
///
/// Does not consume the `PartialBeaconBlock`.
pub fn attempt_complete(&self) -> PartialBeaconBlockCompletion {
/// Does not comsume the `PartialBeaconBlock`.
pub fn attempt_complete(&self) -> PartialBeaconBlockCompletion<E> {
if self.header.is_none() {
PartialBeaconBlockCompletion::MissingHeader(self.slot)
} else if self.body.is_none() {
@@ -288,9 +295,9 @@ impl PartialBeaconBlock {
}
/// The result of trying to convert a `BeaconBlock` into a `PartialBeaconBlock`.
pub enum PartialBeaconBlockCompletion {
pub enum PartialBeaconBlockCompletion<E: EthSpec> {
/// The partial contains a valid BeaconBlock.
Complete(BeaconBlock),
Complete(BeaconBlock<E>),
/// The partial does not exist.
MissingRoot,
/// The partial contains a `BeaconBlockRoot` but no `BeaconBlockHeader`.
+50 -47
View File
@@ -123,7 +123,7 @@ impl<T: BeaconChainTypes> SimpleSync<T> {
/// Handle the connection of a new peer.
///
/// Sends a `Hello` message to the peer.
pub fn on_connect(&self, peer_id: PeerId, network: &mut NetworkContext) {
pub fn on_connect(&self, peer_id: PeerId, network: &mut NetworkContext<T::EthSpec>) {
info!(self.log, "PeerConnected"; "peer" => format!("{:?}", peer_id));
network.send_rpc_request(peer_id, RPCRequest::Hello(hello_message(&self.chain)));
@@ -137,7 +137,7 @@ impl<T: BeaconChainTypes> SimpleSync<T> {
peer_id: PeerId,
request_id: RequestId,
hello: HelloMessage,
network: &mut NetworkContext,
network: &mut NetworkContext<T::EthSpec>,
) {
debug!(self.log, "HelloRequest"; "peer" => format!("{:?}", peer_id));
@@ -156,7 +156,7 @@ impl<T: BeaconChainTypes> SimpleSync<T> {
&mut self,
peer_id: PeerId,
hello: HelloMessage,
network: &mut NetworkContext,
network: &mut NetworkContext<T::EthSpec>,
) {
debug!(self.log, "HelloResponse"; "peer" => format!("{:?}", peer_id));
@@ -171,7 +171,7 @@ impl<T: BeaconChainTypes> SimpleSync<T> {
&mut self,
peer_id: PeerId,
hello: HelloMessage,
network: &mut NetworkContext,
network: &mut NetworkContext<T::EthSpec>,
) {
let remote = PeerSyncInfo::from(hello);
let local = PeerSyncInfo::from(&self.chain);
@@ -188,8 +188,8 @@ impl<T: BeaconChainTypes> SimpleSync<T> {
network.disconnect(peer_id.clone(), GoodbyeReason::IrrelevantNetwork);
} else if remote.latest_finalized_epoch <= local.latest_finalized_epoch
&& remote.latest_finalized_root != self.chain.spec.zero_hash
&& local.latest_finalized_root != self.chain.spec.zero_hash
&& remote.latest_finalized_root != Hash256::zero()
&& local.latest_finalized_root != Hash256::zero()
&& (self.root_at_slot(start_slot(remote.latest_finalized_epoch))
!= Some(remote.latest_finalized_root))
{
@@ -226,7 +226,7 @@ impl<T: BeaconChainTypes> SimpleSync<T> {
} else if self
.chain
.store
.exists::<BeaconBlock>(&remote.best_root)
.exists::<BeaconBlock<T::EthSpec>>(&remote.best_root)
.unwrap_or_else(|_| false)
{
// If the node's best-block is already known to us, we have nothing to request.
@@ -278,7 +278,7 @@ impl<T: BeaconChainTypes> SimpleSync<T> {
peer_id: PeerId,
request_id: RequestId,
req: BeaconBlockRootsRequest,
network: &mut NetworkContext,
network: &mut NetworkContext<T::EthSpec>,
) {
debug!(
self.log,
@@ -323,7 +323,7 @@ impl<T: BeaconChainTypes> SimpleSync<T> {
&mut self,
peer_id: PeerId,
res: BeaconBlockRootsResponse,
network: &mut NetworkContext,
network: &mut NetworkContext<T::EthSpec>,
) {
debug!(
self.log,
@@ -387,7 +387,7 @@ impl<T: BeaconChainTypes> SimpleSync<T> {
peer_id: PeerId,
request_id: RequestId,
req: BeaconBlockHeadersRequest,
network: &mut NetworkContext,
network: &mut NetworkContext<T::EthSpec>,
) {
debug!(
self.log,
@@ -416,7 +416,11 @@ impl<T: BeaconChainTypes> SimpleSync<T> {
.into_iter()
.step_by(req.skip_slots as usize + 1)
.filter_map(|root| {
let block = self.chain.store.get::<BeaconBlock>(&root).ok()?;
let block = self
.chain
.store
.get::<BeaconBlock<T::EthSpec>>(&root)
.ok()?;
Some(block?.block_header())
})
.collect();
@@ -436,7 +440,7 @@ impl<T: BeaconChainTypes> SimpleSync<T> {
&mut self,
peer_id: PeerId,
headers: Vec<BeaconBlockHeader>,
network: &mut NetworkContext,
network: &mut NetworkContext<T::EthSpec>,
) {
debug!(
self.log,
@@ -468,13 +472,13 @@ impl<T: BeaconChainTypes> SimpleSync<T> {
peer_id: PeerId,
request_id: RequestId,
req: BeaconBlockBodiesRequest,
network: &mut NetworkContext,
network: &mut NetworkContext<T::EthSpec>,
) {
let block_bodies: Vec<BeaconBlockBody> = req
let block_bodies: Vec<BeaconBlockBody<_>> = req
.block_roots
.iter()
.filter_map(|root| {
if let Ok(Some(block)) = self.chain.store.get::<BeaconBlock>(root) {
if let Ok(Some(block)) = self.chain.store.get::<BeaconBlock<T::EthSpec>>(root) {
Some(block.body)
} else {
debug!(
@@ -513,8 +517,8 @@ impl<T: BeaconChainTypes> SimpleSync<T> {
pub fn on_beacon_block_bodies_response(
&mut self,
peer_id: PeerId,
res: DecodedBeaconBlockBodiesResponse,
network: &mut NetworkContext,
res: DecodedBeaconBlockBodiesResponse<T::EthSpec>,
network: &mut NetworkContext<T::EthSpec>,
) {
debug!(
self.log,
@@ -531,12 +535,11 @@ impl<T: BeaconChainTypes> SimpleSync<T> {
// Attempt to process all received bodies by recursively processing the latest block
if let Some(root) = last_root {
match self.attempt_process_partial_block(peer_id, root, network, &"rpc") {
Some(BlockProcessingOutcome::Processed { block_root: _ }) => {
// If processing is successful remove from `import_queue`
self.import_queue.remove(root);
}
_ => {}
if let Some(BlockProcessingOutcome::Processed { .. }) =
self.attempt_process_partial_block(peer_id, root, network, &"rpc")
{
// If processing is successful remove from `import_queue`
self.import_queue.remove(root);
}
}
}
@@ -553,8 +556,8 @@ impl<T: BeaconChainTypes> SimpleSync<T> {
pub fn on_block_gossip(
&mut self,
peer_id: PeerId,
block: BeaconBlock,
network: &mut NetworkContext,
block: BeaconBlock<T::EthSpec>,
network: &mut NetworkContext<T::EthSpec>,
) -> bool {
if let Some(outcome) =
self.process_block(peer_id.clone(), block.clone(), network, &"gossip")
@@ -577,7 +580,8 @@ impl<T: BeaconChainTypes> SimpleSync<T> {
.chain
.head()
.beacon_state
.finalized_epoch
.finalized_checkpoint
.epoch
.start_slot(T::EthSpec::slots_per_epoch());
self.request_block_roots(
peer_id,
@@ -622,8 +626,8 @@ impl<T: BeaconChainTypes> SimpleSync<T> {
pub fn on_attestation_gossip(
&mut self,
_peer_id: PeerId,
msg: Attestation,
_network: &mut NetworkContext,
msg: Attestation<T::EthSpec>,
_network: &mut NetworkContext<T::EthSpec>,
) {
match self.chain.process_attestation(msg) {
Ok(()) => info!(self.log, "ImportedAttestation"; "source" => "gossip"),
@@ -638,7 +642,7 @@ impl<T: BeaconChainTypes> SimpleSync<T> {
&mut self,
peer_id: PeerId,
req: BeaconBlockRootsRequest,
network: &mut NetworkContext,
network: &mut NetworkContext<T::EthSpec>,
) {
// Potentially set state to sync.
if self.state == SyncState::Idle && req.count > SLOT_IMPORT_TOLERANCE {
@@ -662,7 +666,7 @@ impl<T: BeaconChainTypes> SimpleSync<T> {
&mut self,
peer_id: PeerId,
req: BeaconBlockHeadersRequest,
network: &mut NetworkContext,
network: &mut NetworkContext<T::EthSpec>,
) {
debug!(
self.log,
@@ -679,7 +683,7 @@ impl<T: BeaconChainTypes> SimpleSync<T> {
&mut self,
peer_id: PeerId,
req: BeaconBlockBodiesRequest,
network: &mut NetworkContext,
network: &mut NetworkContext<T::EthSpec>,
) {
debug!(
self.log,
@@ -715,7 +719,7 @@ impl<T: BeaconChainTypes> SimpleSync<T> {
&mut self,
peer_id: PeerId,
block_root: Hash256,
network: &mut NetworkContext,
network: &mut NetworkContext<T::EthSpec>,
source: &str,
) -> Option<BlockProcessingOutcome> {
match self.import_queue.attempt_complete_block(block_root) {
@@ -807,8 +811,8 @@ impl<T: BeaconChainTypes> SimpleSync<T> {
fn process_block(
&mut self,
peer_id: PeerId,
block: BeaconBlock,
network: &mut NetworkContext,
block: BeaconBlock<T::EthSpec>,
network: &mut NetworkContext<T::EthSpec>,
source: &str,
) -> Option<BlockProcessingOutcome> {
let processing_result = self.chain.process_block(block.clone());
@@ -836,19 +840,18 @@ impl<T: BeaconChainTypes> SimpleSync<T> {
);
// If the parent is in the `import_queue` attempt to complete it then process it.
match self.attempt_process_partial_block(peer_id, parent, network, source) {
// All other cases leave `parent` in `import_queue` and return original outcome.
if let Some(BlockProcessingOutcome::Processed { .. }) =
self.attempt_process_partial_block(peer_id, parent, network, source)
{
// If processing parent is successful, re-process block and remove parent from queue
Some(BlockProcessingOutcome::Processed { block_root: _ }) => {
self.import_queue.remove(parent);
self.import_queue.remove(parent);
// Attempt to process `block` again
match self.chain.process_block(block) {
Ok(outcome) => return Some(outcome),
Err(_) => return None,
}
// Attempt to process `block` again
match self.chain.process_block(block) {
Ok(outcome) => return Some(outcome),
Err(_) => return None,
}
// All other cases leave `parent` in `import_queue` and return original outcome.
_ => {}
}
}
BlockProcessingOutcome::FutureSlot {
@@ -913,9 +916,9 @@ fn hello_message<T: BeaconChainTypes>(beacon_chain: &BeaconChain<T>) -> HelloMes
HelloMessage {
//TODO: Correctly define the chain/network id
network_id: spec.chain_id,
chain_id: spec.chain_id as u64,
latest_finalized_root: state.finalized_root,
latest_finalized_epoch: state.finalized_epoch,
chain_id: u64::from(spec.chain_id),
latest_finalized_root: state.finalized_checkpoint.root,
latest_finalized_epoch: state.finalized_checkpoint.epoch,
best_root: beacon_chain.head().beacon_block_root,
best_slot: state.slot,
}
+1 -1
View File
@@ -19,7 +19,7 @@ use types::Attestation;
#[derive(Clone)]
pub struct AttestationServiceInstance<T: BeaconChainTypes> {
pub chain: Arc<BeaconChain<T>>,
pub network_chan: mpsc::UnboundedSender<NetworkMessage>,
pub network_chan: mpsc::UnboundedSender<NetworkMessage<T::EthSpec>>,
pub log: slog::Logger,
}
+1 -1
View File
@@ -19,7 +19,7 @@ use types::{BeaconBlock, Signature, Slot};
#[derive(Clone)]
pub struct BeaconBlockServiceInstance<T: BeaconChainTypes> {
pub chain: Arc<BeaconChain<T>>,
pub network_chan: mpsc::UnboundedSender<NetworkMessage>,
pub network_chan: mpsc::UnboundedSender<NetworkMessage<T::EthSpec>>,
pub log: Logger,
}
+1 -1
View File
@@ -25,7 +25,7 @@ use tokio::sync::mpsc;
pub fn start_server<T: BeaconChainTypes + Clone + 'static>(
config: &RPCConfig,
executor: &TaskExecutor,
network_chan: mpsc::UnboundedSender<NetworkMessage>,
network_chan: mpsc::UnboundedSender<NetworkMessage<T::EthSpec>>,
beacon_chain: Arc<BeaconChain<T>>,
log: &slog::Logger,
) -> exit_future::Signal {
+1 -1
View File
@@ -210,7 +210,7 @@ fn main() {
}
};
default_dir.push(DEFAULT_DATA_DIR);
PathBuf::from(default_dir)
default_dir
}
};
+2 -4
View File
@@ -57,7 +57,7 @@ pub fn run_beacon_node(
"db_type" => &other_client_config.db_type,
);
let result = match (db_type.as_str(), spec_constants.as_str()) {
match (db_type.as_str(), spec_constants.as_str()) {
("disk", "minimal") => run::<ClientType<DiskStore, MinimalEthSpec>>(
&db_path,
client_config,
@@ -94,9 +94,7 @@ pub fn run_beacon_node(
error!(log, "Unknown runtime configuration"; "spec_constants" => spec, "db_type" => db_type);
Err("Unknown specification and/or db_type.".into())
}
};
result
}
}
/// Performs the type-generic parts of launching a `BeaconChain`.
+27 -23
View File
@@ -1,8 +1,11 @@
use super::*;
use ssz::{Decode, DecodeError};
fn get_block_bytes<T: Store>(store: &T, root: Hash256) -> Result<Option<Vec<u8>>, Error> {
store.get_bytes(BeaconBlock::db_column().into(), &root[..])
fn get_block_bytes<T: Store, E: EthSpec>(
store: &T,
root: Hash256,
) -> Result<Option<Vec<u8>>, Error> {
store.get_bytes(BeaconBlock::<E>::db_column().into(), &root[..])
}
fn read_slot_from_block_bytes(bytes: &[u8]) -> Result<Slot, DecodeError> {
@@ -11,7 +14,7 @@ fn read_slot_from_block_bytes(bytes: &[u8]) -> Result<Slot, DecodeError> {
Slot::from_ssz_bytes(&bytes[0..end])
}
fn read_previous_block_root_from_block_bytes(bytes: &[u8]) -> Result<Hash256, DecodeError> {
fn read_parent_root_from_block_bytes(bytes: &[u8]) -> Result<Hash256, DecodeError> {
let previous_bytes = Slot::ssz_fixed_len();
let slice = bytes
.get(previous_bytes..previous_bytes + Hash256::ssz_fixed_len())
@@ -20,24 +23,26 @@ fn read_previous_block_root_from_block_bytes(bytes: &[u8]) -> Result<Hash256, De
Hash256::from_ssz_bytes(slice)
}
pub fn get_block_at_preceding_slot<T: Store>(
pub fn get_block_at_preceeding_slot<T: Store, E: EthSpec>(
store: &T,
slot: Slot,
start_root: Hash256,
) -> Result<Option<(Hash256, BeaconBlock)>, Error> {
Ok(match get_at_preceding_slot(store, slot, start_root)? {
Some((hash, bytes)) => Some((hash, BeaconBlock::from_ssz_bytes(&bytes)?)),
None => None,
})
) -> Result<Option<(Hash256, BeaconBlock<E>)>, Error> {
Ok(
match get_at_preceeding_slot::<_, E>(store, slot, start_root)? {
Some((hash, bytes)) => Some((hash, BeaconBlock::<E>::from_ssz_bytes(&bytes)?)),
None => None,
},
)
}
fn get_at_preceding_slot<T: Store>(
fn get_at_preceeding_slot<T: Store, E: EthSpec>(
store: &T,
slot: Slot,
mut root: Hash256,
) -> Result<Option<(Hash256, Vec<u8>)>, Error> {
loop {
if let Some(bytes) = get_block_bytes(store, root)? {
if let Some(bytes) = get_block_bytes::<_, E>(store, root)? {
let this_slot = read_slot_from_block_bytes(&bytes)?;
if this_slot == slot {
@@ -45,7 +50,7 @@ fn get_at_preceding_slot<T: Store>(
} else if this_slot < slot {
break Ok(None);
} else {
root = read_previous_block_root_from_block_bytes(&bytes)?;
root = read_parent_root_from_block_bytes(&bytes)?;
}
} else {
break Ok(None);
@@ -59,6 +64,8 @@ mod tests {
use ssz::Encode;
use tree_hash::TreeHash;
type BeaconBlock = types::BeaconBlock<MinimalEthSpec>;
#[test]
fn read_slot() {
let spec = MinimalEthSpec::default_spec();
@@ -84,17 +91,14 @@ mod tests {
}
#[test]
fn read_previous_block_root() {
fn read_parent_root() {
let spec = MinimalEthSpec::default_spec();
let test_root = |root: Hash256| {
let mut block = BeaconBlock::empty(&spec);
block.previous_block_root = root;
block.parent_root = root;
let bytes = block.as_ssz_bytes();
assert_eq!(
read_previous_block_root_from_block_bytes(&bytes).unwrap(),
root
);
assert_eq!(read_parent_root_from_block_bytes(&bytes).unwrap(), root);
};
test_root(Hash256::random());
@@ -114,7 +118,7 @@ mod tests {
block.slot = Slot::from(*slot);
if i > 0 {
block.previous_block_root = blocks_and_roots[i - 1].0;
block.parent_root = blocks_and_roots[i - 1].0;
}
let root = Hash256::from_slice(&block.tree_hash_root());
@@ -141,7 +145,7 @@ mod tests {
let (target_root, target_block) = &blocks_and_roots[target];
let (found_root, found_block) = store
.get_block_at_preceding_slot(*source_root, target_block.slot)
.get_block_at_preceeding_slot(*source_root, target_block.slot)
.unwrap()
.unwrap();
@@ -166,7 +170,7 @@ mod tests {
let (target_root, target_block) = &blocks_and_roots[target];
let (found_root, found_block) = store
.get_block_at_preceding_slot(*source_root, target_block.slot)
.get_block_at_preceeding_slot(*source_root, target_block.slot)
.unwrap()
.unwrap();
@@ -177,14 +181,14 @@ mod tests {
// Slot that doesn't exist
let (source_root, _source_block) = &blocks_and_roots[3];
assert!(store
.get_block_at_preceding_slot(*source_root, Slot::new(3))
.get_block_at_preceeding_slot::<MinimalEthSpec>(*source_root, Slot::new(3))
.unwrap()
.is_none());
// Slot too high
let (source_root, _source_block) = &blocks_and_roots[3];
assert!(store
.get_block_at_preceding_slot(*source_root, Slot::new(3))
.get_block_at_preceeding_slot::<MinimalEthSpec>(*source_root, Slot::new(3))
.unwrap()
.is_none());
}
+1 -1
View File
@@ -3,7 +3,7 @@ use ssz::{Decode, Encode};
mod beacon_state;
impl StoreItem for BeaconBlock {
impl<T: EthSpec> StoreItem for BeaconBlock<T> {
fn db_column() -> DBColumn {
DBColumn::BeaconBlock
}
+14 -12
View File
@@ -9,7 +9,9 @@ pub trait AncestorIter<U: Store, I: Iterator> {
fn try_iter_ancestor_roots(&self, store: Arc<U>) -> Option<I>;
}
impl<'a, U: Store, E: EthSpec> AncestorIter<U, BestBlockRootsIterator<'a, E, U>> for BeaconBlock {
impl<'a, U: Store, E: EthSpec> AncestorIter<U, BestBlockRootsIterator<'a, E, U>>
for BeaconBlock<E>
{
/// Iterates across all the prior block roots of `self`, starting at the most recent and ending
/// at genesis.
fn try_iter_ancestor_roots(&self, store: Arc<U>) -> Option<BestBlockRootsIterator<'a, E, U>> {
@@ -98,7 +100,7 @@ impl<'a, T: EthSpec, U: Store> BlockIterator<'a, T, U> {
}
impl<'a, T: EthSpec, U: Store> Iterator for BlockIterator<'a, T, U> {
type Item = BeaconBlock;
type Item = BeaconBlock<T>;
fn next(&mut self) -> Option<Self::Item> {
let (root, _slot) = self.roots.next()?;
@@ -109,8 +111,8 @@ impl<'a, T: EthSpec, U: Store> Iterator for BlockIterator<'a, T, U> {
/// Iterates backwards through block roots. If any specified slot is unable to be retrieved, the
/// iterator returns `None` indefinitely.
///
/// Uses the `latest_block_roots` field of `BeaconState` to as the source of block roots and will
/// perform a lookup on the `Store` for a prior `BeaconState` if `latest_block_roots` has been
/// Uses the `block_roots` field of `BeaconState` to as the source of block roots and will
/// perform a lookup on the `Store` for a prior `BeaconState` if `block_roots` has been
/// exhausted.
///
/// Returns `None` for roots prior to genesis or when there is an error reading from `Store`.
@@ -191,8 +193,8 @@ impl<'a, T: EthSpec, U: Store> Iterator for BlockRootsIterator<'a, T, U> {
///
/// This is distinct from `BestBlockRootsIterator`.
///
/// Uses the `latest_block_roots` field of `BeaconState` to as the source of block roots and will
/// perform a lookup on the `Store` for a prior `BeaconState` if `latest_block_roots` has been
/// Uses the `block_roots` field of `BeaconState` to as the source of block roots and will
/// perform a lookup on the `Store` for a prior `BeaconState` if `block_roots` has been
/// exhausted.
///
/// Returns `None` for roots prior to genesis or when there is an error reading from `Store`.
@@ -305,15 +307,15 @@ mod test {
let mut hashes = (0..).into_iter().map(|i| Hash256::from(i));
for root in &mut state_a.latest_block_roots[..] {
for root in &mut state_a.block_roots[..] {
*root = hashes.next().unwrap()
}
for root in &mut state_b.latest_block_roots[..] {
for root in &mut state_b.block_roots[..] {
*root = hashes.next().unwrap()
}
let state_a_root = hashes.next().unwrap();
state_b.latest_state_roots[0] = state_a_root;
state_b.state_roots[0] = state_a_root;
store.put(&state_a_root, &state_a).unwrap();
let iter = BlockRootsIterator::new(store.clone(), &state_b, state_b.slot - 1);
@@ -348,15 +350,15 @@ mod test {
let mut hashes = (0..).into_iter().map(|i| Hash256::from(i));
for root in &mut state_a.latest_block_roots[..] {
for root in &mut state_a.block_roots[..] {
*root = hashes.next().unwrap()
}
for root in &mut state_b.latest_block_roots[..] {
for root in &mut state_b.block_roots[..] {
*root = hashes.next().unwrap()
}
let state_a_root = hashes.next().unwrap();
state_b.latest_state_roots[0] = state_a_root;
state_b.state_roots[0] = state_a_root;
store.put(&state_a_root, &state_a).unwrap();
let iter = BestBlockRootsIterator::new(store.clone(), &state_b, state_b.slot);
+3 -3
View File
@@ -52,12 +52,12 @@ pub trait Store: Sync + Send + Sized {
///
/// Returns `None` if no parent block exists at that slot, or if `slot` is greater than the
/// slot of `start_block_root`.
fn get_block_at_preceding_slot(
fn get_block_at_preceeding_slot<E: EthSpec>(
&self,
start_block_root: Hash256,
slot: Slot,
) -> Result<Option<(Hash256, BeaconBlock)>, Error> {
block_at_slot::get_block_at_preceding_slot(self, slot, start_block_root)
) -> Result<Option<(Hash256, BeaconBlock<E>)>, Error> {
block_at_slot::get_block_at_preceeding_slot::<_, E>(self, slot, start_block_root)
}
/// Retrieve some bytes in `column` with `key`.