From 44a560e9644a5667584493ae00443c34cb4b49fb Mon Sep 17 00:00:00 2001 From: Arkadiy Paronyan Date: Mon, 24 Oct 2016 15:09:13 +0200 Subject: [PATCH] CLI option to skip seal check when importing (#2842) --- ethcore/src/client/client.rs | 2 +- ethcore/src/client/config.rs | 2 ++ ethcore/src/client/mod.rs | 1 + ethcore/src/verification/mod.rs | 14 +++++++++++++- ethcore/src/verification/queue/kind.rs | 13 ++++++++----- ethcore/src/verification/queue/mod.rs | 8 ++++---- ethcore/src/verification/verification.rs | 10 ++++++---- parity/blockchain.rs | 6 ++++-- parity/cli/mod.rs | 2 ++ parity/cli/usage.txt | 1 + parity/configuration.rs | 7 +++++++ parity/helpers.rs | 4 +++- parity/run.rs | 2 ++ parity/snapshot.rs | 2 +- 14 files changed, 55 insertions(+), 19 deletions(-) diff --git a/ethcore/src/client/client.rs b/ethcore/src/client/client.rs index ffb44c8c2..49195d952 100644 --- a/ethcore/src/client/client.rs +++ b/ethcore/src/client/client.rs @@ -204,7 +204,7 @@ impl Client { let engine = spec.engine.clone(); - let block_queue = BlockQueue::new(config.queue.clone(), engine.clone(), message_channel.clone()); + let block_queue = BlockQueue::new(config.queue.clone(), engine.clone(), message_channel.clone(), config.verifier_type.verifying_seal()); let panic_handler = PanicHandler::new_in_arc(); panic_handler.forward_from(&block_queue); diff --git a/ethcore/src/client/config.rs b/ethcore/src/client/config.rs index b87da437f..850e5c938 100644 --- a/ethcore/src/client/config.rs +++ b/ethcore/src/client/config.rs @@ -117,6 +117,8 @@ pub struct ClientConfig { pub jump_table_size: usize, /// State pruning history size. pub history: u64, + /// Check seal valididity on block import + pub check_seal: bool, } #[cfg(test)] diff --git a/ethcore/src/client/mod.rs b/ethcore/src/client/mod.rs index 1e8aa9d72..3898ab6cd 100644 --- a/ethcore/src/client/mod.rs +++ b/ethcore/src/client/mod.rs @@ -37,6 +37,7 @@ pub use block_import_error::BlockImportError; pub use transaction_import::TransactionImportResult; pub use transaction_import::TransactionImportError; pub use self::traits::{BlockChainClient, MiningBlockChainClient}; +pub use verification::VerifierType; /// IPC interfaces #[cfg(feature="ipc")] diff --git a/ethcore/src/verification/mod.rs b/ethcore/src/verification/mod.rs index ed9e0ec4c..239c88597 100644 --- a/ethcore/src/verification/mod.rs +++ b/ethcore/src/verification/mod.rs @@ -31,6 +31,8 @@ pub use self::queue::{BlockQueue, Config as QueueConfig, VerificationQueue, Queu pub enum VerifierType { /// Verifies block normally. Canon, + /// Verifies block normallly, but skips seal verification. + CanonNoSeal, /// Does not verify block at all. /// Used in tests. Noop, @@ -44,7 +46,17 @@ impl Default for VerifierType { pub fn new(v: VerifierType) -> Box { match v { - VerifierType::Canon => Box::new(CanonVerifier), + VerifierType::Canon | VerifierType::CanonNoSeal => Box::new(CanonVerifier), VerifierType::Noop => Box::new(NoopVerifier), } } + +impl VerifierType { + /// Check if seal verification is enabled for this verifier type. + pub fn verifying_seal(&self) -> bool { + match *self { + VerifierType::Canon => true, + VerifierType::Noop | VerifierType::CanonNoSeal => false, + } + } +} diff --git a/ethcore/src/verification/queue/kind.rs b/ethcore/src/verification/queue/kind.rs index b6b6c5cf6..17b997490 100644 --- a/ethcore/src/verification/queue/kind.rs +++ b/ethcore/src/verification/queue/kind.rs @@ -57,7 +57,7 @@ pub trait Kind: 'static + Sized + Send + Sync { fn create(input: Self::Input, engine: &Engine) -> Result; /// Attempt to verify the `Unverified` item using the given engine. - fn verify(unverified: Self::Unverified, engine: &Engine) -> Result; + fn verify(unverified: Self::Unverified, engine: &Engine, check_seal: bool) -> Result; } /// The blocks verification module. @@ -89,9 +89,9 @@ pub mod blocks { } } - fn verify(un: Self::Unverified, engine: &Engine) -> Result { + fn verify(un: Self::Unverified, engine: &Engine, check_seal: bool) -> Result { let hash = un.hash(); - match verify_block_unordered(un.header, un.bytes, engine) { + match verify_block_unordered(un.header, un.bytes, engine, check_seal) { Ok(verified) => Ok(verified), Err(e) => { warn!(target: "client", "Stage 2 block verification failed for {}: {:?}", hash, e); @@ -176,8 +176,11 @@ pub mod headers { verify_header_params(&input, engine).map(|_| input) } - fn verify(unverified: Self::Unverified, engine: &Engine) -> Result { - engine.verify_block_unordered(&unverified, None).map(|_| unverified) + fn verify(unverified: Self::Unverified, engine: &Engine, check_seal: bool) -> Result { + match check_seal { + true => engine.verify_block_unordered(&unverified, None).map(|_| unverified), + false => Ok(unverified), + } } } } diff --git a/ethcore/src/verification/queue/mod.rs b/ethcore/src/verification/queue/mod.rs index cf6ca3f53..c4ee53c23 100644 --- a/ethcore/src/verification/queue/mod.rs +++ b/ethcore/src/verification/queue/mod.rs @@ -159,7 +159,7 @@ struct Verification { impl VerificationQueue { /// Creates a new queue instance. - pub fn new(config: Config, engine: Arc, message_channel: IoChannel) -> Self { + pub fn new(config: Config, engine: Arc, message_channel: IoChannel, check_seal: bool) -> Self { let verification = Arc::new(Verification { unverified: Mutex::new(VecDeque::new()), verifying: Mutex::new(VecDeque::new()), @@ -198,7 +198,7 @@ impl VerificationQueue { .name(format!("Verifier #{}", i)) .spawn(move || { panic_handler.catch_panic(move || { - VerificationQueue::verify(verification, engine, more_to_verify, ready_signal, deleting, empty) + VerificationQueue::verify(verification, engine, more_to_verify, ready_signal, deleting, empty, check_seal) }).unwrap() }) .expect("Error starting block verification thread") @@ -219,7 +219,7 @@ impl VerificationQueue { } } - fn verify(verification: Arc>, engine: Arc, wait: Arc, ready: Arc, deleting: Arc, empty: Arc) { + fn verify(verification: Arc>, engine: Arc, wait: Arc, ready: Arc, deleting: Arc, empty: Arc, check_seal: bool) { while !deleting.load(AtomicOrdering::Acquire) { { let mut more_to_verify = verification.more_to_verify.lock().unwrap(); @@ -253,7 +253,7 @@ impl VerificationQueue { }; let hash = item.hash(); - let is_ready = match K::verify(item, &*engine) { + let is_ready = match K::verify(item, &*engine, check_seal) { Ok(verified) => { let mut verifying = verification.verifying.lock(); let mut idx = None; diff --git a/ethcore/src/verification/verification.rs b/ethcore/src/verification/verification.rs index 2d297499d..eefed1261 100644 --- a/ethcore/src/verification/verification.rs +++ b/ethcore/src/verification/verification.rs @@ -66,10 +66,12 @@ pub fn verify_block_basic(header: &Header, bytes: &[u8], engine: &Engine) -> Res /// Phase 2 verification. Perform costly checks such as transaction signatures and block nonce for ethash. /// Still operates on a individual block /// Returns a `PreverifiedBlock` structure populated with transactions -pub fn verify_block_unordered(header: Header, bytes: Bytes, engine: &Engine) -> Result { - try!(engine.verify_block_unordered(&header, Some(&bytes))); - for u in try!(UntrustedRlp::new(&bytes).at(2)).iter().map(|rlp| rlp.as_val::
()) { - try!(engine.verify_block_unordered(&try!(u), None)); +pub fn verify_block_unordered(header: Header, bytes: Bytes, engine: &Engine, check_seal: bool) -> Result { + if check_seal { + try!(engine.verify_block_unordered(&header, Some(&bytes))); + for u in try!(UntrustedRlp::new(&bytes).at(2)).iter().map(|rlp| rlp.as_val::
()) { + try!(engine.verify_block_unordered(&try!(u), None)); + } } // Verify transactions. let mut transactions = Vec::new(); diff --git a/parity/blockchain.rs b/parity/blockchain.rs index fbf25e1cf..2e0fb4233 100644 --- a/parity/blockchain.rs +++ b/parity/blockchain.rs @@ -84,6 +84,7 @@ pub struct ImportBlockchain { pub tracing: Switch, pub fat_db: Switch, pub vm_type: VMType, + pub check_seal: bool, } #[derive(Debug, PartialEq)] @@ -103,6 +104,7 @@ pub struct ExportBlockchain { pub tracing: Switch, pub from_block: BlockID, pub to_block: BlockID, + pub check_seal: bool, } pub fn execute(cmd: BlockchainCmd) -> Result { @@ -158,7 +160,7 @@ fn execute_import(cmd: ImportBlockchain) -> Result { try!(execute_upgrades(&db_dirs, algorithm, cmd.compaction.compaction_profile(db_dirs.fork_path().as_path()))); // prepare client config - let client_config = to_client_config(&cmd.cache_config, cmd.mode, tracing, fat_db, cmd.compaction, cmd.wal, cmd.vm_type, "".into(), algorithm, cmd.pruning_history); + let client_config = to_client_config(&cmd.cache_config, cmd.mode, tracing, fat_db, cmd.compaction, cmd.wal, cmd.vm_type, "".into(), algorithm, cmd.pruning_history, cmd.check_seal); // build client let service = try!(ClientService::start( @@ -309,7 +311,7 @@ fn execute_export(cmd: ExportBlockchain) -> Result { try!(execute_upgrades(&db_dirs, algorithm, cmd.compaction.compaction_profile(db_dirs.fork_path().as_path()))); // prepare client config - let client_config = to_client_config(&cmd.cache_config, cmd.mode, tracing, fat_db, cmd.compaction, cmd.wal, VMType::default(), "".into(), algorithm, cmd.pruning_history); + let client_config = to_client_config(&cmd.cache_config, cmd.mode, tracing, fat_db, cmd.compaction, cmd.wal, VMType::default(), "".into(), algorithm, cmd.pruning_history, cmd.check_seal); let service = try!(ClientService::start( client_config, diff --git a/parity/cli/mod.rs b/parity/cli/mod.rs index a8e1cdba7..9c4a45e12 100644 --- a/parity/cli/mod.rs +++ b/parity/cli/mod.rs @@ -234,6 +234,7 @@ usage! { flag_from: String = "1", or |_| None, flag_to: String = "latest", or |_| None, flag_format: Option = None, or |_| None, + flag_no_seal_check: bool = false, or |_| None, // -- Snapshot Optons flag_at: String = "latest", or |_| None, @@ -561,6 +562,7 @@ mod tests { flag_from: "1".into(), flag_to: "latest".into(), flag_format: None, + flag_no_seal_check: false, // -- Snapshot Optons flag_at: "latest".into(), diff --git a/parity/cli/usage.txt b/parity/cli/usage.txt index 8bf99c5e7..fe6203842 100644 --- a/parity/cli/usage.txt +++ b/parity/cli/usage.txt @@ -247,6 +247,7 @@ Import/Export Options: --format FORMAT For import/export in given format. FORMAT must be one of 'hex' and 'binary'. (default: {flag_format:?} = Import: auto, Export: binary) + --no-seal-check Skip block seal check. (default: {flag_no_seal_check}) Snapshot Options: --at BLOCK Take a snapshot at the given block, which may be an diff --git a/parity/configuration.rs b/parity/configuration.rs index ddfb03669..060679b0e 100644 --- a/parity/configuration.rs +++ b/parity/configuration.rs @@ -154,6 +154,7 @@ impl Configuration { tracing: tracing, fat_db: fat_db, vm_type: vm_type, + check_seal: !self.args.flag_no_seal_check, }; Cmd::Blockchain(BlockchainCmd::Import(import_cmd)) } else if self.args.cmd_export { @@ -173,6 +174,7 @@ impl Configuration { fat_db: fat_db, from_block: try!(to_block_id(&self.args.flag_from)), to_block: try!(to_block_id(&self.args.flag_to)), + check_seal: !self.args.flag_no_seal_check, }; Cmd::Blockchain(BlockchainCmd::Export(export_cmd)) } else if self.args.cmd_snapshot { @@ -251,6 +253,7 @@ impl Configuration { name: self.args.flag_identity, custom_bootnodes: self.args.flag_bootnodes.is_some(), no_periodic_snapshot: self.args.flag_no_periodic_snapshot, + check_seal: !self.args.flag_no_seal_check, }; Cmd::Run(run_cmd) }; @@ -738,6 +741,7 @@ mod tests { tracing: Default::default(), fat_db: Default::default(), vm_type: VMType::Interpreter, + check_seal: true, }))); } @@ -761,6 +765,7 @@ mod tests { fat_db: Default::default(), from_block: BlockID::Number(1), to_block: BlockID::Latest, + check_seal: true, }))); } @@ -784,6 +789,7 @@ mod tests { fat_db: Default::default(), from_block: BlockID::Number(1), to_block: BlockID::Latest, + check_seal: true, }))); } @@ -832,6 +838,7 @@ mod tests { custom_bootnodes: false, fat_db: Default::default(), no_periodic_snapshot: false, + check_seal: true, })); } diff --git a/parity/helpers.rs b/parity/helpers.rs index af947329b..a965314f5 100644 --- a/parity/helpers.rs +++ b/parity/helpers.rs @@ -21,7 +21,7 @@ use std::path::Path; use std::fs::File; use util::{clean_0x, U256, Uint, Address, path, CompactionProfile}; use util::journaldb::Algorithm; -use ethcore::client::{Mode, BlockID, VMType, DatabaseCompactionProfile, ClientConfig}; +use ethcore::client::{Mode, BlockID, VMType, DatabaseCompactionProfile, ClientConfig, VerifierType}; use ethcore::miner::{PendingSet, GasLimit, PrioritizationStrategy}; use cache::CacheConfig; use dir::DatabaseDirectories; @@ -215,6 +215,7 @@ pub fn to_client_config( name: String, pruning: Algorithm, pruning_history: u64, + check_seal: bool, ) -> ClientConfig { let mut client_config = ClientConfig::default(); @@ -247,6 +248,7 @@ pub fn to_client_config( client_config.db_wal = wal; client_config.vm_type = vm_type; client_config.name = name; + client_config.verifier_type = if check_seal { VerifierType::Canon } else { VerifierType::CanonNoSeal }; client_config } diff --git a/parity/run.rs b/parity/run.rs index 46cc543f2..7f35f3514 100644 --- a/parity/run.rs +++ b/parity/run.rs @@ -90,6 +90,7 @@ pub struct RunCmd { pub name: String, pub custom_bootnodes: bool, pub no_periodic_snapshot: bool, + pub check_seal: bool, } pub fn execute(cmd: RunCmd) -> Result<(), String> { @@ -197,6 +198,7 @@ pub fn execute(cmd: RunCmd) -> Result<(), String> { cmd.name, algorithm, cmd.pruning_history, + cmd.check_seal, ); // set up bootnodes diff --git a/parity/snapshot.rs b/parity/snapshot.rs index dc146d8fe..e5c3c672c 100644 --- a/parity/snapshot.rs +++ b/parity/snapshot.rs @@ -163,7 +163,7 @@ impl SnapshotCommand { try!(execute_upgrades(&db_dirs, algorithm, self.compaction.compaction_profile(db_dirs.fork_path().as_path()))); // prepare client config - let client_config = to_client_config(&self.cache_config, self.mode, tracing, fat_db, self.compaction, self.wal, VMType::default(), "".into(), algorithm, self.pruning_history); + let client_config = to_client_config(&self.cache_config, self.mode, tracing, fat_db, self.compaction, self.wal, VMType::default(), "".into(), algorithm, self.pruning_history, true); let service = try!(ClientService::start( client_config,