fix types and lifetimes

This commit is contained in:
keorn 2016-08-21 15:27:39 +02:00
parent 8da38fa98b
commit 74939a43d6
2 changed files with 38 additions and 29 deletions

View File

@ -25,7 +25,7 @@ use evm::Schedule;
use ethjson; use ethjson;
/// `BFT` params. /// `BFT` params.
#[derive(Debug, PartialEq)] #[derive(Debug)]
pub struct BFTParams { pub struct BFTParams {
/// Gas limit divisor. /// Gas limit divisor.
pub gas_limit_bound_divisor: U256, pub gas_limit_bound_divisor: U256,
@ -36,7 +36,7 @@ pub struct BFTParams {
/// Number of validators. /// Number of validators.
pub validator_n: usize, pub validator_n: usize,
/// Precommit step votes. /// Precommit step votes.
precommits: HashMap<H256, HashSet<H520>> precommits: RwLock<HashMap<H256, HashSet<Signature>>>
} }
impl From<ethjson::spec::BFTParams> for BFTParams { impl From<ethjson::spec::BFTParams> for BFTParams {
@ -45,8 +45,9 @@ impl From<ethjson::spec::BFTParams> for BFTParams {
BFTParams { BFTParams {
gas_limit_bound_divisor: p.gas_limit_bound_divisor.into(), gas_limit_bound_divisor: p.gas_limit_bound_divisor.into(),
duration_limit: p.duration_limit.into(), duration_limit: p.duration_limit.into(),
validators: auth, validator_n: val.len(),
validator_n: val.len() validators: val,
precommits: RwLock::new(HashMap::new())
} }
} }
} }
@ -68,17 +69,27 @@ impl BFT {
} }
} }
fn check_precommit(&self, bare_hash: &H256, signature: &H520) -> result::Result<(), Error> { fn add_precommit(&self, bare_hash: &H256, signature: &Signature) {
let signer = Address::from(try!(ec::recover(&sig, bare_hash)).sha3()); if let Some(mut precommits) = self.our_params.precommits.write().get_mut(bare_hash) {
if !self.our_params.validators.contains(&signer) { precommits.insert(signature.clone());
return try!(Err(BlockError::InvalidSeal)); } else {
let mut new = HashSet::new();
new.insert(signature.clone());
assert!(self.our_params.precommits.write().insert(bare_hash.clone(), new).is_none());
}
}
fn check_precommit(&self, bare_hash: &H256, signature: &Signature) -> result::Result<(), Error> {
let signer = Address::from(try!(ec::recover(&signature, bare_hash)).sha3());
match self.our_params.validators.contains(&signer) {
false => try!(Err(BlockError::InvalidSeal)),
true => Ok(()),
} }
Ok(())
} }
fn supermajority(&self) -> usize { 2*self.our_params.validator_n/3 } fn supermajority(&self) -> usize { 2*self.our_params.validator_n/3 }
fn signatures_seal(&self, signatures: &HashSet<H520>) -> Vec<Bytes> { fn signatures_seal(&self, signatures: &HashSet<Signature>) -> Vec<Bytes> {
signatures.iter().map(|sig| encode(&(&*sig as &[u8])).to_vec()).collect() signatures.iter().map(|sig| encode(&(&*sig as &[u8])).to_vec()).collect()
} }
} }
@ -121,22 +132,23 @@ impl Engine for BFT {
/// ///
/// None is returned if not enough signatures can be collected. /// None is returned if not enough signatures can be collected.
fn generate_seal(&self, block: &ExecutedBlock, accounts: Option<&AccountProvider>) -> Option<Vec<Bytes>> { fn generate_seal(&self, block: &ExecutedBlock, accounts: Option<&AccountProvider>) -> Option<Vec<Bytes>> {
let hash = block.bare_hash(); let hash = block.header().bare_hash();
let signatures = self.our_params.precommits.entry(hash).or_insert(HashSet::new()); let guard = self.our_params.precommits.read();
let signatures = guard.get(&hash).unwrap_or(return None);
let threshold = self.supermajority(); let threshold = self.supermajority();
match (signatures.len(), accounts) { match (signatures.len(), accounts) {
(threshold-1, Some(ap)) => { (v, Some(ap)) if v == threshold-1 => {
// account should be pernamently unlocked, otherwise signing will fail // account should be pernamently unlocked, otherwise signing will fail
if let Ok(signature) = ap.sign(*block.header().author(), hash) { if let Ok(signature) = ap.sign(*block.header().author(), hash) {
*signatures.insert(signature); self.add_precommit(&hash, &signature.into());
Some(self.signatures_seal(signatures)); Some(self.signatures_seal(signatures))
} else { } else {
trace!(target: "bft", "generate_seal: FAIL: secret key unavailable"); trace!(target: "bft", "generate_seal: FAIL: secret key unavailable");
None None
} }
}, },
(0..threshold, _) => None, (v, _) if v < threshold => None,
(threshold.., _) => Some(block.header().seal), _ => Some(block.header().seal.clone()),
} }
} }
@ -154,18 +166,19 @@ impl Engine for BFT {
fn verify_block_unordered(&self, header: &Header, _block: Option<&[u8]>) -> result::Result<(), Error> { fn verify_block_unordered(&self, header: &Header, _block: Option<&[u8]>) -> result::Result<(), Error> {
let hash = header.bare_hash(); let hash = header.bare_hash();
let threshold = self.supermajority(); let threshold = self.supermajority();
let signatures = self.our_params.precommits.entry(hash).or_insert(HashSet::new()); let guard = self.our_params.precommits.read();
let mut signatures = guard.get(&hash).unwrap_or(try!(Err(BlockError::InvalidSeal)));
if signatures.len() > threshold { return Ok(()) } if signatures.len() > threshold { return Ok(()) }
// Count all valid precommits. // Count all valid precommits.
for seal_field in header.seal { for seal_field in header.seal() {
let sig = try!(UntrustedRlp::new(seal_field).as_val::<H520>()); let sig = try!(UntrustedRlp::new(&seal_field).as_val::<Signature>());
if !signatures.contains(sig) || self.check_precommit(hash, sig).is_ok() { if !signatures.contains(&sig) || self.check_precommit(&hash, &sig).is_ok() {
trace!(target: "bft", "verify_block_unordered: new validator vote found"); trace!(target: "bft", "verify_block_unordered: new validator vote found");
*signatures.insert(sig); self.add_precommit(&hash, &sig);
if signatures.len() > threshold { return Ok(()) } if signatures.len() > threshold { return Ok(()) }
} }
} }
Err(BlockError::InvalidSeal) try!(Err(BlockError::InvalidSeal))
} }
fn verify_block_family(&self, header: &Header, parent: &Header, _block: Option<&[u8]>) -> result::Result<(), Error> { fn verify_block_family(&self, header: &Header, parent: &Header, _block: Option<&[u8]>) -> result::Result<(), Error> {
@ -197,12 +210,6 @@ impl Engine for BFT {
} }
} }
impl Header {
/// Get the none field of the header.
pub fn signature(&self) -> H520 {
decode(&self.seal()[0])
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {

View File

@ -19,10 +19,12 @@
mod null_engine; mod null_engine;
mod instant_seal; mod instant_seal;
mod basic_authority; mod basic_authority;
mod bft;
pub use self::null_engine::NullEngine; pub use self::null_engine::NullEngine;
pub use self::instant_seal::InstantSeal; pub use self::instant_seal::InstantSeal;
pub use self::basic_authority::BasicAuthority; pub use self::basic_authority::BasicAuthority;
pub use self::bft::BFT;
use common::*; use common::*;
use account_provider::AccountProvider; use account_provider::AccountProvider;