Skip to content

Commit

Permalink
last tests
Browse files Browse the repository at this point in the history
  • Loading branch information
brunoffranca committed Oct 21, 2024
1 parent 1252631 commit d5f8531
Show file tree
Hide file tree
Showing 8 changed files with 420 additions and 188 deletions.
2 changes: 1 addition & 1 deletion node/libs/roles/src/validator/messages/genesis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ impl fmt::Debug for GenesisHash {

/// Genesis with cached hash.
#[derive(Clone)]
pub struct Genesis(GenesisRaw, GenesisHash);
pub struct Genesis(pub(crate) GenesisRaw, pub(crate) GenesisHash);

impl std::ops::Deref for Genesis {
type Target = GenesisRaw;
Expand Down
11 changes: 2 additions & 9 deletions node/libs/roles/src/validator/messages/replica_commit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,6 @@ impl ReplicaCommit {
.verify(genesis)
.map_err(ReplicaCommitVerifyError::BadView)?;

if self.proposal.number < genesis.first_block {
return Err(ReplicaCommitVerifyError::BadBlockNumber);
}

Ok(())
}
}
Expand All @@ -31,9 +27,6 @@ pub enum ReplicaCommitVerifyError {
/// Invalid view.
#[error("view: {0:#}")]
BadView(anyhow::Error),
/// Bad block number.
#[error("block number < first block")]
BadBlockNumber,
}

/// A Commit Quorum Certificate. It is an aggregate of signed ReplicaCommit messages.
Expand Down Expand Up @@ -124,7 +117,7 @@ impl CommitQC {
let weight = genesis.validators.weight(&self.signers);
let threshold = genesis.validators.quorum_threshold();
if weight < threshold {
return Err(CommitQCVerifyError::NotEnoughSigners {
return Err(CommitQCVerifyError::NotEnoughWeight {
got: weight,
want: threshold,
});
Expand Down Expand Up @@ -181,7 +174,7 @@ pub enum CommitQCVerifyError {
BadSignersSet,
/// Weight not reached.
#[error("Signers have not reached threshold weight: got {got}, want {want}")]
NotEnoughSigners {
NotEnoughWeight {
/// Got weight.
got: u64,
/// Want weight.
Expand Down
72 changes: 30 additions & 42 deletions node/libs/roles/src/validator/messages/replica_timeout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,22 +21,16 @@ impl ReplicaTimeout {
pub fn verify(&self, genesis: &Genesis) -> Result<(), ReplicaTimeoutVerifyError> {
self.view
.verify(genesis)
.map_err(ReplicaTimeoutVerifyError::View)?;
.map_err(ReplicaTimeoutVerifyError::BadView)?;

if let Some(v) = &self.high_vote {
if self.view.number <= v.view.number {
return Err(ReplicaTimeoutVerifyError::HighVoteFutureView);
}
v.verify(genesis)
.map_err(ReplicaTimeoutVerifyError::HighVote)?;
.map_err(ReplicaTimeoutVerifyError::InvalidHighVote)?;
}

if let Some(qc) = &self.high_qc {
if self.view.number <= qc.view().number {
return Err(ReplicaTimeoutVerifyError::HighQCFutureView);
}
qc.verify(genesis)
.map_err(ReplicaTimeoutVerifyError::HighQC)?;
.map_err(ReplicaTimeoutVerifyError::InvalidHighQC)?;
}

Ok(())
Expand All @@ -48,19 +42,13 @@ impl ReplicaTimeout {
pub enum ReplicaTimeoutVerifyError {
/// View.
#[error("view: {0:#}")]
View(anyhow::Error),
/// FutureHighVoteView.
#[error("high vote from the future")]
HighVoteFutureView,
/// FutureHighQCView.
#[error("high qc from the future")]
HighQCFutureView,
/// HighVote.
#[error("high_vote: {0:#}")]
HighVote(ReplicaCommitVerifyError),
/// HighQC.
#[error("high_qc: {0:#}")]
HighQC(CommitQCVerifyError),
BadView(anyhow::Error),
/// Invalid High Vote.
#[error("invalid high_vote: {0:#}")]
InvalidHighVote(ReplicaCommitVerifyError),
/// Invalid High QC.
#[error("invalid high_qc: {0:#}")]
InvalidHighQC(CommitQCVerifyError),
}

/// A quorum certificate of ReplicaTimeout messages. Since not all ReplicaTimeout messages are
Expand Down Expand Up @@ -129,7 +117,7 @@ impl TimeoutQC {
});
};

// Check if already have a message from the same signer.
// Check if we already have a message from the same signer.
if self.map.values().any(|s| s.0[i]) {
return Err(TimeoutQCAddError::DuplicateSigner {
signer: Box::new(msg.key.clone()),
Expand Down Expand Up @@ -164,29 +152,23 @@ impl TimeoutQC {
pub fn verify(&self, genesis: &Genesis) -> Result<(), TimeoutQCVerifyError> {
self.view
.verify(genesis)
.map_err(TimeoutQCVerifyError::View)?;
.map_err(TimeoutQCVerifyError::BadView)?;

let mut sum = Signers::new(genesis.validators.len());

// Check the ReplicaTimeout messages.
for (i, (msg, signers)) in self.map.iter().enumerate() {
if msg.view != self.view {
return Err(TimeoutQCVerifyError::InconsistentViews);
return Err(TimeoutQCVerifyError::InconsistentView(i));
}
if signers.len() != sum.len() {
return Err(TimeoutQCVerifyError::BadFormat(anyhow::format_err!(
"msg[{i}].signers has wrong length"
)));
return Err(TimeoutQCVerifyError::WrongSignersLength(i));
}
if signers.is_empty() {
return Err(TimeoutQCVerifyError::BadFormat(anyhow::format_err!(
"msg[{i}] has no signers assigned"
)));
return Err(TimeoutQCVerifyError::NoSignersAssigned(i));
}
if !(&sum & signers).is_empty() {
return Err(TimeoutQCVerifyError::BadFormat(anyhow::format_err!(
"overlapping signature sets for different messages"
)));
return Err(TimeoutQCVerifyError::OverlappingSignatureSet(i));
}
msg.verify(genesis)
.map_err(|err| TimeoutQCVerifyError::InvalidMessage(i, err))?;
Expand All @@ -198,7 +180,7 @@ impl TimeoutQC {
let weight = genesis.validators.weight(&sum);
let threshold = genesis.validators.quorum_threshold();
if weight < threshold {
return Err(TimeoutQCVerifyError::NotEnoughSigners {
return Err(TimeoutQCVerifyError::NotEnoughWeight {
got: weight,
want: threshold,
});
Expand Down Expand Up @@ -261,19 +243,25 @@ pub enum TimeoutQCAddError {
pub enum TimeoutQCVerifyError {
/// Bad view.
#[error("Bad view: {0:#}")]
View(anyhow::Error),
BadView(anyhow::Error),
/// Inconsistent views.
#[error("Inconsistent views of signed messages")]
InconsistentViews,
#[error("Message with inconsistent view: number [{0}]")]
InconsistentView(usize),
/// Invalid message.
#[error("Invalid message: number [{0}], {1:#}")]
InvalidMessage(usize, ReplicaTimeoutVerifyError),
/// Bad message format.
#[error(transparent)]
BadFormat(anyhow::Error),
/// Wrong signers length.
#[error("Message with wrong signers length: number [{0}]")]
WrongSignersLength(usize),
/// No signers assigned.
#[error("Message with no signers assigned: number [{0}]")]
NoSignersAssigned(usize),
/// Overlapping signature sets.
#[error("Message with overlapping signature set: number [{0}]")]
OverlappingSignatureSet(usize),
/// Weight not reached.
#[error("Signers have not reached threshold weight: got {got}, want {want}")]
NotEnoughSigners {
NotEnoughWeight {
/// Got weight.
got: u64,
/// Want weight.
Expand Down
47 changes: 47 additions & 0 deletions node/libs/roles/src/validator/messages/tests/leader_proposal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,3 +95,50 @@ fn test_leader_proposal_verify() {
Err(LeaderProposalVerifyError::NewProposalWhenPreviousNotFinalized)
);
}

#[test]
fn test_justification_get_implied_block() {
let ctx = ctx::test_root(&ctx::RealClock);
let rng = &mut ctx.rng();
let mut setup = Setup::new(rng, 6);
setup.push_blocks(rng, 3);

let payload: Payload = rng.gen();
let block_header = BlockHeader {
number: setup.next(),
payload: payload.hash(),
};

// Justification with a commit QC
let commit_qc = match setup.blocks.last().unwrap() {
Block::Final(block) => block.justification.clone(),
_ => unreachable!(),
};
let justification = ProposalJustification::Commit(commit_qc);
let proposal = LeaderProposal {
proposal: block_header,
proposal_payload: Some(payload.clone()),
justification,
};

let (implied_block_number, implied_payload) =
proposal.justification.get_implied_block(&setup.genesis);

assert_eq!(implied_block_number, setup.next());
assert!(implied_payload.is_none());

// Justification with a timeout QC
let timeout_qc = setup.make_timeout_qc(rng, ViewNumber(7), Some(&payload));
let justification = ProposalJustification::Timeout(timeout_qc);
let proposal = LeaderProposal {
proposal: block_header,
proposal_payload: None,
justification,
};

let (implied_block_number, implied_payload) =
proposal.justification.get_implied_block(&setup.genesis);

assert_eq!(implied_block_number, setup.next());
assert_eq!(implied_payload, Some(payload.hash()));
}
Loading

0 comments on commit d5f8531

Please sign in to comment.