1use fastcrypto::error::FastCryptoError;
5use jsonrpsee::types::ErrorObjectOwned as RpcError;
6use sui_name_service::NameServiceError;
7use thiserror::Error;
8
9use sui_types::base_types::ObjectIDParseError;
10use sui_types::error::{SuiError, SuiObjectResponseError, UserInputError};
11
12#[derive(Debug, Error)]
13pub struct DataDownloadError {
14 pub error: IndexerError,
15 pub next_checkpoint_sequence_number: u64,
16}
17
18impl std::fmt::Display for DataDownloadError {
19 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
20 write!(
21 f,
22 "next_checkpoint_seq: {}, error: {}",
23 self.next_checkpoint_sequence_number, self.error
24 )
25 }
26}
27
28#[derive(Debug, Error)]
29pub enum IndexerError {
30 #[error("Indexer failed to read from archives store with error: `{0}`")]
31 ArchiveReaderError(String),
32
33 #[error("Stream closed unexpectedly with error: `{0}`")]
34 ChannelClosed(String),
35
36 #[error("Indexer failed to convert timestamp to NaiveDateTime with error: `{0}`")]
37 DateTimeParsingError(String),
38
39 #[error("Indexer failed to deserialize event from events table with error: `{0}`")]
40 EventDeserializationError(String),
41
42 #[error(
43 "Fullnode returns unexpected responses, which may block indexers from proceeding, with error: `{0}`"
44 )]
45 UnexpectedFullnodeResponseError(String),
46
47 #[error("Indexer failed to transform data with error: `{0}`")]
48 DataTransformationError(String),
49
50 #[error("Indexer failed to read fullnode with error: `{0}`")]
51 FullNodeReadingError(String),
52
53 #[error("Indexer failed to convert structs to diesel Insertable with error: `{0}`")]
54 InsertableParsingError(String),
55
56 #[error("Indexer failed to build JsonRpcServer with error: `{0}`")]
57 JsonRpcServerError(#[from] sui_json_rpc::error::Error),
58
59 #[error("Indexer failed to find object mutations, which should never happen.")]
60 ObjectMutationNotAvailable,
61
62 #[error("Indexer failed to build PG connection pool with error: `{0}`")]
63 PgConnectionPoolInitError(String),
64
65 #[error("Indexer failed to get a pool connection from PG connection pool with error: `{0}`")]
66 PgPoolConnectionError(String),
67
68 #[error("Indexer failed to read PostgresDB with error: `{0}`")]
69 PostgresReadError(String),
70
71 #[error("Indexer failed to reset PostgresDB with error: `{0}`")]
72 PostgresResetError(String),
73
74 #[error("Indexer failed to commit changes to PostgresDB with error: `{0}`")]
75 PostgresWriteError(String),
76
77 #[error(transparent)]
78 PostgresError(#[from] diesel::result::Error),
79
80 #[error("Indexer failed to initialize fullnode Http client with error: `{0}`")]
81 HttpClientInitError(String),
82
83 #[error("Indexer failed to serialize/deserialize with error: `{0}`")]
84 SerdeError(String),
85
86 #[error("Indexer error related to dynamic field: `{0}`")]
87 DynamicFieldError(String),
88
89 #[error("Indexer does not support the feature with error: `{0}`")]
90 NotSupportedError(String),
91
92 #[error("Indexer read corrupted/incompatible data from persistent storage: `{0}`")]
93 PersistentStorageDataCorruptionError(String),
94
95 #[error("Indexer generic error: `{0}`")]
96 GenericError(String),
97
98 #[error("GCS error: `{0}`")]
99 GcsError(String),
100
101 #[error("Indexer failed to resolve object to move struct with error: `{0}`")]
102 ResolveMoveStructError(String),
103
104 #[error(transparent)]
105 UncategorizedError(#[from] anyhow::Error),
106
107 #[error(transparent)]
108 ObjectIdParseError(#[from] ObjectIDParseError),
109
110 #[error("Invalid transaction digest with error: `{0}`")]
111 InvalidTransactionDigestError(String),
112
113 #[error(transparent)]
114 SuiError(#[from] SuiError),
115
116 #[error(transparent)]
117 BcsError(#[from] bcs::Error),
118
119 #[error("Invalid argument with error: `{0}`")]
120 InvalidArgumentError(String),
121
122 #[error(transparent)]
123 UserInputError(#[from] UserInputError),
124
125 #[error("Indexer failed to resolve module with error: `{0}`")]
126 ModuleResolutionError(String),
127
128 #[error(transparent)]
129 ObjectResponseError(#[from] SuiObjectResponseError),
130
131 #[error(transparent)]
132 FastCryptoError(#[from] FastCryptoError),
133
134 #[error("`{0}`: `{1}`")]
135 ErrorWithContext(String, Box<IndexerError>),
136
137 #[error("Indexer failed to send item to channel with error: `{0}`")]
138 MpscChannelError(String),
139
140 #[error(transparent)]
141 NameServiceError(#[from] NameServiceError),
142
143 #[error("Inconsistent migration records: {0}")]
144 DbMigrationError(String),
145}
146
147pub trait Context<T> {
148 fn context(self, context: &str) -> Result<T, IndexerError>;
149}
150
151impl<T> Context<T> for Result<T, IndexerError> {
152 fn context(self, context: &str) -> Result<T, IndexerError> {
153 self.map_err(|e| IndexerError::ErrorWithContext(context.to_string(), Box::new(e)))
154 }
155}
156
157impl From<IndexerError> for RpcError {
158 fn from(e: IndexerError) -> Self {
159 RpcError::owned(
160 jsonrpsee::types::error::CALL_EXECUTION_FAILED_CODE,
161 e.to_string(),
162 None::<()>,
163 )
164 }
165}
166
167impl From<tokio::task::JoinError> for IndexerError {
168 fn from(value: tokio::task::JoinError) -> Self {
169 IndexerError::UncategorizedError(anyhow::Error::from(value))
170 }
171}
172
173impl From<diesel_async::pooled_connection::bb8::RunError> for IndexerError {
174 fn from(value: diesel_async::pooled_connection::bb8::RunError) -> Self {
175 Self::PgPoolConnectionError(value.to_string())
176 }
177}
178
179impl From<sui_types::error::SuiErrorKind> for IndexerError {
180 fn from(e: sui_types::error::SuiErrorKind) -> Self {
181 IndexerError::SuiError(SuiError::from(e))
182 }
183}
184
185pub(crate) fn client_error_to_error_object(
186 e: jsonrpsee::core::ClientError,
187) -> jsonrpsee::types::ErrorObjectOwned {
188 match e {
189 jsonrpsee::core::ClientError::Call(e) => e,
190 _ => jsonrpsee::types::ErrorObjectOwned::owned(
191 jsonrpsee::types::error::UNKNOWN_ERROR_CODE,
192 e.to_string(),
193 None::<()>,
194 ),
195 }
196}