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;