cometbft_light_client_verifier/operations/
commit_validator.rs

1//! Provides an interface and default implementation for the `CommitValidator` operation
2
3use cometbft::block::CommitSig;
4
5use crate::{
6    errors::VerificationError,
7    types::{SignedHeader, ValidatorSet},
8};
9
10/// Validates the commit associated with a header against a validator set
11pub trait CommitValidator: Send + Sync {
12    /// Perform basic validation
13    fn validate(
14        &self,
15        signed_header: &SignedHeader,
16        validator_set: &ValidatorSet,
17    ) -> Result<(), VerificationError> {
18        let signatures = &signed_header.commit.signatures;
19
20        // Check the the commit contains at least one non-absent signature.
21        // See https://github.com/informalsystems/tendermint-rs/issues/650
22        let has_present_signatures = signatures.iter().any(|cs| !cs.is_absent());
23        if !has_present_signatures {
24            return Err(VerificationError::no_signature_for_commit());
25        }
26
27        // Check that that the number of signatures matches the number of validators.
28        if signatures.len() != validator_set.validators().len() {
29            return Err(VerificationError::mismatch_pre_commit_length(
30                signatures.len(),
31                validator_set.validators().len(),
32            ));
33        }
34
35        Ok(())
36    }
37
38    /// Perform full validation, only necessary if we do full verification (2/3)
39    fn validate_full(
40        &self,
41        signed_header: &SignedHeader,
42        validator_set: &ValidatorSet,
43    ) -> Result<(), VerificationError> {
44        for commit_sig in signed_header.commit.signatures.iter() {
45            let validator_address = match commit_sig {
46                CommitSig::BlockIdFlagAbsent => continue,
47                CommitSig::BlockIdFlagCommit {
48                    validator_address, ..
49                } => validator_address,
50                CommitSig::BlockIdFlagNil {
51                    validator_address, ..
52                } => validator_address,
53            };
54
55            if validator_set.validator(*validator_address).is_none() {
56                return Err(VerificationError::faulty_signer(
57                    *validator_address,
58                    validator_set.clone(),
59                ));
60            }
61        }
62
63        Ok(())
64    }
65}
66
67/// Production-ready implementation of a commit validator.
68#[derive(Copy, Clone, Default, Debug, PartialEq, Eq)]
69pub struct ProdCommitValidator;
70
71impl CommitValidator for ProdCommitValidator {}