1use fastcrypto::error::FastCryptoError;
6use iota_data_ingestion_core::IngestionError;
7use iota_json_rpc_api::{error_object_from_rpc, internal_error};
8use iota_names::error::IotaNamesError;
9use iota_types::{
10 base_types::ObjectIDParseError,
11 error::{IotaError, IotaObjectResponseError, UserInputError},
12};
13use jsonrpsee::{core::ClientError as RpcError, types::ErrorObjectOwned};
14use thiserror::Error;
15
16#[derive(Debug, Error)]
17pub struct DataDownloadError {
18 pub error: IndexerError,
19 pub next_checkpoint_sequence_number: u64,
20}
21
22impl std::fmt::Display for DataDownloadError {
23 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
24 write!(
25 f,
26 "next_checkpoint_seq: {}, error: {}",
27 self.next_checkpoint_sequence_number, self.error
28 )
29 }
30}
31
32#[derive(Debug, Error)]
33#[non_exhaustive]
34pub enum IndexerError {
35 #[error("Stream closed unexpectedly with error: `{0}`")]
36 ChannelClosed(String),
37
38 #[error("Indexer failed to convert timestamp to DateTime with error: `{0}`")]
39 DateTimeParsing(String),
40
41 #[error("Indexer failed to deserialize event from events table with error: `{0}`")]
42 EventDeserialization(String),
43
44 #[error(
45 "Fullnode returns unexpected responses, which may block indexers from proceeding, with error: `{0}`"
46 )]
47 UnexpectedFullnodeResponse(String),
48
49 #[error("Indexer failed to transform data with error: `{0}`")]
50 DataTransformation(String),
51
52 #[error("Indexer failed to read fullnode with error: `{0}`")]
53 FullNodeReading(String),
54
55 #[error("Indexer failed to convert structs to diesel Insertable with error: `{0}`")]
56 InsertableParsing(String),
57
58 #[error("Indexer failed to build JsonRpcServer with error: `{0}`")]
59 JsonRpcServer(#[from] iota_json_rpc::error::Error),
60
61 #[error("Indexer failed to find object mutations, which should never happen.")]
62 ObjectMutationNotAvailable,
63
64 #[error("Indexer failed to build PG connection pool with error: `{0}`")]
65 PgConnectionPoolInit(String),
66
67 #[error("Indexer failed to get a pool connection from PG connection pool with error: `{0}`")]
68 PgPoolConnection(String),
69
70 #[error("Indexer failed to read PostgresDB with error: `{0}`")]
71 PostgresRead(String),
72
73 #[error("Indexer failed to reset PostgresDB with error: `{0}`")]
74 PostgresReset(String),
75
76 #[error("Indexer failed to commit changes to PostgresDB with error: `{0}`")]
77 PostgresWrite(String),
78
79 #[error(transparent)]
80 Postgres(#[from] diesel::result::Error),
81
82 #[error("Indexer failed to initialize fullnode Http client with error: `{0}`")]
83 HttpClientInit(String),
84
85 #[error("Indexer failed to serialize/deserialize with error: `{0}`")]
86 Serde(String),
87
88 #[error("Indexer error related to dynamic field: `{0}`")]
89 DynamicField(String),
90
91 #[error("Indexer does not support the feature with error: `{0}`")]
92 NotSupported(String),
93
94 #[error("Indexer read corrupted/incompatible data from persistent storage: `{0}`")]
95 PersistentStorageDataCorruption(String),
96
97 #[error("Indexer generic error: `{0}`")]
98 Generic(String),
99
100 #[error("Indexer failed to resolve object to move struct with error: `{0}`")]
101 ResolveMoveStruct(String),
102
103 #[error(transparent)]
104 Uncategorized(#[from] anyhow::Error),
105
106 #[error(transparent)]
107 ObjectIdParse(#[from] ObjectIDParseError),
108
109 #[error("Invalid transaction digest with error: `{0}`")]
110 InvalidTransactionDigest(String),
111
112 #[error(transparent)]
113 Iota(#[from] IotaError),
114
115 #[error(transparent)]
116 Bcs(#[from] bcs::Error),
117
118 #[error("Invalid argument with error: `{0}`")]
119 InvalidArgument(String),
120
121 #[error(transparent)]
122 UserInput(#[from] UserInputError),
123
124 #[error("Indexer failed to resolve module with error: `{0}`")]
125 ModuleResolution(String),
126
127 #[error(transparent)]
128 ObjectResponse(#[from] IotaObjectResponseError),
129
130 #[error(transparent)]
131 FastCrypto(#[from] FastCryptoError),
132
133 #[error("`{0}`: `{1}`")]
134 ErrorWithContext(String, Box<IndexerError>),
135
136 #[error("Indexer failed to send item to channel with error: `{0}`")]
137 MpscChannel(String),
138
139 #[error("Failed to process checkpoint(s): `{0}`")]
140 CheckpointProcessing(String),
141
142 #[error(transparent)]
143 Ingestion(#[from] IngestionError),
144
145 #[error(transparent)]
146 IotaNames(#[from] IotaNamesError),
147}
148
149pub trait Context<T> {
150 fn context(self, context: &str) -> Result<T, IndexerError>;
151}
152
153impl<T> Context<T> for Result<T, IndexerError> {
154 fn context(self, context: &str) -> Result<T, IndexerError> {
155 self.map_err(|e| IndexerError::ErrorWithContext(context.to_string(), Box::new(e)))
156 }
157}
158
159impl From<IndexerError> for RpcError {
160 fn from(e: IndexerError) -> Self {
161 RpcError::Call(internal_error(e))
162 }
163}
164
165impl From<IndexerError> for ErrorObjectOwned {
166 fn from(value: IndexerError) -> Self {
167 error_object_from_rpc(value.into())
168 }
169}
170
171impl From<tokio::task::JoinError> for IndexerError {
172 fn from(value: tokio::task::JoinError) -> Self {
173 IndexerError::Uncategorized(anyhow::Error::from(value))
174 }
175}