Skip to content

Commit

Permalink
Merge branch 'master' into directory-restructure
Browse files Browse the repository at this point in the history
  • Loading branch information
pawanjay176 committed Aug 17, 2020
2 parents 01e6166 + 9a97a0b commit e4a7e8c
Show file tree
Hide file tree
Showing 35 changed files with 1,180 additions and 591 deletions.
171 changes: 68 additions & 103 deletions Cargo.lock

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions Cross.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[build.env]
passthrough = [
"RUSTFLAGS",
]
2 changes: 1 addition & 1 deletion account_manager/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "account_manager"
version = "0.2.3"
version = "0.2.4"
authors = ["Paul Hauner <[email protected]>", "Luke Anderson <[email protected]>"]
edition = "2018"

Expand Down
2 changes: 1 addition & 1 deletion beacon_node/Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "beacon_node"
version = "0.2.3"
version = "0.2.4"
authors = ["Paul Hauner <[email protected]>", "Age Manning <[email protected]"]
edition = "2018"

Expand Down
34 changes: 29 additions & 5 deletions beacon_node/beacon_chain/src/attestation_verification.rs
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,12 @@ pub enum Error {
///
/// The peer has sent an invalid message.
Invalid(AttestationValidationError),
/// The attestation head block is too far behind the attestation slot, causing many skip slots.
/// This is deemed a DoS risk.
TooManySkippedSlots {
head_block_slot: Slot,
attestation_slot: Slot,
},
/// There was an error whilst processing the attestation. It is not known if it is valid or invalid.
///
/// ## Peer scoring
Expand Down Expand Up @@ -319,6 +325,7 @@ impl<T: BeaconChainTypes> VerifiedAggregatedAttestation<T> {
}?;

// Ensure the block being voted for (attestation.data.beacon_block_root) passes validation.
// Don't enforce the skip slot restriction for aggregates.
//
// This indirectly checks to see if the `attestation.data.beacon_block_root` is in our fork
// choice. Any known, non-finalized, processed block should be in fork choice, so this
Expand All @@ -327,7 +334,7 @@ impl<T: BeaconChainTypes> VerifiedAggregatedAttestation<T> {
//
// Attestations must be for a known block. If the block is unknown, we simply drop the
// attestation and do not delay consideration for later.
verify_head_block_is_known(chain, &attestation)?;
verify_head_block_is_known(chain, &attestation, None)?;

// Ensure that the attestation has participants.
if attestation.aggregation_bits.is_zero() {
Expand Down Expand Up @@ -433,7 +440,9 @@ impl<T: BeaconChainTypes> VerifiedUnaggregatedAttestation<T> {

// Attestations must be for a known block. If the block is unknown, we simply drop the
// attestation and do not delay consideration for later.
verify_head_block_is_known(chain, &attestation)?;
//
// Enforce a maximum skip distance for unaggregated attestations.
verify_head_block_is_known(chain, &attestation, chain.config.import_max_skip_slots)?;

let (indexed_attestation, committees_per_slot) =
obtain_indexed_attestation_and_committees_per_slot(chain, &attestation)?;
Expand Down Expand Up @@ -531,12 +540,22 @@ impl<T: BeaconChainTypes> VerifiedUnaggregatedAttestation<T> {
fn verify_head_block_is_known<T: BeaconChainTypes>(
chain: &BeaconChain<T>,
attestation: &Attestation<T::EthSpec>,
max_skip_slots: Option<u64>,
) -> Result<(), Error> {
if chain
if let Some(block) = chain
.fork_choice
.read()
.contains_block(&attestation.data.beacon_block_root)
.get_block(&attestation.data.beacon_block_root)
{
// Reject any block that exceeds our limit on skipped slots.
if let Some(max_skip_slots) = max_skip_slots {
if block.slot > attestation.data.slot + max_skip_slots {
return Err(Error::TooManySkippedSlots {
head_block_slot: block.slot,
attestation_slot: attestation.data.slot,
});
}
}
Ok(())
} else {
Err(Error::UnknownHeadBlock {
Expand Down Expand Up @@ -775,7 +794,12 @@ where
metrics::start_timer(&metrics::ATTESTATION_PROCESSING_STATE_READ_TIMES);

let mut state = chain
.get_state(&target_block.state_root, Some(target_block.slot))?
.store
.get_inconsistent_state_for_attestation_verification_only(
&target_block.state_root,
Some(target_block.slot),
)
.map_err(BeaconChainError::from)?
.ok_or_else(|| BeaconChainError::MissingBeaconState(target_block.state_root))?;

metrics::stop_timer(state_read_timer);
Expand Down
3 changes: 3 additions & 0 deletions beacon_node/beacon_chain/src/beacon_chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use crate::block_verification::{
signature_verify_chain_segment, BlockError, FullyVerifiedBlock, GossipVerifiedBlock,
IntoFullyVerifiedBlock,
};
use crate::chain_config::ChainConfig;
use crate::errors::{BeaconChainError as Error, BlockProductionError};
use crate::eth1_chain::{Eth1Chain, Eth1ChainBackend};
use crate::events::{EventHandler, EventKind};
Expand Down Expand Up @@ -161,6 +162,8 @@ pub trait BeaconChainTypes: Send + Sync + 'static {
/// operations and chooses a canonical head.
pub struct BeaconChain<T: BeaconChainTypes> {
pub spec: ChainSpec,
/// Configuration for `BeaconChain` runtime behaviour.
pub config: ChainConfig,
/// Persistent storage for blocks, states, etc. Typically an on-disk store, such as LevelDB.
pub store: Arc<HotColdDB<T::EthSpec, T::HotStore, T::ColdStore>>,
/// Database migrator for running background maintenance on the store.
Expand Down
31 changes: 29 additions & 2 deletions beacon_node/beacon_chain/src/block_verification.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ pub enum BlockError<T: EthSpec> {
/// It's unclear if this block is valid, but it cannot be processed without already knowing
/// its parent.
ParentUnknown(Box<SignedBeaconBlock<T>>),
/// The block skips too many slots and is a DoS risk.
TooManySkippedSlots { parent_slot: Slot, block_slot: Slot },
/// The block slot is greater than the present slot.
///
/// ## Peer scoring
Expand Down Expand Up @@ -390,9 +392,22 @@ impl<T: BeaconChainTypes> GossipVerifiedBlock<T> {
});
}

let block_root = get_block_root(&block);

// Do not gossip a block from a finalized slot.
check_block_against_finalized_slot(&block.message, chain)?;

// Check if the block is already known. We know it is post-finalization, so it is
// sufficient to check the fork choice.
//
// In normal operation this isn't necessary, however it is useful immediately after a
// reboot if the `observed_block_producers` cache is empty. In that case, without this
// check, we will load the parent and state from disk only to find out later that we
// already know this block.
if chain.fork_choice.read().contains_block(&block_root) {
return Err(BlockError::BlockIsAlreadyKnown);
}

// Check that we have not already received a block with a valid signature for this slot.
if chain
.observed_block_producers
Expand All @@ -415,7 +430,6 @@ impl<T: BeaconChainTypes> GossipVerifiedBlock<T> {
)?;

let (mut parent, block) = load_parent(block, chain)?;
let block_root = get_block_root(&block);

let state = cheap_state_advance_to_obtain_committees(
&mut parent.beacon_state,
Expand Down Expand Up @@ -633,6 +647,16 @@ impl<'a, T: BeaconChainTypes> FullyVerifiedBlock<'a, T> {
return Err(BlockError::ParentUnknown(Box::new(block)));
}

// Reject any block that exceeds our limit on skipped slots.
if let Some(max_skip_slots) = chain.config.import_max_skip_slots {
if block.slot() > parent.beacon_block.slot() + max_skip_slots {
return Err(BlockError::TooManySkippedSlots {
parent_slot: parent.beacon_block.slot(),
block_slot: block.slot(),
});
}
}

/*
* Perform cursory checks to see if the block is even worth processing.
*/
Expand Down Expand Up @@ -672,7 +696,10 @@ impl<'a, T: BeaconChainTypes> FullyVerifiedBlock<'a, T> {
let state_root = state.update_tree_hash_cache()?;

let op = if state.slot % T::EthSpec::slots_per_epoch() == 0 {
StoreOp::PutState(state_root.into(), Cow::Owned(state.clone()))
StoreOp::PutState(
state_root.into(),
Cow::Owned(state.clone_with(CloneConfig::committee_caches_only())),
)
} else {
StoreOp::PutStateSummary(
state_root.into(),
Expand Down
19 changes: 19 additions & 0 deletions beacon_node/beacon_chain/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use crate::shuffling_cache::ShufflingCache;
use crate::snapshot_cache::{SnapshotCache, DEFAULT_SNAPSHOT_CACHE_SIZE};
use crate::timeout_rw_lock::TimeoutRwLock;
use crate::validator_pubkey_cache::ValidatorPubkeyCache;
use crate::ChainConfig;
use crate::{
BeaconChain, BeaconChainTypes, BeaconForkChoiceStore, BeaconSnapshot, Eth1Chain,
Eth1ChainBackend, EventHandler,
Expand Down Expand Up @@ -110,6 +111,7 @@ pub struct BeaconChainBuilder<T: BeaconChainTypes> {
pubkey_cache_path: Option<PathBuf>,
validator_pubkey_cache: Option<ValidatorPubkeyCache>,
spec: ChainSpec,
chain_config: ChainConfig,
disabled_forks: Vec<String>,
log: Option<Logger>,
graffiti: Graffiti,
Expand Down Expand Up @@ -157,6 +159,7 @@ where
disabled_forks: Vec::new(),
validator_pubkey_cache: None,
spec: TEthSpec::default_spec(),
chain_config: ChainConfig::default(),
log: None,
graffiti: Graffiti::default(),
}
Expand All @@ -171,6 +174,15 @@ where
self
}

/// Sets the maximum number of blocks that will be skipped when processing
/// some consensus messages.
///
/// Set to `None` for no limit.
pub fn import_max_skip_slots(mut self, n: Option<u64>) -> Self {
self.chain_config.import_max_skip_slots = n;
self
}

/// Sets the store (database).
///
/// Should generally be called early in the build chain.
Expand Down Expand Up @@ -406,6 +418,12 @@ where
self
}

/// Sets the `ChainConfig` that determines `BeaconChain` runtime behaviour.
pub fn chain_config(mut self, config: ChainConfig) -> Self {
self.chain_config = config;
self
}

/// Consumes `self`, returning a `BeaconChain` if all required parameters have been supplied.
///
/// An error will be returned at runtime if all required parameters have not been configured.
Expand Down Expand Up @@ -489,6 +507,7 @@ where

let beacon_chain = BeaconChain {
spec: self.spec,
config: self.chain_config,
store,
store_migrator: self
.store_migrator
Expand Down
20 changes: 20 additions & 0 deletions beacon_node/beacon_chain/src/chain_config.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
use serde_derive::{Deserialize, Serialize};

pub const DEFAULT_IMPORT_BLOCK_MAX_SKIP_SLOTS: u64 = 10 * 32;

#[derive(Debug, PartialEq, Eq, Clone, Deserialize, Serialize)]
pub struct ChainConfig {
/// Maximum number of slots to skip when importing a consensus message (e.g., block,
/// attestation, etc).
///
/// If `None`, there is no limit.
pub import_max_skip_slots: Option<u64>,
}

impl Default for ChainConfig {
fn default() -> Self {
Self {
import_max_skip_slots: Some(DEFAULT_IMPORT_BLOCK_MAX_SKIP_SLOTS),
}
}
}
2 changes: 2 additions & 0 deletions beacon_node/beacon_chain/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ mod beacon_fork_choice_store;
mod beacon_snapshot;
mod block_verification;
pub mod builder;
pub mod chain_config;
mod errors;
pub mod eth1_chain;
pub mod events;
Expand All @@ -32,6 +33,7 @@ pub use self::beacon_chain::{
ForkChoiceError, StateSkipConfig,
};
pub use self::beacon_snapshot::BeaconSnapshot;
pub use self::chain_config::ChainConfig;
pub use self::errors::{BeaconChainError, BlockProductionError};
pub use attestation_verification::Error as AttestationError;
pub use beacon_fork_choice_store::{BeaconForkChoiceStore, Error as ForkChoiceStoreError};
Expand Down
2 changes: 2 additions & 0 deletions beacon_node/beacon_chain/src/test_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,7 @@ impl<E: EthSpec> BeaconChainHarness<DiskHarnessType<E>> {
let chain = BeaconChainBuilder::new(eth_spec_instance)
.logger(log.clone())
.custom_spec(spec.clone())
.import_max_skip_slots(None)
.store(store.clone())
.store_migrator(BlockingMigrator::new(store, log.clone()))
.data_dir(data_dir.path().to_path_buf())
Expand Down Expand Up @@ -190,6 +191,7 @@ impl<E: EthSpec> BeaconChainHarness<DiskHarnessType<E>> {
let chain = BeaconChainBuilder::new(eth_spec_instance)
.logger(log.clone())
.custom_spec(spec)
.import_max_skip_slots(None)
.store(store.clone())
.store_migrator(<BlockingMigrator<_, _, _> as Migrate<E, _, _>>::new(
store,
Expand Down
2 changes: 2 additions & 0 deletions beacon_node/client/src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ where
let eth_spec_instance = self.eth_spec_instance.clone();
let data_dir = config.data_dir.clone();
let disabled_forks = config.disabled_forks.clone();
let chain_config = config.chain.clone();
let graffiti = config.graffiti;

let store =
Expand All @@ -153,6 +154,7 @@ where
.store_migrator(store_migrator)
.data_dir(data_dir)
.custom_spec(spec.clone())
.chain_config(chain_config)
.disabled_forks(disabled_forks)
.graffiti(graffiti);

Expand Down
2 changes: 2 additions & 0 deletions beacon_node/client/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ pub struct Config {
pub store: store::StoreConfig,
pub network: network::NetworkConfig,
pub rest_api: rest_api::Config,
pub chain: beacon_chain::ChainConfig,
pub websocket_server: websocket_server::Config,
pub eth1: eth1::Config,
}
Expand All @@ -77,6 +78,7 @@ impl Default for Config {
genesis: <_>::default(),
store: <_>::default(),
network: NetworkConfig::default(),
chain: <_>::default(),
rest_api: <_>::default(),
websocket_server: <_>::default(),
spec_constants: TESTNET_SPEC_CONSTANTS.into(),
Expand Down
2 changes: 1 addition & 1 deletion beacon_node/eth2_libp2p/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ snap = "1.0.0"
void = "1.0.2"
tokio-io-timeout = "0.4.0"
tokio-util = { version = "0.3.1", features = ["codec", "compat"] }
discv5 = { version = "0.1.0-alpha.9", features = ["libp2p"] }
discv5 = { version = "0.1.0-alpha.8", features = ["libp2p", "openssl-vendored"] }
tiny-keccak = "2.0.2"
environment = { path = "../../lighthouse/environment" }
# TODO: Remove rand crate for mainnet
Expand Down
Loading

0 comments on commit e4a7e8c

Please sign in to comment.