diff --git a/Cargo.lock b/Cargo.lock index a6fa12b3a..6597c44a1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -24,7 +24,7 @@ dependencies = [ "ethcore-stratum 1.4.0", "ethcore-util 1.5.0", "ethsync 1.5.0", - "fdlimit 0.1.0", + "fdlimit 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "hyper 0.9.10 (registry+https://github.com/rust-lang/crates.io-index)", "isatty 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -684,7 +684,8 @@ dependencies = [ [[package]] name = "fdlimit" -version = "0.1.0" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "libc 0.2.16 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -1270,7 +1271,7 @@ dependencies = [ [[package]] name = "parity-ui-precompiled" version = "1.4.0" -source = "git+https://github.com/ethcore/js-precompiled.git#7700411d2b0ba1372e0d6cf72a84ecf873a181f3" +source = "git+https://github.com/ethcore/js-precompiled.git#3cf6c68b7d08be71d12ff142e255a42043e50c75" dependencies = [ "parity-dapps-glue 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -2027,6 +2028,7 @@ dependencies = [ "checksum env_logger 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "aba65b63ffcc17ffacd6cf5aa843da7c5a25e3bd4bbe0b7def8b214e411250e5" "checksum eth-secp256k1 0.5.4 (git+https://github.com/ethcore/rust-secp256k1)" = "" "checksum ethabi 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f7b0c53453517f620847be51943db329276ae52f2e210cfc659e81182864be2f" +"checksum fdlimit 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b1ee15a7050e5580b3712877157068ea713b245b080ff302ae2ca973cfcd9baa" "checksum flate2 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "3eeb481e957304178d2e782f2da1257f1434dfecbae883bafb61ada2a9fea3bb" "checksum gcc 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)" = "91ecd03771effb0c968fd6950b37e89476a578aaf1c70297d8e92b6516ec3312" "checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb" diff --git a/Cargo.toml b/Cargo.toml index e0e4df2e9..078d2916c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,7 +30,7 @@ serde = "0.8.0" serde_json = "0.8.0" hyper = { version = "0.9", default-features = false } ctrlc = { git = "https://github.com/ethcore/rust-ctrlc.git" } -fdlimit = { path = "util/fdlimit" } +fdlimit = "0.1" ethcore = { path = "ethcore" } ethcore-util = { path = "util" } ethsync = { path = "sync" } diff --git a/ethcore/src/blockchain/blockchain.rs b/ethcore/src/blockchain/blockchain.rs index 84285c945..0e8e0a271 100644 --- a/ethcore/src/blockchain/blockchain.rs +++ b/ethcore/src/blockchain/blockchain.rs @@ -200,6 +200,7 @@ pub struct BlockChain { pending_block_details: RwLock>, pending_transaction_addresses: RwLock>>, + // Used for block ordering. engine: Arc, } diff --git a/ethcore/src/engines/authority_round.rs b/ethcore/src/engines/authority_round.rs index f59fd0b17..584ab6f54 100644 --- a/ethcore/src/engines/authority_round.rs +++ b/ethcore/src/engines/authority_round.rs @@ -209,10 +209,6 @@ impl Engine for AuthorityRound { }); } - /// Apply the block reward on finalisation of the block. - /// This assumes that all uncles are valid uncles (i.e. of at least one generation before the current). - fn on_close_block(&self, _block: &mut ExecutedBlock) {} - fn is_sealer(&self, author: &Address) -> Option { let p = &self.our_params; Some(p.authorities.contains(author)) diff --git a/ethcore/src/engines/basic_authority.rs b/ethcore/src/engines/basic_authority.rs index 0b9040a11..264a2d55a 100644 --- a/ethcore/src/engines/basic_authority.rs +++ b/ethcore/src/engines/basic_authority.rs @@ -100,13 +100,8 @@ impl Engine for BasicAuthority { max(gas_floor_target, gas_limit - gas_limit / bound_divisor + 1.into()) } }); -// info!("ethash: populate_from_parent #{}: difficulty={} and gas_limit={}", header.number, header.difficulty, header.gas_limit); } - /// Apply the block reward on finalisation of the block. - /// This assumes that all uncles are valid uncles (i.e. of at least one generation before the current). - fn on_close_block(&self, _block: &mut ExecutedBlock) {} - fn is_sealer(&self, author: &Address) -> Option { Some(self.our_params.authorities.contains(author)) } diff --git a/ethcore/src/engines/mod.rs b/ethcore/src/engines/mod.rs index 29ede0495..17cb46138 100644 --- a/ethcore/src/engines/mod.rs +++ b/ethcore/src/engines/mod.rs @@ -184,17 +184,17 @@ pub trait Engine : Sync + Send { self.builtins().get(a).expect("attempted to execute nonexistent builtin").execute(input, output); } + /// Check if new block should be chosen as the one in chain. + fn is_new_best_block(&self, best_total_difficulty: U256, _best_header: HeaderView, parent_details: &BlockDetails, new_header: &HeaderView) -> bool { + ethash::is_new_best_block(best_total_difficulty, parent_details, new_header) + } + + /// Register an account which signs consensus messages. + fn set_signer(&self, _address: Address, _password: String) {} + /// Add a channel for communication with Client which can be used for sealing. fn register_message_channel(&self, _message_channel: IoChannel) {} /// Add an account provider useful for Engines that sign stuff. fn register_account_provider(&self, _account_provider: Arc) {} - - /// Register an account which signs consensus messages. - fn set_signer(&self, _address: Address, _password: String) {} - - /// Check if new block should be chosen as the one in chain. - fn is_new_best_block(&self, best_total_difficulty: U256, _best_header: HeaderView, parent_details: &BlockDetails, new_header: &HeaderView) -> bool { - ethash::is_new_best_block(best_total_difficulty, parent_details, new_header) - } } diff --git a/ethcore/src/ethereum/ethash.rs b/ethcore/src/ethereum/ethash.rs index f5cf5d4f0..ae768e5d3 100644 --- a/ethcore/src/ethereum/ethash.rs +++ b/ethcore/src/ethereum/ethash.rs @@ -328,12 +328,16 @@ impl Engine for Ethash { t.sender().map(|_|()) // Perform EC recovery and cache sender } - /// Check if new block should be chosen as the one in chain. fn is_new_best_block(&self, best_total_difficulty: U256, _best_header: HeaderView, parent_details: &BlockDetails, new_header: &HeaderView) -> bool { is_new_best_block(best_total_difficulty, parent_details, new_header) } } +/// Check if a new block should replace the best blockchain block. +pub fn is_new_best_block(best_total_difficulty: U256, parent_details: &BlockDetails, new_header: &HeaderView) -> bool { + parent_details.total_difficulty + new_header.difficulty() > best_total_difficulty +} + #[cfg_attr(feature="dev", allow(wrong_self_convention))] impl Ethash { fn calculate_difficulty(&self, header: &Header, parent: &Header) -> U256 { @@ -409,12 +413,6 @@ impl Ethash { } } -/// Check if a new block should replace the best blockchain block. -pub fn is_new_best_block(best_total_difficulty: U256, parent_details: &BlockDetails, new_header: &HeaderView) -> bool { - parent_details.total_difficulty + new_header.difficulty() > best_total_difficulty -} - - impl Header { /// Get the none field of the header. pub fn nonce(&self) -> H64 { diff --git a/ethcore/src/miner/miner.rs b/ethcore/src/miner/miner.rs index 4b38a7e07..806ff6964 100644 --- a/ethcore/src/miner/miner.rs +++ b/ethcore/src/miner/miner.rs @@ -737,7 +737,7 @@ impl MinerService for Miner { *self.author.write() = author; } - fn set_consensus_signer(&self, address: Address, password: String) -> Result<(), AccountError> { + fn set_engine_signer(&self, address: Address, password: String) -> Result<(), AccountError> { if self.seals_internally { if let Some(ref ap) = self.accounts { try!(ap.sign(address.clone(), Some(password.clone()), Default::default())); diff --git a/ethcore/src/miner/mod.rs b/ethcore/src/miner/mod.rs index 26cefb295..8c466581b 100644 --- a/ethcore/src/miner/mod.rs +++ b/ethcore/src/miner/mod.rs @@ -77,7 +77,7 @@ pub trait MinerService : Send + Sync { fn set_author(&self, author: Address); /// Set info necessary to sign consensus messages. - fn set_consensus_signer(&self, address: Address, password: String) -> Result<(), ::account_provider::Error>; + fn set_engine_signer(&self, address: Address, password: String) -> Result<(), ::account_provider::Error>; /// Get the extra_data that we will seal blocks with. fn extra_data(&self) -> Bytes; diff --git a/ethcore/src/snapshot/service.rs b/ethcore/src/snapshot/service.rs index 47c4f992b..a7ab8bcd2 100644 --- a/ethcore/src/snapshot/service.rs +++ b/ethcore/src/snapshot/service.rs @@ -82,6 +82,7 @@ struct Restoration { struct RestorationParams<'a> { manifest: ManifestData, // manifest to base restoration on. pruning: Algorithm, // pruning algorithm for the database. + engine: Arc, // consensus engine of the chain. db_path: PathBuf, // database path db_config: &'a DatabaseConfig, // configuration for the database. writer: Option, // writer for recovered snapshot. @@ -100,7 +101,7 @@ impl Restoration { let raw_db = Arc::new(try!(Database::open(params.db_config, &*params.db_path.to_string_lossy()) .map_err(UtilError::SimpleString))); - let chain = BlockChain::new(Default::default(), params.genesis, raw_db.clone(), Spec::new_null().engine); + let chain = BlockChain::new(Default::default(), params.genesis, raw_db.clone(), params.engine); let blocks = try!(BlockRebuilder::new(chain, raw_db.clone(), &manifest)); let root = manifest.state_root.clone(); @@ -421,6 +422,7 @@ impl Service { let params = RestorationParams { manifest: manifest, pruning: self.pruning, + engine: self.engine.clone(), db_path: self.restoration_db(), db_config: &self.db_config, writer: writer, diff --git a/ethcore/src/verification/queue/mod.rs b/ethcore/src/verification/queue/mod.rs index 686a1d093..14df0819c 100644 --- a/ethcore/src/verification/queue/mod.rs +++ b/ethcore/src/verification/queue/mod.rs @@ -17,7 +17,7 @@ //! A queue of blocks. Sits between network or other I/O and the `BlockChain`. //! Sorts them ready for blockchain insertion. -use std::thread::{JoinHandle, self}; +use std::thread::{self, JoinHandle}; use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering as AtomicOrdering}; use std::sync::{Condvar as SCondvar, Mutex as SMutex}; use util::*; @@ -64,35 +64,11 @@ impl Default for Config { } } -struct VerifierHandle { - deleting: Arc, - sleep: Arc, - thread: JoinHandle<()>, -} - -impl VerifierHandle { - // signal to the verifier thread that it should sleep. - fn sleep(&self) { - self.sleep.store(true, AtomicOrdering::SeqCst); - } - - // signal to the verifier thread that it should wake up. - fn wake_up(&self) { - self.sleep.store(false, AtomicOrdering::SeqCst); - self.thread.thread().unpark(); - } - - // signal to the verifier thread that it should conclude its - // operations. - fn conclude(&self) { - self.wake_up(); - self.deleting.store(true, AtomicOrdering::Release); - } - - // join the verifier thread. - fn join(self) { - self.thread.join().expect("Verifier thread panicked"); - } +// pool states +enum State { + // all threads with id < inner value are to work. + Work(usize), + Exit, } /// An item which is in the process of being verified. @@ -131,7 +107,6 @@ pub struct VerificationQueue { engine: Arc, more_to_verify: Arc, verification: Arc>, - verifiers: Mutex<(Vec, usize)>, deleting: Arc, ready_signal: Arc, empty: Arc, @@ -139,6 +114,8 @@ pub struct VerificationQueue { ticks_since_adjustment: AtomicUsize, max_queue_size: usize, max_mem_use: usize, + verifier_handles: Vec>, + state: Arc<(Mutex, Condvar)>, } struct QueueSignal { @@ -224,40 +201,39 @@ impl VerificationQueue { let max_verifiers = min(::num_cpus::get(), MAX_VERIFIERS); let default_amount = max(::num_cpus::get(), 3) - 2; - let mut verifiers = Vec::with_capacity(max_verifiers); + let state = Arc::new((Mutex::new(State::Work(default_amount)), Condvar::new())); + let mut verifier_handles = Vec::with_capacity(max_verifiers); debug!(target: "verification", "Allocating {} verifiers, {} initially active", max_verifiers, default_amount); for i in 0..max_verifiers { debug!(target: "verification", "Adding verification thread #{}", i); - let deleting = deleting.clone(); let panic_handler = panic_handler.clone(); let verification = verification.clone(); let engine = engine.clone(); let wait = more_to_verify.clone(); let ready = ready_signal.clone(); let empty = empty.clone(); + let state = state.clone(); - // enable only the first few verifiers. - let sleep = if i < default_amount { - Arc::new(AtomicBool::new(false)) - } else { - Arc::new(AtomicBool::new(true)) - }; - - verifiers.push(VerifierHandle { - deleting: deleting.clone(), - sleep: sleep.clone(), - thread: thread::Builder::new() - .name(format!("Verifier #{}", i)) - .spawn(move || { - panic_handler.catch_panic(move || { - VerificationQueue::verify(verification, engine, wait, ready, deleting, empty, sleep) - }).unwrap() - }) - .expect("Failed to create verifier thread.") - }); + let handle = thread::Builder::new() + .name(format!("Verifier #{}", i)) + .spawn(move || { + panic_handler.catch_panic(move || { + VerificationQueue::verify( + verification, + engine, + wait, + ready, + empty, + state, + i, + ) + }).unwrap() + }) + .expect("Failed to create verifier thread."); + verifier_handles.push(handle); } VerificationQueue { @@ -266,13 +242,14 @@ impl VerificationQueue { ready_signal: ready_signal, more_to_verify: more_to_verify, verification: verification, - verifiers: Mutex::new((verifiers, default_amount)), deleting: deleting, processing: RwLock::new(HashSet::new()), empty: empty, ticks_since_adjustment: AtomicUsize::new(0), max_queue_size: max(config.max_queue_size, MIN_QUEUE_LIMIT), max_mem_use: max(config.max_mem_use, MIN_MEM_LIMIT), + verifier_handles: verifier_handles, + state: state, } } @@ -281,23 +258,30 @@ impl VerificationQueue { engine: Arc, wait: Arc, ready: Arc, - deleting: Arc, empty: Arc, - sleep: Arc, + state: Arc<(Mutex, Condvar)>, + id: usize, ) { - while !deleting.load(AtomicOrdering::Acquire) { + loop { + // check current state. { - while sleep.load(AtomicOrdering::SeqCst) { - trace!(target: "verification", "Verifier sleeping"); - ::std::thread::park(); - trace!(target: "verification", "Verifier waking up"); + let mut cur_state = state.0.lock(); + while let State::Work(x) = *cur_state { + // sleep until this thread is required. + if id < x { break } - if deleting.load(AtomicOrdering::Acquire) { - return; - } + debug!(target: "verification", "verifier {} sleeping", id); + state.1.wait(&mut cur_state); + debug!(target: "verification", "verifier {} waking up", id); + } + + if let State::Exit = *cur_state { + debug!(target: "verification", "verifier {} exiting", id); + break; } } + // wait for work if empty. { let mut more_to_verify = verification.more_to_verify.lock().unwrap(); @@ -305,15 +289,22 @@ impl VerificationQueue { empty.notify_all(); } - while verification.unverified.lock().is_empty() && !deleting.load(AtomicOrdering::Acquire) { + while verification.unverified.lock().is_empty() { + if let State::Exit = *state.0.lock() { + debug!(target: "verification", "verifier {} exiting", id); + return; + } + more_to_verify = wait.wait(more_to_verify).unwrap(); } - if deleting.load(AtomicOrdering::Acquire) { + if let State::Exit = *state.0.lock() { + debug!(target: "verification", "verifier {} exiting", id); return; } } + // do work. let item = { // acquire these locks before getting the item to verify. let mut unverified = verification.unverified.lock(); @@ -568,6 +559,14 @@ impl VerificationQueue { } } + /// Get the current number of working verifiers. + pub fn num_verifiers(&self) -> usize { + match *self.state.0.lock() { + State::Work(x) => x, + State::Exit => panic!("state only set to exit on drop; queue live now; qed"), + } + } + /// Optimise memory footprint of the heap fields, and adjust the number of threads /// to better suit the workload. pub fn collect_garbage(&self) { @@ -604,7 +603,7 @@ impl VerificationQueue { return; } - let current = self.verifiers.lock().1; + let current = self.num_verifiers(); let diff = (v_len - u_len).abs(); let total = v_len + u_len; @@ -626,27 +625,14 @@ impl VerificationQueue { // possible, never going over the amount of initially allocated threads // or below 1. fn scale_verifiers(&self, target: usize) { - let mut verifiers = self.verifiers.lock(); - let &mut (ref mut verifiers, ref mut verifier_count) = &mut *verifiers; - - let target = min(verifiers.len(), target); + let current = self.num_verifiers(); + let target = min(self.verifier_handles.len(), target); let target = max(1, target); - debug!(target: "verification", "Scaling from {} to {} verifiers", verifier_count, target); + debug!(target: "verification", "Scaling from {} to {} verifiers", current, target); - // scaling up - for i in *verifier_count..target { - debug!(target: "verification", "Waking up verifier {}", i); - verifiers[i].wake_up(); - } - - // scaling down. - for i in target..*verifier_count { - debug!(target: "verification", "Putting verifier {} to sleep", i); - verifiers[i].sleep(); - } - - *verifier_count = target; + *self.state.0.lock() = State::Work(target); + self.state.1.notify_all(); } } @@ -660,22 +646,18 @@ impl Drop for VerificationQueue { fn drop(&mut self) { trace!(target: "shutdown", "[VerificationQueue] Closing..."); self.clear(); - self.deleting.store(true, AtomicOrdering::Release); + self.deleting.store(true, AtomicOrdering::SeqCst); - let mut verifiers = self.verifiers.get_mut(); - let mut verifiers = &mut verifiers.0; - - // first pass to signal conclusion. must be done before - // notify or deadlock possible. - for handle in verifiers.iter() { - handle.conclude(); - } + // set exit state; should be done before `more_to_verify` notification. + *self.state.0.lock() = State::Exit; + self.state.1.notify_all(); + // wake up all threads waiting for more work. self.more_to_verify.notify_all(); - // second pass to join. - for handle in verifiers.drain(..) { - handle.join(); + // wait for all verifier threads to join. + for thread in self.verifier_handles.drain(..) { + thread.join().expect("Propagating verifier thread panic on shutdown"); } trace!(target: "shutdown", "[VerificationQueue] Closed."); @@ -687,7 +669,7 @@ mod tests { use util::*; use io::*; use spec::*; - use super::{BlockQueue, Config}; + use super::{BlockQueue, Config, State}; use super::kind::blocks::Unverified; use tests::helpers::*; use error::*; @@ -784,11 +766,11 @@ mod tests { let queue = get_test_queue(); queue.scale_verifiers(MAX_VERIFIERS + 1); - assert!(queue.verifiers.lock().1 < MAX_VERIFIERS + 1); + assert!(queue.num_verifiers() < MAX_VERIFIERS + 1); queue.scale_verifiers(0); - assert!(queue.verifiers.lock().1 == 1); + assert!(queue.num_verifiers() == 1); } #[test] @@ -797,14 +779,7 @@ mod tests { // put all the verifiers to sleep to ensure // the test isn't timing sensitive. - let num_verifiers = { - let verifiers = queue.verifiers.lock(); - for i in 0..verifiers.1 { - verifiers.0[i].sleep(); - } - - verifiers.1 - }; + *queue.state.0.lock() = State::Work(0); for block in get_good_dummy_block_seq(5000) { queue.import(Unverified::new(block)).expect("Block good by definition; qed"); @@ -812,20 +787,12 @@ mod tests { // almost all unverified == bump verifier count. queue.collect_garbage(); - assert_eq!(queue.verifiers.lock().1, num_verifiers + 1); - - // wake them up again and verify everything. - { - let verifiers = queue.verifiers.lock(); - for i in 0..verifiers.1 { - verifiers.0[i].wake_up(); - } - } + assert_eq!(queue.num_verifiers(), 1); queue.flush(); // nothing to verify == use minimum number of verifiers. queue.collect_garbage(); - assert_eq!(queue.verifiers.lock().1, 1); + assert_eq!(queue.num_verifiers(), 1); } } diff --git a/js/package.json b/js/package.json index 5341cee31..42836bb7c 100644 --- a/js/package.json +++ b/js/package.json @@ -1,6 +1,6 @@ { "name": "parity.js", - "version": "0.2.91", + "version": "0.2.92", "main": "release/index.js", "jsnext:main": "src/index.js", "author": "Parity Team ", diff --git a/js/src/ui/MethodDecoding/methodDecoding.js b/js/src/ui/MethodDecoding/methodDecoding.js index 70258f744..efb22b67b 100644 --- a/js/src/ui/MethodDecoding/methodDecoding.js +++ b/js/src/ui/MethodDecoding/methodDecoding.js @@ -457,6 +457,14 @@ class MethodDecoding extends Component { return; } + const { signature, paramdata } = api.util.decodeCallData(input); + this.setState({ methodSignature: signature, methodParams: paramdata }); + + if (!signature || signature === CONTRACT_CREATE || transaction.creates) { + this.setState({ isDeploy: true }); + return; + } + if (contractAddress === '0x') { return; } @@ -472,14 +480,6 @@ class MethodDecoding extends Component { return; } - const { signature, paramdata } = api.util.decodeCallData(input); - this.setState({ methodSignature: signature, methodParams: paramdata }); - - if (!signature || signature === CONTRACT_CREATE || transaction.creates) { - this.setState({ isDeploy: true }); - return; - } - return Contracts.get() .signatureReg .lookup(signature) diff --git a/parity/cli/config.full.toml b/parity/cli/config.full.toml index fcd9a9712..4f3e4fa07 100644 --- a/parity/cli/config.full.toml +++ b/parity/cli/config.full.toml @@ -61,6 +61,7 @@ pass = "test_pass" [mining] author = "0xdeadbeefcafe0000000000000000000000000001" +engine_signer = "0xdeadbeefcafe0000000000000000000000000001" force_sealing = true reseal_on_txs = "all" reseal_min_period = 4000 diff --git a/parity/cli/config.toml b/parity/cli/config.toml index c9bd563a8..34bab5b46 100644 --- a/parity/cli/config.toml +++ b/parity/cli/config.toml @@ -40,6 +40,7 @@ pass = "password" [mining] author = "0xdeadbeefcafe0000000000000000000000000001" +engine_signer = "0xdeadbeefcafe0000000000000000000000000001" force_sealing = true reseal_on_txs = "all" reseal_min_period = 4000 diff --git a/parity/cli/mod.rs b/parity/cli/mod.rs index d7df05b89..1bbdce7cd 100644 --- a/parity/cli/mod.rs +++ b/parity/cli/mod.rs @@ -178,6 +178,8 @@ usage! { // -- Sealing/Mining Options flag_author: Option = None, or |c: &Config| otry!(c.mining).author.clone().map(Some), + flag_engine_signer: Option = None, + or |c: &Config| otry!(c.mining).engine_signer.clone().map(Some), flag_force_sealing: bool = false, or |c: &Config| otry!(c.mining).force_sealing.clone(), flag_reseal_on_txs: String = "own", @@ -367,6 +369,7 @@ struct Dapps { #[derive(Default, Debug, PartialEq, RustcDecodable)] struct Mining { author: Option, + engine_signer: Option, force_sealing: Option, reseal_on_txs: Option, reseal_min_period: Option, @@ -569,6 +572,7 @@ mod tests { // -- Sealing/Mining Options flag_author: Some("0xdeadbeefcafe0000000000000000000000000001".into()), + flag_engine_signer: Some("0xdeadbeefcafe0000000000000000000000000001".into()), flag_force_sealing: true, flag_reseal_on_txs: "all".into(), flag_reseal_min_period: 4000u64, @@ -738,6 +742,7 @@ mod tests { }), mining: Some(Mining { author: Some("0xdeadbeefcafe0000000000000000000000000001".into()), + engine_signer: Some("0xdeadbeefcafe0000000000000000000000000001".into()), force_sealing: Some(true), reseal_on_txs: Some("all".into()), reseal_min_period: Some(4000), diff --git a/parity/cli/usage.txt b/parity/cli/usage.txt index b67af6110..2829f4fe1 100644 --- a/parity/cli/usage.txt +++ b/parity/cli/usage.txt @@ -149,6 +149,10 @@ Sealing/Mining Options: for sending block rewards from sealed blocks. NOTE: MINING WILL NOT WORK WITHOUT THIS OPTION. (default: {flag_author:?}) + --engine-signer ADDRESS Specify the address which should be used to + sign consensus messages and issue blocks. + Relevant only to non-PoW chains. + (default: {flag_engine_signer:?}) --force-sealing Force the node to author new blocks as if it were always sealing/mining. (default: {flag_force_sealing}) diff --git a/parity/configuration.rs b/parity/configuration.rs index 37c699521..bcca3aa58 100644 --- a/parity/configuration.rs +++ b/parity/configuration.rs @@ -300,6 +300,7 @@ impl Configuration { gas_floor_target: try!(to_u256(&self.args.flag_gas_floor_target)), gas_ceil_target: try!(to_u256(&self.args.flag_gas_cap)), transactions_limit: self.args.flag_tx_queue_size, + engine_signer: try!(self.engine_signer()), }; Ok(extras) @@ -309,6 +310,10 @@ impl Configuration { to_address(self.args.flag_etherbase.clone().or(self.args.flag_author.clone())) } + fn engine_signer(&self) -> Result { + to_address(self.args.flag_engine_signer.clone()) + } + fn format(&self) -> Result, String> { match self.args.flag_format { Some(ref f) => Ok(Some(try!(f.parse()))), diff --git a/parity/helpers.rs b/parity/helpers.rs index ab0dafddd..654270b64 100644 --- a/parity/helpers.rs +++ b/parity/helpers.rs @@ -300,14 +300,14 @@ pub fn password_prompt() -> Result { /// Read a password from password file. pub fn password_from_file(path: String) -> Result { - let passwords = try!(passwords_from_files(vec![path])); + let passwords = try!(passwords_from_files(&[path])); // use only first password from the file passwords.get(0).map(String::to_owned) .ok_or_else(|| "Password file seems to be empty.".to_owned()) } /// Reads passwords from files. Treats each line as a separate password. -pub fn passwords_from_files(files: Vec) -> Result, String> { +pub fn passwords_from_files(files: &[String]) -> Result, String> { let passwords = files.iter().map(|filename| { let file = try!(File::open(filename).map_err(|_| format!("{} Unable to read password file. Ensure it exists and permissions are correct.", filename))); let reader = BufReader::new(&file); diff --git a/parity/params.rs b/parity/params.rs index 8fdae89d4..25ddc8814 100644 --- a/parity/params.rs +++ b/parity/params.rs @@ -204,6 +204,7 @@ pub struct MinerExtras { pub gas_floor_target: U256, pub gas_ceil_target: U256, pub transactions_limit: usize, + pub engine_signer: Address, } impl Default for MinerExtras { @@ -213,7 +214,8 @@ impl Default for MinerExtras { extra_data: version_data(), gas_floor_target: U256::from(4_700_000), gas_ceil_target: U256::from(6_283_184), - transactions_limit: 2048, + transactions_limit: 1024, + engine_signer: Default::default(), } } } diff --git a/parity/run.rs b/parity/run.rs index 2509d1347..2a719fb66 100644 --- a/parity/run.rs +++ b/parity/run.rs @@ -205,8 +205,13 @@ pub fn execute(cmd: RunCmd, logger: Arc) -> Result<(), String> { sync_config.warp_sync = cmd.warp_sync; sync_config.download_old_blocks = cmd.download_old_blocks; + let passwords = try!(passwords_from_files(&cmd.acc_conf.password_files)); + // prepare account provider - let account_provider = Arc::new(try!(prepare_account_provider(&cmd.dirs, cmd.acc_conf))); + let account_provider = Arc::new(try!(prepare_account_provider(&cmd.dirs, cmd.acc_conf, &passwords))); + + // let the Engine access the accounts + spec.engine.register_account_provider(account_provider.clone()); // let the Engine access the accounts spec.engine.register_account_provider(account_provider.clone()); @@ -218,6 +223,10 @@ pub fn execute(cmd: RunCmd, logger: Arc) -> Result<(), String> { miner.set_gas_ceil_target(cmd.miner_extras.gas_ceil_target); miner.set_extra_data(cmd.miner_extras.extra_data); miner.set_transactions_limit(cmd.miner_extras.transactions_limit); + let engine_signer = cmd.miner_extras.engine_signer; + if !passwords.into_iter().any(|p| miner.set_engine_signer(engine_signer, p).is_ok()) { + return Err(format!("No password found for the consensus signer {}. Make sure valid password is present in files passed using `--password`.", cmd.miner_extras.engine_signer)); + } // create client config let client_config = to_client_config( @@ -424,19 +433,17 @@ fn daemonize(_pid_file: String) -> Result<(), String> { Err("daemon is no supported on windows".into()) } -fn prepare_account_provider(dirs: &Directories, cfg: AccountsConfig) -> Result { +fn prepare_account_provider(dirs: &Directories, cfg: AccountsConfig, passwords: &[String]) -> Result { use ethcore::ethstore::EthStore; use ethcore::ethstore::dir::DiskDirectory; - let passwords = try!(passwords_from_files(cfg.password_files)); - let dir = Box::new(try!(DiskDirectory::create(dirs.keys.clone()).map_err(|e| format!("Could not open keys directory: {}", e)))); let account_service = AccountProvider::new(Box::new( try!(EthStore::open_with_iterations(dir, cfg.iterations).map_err(|e| format!("Could not open keys directory: {}", e))) )); for a in cfg.unlocked_accounts { - if passwords.iter().find(|p| account_service.unlock_account_permanently(a, (*p).clone()).is_ok()).is_none() { + if !passwords.iter().any(|p| account_service.unlock_account_permanently(a, (*p).clone()).is_ok()) { return Err(format!("No password found to unlock account {}. Make sure valid password is present in files passed using `--password`.", a)); } } diff --git a/rpc/src/v1/impls/parity_set.rs b/rpc/src/v1/impls/parity_set.rs index e28f9a573..92de99a1f 100644 --- a/rpc/src/v1/impls/parity_set.rs +++ b/rpc/src/v1/impls/parity_set.rs @@ -116,9 +116,9 @@ impl ParitySet for ParitySetClient where Ok(true) } - fn set_consensus_signer(&self, address: H160, password: String) -> Result { + fn set_engine_signer(&self, address: H160, password: String) -> Result { try!(self.active()); - try!(take_weak!(self.miner).set_consensus_signer(address.into(), password).map_err(Into::into).map_err(errors::from_password_error)); + try!(take_weak!(self.miner).set_engine_signer(address.into(), password).map_err(Into::into).map_err(errors::from_password_error)); Ok(true) } diff --git a/rpc/src/v1/tests/helpers/miner_service.rs b/rpc/src/v1/tests/helpers/miner_service.rs index 6037cdd4a..39fba8406 100644 --- a/rpc/src/v1/tests/helpers/miner_service.rs +++ b/rpc/src/v1/tests/helpers/miner_service.rs @@ -87,7 +87,7 @@ impl MinerService for TestMinerService { *self.author.write() = author; } - fn set_consensus_signer(&self, address: Address, password: String) -> Result<(), AccountError> { + fn set_engine_signer(&self, address: Address, password: String) -> Result<(), AccountError> { *self.author.write() = address; *self.password.write() = password; Ok(()) diff --git a/rpc/src/v1/tests/mocked/parity_set.rs b/rpc/src/v1/tests/mocked/parity_set.rs index fdf3f2d0f..55f155693 100644 --- a/rpc/src/v1/tests/mocked/parity_set.rs +++ b/rpc/src/v1/tests/mocked/parity_set.rs @@ -107,14 +107,14 @@ fn rpc_parity_set_author() { } #[test] -fn rpc_parity_set_consensus_signer() { +fn rpc_parity_set_engine_signer() { let miner = miner_service(); let client = client_service(); let network = network_service(); let io = IoHandler::new(); io.add_delegate(parity_set_client(&client, &miner, &network).to_delegate()); - let request = r#"{"jsonrpc": "2.0", "method": "parity_setConsensusSigner", "params":["0xcd1722f3947def4cf144679da39c4c32bdc35681", "password"], "id": 1}"#; + let request = r#"{"jsonrpc": "2.0", "method": "parity_setEngineSigner", "params":["0xcd1722f3947def4cf144679da39c4c32bdc35681", "password"], "id": 1}"#; let response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#; assert_eq!(io.handle_request_sync(request), Some(response.to_owned())); diff --git a/rpc/src/v1/traits/parity_set.rs b/rpc/src/v1/traits/parity_set.rs index e196a7d21..c40abd01f 100644 --- a/rpc/src/v1/traits/parity_set.rs +++ b/rpc/src/v1/traits/parity_set.rs @@ -45,8 +45,8 @@ build_rpc_trait! { fn set_author(&self, H160) -> Result; /// Sets account for signing consensus messages. - #[rpc(name = "parity_setConsensusSigner")] - fn set_consensus_signer(&self, H160, String) -> Result; + #[rpc(name = "parity_setEngineSigner")] + fn set_engine_signer(&self, H160, String) -> Result; /// Sets the limits for transaction queue. #[rpc(name = "parity_setTransactionsLimit")] diff --git a/util/fdlimit/Cargo.toml b/util/fdlimit/Cargo.toml deleted file mode 100644 index 42aa582fe..000000000 --- a/util/fdlimit/Cargo.toml +++ /dev/null @@ -1,10 +0,0 @@ -[package] -description = "Utility function to raise file descriptor limit on OS X" -homepage = "http://ethcore.io" -license = "GPL-3.0" -name = "fdlimit" -version = "0.1.0" -authors = ["Ethcore "] - -[dependencies] -libc = "0.2" diff --git a/util/fdlimit/src/lib.rs b/util/fdlimit/src/lib.rs deleted file mode 100644 index 92c403058..000000000 --- a/util/fdlimit/src/lib.rs +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2015, 2016 Ethcore (UK) Ltd. -// This file is part of Parity. -// -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see .extern crate libc; - -extern crate libc; -mod raise_fd_limit; -pub use raise_fd_limit::raise_fd_limit; diff --git a/util/fdlimit/src/raise_fd_limit.rs b/util/fdlimit/src/raise_fd_limit.rs deleted file mode 100644 index d0539fda9..000000000 --- a/util/fdlimit/src/raise_fd_limit.rs +++ /dev/null @@ -1,88 +0,0 @@ -// Copyright 2015 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 or the MIT license -// , at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/// darwin_fd_limit exists to work around an issue where launchctl on Mac OS X -/// defaults the rlimit maxfiles to 256/unlimited. The default soft limit of 256 -/// ends up being far too low for our multithreaded scheduler testing, depending -/// on the number of cores available. -/// -#[cfg(any(target_os = "macos", target_os = "ios"))] -#[allow(non_camel_case_types)] -pub fn raise_fd_limit() { - use libc; - use std::cmp; - use std::io; - use std::mem::size_of_val; - use std::ptr::null_mut; - - unsafe { - static CTL_KERN: libc::c_int = 1; - static KERN_MAXFILESPERPROC: libc::c_int = 29; - - // The strategy here is to fetch the current resource limits, read the - // kern.maxfilesperproc sysctl value, and bump the soft resource limit for - // maxfiles up to the sysctl value. - - // Fetch the kern.maxfilesperproc value - let mut mib: [libc::c_int; 2] = [CTL_KERN, KERN_MAXFILESPERPROC]; - let mut maxfiles: libc::c_int = 0; - let mut size: libc::size_t = size_of_val(&maxfiles) as libc::size_t; - if libc::sysctl(&mut mib[0], 2, &mut maxfiles as *mut _ as *mut _, &mut size, - null_mut(), 0) != 0 { - let err = io::Error::last_os_error(); - panic!("raise_fd_limit: error calling sysctl: {}", err); - } - - // Fetch the current resource limits - let mut rlim = libc::rlimit{rlim_cur: 0, rlim_max: 0}; - if libc::getrlimit(libc::RLIMIT_NOFILE, &mut rlim) != 0 { - let err = io::Error::last_os_error(); - panic!("raise_fd_limit: error calling getrlimit: {}", err); - } - - // Bump the soft limit to the smaller of kern.maxfilesperproc and the hard - // limit - rlim.rlim_cur = cmp::min(maxfiles as libc::rlim_t, rlim.rlim_max); - - // Set our newly-increased resource limit - if libc::setrlimit(libc::RLIMIT_NOFILE, &rlim) != 0 { - let err = io::Error::last_os_error(); - panic!("raise_fd_limit: error calling setrlimit: {}", err); - } - } -} - -#[cfg(any(target_os = "linux"))] -#[allow(non_camel_case_types)] -pub fn raise_fd_limit() { - use libc; - use std::io; - - unsafe { - // Fetch the current resource limits - let mut rlim = libc::rlimit{rlim_cur: 0, rlim_max: 0}; - if libc::getrlimit(libc::RLIMIT_NOFILE, &mut rlim) != 0 { - let err = io::Error::last_os_error(); - panic!("raise_fd_limit: error calling getrlimit: {}", err); - } - - // Set soft limit to hard imit - rlim.rlim_cur = rlim.rlim_max; - - // Set our newly-increased resource limit - if libc::setrlimit(libc::RLIMIT_NOFILE, &rlim) != 0 { - let err = io::Error::last_os_error(); - panic!("raise_fd_limit: error calling setrlimit: {}", err); - } - } -} - -#[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "linux")))] -pub fn raise_fd_limit() {}