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
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
//! This module defines the various errors that be raised in the relayer.

use anomaly::{BoxError, Context};
use thiserror::Error;

use ibc::{
    ics02_client::client_type::ClientType,
    ics24_host::identifier::{ChannelId, ConnectionId},
};

/// An error that can be raised by the relayer.
pub type Error = anomaly::Error<Kind>;

/// Various kinds of errors that can be raiser by the relayer.
#[derive(Clone, Debug, Error)]
pub enum Kind {
    /// Config I/O error
    #[error("config I/O error")]
    ConfigIo,

    /// I/O error
    #[error("I/O error")]
    Io,

    /// Invalid configuration
    #[error("invalid configuration")]
    Config,

    /// RPC error (typically raised by the RPC client or the RPC requester)
    #[error("RPC error to endpoint {0}")]
    Rpc(tendermint_rpc::Url),

    /// Websocket error (typically raised by the Websocket client)
    #[error("Websocket error to endpoint {0}")]
    Websocket(tendermint_rpc::Url),

    /// Event monitor error
    #[error("event monitor error: {0}")]
    EventMonitor(crate::event::monitor::Error),

    /// GRPC error (typically raised by the GRPC client or the GRPC requester)
    #[error("GRPC error")]
    Grpc,

    /// Light client instance error, typically raised by a `Client`
    #[error("Light client error for RPC address {0}")]
    LightClient(String),

    /// Trusted store error, raised by instances of `Store`
    #[error("Store error")]
    Store,

    /// Event error (raised by the event monitor)
    #[error("Bad Notification")]
    Event,

    /// Missing ClientState in the upgrade CurrentPlan
    #[error("The upgrade plan specifies no upgraded client state")]
    EmptyUpgradedClientState,

    /// Response does not contain data
    #[error("Empty response value")]
    EmptyResponseValue,

    /// Response does not contain a proof
    #[error("Empty response proof")]
    EmptyResponseProof,

    /// Response does not contain a proof
    #[error("Malformed proof")]
    MalformedProof,

    /// Invalid height
    #[error("Invalid height")]
    InvalidHeight,

    /// Unable to build the client state
    #[error("Failed to create client state")]
    BuildClientStateFailure,

    /// Create client failure
    #[error("Failed to create client {0}")]
    CreateClient(String),

    /// Common failures to all connection messages
    #[error("Failed to build conn open message {0}: {1}")]
    ConnOpen(ConnectionId, String),

    /// Connection open init failure
    #[error("Failed to build conn open init {0}")]
    ConnOpenInit(String),

    /// Connection open try failure
    #[error("Failed to build conn open try {0}")]
    ConnOpenTry(String),

    /// Connection open ack failure
    #[error("Failed to build conn open ack {0}: {1}")]
    ConnOpenAck(ConnectionId, String),

    /// Connection open confirm failure
    #[error("Failed to build conn open confirm {0}: {1}")]
    ConnOpenConfirm(ConnectionId, String),

    /// Common failures to all channel messages
    #[error("Failed to build chan open msg {0}: {1}")]
    ChanOpen(ChannelId, String),

    /// Channel open init failure
    #[error("Failed to build channel open init {0}")]
    ChanOpenInit(String),

    /// Channel open try failure
    #[error("Failed to build channel open try {0}")]
    ChanOpenTry(String),

    /// Channel open ack failure
    #[error("Failed to build channel open ack {0}: {1}")]
    ChanOpenAck(ChannelId, String),

    /// Channel open confirm failure
    #[error("Failed to build channel open confirm {0}: {1}")]
    ChanOpenConfirm(ChannelId, String),

    /// Packet build failure
    #[error("Failed to build packet {0}: {1}")]
    Packet(ChannelId, String),

    /// Packet recv  failure
    #[error("Failed to build recv packet {0}: {1}")]
    RecvPacket(ChannelId, String),

    /// Packet acknowledgement failure
    #[error("Failed to build acknowledge packet {0}: {1}")]
    AckPacket(ChannelId, String),

    /// Packet timeout  failure
    #[error("Failed to build timeout packet {0}: {1}")]
    TimeoutPacket(ChannelId, String),

    /// A message transaction failure
    #[error("Message transaction failure: {0}")]
    MessageTransaction(String),

    /// Failed query
    #[error("Query error occurred (failed to query for {0})")]
    Query(String),

    /// Keybase related error
    #[error("Keybase error")]
    KeyBase,

    /// ICS 007 error
    #[error("ICS 007 error")]
    Ics007,

    /// ICS 023 error
    #[error("ICS 023 error")]
    Ics023(#[from] ibc::ics23_commitment::error::Error),

    /// Invalid chain identifier
    #[error("invalid chain identifier format: {0}")]
    ChainIdentifier(String),

    #[error("requested proof for data in the privateStore")]
    NonProvableData,

    #[error("failed to send or receive through channel")]
    Channel,

    #[error("the input header is not recognized as a header for this chain")]
    InvalidInputHeader,

    #[error("error raised while submitting the misbehaviour evidence: {0}")]
    Misbehaviour(String),

    #[error("invalid key address: {0}")]
    InvalidKeyAddress(String),

    #[error("bech32 encoding failed")]
    Bech32Encoding(#[from] bech32::Error),

    #[error("client type mismatch: expected '{expected}', got '{got}'")]
    ClientTypeMismatch {
        expected: ClientType,
        got: ClientType,
    },
}

impl Kind {
    /// Add a given source error as context for this error kind
    ///
    /// This is typically use with `map_err` as follows:
    ///
    /// ```ignore
    /// let x = self.something.do_stuff()
    ///     .map_err(|e| error::Kind::Config.context(e))?;
    /// ```
    pub fn context(self, source: impl Into<BoxError>) -> Context<Self> {
        Context::new(self, Some(source.into()))
    }

    pub fn channel(err: impl Into<BoxError>) -> Context<Self> {
        Self::Channel.context(err)
    }
}