From 529a7fc33c61a88298a63fc205585538b219f4f5 Mon Sep 17 00:00:00 2001 From: keorn Date: Mon, 5 Dec 2016 17:08:16 +0000 Subject: [PATCH 01/10] add password and AccountProvider --- ethcore/src/engines/authority_round.rs | 46 +++++++++++------------ ethcore/src/engines/basic_authority.rs | 13 +++++-- ethcore/src/engines/instant_seal.rs | 12 ++---- ethcore/src/engines/mod.rs | 14 +++++-- ethcore/src/miner/miner.rs | 43 ++++++++++++++------- ethcore/src/miner/mod.rs | 3 ++ parity/run.rs | 5 ++- rpc/src/v1/impls/parity_set.rs | 6 +++ rpc/src/v1/tests/eth.rs | 1 + rpc/src/v1/tests/helpers/miner_service.rs | 10 +++++ rpc/src/v1/tests/helpers/sync_provider.rs | 2 +- rpc/src/v1/tests/mocked/parity_set.rs | 17 +++++++++ rpc/src/v1/traits/parity_set.rs | 4 ++ 13 files changed, 119 insertions(+), 57 deletions(-) diff --git a/ethcore/src/engines/authority_round.rs b/ethcore/src/engines/authority_round.rs index f28a06117..646c107e0 100644 --- a/ethcore/src/engines/authority_round.rs +++ b/ethcore/src/engines/authority_round.rs @@ -21,13 +21,15 @@ use std::sync::Weak; use std::time::{UNIX_EPOCH, Duration}; use util::*; use ethkey::{verify_address, Signature}; -use rlp::{Rlp, UntrustedRlp, View, encode}; +use rlp::{UntrustedRlp, View, encode}; use account_provider::AccountProvider; use block::*; use spec::CommonParams; use engines::Engine; use header::Header; use error::{Error, BlockError}; +use blockchain::extras::BlockDetails; +use views::HeaderView; use evm::Schedule; use ethjson; use io::{IoContext, IoHandler, TimerToken, IoService, IoChannel}; @@ -35,8 +37,6 @@ use service::ClientIoMessage; use transaction::SignedTransaction; use env_info::EnvInfo; use builtin::Builtin; -use blockchain::extras::BlockDetails; -use views::HeaderView; /// `AuthorityRound` params. #[derive(Debug, PartialEq)] @@ -72,6 +72,7 @@ pub struct AuthorityRound { message_channel: Mutex>>, step: AtomicUsize, proposed: AtomicBool, + account_provider: Mutex>>, } fn header_step(header: &Header) -> Result { @@ -104,7 +105,8 @@ impl AuthorityRound { transition_service: try!(IoService::::start()), message_channel: Mutex::new(None), step: AtomicUsize::new(initial_step), - proposed: AtomicBool::new(false) + proposed: AtomicBool::new(false), + account_provider: Mutex::new(None), }); let handler = TransitionHandler { engine: Arc::downgrade(&engine) }; try!(engine.transition_service.register_handler(Arc::new(handler))); @@ -196,7 +198,6 @@ impl Engine for AuthorityRound { } fn populate_from_parent(&self, header: &mut Header, parent: &Header, gas_floor_target: U256, _gas_ceil_target: U256) { - header.set_difficulty(parent.difficulty().clone()); header.set_gas_limit({ let gas_limit = parent.gas_limit().clone(); let bound_divisor = self.our_params.gas_limit_bound_divisor; @@ -221,12 +222,12 @@ impl Engine for AuthorityRound { /// /// This operation is synchronous and may (quite reasonably) not be available, in which `false` will /// be returned. - fn generate_seal(&self, block: &ExecutedBlock, accounts: Option<&AccountProvider>) -> Option> { + fn generate_seal(&self, block: &ExecutedBlock) -> Option> { if self.proposed.load(AtomicOrdering::SeqCst) { return None; } let header = block.header(); let step = self.step(); if self.is_step_proposer(step, header.author()) { - if let Some(ap) = accounts { + if let Some(ref ap) = *self.account_provider.lock() { // Account should be permanently unlocked, otherwise sealing will fail. if let Ok(signature) = ap.sign(*header.author(), None, header.bare_hash()) { trace!(target: "poa", "generate_seal: Issuing a block for step {}.", step); @@ -303,22 +304,16 @@ impl Engine for AuthorityRound { t.sender().map(|_|()) // Perform EC recovery and cache sender } - fn register_message_channel(&self, message_channel: IoChannel) { - let mut guard = self.message_channel.lock(); - *guard = Some(message_channel); + fn is_new_best_block(&self, _best_total_difficulty: U256, best_header: HeaderView, _parent_details: &BlockDetails, new_header: &HeaderView) -> bool { + new_header.number() > best_header.number() } - fn is_new_best_block(&self, _best_total_difficulty: U256, best_header: HeaderView, _parent_details: &BlockDetails, new_header: &HeaderView) -> bool { - let new_number = new_header.number(); - let best_number = best_header.number(); - if new_number != best_number { - new_number > best_number - } else { - // Take the oldest step at given height. - let new_step: usize = Rlp::new(&new_header.seal()[0]).as_val(); - let best_step: usize = Rlp::new(&best_header.seal()[0]).as_val(); - new_step < best_step - } + fn register_message_channel(&self, message_channel: IoChannel) { + *self.message_channel.lock() = Some(message_channel); + } + + fn register_account_provider(&self, account_provider: Arc) { + *self.account_provider.lock() = Some(account_provider); } } @@ -393,6 +388,7 @@ mod tests { let spec = Spec::new_test_round(); let engine = &*spec.engine; + engine.register_account_provider(Arc::new(tap)); let genesis_header = spec.genesis_header(); let mut db1 = get_temp_state_db().take(); spec.ensure_db_good(&mut db1, &TrieFactory::new(TrieSpec::Secure)).unwrap(); @@ -404,16 +400,16 @@ mod tests { let b2 = OpenBlock::new(engine, Default::default(), false, db2, &genesis_header, last_hashes, addr2, (3141562.into(), 31415620.into()), vec![]).unwrap(); let b2 = b2.close_and_lock(); - if let Some(seal) = engine.generate_seal(b1.block(), Some(&tap)) { + if let Some(seal) = engine.generate_seal(b1.block()) { assert!(b1.clone().try_seal(engine, seal).is_ok()); // Second proposal is forbidden. - assert!(engine.generate_seal(b1.block(), Some(&tap)).is_none()); + assert!(engine.generate_seal(b1.block()).is_none()); } - if let Some(seal) = engine.generate_seal(b2.block(), Some(&tap)) { + if let Some(seal) = engine.generate_seal(b2.block()) { assert!(b2.clone().try_seal(engine, seal).is_ok()); // Second proposal is forbidden. - assert!(engine.generate_seal(b2.block(), Some(&tap)).is_none()); + assert!(engine.generate_seal(b2.block()).is_none()); } } diff --git a/ethcore/src/engines/basic_authority.rs b/ethcore/src/engines/basic_authority.rs index fb2f9bde6..0b9040a11 100644 --- a/ethcore/src/engines/basic_authority.rs +++ b/ethcore/src/engines/basic_authority.rs @@ -58,6 +58,7 @@ pub struct BasicAuthority { params: CommonParams, our_params: BasicAuthorityParams, builtins: BTreeMap, + account_provider: Mutex>>, } impl BasicAuthority { @@ -67,6 +68,7 @@ impl BasicAuthority { params: params, our_params: our_params, builtins: builtins, + account_provider: Mutex::new(None) } } } @@ -113,8 +115,8 @@ impl Engine for BasicAuthority { /// /// This operation is synchronous and may (quite reasonably) not be available, in which `false` will /// be returned. - fn generate_seal(&self, block: &ExecutedBlock, accounts: Option<&AccountProvider>) -> Option> { - if let Some(ap) = accounts { + fn generate_seal(&self, block: &ExecutedBlock) -> Option> { + if let Some(ref ap) = *self.account_provider.lock() { let header = block.header(); let message = header.bare_hash(); // account should be pernamently unlocked, otherwise sealing will fail @@ -179,6 +181,10 @@ impl Engine for BasicAuthority { fn verify_transaction(&self, t: &SignedTransaction, _header: &Header) -> Result<(), Error> { t.sender().map(|_|()) // Perform EC recovery and cache sender } + + fn register_account_provider(&self, ap: Arc) { + *self.account_provider.lock() = Some(ap); + } } #[cfg(test)] @@ -254,6 +260,7 @@ mod tests { let spec = new_test_authority(); let engine = &*spec.engine; + engine.register_account_provider(Arc::new(tap)); let genesis_header = spec.genesis_header(); let mut db_result = get_temp_state_db(); let mut db = db_result.take(); @@ -261,7 +268,7 @@ mod tests { let last_hashes = Arc::new(vec![genesis_header.hash()]); let b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes, addr, (3141562.into(), 31415620.into()), vec![]).unwrap(); let b = b.close_and_lock(); - let seal = engine.generate_seal(b.block(), Some(&tap)).unwrap(); + let seal = engine.generate_seal(b.block()).unwrap(); assert!(b.try_seal(engine, seal).is_ok()); } diff --git a/ethcore/src/engines/instant_seal.rs b/ethcore/src/engines/instant_seal.rs index f50f7344b..83335fb03 100644 --- a/ethcore/src/engines/instant_seal.rs +++ b/ethcore/src/engines/instant_seal.rs @@ -23,7 +23,6 @@ use spec::CommonParams; use evm::Schedule; use block::ExecutedBlock; use util::Bytes; -use account_provider::AccountProvider; /// An engine which does not provide any consensus mechanism, just seals blocks internally. pub struct InstantSeal { @@ -60,7 +59,7 @@ impl Engine for InstantSeal { fn is_sealer(&self, _author: &Address) -> Option { Some(true) } - fn generate_seal(&self, _block: &ExecutedBlock, _accounts: Option<&AccountProvider>) -> Option> { + fn generate_seal(&self, _block: &ExecutedBlock) -> Option> { Some(Vec::new()) } } @@ -70,16 +69,12 @@ mod tests { use util::*; use util::trie::TrieSpec; use tests::helpers::*; - use account_provider::AccountProvider; use spec::Spec; use header::Header; use block::*; #[test] fn instant_can_seal() { - let tap = AccountProvider::transient_provider(); - let addr = tap.insert_account("".sha3(), "").unwrap(); - let spec = Spec::new_instant(); let engine = &*spec.engine; let genesis_header = spec.genesis_header(); @@ -87,10 +82,9 @@ mod tests { let mut db = db_result.take(); spec.ensure_db_good(&mut db, &TrieFactory::new(TrieSpec::Secure)).unwrap(); let last_hashes = Arc::new(vec![genesis_header.hash()]); - let b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes, addr, (3141562.into(), 31415620.into()), vec![]).unwrap(); + let b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes, Address::default(), (3141562.into(), 31415620.into()), vec![]).unwrap(); let b = b.close_and_lock(); - // Seal with empty AccountProvider. - let seal = engine.generate_seal(b.block(), Some(&tap)).unwrap(); + let seal = engine.generate_seal(b.block()).unwrap(); assert!(b.try_seal(engine, seal).is_ok()); } diff --git a/ethcore/src/engines/mod.rs b/ethcore/src/engines/mod.rs index 163901edc..0401ba667 100644 --- a/ethcore/src/engines/mod.rs +++ b/ethcore/src/engines/mod.rs @@ -94,7 +94,7 @@ pub trait Engine : Sync + Send { /// /// This operation is synchronous and may (quite reasonably) not be available, in which None will /// be returned. - fn generate_seal(&self, _block: &ExecutedBlock, _accounts: Option<&AccountProvider>) -> Option> { None } + fn generate_seal(&self, _block: &ExecutedBlock) -> Option> { None } /// Phase 1 quick block verification. Only does checks that are cheap. `block` (the header's full block) /// may be provided for additional checks. Returns either a null `Ok` or a general error detailing the problem with import. @@ -147,11 +147,17 @@ pub trait Engine : Sync + Send { self.builtins().get(a).expect("attempted to execute nonexistent builtin").execute(input, output); } - /// Add a channel for communication with Client which can be used for sealing. - fn register_message_channel(&self, _message_channel: IoChannel) {} - /// 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) {} } diff --git a/ethcore/src/miner/miner.rs b/ethcore/src/miner/miner.rs index a543e608d..4b38a7e07 100644 --- a/ethcore/src/miner/miner.rs +++ b/ethcore/src/miner/miner.rs @@ -19,7 +19,7 @@ use std::time::{Instant, Duration}; use util::*; use util::using_queue::{UsingQueue, GetAction}; -use account_provider::AccountProvider; +use account_provider::{AccountProvider, Error as AccountError}; use views::{BlockView, HeaderView}; use header::Header; use state::{State, CleanupMode}; @@ -464,15 +464,12 @@ impl Miner { /// Attempts to perform internal sealing (one that does not require work) to return Ok(sealed), /// Err(Some(block)) returns for unsuccesful sealing while Err(None) indicates misspecified engine. fn seal_block_internally(&self, block: ClosedBlock) -> Result> { - trace!(target: "miner", "seal_block_internally: block has transaction - attempting internal seal."); - let s = self.engine.generate_seal(block.block(), match self.accounts { - Some(ref x) => Some(&**x), - None => None, - }); + trace!(target: "miner", "seal_block_internally: attempting internal seal."); + let s = self.engine.generate_seal(block.block()); if let Some(seal) = s { trace!(target: "miner", "seal_block_internally: managed internal seal. importing..."); - block.lock().try_seal(&*self.engine, seal).or_else(|_| { - warn!("prepare_sealing: ERROR: try_seal failed when given internally generated seal. WTF?"); + block.lock().try_seal(&*self.engine, seal).or_else(|(e, _)| { + warn!("prepare_sealing: ERROR: try_seal failed when given internally generated seal: {}", e); Err(None) }) } else { @@ -485,7 +482,7 @@ impl Miner { fn seal_and_import_block_internally(&self, chain: &MiningBlockChainClient, block: ClosedBlock) -> bool { if !block.transactions().is_empty() || self.forced_sealing() { if let Ok(sealed) = self.seal_block_internally(block) { - if chain.import_block(sealed.rlp_bytes()).is_ok() { + if chain.import_sealed_block(sealed).is_ok() { trace!(target: "miner", "import_block_internally: imported internally sealed block"); return true } @@ -740,6 +737,19 @@ impl MinerService for Miner { *self.author.write() = author; } + fn set_consensus_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())); + } + let mut sealing_work = self.sealing_work.lock(); + sealing_work.enabled = self.engine.is_sealer(&address).unwrap_or(false); + *self.author.write() = address; + self.engine.set_signer(address, password); + } + Ok(()) + } + fn set_extra_data(&self, extra_data: Bytes) { *self.extra_data.write() = extra_data; } @@ -1020,6 +1030,11 @@ impl MinerService for Miner { let (block, original_work_hash) = self.prepare_block(chain); if self.seals_internally { trace!(target: "miner", "update_sealing: engine indicates internal sealing"); + { + let mut sealing_work = self.sealing_work.lock(); + sealing_work.queue.push(block.clone()); + sealing_work.queue.use_last_ref(); + } self.seal_and_import_block_internally(chain, block); } else { trace!(target: "miner", "update_sealing: engine does not seal internally, preparing work"); @@ -1042,7 +1057,7 @@ impl MinerService for Miner { ret.map(f) } - fn submit_seal(&self, chain: &MiningBlockChainClient, pow_hash: H256, seal: Vec) -> Result<(), Error> { + fn submit_seal(&self, chain: &MiningBlockChainClient, block_hash: H256, seal: Vec) -> Result<(), Error> { let result = if let Some(b) = self.sealing_work.lock().queue.get_used_if( if self.options.enable_resubmission { @@ -1050,22 +1065,22 @@ impl MinerService for Miner { } else { GetAction::Take }, - |b| &b.hash() == &pow_hash + |b| &b.hash() == &block_hash ) { - trace!(target: "miner", "Sealing block {}={}={} with seal {:?}", pow_hash, b.hash(), b.header().bare_hash(), seal); + trace!(target: "miner", "Submitted block {}={}={} with seal {:?}", block_hash, b.hash(), b.header().bare_hash(), seal); b.lock().try_seal(&*self.engine, seal).or_else(|(e, _)| { warn!(target: "miner", "Mined solution rejected: {}", e); Err(Error::PowInvalid) }) } else { - warn!(target: "miner", "Mined solution rejected: Block unknown or out of date."); + warn!(target: "miner", "Submitted solution rejected: Block unknown or out of date."); Err(Error::PowHashInvalid) }; result.and_then(|sealed| { let n = sealed.header().number(); let h = sealed.header().hash(); try!(chain.import_sealed_block(sealed)); - info!(target: "miner", "Mined block imported OK. #{}: {}", Colour::White.bold().paint(format!("{}", n)), Colour::White.bold().paint(h.hex())); + info!(target: "miner", "Submitted block imported OK. #{}: {}", Colour::White.bold().paint(format!("{}", n)), Colour::White.bold().paint(h.hex())); Ok(()) }) } diff --git a/ethcore/src/miner/mod.rs b/ethcore/src/miner/mod.rs index 1fb2244fd..26cefb295 100644 --- a/ethcore/src/miner/mod.rs +++ b/ethcore/src/miner/mod.rs @@ -76,6 +76,9 @@ pub trait MinerService : Send + Sync { /// Set the author that we will seal blocks as. 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>; + /// Get the extra_data that we will seal blocks with. fn extra_data(&self) -> Bytes; diff --git a/parity/run.rs b/parity/run.rs index f977c450c..2509d1347 100644 --- a/parity/run.rs +++ b/parity/run.rs @@ -70,7 +70,7 @@ pub struct RunCmd { pub http_conf: HttpConfiguration, pub ipc_conf: IpcConfiguration, pub net_conf: NetworkConfiguration, - pub network_id: Option, + pub network_id: Option, pub warp_sync: bool, pub acc_conf: AccountsConfig, pub gas_pricer: GasPricerConfig, @@ -208,6 +208,9 @@ pub fn execute(cmd: RunCmd, logger: Arc) -> Result<(), String> { // prepare account provider let account_provider = Arc::new(try!(prepare_account_provider(&cmd.dirs, cmd.acc_conf))); + // let the Engine access the accounts + spec.engine.register_account_provider(account_provider.clone()); + // create miner let miner = Miner::new(cmd.miner_options, cmd.gas_pricer.into(), &spec, Some(account_provider.clone())); miner.set_author(cmd.miner_extras.author); diff --git a/rpc/src/v1/impls/parity_set.rs b/rpc/src/v1/impls/parity_set.rs index 47634d518..e28f9a573 100644 --- a/rpc/src/v1/impls/parity_set.rs +++ b/rpc/src/v1/impls/parity_set.rs @@ -116,6 +116,12 @@ impl ParitySet for ParitySetClient where Ok(true) } + fn set_consensus_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)); + Ok(true) + } + fn set_transactions_limit(&self, limit: usize) -> Result { try!(self.active()); diff --git a/rpc/src/v1/tests/eth.rs b/rpc/src/v1/tests/eth.rs index 7894fa111..3aa83fec9 100644 --- a/rpc/src/v1/tests/eth.rs +++ b/rpc/src/v1/tests/eth.rs @@ -116,6 +116,7 @@ impl EthTester { fn from_spec(spec: Spec) -> Self { let dir = RandomTempPath::new(); let account_provider = account_provider(); + spec.engine.register_account_provider(account_provider.clone()); let miner_service = miner_service(&spec, account_provider.clone()); let snapshot_service = snapshot_service(); diff --git a/rpc/src/v1/tests/helpers/miner_service.rs b/rpc/src/v1/tests/helpers/miner_service.rs index ad55faa7b..6037cdd4a 100644 --- a/rpc/src/v1/tests/helpers/miner_service.rs +++ b/rpc/src/v1/tests/helpers/miner_service.rs @@ -25,6 +25,7 @@ use ethcore::header::BlockNumber; use ethcore::transaction::SignedTransaction; use ethcore::receipt::{Receipt, RichReceipt}; use ethcore::miner::{MinerService, MinerStatus, TransactionImportResult, LocalTransactionStatus}; +use ethcore::account_provider::Error as AccountError; /// Test miner service. pub struct TestMinerService { @@ -40,6 +41,8 @@ pub struct TestMinerService { pub pending_receipts: Mutex>, /// Last nonces. pub last_nonces: RwLock>, + /// Password held by Engine. + pub password: RwLock, min_gas_price: RwLock, gas_range_target: RwLock<(U256, U256)>, @@ -61,6 +64,7 @@ impl Default for TestMinerService { min_gas_price: RwLock::new(U256::from(20_000_000)), gas_range_target: RwLock::new((U256::from(12345), U256::from(54321))), author: RwLock::new(Address::zero()), + password: RwLock::new(String::new()), extra_data: RwLock::new(vec![1, 2, 3, 4]), limit: RwLock::new(1024), tx_gas_limit: RwLock::new(!U256::zero()), @@ -83,6 +87,12 @@ impl MinerService for TestMinerService { *self.author.write() = author; } + fn set_consensus_signer(&self, address: Address, password: String) -> Result<(), AccountError> { + *self.author.write() = address; + *self.password.write() = password; + Ok(()) + } + fn set_extra_data(&self, extra_data: Bytes) { *self.extra_data.write() = extra_data; } diff --git a/rpc/src/v1/tests/helpers/sync_provider.rs b/rpc/src/v1/tests/helpers/sync_provider.rs index 24be33417..8800d926a 100644 --- a/rpc/src/v1/tests/helpers/sync_provider.rs +++ b/rpc/src/v1/tests/helpers/sync_provider.rs @@ -23,7 +23,7 @@ use ethsync::{SyncProvider, SyncStatus, SyncState, PeerInfo, TransactionStats}; /// TestSyncProvider config. pub struct Config { /// Protocol version. - pub network_id: usize, + pub network_id: u64, /// Number of peers. pub num_peers: usize, } diff --git a/rpc/src/v1/tests/mocked/parity_set.rs b/rpc/src/v1/tests/mocked/parity_set.rs index 01f33e251..fdf3f2d0f 100644 --- a/rpc/src/v1/tests/mocked/parity_set.rs +++ b/rpc/src/v1/tests/mocked/parity_set.rs @@ -106,6 +106,23 @@ fn rpc_parity_set_author() { assert_eq!(miner.author(), Address::from_str("cd1722f3947def4cf144679da39c4c32bdc35681").unwrap()); } +#[test] +fn rpc_parity_set_consensus_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 response = r#"{"jsonrpc":"2.0","result":true,"id":1}"#; + + assert_eq!(io.handle_request_sync(request), Some(response.to_owned())); + assert_eq!(miner.author(), Address::from_str("cd1722f3947def4cf144679da39c4c32bdc35681").unwrap()); + assert_eq!(*miner.password.read(), "password".to_string()); +} + + #[test] fn rpc_parity_set_transactions_limit() { let miner = miner_service(); diff --git a/rpc/src/v1/traits/parity_set.rs b/rpc/src/v1/traits/parity_set.rs index c83eff022..e196a7d21 100644 --- a/rpc/src/v1/traits/parity_set.rs +++ b/rpc/src/v1/traits/parity_set.rs @@ -44,6 +44,10 @@ build_rpc_trait! { #[rpc(name = "parity_setAuthor")] fn set_author(&self, H160) -> Result; + /// Sets account for signing consensus messages. + #[rpc(name = "parity_setConsensusSigner")] + fn set_consensus_signer(&self, H160, String) -> Result; + /// Sets the limits for transaction queue. #[rpc(name = "parity_setTransactionsLimit")] fn set_transactions_limit(&self, usize) -> Result; From 01bf483b63152b3e5fb1a5cf4ea8285a033cfc6b Mon Sep 17 00:00:00 2001 From: keorn Date: Mon, 5 Dec 2016 17:29:47 +0000 Subject: [PATCH 02/10] remove unnecessary impls --- ethcore/src/engines/authority_round.rs | 4 ---- ethcore/src/engines/basic_authority.rs | 5 ----- ethcore/src/miner/miner.rs | 5 ----- 3 files changed, 14 deletions(-) diff --git a/ethcore/src/engines/authority_round.rs b/ethcore/src/engines/authority_round.rs index 646c107e0..02993fe83 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/miner/miner.rs b/ethcore/src/miner/miner.rs index 4b38a7e07..3b4223c68 100644 --- a/ethcore/src/miner/miner.rs +++ b/ethcore/src/miner/miner.rs @@ -1030,11 +1030,6 @@ impl MinerService for Miner { let (block, original_work_hash) = self.prepare_block(chain); if self.seals_internally { trace!(target: "miner", "update_sealing: engine indicates internal sealing"); - { - let mut sealing_work = self.sealing_work.lock(); - sealing_work.queue.push(block.clone()); - sealing_work.queue.use_last_ref(); - } self.seal_and_import_block_internally(chain, block); } else { trace!(target: "miner", "update_sealing: engine does not seal internally, preparing work"); From 5e7c21ad4aa613038d30715fc5b55f02e50a904b Mon Sep 17 00:00:00 2001 From: keorn Date: Mon, 5 Dec 2016 19:23:03 +0000 Subject: [PATCH 03/10] add a cli flag --- parity/cli/config.full.toml | 1 + parity/cli/config.toml | 1 + parity/cli/mod.rs | 5 +++++ parity/cli/usage.txt | 4 ++++ parity/configuration.rs | 5 +++++ parity/helpers.rs | 4 ++-- parity/params.rs | 2 ++ parity/run.rs | 14 +++++++++----- 8 files changed, 29 insertions(+), 7 deletions(-) diff --git a/parity/cli/config.full.toml b/parity/cli/config.full.toml index fcd9a9712..e2e4aeb5a 100644 --- a/parity/cli/config.full.toml +++ b/parity/cli/config.full.toml @@ -61,6 +61,7 @@ pass = "test_pass" [mining] author = "0xdeadbeefcafe0000000000000000000000000001" +consensus_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..b84c10b22 100644 --- a/parity/cli/config.toml +++ b/parity/cli/config.toml @@ -40,6 +40,7 @@ pass = "password" [mining] author = "0xdeadbeefcafe0000000000000000000000000001" +consensus_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 7fcdd2209..8939b22e1 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).consensus_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, + consensus_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()), + consensus_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..0ba084673 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, + consensus_signer: try!(self.consensus_signer()), }; Ok(extras) @@ -309,6 +310,10 @@ impl Configuration { to_address(self.args.flag_etherbase.clone().or(self.args.flag_author.clone())) } + fn consensus_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 3ce07e889..97a5e7b08 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 consensus_signer: Address, } impl Default for MinerExtras { @@ -214,6 +215,7 @@ impl Default for MinerExtras { gas_floor_target: U256::from(4_700_000), gas_ceil_target: U256::from(6_283_184), transactions_limit: 1024, + consensus_signer: Default::default(), } } } diff --git a/parity/run.rs b/parity/run.rs index 2509d1347..332f296c1 100644 --- a/parity/run.rs +++ b/parity/run.rs @@ -205,8 +205,10 @@ 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()); @@ -218,6 +220,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 consensus_signer = cmd.miner_extras.consensus_signer; + if passwords.into_iter().any(|p| miner.set_consensus_signer(consensus_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.consensus_signer)); + } // create client config let client_config = to_client_config( @@ -424,19 +430,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)); } } From 46dd2543e5b104a58bd4dd2aae32c1c4158aae62 Mon Sep 17 00:00:00 2001 From: keorn Date: Mon, 5 Dec 2016 19:27:24 +0000 Subject: [PATCH 04/10] rename rpc to match cli --- rpc/src/v1/tests/mocked/parity_set.rs | 2 +- rpc/src/v1/traits/parity_set.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/rpc/src/v1/tests/mocked/parity_set.rs b/rpc/src/v1/tests/mocked/parity_set.rs index fdf3f2d0f..5c249f08b 100644 --- a/rpc/src/v1/tests/mocked/parity_set.rs +++ b/rpc/src/v1/tests/mocked/parity_set.rs @@ -114,7 +114,7 @@ fn rpc_parity_set_consensus_signer() { 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..c41a88033 100644 --- a/rpc/src/v1/traits/parity_set.rs +++ b/rpc/src/v1/traits/parity_set.rs @@ -45,7 +45,7 @@ build_rpc_trait! { fn set_author(&self, H160) -> Result; /// Sets account for signing consensus messages. - #[rpc(name = "parity_setConsensusSigner")] + #[rpc(name = "parity_setEngineSigner")] fn set_consensus_signer(&self, H160, String) -> Result; /// Sets the limits for transaction queue. From 0a2ec319ac5be557493de6df53f381c09fde6108 Mon Sep 17 00:00:00 2001 From: keorn Date: Mon, 5 Dec 2016 21:31:38 +0000 Subject: [PATCH 05/10] rename to engine_signer --- ethcore/src/miner/miner.rs | 2 +- ethcore/src/miner/mod.rs | 2 +- parity/cli/config.full.toml | 2 +- parity/cli/config.toml | 2 +- parity/cli/mod.rs | 6 +++--- parity/configuration.rs | 4 ++-- parity/params.rs | 4 ++-- parity/run.rs | 6 +++--- rpc/src/v1/impls/parity_set.rs | 4 ++-- rpc/src/v1/tests/helpers/miner_service.rs | 2 +- rpc/src/v1/tests/mocked/parity_set.rs | 2 +- rpc/src/v1/traits/parity_set.rs | 2 +- 12 files changed, 19 insertions(+), 19 deletions(-) diff --git a/ethcore/src/miner/miner.rs b/ethcore/src/miner/miner.rs index 3b4223c68..8d1f55567 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/parity/cli/config.full.toml b/parity/cli/config.full.toml index e2e4aeb5a..4f3e4fa07 100644 --- a/parity/cli/config.full.toml +++ b/parity/cli/config.full.toml @@ -61,7 +61,7 @@ pass = "test_pass" [mining] author = "0xdeadbeefcafe0000000000000000000000000001" -consensus_signer = "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 b84c10b22..34bab5b46 100644 --- a/parity/cli/config.toml +++ b/parity/cli/config.toml @@ -40,7 +40,7 @@ pass = "password" [mining] author = "0xdeadbeefcafe0000000000000000000000000001" -consensus_signer = "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 8939b22e1..1f6a266b3 100644 --- a/parity/cli/mod.rs +++ b/parity/cli/mod.rs @@ -179,7 +179,7 @@ usage! { 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).consensus_signer.clone().map(Some), + 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", @@ -369,7 +369,7 @@ struct Dapps { #[derive(Default, Debug, PartialEq, RustcDecodable)] struct Mining { author: Option, - consensus_signer: Option, + engine_signer: Option, force_sealing: Option, reseal_on_txs: Option, reseal_min_period: Option, @@ -742,7 +742,7 @@ mod tests { }), mining: Some(Mining { author: Some("0xdeadbeefcafe0000000000000000000000000001".into()), - consensus_signer: 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/configuration.rs b/parity/configuration.rs index 0ba084673..bcca3aa58 100644 --- a/parity/configuration.rs +++ b/parity/configuration.rs @@ -300,7 +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, - consensus_signer: try!(self.consensus_signer()), + engine_signer: try!(self.engine_signer()), }; Ok(extras) @@ -310,7 +310,7 @@ impl Configuration { to_address(self.args.flag_etherbase.clone().or(self.args.flag_author.clone())) } - fn consensus_signer(&self) -> Result { + fn engine_signer(&self) -> Result { to_address(self.args.flag_engine_signer.clone()) } diff --git a/parity/params.rs b/parity/params.rs index 97a5e7b08..25ddc8814 100644 --- a/parity/params.rs +++ b/parity/params.rs @@ -204,7 +204,7 @@ pub struct MinerExtras { pub gas_floor_target: U256, pub gas_ceil_target: U256, pub transactions_limit: usize, - pub consensus_signer: Address, + pub engine_signer: Address, } impl Default for MinerExtras { @@ -215,7 +215,7 @@ impl Default for MinerExtras { gas_floor_target: U256::from(4_700_000), gas_ceil_target: U256::from(6_283_184), transactions_limit: 1024, - consensus_signer: Default::default(), + engine_signer: Default::default(), } } } diff --git a/parity/run.rs b/parity/run.rs index 332f296c1..774dd6271 100644 --- a/parity/run.rs +++ b/parity/run.rs @@ -220,9 +220,9 @@ 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 consensus_signer = cmd.miner_extras.consensus_signer; - if passwords.into_iter().any(|p| miner.set_consensus_signer(consensus_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.consensus_signer)); + 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 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 5c249f08b..55f155693 100644 --- a/rpc/src/v1/tests/mocked/parity_set.rs +++ b/rpc/src/v1/tests/mocked/parity_set.rs @@ -107,7 +107,7 @@ 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(); diff --git a/rpc/src/v1/traits/parity_set.rs b/rpc/src/v1/traits/parity_set.rs index c41a88033..c40abd01f 100644 --- a/rpc/src/v1/traits/parity_set.rs +++ b/rpc/src/v1/traits/parity_set.rs @@ -46,7 +46,7 @@ build_rpc_trait! { /// Sets account for signing consensus messages. #[rpc(name = "parity_setEngineSigner")] - fn set_consensus_signer(&self, H160, String) -> Result; + fn set_engine_signer(&self, H160, String) -> Result; /// Sets the limits for transaction queue. #[rpc(name = "parity_setTransactionsLimit")] From b089aa7a6b47d955a0d66503c98f239b6eb3dc62 Mon Sep 17 00:00:00 2001 From: keorn Date: Tue, 6 Dec 2016 08:38:41 +0000 Subject: [PATCH 06/10] fix password loading --- parity/run.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/parity/run.rs b/parity/run.rs index 774dd6271..cd2392ae6 100644 --- a/parity/run.rs +++ b/parity/run.rs @@ -221,7 +221,7 @@ pub fn execute(cmd: RunCmd, logger: Arc) -> Result<(), String> { 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()) { + 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)); } @@ -440,7 +440,7 @@ fn prepare_account_provider(dirs: &Directories, cfg: AccountsConfig, passwords: )); for a in cfg.unlocked_accounts { - if passwords.iter().any(|p| account_service.unlock_account_permanently(a, (*p).clone()).is_ok()) { + 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)); } } From 71a96588b0c48436af549efa3cf891a67e79512a Mon Sep 17 00:00:00 2001 From: keorn Date: Wed, 7 Dec 2016 10:34:06 +0100 Subject: [PATCH 07/10] add the methods to engines --- ethcore/src/engines/authority_round.rs | 13 ++++++++++--- ethcore/src/engines/basic_authority.rs | 10 ++++++++-- parity/run.rs | 6 ++++-- 3 files changed, 22 insertions(+), 7 deletions(-) diff --git a/ethcore/src/engines/authority_round.rs b/ethcore/src/engines/authority_round.rs index 02993fe83..a478df6bb 100644 --- a/ethcore/src/engines/authority_round.rs +++ b/ethcore/src/engines/authority_round.rs @@ -73,14 +73,15 @@ pub struct AuthorityRound { step: AtomicUsize, proposed: AtomicBool, account_provider: Mutex>>, + password: RwLock>, } fn header_step(header: &Header) -> Result { - UntrustedRlp::new(&header.seal()[0]).as_val() + UntrustedRlp::new(&header.seal().get(0).expect("was either checked with verify_block_basic or is genesis; has 2 fields; qed (Make sure the spec file has a correct genesis seal)")).as_val() } fn header_signature(header: &Header) -> Result { - UntrustedRlp::new(&header.seal()[1]).as_val::().map(Into::into) + UntrustedRlp::new(&header.seal().get(1).expect("was checked with verify_block_basic; has 2 fields; qed")).as_val::().map(Into::into) } trait AsMillis { @@ -107,6 +108,7 @@ impl AuthorityRound { step: AtomicUsize::new(initial_step), proposed: AtomicBool::new(false), account_provider: Mutex::new(None), + password: RwLock::new(None), }); let handler = TransitionHandler { engine: Arc::downgrade(&engine) }; try!(engine.transition_service.register_handler(Arc::new(handler))); @@ -198,6 +200,7 @@ impl Engine for AuthorityRound { } fn populate_from_parent(&self, header: &mut Header, parent: &Header, gas_floor_target: U256, _gas_ceil_target: U256) { + header.set_difficulty(parent.difficulty().clone()); header.set_gas_limit({ let gas_limit = parent.gas_limit().clone(); let bound_divisor = self.our_params.gas_limit_bound_divisor; @@ -225,7 +228,7 @@ impl Engine for AuthorityRound { if self.is_step_proposer(step, header.author()) { if let Some(ref ap) = *self.account_provider.lock() { // Account should be permanently unlocked, otherwise sealing will fail. - if let Ok(signature) = ap.sign(*header.author(), None, header.bare_hash()) { + if let Ok(signature) = ap.sign(*header.author(), self.password.read().clone(), header.bare_hash()) { trace!(target: "poa", "generate_seal: Issuing a block for step {}.", step); self.proposed.store(true, AtomicOrdering::SeqCst); return Some(vec![encode(&step).to_vec(), encode(&(&*signature as &[u8])).to_vec()]); @@ -308,6 +311,10 @@ impl Engine for AuthorityRound { *self.message_channel.lock() = Some(message_channel); } + fn set_signer(&self, _address: Address, password: String) { + *self.password.write() = Some(password); + } + fn register_account_provider(&self, account_provider: Arc) { *self.account_provider.lock() = Some(account_provider); } diff --git a/ethcore/src/engines/basic_authority.rs b/ethcore/src/engines/basic_authority.rs index 264a2d55a..4db8357e6 100644 --- a/ethcore/src/engines/basic_authority.rs +++ b/ethcore/src/engines/basic_authority.rs @@ -59,6 +59,7 @@ pub struct BasicAuthority { our_params: BasicAuthorityParams, builtins: BTreeMap, account_provider: Mutex>>, + password: RwLock>, } impl BasicAuthority { @@ -68,7 +69,8 @@ impl BasicAuthority { params: params, our_params: our_params, builtins: builtins, - account_provider: Mutex::new(None) + account_provider: Mutex::new(None), + password: RwLock::new(None), } } } @@ -115,7 +117,7 @@ impl Engine for BasicAuthority { let header = block.header(); let message = header.bare_hash(); // account should be pernamently unlocked, otherwise sealing will fail - if let Ok(signature) = ap.sign(*block.header().author(), None, message) { + if let Ok(signature) = ap.sign(*block.header().author(), self.password.read().clone(), message) { return Some(vec![::rlp::encode(&(&*signature as &[u8])).to_vec()]); } else { trace!(target: "basicauthority", "generate_seal: FAIL: accounts secret key unavailable"); @@ -177,6 +179,10 @@ impl Engine for BasicAuthority { t.sender().map(|_|()) // Perform EC recovery and cache sender } + fn set_signer(&self, _address: Address, password: String) { + *self.password.write() = Some(password); + } + fn register_account_provider(&self, ap: Arc) { *self.account_provider.lock() = Some(ap); } diff --git a/parity/run.rs b/parity/run.rs index cd2392ae6..d535b63ee 100644 --- a/parity/run.rs +++ b/parity/run.rs @@ -221,8 +221,10 @@ pub fn execute(cmd: RunCmd, logger: Arc) -> Result<(), String> { 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)); + if engine_signer != Default::default() { + 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`.", engine_signer)); + } } // create client config From 3ae09de0190ededd318fc50e35d2974f85400bc9 Mon Sep 17 00:00:00 2001 From: keorn Date: Wed, 7 Dec 2016 11:40:46 +0100 Subject: [PATCH 08/10] restore is_new_best --- ethcore/src/engines/authority_round.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/ethcore/src/engines/authority_round.rs b/ethcore/src/engines/authority_round.rs index a478df6bb..c78193e3f 100644 --- a/ethcore/src/engines/authority_round.rs +++ b/ethcore/src/engines/authority_round.rs @@ -304,7 +304,16 @@ impl Engine for AuthorityRound { } fn is_new_best_block(&self, _best_total_difficulty: U256, best_header: HeaderView, _parent_details: &BlockDetails, new_header: &HeaderView) -> bool { - new_header.number() > best_header.number() + let new_number = new_header.number(); + let best_number = best_header.number(); + if new_number != best_number { + new_number > best_number + } else { + // Take the oldest step at given height. + let new_step: usize = Rlp::new(&new_header.seal()[0]).as_val(); + let best_step: usize = Rlp::new(&best_header.seal()[0]).as_val(); + new_step < best_step + } } fn register_message_channel(&self, message_channel: IoChannel) { From 5faa4a85cb926e6036f33d4a1b43155e32026420 Mon Sep 17 00:00:00 2001 From: keorn Date: Wed, 7 Dec 2016 14:49:07 +0100 Subject: [PATCH 09/10] remove dummy type --- ethcore/src/engines/authority_round.rs | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/ethcore/src/engines/authority_round.rs b/ethcore/src/engines/authority_round.rs index c78193e3f..f966bd7f6 100644 --- a/ethcore/src/engines/authority_round.rs +++ b/ethcore/src/engines/authority_round.rs @@ -21,7 +21,7 @@ use std::sync::Weak; use std::time::{UNIX_EPOCH, Duration}; use util::*; use ethkey::{verify_address, Signature}; -use rlp::{UntrustedRlp, View, encode}; +use rlp::{UntrustedRlp, Rlp, View, encode}; use account_provider::AccountProvider; use block::*; use spec::CommonParams; @@ -68,7 +68,7 @@ pub struct AuthorityRound { params: CommonParams, our_params: AuthorityRoundParams, builtins: BTreeMap, - transition_service: IoService, + transition_service: IoService<()>, message_channel: Mutex>>, step: AtomicUsize, proposed: AtomicBool, @@ -103,7 +103,7 @@ impl AuthorityRound { params: params, our_params: our_params, builtins: builtins, - transition_service: try!(IoService::::start()), + transition_service: try!(IoService::<()>::start()), message_channel: Mutex::new(None), step: AtomicUsize::new(initial_step), proposed: AtomicBool::new(false), @@ -147,20 +147,17 @@ struct TransitionHandler { engine: Weak, } -#[derive(Clone)] -struct BlockArrived; - const ENGINE_TIMEOUT_TOKEN: TimerToken = 23; -impl IoHandler for TransitionHandler { - fn initialize(&self, io: &IoContext) { +impl IoHandler<()> for TransitionHandler { + fn initialize(&self, io: &IoContext<()>) { if let Some(engine) = self.engine.upgrade() { io.register_timer_once(ENGINE_TIMEOUT_TOKEN, engine.remaining_step_duration().as_millis()) .unwrap_or_else(|e| warn!(target: "poa", "Failed to start consensus step timer: {}.", e)) } } - fn timeout(&self, io: &IoContext, timer: TimerToken) { + fn timeout(&self, io: &IoContext<()>, timer: TimerToken) { if timer == ENGINE_TIMEOUT_TOKEN { if let Some(engine) = self.engine.upgrade() { engine.step.fetch_add(1, AtomicOrdering::SeqCst); From 727ace0561e54fd0fefa7c89937198983e12cfde Mon Sep 17 00:00:00 2001 From: keorn Date: Wed, 7 Dec 2016 15:14:21 +0100 Subject: [PATCH 10/10] add test --- ethcore/src/engines/authority_round.rs | 4 ++-- ethcore/src/engines/basic_authority.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/ethcore/src/engines/authority_round.rs b/ethcore/src/engines/authority_round.rs index f966bd7f6..f632c9382 100644 --- a/ethcore/src/engines/authority_round.rs +++ b/ethcore/src/engines/authority_round.rs @@ -391,9 +391,7 @@ mod tests { fn generates_seal_and_does_not_double_propose() { let tap = AccountProvider::transient_provider(); let addr1 = tap.insert_account("1".sha3(), "1").unwrap(); - tap.unlock_account_permanently(addr1, "1".into()).unwrap(); let addr2 = tap.insert_account("2".sha3(), "2").unwrap(); - tap.unlock_account_permanently(addr2, "2".into()).unwrap(); let spec = Spec::new_test_round(); let engine = &*spec.engine; @@ -409,12 +407,14 @@ mod tests { let b2 = OpenBlock::new(engine, Default::default(), false, db2, &genesis_header, last_hashes, addr2, (3141562.into(), 31415620.into()), vec![]).unwrap(); let b2 = b2.close_and_lock(); + engine.set_signer(addr1, "1".into()); if let Some(seal) = engine.generate_seal(b1.block()) { assert!(b1.clone().try_seal(engine, seal).is_ok()); // Second proposal is forbidden. assert!(engine.generate_seal(b1.block()).is_none()); } + engine.set_signer(addr2, "2".into()); if let Some(seal) = engine.generate_seal(b2.block()) { assert!(b2.clone().try_seal(engine, seal).is_ok()); // Second proposal is forbidden. diff --git a/ethcore/src/engines/basic_authority.rs b/ethcore/src/engines/basic_authority.rs index 4db8357e6..1070d3a3d 100644 --- a/ethcore/src/engines/basic_authority.rs +++ b/ethcore/src/engines/basic_authority.rs @@ -257,10 +257,10 @@ mod tests { fn can_generate_seal() { let tap = AccountProvider::transient_provider(); let addr = tap.insert_account("".sha3(), "").unwrap(); - tap.unlock_account_permanently(addr, "".into()).unwrap(); let spec = new_test_authority(); let engine = &*spec.engine; + engine.set_signer(addr, "".into()); engine.register_account_provider(Arc::new(tap)); let genesis_header = spec.genesis_header(); let mut db_result = get_temp_state_db();