diff --git a/beacon_node/beacon_chain/src/attestation_verification.rs b/beacon_node/beacon_chain/src/attestation_verification.rs index 6502e106b..b81daa4bd 100644 --- a/beacon_node/beacon_chain/src/attestation_verification.rs +++ b/beacon_node/beacon_chain/src/attestation_verification.rs @@ -549,7 +549,7 @@ fn verify_head_block_is_known( { // 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 { + if attestation.data.slot > block.slot + max_skip_slots { return Err(Error::TooManySkippedSlots { head_block_slot: block.slot, attestation_slot: attestation.data.slot, diff --git a/beacon_node/beacon_chain/src/block_verification.rs b/beacon_node/beacon_chain/src/block_verification.rs index 520ebcea5..9f25186ed 100644 --- a/beacon_node/beacon_chain/src/block_verification.rs +++ b/beacon_node/beacon_chain/src/block_verification.rs @@ -431,6 +431,9 @@ impl GossipVerifiedBlock { let (mut parent, block) = load_parent(block, chain)?; + // Reject any block that exceeds our limit on skipped slots. + check_block_skip_slots(chain, &parent.beacon_block.message, &block.message)?; + let state = cheap_state_advance_to_obtain_committees( &mut parent.beacon_state, block.slot(), @@ -517,6 +520,10 @@ impl SignatureVerifiedBlock { chain: &BeaconChain, ) -> Result> { let (mut parent, block) = load_parent(block, chain)?; + + // Reject any block that exceeds our limit on skipped slots. + check_block_skip_slots(chain, &parent.beacon_block.message, &block.message)?; + let block_root = get_block_root(&block); let state = cheap_state_advance_to_obtain_committees( @@ -648,14 +655,7 @@ impl<'a, T: BeaconChainTypes> FullyVerifiedBlock<'a, T> { } // 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(), - }); - } - } + check_block_skip_slots(chain, &parent.beacon_block.message, &block.message)?; /* * Perform cursory checks to see if the block is even worth processing. @@ -799,6 +799,30 @@ impl<'a, T: BeaconChainTypes> FullyVerifiedBlock<'a, T> { } } +/// Check that the count of skip slots between the block and its parent does not exceed our maximum +/// value. +/// +/// Whilst this is not part of the specification, we include this to help prevent us from DoS +/// attacks. In times of dire network circumstance, the user can configure the +/// `import_max_skip_slots` value. +fn check_block_skip_slots( + chain: &BeaconChain, + parent: &BeaconBlock, + block: &BeaconBlock, +) -> Result<(), BlockError> { + // 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.slot + max_skip_slots { + return Err(BlockError::TooManySkippedSlots { + parent_slot: parent.slot, + block_slot: block.slot, + }); + } + } + + Ok(()) +} + /// Returns `Ok(())` if the block is later than the finalized slot on `chain`. /// /// Returns an error if the block is earlier or equal to the finalized slot, or there was an error