hold password in engine, add rpc

This commit is contained in:
keorn 2016-11-30 12:59:33 +00:00
parent 4ef5badcea
commit 34d5017950
7 changed files with 55 additions and 6 deletions

View File

@ -187,6 +187,9 @@ pub trait Engine : Sync + Send {
/// Add an account provider useful for Engines that sign stuff.
fn register_account_provider(&self, _account_provider: Arc<AccountProvider>) {}
/// 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)

View File

@ -66,6 +66,8 @@ pub struct Tendermint {
step_service: IoService<Step>,
/// Address to be used as authority.
authority: RwLock<Address>,
/// Password used for signing messages.
password: RwLock<Option<String>>,
/// Blockchain height.
height: AtomicUsize,
/// Consensus round.
@ -98,6 +100,7 @@ impl Tendermint {
builtins: builtins,
step_service: try!(IoService::<Step>::start()),
authority: RwLock::new(Address::default()),
password: RwLock::new(None),
height: AtomicUsize::new(1),
round: AtomicUsize::new(0),
step: RwLock::new(Step::Propose),
@ -144,7 +147,7 @@ impl Tendermint {
fn generate_message(&self, block_hash: Option<BlockHash>) -> Option<Bytes> {
if let Some(ref ap) = *self.account_provider.lock() {
message_full_rlp(
|mh| ap.sign(*self.authority.read(), None, mh).ok().map(H520::from),
|mh| ap.sign(*self.authority.read(), self.password.read().clone(), mh).ok().map(H520::from),
self.height.load(AtomicOrdering::SeqCst),
self.round.load(AtomicOrdering::SeqCst),
*self.step.read(),
@ -333,7 +336,7 @@ impl Engine for Tendermint {
let round = self.round.load(AtomicOrdering::SeqCst);
let bh = Some(header.bare_hash());
let vote_info = message_info_rlp(height, round, Step::Propose, bh);
if let Ok(signature) = ap.sign(*author, None, vote_info.sha3()).map(H520::from) {
if let Ok(signature) = ap.sign(*author, self.password.read().clone(), vote_info.sha3()).map(H520::from) {
self.votes.vote(ConsensusMessage { signature: signature, height: height, round: round, step: Step::Propose, block_hash: bh }, *author);
*self.proposal.write() = Some(header.bare_hash());
Some(vec![
@ -472,6 +475,11 @@ impl Engine for Tendermint {
t.sender().map(|_|()) // Perform EC recovery and cache sender
}
fn set_signer(&self, address: Address, password: String) {
*self.authority.write() = address;
*self.password.write() = Some(password);
}
fn is_new_best_block(&self, _best_total_difficulty: U256, best_header: HeaderView, _parent_details: &BlockDetails, new_header: &HeaderView) -> bool {
let new_signatures = new_header.seal().get(2).expect("Tendermint seal should have three elements.").len();
let best_signatures = best_header.seal().get(2).expect("Tendermint seal should have three elements.").len();
@ -695,7 +703,6 @@ mod tests {
let proposal = Some(b.header().bare_hash());
// Register IoHandler remembers messages.
seal[2] = precommit_signatures(&tap, h, r, Some(b.header().bare_hash()), v0, v1);
let io_service = IoService::<ClientIoMessage>::start().unwrap();
let test_io = TestIo::new();
io_service.register_handler(test_io.clone()).unwrap();
@ -708,8 +715,12 @@ mod tests {
vote(&engine, |mh| tap.sign(v1, None, mh).ok().map(H520::from), h, r, Step::Precommit, proposal);
vote(&engine, |mh| tap.sign(v0, None, mh).ok().map(H520::from), h, r, Step::Precommit, proposal);
// Wait a bit for async stuff.
::std::thread::sleep(::std::time::Duration::from_millis(500));
assert_eq!(test_io.received.read()[5], ClientIoMessage::SubmitSeal(proposal.unwrap(), seal));
println!("{:?}", *test_io.received.read());
seal[2] = precommit_signatures(&tap, h, r, Some(b.header().bare_hash()), v0, v1);
let first = test_io.received.read()[5] == ClientIoMessage::SubmitSeal(proposal.unwrap(), seal.clone());
seal[2] = precommit_signatures(&tap, h, r, Some(b.header().bare_hash()), v1, v0);
let second = test_io.received.read()[5] == ClientIoMessage::SubmitSeal(proposal.unwrap(), seal);
assert!(first ^ second);
}
}

View File

@ -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};
@ -735,6 +735,19 @@ impl MinerService for Miner {
*self.author.write() = author;
}
fn set_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;
}

View File

@ -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_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;

View File

@ -116,6 +116,12 @@ impl<C, M, F> ParitySet for ParitySetClient<C, M, F> where
Ok(true)
}
fn set_sealer(&self, address: H160, password: String) -> Result<bool, Error> {
try!(self.active());
try!(take_weak!(self.miner).set_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> {
try!(self.active());

View File

@ -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 {
@ -43,6 +44,7 @@ pub struct TestMinerService {
min_gas_price: RwLock<U256>,
gas_range_target: RwLock<(U256, U256)>,
password: RwLock<String>,
author: RwLock<Address>,
extra_data: RwLock<Bytes>,
limit: RwLock<usize>,
@ -61,6 +63,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 +86,12 @@ impl MinerService for TestMinerService {
*self.author.write() = author;
}
fn set_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;
}

View File

@ -44,6 +44,10 @@ build_rpc_trait! {
#[rpc(name = "parity_setAuthor")]
fn set_author(&self, H160) -> Result<bool, Error>;
/// Sets account for signing consensus messages.
#[rpc(name = "parity_setSealer")]
fn set_sealer(&self, H160, String) -> Result<bool, Error>;
/// Sets the limits for transaction queue.
#[rpc(name = "parity_setTransactionsLimit")]
fn set_transactions_limit(&self, usize) -> Result<bool, Error>;