1use crate::{BlockNumberOf, Chain, HashOf, SimpleRuntimeVersion};
20use bp_header_chain::SubmitFinalityProofCallExtras;
21use bp_polkadot_core::parachains::ParaId;
22use jsonrpsee::core::ClientError as RpcError;
23use relay_utils::MaybeConnectionError;
24use sc_rpc_api::system::Health;
25use sp_core::{storage::StorageKey, Bytes};
26use sp_runtime::transaction_validity::TransactionValidityError;
27use thiserror::Error;
28
29pub type Result<T> = std::result::Result<T, Error>;
31
32#[derive(Error, Debug)]
35pub enum Error {
36 #[error("IO error: {0}")]
38 Io(#[from] std::io::Error),
39 #[error("RPC error: {0}")]
42 RpcError(#[from] RpcError),
43 #[error("Response parse failed: {0}")]
45 ResponseParseFailed(#[from] codec::Error),
46 #[error("Internal communication channel error: {0:?}.")]
49 ChannelError(String),
50 #[error("Parachain {0:?} head {1} is missing from the relay chain storage.")]
52 MissingRequiredParachainHead(ParaId, u64),
53 #[error("Failed to find finality proof for header {0}.")]
55 FinalityProofNotFound(u64),
56 #[error("Substrate client is not synced {0}.")]
58 ClientNotSynced(Health),
59 #[error("Failed to get system health of {chain} node: {error:?}.")]
61 FailedToGetSystemHealth {
62 chain: String,
64 error: Box<Error>,
66 },
67 #[error("Failed to read best finalized header hash of {chain}: {error:?}.")]
69 FailedToReadBestFinalizedHeaderHash {
70 chain: String,
72 error: Box<Error>,
74 },
75 #[error("Failed to read best header of {chain}: {error:?}.")]
77 FailedToReadBestHeader {
78 chain: String,
80 error: Box<Error>,
82 },
83 #[error("Failed to read header hash by number {number} of {chain}: {error:?}.")]
85 FailedToReadHeaderHashByNumber {
86 chain: String,
88 number: String,
90 error: Box<Error>,
92 },
93 #[error("Failed to read header {hash} of {chain}: {error:?}.")]
95 FailedToReadHeaderByHash {
96 chain: String,
98 hash: String,
100 error: Box<Error>,
102 },
103 #[error("Failed to read block {hash} of {chain}: {error:?}.")]
105 FailedToReadBlockByHash {
106 chain: String,
108 hash: String,
110 error: Box<Error>,
112 },
113 #[error("Failed to read storage value {key:?} at {chain}: {error:?}.")]
115 FailedToReadStorageValue {
116 chain: String,
118 hash: String,
120 key: StorageKey,
122 error: Box<Error>,
124 },
125 #[error("Failed to read runtime version of {chain}: {error:?}.")]
127 FailedToReadRuntimeVersion {
128 chain: String,
130 error: Box<Error>,
132 },
133 #[error("Failed to get pending extrinsics of {chain}: {error:?}.")]
135 FailedToGetPendingExtrinsics {
136 chain: String,
138 error: Box<Error>,
140 },
141 #[error("Failed to submit {chain} transaction: {error:?}.")]
143 FailedToSubmitTransaction {
144 chain: String,
146 error: Box<Error>,
148 },
149 #[error("Runtime call {method} with arguments {arguments:?} of chain {chain} at {hash} has failed: {error:?}.")]
151 FailedStateCall {
152 chain: String,
154 hash: String,
156 method: String,
158 arguments: Bytes,
160 error: Box<Error>,
162 },
163 #[error("Failed to prove storage keys {storage_keys:?} of {chain} at {hash}: {error:?}.")]
165 FailedToProveStorage {
166 chain: String,
168 hash: String,
170 storage_keys: Vec<StorageKey>,
172 error: Box<Error>,
174 },
175 #[error("Failed to subscribe to {chain} best headers: {error:?}.")]
177 FailedToSubscribeBestHeaders {
178 chain: String,
180 error: Box<Error>,
182 },
183 #[error("Failed to subscribe to {chain} finalized headers: {error:?}.")]
185 FailedToSubscribeFinalizedHeaders {
186 chain: String,
188 error: Box<Error>,
190 },
191 #[error("Failed to subscribe to {chain} justifications: {error:?}.")]
193 FailedToSubscribeJustifications {
194 chain: String,
196 error: Box<Error>,
198 },
199 #[error("Finalized headers of {chain} are unordered: previously finalized {prev_number} vs new {next_number}")]
202 UnorderedFinalizedHeaders {
203 chain: String,
205 prev_number: String,
207 next_number: String,
209 },
210 #[error("Bridge pallet is halted.")]
212 BridgePalletIsHalted,
213 #[error("Bridge pallet is not initialized.")]
215 BridgePalletIsNotInitialized,
216 #[error("Substrate transaction is invalid: {0:?}")]
218 TransactionInvalid(#[from] TransactionValidityError),
219 #[error("Waiting for {chain} runtime upgrade: expected {expected:?} actual {actual:?}")]
222 WaitingForRuntimeUpgrade {
223 chain: String,
225 expected: SimpleRuntimeVersion,
227 actual: SimpleRuntimeVersion,
229 },
230 #[error("Finality proof submission exceeds limits: {extras:?}")]
232 FinalityProofWeightLimitExceeded {
233 extras: SubmitFinalityProofCallExtras,
235 },
236 #[error("{0}")]
238 Custom(String),
239}
240
241impl From<tokio::task::JoinError> for Error {
242 fn from(error: tokio::task::JoinError) -> Self {
243 Error::ChannelError(format!("failed to wait tokio task: {error}"))
244 }
245}
246
247impl<T> From<async_std::channel::TrySendError<T>> for Error {
248 fn from(error: async_std::channel::TrySendError<T>) -> Self {
249 Error::ChannelError(format!("`try_send` has failed: {error:?}"))
250 }
251}
252
253impl From<async_std::channel::RecvError> for Error {
254 fn from(error: async_std::channel::RecvError) -> Self {
255 Error::ChannelError(format!("`recv` has failed: {error:?}"))
256 }
257}
258
259impl Error {
260 pub fn boxed(self) -> Box<Self> {
262 Box::new(self)
263 }
264
265 pub fn nested(&self) -> Option<&Self> {
267 match *self {
268 Self::FailedToReadBestFinalizedHeaderHash { ref error, .. } => Some(&**error),
269 Self::FailedToReadBestHeader { ref error, .. } => Some(&**error),
270 Self::FailedToReadHeaderHashByNumber { ref error, .. } => Some(&**error),
271 Self::FailedToReadHeaderByHash { ref error, .. } => Some(&**error),
272 Self::FailedToReadBlockByHash { ref error, .. } => Some(&**error),
273 Self::FailedToReadStorageValue { ref error, .. } => Some(&**error),
274 Self::FailedToReadRuntimeVersion { ref error, .. } => Some(&**error),
275 Self::FailedToGetPendingExtrinsics { ref error, .. } => Some(&**error),
276 Self::FailedToSubmitTransaction { ref error, .. } => Some(&**error),
277 Self::FailedStateCall { ref error, .. } => Some(&**error),
278 Self::FailedToProveStorage { ref error, .. } => Some(&**error),
279 Self::FailedToGetSystemHealth { ref error, .. } => Some(&**error),
280 Self::FailedToSubscribeBestHeaders { ref error, .. } => Some(&**error),
281 Self::FailedToSubscribeFinalizedHeaders { ref error, .. } => Some(&**error),
282 Self::FailedToSubscribeJustifications { ref error, .. } => Some(&**error),
283 _ => None,
284 }
285 }
286
287 pub fn failed_to_read_header_hash_by_number<C: Chain>(
289 number: BlockNumberOf<C>,
290 e: Error,
291 ) -> Self {
292 Error::FailedToReadHeaderHashByNumber {
293 chain: C::NAME.into(),
294 number: format!("{number}"),
295 error: e.boxed(),
296 }
297 }
298
299 pub fn failed_to_read_header_by_hash<C: Chain>(hash: HashOf<C>, e: Error) -> Self {
301 Error::FailedToReadHeaderByHash {
302 chain: C::NAME.into(),
303 hash: format!("{hash}"),
304 error: e.boxed(),
305 }
306 }
307
308 pub fn failed_to_read_block_by_hash<C: Chain>(hash: HashOf<C>, e: Error) -> Self {
310 Error::FailedToReadHeaderByHash {
311 chain: C::NAME.into(),
312 hash: format!("{hash}"),
313 error: e.boxed(),
314 }
315 }
316
317 pub fn failed_to_read_best_finalized_header_hash<C: Chain>(e: Error) -> Self {
319 Error::FailedToReadBestFinalizedHeaderHash { chain: C::NAME.into(), error: e.boxed() }
320 }
321
322 pub fn failed_to_read_best_header<C: Chain>(e: Error) -> Self {
324 Error::FailedToReadBestHeader { chain: C::NAME.into(), error: e.boxed() }
325 }
326
327 pub fn failed_to_read_runtime_version<C: Chain>(e: Error) -> Self {
329 Error::FailedToReadRuntimeVersion { chain: C::NAME.into(), error: e.boxed() }
330 }
331
332 pub fn failed_to_read_storage_value<C: Chain>(
334 at: HashOf<C>,
335 key: StorageKey,
336 e: Error,
337 ) -> Self {
338 Error::FailedToReadStorageValue {
339 chain: C::NAME.into(),
340 hash: format!("{at}"),
341 key,
342 error: e.boxed(),
343 }
344 }
345
346 pub fn failed_to_get_pending_extrinsics<C: Chain>(e: Error) -> Self {
348 Error::FailedToGetPendingExtrinsics { chain: C::NAME.into(), error: e.boxed() }
349 }
350
351 pub fn failed_to_submit_transaction<C: Chain>(e: Error) -> Self {
353 Error::FailedToSubmitTransaction { chain: C::NAME.into(), error: e.boxed() }
354 }
355
356 pub fn failed_state_call<C: Chain>(
358 at: HashOf<C>,
359 method: String,
360 arguments: Bytes,
361 e: Error,
362 ) -> Self {
363 Error::FailedStateCall {
364 chain: C::NAME.into(),
365 hash: format!("{at}"),
366 method,
367 arguments,
368 error: e.boxed(),
369 }
370 }
371
372 pub fn failed_to_prove_storage<C: Chain>(
374 at: HashOf<C>,
375 storage_keys: Vec<StorageKey>,
376 e: Error,
377 ) -> Self {
378 Error::FailedToProveStorage {
379 chain: C::NAME.into(),
380 hash: format!("{at}"),
381 storage_keys,
382 error: e.boxed(),
383 }
384 }
385
386 pub fn failed_to_get_system_health<C: Chain>(e: Error) -> Self {
388 Error::FailedToGetSystemHealth { chain: C::NAME.into(), error: e.boxed() }
389 }
390
391 pub fn failed_to_subscribe_best_headers<C: Chain>(e: Error) -> Self {
393 Error::FailedToSubscribeBestHeaders { chain: C::NAME.into(), error: e.boxed() }
394 }
395
396 pub fn failed_to_subscribe_finalized_headers<C: Chain>(e: Error) -> Self {
398 Error::FailedToSubscribeFinalizedHeaders { chain: C::NAME.into(), error: e.boxed() }
399 }
400
401 pub fn failed_to_subscribe_justification<C: Chain>(e: Error) -> Self {
403 Error::FailedToSubscribeJustifications { chain: C::NAME.into(), error: e.boxed() }
404 }
405
406 pub fn unordered_finalized_headers<C: Chain>(
408 prev_number: BlockNumberOf<C>,
409 next_number: BlockNumberOf<C>,
410 ) -> Self {
411 Error::UnorderedFinalizedHeaders {
412 chain: C::NAME.into(),
413 prev_number: format!("{}", prev_number),
414 next_number: format!("{}", next_number),
415 }
416 }
417}
418
419impl MaybeConnectionError for Error {
420 fn is_connection_error(&self) -> bool {
421 match *self {
422 Error::ChannelError(_) => true,
423 Error::RpcError(ref e) =>
424 matches!(*e, RpcError::Transport(_) | RpcError::RestartNeeded(_),),
425 Error::ClientNotSynced(_) => true,
426 Error::UnorderedFinalizedHeaders { .. } => true,
427 _ => self.nested().map(|e| e.is_connection_error()).unwrap_or(false),
428 }
429 }
430}