add password and AccountProvider
This commit is contained in:
parent
53b479fb7a
commit
529a7fc33c
@ -21,13 +21,15 @@ use std::sync::Weak;
|
|||||||
use std::time::{UNIX_EPOCH, Duration};
|
use std::time::{UNIX_EPOCH, Duration};
|
||||||
use util::*;
|
use util::*;
|
||||||
use ethkey::{verify_address, Signature};
|
use ethkey::{verify_address, Signature};
|
||||||
use rlp::{Rlp, UntrustedRlp, View, encode};
|
use rlp::{UntrustedRlp, View, encode};
|
||||||
use account_provider::AccountProvider;
|
use account_provider::AccountProvider;
|
||||||
use block::*;
|
use block::*;
|
||||||
use spec::CommonParams;
|
use spec::CommonParams;
|
||||||
use engines::Engine;
|
use engines::Engine;
|
||||||
use header::Header;
|
use header::Header;
|
||||||
use error::{Error, BlockError};
|
use error::{Error, BlockError};
|
||||||
|
use blockchain::extras::BlockDetails;
|
||||||
|
use views::HeaderView;
|
||||||
use evm::Schedule;
|
use evm::Schedule;
|
||||||
use ethjson;
|
use ethjson;
|
||||||
use io::{IoContext, IoHandler, TimerToken, IoService, IoChannel};
|
use io::{IoContext, IoHandler, TimerToken, IoService, IoChannel};
|
||||||
@ -35,8 +37,6 @@ use service::ClientIoMessage;
|
|||||||
use transaction::SignedTransaction;
|
use transaction::SignedTransaction;
|
||||||
use env_info::EnvInfo;
|
use env_info::EnvInfo;
|
||||||
use builtin::Builtin;
|
use builtin::Builtin;
|
||||||
use blockchain::extras::BlockDetails;
|
|
||||||
use views::HeaderView;
|
|
||||||
|
|
||||||
/// `AuthorityRound` params.
|
/// `AuthorityRound` params.
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
@ -72,6 +72,7 @@ pub struct AuthorityRound {
|
|||||||
message_channel: Mutex<Option<IoChannel<ClientIoMessage>>>,
|
message_channel: Mutex<Option<IoChannel<ClientIoMessage>>>,
|
||||||
step: AtomicUsize,
|
step: AtomicUsize,
|
||||||
proposed: AtomicBool,
|
proposed: AtomicBool,
|
||||||
|
account_provider: Mutex<Option<Arc<AccountProvider>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn header_step(header: &Header) -> Result<usize, ::rlp::DecoderError> {
|
fn header_step(header: &Header) -> Result<usize, ::rlp::DecoderError> {
|
||||||
@ -104,7 +105,8 @@ impl AuthorityRound {
|
|||||||
transition_service: try!(IoService::<BlockArrived>::start()),
|
transition_service: try!(IoService::<BlockArrived>::start()),
|
||||||
message_channel: Mutex::new(None),
|
message_channel: Mutex::new(None),
|
||||||
step: AtomicUsize::new(initial_step),
|
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) };
|
let handler = TransitionHandler { engine: Arc::downgrade(&engine) };
|
||||||
try!(engine.transition_service.register_handler(Arc::new(handler)));
|
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) {
|
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({
|
header.set_gas_limit({
|
||||||
let gas_limit = parent.gas_limit().clone();
|
let gas_limit = parent.gas_limit().clone();
|
||||||
let bound_divisor = self.our_params.gas_limit_bound_divisor;
|
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
|
/// This operation is synchronous and may (quite reasonably) not be available, in which `false` will
|
||||||
/// be returned.
|
/// be returned.
|
||||||
fn generate_seal(&self, block: &ExecutedBlock, accounts: Option<&AccountProvider>) -> Option<Vec<Bytes>> {
|
fn generate_seal(&self, block: &ExecutedBlock) -> Option<Vec<Bytes>> {
|
||||||
if self.proposed.load(AtomicOrdering::SeqCst) { return None; }
|
if self.proposed.load(AtomicOrdering::SeqCst) { return None; }
|
||||||
let header = block.header();
|
let header = block.header();
|
||||||
let step = self.step();
|
let step = self.step();
|
||||||
if self.is_step_proposer(step, header.author()) {
|
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.
|
// 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(), None, header.bare_hash()) {
|
||||||
trace!(target: "poa", "generate_seal: Issuing a block for step {}.", step);
|
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
|
t.sender().map(|_|()) // Perform EC recovery and cache sender
|
||||||
}
|
}
|
||||||
|
|
||||||
fn register_message_channel(&self, message_channel: IoChannel<ClientIoMessage>) {
|
fn is_new_best_block(&self, _best_total_difficulty: U256, best_header: HeaderView, _parent_details: &BlockDetails, new_header: &HeaderView) -> bool {
|
||||||
let mut guard = self.message_channel.lock();
|
new_header.number() > best_header.number()
|
||||||
*guard = Some(message_channel);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_new_best_block(&self, _best_total_difficulty: U256, best_header: HeaderView, _parent_details: &BlockDetails, new_header: &HeaderView) -> bool {
|
fn register_message_channel(&self, message_channel: IoChannel<ClientIoMessage>) {
|
||||||
let new_number = new_header.number();
|
*self.message_channel.lock() = Some(message_channel);
|
||||||
let best_number = best_header.number();
|
}
|
||||||
if new_number != best_number {
|
|
||||||
new_number > best_number
|
fn register_account_provider(&self, account_provider: Arc<AccountProvider>) {
|
||||||
} else {
|
*self.account_provider.lock() = Some(account_provider);
|
||||||
// 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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -393,6 +388,7 @@ mod tests {
|
|||||||
|
|
||||||
let spec = Spec::new_test_round();
|
let spec = Spec::new_test_round();
|
||||||
let engine = &*spec.engine;
|
let engine = &*spec.engine;
|
||||||
|
engine.register_account_provider(Arc::new(tap));
|
||||||
let genesis_header = spec.genesis_header();
|
let genesis_header = spec.genesis_header();
|
||||||
let mut db1 = get_temp_state_db().take();
|
let mut db1 = get_temp_state_db().take();
|
||||||
spec.ensure_db_good(&mut db1, &TrieFactory::new(TrieSpec::Secure)).unwrap();
|
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 = OpenBlock::new(engine, Default::default(), false, db2, &genesis_header, last_hashes, addr2, (3141562.into(), 31415620.into()), vec![]).unwrap();
|
||||||
let b2 = b2.close_and_lock();
|
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());
|
assert!(b1.clone().try_seal(engine, seal).is_ok());
|
||||||
// Second proposal is forbidden.
|
// 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());
|
assert!(b2.clone().try_seal(engine, seal).is_ok());
|
||||||
// Second proposal is forbidden.
|
// Second proposal is forbidden.
|
||||||
assert!(engine.generate_seal(b2.block(), Some(&tap)).is_none());
|
assert!(engine.generate_seal(b2.block()).is_none());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -58,6 +58,7 @@ pub struct BasicAuthority {
|
|||||||
params: CommonParams,
|
params: CommonParams,
|
||||||
our_params: BasicAuthorityParams,
|
our_params: BasicAuthorityParams,
|
||||||
builtins: BTreeMap<Address, Builtin>,
|
builtins: BTreeMap<Address, Builtin>,
|
||||||
|
account_provider: Mutex<Option<Arc<AccountProvider>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl BasicAuthority {
|
impl BasicAuthority {
|
||||||
@ -67,6 +68,7 @@ impl BasicAuthority {
|
|||||||
params: params,
|
params: params,
|
||||||
our_params: our_params,
|
our_params: our_params,
|
||||||
builtins: builtins,
|
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
|
/// This operation is synchronous and may (quite reasonably) not be available, in which `false` will
|
||||||
/// be returned.
|
/// be returned.
|
||||||
fn generate_seal(&self, block: &ExecutedBlock, accounts: Option<&AccountProvider>) -> Option<Vec<Bytes>> {
|
fn generate_seal(&self, block: &ExecutedBlock) -> Option<Vec<Bytes>> {
|
||||||
if let Some(ap) = accounts {
|
if let Some(ref ap) = *self.account_provider.lock() {
|
||||||
let header = block.header();
|
let header = block.header();
|
||||||
let message = header.bare_hash();
|
let message = header.bare_hash();
|
||||||
// account should be pernamently unlocked, otherwise sealing will fail
|
// 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> {
|
fn verify_transaction(&self, t: &SignedTransaction, _header: &Header) -> Result<(), Error> {
|
||||||
t.sender().map(|_|()) // Perform EC recovery and cache sender
|
t.sender().map(|_|()) // Perform EC recovery and cache sender
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn register_account_provider(&self, ap: Arc<AccountProvider>) {
|
||||||
|
*self.account_provider.lock() = Some(ap);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
@ -254,6 +260,7 @@ mod tests {
|
|||||||
|
|
||||||
let spec = new_test_authority();
|
let spec = new_test_authority();
|
||||||
let engine = &*spec.engine;
|
let engine = &*spec.engine;
|
||||||
|
engine.register_account_provider(Arc::new(tap));
|
||||||
let genesis_header = spec.genesis_header();
|
let genesis_header = spec.genesis_header();
|
||||||
let mut db_result = get_temp_state_db();
|
let mut db_result = get_temp_state_db();
|
||||||
let mut db = db_result.take();
|
let mut db = db_result.take();
|
||||||
@ -261,7 +268,7 @@ mod tests {
|
|||||||
let last_hashes = Arc::new(vec![genesis_header.hash()]);
|
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, addr, (3141562.into(), 31415620.into()), vec![]).unwrap();
|
||||||
let b = b.close_and_lock();
|
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());
|
assert!(b.try_seal(engine, seal).is_ok());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,7 +23,6 @@ use spec::CommonParams;
|
|||||||
use evm::Schedule;
|
use evm::Schedule;
|
||||||
use block::ExecutedBlock;
|
use block::ExecutedBlock;
|
||||||
use util::Bytes;
|
use util::Bytes;
|
||||||
use account_provider::AccountProvider;
|
|
||||||
|
|
||||||
/// An engine which does not provide any consensus mechanism, just seals blocks internally.
|
/// An engine which does not provide any consensus mechanism, just seals blocks internally.
|
||||||
pub struct InstantSeal {
|
pub struct InstantSeal {
|
||||||
@ -60,7 +59,7 @@ impl Engine for InstantSeal {
|
|||||||
|
|
||||||
fn is_sealer(&self, _author: &Address) -> Option<bool> { Some(true) }
|
fn is_sealer(&self, _author: &Address) -> Option<bool> { Some(true) }
|
||||||
|
|
||||||
fn generate_seal(&self, _block: &ExecutedBlock, _accounts: Option<&AccountProvider>) -> Option<Vec<Bytes>> {
|
fn generate_seal(&self, _block: &ExecutedBlock) -> Option<Vec<Bytes>> {
|
||||||
Some(Vec::new())
|
Some(Vec::new())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -70,16 +69,12 @@ mod tests {
|
|||||||
use util::*;
|
use util::*;
|
||||||
use util::trie::TrieSpec;
|
use util::trie::TrieSpec;
|
||||||
use tests::helpers::*;
|
use tests::helpers::*;
|
||||||
use account_provider::AccountProvider;
|
|
||||||
use spec::Spec;
|
use spec::Spec;
|
||||||
use header::Header;
|
use header::Header;
|
||||||
use block::*;
|
use block::*;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn instant_can_seal() {
|
fn instant_can_seal() {
|
||||||
let tap = AccountProvider::transient_provider();
|
|
||||||
let addr = tap.insert_account("".sha3(), "").unwrap();
|
|
||||||
|
|
||||||
let spec = Spec::new_instant();
|
let spec = Spec::new_instant();
|
||||||
let engine = &*spec.engine;
|
let engine = &*spec.engine;
|
||||||
let genesis_header = spec.genesis_header();
|
let genesis_header = spec.genesis_header();
|
||||||
@ -87,10 +82,9 @@ mod tests {
|
|||||||
let mut db = db_result.take();
|
let mut db = db_result.take();
|
||||||
spec.ensure_db_good(&mut db, &TrieFactory::new(TrieSpec::Secure)).unwrap();
|
spec.ensure_db_good(&mut db, &TrieFactory::new(TrieSpec::Secure)).unwrap();
|
||||||
let last_hashes = Arc::new(vec![genesis_header.hash()]);
|
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();
|
let b = b.close_and_lock();
|
||||||
// Seal with empty AccountProvider.
|
let seal = engine.generate_seal(b.block()).unwrap();
|
||||||
let seal = engine.generate_seal(b.block(), Some(&tap)).unwrap();
|
|
||||||
assert!(b.try_seal(engine, seal).is_ok());
|
assert!(b.try_seal(engine, seal).is_ok());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -94,7 +94,7 @@ pub trait Engine : Sync + Send {
|
|||||||
///
|
///
|
||||||
/// This operation is synchronous and may (quite reasonably) not be available, in which None will
|
/// This operation is synchronous and may (quite reasonably) not be available, in which None will
|
||||||
/// be returned.
|
/// be returned.
|
||||||
fn generate_seal(&self, _block: &ExecutedBlock, _accounts: Option<&AccountProvider>) -> Option<Vec<Bytes>> { None }
|
fn generate_seal(&self, _block: &ExecutedBlock) -> Option<Vec<Bytes>> { None }
|
||||||
|
|
||||||
/// Phase 1 quick block verification. Only does checks that are cheap. `block` (the header's full block)
|
/// 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.
|
/// 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);
|
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<ClientIoMessage>) {}
|
|
||||||
|
|
||||||
/// Check if new block should be chosen as the one in chain.
|
/// 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 {
|
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)
|
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<ClientIoMessage>) {}
|
||||||
|
|
||||||
|
/// Add an account provider useful for Engines that sign stuff.
|
||||||
|
fn register_account_provider(&self, _account_provider: Arc<AccountProvider>) {}
|
||||||
}
|
}
|
||||||
|
@ -19,7 +19,7 @@ use std::time::{Instant, Duration};
|
|||||||
|
|
||||||
use util::*;
|
use util::*;
|
||||||
use util::using_queue::{UsingQueue, GetAction};
|
use util::using_queue::{UsingQueue, GetAction};
|
||||||
use account_provider::AccountProvider;
|
use account_provider::{AccountProvider, Error as AccountError};
|
||||||
use views::{BlockView, HeaderView};
|
use views::{BlockView, HeaderView};
|
||||||
use header::Header;
|
use header::Header;
|
||||||
use state::{State, CleanupMode};
|
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),
|
/// 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.
|
/// Err(Some(block)) returns for unsuccesful sealing while Err(None) indicates misspecified engine.
|
||||||
fn seal_block_internally(&self, block: ClosedBlock) -> Result<SealedBlock, Option<ClosedBlock>> {
|
fn seal_block_internally(&self, block: ClosedBlock) -> Result<SealedBlock, Option<ClosedBlock>> {
|
||||||
trace!(target: "miner", "seal_block_internally: block has transaction - attempting internal seal.");
|
trace!(target: "miner", "seal_block_internally: attempting internal seal.");
|
||||||
let s = self.engine.generate_seal(block.block(), match self.accounts {
|
let s = self.engine.generate_seal(block.block());
|
||||||
Some(ref x) => Some(&**x),
|
|
||||||
None => None,
|
|
||||||
});
|
|
||||||
if let Some(seal) = s {
|
if let Some(seal) = s {
|
||||||
trace!(target: "miner", "seal_block_internally: managed internal seal. importing...");
|
trace!(target: "miner", "seal_block_internally: managed internal seal. importing...");
|
||||||
block.lock().try_seal(&*self.engine, seal).or_else(|_| {
|
block.lock().try_seal(&*self.engine, seal).or_else(|(e, _)| {
|
||||||
warn!("prepare_sealing: ERROR: try_seal failed when given internally generated seal. WTF?");
|
warn!("prepare_sealing: ERROR: try_seal failed when given internally generated seal: {}", e);
|
||||||
Err(None)
|
Err(None)
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
@ -485,7 +482,7 @@ impl Miner {
|
|||||||
fn seal_and_import_block_internally(&self, chain: &MiningBlockChainClient, block: ClosedBlock) -> bool {
|
fn seal_and_import_block_internally(&self, chain: &MiningBlockChainClient, block: ClosedBlock) -> bool {
|
||||||
if !block.transactions().is_empty() || self.forced_sealing() {
|
if !block.transactions().is_empty() || self.forced_sealing() {
|
||||||
if let Ok(sealed) = self.seal_block_internally(block) {
|
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");
|
trace!(target: "miner", "import_block_internally: imported internally sealed block");
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@ -740,6 +737,19 @@ impl MinerService for Miner {
|
|||||||
*self.author.write() = author;
|
*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) {
|
fn set_extra_data(&self, extra_data: Bytes) {
|
||||||
*self.extra_data.write() = extra_data;
|
*self.extra_data.write() = extra_data;
|
||||||
}
|
}
|
||||||
@ -1020,6 +1030,11 @@ impl MinerService for Miner {
|
|||||||
let (block, original_work_hash) = self.prepare_block(chain);
|
let (block, original_work_hash) = self.prepare_block(chain);
|
||||||
if self.seals_internally {
|
if self.seals_internally {
|
||||||
trace!(target: "miner", "update_sealing: engine indicates internal sealing");
|
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);
|
self.seal_and_import_block_internally(chain, block);
|
||||||
} else {
|
} else {
|
||||||
trace!(target: "miner", "update_sealing: engine does not seal internally, preparing work");
|
trace!(target: "miner", "update_sealing: engine does not seal internally, preparing work");
|
||||||
@ -1042,7 +1057,7 @@ impl MinerService for Miner {
|
|||||||
ret.map(f)
|
ret.map(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn submit_seal(&self, chain: &MiningBlockChainClient, pow_hash: H256, seal: Vec<Bytes>) -> Result<(), Error> {
|
fn submit_seal(&self, chain: &MiningBlockChainClient, block_hash: H256, seal: Vec<Bytes>) -> Result<(), Error> {
|
||||||
let result =
|
let result =
|
||||||
if let Some(b) = self.sealing_work.lock().queue.get_used_if(
|
if let Some(b) = self.sealing_work.lock().queue.get_used_if(
|
||||||
if self.options.enable_resubmission {
|
if self.options.enable_resubmission {
|
||||||
@ -1050,22 +1065,22 @@ impl MinerService for Miner {
|
|||||||
} else {
|
} else {
|
||||||
GetAction::Take
|
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, _)| {
|
b.lock().try_seal(&*self.engine, seal).or_else(|(e, _)| {
|
||||||
warn!(target: "miner", "Mined solution rejected: {}", e);
|
warn!(target: "miner", "Mined solution rejected: {}", e);
|
||||||
Err(Error::PowInvalid)
|
Err(Error::PowInvalid)
|
||||||
})
|
})
|
||||||
} else {
|
} 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)
|
Err(Error::PowHashInvalid)
|
||||||
};
|
};
|
||||||
result.and_then(|sealed| {
|
result.and_then(|sealed| {
|
||||||
let n = sealed.header().number();
|
let n = sealed.header().number();
|
||||||
let h = sealed.header().hash();
|
let h = sealed.header().hash();
|
||||||
try!(chain.import_sealed_block(sealed));
|
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(())
|
Ok(())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -76,6 +76,9 @@ pub trait MinerService : Send + Sync {
|
|||||||
/// Set the author that we will seal blocks as.
|
/// Set the author that we will seal blocks as.
|
||||||
fn set_author(&self, author: Address);
|
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.
|
/// Get the extra_data that we will seal blocks with.
|
||||||
fn extra_data(&self) -> Bytes;
|
fn extra_data(&self) -> Bytes;
|
||||||
|
|
||||||
|
@ -70,7 +70,7 @@ pub struct RunCmd {
|
|||||||
pub http_conf: HttpConfiguration,
|
pub http_conf: HttpConfiguration,
|
||||||
pub ipc_conf: IpcConfiguration,
|
pub ipc_conf: IpcConfiguration,
|
||||||
pub net_conf: NetworkConfiguration,
|
pub net_conf: NetworkConfiguration,
|
||||||
pub network_id: Option<usize>,
|
pub network_id: Option<u64>,
|
||||||
pub warp_sync: bool,
|
pub warp_sync: bool,
|
||||||
pub acc_conf: AccountsConfig,
|
pub acc_conf: AccountsConfig,
|
||||||
pub gas_pricer: GasPricerConfig,
|
pub gas_pricer: GasPricerConfig,
|
||||||
@ -208,6 +208,9 @@ pub fn execute(cmd: RunCmd, logger: Arc<RotatingLogger>) -> Result<(), String> {
|
|||||||
// prepare account provider
|
// 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)));
|
||||||
|
|
||||||
|
// let the Engine access the accounts
|
||||||
|
spec.engine.register_account_provider(account_provider.clone());
|
||||||
|
|
||||||
// create miner
|
// create miner
|
||||||
let miner = Miner::new(cmd.miner_options, cmd.gas_pricer.into(), &spec, Some(account_provider.clone()));
|
let miner = Miner::new(cmd.miner_options, cmd.gas_pricer.into(), &spec, Some(account_provider.clone()));
|
||||||
miner.set_author(cmd.miner_extras.author);
|
miner.set_author(cmd.miner_extras.author);
|
||||||
|
@ -116,6 +116,12 @@ impl<C, M, F> ParitySet for ParitySetClient<C, M, F> where
|
|||||||
Ok(true)
|
Ok(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn set_consensus_signer(&self, address: H160, password: String) -> Result<bool, Error> {
|
||||||
|
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<bool, Error> {
|
fn set_transactions_limit(&self, limit: usize) -> Result<bool, Error> {
|
||||||
try!(self.active());
|
try!(self.active());
|
||||||
|
|
||||||
|
@ -116,6 +116,7 @@ impl EthTester {
|
|||||||
fn from_spec(spec: Spec) -> Self {
|
fn from_spec(spec: Spec) -> Self {
|
||||||
let dir = RandomTempPath::new();
|
let dir = RandomTempPath::new();
|
||||||
let account_provider = account_provider();
|
let account_provider = account_provider();
|
||||||
|
spec.engine.register_account_provider(account_provider.clone());
|
||||||
let miner_service = miner_service(&spec, account_provider.clone());
|
let miner_service = miner_service(&spec, account_provider.clone());
|
||||||
let snapshot_service = snapshot_service();
|
let snapshot_service = snapshot_service();
|
||||||
|
|
||||||
|
@ -25,6 +25,7 @@ use ethcore::header::BlockNumber;
|
|||||||
use ethcore::transaction::SignedTransaction;
|
use ethcore::transaction::SignedTransaction;
|
||||||
use ethcore::receipt::{Receipt, RichReceipt};
|
use ethcore::receipt::{Receipt, RichReceipt};
|
||||||
use ethcore::miner::{MinerService, MinerStatus, TransactionImportResult, LocalTransactionStatus};
|
use ethcore::miner::{MinerService, MinerStatus, TransactionImportResult, LocalTransactionStatus};
|
||||||
|
use ethcore::account_provider::Error as AccountError;
|
||||||
|
|
||||||
/// Test miner service.
|
/// Test miner service.
|
||||||
pub struct TestMinerService {
|
pub struct TestMinerService {
|
||||||
@ -40,6 +41,8 @@ pub struct TestMinerService {
|
|||||||
pub pending_receipts: Mutex<BTreeMap<H256, Receipt>>,
|
pub pending_receipts: Mutex<BTreeMap<H256, Receipt>>,
|
||||||
/// Last nonces.
|
/// Last nonces.
|
||||||
pub last_nonces: RwLock<HashMap<Address, U256>>,
|
pub last_nonces: RwLock<HashMap<Address, U256>>,
|
||||||
|
/// Password held by Engine.
|
||||||
|
pub password: RwLock<String>,
|
||||||
|
|
||||||
min_gas_price: RwLock<U256>,
|
min_gas_price: RwLock<U256>,
|
||||||
gas_range_target: RwLock<(U256, U256)>,
|
gas_range_target: RwLock<(U256, U256)>,
|
||||||
@ -61,6 +64,7 @@ impl Default for TestMinerService {
|
|||||||
min_gas_price: RwLock::new(U256::from(20_000_000)),
|
min_gas_price: RwLock::new(U256::from(20_000_000)),
|
||||||
gas_range_target: RwLock::new((U256::from(12345), U256::from(54321))),
|
gas_range_target: RwLock::new((U256::from(12345), U256::from(54321))),
|
||||||
author: RwLock::new(Address::zero()),
|
author: RwLock::new(Address::zero()),
|
||||||
|
password: RwLock::new(String::new()),
|
||||||
extra_data: RwLock::new(vec![1, 2, 3, 4]),
|
extra_data: RwLock::new(vec![1, 2, 3, 4]),
|
||||||
limit: RwLock::new(1024),
|
limit: RwLock::new(1024),
|
||||||
tx_gas_limit: RwLock::new(!U256::zero()),
|
tx_gas_limit: RwLock::new(!U256::zero()),
|
||||||
@ -83,6 +87,12 @@ impl MinerService for TestMinerService {
|
|||||||
*self.author.write() = author;
|
*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) {
|
fn set_extra_data(&self, extra_data: Bytes) {
|
||||||
*self.extra_data.write() = extra_data;
|
*self.extra_data.write() = extra_data;
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,7 @@ use ethsync::{SyncProvider, SyncStatus, SyncState, PeerInfo, TransactionStats};
|
|||||||
/// TestSyncProvider config.
|
/// TestSyncProvider config.
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
/// Protocol version.
|
/// Protocol version.
|
||||||
pub network_id: usize,
|
pub network_id: u64,
|
||||||
/// Number of peers.
|
/// Number of peers.
|
||||||
pub num_peers: usize,
|
pub num_peers: usize,
|
||||||
}
|
}
|
||||||
|
@ -106,6 +106,23 @@ fn rpc_parity_set_author() {
|
|||||||
assert_eq!(miner.author(), Address::from_str("cd1722f3947def4cf144679da39c4c32bdc35681").unwrap());
|
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]
|
#[test]
|
||||||
fn rpc_parity_set_transactions_limit() {
|
fn rpc_parity_set_transactions_limit() {
|
||||||
let miner = miner_service();
|
let miner = miner_service();
|
||||||
|
@ -44,6 +44,10 @@ build_rpc_trait! {
|
|||||||
#[rpc(name = "parity_setAuthor")]
|
#[rpc(name = "parity_setAuthor")]
|
||||||
fn set_author(&self, H160) -> Result<bool, Error>;
|
fn set_author(&self, H160) -> Result<bool, Error>;
|
||||||
|
|
||||||
|
/// Sets account for signing consensus messages.
|
||||||
|
#[rpc(name = "parity_setConsensusSigner")]
|
||||||
|
fn set_consensus_signer(&self, H160, String) -> Result<bool, Error>;
|
||||||
|
|
||||||
/// Sets the limits for transaction queue.
|
/// Sets the limits for transaction queue.
|
||||||
#[rpc(name = "parity_setTransactionsLimit")]
|
#[rpc(name = "parity_setTransactionsLimit")]
|
||||||
fn set_transactions_limit(&self, usize) -> Result<bool, Error>;
|
fn set_transactions_limit(&self, usize) -> Result<bool, Error>;
|
||||||
|
Loading…
Reference in New Issue
Block a user