From 25ada9c8fc53928bb94f2e23357e44506eccaa8a Mon Sep 17 00:00:00 2001 From: Gianbelinche <39842759+gianbelinche@users.noreply.github.com> Date: Fri, 29 Nov 2024 15:52:39 -0300 Subject: [PATCH 1/5] Add thiserror --- Cargo.toml | 4 -- src/blob_info.rs | 15 +------- src/client.rs | 18 +++++---- src/config.rs | 8 +++- src/errors.rs | 95 +++++++++++++++++++++++++++++++++++++++++++++++ src/eth_client.rs | 12 +----- src/lib.rs | 1 + src/sdk.rs | 83 +++++++++++++++++++++++------------------ src/verifier.rs | 22 ++--------- 9 files changed, 166 insertions(+), 92 deletions(-) create mode 100644 src/errors.rs diff --git a/Cargo.toml b/Cargo.toml index b30dc5c..df2254c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,7 +32,3 @@ async-trait = "0.1" hex = "0.4" secrecy = "0.8.0" byteorder = "1.5.0" - - - -anyhow = "1" #TODO: Remove diff --git a/src/blob_info.rs b/src/blob_info.rs index 658e3be..58787d5 100644 --- a/src/blob_info.rs +++ b/src/blob_info.rs @@ -2,6 +2,8 @@ use std::fmt; use rlp::{Decodable, DecoderError, Encodable, Rlp, RlpStream}; +use crate::errors::ConversionError; + use super::{ common::G1Commitment as DisperserG1Commitment, disperser::{ @@ -12,19 +14,6 @@ use super::{ }, }; -#[derive(Debug)] -pub enum ConversionError { - NotPresentError, -} - -impl fmt::Display for ConversionError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - ConversionError::NotPresentError => write!(f, "Failed to convert BlobInfo"), - } - } -} - #[derive(Debug, PartialEq, Clone)] pub struct G1Commitment { pub x: Vec, diff --git a/src/client.rs b/src/client.rs index 6c2262f..8fe1b08 100644 --- a/src/client.rs +++ b/src/client.rs @@ -1,3 +1,5 @@ +use crate::errors::EigenClientError; + use super::{ blob_info::BlobInfo, config::{EigenConfig, EigenSecrets}, @@ -14,9 +16,8 @@ pub struct EigenClient { } impl EigenClient { - pub async fn new(config: EigenConfig, secrets: EigenSecrets) -> anyhow::Result { - let private_key = SecretKey::from_str(secrets.private_key.0.expose_secret().as_str()) - .map_err(|e| anyhow::anyhow!("Failed to parse private key: {}", e))?; + pub async fn new(config: EigenConfig, secrets: EigenSecrets) -> Result { + let private_key = SecretKey::from_str(secrets.private_key.0.expose_secret().as_str())?; let client = RawEigenClient::new(private_key, config).await?; Ok(Self { @@ -24,18 +25,18 @@ impl EigenClient { }) } - pub async fn get_commitment(&self, blob_id: &str) -> anyhow::Result { + pub async fn get_commitment(&self, blob_id: &str) -> Result { let blob_info = self.client.get_inclusion_data(blob_id).await?; Ok(blob_info) } - async fn dispatch_blob(&self, data: Vec) -> anyhow::Result { + async fn dispatch_blob(&self, data: Vec) -> Result { let blob_id = self.client.dispatch_blob(data).await?; Ok(blob_id) } - async fn get_inclusion_data(&self, blob_id: &str) -> anyhow::Result> { + async fn get_inclusion_data(&self, blob_id: &str) -> Result, EigenClientError> { let blob_info = self.get_commitment(blob_id).await?; let rlp_encoded_bytes = hex::decode(blob_info)?; let blob_info: BlobInfo = rlp::decode(&rlp_encoded_bytes)?; @@ -61,7 +62,10 @@ mod tests { use crate::blob_info::BlobInfo; impl EigenClient { - pub async fn get_blob_data(&self, blob_id: &str) -> anyhow::Result>> { + pub async fn get_blob_data( + &self, + blob_id: &str, + ) -> Result>, EigenClientError> { self.client.get_blob_data(blob_id).await } } diff --git a/src/config.rs b/src/config.rs index 7317f1d..80e3159 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,6 +1,8 @@ use secrecy::{ExposeSecret, Secret}; use std::str::FromStr; +use crate::errors::EigenClientError; + #[derive(Clone, Debug, PartialEq)] pub enum PointsSource { Path(String), @@ -56,9 +58,11 @@ impl PartialEq for PrivateKey { } impl FromStr for PrivateKey { - type Err = anyhow::Error; + type Err = EigenClientError; fn from_str(s: &str) -> Result { - Ok(PrivateKey(s.parse()?)) + Ok(PrivateKey( + s.parse().map_err(|_| EigenClientError::PrivateKeyError)?, + )) } } diff --git a/src/errors.rs b/src/errors.rs new file mode 100644 index 0000000..c371761 --- /dev/null +++ b/src/errors.rs @@ -0,0 +1,95 @@ +use tonic::{transport::Error as TonicError, Status}; + +#[derive(Debug, thiserror::Error)] +pub enum EigenClientError { + #[error(transparent)] + EthClientError(#[from] EthClientError), + #[error(transparent)] + VerificationError(#[from] VerificationError), + #[error("Private Key Error")] + PrivateKeyError, + #[error(transparent)] + SecpError(#[from] secp256k1::Error), + #[error(transparent)] + HexError(#[from] hex::FromHexError), + #[error(transparent)] + RlpError(#[from] rlp::DecoderError), + #[error(transparent)] + TonicError(#[from] TonicError), + #[error(transparent)] + Status(#[from] Status), + #[error("No response from server")] + NoResponseFromServer, + #[error("No payload in response")] + NoPayloadInResponse, + #[error("Unexpected response from server")] + UnexpectedResponseFromServer, + #[error("Failed to get blob data")] + FailedToGetBlobData, + #[error("Failed to send DisperseBlobRequest: {0}")] + DisperseBlobError(String), + #[error("Failed to send AuthenticationData: {0}")] + AuthenticationDataError(String), + #[error("Error from server: {0}")] + ErrorFromServer(String), + #[error("Blob still processing")] + BlobStillProcessing, + #[error("Blob dispatched failed")] + BlobDispatchedFailed, + #[error("Insufficient signatures")] + InsufficientSignatures, + #[error("No blob header in response")] + NoBlobHeaderInResponse, + #[error("Received unknown blob status")] + ReceivedUnknownBlobStatus, + #[error(transparent)] + ConversionError(#[from] ConversionError), + #[error(transparent)] + ProstError(#[from] prost::DecodeError), +} + +#[derive(Debug, thiserror::Error)] +pub enum ConversionError { + #[error("Failed to convert BlobInfo")] + NotPresentError, +} + +#[derive(Debug, thiserror::Error)] +pub enum EthClientError { + #[error("Failed to serialize request body: {0}")] + FailedToSerializeRequestBody(String), + #[error("reqwest error: {0}")] + ReqwestError(#[from] reqwest::Error), + #[error(transparent)] + SerdeJSONError(#[from] serde_json::Error), + #[error("{0}")] + RPCError(String), +} + +#[derive(Debug, thiserror::Error)] +pub enum VerificationError { + #[error("Service Manager Error")] + ServiceManagerError, + #[error("Kzg Error")] + KzgError, + #[error("Wrong proof")] + WrongProof, + #[error("Different commitments")] + DifferentCommitments, + #[error("Different roots")] + DifferentRoots, + #[error("Empty hashes")] + EmptyHash, + #[error("Different hashes")] + DifferentHashes, + #[error("Wrong quorum params")] + WrongQuorumParams, + #[error("Quorum not confirmed")] + QuorumNotConfirmed, + #[error("Commitment not on curve")] + CommitmentNotOnCurve, + #[error("Commitment not on correct subgroup")] + CommitmentNotOnCorrectSubgroup, + #[error("Link Error")] + LinkError, +} diff --git a/src/eth_client.rs b/src/eth_client.rs index be96bc7..981f9ba 100644 --- a/src/eth_client.rs +++ b/src/eth_client.rs @@ -5,17 +5,7 @@ use reqwest::Client; use serde::{Deserialize, Serialize}; use serde_json::{json, Value}; -#[derive(Debug, thiserror::Error)] -pub enum EthClientError { - #[error("Failed to serialize request body: {0}")] - FailedToSerializeRequestBody(String), - #[error("reqwest error: {0}")] - ReqwestError(#[from] reqwest::Error), - #[error("{0}")] - SerdeJSONError(#[from] serde_json::Error), - #[error("{0}")] - RPCError(String), -} +use crate::errors::EthClientError; #[derive(Debug, Serialize, Deserialize)] #[serde(untagged)] diff --git a/src/lib.rs b/src/lib.rs index 9f5c7c7..e2bc98c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -5,6 +5,7 @@ pub const QUORUM_NUMBERS_REQUIRED_FUNCTION_SELECTOR: [u8; 4] = [225, 82, 52, 255 mod blob_info; mod client; mod config; +mod errors; mod eth_client; mod sdk; mod verifier; diff --git a/src/sdk.rs b/src/sdk.rs index a96b739..19866c3 100644 --- a/src/sdk.rs +++ b/src/sdk.rs @@ -15,6 +15,7 @@ use crate::{ disperser_client::DisperserClient, AuthenticatedReply, BlobAuthHeader, }, + errors::EigenClientError, }; use backon::{ConstantBuilder, Retryable}; use byteorder::{BigEndian, ByteOrder}; @@ -44,7 +45,10 @@ pub(crate) const AVG_BLOCK_TIME: u64 = 12; impl RawEigenClient { const BLOB_SIZE_LIMIT: usize = 1024 * 1024 * 2; // 2 MB - pub async fn new(private_key: SecretKey, config: EigenConfig) -> anyhow::Result { + pub async fn new( + private_key: SecretKey, + config: EigenConfig, + ) -> Result { let endpoint = Endpoint::from_str(config.disperser_rpc.as_str())?.tls_config(ClientTlsConfig::new())?; let client = Arc::new(Mutex::new(DisperserClient::connect(endpoint).await?)); @@ -58,9 +62,7 @@ impl RawEigenClient { }; let eth_client = eth_client::EthClient::new(&config.eigenda_eth_rpc); - let verifier = Verifier::new(verifier_config, eth_client) - .await - .map_err(|e| anyhow::anyhow!(format!("Failed to create verifier {:?}", e)))?; + let verifier = Verifier::new(verifier_config, eth_client).await?; Ok(RawEigenClient { client, private_key, @@ -73,7 +75,10 @@ impl RawEigenClient { Self::BLOB_SIZE_LIMIT } - async fn dispatch_blob_non_authenticated(&self, data: Vec) -> anyhow::Result { + async fn dispatch_blob_non_authenticated( + &self, + data: Vec, + ) -> Result { let padded_data = convert_by_padding_empty_byte(&data); let request = disperser::DisperseBlobRequest { data: padded_data, @@ -96,7 +101,7 @@ impl RawEigenClient { &self, blob_info: BlobInfo, disperse_elapsed: Duration, - ) -> anyhow::Result<()> { + ) -> Result<(), EigenClientError> { (|| async { self.verifier.verify_certificate(blob_info.clone()).await }) .retry( &ConstantBuilder::default() @@ -108,10 +113,10 @@ impl RawEigenClient { ), ) .await - .map_err(|_| anyhow::anyhow!("Failed to verify certificate")) + .map_err(EigenClientError::from) } - async fn dispatch_blob_authenticated(&self, data: Vec) -> anyhow::Result { + async fn dispatch_blob_authenticated(&self, data: Vec) -> Result { let (tx, rx) = mpsc::unbounded_channel(); // 1. send DisperseBlobRequest @@ -138,34 +143,32 @@ impl RawEigenClient { let reply = response_stream .next() .await - .ok_or_else(|| anyhow::anyhow!("No response from server"))? + .ok_or_else(|| EigenClientError::NoResponseFromServer)? .unwrap() .payload - .ok_or_else(|| anyhow::anyhow!("No payload in response"))?; + .ok_or_else(|| EigenClientError::NoPayloadInResponse)?; let disperser::authenticated_reply::Payload::DisperseReply(disperse_reply) = reply else { - return Err(anyhow::anyhow!("Unexpected response from server")); + return Err(EigenClientError::UnexpectedResponseFromServer); }; Ok(hex::encode(disperse_reply.request_id)) } - pub async fn get_inclusion_data(&self, blob_id: &str) -> anyhow::Result { + pub async fn get_inclusion_data(&self, blob_id: &str) -> Result { let disperse_time = Instant::now(); let blob_info = self.await_for_inclusion(blob_id.to_string()).await?; - let blob_info = blob_info::BlobInfo::try_from(blob_info) - .map_err(|e| anyhow::anyhow!("Failed to convert blob info: {}", e))?; + let blob_info = blob_info::BlobInfo::try_from(blob_info)?; let disperse_elapsed = Instant::now() - disperse_time; let data = self .get_blob_data(&hex::encode(rlp::encode(&blob_info))) .await?; if data.is_none() { - return Err(anyhow::anyhow!("Failed to get blob data")); + return Err(EigenClientError::FailedToGetBlobData); } self.verifier - .verify_commitment(blob_info.blob_header.commitment.clone(), data.unwrap()) - .map_err(|_| anyhow::anyhow!("Failed to verify commitment"))?; + .verify_commitment(blob_info.blob_header.commitment.clone(), data.unwrap())?; self.perform_verification(blob_info.clone(), disperse_elapsed) .await?; @@ -174,7 +177,7 @@ impl RawEigenClient { Ok(hex::encode(rlp::encode(&blob_info))) } - pub async fn dispatch_blob(&self, data: Vec) -> anyhow::Result { + pub async fn dispatch_blob(&self, data: Vec) -> Result { if self.config.authenticated { self.dispatch_blob_authenticated(data).await } else { @@ -186,7 +189,7 @@ impl RawEigenClient { &self, data: Vec, tx: &mpsc::UnboundedSender, - ) -> anyhow::Result<()> { + ) -> Result<(), EigenClientError> { let req = disperser::AuthenticatedRequest { payload: Some(DisperseRequest(disperser::DisperseBlobRequest { data, @@ -196,7 +199,7 @@ impl RawEigenClient { }; tx.send(req) - .map_err(|e| anyhow::anyhow!("Failed to send DisperseBlobRequest: {}", e)) + .map_err(|e| EigenClientError::DisperseBlobError(format!("{}", e))) } fn keccak256(&self, input: &[u8]) -> [u8; 32] { @@ -211,7 +214,7 @@ impl RawEigenClient { &self, blob_auth_header: BlobAuthHeader, tx: &mpsc::UnboundedSender, - ) -> anyhow::Result<()> { + ) -> Result<(), EigenClientError> { // TODO: replace challenge_parameter with actual auth header when it is available let mut buf = [0u8; 4]; BigEndian::write_u32(&mut buf, blob_auth_header.challenge_parameter); @@ -234,34 +237,37 @@ impl RawEigenClient { }; tx.send(req) - .map_err(|e| anyhow::anyhow!("Failed to send AuthenticationData: {}", e)) + .map_err(|e| EigenClientError::AuthenticationDataError(format!("{}", e))) } async fn receive_blob_auth_header( &self, response_stream: &mut Streaming, - ) -> anyhow::Result { + ) -> Result { let reply = response_stream .next() .await - .ok_or_else(|| anyhow::anyhow!("No response from server"))?; + .ok_or_else(|| EigenClientError::NoResponseFromServer)?; let Ok(reply) = reply else { - return Err(anyhow::anyhow!("Err from server: {:?}", reply)); + return Err(EigenClientError::ErrorFromServer(format!("{:?}", reply))); }; let reply = reply .payload - .ok_or_else(|| anyhow::anyhow!("No payload in response"))?; + .ok_or_else(|| EigenClientError::NoPayloadInResponse)?; if let disperser::authenticated_reply::Payload::BlobAuthHeader(blob_auth_header) = reply { Ok(blob_auth_header) } else { - Err(anyhow::anyhow!("Unexpected response from server")) + Err(EigenClientError::UnexpectedResponseFromServer) } } - async fn await_for_inclusion(&self, request_id: String) -> anyhow::Result { + async fn await_for_inclusion( + &self, + request_id: String, + ) -> Result { let polling_request = disperser::BlobStatusRequest { request_id: hex::decode(request_id)?, }; @@ -277,29 +283,29 @@ impl RawEigenClient { match disperser::BlobStatus::try_from(resp.status)? { disperser::BlobStatus::Processing | disperser::BlobStatus::Dispersing => { - Err(anyhow::anyhow!("Blob is still processing")) + Err(EigenClientError::BlobStillProcessing) } - disperser::BlobStatus::Failed => Err(anyhow::anyhow!("Blob dispatch failed")), + disperser::BlobStatus::Failed => Err(EigenClientError::BlobDispatchedFailed), disperser::BlobStatus::InsufficientSignatures => { - Err(anyhow::anyhow!("Insufficient signatures")) + Err(EigenClientError::InsufficientSignatures) } disperser::BlobStatus::Confirmed => { if !self.config.wait_for_finalization { let blob_info = resp .info - .ok_or_else(|| anyhow::anyhow!("No blob header in response"))?; + .ok_or_else(|| EigenClientError::NoBlobHeaderInResponse)?; return Ok(blob_info); } - Err(anyhow::anyhow!("Blob is still processing")) + Err(EigenClientError::BlobStillProcessing) } disperser::BlobStatus::Finalized => { let blob_info = resp .info - .ok_or_else(|| anyhow::anyhow!("No blob header in response"))?; + .ok_or_else(|| EigenClientError::NoBlobHeaderInResponse)?; Ok(blob_info) } - _ => Err(anyhow::anyhow!("Received unknown blob status")), + _ => Err(EigenClientError::ReceivedUnknownBlobStatus), } }) .retry( @@ -315,7 +321,10 @@ impl RawEigenClient { Ok(blob_info) } - pub async fn get_blob_data(&self, blob_info: &str) -> anyhow::Result>> { + pub async fn get_blob_data( + &self, + blob_info: &str, + ) -> Result>, EigenClientError> { let commit = hex::decode(blob_info)?; let blob_info: BlobInfo = rlp::decode(&commit)?; let blob_index = blob_info.blob_verification_proof.blob_index; @@ -335,7 +344,7 @@ impl RawEigenClient { .into_inner(); if get_response.data.is_empty() { - return Err(anyhow::anyhow!("Failed to get blob data")); + return Err(EigenClientError::FailedToGetBlobData); } let data = remove_empty_byte_from_padded_bytes(&get_response.data); diff --git a/src/verifier.rs b/src/verifier.rs index f518da2..f9086a5 100644 --- a/src/verifier.rs +++ b/src/verifier.rs @@ -7,31 +7,17 @@ use ethereum_types::{Address, U256}; use rust_kzg_bn254::{blob::Blob, kzg::Kzg, polynomial::PolynomialFormat}; use tiny_keccak::{Hasher, Keccak}; +use crate::errors::VerificationError; + use super::{ blob_info::{BatchHeader, BlobHeader, BlobInfo, G1Commitment}, config::PointsSource, - eth_client::{EthClient, EthClientError}, + errors::EthClientError, + eth_client::EthClient, BATCH_ID_TO_METADATA_HASH_FUNCTION_SELECTOR, QUORUM_ADVERSARY_THRESHOLD_PERCENTAGES_FUNCTION_SELECTOR, QUORUM_NUMBERS_REQUIRED_FUNCTION_SELECTOR, }; - -#[derive(Debug)] -pub enum VerificationError { - ServiceManagerError, - KzgError, - WrongProof, - DifferentCommitments, - DifferentRoots, - EmptyHash, - DifferentHashes, - WrongQuorumParams, - QuorumNotConfirmed, - CommitmentNotOnCurve, - CommitmentNotOnCorrectSubgroup, - LinkError, -} - #[async_trait::async_trait] pub trait VerifierClient: Sync + Send + std::fmt::Debug { fn clone_boxed(&self) -> Box; From a44decfea328e2c98d6c084daa8b6e7a48006ce7 Mon Sep 17 00:00:00 2001 From: Gianbelinche <39842759+gianbelinche@users.noreply.github.com> Date: Fri, 29 Nov 2024 16:00:13 -0300 Subject: [PATCH 2/5] Fix warnings --- src/blob_info.rs | 94 ------------------------------------------------ src/sdk.rs | 1 - src/verifier.rs | 2 +- 3 files changed, 1 insertion(+), 96 deletions(-) diff --git a/src/blob_info.rs b/src/blob_info.rs index 58787d5..f5f3db9 100644 --- a/src/blob_info.rs +++ b/src/blob_info.rs @@ -1,5 +1,3 @@ -use std::fmt; - use rlp::{Decodable, DecoderError, Encodable, Rlp, RlpStream}; use crate::errors::ConversionError; @@ -20,18 +18,6 @@ pub struct G1Commitment { pub y: Vec, } -impl G1Commitment { - pub fn to_bytes(&self) -> Vec { - let mut bytes = vec![]; - bytes.extend(&self.x.len().to_be_bytes()); - bytes.extend(&self.x); - bytes.extend(&self.y.len().to_be_bytes()); - bytes.extend(&self.y); - - bytes - } -} - impl Decodable for G1Commitment { fn decode(rlp: &Rlp) -> Result { let x: Vec = rlp.val_at(0)?; // Decode first element as Vec @@ -66,18 +52,6 @@ pub struct BlobQuorumParam { pub chunk_length: u32, } -impl BlobQuorumParam { - pub fn to_bytes(&self) -> Vec { - let mut bytes = vec![]; - bytes.extend(&self.quorum_number.to_be_bytes()); - bytes.extend(&self.adversary_threshold_percentage.to_be_bytes()); - bytes.extend(&self.confirmation_threshold_percentage.to_be_bytes()); - bytes.extend(&self.chunk_length.to_be_bytes()); - - bytes - } -} - impl Decodable for BlobQuorumParam { fn decode(rlp: &Rlp) -> Result { Ok(BlobQuorumParam { @@ -117,21 +91,6 @@ pub struct BlobHeader { pub blob_quorum_params: Vec, } -impl BlobHeader { - pub fn to_bytes(&self) -> Vec { - let mut bytes = vec![]; - bytes.extend(self.commitment.to_bytes()); - bytes.extend(&self.data_length.to_be_bytes()); - bytes.extend(&self.blob_quorum_params.len().to_be_bytes()); - - for quorum in &self.blob_quorum_params { - bytes.extend(quorum.to_bytes()); - } - - bytes - } -} - impl Decodable for BlobHeader { fn decode(rlp: &Rlp) -> Result { let commitment: G1Commitment = rlp.val_at(0)?; @@ -182,21 +141,6 @@ pub struct BatchHeader { pub reference_block_number: u32, } -impl BatchHeader { - pub fn to_bytes(&self) -> Vec { - let mut bytes = vec![]; - bytes.extend(&self.batch_root.len().to_be_bytes()); - bytes.extend(&self.batch_root); - bytes.extend(&self.quorum_numbers.len().to_be_bytes()); - bytes.extend(&self.quorum_numbers); - bytes.extend(&self.quorum_signed_percentages.len().to_be_bytes()); - bytes.extend(&self.quorum_signed_percentages); - bytes.extend(&self.reference_block_number.to_be_bytes()); - - bytes - } -} - impl Decodable for BatchHeader { fn decode(rlp: &Rlp) -> Result { Ok(BatchHeader { @@ -238,17 +182,6 @@ pub struct BatchMetadata { pub batch_header_hash: Vec, } -impl BatchMetadata { - pub fn to_bytes(&self) -> Vec { - let mut bytes = vec![]; - bytes.extend(self.batch_header.to_bytes()); - bytes.extend(&self.signatory_record_hash); - bytes.extend(&self.confirmation_block_number.to_be_bytes()); - - bytes - } -} - impl Decodable for BatchMetadata { fn decode(rlp: &Rlp) -> Result { let batch_header: BatchHeader = rlp.val_at(0)?; @@ -299,21 +232,6 @@ pub struct BlobVerificationProof { pub quorum_indexes: Vec, } -impl BlobVerificationProof { - pub fn to_bytes(&self) -> Vec { - let mut bytes = vec![]; - bytes.extend(&self.batch_id.to_be_bytes()); - bytes.extend(&self.blob_index.to_be_bytes()); - bytes.extend(self.batch_medatada.to_bytes()); - bytes.extend(&self.inclusion_proof.len().to_be_bytes()); - bytes.extend(&self.inclusion_proof); - bytes.extend(&self.quorum_indexes.len().to_be_bytes()); - bytes.extend(&self.quorum_indexes); - - bytes - } -} - impl Decodable for BlobVerificationProof { fn decode(rlp: &Rlp) -> Result { Ok(BlobVerificationProof { @@ -359,18 +277,6 @@ pub struct BlobInfo { pub blob_verification_proof: BlobVerificationProof, } -impl BlobInfo { - pub fn to_bytes(&self) -> Vec { - let mut bytes = vec![]; - let blob_header_bytes = self.blob_header.to_bytes(); - bytes.extend(blob_header_bytes.len().to_be_bytes()); - bytes.extend(blob_header_bytes); - let blob_verification_proof_bytes = self.blob_verification_proof.to_bytes(); - bytes.extend(blob_verification_proof_bytes); - bytes - } -} - impl Decodable for BlobInfo { fn decode(rlp: &Rlp) -> Result { let blob_header: BlobHeader = rlp.val_at(0)?; diff --git a/src/sdk.rs b/src/sdk.rs index 19866c3..de0c6ae 100644 --- a/src/sdk.rs +++ b/src/sdk.rs @@ -173,7 +173,6 @@ impl RawEigenClient { self.perform_verification(blob_info.clone(), disperse_elapsed) .await?; - let verification_proof = blob_info.blob_verification_proof.clone(); Ok(hex::encode(rlp::encode(&blob_info))) } diff --git a/src/verifier.rs b/src/verifier.rs index f9086a5..c3c4933 100644 --- a/src/verifier.rs +++ b/src/verifier.rs @@ -128,7 +128,7 @@ impl Verifier { srs_points_to_load, "".to_string(), ); - let kzg = kzg.map_err(|e| VerificationError::KzgError)?; + let kzg = kzg.map_err(|_| VerificationError::KzgError)?; Ok(Self { kzg, From 6a439ae511c8ce96f9830acfc6d1828c21772247 Mon Sep 17 00:00:00 2001 From: Gianbelinche <39842759+gianbelinche@users.noreply.github.com> Date: Fri, 29 Nov 2024 16:04:48 -0300 Subject: [PATCH 3/5] Fix remaining warnings --- src/client.rs | 6 +++--- src/lib.rs | 14 +++++++------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/client.rs b/src/client.rs index 8fe1b08..903d35a 100644 --- a/src/client.rs +++ b/src/client.rs @@ -30,13 +30,13 @@ impl EigenClient { Ok(blob_info) } - async fn dispatch_blob(&self, data: Vec) -> Result { + pub async fn dispatch_blob(&self, data: Vec) -> Result { let blob_id = self.client.dispatch_blob(data).await?; Ok(blob_id) } - async fn get_inclusion_data(&self, blob_id: &str) -> Result, EigenClientError> { + pub async fn get_inclusion_data(&self, blob_id: &str) -> Result, EigenClientError> { let blob_info = self.get_commitment(blob_id).await?; let rlp_encoded_bytes = hex::decode(blob_info)?; let blob_info: BlobInfo = rlp::decode(&rlp_encoded_bytes)?; @@ -44,7 +44,7 @@ impl EigenClient { Ok(inclusion_data) } - fn blob_size_limit(&self) -> Option { + pub fn blob_size_limit(&self) -> Option { Some(RawEigenClient::blob_size_limit()) } } diff --git a/src/lib.rs b/src/lib.rs index e2bc98c..7ad8ad6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,13 +2,13 @@ pub const BATCH_ID_TO_METADATA_HASH_FUNCTION_SELECTOR: [u8; 4] = [236, 203, 191, pub const QUORUM_ADVERSARY_THRESHOLD_PERCENTAGES_FUNCTION_SELECTOR: [u8; 4] = [134, 135, 254, 174]; pub const QUORUM_NUMBERS_REQUIRED_FUNCTION_SELECTOR: [u8; 4] = [225, 82, 52, 255]; -mod blob_info; -mod client; -mod config; -mod errors; -mod eth_client; -mod sdk; -mod verifier; +pub mod blob_info; +pub mod client; +pub mod config; +pub mod errors; +pub mod eth_client; +pub mod sdk; +pub mod verifier; pub use self::client::EigenClient; From c925859116836935a0a99aaed6b835839460e242 Mon Sep 17 00:00:00 2001 From: Gianbelinche <39842759+gianbelinche@users.noreply.github.com> Date: Mon, 2 Dec 2024 14:59:29 -0300 Subject: [PATCH 4/5] Fix PR comments --- src/blob_info.rs | 10 ++++++---- src/config.rs | 2 +- src/errors.rs | 48 +++++++++++++++++++++++------------------------ src/eth_client.rs | 8 ++++---- src/sdk.rs | 9 ++++++--- src/verifier.rs | 45 +++++++++++++++++++++++--------------------- 6 files changed, 65 insertions(+), 57 deletions(-) diff --git a/src/blob_info.rs b/src/blob_info.rs index f5f3db9..38ab97d 100644 --- a/src/blob_info.rs +++ b/src/blob_info.rs @@ -118,7 +118,7 @@ impl TryFrom for BlobHeader { type Error = ConversionError; fn try_from(value: DisperserBlobHeader) -> Result { if value.commitment.is_none() { - return Err(ConversionError::NotPresentError); + return Err(ConversionError::NotPresent("BlobHeader".to_string())); } let blob_quorum_params: Vec = value .blob_quorum_params @@ -211,7 +211,7 @@ impl TryFrom for BatchMetadata { type Error = ConversionError; fn try_from(value: DisperserBatchMetadata) -> Result { if value.batch_header.is_none() { - return Err(ConversionError::NotPresentError); + return Err(ConversionError::NotPresent("BatchMetadata".to_string())); } Ok(Self { batch_header: BatchHeader::from(value.batch_header.unwrap()), @@ -259,7 +259,9 @@ impl TryFrom for BlobVerificationProof { type Error = ConversionError; fn try_from(value: DisperserBlobVerificationProof) -> Result { if value.batch_metadata.is_none() { - return Err(ConversionError::NotPresentError); + return Err(ConversionError::NotPresent( + "BlobVerificationProof".to_string(), + )); } Ok(Self { batch_id: value.batch_id, @@ -301,7 +303,7 @@ impl TryFrom for BlobInfo { type Error = ConversionError; fn try_from(value: DisperserBlobInfo) -> Result { if value.blob_header.is_none() || value.blob_verification_proof.is_none() { - return Err(ConversionError::NotPresentError); + return Err(ConversionError::NotPresent("BlobInfo".to_string())); } Ok(Self { blob_header: BlobHeader::try_from(value.blob_header.unwrap())?, diff --git a/src/config.rs b/src/config.rs index 80e3159..13d871a 100644 --- a/src/config.rs +++ b/src/config.rs @@ -62,7 +62,7 @@ impl FromStr for PrivateKey { fn from_str(s: &str) -> Result { Ok(PrivateKey( - s.parse().map_err(|_| EigenClientError::PrivateKeyError)?, + s.parse().map_err(|_| EigenClientError::PrivateKey)?, )) } } diff --git a/src/errors.rs b/src/errors.rs index c371761..d77408a 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -3,19 +3,19 @@ use tonic::{transport::Error as TonicError, Status}; #[derive(Debug, thiserror::Error)] pub enum EigenClientError { #[error(transparent)] - EthClientError(#[from] EthClientError), + EthClient(#[from] EthClientError), #[error(transparent)] - VerificationError(#[from] VerificationError), + Verification(#[from] VerificationError), #[error("Private Key Error")] - PrivateKeyError, + PrivateKey, #[error(transparent)] - SecpError(#[from] secp256k1::Error), + Secp(#[from] secp256k1::Error), #[error(transparent)] - HexError(#[from] hex::FromHexError), + Hex(#[from] hex::FromHexError), #[error(transparent)] - RlpError(#[from] rlp::DecoderError), + Rlp(#[from] rlp::DecoderError), #[error(transparent)] - TonicError(#[from] TonicError), + Tonic(#[from] TonicError), #[error(transparent)] Status(#[from] Status), #[error("No response from server")] @@ -27,9 +27,9 @@ pub enum EigenClientError { #[error("Failed to get blob data")] FailedToGetBlobData, #[error("Failed to send DisperseBlobRequest: {0}")] - DisperseBlobError(String), + DisperseBlob(String), #[error("Failed to send AuthenticationData: {0}")] - AuthenticationDataError(String), + AuthenticationData(String), #[error("Error from server: {0}")] ErrorFromServer(String), #[error("Blob still processing")] @@ -43,35 +43,35 @@ pub enum EigenClientError { #[error("Received unknown blob status")] ReceivedUnknownBlobStatus, #[error(transparent)] - ConversionError(#[from] ConversionError), + Conversion(#[from] ConversionError), #[error(transparent)] - ProstError(#[from] prost::DecodeError), + Prost(#[from] prost::DecodeError), } #[derive(Debug, thiserror::Error)] pub enum ConversionError { - #[error("Failed to convert BlobInfo")] - NotPresentError, + #[error("Failed to convert {0}")] + NotPresent(String), } #[derive(Debug, thiserror::Error)] pub enum EthClientError { #[error("Failed to serialize request body: {0}")] FailedToSerializeRequestBody(String), - #[error("reqwest error: {0}")] - ReqwestError(#[from] reqwest::Error), #[error(transparent)] - SerdeJSONError(#[from] serde_json::Error), - #[error("{0}")] - RPCError(String), + HTTPClient(#[from] reqwest::Error), + #[error(transparent)] + SerdeJSON(#[from] serde_json::Error), + #[error("RPC: {0}")] + RPC(String), } #[derive(Debug, thiserror::Error)] pub enum VerificationError { - #[error("Service Manager Error")] - ServiceManagerError, - #[error("Kzg Error")] - KzgError, + #[error("Service Manager Error: {0}")] + ServiceManager(String), + #[error("Kzg Error: {0}")] + Kzg(String), #[error("Wrong proof")] WrongProof, #[error("Different commitments")] @@ -90,6 +90,6 @@ pub enum VerificationError { CommitmentNotOnCurve, #[error("Commitment not on correct subgroup")] CommitmentNotOnCorrectSubgroup, - #[error("Link Error")] - LinkError, + #[error("Link Error: {0}")] + Link(String), } diff --git a/src/eth_client.rs b/src/eth_client.rs index 981f9ba..117aa96 100644 --- a/src/eth_client.rs +++ b/src/eth_client.rs @@ -89,10 +89,10 @@ impl EthClient { match self.send_request(request).await { Ok(RpcResponse::Success(result)) => { - serde_json::from_value(result.result).map_err(EthClientError::SerdeJSONError) + serde_json::from_value(result.result).map_err(EthClientError::SerdeJSON) } Ok(RpcResponse::Error(error_response)) => { - Err(EthClientError::RPCError(error_response.error.message)) + Err(EthClientError::RPC(error_response.error.message)) } Err(error) => Err(error), } @@ -124,10 +124,10 @@ impl EthClient { match self.send_request(request).await { Ok(RpcResponse::Success(result)) => { - serde_json::from_value(result.result).map_err(EthClientError::SerdeJSONError) + serde_json::from_value(result.result).map_err(EthClientError::SerdeJSON) } Ok(RpcResponse::Error(error_response)) => { - Err(EthClientError::RPCError(error_response.error.message)) + Err(EthClientError::RPC(error_response.error.message)) } Err(error) => Err(error), } diff --git a/src/sdk.rs b/src/sdk.rs index de0c6ae..bb76aa6 100644 --- a/src/sdk.rs +++ b/src/sdk.rs @@ -198,7 +198,7 @@ impl RawEigenClient { }; tx.send(req) - .map_err(|e| EigenClientError::DisperseBlobError(format!("{}", e))) + .map_err(|e| EigenClientError::DisperseBlob(format!("{}", e))) } fn keccak256(&self, input: &[u8]) -> [u8; 32] { @@ -236,7 +236,7 @@ impl RawEigenClient { }; tx.send(req) - .map_err(|e| EigenClientError::AuthenticationDataError(format!("{}", e))) + .map_err(|e| EigenClientError::AuthenticationData(format!("{}", e))) } async fn receive_blob_auth_header( @@ -314,7 +314,10 @@ impl RawEigenClient { (self.config.status_query_timeout / self.config.status_query_interval) as usize, ), ) - .when(|e| e.to_string().contains("Blob is still processing")) + .when(|e| match e { + EigenClientError::BlobStillProcessing => true, + _ => false, + }) .await?; Ok(blob_info) diff --git a/src/verifier.rs b/src/verifier.rs index c3c4933..4415c19 100644 --- a/src/verifier.rs +++ b/src/verifier.rs @@ -88,26 +88,28 @@ impl Verifier { let url_g1 = format!("{}{}", link, "/g1.point"); let response = reqwest::get(url_g1) .await - .map_err(|_| VerificationError::LinkError)?; + .map_err(|e| VerificationError::Link(e.to_string()))?; let path = Path::new("./g1.point"); - let mut file = File::create(path).map_err(|_| VerificationError::LinkError)?; + let mut file = File::create(path).map_err(|e| VerificationError::Link(e.to_string()))?; let content = response .bytes() .await - .map_err(|_| VerificationError::LinkError)?; - copy(&mut content.as_ref(), &mut file).map_err(|_| VerificationError::LinkError)?; + .map_err(|e| VerificationError::Link(e.to_string()))?; + copy(&mut content.as_ref(), &mut file) + .map_err(|e| VerificationError::Link(e.to_string()))?; let url_g2 = format!("{}{}", link, "/g2.point.powerOf2"); let response = reqwest::get(url_g2) .await - .map_err(|_| VerificationError::LinkError)?; + .map_err(|e| VerificationError::Link(e.to_string()))?; let path = Path::new("./g2.point.powerOf2"); - let mut file = File::create(path).map_err(|_| VerificationError::LinkError)?; + let mut file = File::create(path).map_err(|e| VerificationError::Link(e.to_string()))?; let content = response .bytes() .await - .map_err(|_| VerificationError::LinkError)?; - copy(&mut content.as_ref(), &mut file).map_err(|_| VerificationError::LinkError)?; + .map_err(|e| VerificationError::Link(e.to_string()))?; + copy(&mut content.as_ref(), &mut file) + .map_err(|e| VerificationError::Link(e.to_string()))?; Ok(".".to_string()) } @@ -128,7 +130,7 @@ impl Verifier { srs_points_to_load, "".to_string(), ); - let kzg = kzg.map_err(|_| VerificationError::KzgError)?; + let kzg = kzg.map_err(|e| VerificationError::Kzg(e.to_string()))?; Ok(Self { kzg, @@ -142,7 +144,7 @@ impl Verifier { let blob = Blob::from_bytes_and_pad(&blob.to_vec()); self.kzg .blob_to_kzg_commitment(&blob, PolynomialFormat::InEvaluationForm) - .map_err(|_| VerificationError::KzgError) + .map_err(|e| VerificationError::Kzg(e.to_string())) } /// Compare the given commitment with the commitment generated with the blob @@ -318,15 +320,16 @@ impl Verifier { .eth_client .call( Address::from_str(&self.cfg.svc_manager_addr) - .map_err(|_| VerificationError::ServiceManagerError)?, + .map_err(|e| VerificationError::ServiceManager(e.to_string()))?, bytes::Bytes::copy_from_slice(&data), Some(context_block), ) .await - .map_err(|_| VerificationError::ServiceManagerError)?; + .map_err(|e| VerificationError::ServiceManager(e.to_string()))?; let res = res.trim_start_matches("0x"); - let expected_hash = hex::decode(res).map_err(|_| VerificationError::ServiceManagerError)?; + let expected_hash = + hex::decode(res).map_err(|e| VerificationError::ServiceManager(e.to_string()))?; if expected_hash == vec![0u8; 32] { return Err(VerificationError::EmptyHash); @@ -401,21 +404,21 @@ impl Verifier { .eth_client .call( Address::from_str(&self.cfg.svc_manager_addr) - .map_err(|_| VerificationError::ServiceManagerError)?, + .map_err(|e| VerificationError::ServiceManager(e.to_string()))?, bytes::Bytes::copy_from_slice(&data), None, ) .await - .map_err(|_| VerificationError::ServiceManagerError)?; + .map_err(|e| VerificationError::ServiceManager(e.to_string()))?; let res = res.trim_start_matches("0x"); let percentages_vec = - hex::decode(res).map_err(|_| VerificationError::ServiceManagerError)?; + hex::decode(res).map_err(|e| VerificationError::ServiceManager(e.to_string()))?; let percentages = self .decode_bytes(percentages_vec) - .map_err(|_| VerificationError::ServiceManagerError)?; + .map_err(|e| VerificationError::ServiceManager(e.to_string()))?; if percentages.len() > quorum_number as usize { return Ok(percentages[quorum_number as usize]); @@ -466,21 +469,21 @@ impl Verifier { .eth_client .call( Address::from_str(&self.cfg.svc_manager_addr) - .map_err(|_| VerificationError::ServiceManagerError)?, + .map_err(|e| VerificationError::ServiceManager(e.to_string()))?, bytes::Bytes::copy_from_slice(&data), None, ) .await - .map_err(|_| VerificationError::ServiceManagerError)?; + .map_err(|e| VerificationError::ServiceManager(e.to_string()))?; let res = res.trim_start_matches("0x"); let required_quorums_vec = - hex::decode(res).map_err(|_| VerificationError::ServiceManagerError)?; + hex::decode(res).map_err(|e| VerificationError::ServiceManager(e.to_string()))?; let required_quorums = self .decode_bytes(required_quorums_vec) - .map_err(|_| VerificationError::ServiceManagerError)?; + .map_err(|e| VerificationError::ServiceManager(e.to_string()))?; for quorum in required_quorums { if !confirmed_quorums.contains_key(&(quorum as u32)) { From 402ec488b5b221819dbc434dda9f996bb6a5c4c0 Mon Sep 17 00:00:00 2001 From: Gianbelinche <39842759+gianbelinche@users.noreply.github.com> Date: Mon, 23 Dec 2024 18:49:24 -0300 Subject: [PATCH 5/5] Fix comments --- src/client.rs | 10 +++--- src/config.rs | 6 ++-- src/errors.rs | 49 ++++++++++++++++++--------- src/eth_client.rs | 18 +++++----- src/sdk.rs | 84 +++++++++++++++++++++++++++-------------------- 5 files changed, 99 insertions(+), 68 deletions(-) diff --git a/src/client.rs b/src/client.rs index 903d35a..0187608 100644 --- a/src/client.rs +++ b/src/client.rs @@ -1,4 +1,4 @@ -use crate::errors::EigenClientError; +use crate::errors::{CommunicationError, ConfigError, EigenClientError}; use super::{ blob_info::BlobInfo, @@ -17,7 +17,8 @@ pub struct EigenClient { impl EigenClient { pub async fn new(config: EigenConfig, secrets: EigenSecrets) -> Result { - let private_key = SecretKey::from_str(secrets.private_key.0.expose_secret().as_str())?; + let private_key = SecretKey::from_str(secrets.private_key.0.expose_secret().as_str()) + .map_err(ConfigError::Secp)?; let client = RawEigenClient::new(private_key, config).await?; Ok(Self { @@ -38,8 +39,9 @@ impl EigenClient { pub async fn get_inclusion_data(&self, blob_id: &str) -> Result, EigenClientError> { let blob_info = self.get_commitment(blob_id).await?; - let rlp_encoded_bytes = hex::decode(blob_info)?; - let blob_info: BlobInfo = rlp::decode(&rlp_encoded_bytes)?; + let rlp_encoded_bytes = hex::decode(blob_info).map_err(CommunicationError::Hex)?; + let blob_info: BlobInfo = + rlp::decode(&rlp_encoded_bytes).map_err(CommunicationError::Rlp)?; let inclusion_data = blob_info.blob_verification_proof.inclusion_proof; Ok(inclusion_data) } diff --git a/src/config.rs b/src/config.rs index 13d871a..d9306f8 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1,7 +1,7 @@ use secrecy::{ExposeSecret, Secret}; use std::str::FromStr; -use crate::errors::EigenClientError; +use crate::errors::{ConfigError, EigenClientError}; #[derive(Clone, Debug, PartialEq)] pub enum PointsSource { @@ -61,8 +61,6 @@ impl FromStr for PrivateKey { type Err = EigenClientError; fn from_str(s: &str) -> Result { - Ok(PrivateKey( - s.parse().map_err(|_| EigenClientError::PrivateKey)?, - )) + Ok(PrivateKey(s.parse().map_err(|_| ConfigError::PrivateKey)?)) } } diff --git a/src/errors.rs b/src/errors.rs index d77408a..9716239 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -1,37 +1,58 @@ +use tokio::sync::mpsc::error::SendError; use tonic::{transport::Error as TonicError, Status}; +use crate::{disperser, eth_client::RpcErrorResponse}; + #[derive(Debug, thiserror::Error)] pub enum EigenClientError { #[error(transparent)] EthClient(#[from] EthClientError), #[error(transparent)] Verification(#[from] VerificationError), + #[error(transparent)] + Communication(#[from] CommunicationError), + #[error(transparent)] + BlobStatus(#[from] BlobStatusError), + #[error(transparent)] + Conversion(#[from] ConversionError), + #[error(transparent)] + Config(#[from] ConfigError), +} + +#[derive(Debug, thiserror::Error)] +pub enum ConfigError { #[error("Private Key Error")] PrivateKey, #[error(transparent)] Secp(#[from] secp256k1::Error), #[error(transparent)] - Hex(#[from] hex::FromHexError), - #[error(transparent)] - Rlp(#[from] rlp::DecoderError), - #[error(transparent)] Tonic(#[from] TonicError), - #[error(transparent)] - Status(#[from] Status), +} + +#[derive(Debug, thiserror::Error)] +pub enum CommunicationError { #[error("No response from server")] NoResponseFromServer, #[error("No payload in response")] NoPayloadInResponse, - #[error("Unexpected response from server")] - UnexpectedResponseFromServer, #[error("Failed to get blob data")] FailedToGetBlobData, #[error("Failed to send DisperseBlobRequest: {0}")] - DisperseBlob(String), + DisperseBlob(SendError), #[error("Failed to send AuthenticationData: {0}")] - AuthenticationData(String), + AuthenticationData(SendError), #[error("Error from server: {0}")] ErrorFromServer(String), + #[error(transparent)] + Secp(#[from] secp256k1::Error), + #[error(transparent)] + Hex(#[from] hex::FromHexError), + #[error(transparent)] + Rlp(#[from] rlp::DecoderError), +} + +#[derive(Debug, thiserror::Error)] +pub enum BlobStatusError { #[error("Blob still processing")] BlobStillProcessing, #[error("Blob dispatched failed")] @@ -43,9 +64,9 @@ pub enum EigenClientError { #[error("Received unknown blob status")] ReceivedUnknownBlobStatus, #[error(transparent)] - Conversion(#[from] ConversionError), - #[error(transparent)] Prost(#[from] prost::DecodeError), + #[error(transparent)] + Status(#[from] Status), } #[derive(Debug, thiserror::Error)] @@ -56,14 +77,12 @@ pub enum ConversionError { #[derive(Debug, thiserror::Error)] pub enum EthClientError { - #[error("Failed to serialize request body: {0}")] - FailedToSerializeRequestBody(String), #[error(transparent)] HTTPClient(#[from] reqwest::Error), #[error(transparent)] SerdeJSON(#[from] serde_json::Error), #[error("RPC: {0}")] - RPC(String), + RPC(RpcErrorResponse), } #[derive(Debug, thiserror::Error)] diff --git a/src/eth_client.rs b/src/eth_client.rs index 117aa96..2f91dd0 100644 --- a/src/eth_client.rs +++ b/src/eth_client.rs @@ -36,6 +36,12 @@ pub struct RpcErrorResponse { pub error: RpcErrorMetadata, } +impl std::fmt::Display for RpcErrorResponse { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "RpcErrorResponse: {:?}", self) + } +} + #[derive(Deserialize, Debug)] #[serde(untagged)] pub enum RpcResponse { @@ -69,9 +75,7 @@ impl EthClient { self.client .post(&self.url) .header("content-type", "application/json") - .body(serde_json::ser::to_string(&request).map_err(|error| { - EthClientError::FailedToSerializeRequestBody(format!("{error}: {request:?}")) - })?) + .body(serde_json::ser::to_string(&request).map_err(EthClientError::SerdeJSON)?) .send() .await? .json::() @@ -91,9 +95,7 @@ impl EthClient { Ok(RpcResponse::Success(result)) => { serde_json::from_value(result.result).map_err(EthClientError::SerdeJSON) } - Ok(RpcResponse::Error(error_response)) => { - Err(EthClientError::RPC(error_response.error.message)) - } + Ok(RpcResponse::Error(error_response)) => Err(EthClientError::RPC(error_response)), Err(error) => Err(error), } } @@ -126,9 +128,7 @@ impl EthClient { Ok(RpcResponse::Success(result)) => { serde_json::from_value(result.result).map_err(EthClientError::SerdeJSON) } - Ok(RpcResponse::Error(error_response)) => { - Err(EthClientError::RPC(error_response.error.message)) - } + Ok(RpcResponse::Error(error_response)) => Err(EthClientError::RPC(error_response)), Err(error) => Err(error), } } diff --git a/src/sdk.rs b/src/sdk.rs index bb76aa6..fe70280 100644 --- a/src/sdk.rs +++ b/src/sdk.rs @@ -15,7 +15,7 @@ use crate::{ disperser_client::DisperserClient, AuthenticatedReply, BlobAuthHeader, }, - errors::EigenClientError, + errors::{BlobStatusError, CommunicationError, ConfigError, EigenClientError}, }; use backon::{ConstantBuilder, Retryable}; use byteorder::{BigEndian, ByteOrder}; @@ -49,9 +49,15 @@ impl RawEigenClient { private_key: SecretKey, config: EigenConfig, ) -> Result { - let endpoint = - Endpoint::from_str(config.disperser_rpc.as_str())?.tls_config(ClientTlsConfig::new())?; - let client = Arc::new(Mutex::new(DisperserClient::connect(endpoint).await?)); + let endpoint = Endpoint::from_str(config.disperser_rpc.as_str()) + .map_err(ConfigError::Tonic)? + .tls_config(ClientTlsConfig::new()) + .map_err(ConfigError::Tonic)?; + let client = Arc::new(Mutex::new( + DisperserClient::connect(endpoint) + .await + .map_err(ConfigError::Tonic)?, + )); let verifier_config = VerifierConfig { svc_manager_addr: config.eigenda_svc_manager_address.clone(), @@ -91,7 +97,8 @@ impl RawEigenClient { .lock() .await .disperse_blob(request) - .await? + .await + .map_err(BlobStatusError::Status)? .into_inner(); Ok(hex::encode(disperse_reply.request_id)) @@ -112,8 +119,9 @@ impl RawEigenClient { as usize, ), ) - .await - .map_err(EigenClientError::from) + .await?; + + Ok(()) } async fn dispatch_blob_authenticated(&self, data: Vec) -> Result { @@ -130,7 +138,8 @@ impl RawEigenClient { .lock() .await .disperse_blob_authenticated(UnboundedReceiverStream::new(rx)) - .await?; + .await + .map_err(BlobStatusError::Status)?; let response_stream = response_stream.get_mut(); // 2. receive BlobAuthHeader @@ -143,13 +152,15 @@ impl RawEigenClient { let reply = response_stream .next() .await - .ok_or_else(|| EigenClientError::NoResponseFromServer)? + .ok_or(CommunicationError::NoResponseFromServer)? .unwrap() .payload - .ok_or_else(|| EigenClientError::NoPayloadInResponse)?; + .ok_or(CommunicationError::NoPayloadInResponse)?; let disperser::authenticated_reply::Payload::DisperseReply(disperse_reply) = reply else { - return Err(EigenClientError::UnexpectedResponseFromServer); + return Err(CommunicationError::ErrorFromServer( + "Unexpected response".to_string(), + ))?; }; Ok(hex::encode(disperse_reply.request_id)) } @@ -165,7 +176,7 @@ impl RawEigenClient { .get_blob_data(&hex::encode(rlp::encode(&blob_info))) .await?; if data.is_none() { - return Err(EigenClientError::FailedToGetBlobData); + return Err(CommunicationError::FailedToGetBlobData)?; } self.verifier .verify_commitment(blob_info.blob_header.commitment.clone(), data.unwrap())?; @@ -197,8 +208,8 @@ impl RawEigenClient { })), }; - tx.send(req) - .map_err(|e| EigenClientError::DisperseBlob(format!("{}", e))) + tx.send(req).map_err(CommunicationError::DisperseBlob)?; + Ok(()) } fn keccak256(&self, input: &[u8]) -> [u8; 32] { @@ -220,7 +231,7 @@ impl RawEigenClient { let digest = self.keccak256(&buf); let signature: RecoverableSignature = secp256k1::Secp256k1::signing_only() .sign_ecdsa_recoverable( - &secp256k1::Message::from_slice(&digest[..])?, + &secp256k1::Message::from_slice(&digest[..]).map_err(CommunicationError::Secp)?, &self.private_key, ); let (recovery_id, sig) = signature.serialize_compact(); @@ -236,7 +247,8 @@ impl RawEigenClient { }; tx.send(req) - .map_err(|e| EigenClientError::AuthenticationData(format!("{}", e))) + .map_err(CommunicationError::AuthenticationData)?; + Ok(()) } async fn receive_blob_auth_header( @@ -246,20 +258,22 @@ impl RawEigenClient { let reply = response_stream .next() .await - .ok_or_else(|| EigenClientError::NoResponseFromServer)?; + .ok_or(CommunicationError::NoResponseFromServer)?; let Ok(reply) = reply else { - return Err(EigenClientError::ErrorFromServer(format!("{:?}", reply))); + return Err(CommunicationError::ErrorFromServer(format!("{:?}", reply)))?; }; let reply = reply .payload - .ok_or_else(|| EigenClientError::NoPayloadInResponse)?; + .ok_or(CommunicationError::NoPayloadInResponse)?; if let disperser::authenticated_reply::Payload::BlobAuthHeader(blob_auth_header) = reply { Ok(blob_auth_header) } else { - Err(EigenClientError::UnexpectedResponseFromServer) + Err(CommunicationError::ErrorFromServer( + "Unexpected Response".to_string(), + ))? } } @@ -268,7 +282,7 @@ impl RawEigenClient { request_id: String, ) -> Result { let polling_request = disperser::BlobStatusRequest { - request_id: hex::decode(request_id)?, + request_id: hex::decode(request_id).map_err(CommunicationError::Hex)?, }; let blob_info = (|| async { @@ -282,29 +296,29 @@ impl RawEigenClient { match disperser::BlobStatus::try_from(resp.status)? { disperser::BlobStatus::Processing | disperser::BlobStatus::Dispersing => { - Err(EigenClientError::BlobStillProcessing) + Err(BlobStatusError::BlobStillProcessing) } - disperser::BlobStatus::Failed => Err(EigenClientError::BlobDispatchedFailed), + disperser::BlobStatus::Failed => Err(BlobStatusError::BlobDispatchedFailed), disperser::BlobStatus::InsufficientSignatures => { - Err(EigenClientError::InsufficientSignatures) + Err(BlobStatusError::InsufficientSignatures) } disperser::BlobStatus::Confirmed => { if !self.config.wait_for_finalization { let blob_info = resp .info - .ok_or_else(|| EigenClientError::NoBlobHeaderInResponse)?; + .ok_or_else(|| BlobStatusError::NoBlobHeaderInResponse)?; return Ok(blob_info); } - Err(EigenClientError::BlobStillProcessing) + Err(BlobStatusError::BlobStillProcessing) } disperser::BlobStatus::Finalized => { let blob_info = resp .info - .ok_or_else(|| EigenClientError::NoBlobHeaderInResponse)?; + .ok_or_else(|| BlobStatusError::NoBlobHeaderInResponse)?; Ok(blob_info) } - _ => Err(EigenClientError::ReceivedUnknownBlobStatus), + _ => Err(BlobStatusError::ReceivedUnknownBlobStatus), } }) .retry( @@ -314,10 +328,7 @@ impl RawEigenClient { (self.config.status_query_timeout / self.config.status_query_interval) as usize, ), ) - .when(|e| match e { - EigenClientError::BlobStillProcessing => true, - _ => false, - }) + .when(|e| matches!(e, BlobStatusError::BlobStillProcessing)) .await?; Ok(blob_info) @@ -327,8 +338,8 @@ impl RawEigenClient { &self, blob_info: &str, ) -> Result>, EigenClientError> { - let commit = hex::decode(blob_info)?; - let blob_info: BlobInfo = rlp::decode(&commit)?; + let commit = hex::decode(blob_info).map_err(CommunicationError::Hex)?; + let blob_info: BlobInfo = rlp::decode(&commit).map_err(CommunicationError::Rlp)?; let blob_index = blob_info.blob_verification_proof.blob_index; let batch_header_hash = blob_info .blob_verification_proof @@ -342,11 +353,12 @@ impl RawEigenClient { batch_header_hash, blob_index, }) - .await? + .await + .map_err(BlobStatusError::Status)? .into_inner(); if get_response.data.is_empty() { - return Err(EigenClientError::FailedToGetBlobData); + return Err(CommunicationError::FailedToGetBlobData)?; } let data = remove_empty_byte_from_padded_bytes(&get_response.data);