From b8bc548aaae585daabbbd78df315bcd53842b50f Mon Sep 17 00:00:00 2001 From: Paul Hauner Date: Mon, 25 Nov 2019 18:18:41 +1100 Subject: [PATCH] Use time instead of skip count for denying long skips --- beacon_node/beacon_chain/src/beacon_chain.rs | 40 ++++++++++---------- beacon_node/beacon_chain/src/errors.rs | 4 +- 2 files changed, 22 insertions(+), 22 deletions(-) diff --git a/beacon_node/beacon_chain/src/beacon_chain.rs b/beacon_node/beacon_chain/src/beacon_chain.rs index 95d682cc4a..28dfbcb6c4 100644 --- a/beacon_node/beacon_chain/src/beacon_chain.rs +++ b/beacon_node/beacon_chain/src/beacon_chain.rs @@ -26,6 +26,7 @@ use state_processing::{ use std::fs; use std::io::prelude::*; use std::sync::Arc; +use std::time::{Duration, Instant}; use store::iter::{BlockRootsIterator, StateRootsIterator}; use store::{Error as DBError, Store}; use tree_hash::TreeHash; @@ -43,9 +44,6 @@ pub const GRAFFITI: &str = "sigp/lighthouse-0.0.0-prerelease"; /// Only useful for testing. const WRITE_BLOCK_PROCESSING_SSZ: bool = cfg!(feature = "write_ssz_files"); -const BLOCK_SKIPPING_LOGGING_THRESHOLD: u64 = 3; -const BLOCK_SKIPPING_FAILURE_THRESHOLD: u64 = 128; - #[derive(Debug, PartialEq)] pub enum BlockProcessingOutcome { /// Block was valid and imported into the block graph. @@ -350,34 +348,34 @@ impl BeaconChain { if slot == head_state.slot { Ok(head_state) } else if slot > head_state.slot { - // It is presently very resource intensive (lots of hashing) to skip slots. - // - // We log warnings or simply fail if there are too many skip slots. This is a - // protection against DoS attacks. - if slot > head_state.slot + BLOCK_SKIPPING_FAILURE_THRESHOLD { - error!( - self.log, - "Refusing to skip more than {} blocks", BLOCK_SKIPPING_FAILURE_THRESHOLD; - "head_slot" => head_state.slot, - "request_slot" => slot - ); - - return Err(Error::StateSkipTooLarge { - head_slot: head_state.slot, - requested_slot: slot, - }); - } else if slot > head_state.slot + BLOCK_SKIPPING_LOGGING_THRESHOLD { + if slot > head_state.slot + T::EthSpec::slots_per_epoch() { warn!( self.log, - "Skipping more than {} blocks", BLOCK_SKIPPING_LOGGING_THRESHOLD; + "Skipping more than an epoch"; "head_slot" => head_state.slot, "request_slot" => slot ) } + let start_slot = head_state.slot; + let task_start = Instant::now(); + let max_task_runtime = Duration::from_millis(self.spec.milliseconds_per_slot); + let head_state_slot = head_state.slot; let mut state = head_state; while state.slot < slot { + // Do not allow and forward state skip that takes longer than the maximum task duration. + // + // This is a protection against nodes doing too much work when they're not synced + // to a chain. + if task_start + max_task_runtime < Instant::now() { + return Err(Error::StateSkipTooLarge { + start_slot, + requested_slot: slot, + max_task_runtime, + }); + } + match per_slot_processing(&mut state, &self.spec) { Ok(()) => (), Err(e) => { diff --git a/beacon_node/beacon_chain/src/errors.rs b/beacon_node/beacon_chain/src/errors.rs index fa29432bb1..1dae2ff197 100644 --- a/beacon_node/beacon_chain/src/errors.rs +++ b/beacon_node/beacon_chain/src/errors.rs @@ -4,6 +4,7 @@ use ssz_types::Error as SszTypesError; use state_processing::per_block_processing::errors::AttestationValidationError; use state_processing::BlockProcessingError; use state_processing::SlotProcessingError; +use std::time::Duration; use types::*; macro_rules! easy_from_to { @@ -40,8 +41,9 @@ pub enum BeaconChainError { }, AttestationValidationError(AttestationValidationError), StateSkipTooLarge { - head_slot: Slot, + start_slot: Slot, requested_slot: Slot, + max_task_runtime: Duration, }, /// Returned when an internal check fails, indicating corrupt data. InvariantViolated(String),