fn verify_network_record()

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)
            }
        }
    }