cometbft_light_client_verifier/
errors.rs

1//! Errors which may be raised when verifying a `LightBlock`
2
3use core::time::Duration;
4
5use cometbft::{account::Id, Error as CometbftError};
6use flex_error::define_error;
7use serde::{Deserialize, Serialize};
8
9use crate::{
10    operations::voting_power::VotingPowerTally,
11    prelude::*,
12    types::{Hash, Height, Time, Validator, ValidatorAddress, ValidatorSet},
13};
14
15define_error! {
16    #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
17    VerificationError {
18        Cometbft
19            [ CometbftError ]
20            | _ | { "CometBFT error" },
21
22        HeaderFromTheFuture
23            {
24                header_time: Time,
25                now: Time,
26                max_clock_drift: Duration,
27            }
28            | e | {
29                format_args!("header from the future: header_time={0} now={1} max_clock_drift={2:?}",
30                    e.header_time, e.now, e.max_clock_drift)
31            },
32
33        NotEnoughTrust
34            {
35                tally: VotingPowerTally,
36            }
37            | e | {
38                format_args!("not enough trust because insufficient validators overlap: {0}",
39                    e.tally)
40            },
41
42        InsufficientSignersOverlap
43            {
44                tally: VotingPowerTally,
45            }
46            | e | {
47                format_args!("insufficient signers overlap: {0}",
48                    e.tally)
49            },
50
51        DuplicateValidator
52            {
53                address: ValidatorAddress,
54            }
55            | e | {
56                format_args!("duplicate validator with address {0}",
57                    e.address)
58            },
59
60        MissingSignature
61            | _ | {
62                format_args!("missing signature")
63            },
64
65        InvalidSignature
66            {
67                signature: Vec<u8>,
68                validator: Box<Validator>,
69                sign_bytes: Vec<u8>,
70            }
71            | e | {
72                format_args!("failed to verify signature `{:?}` with validator `{:?}` on sign_bytes `{:?}`",
73                    e.signature, e.validator, e.sign_bytes)
74            },
75
76        InvalidCommitValue
77            {
78                header_hash: Hash,
79                commit_hash: Hash,
80            }
81            | e | {
82                format_args!("invalid commit value: header_hash={0} commit_hash={1}",
83                    e.header_hash, e.commit_hash)
84            },
85
86        InvalidNextValidatorSet
87            {
88                header_next_validators_hash: Hash,
89                next_validators_hash: Hash,
90            }
91            | e | {
92                format_args!("invalid next validator set: header_next_validators_hash={0} next_validators_hash={1}",
93                    e.header_next_validators_hash, e.next_validators_hash)
94            },
95
96        InvalidValidatorSet
97            {
98                header_validators_hash: Hash,
99                validators_hash: Hash,
100            }
101            | e | {
102                format_args!("invalid validator set: header_validators_hash={0} validators_hash={1}",
103                    e.header_validators_hash, e.validators_hash)
104            },
105
106        NonIncreasingHeight
107            {
108                got: Height,
109                expected: Height,
110            }
111            | e | {
112                format_args!("non increasing height: got={0} expected={1}",
113                    e.got, e.expected)
114            },
115
116        ChainIdMismatch
117            {
118                got: String,
119                expected: String,
120            }
121            | e | {
122                format_args!("chain-id mismatch: got={0} expected={1}",
123                    e.got, e.expected)
124            },
125
126        NonMonotonicBftTime
127            {
128                header_bft_time: Time,
129                trusted_header_bft_time: Time,
130            }
131            | e | {
132                format_args!("non monotonic BFT time: header_bft_time={0} trusted_header_bft_time={1}",
133                    e.header_bft_time, e.trusted_header_bft_time)
134            },
135
136        NotWithinTrustPeriod
137            {
138                expires_at: Time,
139                now: Time,
140            }
141            | e | {
142                format_args!("not within trusting period: expires_at={0} now={1}",
143                    e.expires_at, e.now)
144            },
145
146        NoSignatureForCommit
147            | _ | { "no signatures for commit"  },
148
149        MismatchPreCommitLength
150            {
151                pre_commit_length: usize,
152                validator_length: usize,
153            }
154            | e | {
155                format_args!(
156                    "pre-commit length: {} doesn't match validator length: {}",
157                    e.pre_commit_length,
158                    e.validator_length
159                )
160            },
161
162        FaultySigner
163            {
164                signer: Id,
165                validator_set: ValidatorSet
166            }
167            | e | {
168                format_args!(
169                    "Found a faulty signer ({}) not present in the validator set",
170                    e.signer,
171                )
172            },
173
174    }
175}
176
177/// Extension methods for `ErrorKind`
178pub trait ErrorExt {
179    /// Whether this error means that the light block
180    /// cannot be trusted w.r.t. the latest trusted state.
181    fn not_enough_trust(&self) -> Option<VotingPowerTally>;
182
183    /// Whether this error means that the light block has expired,
184    /// ie. it's outside of the trusting period.
185    fn has_expired(&self) -> bool;
186
187    /// Whether this error means that a timeout occurred when
188    /// querying a node.
189    fn is_timeout(&self) -> Option<Duration>;
190
191    /// Whether an I/O error occurred when querying a node.
192    fn is_io(&self) -> bool;
193
194    /// Whether the height of the requested light block is higher than the
195    /// latest height available on the node.
196    fn is_height_too_high(&self) -> bool;
197}
198
199impl ErrorExt for VerificationErrorDetail {
200    fn not_enough_trust(&self) -> Option<VotingPowerTally> {
201        match &self {
202            Self::NotEnoughTrust(e) => Some(e.tally),
203            _ => None,
204        }
205    }
206
207    fn has_expired(&self) -> bool {
208        matches!(self, Self::NotWithinTrustPeriod { .. })
209    }
210
211    fn is_timeout(&self) -> Option<Duration> {
212        None
213    }
214
215    fn is_io(&self) -> bool {
216        false
217    }
218
219    fn is_height_too_high(&self) -> bool {
220        false
221    }
222}