rust_eigenda_v2_client/
errors.rs

1use ark_bn254::{Fr, G1Affine};
2use ethereum_types::H160;
3use rust_eigenda_v2_common::ConversionError as CommonConversionError;
4use rust_kzg_bn254_primitives::errors::KzgError;
5
6use crate::relay_client::RelayKey;
7use prost::DecodeError;
8
9/// Errors returned by the client.
10#[derive(Debug, thiserror::Error)]
11pub enum EigenClientError {
12    #[error(transparent)]
13    Conversion(#[from] ConversionError),
14    #[error(transparent)]
15    Blob(#[from] BlobError),
16    #[error(transparent)]
17    PayloadDisperser(#[from] Box<PayloadDisperserError>),
18}
19
20/// Errors specific to conversion
21#[derive(Debug, thiserror::Error)]
22pub enum ConversionError {
23    #[error("Failed to parse payload: {0}")]
24    Payload(String),
25    #[error("Failed to parse encoded payload: {0}")]
26    EncodedPayload(String),
27    #[error("Failed to parse G1 point: {0}")]
28    G1Point(String),
29    #[error("Failed to parse G2 point: {0}")]
30    G2Point(String),
31    #[error("Failed to parse blob header: {0}")]
32    BlobHeader(String),
33    #[error("Failed to parse blob certificate: {0}")]
34    BlobCertificate(String),
35    #[error("Failed to parse blob inclusion: {0}")]
36    BlobInclusion(String),
37    #[error("Failed to parse batch header: {0}")]
38    BatchHeader(String),
39    #[error("Failed to parse blob key: {0}")]
40    BlobKey(String),
41    #[error("Failed to serialize ark: {0}")]
42    ArkSerialization(String),
43    #[error("Failed to parse signed batch: {0}")]
44    SignedBatch(String),
45    #[error("Private Key Error")]
46    PrivateKey,
47    #[error(transparent)]
48    UrlParse(#[from] url::ParseError),
49    #[error(transparent)]
50    EigenDACommon(#[from] rust_eigenda_v2_common::ConversionError),
51    #[error("Failed to convert U256: {0}")]
52    U256Conversion(String),
53    #[error("Failed to parse attestation: {0}")]
54    Attestation(String),
55    #[error("Failed to parse address: {0}")]
56    Address(String),
57}
58
59/// Errors specific to the [`RelayPayloadRetriever`].
60#[derive(Debug, thiserror::Error)]
61pub enum RelayPayloadRetrieverError {
62    #[error(transparent)]
63    RelayClient(#[from] Box<RelayClientError>),
64    #[error(transparent)]
65    Blob(#[from] BlobError),
66    #[error(transparent)]
67    Conversion(#[from] ConversionError),
68    #[error(transparent)]
69    Kzg(#[from] KzgError),
70    #[error("Unable to retrieve payload")]
71    UnableToRetrievePayload,
72    #[error("Invalid certificate: {0}")]
73    InvalidCertificate(String),
74    #[error("Retrieval request to relay timed out")]
75    RetrievalTimeout,
76}
77
78/// Errors specific to the Blob type
79#[derive(Debug, thiserror::Error)]
80pub enum BlobError {
81    #[error("Invalid quorum number: {0}")]
82    InvalidQuorumNumber(u32),
83    #[error("Missing field: {0}")]
84    MissingField(String),
85    #[error(transparent)]
86    Bn254(#[from] Bn254Error),
87    #[error(transparent)]
88    CommonBlob(#[from] rust_eigenda_v2_common::BlobError),
89}
90
91/// Errors related to the BN254 and its points
92#[derive(Debug, thiserror::Error)]
93pub enum Bn254Error {
94    #[error("Insufficient SRS in memory: have {0}, need {1}")]
95    InsufficientSrsInMemory(usize, usize),
96    #[error("Failed calculating multi scalar multiplication on base {:?} with scalars {:?}", .0, .1)]
97    FailedComputingMSM(Vec<G1Affine>, Vec<Fr>),
98}
99
100/// Errors specific to the [`RelayClient`].
101#[derive(Debug, thiserror::Error)]
102pub enum RelayClientError {
103    #[error("Max grpc message size must be greater than 0")]
104    InvalidMaxGrpcMessageSize,
105    #[error("Failed RPC call: {0}")]
106    FailedRPC(#[from] tonic::Status),
107    #[error("Failed connection call")]
108    FailedConnection(#[from] tonic::transport::Error),
109    #[error("Invalid relay key {0}")]
110    InvalidRelayKey(RelayKey),
111    #[error("Request cannot be empty")]
112    EmptyRequest,
113    #[error("Failed to fetch current timestamp")]
114    FailedToFetchCurrentTimestamp,
115    #[error("Invalid disperser URI: {0}")]
116    InvalidURI(String),
117    #[error(transparent)]
118    EthClient(#[from] EthClientError),
119    #[error(transparent)]
120    Conversion(#[from] ConversionError),
121    #[error("Failed to parse relay key to URL: {0}")]
122    RelayKeyToUrl(u32),
123}
124
125impl From<RelayClientError> for RelayPayloadRetrieverError {
126    fn from(err: RelayClientError) -> Self {
127        RelayPayloadRetrieverError::RelayClient(Box::new(err))
128    }
129}
130
131/// Errors for the EthClient
132#[derive(Debug, thiserror::Error)]
133pub enum EthClientError {
134    #[error(transparent)]
135    HTTPClient(#[from] reqwest::Error),
136    #[error(transparent)]
137    SerdeJSON(#[from] serde_json::Error),
138    #[error(transparent)]
139    HexEncoding(#[from] hex::FromHexError),
140    #[error(transparent)]
141    EthAbi(#[from] ethabi::Error),
142    #[error("Invalid response: {0}")]
143    InvalidResponse(String),
144}
145
146/// Errors specific to the Accountant
147#[derive(Debug, thiserror::Error)]
148pub enum AccountantError {
149    #[error("invalid payments: no available bandwidth reservation found for account {0}, and current cumulativePayment balance insufficient to make an on-demand dispersal. Consider increasing reservation or cumulative payment on-chain. For more details, see https://docs.eigenda.xyz/core-concepts/payments#disperser-client-requirements")]
150    PaymentNotAvailable(String),
151    #[error("Payment reply is not complete")]
152    PaymentReply,
153}
154
155/// Errors specific to the Disperser Client
156#[derive(Debug, thiserror::Error)]
157pub enum DisperseError {
158    #[error(transparent)]
159    Accountant(AccountantError),
160    #[error("Failed to initialize disperser config: {0}")]
161    ConfigInitialization(String),
162    #[error(transparent)]
163    Tonic(#[from] tonic::transport::Error),
164    #[error("Failed to parse URL: {0}")]
165    InvalidURI(String),
166    #[error("Empty quorums must be provided")]
167    EmptyQuorums,
168    #[error("Blob commitment is empty")]
169    EmptyBlobCommitment,
170    #[error(transparent)]
171    Conversion(#[from] ConversionError),
172    #[error("Blob commitment length {0} does not match symbol length {1}")]
173    CommitmentLengthMismatch(u32, usize),
174    #[error("Invalid Account id")]
175    AccountID,
176    #[error("Failed RPC call: {0}")]
177    FailedRPC(#[from] Box<tonic::Status>),
178    #[error("Calculated and disperser blob key mismatch")]
179    BlobKeyMismatch,
180    #[error(transparent)]
181    Decode(#[from] DecodeError),
182    #[error("Failed to get current time")]
183    SystemTime(#[from] std::time::SystemTimeError),
184    #[error(transparent)]
185    Signer(#[from] Box<dyn std::error::Error + Send + Sync>),
186    #[error(transparent)]
187    CommonConversion(#[from] CommonConversionError),
188}
189
190impl From<tonic::Status> for DisperseError {
191    fn from(err: tonic::Status) -> Self {
192        DisperseError::FailedRPC(Box::new(err))
193    }
194}
195
196/// Errors specific to the [`PayloadDisperser`].
197#[derive(Debug, thiserror::Error)]
198pub enum PayloadDisperserError {
199    #[error(transparent)]
200    Disperser(#[from] DisperseError),
201    #[error(transparent)]
202    Conversion(#[from] ConversionError),
203    #[error("Blob status is unknown or failed")]
204    BlobStatus,
205    #[error(transparent)]
206    Decode(#[from] DecodeError),
207    #[error(transparent)]
208    CertVerifier(#[from] CertVerifierError),
209    #[error("Expected >0 quorum numbers in blob header")]
210    NoQuorumNumbers,
211    #[error("Batch quorum number count and signed percentage count don't match")]
212    QuorumNumbersMismatch,
213    #[error("Expected batch header to be present in signed batch")]
214    BatchHeaderNotPresent,
215    #[error("Signed percentage not found for quorum: {0}")]
216    SignedPercentageNotFound(u32),
217    #[error("Confirmation threshold not met for quorum {quorum_number}, signed percentage {signed_percentage}, threshold {threshold}")]
218    ConfirmationThresholdNotMet {
219        quorum_number: u32,
220        signed_percentage: u8,
221        threshold: u8,
222    },
223    #[error("Failed to initialize Eigen SDK")]
224    EigenSDKNotInitialized,
225    #[error("Failed to check signature indices")]
226    GetCheckSignaturesIndices,
227}
228
229impl From<PayloadDisperserError> for EigenClientError {
230    fn from(err: PayloadDisperserError) -> Self {
231        EigenClientError::PayloadDisperser(Box::new(err))
232    }
233}
234
235/// Errors specific to the CertVerifier
236#[derive(Debug, thiserror::Error)]
237pub enum CertVerifierError {
238    #[error(transparent)]
239    Conversion(#[from] ConversionError),
240    #[error(transparent)]
241    CommonConversion(#[from] CommonConversionError),
242    #[error("Invalid cert verifier contract address: {0}")]
243    InvalidCertVerifierAddress(H160),
244    #[error("Error while calling contract function: {0}")]
245    Contract(String),
246    #[error("Error while signing: {0}")]
247    Signing(String),
248    #[error("Error while verifying checkDACert: {0}")]
249    VerificationFailed(String),
250    #[error("Error while verifying checkDACert, Null Error returned, this is a bug in the contracts, please report it")]
251    VerificationFailedNullError,
252}