add proposer step to seal
This commit is contained in:
parent
7f177f27d8
commit
d84f94975f
@ -80,13 +80,17 @@ impl AuthorityRound {
|
|||||||
engine
|
engine
|
||||||
}
|
}
|
||||||
|
|
||||||
fn proposer(&self) -> &Address {
|
fn step(&self) -> usize {
|
||||||
let ref p = self.our_params;
|
self.step.load(AtomicOrdering::SeqCst)
|
||||||
p.authorities.get(self.step.load(AtomicOrdering::Relaxed)%p.authority_n).unwrap()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_proposer(&self, address: &Address) -> bool {
|
fn step_proposer(&self, step: usize) -> &Address {
|
||||||
self.proposer() == address
|
let ref p = self.our_params;
|
||||||
|
p.authorities.get(step%p.authority_n).unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_step_proposer(&self, step: usize, address: &Address) -> bool {
|
||||||
|
self.step_proposer(step) == address
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -110,7 +114,7 @@ impl IoHandler<BlockArrived> for TransitionHandler {
|
|||||||
if timer == ENGINE_TIMEOUT_TOKEN {
|
if timer == ENGINE_TIMEOUT_TOKEN {
|
||||||
debug!(target: "authorityround", "timeout");
|
debug!(target: "authorityround", "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::SeqCst);
|
||||||
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.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -119,7 +123,7 @@ impl IoHandler<BlockArrived> for TransitionHandler {
|
|||||||
fn message(&self, io: &IoContext<BlockArrived>, _net_message: &BlockArrived) {
|
fn message(&self, io: &IoContext<BlockArrived>, _net_message: &BlockArrived) {
|
||||||
if let Some(engine) = self.engine.upgrade() {
|
if let Some(engine) = self.engine.upgrade() {
|
||||||
trace!(target: "authorityround", "Message: {:?}", get_time().sec);
|
trace!(target: "authorityround", "Message: {:?}", get_time().sec);
|
||||||
engine.step.fetch_add(1, AtomicOrdering::Relaxed);
|
engine.step.fetch_add(1, AtomicOrdering::SeqCst);
|
||||||
io.clear_timer(ENGINE_TIMEOUT_TOKEN).expect("Failed to restart consensus step timer.");
|
io.clear_timer(ENGINE_TIMEOUT_TOKEN).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.")
|
io.register_timer_once(ENGINE_TIMEOUT_TOKEN, engine.our_params.step_duration).expect("Failed to restart consensus step timer.")
|
||||||
}
|
}
|
||||||
@ -130,7 +134,7 @@ impl Engine for AuthorityRound {
|
|||||||
fn name(&self) -> &str { "AuthorityRound" }
|
fn name(&self) -> &str { "AuthorityRound" }
|
||||||
fn version(&self) -> SemanticVersion { SemanticVersion::new(1, 0, 0) }
|
fn version(&self) -> SemanticVersion { SemanticVersion::new(1, 0, 0) }
|
||||||
// One field - the proposer signature.
|
// One field - the proposer signature.
|
||||||
fn seal_fields(&self) -> usize { 1 }
|
fn seal_fields(&self) -> usize { 2 }
|
||||||
|
|
||||||
fn params(&self) -> &CommonParams { &self.params }
|
fn params(&self) -> &CommonParams { &self.params }
|
||||||
fn builtins(&self) -> &BTreeMap<Address, Builtin> { &self.builtins }
|
fn builtins(&self) -> &BTreeMap<Address, Builtin> { &self.builtins }
|
||||||
@ -170,11 +174,12 @@ impl Engine for AuthorityRound {
|
|||||||
/// 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>> {
|
||||||
let header = block.header();
|
let header = block.header();
|
||||||
if self.is_proposer(header.author()) {
|
let step = self.step();
|
||||||
|
if self.is_step_proposer(step, header.author()) {
|
||||||
if let Some(ap) = accounts {
|
if let Some(ap) = accounts {
|
||||||
// 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(), header.bare_hash()) {
|
if let Ok(signature) = ap.sign(*header.author(), header.bare_hash()) {
|
||||||
return Some(vec![encode(&(&*signature as &[u8])).to_vec()]);
|
return Some(vec![encode(&step).to_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");
|
||||||
}
|
}
|
||||||
@ -188,19 +193,30 @@ 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<(), 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(
|
trace!(target: "authorityround", "verify_block_basic: wrong number of seal fields");
|
||||||
|
Err(From::from(BlockError::InvalidSealArity(
|
||||||
Mismatch { expected: self.seal_fields(), found: header.seal().len() }
|
Mismatch { expected: self.seal_fields(), found: header.seal().len() }
|
||||||
)));
|
)))
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check if the signature belongs to the correct proposer.
|
/// Check if the signature belongs to the correct proposer.
|
||||||
|
/// TODO: Keep track of BlockNumber to step relationship
|
||||||
fn verify_block_unordered(&self, header: &Header, _block: Option<&[u8]>) -> 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 step = try!(UntrustedRlp::new(&header.seal()[0]).as_val::<usize>());
|
||||||
if try!(verify_address(self.proposer(), &sig.into(), &header.bare_hash())) {
|
if step <= self.step() {
|
||||||
Ok(())
|
let sig = try!(UntrustedRlp::new(&header.seal()[1]).as_val::<H520>());
|
||||||
|
let ok_sig = try!(verify_address(self.step_proposer(step), &sig.into(), &header.bare_hash()));
|
||||||
|
if ok_sig {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
trace!(target: "authorityround", "verify_block_unordered: invalid seal signature");
|
||||||
|
try!(Err(BlockError::InvalidSeal))
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
|
trace!(target: "authorityround", "verify_block_unordered: block from the future");
|
||||||
try!(Err(BlockError::InvalidSeal))
|
try!(Err(BlockError::InvalidSeal))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -320,7 +336,6 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn proposer_switching() {
|
fn proposer_switching() {
|
||||||
let engine = Spec::new_test_round().engine;
|
|
||||||
let mut header: Header = Header::default();
|
let mut header: Header = Header::default();
|
||||||
let tap = AccountProvider::transient_provider();
|
let tap = AccountProvider::transient_provider();
|
||||||
let addr = tap.insert_account("0".sha3(), "0").unwrap();
|
let addr = tap.insert_account("0".sha3(), "0").unwrap();
|
||||||
@ -328,19 +343,21 @@ mod tests {
|
|||||||
header.set_author(addr);
|
header.set_author(addr);
|
||||||
|
|
||||||
let signature = tap.sign_with_password(addr, "0".into(), header.bare_hash()).unwrap();
|
let signature = tap.sign_with_password(addr, "0".into(), header.bare_hash()).unwrap();
|
||||||
header.set_seal(vec![encode(&(&*signature as &[u8])).to_vec()]);
|
header.set_seal(vec![vec![1u8], encode(&(&*signature as &[u8])).to_vec()]);
|
||||||
|
|
||||||
// Wrong step.
|
let engine = Spec::new_test_round().engine;
|
||||||
assert!(engine.verify_block_unordered(&header, None).is_err());
|
|
||||||
|
// Too early.
|
||||||
|
assert!(engine.verify_block_seal(&header).is_err());
|
||||||
|
|
||||||
sleep(Duration::from_millis(1000));
|
sleep(Duration::from_millis(1000));
|
||||||
|
|
||||||
// Right step.
|
// Right step.
|
||||||
assert!(engine.verify_block_unordered(&header, None).is_ok());
|
assert!(engine.verify_block_seal(&header).is_ok());
|
||||||
|
|
||||||
sleep(Duration::from_millis(1000));
|
sleep(Duration::from_millis(1000));
|
||||||
|
|
||||||
// Wrong step.
|
// Future step.
|
||||||
assert!(engine.verify_block_unordered(&header, None).is_err());
|
assert!(engine.verify_block_seal(&header).is_ok());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@ use std::time::Duration;
|
|||||||
use ethcore::client::BlockChainClient;
|
use ethcore::client::BlockChainClient;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn issue_tx() {
|
fn 2_peer_1_tx_seal() {
|
||||||
::env_logger::init().ok();
|
::env_logger::init().ok();
|
||||||
let mut net = MockNet::new_with_spec(2, vec!["1".sha3()], &Spec::new_test_round);
|
let mut net = MockNet::new_with_spec(2, vec!["1".sha3()], &Spec::new_test_round);
|
||||||
net.peer(1).issue_rand_tx();
|
net.peer(1).issue_rand_tx();
|
||||||
|
Loading…
Reference in New Issue
Block a user