use core::time::Duration;
use flex_error::define_error;
use serde::{Deserialize, Serialize};
use tendermint::{account::Id, Error as TendermintError};
use crate::{
operations::voting_power::VotingPowerTally,
prelude::*,
types::{Hash, Height, Time, Validator, ValidatorAddress, ValidatorSet},
};
define_error! {
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
VerificationError {
Tendermint
[ TendermintError ]
| _ | { "tendermint error" },
HeaderFromTheFuture
{
header_time: Time,
now: Time,
max_clock_drift: Duration,
}
| e | {
format_args!("header from the future: header_time={0} now={1} max_clock_drift={2:?}",
e.header_time, e.now, e.max_clock_drift)
},
NotEnoughTrust
{
tally: VotingPowerTally,
}
| e | {
format_args!("not enough trust because insufficient validators overlap: {0}",
e.tally)
},
InsufficientSignersOverlap
{
tally: VotingPowerTally,
}
| e | {
format_args!("insufficient signers overlap: {0}",
e.tally)
},
DuplicateValidator
{
address: ValidatorAddress,
}
| e | {
format_args!("duplicate validator with address {0}",
e.address)
},
MissingSignature
| _ | {
format_args!("missing signature")
},
InvalidSignature
{
signature: Vec<u8>,
validator: Box<Validator>,
sign_bytes: Vec<u8>,
}
| e | {
format_args!("failed to verify signature `{:?}` with validator `{:?}` on sign_bytes `{:?}`",
e.signature, e.validator, e.sign_bytes)
},
InvalidCommitValue
{
header_hash: Hash,
commit_hash: Hash,
}
| e | {
format_args!("invalid commit value: header_hash={0} commit_hash={1}",
e.header_hash, e.commit_hash)
},
InvalidNextValidatorSet
{
header_next_validators_hash: Hash,
next_validators_hash: Hash,
}
| e | {
format_args!("invalid next validator set: header_next_validators_hash={0} next_validators_hash={1}",
e.header_next_validators_hash, e.next_validators_hash)
},
InvalidValidatorSet
{
header_validators_hash: Hash,
validators_hash: Hash,
}
| e | {
format_args!("invalid validator set: header_validators_hash={0} validators_hash={1}",
e.header_validators_hash, e.validators_hash)
},
NonIncreasingHeight
{
got: Height,
expected: Height,
}
| e | {
format_args!("non increasing height: got={0} expected={1}",
e.got, e.expected)
},
ChainIdMismatch
{
got: String,
expected: String,
}
| e | {
format_args!("chain-id mismatch: got={0} expected={1}",
e.got, e.expected)
},
NonMonotonicBftTime
{
header_bft_time: Time,
trusted_header_bft_time: Time,
}
| e | {
format_args!("non monotonic BFT time: header_bft_time={0} trusted_header_bft_time={1}",
e.header_bft_time, e.trusted_header_bft_time)
},
NotWithinTrustPeriod
{
expires_at: Time,
now: Time,
}
| e | {
format_args!("not within trusting period: expires_at={0} now={1}",
e.expires_at, e.now)
},
NoSignatureForCommit
| _ | { "no signatures for commit" },
MismatchPreCommitLength
{
pre_commit_length: usize,
validator_length: usize,
}
| e | {
format_args!(
"pre-commit length: {} doesn't match validator length: {}",
e.pre_commit_length,
e.validator_length
)
},
FaultySigner
{
signer: Id,
validator_set: ValidatorSet
}
| e | {
format_args!(
"Found a faulty signer ({}) not present in the validator set",
e.signer,
)
},
}
}
pub trait ErrorExt {
fn not_enough_trust(&self) -> Option<VotingPowerTally>;
fn has_expired(&self) -> bool;
fn is_timeout(&self) -> Option<Duration>;
fn is_io(&self) -> bool;
fn is_height_too_high(&self) -> bool;
}
impl ErrorExt for VerificationErrorDetail {
fn not_enough_trust(&self) -> Option<VotingPowerTally> {
match &self {
Self::NotEnoughTrust(e) => Some(e.tally),
_ => None,
}
}
fn has_expired(&self) -> bool {
matches!(self, Self::NotWithinTrustPeriod { .. })
}
fn is_timeout(&self) -> Option<Duration> {
None
}
fn is_io(&self) -> bool {
false
}
fn is_height_too_high(&self) -> bool {
false
}
}