seal checks
This commit is contained in:
parent
38f25fc195
commit
8f37807d4b
@ -211,13 +211,15 @@ impl Tendermint {
|
||||
}
|
||||
|
||||
/// 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 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");
|
||||
println!("{:?}", &proposer);
|
||||
println!("{:?}", &address);
|
||||
proposer == address
|
||||
if proposer == address {
|
||||
Ok(())
|
||||
} else {
|
||||
Err(BlockError::NotProposer(Mismatch { expected: proposer.clone(), found: address.clone() }))
|
||||
}
|
||||
}
|
||||
|
||||
fn is_height(&self, message: &ConsensusMessage) -> bool {
|
||||
@ -310,7 +312,7 @@ impl Engine for Tendermint {
|
||||
|
||||
/// Round proposer switching.
|
||||
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.
|
||||
@ -318,6 +320,7 @@ impl Engine for Tendermint {
|
||||
if let Some(ref ap) = *self.account_provider.lock() {
|
||||
let header = block.header();
|
||||
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()));
|
||||
if let Ok(signature) = ap.sign(*author, None, vote_info.sha3()) {
|
||||
*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())));
|
||||
// TODO: Do not admit old messages.
|
||||
if !self.is_authority(&sender) {
|
||||
try!(Err(BlockError::InvalidSeal));
|
||||
try!(Err(BlockError::NotAuthorized(sender)));
|
||||
}
|
||||
|
||||
// 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> {
|
||||
let proposal = try!(ConsensusMessage::new_proposal(header));
|
||||
let proposer = try!(proposal.verify());
|
||||
if !self.is_proposer(&proposer) {
|
||||
try!(Err(BlockError::InvalidSeal))
|
||||
}
|
||||
try!(self.is_proposer(&proposer));
|
||||
self.votes.vote(proposal, proposer);
|
||||
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() {
|
||||
let signature: H520 = try!(rlp.as_val());
|
||||
let address = public_to_address(&try!(recover(&signature.into(), &block_info_hash)));
|
||||
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(())
|
||||
}
|
||||
@ -478,6 +486,7 @@ mod tests {
|
||||
use super::params::TendermintParams;
|
||||
use super::message::*;
|
||||
|
||||
/// Accounts inserted with "1" and "2" are authorities. First proposer is "0".
|
||||
fn setup() -> (Spec, Arc<AccountProvider>) {
|
||||
let tap = Arc::new(AccountProvider::transient_provider());
|
||||
let spec = Spec::new_test_tendermint();
|
||||
@ -500,6 +509,7 @@ mod tests {
|
||||
|
||||
fn proposal_seal(tap: &Arc<AccountProvider>, header: &Header, round: Round) -> Vec<Bytes> {
|
||||
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 signature = tap.sign(*author, None, vote_info.sha3()).unwrap();
|
||||
vec![
|
||||
@ -545,7 +555,7 @@ mod tests {
|
||||
#[test]
|
||||
fn verification_fails_on_short_seal() {
|
||||
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);
|
||||
|
||||
@ -558,16 +568,17 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn allows_correct_proposer() {
|
||||
::env_logger::init().unwrap();
|
||||
let (spec, tap) = setup();
|
||||
let engine = spec.engine;
|
||||
|
||||
let mut header = Header::default();
|
||||
let validator = insert_and_unlock(&tap, "0");
|
||||
println!("validator: {:?}", &validator);
|
||||
header.set_author(validator);
|
||||
let seal = proposal_seal(&tap, &header, 0);
|
||||
header.set_seal(seal);
|
||||
// Good proposer.
|
||||
println!("{:?}", engine.verify_block_unordered(&header, None));
|
||||
assert!(engine.verify_block_unordered(&header, None).is_ok());
|
||||
|
||||
let mut header = Header::default();
|
||||
@ -576,75 +587,64 @@ mod tests {
|
||||
let seal = proposal_seal(&tap, &header, 0);
|
||||
header.set_seal(seal);
|
||||
// Bad proposer.
|
||||
assert!(engine.verify_block_unordered(&header, None).is_err());
|
||||
}
|
||||
|
||||
#[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"),
|
||||
match engine.verify_block_unordered(&header, None) {
|
||||
Err(Error::Block(BlockError::NotProposer(_))) => {},
|
||||
_ => panic!(),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn seal_with_enough_signatures_is_ok() {
|
||||
fn seal_signatures_checking() {
|
||||
let (spec, tap) = setup();
|
||||
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);
|
||||
|
||||
// Enough signatures.
|
||||
assert!(engine.verify_block_basic(&header, None).is_ok());
|
||||
|
||||
// And they are ok.
|
||||
assert!(engine.verify_block_unordered(&header, None).is_ok());
|
||||
// One good and one bad signature.
|
||||
match engine.verify_block_unordered(&header, None) {
|
||||
Err(Error::Block(BlockError::NotAuthorized(_))) => {},
|
||||
_ => panic!(),
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn can_generate_seal() {
|
||||
let (spec, _) = setup();
|
||||
let (spec, tap) = setup();
|
||||
|
||||
let genesis_header = spec.genesis_header();
|
||||
let mut db_result = get_temp_state_db();
|
||||
let mut db = db_result.take();
|
||||
spec.ensure_db_good(&mut db).unwrap();
|
||||
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 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]
|
||||
|
Loading…
Reference in New Issue
Block a user