Skip to content
Merged
8 changes: 8 additions & 0 deletions beacon_node/beacon_chain/src/beacon_chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1358,6 +1358,14 @@ impl<T: BeaconChainTypes> BeaconChain<T> {
.collect::<Vec<_>>();

for (i, block) in chain_segment.into_iter().enumerate() {
// Ensure the block is the correct structure for the fork at `block.slot()`.
if let Err(e) = block.fork_name(&self.spec) {
return ChainSegmentResult::Failed {
imported_blocks,
error: BlockError::InconsistentFork(e),
};
}

let block_root = get_block_root(&block);

if let Some((child_parent_root, child_slot)) = children.get(i) {
Expand Down
18 changes: 17 additions & 1 deletion beacon_node/beacon_chain/src/block_verification.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ use store::{Error as DBError, HotColdDB, HotStateSummary, KeyValueStore, StoreOp
use tree_hash::TreeHash;
use types::{
BeaconBlockRef, BeaconState, BeaconStateError, ChainSpec, CloneConfig, Epoch, EthSpec, Hash256,
PublicKey, RelativeEpoch, SignedBeaconBlock, SignedBeaconBlockHeader, Slot,
InconsistentFork, PublicKey, RelativeEpoch, SignedBeaconBlock, SignedBeaconBlockHeader, Slot,
};

/// Maximum block slot number. Block with slots bigger than this constant will NOT be processed.
Expand Down Expand Up @@ -219,6 +219,12 @@ pub enum BlockError<T: EthSpec> {
///
/// The block is invalid and the peer is faulty.
WeakSubjectivityConflict,
/// The block has the wrong structure for the fork at `block.slot`.
///
/// ## Peer scoring
///
/// The block is invalid and the peer is faulty.
InconsistentFork(InconsistentFork),
}

impl<T: EthSpec> std::fmt::Display for BlockError<T> {
Expand Down Expand Up @@ -477,6 +483,11 @@ impl<T: BeaconChainTypes> GossipVerifiedBlock<T> {
block: SignedBeaconBlock<T::EthSpec>,
chain: &BeaconChain<T>,
) -> Result<Self, BlockError<T::EthSpec>> {
// Ensure the block is the correct structure for the fork at `block.slot()`.
block
.fork_name(&chain.spec)
.map_err(BlockError::InconsistentFork)?;

// Do not gossip or process blocks from future slots.
let present_slot_with_tolerance = chain
.slot_clock
Expand Down Expand Up @@ -692,6 +703,11 @@ impl<T: BeaconChainTypes> SignatureVerifiedBlock<T> {
block: SignedBeaconBlock<T::EthSpec>,
chain: &BeaconChain<T>,
) -> Result<Self, BlockError<T::EthSpec>> {
// Ensure the block is the correct structure for the fork at `block.slot()`.
block
.fork_name(&chain.spec)
.map_err(BlockError::InconsistentFork)?;

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

// Reject any block that exceeds our limit on skipped slots.
Expand Down
1 change: 1 addition & 0 deletions beacon_node/beacon_chain/src/snapshot_cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,7 @@ mod test {
fn get_harness() -> BeaconChainHarness<EphemeralHarnessType<MainnetEthSpec>> {
let harness = BeaconChainHarness::new_with_store_config(
MainnetEthSpec,
None,
types::test_utils::generate_deterministic_keypairs(1),
StoreConfig::default(),
);
Expand Down
27 changes: 22 additions & 5 deletions beacon_node/beacon_chain/src/test_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -156,35 +156,49 @@ pub type HarnessAttestations<E> = Vec<(
)>;

impl<E: EthSpec> BeaconChainHarness<EphemeralHarnessType<E>> {
pub fn new(eth_spec_instance: E, validator_keypairs: Vec<Keypair>) -> Self {
pub fn new(
eth_spec_instance: E,
spec: Option<ChainSpec>,
validator_keypairs: Vec<Keypair>,
) -> Self {
Self::new_with_store_config(
eth_spec_instance,
spec,
validator_keypairs,
StoreConfig::default(),
)
}

pub fn new_with_store_config(
eth_spec_instance: E,
spec: Option<ChainSpec>,
validator_keypairs: Vec<Keypair>,
config: StoreConfig,
) -> Self {
// Setting the target aggregators to really high means that _all_ validators in the
// committee are required to produce an aggregate. This is overkill, however with small
// validator counts it's the only way to be certain there is _at least one_ aggregator per
// committee.
Self::new_with_target_aggregators(eth_spec_instance, validator_keypairs, 1 << 32, config)
Self::new_with_target_aggregators(
eth_spec_instance,
spec,
validator_keypairs,
1 << 32,
config,
)
}

/// Instantiate a new harness with a custom `target_aggregators_per_committee` spec value
pub fn new_with_target_aggregators(
eth_spec_instance: E,
spec: Option<ChainSpec>,
validator_keypairs: Vec<Keypair>,
target_aggregators_per_committee: u64,
store_config: StoreConfig,
) -> Self {
Self::new_with_chain_config(
eth_spec_instance,
spec,
validator_keypairs,
target_aggregators_per_committee,
store_config,
Expand All @@ -196,13 +210,14 @@ impl<E: EthSpec> BeaconChainHarness<EphemeralHarnessType<E>> {
/// `target_aggregators_per_committee` spec value, and a `ChainConfig`
pub fn new_with_chain_config(
eth_spec_instance: E,
spec: Option<ChainSpec>,
validator_keypairs: Vec<Keypair>,
target_aggregators_per_committee: u64,
store_config: StoreConfig,
chain_config: ChainConfig,
) -> Self {
let data_dir = tempdir().expect("should create temporary data_dir");
let mut spec = test_spec::<E>();
let mut spec = spec.unwrap_or_else(test_spec::<E>);

spec.target_aggregators_per_committee = target_aggregators_per_committee;

Expand Down Expand Up @@ -250,11 +265,12 @@ impl<E: EthSpec> BeaconChainHarness<DiskHarnessType<E>> {
/// Instantiate a new harness with `validator_count` initial validators.
pub fn new_with_disk_store(
eth_spec_instance: E,
spec: Option<ChainSpec>,
store: Arc<HotColdDB<E, LevelDB<E>, LevelDB<E>>>,
validator_keypairs: Vec<Keypair>,
) -> Self {
let data_dir = tempdir().expect("should create temporary data_dir");
let spec = test_spec::<E>();
let spec = spec.unwrap_or_else(test_spec::<E>);

let log = test_logger();
let (shutdown_tx, shutdown_receiver) = futures::channel::mpsc::channel(1);
Expand Down Expand Up @@ -294,11 +310,12 @@ impl<E: EthSpec> BeaconChainHarness<DiskHarnessType<E>> {
/// Instantiate a new harness with `validator_count` initial validators.
pub fn resume_from_disk_store(
eth_spec_instance: E,
spec: Option<ChainSpec>,
store: Arc<HotColdDB<E, LevelDB<E>, LevelDB<E>>>,
validator_keypairs: Vec<Keypair>,
data_dir: TempDir,
) -> Self {
let spec = test_spec::<E>();
let spec = spec.unwrap_or_else(test_spec::<E>);

let log = test_logger();
let (shutdown_tx, shutdown_receiver) = futures::channel::mpsc::channel(1);
Expand Down
1 change: 1 addition & 0 deletions beacon_node/beacon_chain/src/validator_pubkey_cache.rs
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,7 @@ mod test {
fn get_state(validator_count: usize) -> (BeaconState<E>, Vec<Keypair>) {
let harness = BeaconChainHarness::new_with_store_config(
MainnetEthSpec,
None,
types::test_utils::generate_deterministic_keypairs(validator_count),
StoreConfig::default(),
);
Expand Down
1 change: 1 addition & 0 deletions beacon_node/beacon_chain/tests/attestation_production.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ fn produces_attestations() {

let harness = BeaconChainHarness::new_with_store_config(
MainnetEthSpec,
None,
KEYPAIRS[..].to_vec(),
StoreConfig::default(),
);
Expand Down
1 change: 1 addition & 0 deletions beacon_node/beacon_chain/tests/attestation_verification.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ lazy_static! {
fn get_harness(validator_count: usize) -> BeaconChainHarness<EphemeralHarnessType<E>> {
let harness = BeaconChainHarness::new_with_target_aggregators(
MainnetEthSpec,
None,
KEYPAIRS[0..validator_count].to_vec(),
// A kind-of arbitrary number that ensures that _some_ validators are aggregators, but
// not all.
Expand Down
Loading