1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
//! Defines the client error type

use core::convert::Infallible;

use displaydoc::Display;
use ibc_core_commitment_types::error::CommitmentError;
use ibc_core_host_types::error::IdentifierError;
use ibc_core_host_types::identifiers::{ClientId, ClientType};
use ibc_primitives::prelude::*;
use ibc_primitives::Timestamp;

use super::status::Status;
use crate::height::Height;

/// Encodes all the possible client errors
#[derive(Debug, Display)]
pub enum ClientError {
    /// upgrade client error: `{0}`
    Upgrade(UpgradeClientError),
    /// client is frozen with description: `{description}`
    ClientFrozen { description: String },
    /// client is not active. Status=`{status}`
    ClientNotActive { status: Status },
    /// client is not frozen or expired. Status=`{status}`
    ClientNotInactive { status: Status },
    /// client state not found: `{client_id}`
    ClientStateNotFound { client_id: ClientId },
    /// client state already exists: `{client_id}`
    ClientStateAlreadyExists { client_id: ClientId },
    /// Substitute client height `{substitute_height}` is not greater than subject client height `{subject_height}` during client recovery
    ClientRecoveryHeightMismatch {
        subject_height: Height,
        substitute_height: Height,
    },
    /// Subject and substitute client state mismatch during client recovery
    ClientRecoveryStateMismatch,
    /// consensus state not found at: `{client_id}` at height `{height}`
    ConsensusStateNotFound { client_id: ClientId, height: Height },
    /// Processed time or height for the client `{client_id}` at height `{height}` not found
    UpdateMetaDataNotFound { client_id: ClientId, height: Height },
    /// header verification failed with reason: `{reason}`
    HeaderVerificationFailure { reason: String },
    /// failed to build trust threshold from fraction: `{numerator}`/`{denominator}`
    InvalidTrustThreshold { numerator: u64, denominator: u64 },
    /// failed to build Tendermint domain type trust threshold from fraction: `{numerator}`/`{denominator}`
    FailedTrustThresholdConversion { numerator: u64, denominator: u64 },
    /// unknown client state type: `{client_state_type}`
    UnknownClientStateType { client_state_type: String },
    /// unknown client consensus state type: `{consensus_state_type}`
    UnknownConsensusStateType { consensus_state_type: String },
    /// unknown header type: `{header_type}`
    UnknownHeaderType { header_type: String },
    /// unknown misbehaviour type: `{misbehaviour_type}`
    UnknownMisbehaviourType { misbehaviour_type: String },
    /// missing raw client state
    MissingRawClientState,
    /// missing raw client consensus state
    MissingRawConsensusState,
    /// invalid client id in the update client message: `{0}`
    InvalidMsgUpdateClientId(IdentifierError),
    /// invalid client id in recover client message: `{0}`
    InvalidMsgRecoverClientId(IdentifierError),
    /// invalid client identifier error: `{0}`
    InvalidClientIdentifier(IdentifierError),
    /// invalid raw header error: `{reason}`
    InvalidRawHeader { reason: String },
    /// missing raw client message
    MissingClientMessage,
    /// invalid raw misbehaviour error: `{0}`
    InvalidRawMisbehaviour(IdentifierError),
    /// missing raw misbehaviour
    MissingRawMisbehaviour,
    /// revision height cannot be zero
    InvalidHeight,
    /// height cannot end up zero or negative
    InvalidHeightResult,
    /// the proof height is insufficient: latest_height=`{latest_height}` proof_height=`{proof_height}`
    InvalidProofHeight {
        latest_height: Height,
        proof_height: Height,
    },
    /// invalid commitment proof bytes error: `{0}`
    InvalidCommitmentProof(CommitmentError),
    /// mismatch between client and arguments types
    ClientArgsTypeMismatch { client_type: ClientType },
    /// timestamp is invalid or missing, timestamp=`{time1}`,  now=`{time2}`
    InvalidConsensusStateTimestamp { time1: Timestamp, time2: Timestamp },
    /// the local consensus state could not be retrieved for height `{height}`
    MissingLocalConsensusState { height: Height },
    /// invalid signer error: `{reason}`
    InvalidSigner { reason: String },
    /// ics23 verification failure error: `{0}`
    Ics23Verification(CommitmentError),
    /// misbehaviour handling failed with reason: `{reason}`
    MisbehaviourHandlingFailure { reason: String },
    /// client-specific error: `{description}`
    ClientSpecific { description: String },
    /// client counter overflow error
    CounterOverflow,
    /// update client message did not contain valid header or misbehaviour
    InvalidUpdateClientMessage,
    /// other error: `{description}`
    Other { description: String },
    /// invalid attribute key: `{attribute_key}`
    InvalidAttributeKey { attribute_key: String },
    /// invalid attribute value: `{attribute_value}`
    InvalidAttributeValue { attribute_value: String },
    /// Missing attribute key: `{attribute_key}`
    MissingAttributeKey { attribute_key: String },
}

impl From<&'static str> for ClientError {
    fn from(s: &'static str) -> Self {
        Self::Other {
            description: s.to_string(),
        }
    }
}

impl From<Infallible> for ClientError {
    fn from(value: Infallible) -> Self {
        match value {}
    }
}

#[cfg(feature = "std")]
impl std::error::Error for ClientError {
    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        match &self {
            Self::InvalidMsgUpdateClientId(e)
            | Self::InvalidClientIdentifier(e)
            | Self::InvalidRawMisbehaviour(e) => Some(e),
            Self::InvalidCommitmentProof(e) | Self::Ics23Verification(e) => Some(e),
            _ => None,
        }
    }
}

/// Encodes all the possible upgrade client errors
#[derive(Debug, Display)]
pub enum UpgradeClientError {
    /// invalid proof for the upgraded client state error: `{0}`
    InvalidUpgradeClientProof(CommitmentError),
    /// invalid proof for the upgraded consensus state error: `{0}`
    InvalidUpgradeConsensusStateProof(CommitmentError),
    /// upgraded client height `{upgraded_height}` must be at greater than current client height `{client_height}`
    LowUpgradeHeight {
        upgraded_height: Height,
        client_height: Height,
    },
    /// Invalid upgrade path: `{reason}`
    InvalidUpgradePath { reason: String },
    /// invalid upgrade proposal: `{reason}`
    InvalidUpgradeProposal { reason: String },
    /// invalid upgrade plan: `{reason}`
    InvalidUpgradePlan { reason: String },
    /// other upgrade client error: `{reason}`
    Other { reason: String },
}

impl From<UpgradeClientError> for ClientError {
    fn from(e: UpgradeClientError) -> Self {
        ClientError::Upgrade(e)
    }
}

#[cfg(feature = "std")]
impl std::error::Error for UpgradeClientError {
    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        match &self {
            Self::InvalidUpgradeClientProof(e) | Self::InvalidUpgradeConsensusStateProof(e) => {
                Some(e)
            }
            _ => None,
        }
    }
}