nyxd_scraper_shared/
error.rs

1// Copyright 2023 - Nym Technologies SA <contact@nymtech.net>
2// SPDX-License-Identifier: Apache-2.0
3
4use crate::block_processor::pruning::{
5    EVERYTHING_PRUNING_INTERVAL, EVERYTHING_PRUNING_KEEP_RECENT,
6};
7use crate::helpers::MalformedDataError;
8use crate::storage::NyxdScraperStorageError;
9use tendermint::Hash;
10use thiserror::Error;
11use tokio::sync::mpsc::error::SendError;
12
13#[derive(Debug, Error)]
14pub enum ScraperError {
15    #[error("storage error: {0}")]
16    StorageError(#[from] NyxdScraperStorageError),
17
18    #[error("the block scraper is already running")]
19    ScraperAlreadyRunning,
20
21    #[error("block information for height {height} is not available on the provided rpc endpoint")]
22    BlocksUnavailable { height: u32 },
23
24    #[error("failed to establish websocket connection to {url}: {source}")]
25    WebSocketConnectionFailure {
26        url: String,
27        #[source]
28        source: Box<tendermint_rpc::Error>,
29    },
30
31    #[error("failed to establish rpc connection to {url}: {source}")]
32    HttpConnectionFailure {
33        url: String,
34        #[source]
35        source: Box<tendermint_rpc::Error>,
36    },
37
38    #[error("failed to create chain subscription: {source}")]
39    ChainSubscriptionFailure {
40        #[source]
41        source: Box<tendermint_rpc::Error>,
42    },
43
44    #[error("could not obtain basic block information at height: {height}: {source}")]
45    BlockQueryFailure {
46        height: u32,
47        #[source]
48        source: Box<tendermint_rpc::Error>,
49    },
50
51    #[error("could not obtain block results information at height: {height}: {source}")]
52    BlockResultsQueryFailure {
53        height: u32,
54        #[source]
55        source: Box<tendermint_rpc::Error>,
56    },
57
58    #[error("could not obtain validators information at height: {height}: {source}")]
59    ValidatorsQueryFailure {
60        height: u32,
61        #[source]
62        source: Box<tendermint_rpc::Error>,
63    },
64
65    #[error("could not obtain tx results for tx: {hash}: {source}")]
66    TxResultsQueryFailure {
67        hash: Hash,
68        #[source]
69        source: Box<tendermint_rpc::Error>,
70    },
71
72    #[error("could not obtain current abci info: {source}")]
73    AbciInfoQueryFailure {
74        #[source]
75        source: Box<tendermint_rpc::Error>,
76    },
77
78    #[error("could not parse tx {hash}: {source}")]
79    TxParseFailure {
80        hash: Hash,
81        #[source]
82        source: cosmrs::ErrorReport,
83    },
84
85    #[error("could not parse msg in tx {hash} at index {index} into {type_url}: {source}")]
86    MsgParseFailure {
87        hash: Hash,
88        index: usize,
89        type_url: String,
90        #[source]
91        source: cosmrs::ErrorReport,
92    },
93
94    #[error(
95        "received an invalid chain subscription event of kind {kind} while we were waiting for new block data (query: '{query}')"
96    )]
97    InvalidSubscriptionEvent { query: String, kind: String },
98
99    #[error("received block data was empty (query: '{query}')")]
100    EmptyBlockData { query: String },
101
102    #[error("reached maximum number of allowed errors for subscription events")]
103    MaximumWebSocketFailures,
104
105    #[error("failed to begin storage tx: {source}")]
106    StorageTxBeginFailure {
107        #[source]
108        source: NyxdScraperStorageError,
109    },
110
111    #[error("failed to commit storage tx: {source}")]
112    StorageTxCommitFailure {
113        #[source]
114        source: NyxdScraperStorageError,
115    },
116
117    #[error("failed to send on a closed channel")]
118    ClosedChannelError,
119
120    #[error(transparent)]
121    MalformedData(#[from] MalformedDataError),
122
123    #[error(
124        "could not find the block proposer ('{proposer}') for height {height} in the validator set"
125    )]
126    BlockProposerNotInValidatorSet { height: u32, proposer: String },
127
128    #[error(
129        "pruning.interval must not be set to 0. If you want to disable pruning, select pruning.strategy = \"nothing\""
130    )]
131    ZeroPruningInterval,
132
133    #[error(
134        "pruning.interval must not be smaller than {}. got: {interval}. for most aggressive pruning, select pruning.strategy = \"everything\"",
135        EVERYTHING_PRUNING_INTERVAL
136    )]
137    TooSmallPruningInterval { interval: u32 },
138
139    #[error(
140        "pruning.keep_recent must not be smaller than {}. got: {keep_recent}. for most aggressive pruning, select pruning.strategy = \"everything\"",
141        EVERYTHING_PRUNING_KEEP_RECENT
142    )]
143    TooSmallKeepRecent { keep_recent: u32 },
144
145    #[error("'{type_url}' is not registered in the message registry")]
146    MissingTypeUrlRegistration { type_url: String },
147
148    #[error("failed to decode message of type '{type_url}': {error}")]
149    InvalidProtoRepresentation {
150        type_url: String,
151        #[source]
152        error: prost::DecodeError,
153    },
154
155    #[error("failed to encode message of type '{type_url}' to json: '{error}'")]
156    JsonSerialisationFailure {
157        type_url: String,
158        #[source]
159        error: serde_json::Error,
160    },
161
162    #[error("serialisation of message of type '{type_url}' didn't result in an object!")]
163    JsonSerialisationFailureNotObject { type_url: String },
164
165    #[error("field '{field}' in '{type_url}' is not a string")]
166    JsonWasmSerialisationFailureNotString { field: String, type_url: String },
167
168    #[error("field '{field}' in '{type_url}' has invalid base64 encoding: {error}")]
169    JsonWasmSerialisationFailureInvalidBase64Encoding {
170        field: String,
171        type_url: String,
172        #[source]
173        error: base64::DecodeError,
174    },
175}
176
177impl ScraperError {
178    pub fn tx_begin_failure(source: NyxdScraperStorageError) -> ScraperError
179where {
180        ScraperError::StorageTxBeginFailure { source }
181    }
182
183    pub fn tx_commit_failure(source: NyxdScraperStorageError) -> ScraperError
184where {
185        ScraperError::StorageTxCommitFailure { source }
186    }
187}
188
189impl<T> From<SendError<T>> for ScraperError {
190    fn from(_: SendError<T>) -> Self {
191        ScraperError::ClosedChannelError
192    }
193}