in librabft-v2/src/record_store.rs [257:417]
fn verify_network_record(
&self,
context: &Context,
record: &Record<Context>,
) -> Result<Context::HashValue> {
match record {
Record::Block(block) => {
let hash = context.hash(&block.value);
ensure!(
!self.blocks.contains_key(&BlockHash(hash)),
"Block was already inserted."
);
context.verify(block.value.author, hash, block.signature)?;
ensure!(
block.value.previous_quorum_certificate_hash == self.initial_hash
|| self
.quorum_certificates
.contains_key(&block.value.previous_quorum_certificate_hash),
"The previous QC (if any) must be verified first."
);
if self.initial_hash == block.value.previous_quorum_certificate_hash {
ensure!(block.value.round > Round(0), "Rounds must start at 1");
} else {
let previous_qc = self
.quorum_certificate(block.value.previous_quorum_certificate_hash)
.unwrap();
let previous_block =
self.block(previous_qc.value.certified_block_hash).unwrap();
ensure!(
block.value.round > previous_block.value.round,
"Rounds must be increasing"
);
}
Ok(hash)
}
Record::Vote(vote) => {
let hash = context.hash(&vote.value);
ensure!(
vote.value.epoch_id == self.epoch_id,
"Epoch identifier of vote ({:?}) must match the current epoch ({:?}).",
vote.value.epoch_id,
self.epoch_id
);
ensure!(
self.blocks.contains_key(&vote.value.certified_block_hash),
"The certified block hash of a vote must be verified first."
);
ensure!(
self.block(vote.value.certified_block_hash)
.unwrap()
.value
.round
== vote.value.round,
"The round of the vote must match the certified block."
);
ensure!(
self.vote_committed_state(vote.value.certified_block_hash)
== vote.value.committed_state,
"The committed_state value of a vote must follow the commit rule."
);
ensure!(
vote.value.round == self.current_round,
"Only accepting votes for a proposal at the current {:?}. This one was at {:?}",
self.current_round,
vote.value.round
);
ensure!(
!self.current_votes.contains_key(&vote.value.author),
"We insert votes only for authors who haven't voted yet."
);
context.verify(vote.value.author, hash, vote.signature)?;
Ok(hash)
}
Record::QuorumCertificate(qc) => {
let hash = context.hash(&qc.value);
ensure!(
qc.value.epoch_id == self.epoch_id,
"Epoch identifier of QC ({:?}) must match the current epoch ({:?}).",
qc.value.epoch_id,
self.epoch_id
);
ensure!(
!self
.quorum_certificates
.contains_key(&QuorumCertificateHash(hash)),
"QuorumCertificate was already inserted."
);
ensure!(
self.blocks.contains_key(&qc.value.certified_block_hash),
"The certified block hash of a QC must be verified first."
);
ensure!(
self.block(qc.value.certified_block_hash)
.unwrap()
.value
.round
== qc.value.round,
"The round of the QC must match the certified block."
);
ensure!(
qc.value.author
== self
.block(qc.value.certified_block_hash)
.unwrap()
.value
.author,
"QCs must be created by the author of the certified block"
);
ensure!(
self.vote_committed_state(qc.value.certified_block_hash)
== qc.value.committed_state,
"The committed_state value of a QC must follow the commit rule."
);
let mut weight = 0;
for (author, signature) in &qc.value.votes {
let original_vote_hash = context.hash(&Vote_::<Context> {
epoch_id: self.epoch_id,
round: qc.value.round,
certified_block_hash: qc.value.certified_block_hash,
state: qc.value.state.clone(),
committed_state: qc.value.committed_state.clone(),
author: *author,
});
context.verify(*author, original_vote_hash, *signature)?;
weight += self.configuration.weight(author);
}
ensure!(
weight >= self.configuration.quorum_threshold(),
"Votes in QCs must form a quorum"
);
context.verify(qc.value.author, hash, qc.signature)?;
Ok(hash)
}
Record::Timeout(timeout) => {
let hash = context.hash(&timeout.value);
ensure!(
timeout.value.epoch_id == self.epoch_id,
"Epoch identifier of timeout ({:?}) must match the current epoch ({:?}).",
timeout.value.epoch_id,
self.epoch_id
);
ensure!(
timeout.value.highest_certified_block_round
<= self.highest_quorum_certificate_round(),
"Timeouts must refer to a known certified block round."
);
ensure!(
timeout.value.round == self.current_round,
"Accepting only timeouts at the current {:?}. This one was at {:?}",
self.current_round,
timeout.value.round
);
ensure!(
!self.current_timeouts.contains_key(&timeout.value.author),
"A timeout is already known for the same round and the same author"
);
context.verify(timeout.value.author, hash, timeout.signature)?;
Ok(hash)
}
}
}