From ff4d68d2be12b2b1b5f153d7c6c8d1f796df2c1d Mon Sep 17 00:00:00 2001 From: Antioch Peverell <30642645+antiochp@users.noreply.github.com> Date: Wed, 21 Mar 2018 16:50:08 -0400 Subject: [PATCH] config to enable full chain validation per block (#839) * default to full chain validation on processing each block (except during sync) * add sample config for chain_validation_mode * document chain_validation_mode --- grin.toml | 6 ++++++ grin/src/adapters.rs | 36 +++++++++++++++++++++++++++++++++++- grin/src/server.rs | 1 + grin/src/types.rs | 21 +++++++++++++++++++++ 4 files changed, 63 insertions(+), 1 deletion(-) diff --git a/grin.toml b/grin.toml index ef7c21907..1ef71c397 100644 --- a/grin.toml +++ b/grin.toml @@ -42,6 +42,12 @@ db_root = ".grin" # chain_type = "Testnet2" +#The chain validation mode, defines how often (if at all) we +#want to run a full chain validation. Can be: +#EveryBlock - run full chain validation when processing each block (except during sync) +#Disabled - disable full chain validation (just run regular block validation) +#chain_validation_mode=EveryBlock + #run the node in "full archive" mode (default is fast-sync, pruned node) #archive_mode = false diff --git a/grin/src/adapters.rs b/grin/src/adapters.rs index d93cc5231..74be3e1c9 100644 --- a/grin/src/adapters.rs +++ b/grin/src/adapters.rs @@ -17,6 +17,7 @@ use std::net::SocketAddr; use std::ops::Deref; use std::sync::{Arc, RwLock, Weak}; use std::sync::atomic::{AtomicBool, Ordering}; +use std::time::Instant; use rand; use rand::Rng; @@ -30,6 +31,7 @@ use p2p; use pool; use util::OneTime; use store; +use types::{ChainValidationMode, ServerConfig}; use util::LOGGER; // All adapters use `Weak` references instead of `Arc` to avoid cycles that @@ -51,6 +53,7 @@ pub struct NetToChainAdapter { chain: Weak, tx_pool: Arc>>, peers: OneTime>, + config: ServerConfig, } impl p2p::ChainAdapter for NetToChainAdapter { @@ -334,12 +337,14 @@ impl NetToChainAdapter { currently_syncing: Arc, chain_ref: Weak, tx_pool: Arc>>, + config: ServerConfig, ) -> NetToChainAdapter { NetToChainAdapter { currently_syncing: currently_syncing, chain: chain_ref, tx_pool: tx_pool, peers: OneTime::new(), + config: config, } } @@ -388,7 +393,7 @@ impl NetToChainAdapter { let prev_hash = b.header.previous; let bhash = b.hash(); let chain = w(&self.chain); - match chain.process_block(b, self.chain_opts()) { + let result = match chain.process_block(b, self.chain_opts()) { Ok(_) => true, Err(chain::Error::Orphan) => { // make sure we did not miss the parent block @@ -415,7 +420,36 @@ impl NetToChainAdapter { ); true } + }; + + // If we are running in "validate the full chain every block" then + // panic here if validation fails for any reason. + // We are out of consensus at this point and want to track the problem + // down as soon as possible. + // Skip this if we are currently syncing (too slow). + if !self.currently_syncing.load(Ordering::Relaxed) + && self.config.chain_validation_mode == ChainValidationMode::EveryBlock + { + let now = Instant::now(); + + debug!( + LOGGER, + "adapter: process_block: ***** validating full chain state at {}", bhash, + ); + + let chain = w(&self.chain); + chain + .validate(true) + .expect("chain validation failed, hard stop"); + + debug!( + LOGGER, + "adapter: process_block: ***** done validating full chain state, took {}s", + now.elapsed().as_secs(), + ); } + + result } // After receiving a compact block if we cannot successfully hydrate diff --git a/grin/src/server.rs b/grin/src/server.rs index ce48fad31..ce743e877 100644 --- a/grin/src/server.rs +++ b/grin/src/server.rs @@ -120,6 +120,7 @@ impl Server { currently_syncing.clone(), Arc::downgrade(&shared_chain), tx_pool.clone(), + config.clone(), )); let p2p_config = config.p2p_config.clone(); diff --git a/grin/src/types.rs b/grin/src/types.rs index 7e77c52ea..4d980ede2 100644 --- a/grin/src/types.rs +++ b/grin/src/types.rs @@ -86,6 +86,22 @@ impl From for Error { } } +/// Type of seeding the server will use to find other peers on the network. +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +pub enum ChainValidationMode { + /// Run full chain validation after processing every block. + EveryBlock, + /// Do not automatically run chain validation during normal block + /// processing. + Disabled, +} + +impl Default for ChainValidationMode { + fn default() -> ChainValidationMode { + ChainValidationMode::EveryBlock + } +} + /// Type of seeding the server will use to find other peers on the network. #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] pub enum Seeding { @@ -122,6 +138,10 @@ pub struct ServerConfig { /// Whether this node is a full archival node or a fast-sync, pruned node pub archive_mode: Option, + /// Automatically run full chain validation during normal block processing? + #[serde(default)] + pub chain_validation_mode: ChainValidationMode, + /// Method used to get the list of seed nodes for initial bootstrap. #[serde(default)] pub seeding_type: Seeding, @@ -169,6 +189,7 @@ impl Default for ServerConfig { mining_config: Some(pow::types::MinerConfig::default()), chain_type: ChainTypes::default(), archive_mode: None, + chain_validation_mode: ChainValidationMode::default(), pool_config: pool::PoolConfig::default(), skip_sync_wait: None, run_tui: None,