seal checks
This commit is contained in:
parent
38f25fc195
commit
8f37807d4b
@ -211,13 +211,15 @@ impl Tendermint {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Round proposer switching.
|
/// Round proposer switching.
|
||||||
fn is_proposer(&self, address: &Address) -> bool {
|
fn is_proposer(&self, address: &Address) -> Result<(), BlockError> {
|
||||||
let ref p = self.our_params;
|
let ref p = self.our_params;
|
||||||
let proposer_nonce = self.proposer_nonce.load(AtomicOrdering::SeqCst);
|
let proposer_nonce = self.proposer_nonce.load(AtomicOrdering::SeqCst);
|
||||||
let proposer = p.authorities.get(proposer_nonce % p.authority_n).expect("There are authority_n authorities; taking number modulo authority_n gives number in authority_n range; qed");
|
let proposer = p.authorities.get(proposer_nonce % p.authority_n).expect("There are authority_n authorities; taking number modulo authority_n gives number in authority_n range; qed");
|
||||||
println!("{:?}", &proposer);
|
if proposer == address {
|
||||||
println!("{:?}", &address);
|
Ok(())
|
||||||
proposer == address
|
} else {
|
||||||
|
Err(BlockError::NotProposer(Mismatch { expected: proposer.clone(), found: address.clone() }))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_height(&self, message: &ConsensusMessage) -> bool {
|
fn is_height(&self, message: &ConsensusMessage) -> bool {
|
||||||
@ -310,7 +312,7 @@ impl Engine for Tendermint {
|
|||||||
|
|
||||||
/// Round proposer switching.
|
/// Round proposer switching.
|
||||||
fn is_sealer(&self, address: &Address) -> Option<bool> {
|
fn is_sealer(&self, address: &Address) -> Option<bool> {
|
||||||
Some(self.is_proposer(address))
|
Some(self.is_proposer(address).is_ok())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Attempt to seal the block internally using all available signatures.
|
/// Attempt to seal the block internally using all available signatures.
|
||||||
@ -318,6 +320,7 @@ impl Engine for Tendermint {
|
|||||||
if let Some(ref ap) = *self.account_provider.lock() {
|
if let Some(ref ap) = *self.account_provider.lock() {
|
||||||
let header = block.header();
|
let header = block.header();
|
||||||
let author = header.author();
|
let author = header.author();
|
||||||
|
println!("author: {:?}", author);
|
||||||
let vote_info = message_info_rlp(header.number() as Height, self.round.load(AtomicOrdering::SeqCst), Step::Propose, Some(header.bare_hash()));
|
let vote_info = message_info_rlp(header.number() as Height, self.round.load(AtomicOrdering::SeqCst), Step::Propose, Some(header.bare_hash()));
|
||||||
if let Ok(signature) = ap.sign(*author, None, vote_info.sha3()) {
|
if let Ok(signature) = ap.sign(*author, None, vote_info.sha3()) {
|
||||||
*self.proposal.write() = Some(header.bare_hash());
|
*self.proposal.write() = Some(header.bare_hash());
|
||||||
@ -341,7 +344,7 @@ impl Engine for Tendermint {
|
|||||||
let sender = public_to_address(&try!(recover(&message.signature.into(), &try!(rlp.at(1)).as_raw().sha3())));
|
let sender = public_to_address(&try!(recover(&message.signature.into(), &try!(rlp.at(1)).as_raw().sha3())));
|
||||||
// TODO: Do not admit old messages.
|
// TODO: Do not admit old messages.
|
||||||
if !self.is_authority(&sender) {
|
if !self.is_authority(&sender) {
|
||||||
try!(Err(BlockError::InvalidSeal));
|
try!(Err(BlockError::NotAuthorized(sender)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if the message is known.
|
// Check if the message is known.
|
||||||
@ -403,17 +406,22 @@ impl Engine for Tendermint {
|
|||||||
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 proposal = try!(ConsensusMessage::new_proposal(header));
|
let proposal = try!(ConsensusMessage::new_proposal(header));
|
||||||
let proposer = try!(proposal.verify());
|
let proposer = try!(proposal.verify());
|
||||||
if !self.is_proposer(&proposer) {
|
try!(self.is_proposer(&proposer));
|
||||||
try!(Err(BlockError::InvalidSeal))
|
|
||||||
}
|
|
||||||
self.votes.vote(proposal, proposer);
|
self.votes.vote(proposal, proposer);
|
||||||
let block_info_hash = try!(message_info_rlp_from_header(header)).sha3();
|
let block_info_hash = try!(message_info_rlp_from_header(header)).sha3();
|
||||||
|
|
||||||
|
let mut signature_count = 0;
|
||||||
for rlp in UntrustedRlp::new(&header.seal()[2]).iter() {
|
for rlp in UntrustedRlp::new(&header.seal()[2]).iter() {
|
||||||
let signature: H520 = try!(rlp.as_val());
|
let signature: H520 = try!(rlp.as_val());
|
||||||
let address = public_to_address(&try!(recover(&signature.into(), &block_info_hash)));
|
let address = public_to_address(&try!(recover(&signature.into(), &block_info_hash)));
|
||||||
if !self.our_params.authorities.contains(&address) {
|
if !self.our_params.authorities.contains(&address) {
|
||||||
try!(Err(BlockError::InvalidSeal))
|
try!(Err(BlockError::NotAuthorized(address)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
signature_count += 1;
|
||||||
|
}
|
||||||
|
if signature_count > self.our_params.authority_n {
|
||||||
|
try!(Err(BlockError::InvalidSealArity(Mismatch { expected: self.our_params.authority_n, found: signature_count })))
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -478,6 +486,7 @@ mod tests {
|
|||||||
use super::params::TendermintParams;
|
use super::params::TendermintParams;
|
||||||
use super::message::*;
|
use super::message::*;
|
||||||
|
|
||||||
|
/// Accounts inserted with "1" and "2" are authorities. First proposer is "0".
|
||||||
fn setup() -> (Spec, Arc<AccountProvider>) {
|
fn setup() -> (Spec, Arc<AccountProvider>) {
|
||||||
let tap = Arc::new(AccountProvider::transient_provider());
|
let tap = Arc::new(AccountProvider::transient_provider());
|
||||||
let spec = Spec::new_test_tendermint();
|
let spec = Spec::new_test_tendermint();
|
||||||
@ -500,6 +509,7 @@ mod tests {
|
|||||||
|
|
||||||
fn proposal_seal(tap: &Arc<AccountProvider>, header: &Header, round: Round) -> Vec<Bytes> {
|
fn proposal_seal(tap: &Arc<AccountProvider>, header: &Header, round: Round) -> Vec<Bytes> {
|
||||||
let author = header.author();
|
let author = header.author();
|
||||||
|
println!("author: {:?}", author);
|
||||||
let vote_info = message_info_rlp(header.number() as Height, round, Step::Propose, Some(header.bare_hash()));
|
let vote_info = message_info_rlp(header.number() as Height, round, Step::Propose, Some(header.bare_hash()));
|
||||||
let signature = tap.sign(*author, None, vote_info.sha3()).unwrap();
|
let signature = tap.sign(*author, None, vote_info.sha3()).unwrap();
|
||||||
vec![
|
vec![
|
||||||
@ -545,7 +555,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn verification_fails_on_short_seal() {
|
fn verification_fails_on_short_seal() {
|
||||||
let engine = Spec::new_test_tendermint().engine;
|
let engine = Spec::new_test_tendermint().engine;
|
||||||
let header: Header = Header::default();
|
let header = Header::default();
|
||||||
|
|
||||||
let verify_result = engine.verify_block_basic(&header, None);
|
let verify_result = engine.verify_block_basic(&header, None);
|
||||||
|
|
||||||
@ -558,16 +568,17 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn allows_correct_proposer() {
|
fn allows_correct_proposer() {
|
||||||
::env_logger::init().unwrap();
|
|
||||||
let (spec, tap) = setup();
|
let (spec, tap) = setup();
|
||||||
let engine = spec.engine;
|
let engine = spec.engine;
|
||||||
|
|
||||||
let mut header = Header::default();
|
let mut header = Header::default();
|
||||||
let validator = insert_and_unlock(&tap, "0");
|
let validator = insert_and_unlock(&tap, "0");
|
||||||
|
println!("validator: {:?}", &validator);
|
||||||
header.set_author(validator);
|
header.set_author(validator);
|
||||||
let seal = proposal_seal(&tap, &header, 0);
|
let seal = proposal_seal(&tap, &header, 0);
|
||||||
header.set_seal(seal);
|
header.set_seal(seal);
|
||||||
// Good proposer.
|
// Good proposer.
|
||||||
|
println!("{:?}", engine.verify_block_unordered(&header, None));
|
||||||
assert!(engine.verify_block_unordered(&header, None).is_ok());
|
assert!(engine.verify_block_unordered(&header, None).is_ok());
|
||||||
|
|
||||||
let mut header = Header::default();
|
let mut header = Header::default();
|
||||||
@ -576,75 +587,64 @@ mod tests {
|
|||||||
let seal = proposal_seal(&tap, &header, 0);
|
let seal = proposal_seal(&tap, &header, 0);
|
||||||
header.set_seal(seal);
|
header.set_seal(seal);
|
||||||
// Bad proposer.
|
// Bad proposer.
|
||||||
assert!(engine.verify_block_unordered(&header, None).is_err());
|
match engine.verify_block_unordered(&header, None) {
|
||||||
}
|
Err(Error::Block(BlockError::NotProposer(_))) => {},
|
||||||
|
_ => panic!(),
|
||||||
#[test]
|
|
||||||
fn verification_fails_on_wrong_signatures() {
|
|
||||||
let (spec, tap) = setup();
|
|
||||||
let engine = spec.engine;
|
|
||||||
let mut header = Header::default();
|
|
||||||
|
|
||||||
|
|
||||||
let v1 = tap.insert_account("0".sha3(), "0").unwrap();
|
|
||||||
|
|
||||||
header.set_author(v1);
|
|
||||||
let mut seal = proposal_seal(&tap, &header, 0);
|
|
||||||
|
|
||||||
header.set_seal(seal.clone());
|
|
||||||
|
|
||||||
// Not enough signatures.
|
|
||||||
assert!(engine.verify_block_unordered(&header, None).is_err());
|
|
||||||
|
|
||||||
let v2 = tap.insert_account("101".sha3(), "101").unwrap();
|
|
||||||
let sig2 = tap.sign(v2, Some("101".into()), header.bare_hash()).unwrap();
|
|
||||||
seal.push(::rlp::encode(&(&*sig2 as &[u8])).to_vec());
|
|
||||||
|
|
||||||
header.set_seal(seal);
|
|
||||||
|
|
||||||
// Enough signatures.
|
|
||||||
assert!(engine.verify_block_unordered(&header, None).is_ok());
|
|
||||||
|
|
||||||
let verify_result = engine.verify_block_unordered(&header, None);
|
|
||||||
|
|
||||||
// But wrong signatures.
|
|
||||||
match verify_result {
|
|
||||||
Err(Error::Block(BlockError::InvalidSeal)) => (),
|
|
||||||
Err(_) => panic!("should be block seal-arity mismatch error (got {:?})", verify_result),
|
|
||||||
_ => panic!("Should be error, got Ok"),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn seal_with_enough_signatures_is_ok() {
|
fn seal_signatures_checking() {
|
||||||
let (spec, tap) = setup();
|
let (spec, tap) = setup();
|
||||||
let engine = spec.engine;
|
let engine = spec.engine;
|
||||||
let mut header = Header::default();
|
|
||||||
|
|
||||||
let seal = proposal_seal(&tap, &header, 0);
|
let mut header = Header::default();
|
||||||
|
let proposer = insert_and_unlock(&tap, "0");
|
||||||
|
header.set_author(proposer);
|
||||||
|
let mut seal = proposal_seal(&tap, &header, 0);
|
||||||
|
|
||||||
|
let voter = insert_and_unlock(&tap, "1");
|
||||||
|
let vote_info = message_info_rlp(0, 0, Step::Prevote, Some(header.bare_hash()));
|
||||||
|
let signature = tap.sign(voter, None, vote_info.sha3()).unwrap();
|
||||||
|
|
||||||
|
seal[2] = ::rlp::encode(&vec![H520::from(signature)]).to_vec();
|
||||||
|
|
||||||
|
header.set_seal(seal.clone());
|
||||||
|
|
||||||
|
// One good signature.
|
||||||
|
assert!(engine.verify_block_unordered(&header, None).is_ok());
|
||||||
|
|
||||||
|
let bad_voter = insert_and_unlock(&tap, "101");
|
||||||
|
let bad_signature = tap.sign(bad_voter, None, vote_info.sha3()).unwrap();
|
||||||
|
seal.push(::rlp::encode(&(&*bad_signature as &[u8])).to_vec());
|
||||||
|
|
||||||
header.set_seal(seal);
|
header.set_seal(seal);
|
||||||
|
|
||||||
// Enough signatures.
|
// One good and one bad signature.
|
||||||
assert!(engine.verify_block_basic(&header, None).is_ok());
|
match engine.verify_block_unordered(&header, None) {
|
||||||
|
Err(Error::Block(BlockError::NotAuthorized(_))) => {},
|
||||||
// And they are ok.
|
_ => panic!(),
|
||||||
assert!(engine.verify_block_unordered(&header, None).is_ok());
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn can_generate_seal() {
|
fn can_generate_seal() {
|
||||||
let (spec, _) = setup();
|
let (spec, tap) = setup();
|
||||||
|
|
||||||
let genesis_header = spec.genesis_header();
|
let genesis_header = spec.genesis_header();
|
||||||
let mut db_result = get_temp_state_db();
|
let mut db_result = get_temp_state_db();
|
||||||
let mut db = db_result.take();
|
let mut db = db_result.take();
|
||||||
spec.ensure_db_good(&mut db).unwrap();
|
spec.ensure_db_good(&mut db).unwrap();
|
||||||
let last_hashes = Arc::new(vec![genesis_header.hash()]);
|
let last_hashes = Arc::new(vec![genesis_header.hash()]);
|
||||||
let b = OpenBlock::new(spec.engine.as_ref(), Default::default(), false, db, &genesis_header, last_hashes, Address::default(), (3141562.into(), 31415620.into()), vec![]).unwrap();
|
let validator = insert_and_unlock(&tap, "0");
|
||||||
|
let b = OpenBlock::new(spec.engine.as_ref(), Default::default(), false, db, &genesis_header, last_hashes, validator, (3141562.into(), 31415620.into()), vec![]).unwrap();
|
||||||
let b = b.close_and_lock();
|
let b = b.close_and_lock();
|
||||||
|
|
||||||
let seal = spec.engine.generate_seal(b.block()).unwrap();
|
let seal = spec.engine.generate_seal(b.block()).unwrap();
|
||||||
assert!(b.try_seal(spec.engine.as_ref(), seal).is_ok());
|
println!("{:?}", seal.clone());
|
||||||
|
if let Err(e) = b.try_seal(spec.engine.as_ref(), seal) {
|
||||||
|
println!("{:?}", e.0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
Loading…
Reference in New Issue
Block a user