sui_indexer/
errors.rs

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
// Copyright (c) Mysten Labs, Inc.
// SPDX-License-Identifier: Apache-2.0

use fastcrypto::error::FastCryptoError;
use jsonrpsee::types::ErrorObjectOwned as RpcError;
use sui_name_service::NameServiceError;
use thiserror::Error;

use sui_types::base_types::ObjectIDParseError;
use sui_types::error::{SuiError, SuiObjectResponseError, UserInputError};

#[derive(Debug, Error)]
pub struct DataDownloadError {
    pub error: IndexerError,
    pub next_checkpoint_sequence_number: u64,
}

impl std::fmt::Display for DataDownloadError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(
            f,
            "next_checkpoint_seq: {}, error: {}",
            self.next_checkpoint_sequence_number, self.error
        )
    }
}

#[derive(Debug, Error)]
pub enum IndexerError {
    #[error("Indexer failed to read from archives store with error: `{0}`")]
    ArchiveReaderError(String),

    #[error("Stream closed unexpectedly with error: `{0}`")]
    ChannelClosed(String),

    #[error("Indexer failed to convert timestamp to NaiveDateTime with error: `{0}`")]
    DateTimeParsingError(String),

    #[error("Indexer failed to deserialize event from events table with error: `{0}`")]
    EventDeserializationError(String),

    #[error("Fullnode returns unexpected responses, which may block indexers from proceeding, with error: `{0}`")]
    UnexpectedFullnodeResponseError(String),

    #[error("Indexer failed to transform data with error: `{0}`")]
    DataTransformationError(String),

    #[error("Indexer failed to read fullnode with error: `{0}`")]
    FullNodeReadingError(String),

    #[error("Indexer failed to convert structs to diesel Insertable with error: `{0}`")]
    InsertableParsingError(String),

    #[error("Indexer failed to build JsonRpcServer with error: `{0}`")]
    JsonRpcServerError(#[from] sui_json_rpc::error::Error),

    #[error("Indexer failed to find object mutations, which should never happen.")]
    ObjectMutationNotAvailable,

    #[error("Indexer failed to build PG connection pool with error: `{0}`")]
    PgConnectionPoolInitError(String),

    #[error("Indexer failed to get a pool connection from PG connection pool with error: `{0}`")]
    PgPoolConnectionError(String),

    #[error("Indexer failed to read PostgresDB with error: `{0}`")]
    PostgresReadError(String),

    #[error("Indexer failed to reset PostgresDB with error: `{0}`")]
    PostgresResetError(String),

    #[error("Indexer failed to commit changes to PostgresDB with error: `{0}`")]
    PostgresWriteError(String),

    #[error(transparent)]
    PostgresError(#[from] diesel::result::Error),

    #[error("Indexer failed to initialize fullnode Http client with error: `{0}`")]
    HttpClientInitError(String),

    #[error("Indexer failed to serialize/deserialize with error: `{0}`")]
    SerdeError(String),

    #[error("Indexer error related to dynamic field: `{0}`")]
    DynamicFieldError(String),

    #[error("Indexer does not support the feature with error: `{0}`")]
    NotSupportedError(String),

    #[error("Indexer read corrupted/incompatible data from persistent storage: `{0}`")]
    PersistentStorageDataCorruptionError(String),

    #[error("Indexer generic error: `{0}`")]
    GenericError(String),

    #[error("GCS error: `{0}`")]
    GcsError(String),

    #[error("Indexer failed to resolve object to move struct with error: `{0}`")]
    ResolveMoveStructError(String),

    #[error(transparent)]
    UncategorizedError(#[from] anyhow::Error),

    #[error(transparent)]
    ObjectIdParseError(#[from] ObjectIDParseError),

    #[error("Invalid transaction digest with error: `{0}`")]
    InvalidTransactionDigestError(String),

    #[error(transparent)]
    SuiError(#[from] SuiError),

    #[error(transparent)]
    BcsError(#[from] bcs::Error),

    #[error("Invalid argument with error: `{0}`")]
    InvalidArgumentError(String),

    #[error(transparent)]
    UserInputError(#[from] UserInputError),

    #[error("Indexer failed to resolve module with error: `{0}`")]
    ModuleResolutionError(String),

    #[error(transparent)]
    ObjectResponseError(#[from] SuiObjectResponseError),

    #[error(transparent)]
    FastCryptoError(#[from] FastCryptoError),

    #[error("`{0}`: `{1}`")]
    ErrorWithContext(String, Box<IndexerError>),

    #[error("Indexer failed to send item to channel with error: `{0}`")]
    MpscChannelError(String),

    #[error(transparent)]
    NameServiceError(#[from] NameServiceError),

    #[error("Inconsistent migration records: {0}")]
    DbMigrationError(String),
}

pub trait Context<T> {
    fn context(self, context: &str) -> Result<T, IndexerError>;
}

impl<T> Context<T> for Result<T, IndexerError> {
    fn context(self, context: &str) -> Result<T, IndexerError> {
        self.map_err(|e| IndexerError::ErrorWithContext(context.to_string(), Box::new(e)))
    }
}

impl From<IndexerError> for RpcError {
    fn from(e: IndexerError) -> Self {
        RpcError::owned(
            jsonrpsee::types::error::CALL_EXECUTION_FAILED_CODE,
            e.to_string(),
            None::<()>,
        )
    }
}

impl From<tokio::task::JoinError> for IndexerError {
    fn from(value: tokio::task::JoinError) -> Self {
        IndexerError::UncategorizedError(anyhow::Error::from(value))
    }
}

impl From<diesel_async::pooled_connection::bb8::RunError> for IndexerError {
    fn from(value: diesel_async::pooled_connection::bb8::RunError) -> Self {
        Self::PgPoolConnectionError(value.to_string())
    }
}

pub(crate) fn client_error_to_error_object(
    e: jsonrpsee::core::ClientError,
) -> jsonrpsee::types::ErrorObjectOwned {
    match e {
        jsonrpsee::core::ClientError::Call(e) => e,
        _ => jsonrpsee::types::ErrorObjectOwned::owned(
            jsonrpsee::types::error::UNKNOWN_ERROR_CODE,
            e.to_string(),
            None::<()>,
        ),
    }
}