add tests, fixes, simplifications
This commit is contained in:
parent
747898d8e7
commit
fc3d01ec71
@ -1,11 +1,14 @@
|
|||||||
{
|
{
|
||||||
"name": "TestAuthorityRound",
|
"name": "TestAuthorityRound",
|
||||||
"engine": {
|
"engine": {
|
||||||
"BasicAuthority": {
|
"AuthorityRound": {
|
||||||
"params": {
|
"params": {
|
||||||
"gasLimitBoundDivisor": "0x0400",
|
"gasLimitBoundDivisor": "0x0400",
|
||||||
"stepDuration": "0x0d",
|
"stepDuration": "0x03e8",
|
||||||
"authorities" : ["0x9cce34f7ab185c7aba1b7c8140d620b4bda941d6"]
|
"authorities" : [
|
||||||
|
"0x7d577a597b2742b498cb5cf0c26cdcd726d39e6e",
|
||||||
|
"0x82a978b3f5962a5b0957d9ee9eef472ee55b42f1"
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -19,7 +19,7 @@
|
|||||||
use std::sync::atomic::{AtomicUsize, Ordering as AtomicOrdering};
|
use std::sync::atomic::{AtomicUsize, Ordering as AtomicOrdering};
|
||||||
use std::sync::Weak;
|
use std::sync::Weak;
|
||||||
use common::*;
|
use common::*;
|
||||||
use ethkey::{recover, public_to_address};
|
use ethkey::verify_address;
|
||||||
use rlp::{UntrustedRlp, View, encode, decode};
|
use rlp::{UntrustedRlp, View, encode, decode};
|
||||||
use account_provider::AccountProvider;
|
use account_provider::AccountProvider;
|
||||||
use block::*;
|
use block::*;
|
||||||
@ -108,6 +108,7 @@ impl IoHandler<BlockArrived> for TransitionHandler {
|
|||||||
|
|
||||||
fn timeout(&self, io: &IoContext<BlockArrived>, timer: TimerToken) {
|
fn timeout(&self, io: &IoContext<BlockArrived>, timer: TimerToken) {
|
||||||
if timer == ENGINE_TIMEOUT_TOKEN {
|
if timer == ENGINE_TIMEOUT_TOKEN {
|
||||||
|
println!("timeout");
|
||||||
if let Some(engine) = self.engine.upgrade() {
|
if let Some(engine) = self.engine.upgrade() {
|
||||||
engine.step.fetch_add(1, AtomicOrdering::Relaxed);
|
engine.step.fetch_add(1, AtomicOrdering::Relaxed);
|
||||||
io.register_timer_once(ENGINE_TIMEOUT_TOKEN, engine.our_params.step_duration).expect("Failed to restart consensus step timer.")
|
io.register_timer_once(ENGINE_TIMEOUT_TOKEN, engine.our_params.step_duration).expect("Failed to restart consensus step timer.")
|
||||||
@ -163,12 +164,11 @@ 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, accounts: Option<&AccountProvider>) -> Option<Vec<Bytes>> {
|
||||||
if self.is_proposer(block.header().author()) {
|
let header = block.header();
|
||||||
|
if self.is_proposer(header.author()) {
|
||||||
if let Some(ap) = accounts {
|
if let Some(ap) = accounts {
|
||||||
let header = block.header();
|
// Account should be permanently unlocked, otherwise sealing will fail.
|
||||||
let message = header.bare_hash();
|
if let Ok(signature) = ap.sign(*header.author(), header.bare_hash()) {
|
||||||
// Account should be pernamently unlocked, otherwise sealing will fail.
|
|
||||||
if let Ok(signature) = ap.sign(*header.author(), message) {
|
|
||||||
return Some(vec![encode(&(&*signature as &[u8])).to_vec()]);
|
return Some(vec![encode(&(&*signature as &[u8])).to_vec()]);
|
||||||
} else {
|
} else {
|
||||||
trace!(target: "authorityround", "generate_seal: FAIL: accounts secret key unavailable");
|
trace!(target: "authorityround", "generate_seal: FAIL: accounts secret key unavailable");
|
||||||
@ -181,7 +181,7 @@ impl Engine for AuthorityRound {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Check the number of seal fields.
|
/// Check the number of seal fields.
|
||||||
fn verify_block_basic(&self, header: &Header, _block: Option<&[u8]>) -> result::Result<(), Error> {
|
fn verify_block_basic(&self, header: &Header, _block: Option<&[u8]>) -> Result<(), Error> {
|
||||||
if header.seal().len() != self.seal_fields() {
|
if header.seal().len() != self.seal_fields() {
|
||||||
return Err(From::from(BlockError::InvalidSealArity(
|
return Err(From::from(BlockError::InvalidSealArity(
|
||||||
Mismatch { expected: self.seal_fields(), found: header.seal().len() }
|
Mismatch { expected: self.seal_fields(), found: header.seal().len() }
|
||||||
@ -191,17 +191,16 @@ impl Engine for AuthorityRound {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Check if the signature belongs to the correct proposer.
|
/// Check if the signature belongs to the correct proposer.
|
||||||
fn verify_block_unordered(&self, header: &Header, _block: Option<&[u8]>) -> result::Result<(), Error> {
|
fn verify_block_unordered(&self, header: &Header, _block: Option<&[u8]>) -> Result<(), Error> {
|
||||||
let sig = try!(UntrustedRlp::new(&header.seal()[0]).as_val::<H520>());
|
let sig = try!(UntrustedRlp::new(&header.seal()[0]).as_val::<H520>());
|
||||||
let signer = public_to_address(&try!(recover(&sig.into(), &header.bare_hash())));
|
if try!(verify_address(self.proposer(), &sig.into(), &header.bare_hash())) {
|
||||||
if self.is_proposer(&signer) {
|
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
try!(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<(), Error> {
|
||||||
// Don't calculate difficulty for genesis blocks.
|
// Don't calculate difficulty for genesis blocks.
|
||||||
if header.number() == 0 {
|
if header.number() == 0 {
|
||||||
return Err(From::from(BlockError::RidiculousNumber(OutOfBounds { min: Some(1), max: None, found: header.number() })));
|
return Err(From::from(BlockError::RidiculousNumber(OutOfBounds { min: Some(1), max: None, found: header.number() })));
|
||||||
@ -220,7 +219,7 @@ impl Engine for AuthorityRound {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn verify_transaction_basic(&self, t: &SignedTransaction, _header: &Header) -> result::Result<(), Error> {
|
fn verify_transaction_basic(&self, t: &SignedTransaction, _header: &Header) -> Result<(), Error> {
|
||||||
try!(t.check_low_s());
|
try!(t.check_low_s());
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -245,6 +244,8 @@ mod tests {
|
|||||||
use tests::helpers::*;
|
use tests::helpers::*;
|
||||||
use account_provider::AccountProvider;
|
use account_provider::AccountProvider;
|
||||||
use spec::Spec;
|
use spec::Spec;
|
||||||
|
use std::thread::sleep;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
/// Create a new test chain spec with `AuthorityRound` consensus engine.
|
/// Create a new test chain spec with `AuthorityRound` consensus engine.
|
||||||
fn new_test_authority() -> Spec {
|
fn new_test_authority() -> Spec {
|
||||||
@ -276,7 +277,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn can_do_seal_verification_fail() {
|
fn verification_fails_on_short_seal() {
|
||||||
let engine = new_test_authority().engine;
|
let engine = new_test_authority().engine;
|
||||||
let header: Header = Header::default();
|
let header: Header = Header::default();
|
||||||
|
|
||||||
@ -302,8 +303,8 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn can_generate_seal() {
|
fn can_generate_seal() {
|
||||||
let tap = AccountProvider::transient_provider();
|
let tap = AccountProvider::transient_provider();
|
||||||
let addr = tap.insert_account("".sha3(), "").unwrap();
|
let addr = tap.insert_account("1".sha3(), "1").unwrap();
|
||||||
tap.unlock_account_permanently(addr, "".into()).unwrap();
|
tap.unlock_account_permanently(addr, "1".into()).unwrap();
|
||||||
|
|
||||||
let spec = new_test_authority();
|
let spec = new_test_authority();
|
||||||
let engine = &*spec.engine;
|
let engine = &*spec.engine;
|
||||||
@ -317,4 +318,30 @@ mod tests {
|
|||||||
let seal = engine.generate_seal(b.block(), Some(&tap)).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());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn proposer_switching() {
|
||||||
|
let engine = new_test_authority().engine;
|
||||||
|
let mut header: Header = Header::default();
|
||||||
|
let tap = AccountProvider::transient_provider();
|
||||||
|
let addr = tap.insert_account("0".sha3(), "0").unwrap();
|
||||||
|
|
||||||
|
header.set_author(addr);
|
||||||
|
|
||||||
|
let signature = tap.sign_with_password(addr, "0".into(), header.bare_hash()).unwrap();
|
||||||
|
header.set_seal(vec![encode(&(&*signature as &[u8])).to_vec()]);
|
||||||
|
|
||||||
|
// Wrong step.
|
||||||
|
assert!(engine.verify_block_unordered(&header, None).is_err());
|
||||||
|
|
||||||
|
sleep(Duration::from_millis(1000));
|
||||||
|
|
||||||
|
// Right step.
|
||||||
|
assert!(engine.verify_block_unordered(&header, None).is_ok());
|
||||||
|
|
||||||
|
sleep(Duration::from_millis(1000));
|
||||||
|
|
||||||
|
// Wrong step.
|
||||||
|
assert!(engine.verify_block_unordered(&header, None).is_err());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -181,7 +181,7 @@ mod tests {
|
|||||||
|
|
||||||
/// Create a new test chain spec with `BasicAuthority` consensus engine.
|
/// Create a new test chain spec with `BasicAuthority` consensus engine.
|
||||||
fn new_test_authority() -> Spec {
|
fn new_test_authority() -> Spec {
|
||||||
let bytes: &[u8] = include_bytes!("../../res/test_authority.json");
|
let bytes: &[u8] = include_bytes!("../../res/basic_authority.json");
|
||||||
Spec::load(bytes).expect("invalid chain spec")
|
Spec::load(bytes).expect("invalid chain spec")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,7 +42,7 @@ pub struct AuthorityRound {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use serde_json;
|
use serde_json;
|
||||||
use spec::basic_authority::AuthorityRound;
|
use spec::authority_round::AuthorityRound;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn basic_authority_deserialization() {
|
fn basic_authority_deserialization() {
|
||||||
|
Loading…
Reference in New Issue
Block a user