forked from edgeandnode/gateway
-
Notifications
You must be signed in to change notification settings - Fork 0
/
errors.rs
139 lines (119 loc) · 4.07 KB
/
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
use std::{
collections::BTreeMap,
fmt::{self, Write as _},
};
use axum::response::{IntoResponse, Response};
use itertools::Itertools as _;
use thegraph_core::{BlockNumber, IndexerId};
use crate::{blocks::UnresolvedBlock, graphql};
#[derive(thiserror::Error, Debug)]
pub enum Error {
/// Errors that should only occur in exceptional conditions.
#[error("internal error: {0:#}")]
Internal(anyhow::Error),
/// Failed to authenticate or authorize the client request.
#[error("auth error: {0:#}")]
Auth(anyhow::Error),
/// A block required by the query is not found.
#[error("block not found: {0}")]
BlockNotFound(UnresolvedBlock),
/// The requested subgraph or deployment is not found or invalid.
#[error("subgraph not found: {0:#}")]
SubgraphNotFound(anyhow::Error),
/// The GraphQL query is invalid.
#[error("bad query: {0:#}")]
BadQuery(anyhow::Error),
/// There are no indexers allocated to the requested subgraph or deployment.
#[error("no indexers found")]
NoIndexers,
/// Indexers are available, but failed to return a suitable result.
#[error("bad indexers: {0}")]
BadIndexers(IndexerErrors),
}
impl IntoResponse for Error {
fn into_response(self) -> Response {
tracing::info!(response_err = %self);
graphql::error_response(self).into_response()
}
}
#[derive(Debug, Clone, Default)]
pub struct IndexerErrors(pub BTreeMap<IndexerId, IndexerError>);
impl std::ops::Deref for IndexerErrors {
type Target = BTreeMap<IndexerId, IndexerError>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl std::ops::DerefMut for IndexerErrors {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl fmt::Display for IndexerErrors {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let entries = self.iter().map(|(k, v)| format!("{k:?}: {v}")).join(", ");
write!(f, "{{{}}}", entries)
}
}
#[derive(thiserror::Error, Clone, Debug)]
pub enum IndexerError {
/// Errors that should only occur in exceptional conditions.
#[error("InternalError({0})")]
Internal(&'static str),
/// The indexer is considered unavailable.
#[error("Unavailable({0})")]
Unavailable(UnavailableReason),
/// The indexer request timed out.
#[error("Timeout")]
Timeout,
/// The indexer’s response is bad.
#[error("BadResponse({0:#})")]
BadResponse(String),
}
#[derive(thiserror::Error, Clone, Debug)]
pub enum UnavailableReason {
/// The indexer is blocked.
#[error("blocked ({0})")]
Blocked(String),
/// The indexer version is not supported (e.g., the indexer service version is below the minimum
/// version required by the gateway, etc.)
#[error("not supported: {0}")]
NotSupported(String),
/// The indexer information resolution failed (e.g. the indexer failed to report the indexer
/// version within the expected time, the indexer failed to report the indexing progress info
/// within the expected time, etc.)
#[error("no status: {0}")]
NoStatus(String),
/// The indexer has zero stake.
#[error("no stake")]
NoStake,
/// The indexer's cost model did not produce a fee for the GraphQL document.
#[error("no fee")]
NoFee,
/// The indexer did not have a block required by the query.
#[error("{}", .0.message())]
MissingBlock(MissingBlockError),
/// The indexer is too far behind chain head for an unconstrained query.
#[error("too far behind")]
TooFarBehind,
/// An internal error occurred.
#[error("internal error: {0}")]
Internal(&'static str),
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct MissingBlockError {
pub missing: Option<BlockNumber>,
pub latest: Option<BlockNumber>,
}
impl MissingBlockError {
fn message(&self) -> String {
let mut text = "missing block".to_string();
if let Some(n) = self.missing {
write!(&mut text, ": {n}").unwrap();
}
if let Some(n) = self.latest {
write!(&mut text, ", latest: {n}").unwrap();
}
text
}
}