Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix error types #89

Merged
merged 7 commits into from
Nov 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions zaino-fetch/src/jsonrpc/connector.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//! JsonRPC client implementation.
//!
//! TODO: - Add option for http connector.
//! - Refactor JsonRpcConnectorError into concrete error types and implement fmt::display [https://github.com/zingolabs/zaino/issues/67].

use http::Uri;
use reqwest::{Client, Url};
Expand Down Expand Up @@ -126,15 +127,15 @@ impl JsonRpcConnector {
if body_str.contains("Work queue depth exceeded") {
if attempts >= max_attempts {
return Err(JsonRpcConnectorError::new(
"Work queue depth exceeded after multiple attempts",
"Error: The node's rpc queue depth was exceeded after multiple attempts",
idky137 marked this conversation as resolved.
Show resolved Hide resolved
));
}
tokio::time::sleep(std::time::Duration::from_millis(500)).await;
continue;
}
if !status.is_success() {
return Err(JsonRpcConnectorError::new(format!(
"HTTP Error: {}",
"Error: Error status from node's rpc server: {}",
status
)));
}
Expand All @@ -143,7 +144,7 @@ impl JsonRpcConnector {
.map_err(JsonRpcConnectorError::SerdeJsonError)?;
return match response.error {
Some(error) => Err(JsonRpcConnectorError::new(format!(
"RPC Error {}: {}",
"Error: Error from node's rpc server: {} - {}",
error.code, error.message
))),
None => Ok(response.result),
Expand Down
49 changes: 16 additions & 33 deletions zaino-fetch/src/jsonrpc/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,57 +3,40 @@
/// General error type for handling JsonRpcConnector errors.
#[derive(Debug, thiserror::Error)]
pub enum JsonRpcConnectorError {
/// Uncatogorized Errors.
#[error("{0}")]
CustomError(String),
/// Type for errors without an underlying source.
#[error("Error: {0}")]
JsonRpcClientError(String),

/// Serialization/Deserialization Errors.
#[error("Serialization/Deserialization Error: {0}")]
#[error("Error: Serialization/Deserialization Error: {0}")]
SerdeJsonError(#[from] serde_json::Error),

/// Reqwest Based Errors.
#[error("HTTP Request Error: {0}")]
#[error("Error: HTTP Request Error: {0}")]
ReqwestError(#[from] reqwest::Error),

///HTTP Errors.
#[error("HTTP Error: {0}")]
HttpError(#[from] http::Error),

/// Invalid URI Errors.
#[error("Invalid URI: {0}")]
#[error("Error: Invalid URI: {0}")]
InvalidUriError(#[from] http::uri::InvalidUri),

/// Invalid URL Errors.
#[error("Invalid URL: {0}")]
InvalidUrlError(#[from] url::ParseError),

/// UTF-8 Conversion Errors.
#[error("UTF-8 Conversion Error")]
Utf8Error(#[from] std::string::FromUtf8Error),

/// Request Timeout Errors.
#[error("Request Timeout Error")]
TimeoutError(#[from] tokio::time::error::Elapsed),
/// URL Parse Errors.
#[error("Error: Invalid URL:{0}")]
UrlParseError(#[from] url::ParseError),
}

impl JsonRpcConnectorError {
/// Constructor for errors without an underlying source
pub fn new(msg: impl Into<String>) -> Self {
JsonRpcConnectorError::CustomError(msg.into())
JsonRpcConnectorError::JsonRpcClientError(msg.into())
}

/// Maps JsonRpcConnectorError to tonic::Status
/// Converts JsonRpcConnectorError to tonic::Status
///
/// TODO: This impl should be changed to return the correct status [https://github.com/zcash/lightwalletd/issues/497] before release,
/// however propagating the server error is useful durin development.
pub fn to_grpc_status(&self) -> tonic::Status {
eprintln!("Error occurred: {}.", self);

match self {
JsonRpcConnectorError::SerdeJsonError(_) => {
tonic::Status::invalid_argument(self.to_string())
}
JsonRpcConnectorError::ReqwestError(_) => tonic::Status::unavailable(self.to_string()),
JsonRpcConnectorError::HttpError(_) => tonic::Status::internal(self.to_string()),
_ => tonic::Status::internal(self.to_string()),
}
// TODO: Hide server error from clients before release. Currently useful for dev purposes.
tonic::Status::internal(format!("Error: JsonRPC Client Error: {}", self.to_string()))
}
}

Expand Down
196 changes: 111 additions & 85 deletions zaino-serve/src/rpc/service.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,25 +159,27 @@ impl CompactTxStreamer for GrpcClient {
match get_block_from_node(&zebrad_uri, &height).await {
Ok(block) => Ok(tonic::Response::new(block)),
Err(e) => {
if height
< JsonRpcConnector::new(
self.zebrad_uri.clone(),
Some("xxxxxx".to_string()),
Some("xxxxxx".to_string()),
)
.await?
.get_blockchain_info()
.await
.map_err(|e| e.to_grpc_status())?
.blocks
.0
{
return Err(tonic::Status::invalid_argument(
"Error: Height out of range. Height requested is greater than the best chain tip.",
let chain_height = JsonRpcConnector::new(
self.zebrad_uri.clone(),
Some("xxxxxx".to_string()),
Some("xxxxxx".to_string()),
)
.await?
.get_blockchain_info()
.await
.map_err(|e| e.to_grpc_status())?
.blocks
.0;
if height >= chain_height {
return Err(tonic::Status::out_of_range(
format!(
"Error: Height out of range [{}]. Height requested is greater than the best chain tip [{}].",
height, chain_height,
)
));
} else {
// TODO: Hide server error from clients before release. Currently useful for dev purposes.
return Err(tonic::Status::internal(format!(
return Err(tonic::Status::unknown(format!(
"Error: Failed to retrieve block from node. Server Error: {}",
e.to_string(),
)));
Expand Down Expand Up @@ -220,25 +222,27 @@ impl CompactTxStreamer for GrpcClient {
match get_nullifiers_from_node(&zebrad_uri, &height).await {
Ok(block) => Ok(tonic::Response::new(block)),
Err(e) => {
if height
< JsonRpcConnector::new(
self.zebrad_uri.clone(),
Some("xxxxxx".to_string()),
Some("xxxxxx".to_string()),
)
.await?
.get_blockchain_info()
.await
.map_err(|e| e.to_grpc_status())?
.blocks
.0
{
return Err(tonic::Status::invalid_argument(
"Error: Height out of range. Height requested is greater than the best chain tip.",
let chain_height = JsonRpcConnector::new(
self.zebrad_uri.clone(),
Some("xxxxxx".to_string()),
Some("xxxxxx".to_string()),
)
.await?
.get_blockchain_info()
.await
.map_err(|e| e.to_grpc_status())?
.blocks
.0;
if height >= chain_height {
return Err(tonic::Status::out_of_range(
format!(
"Error: Height out of range [{}]. Height requested is greater than the best chain tip [{}].",
height, chain_height,
)
));
} else {
// TODO: Hide server error from clients before release. Currently useful for dev purposes.
return Err(tonic::Status::internal(format!(
return Err(tonic::Status::unknown(format!(
"Error: Failed to retrieve nullifiers from node. Server Error: {}",
e.to_string(),
)));
Expand Down Expand Up @@ -315,23 +319,17 @@ impl CompactTxStreamer for GrpcClient {
} else {
false
};
if end
< JsonRpcConnector::new(
self.zebrad_uri.clone(),
Some("xxxxxx".to_string()),
Some("xxxxxx".to_string()),
)
.await?
.get_blockchain_info()
.await
.map_err(|e| e.to_grpc_status())?
.blocks
.0
{
return Err(tonic::Status::invalid_argument(
"Error: Blockrange out of range. Height requested is greater than the best chain tip.",
));
}
let chain_height = JsonRpcConnector::new(
self.zebrad_uri.clone(),
Some("xxxxxx".to_string()),
Some("xxxxxx".to_string()),
)
.await?
.get_blockchain_info()
.await
.map_err(|e| e.to_grpc_status())?
.blocks
.0;
println!("[TEST] Fetching blocks in range: {}-{}.", start, end);
let (channel_tx, channel_rx) = tokio::sync::mpsc::channel(32);
tokio::spawn(async move {
Expand All @@ -351,13 +349,30 @@ impl CompactTxStreamer for GrpcClient {
}
}
Err(e) => {
// TODO: Hide server error from clients before release. Currently useful for dev purposes.
if channel_tx
.send(Err(tonic::Status::internal(e.to_string())))
.await
.is_err()
{
break;
if height >= chain_height {
match channel_tx
.send(Err(tonic::Status::out_of_range(format!(
"Error: Height out of range [{}]. Height requested is greater than the best chain tip [{}].",
height, chain_height,
))))
.await

{
Ok(_) => break,
Err(e) => {
eprintln!("Error: Channel closed unexpectedly: {}", e.to_string());
break;
}
}
} else {
// TODO: Hide server error from clients before release. Currently useful for dev purposes.
if channel_tx
.send(Err(tonic::Status::unknown(e.to_string())))
.await
.is_err()
{
break;
}
}
}
}
Expand All @@ -368,8 +383,8 @@ impl CompactTxStreamer for GrpcClient {
Ok(_) => {}
Err(_) => {
channel_tx
.send(Err(tonic::Status::internal(
"get_block_range gRPC request timed out",
.send(Err(tonic::Status::deadline_exceeded(
"Error: get_block_range gRPC request timed out.",
)))
.await
.ok();
Expand Down Expand Up @@ -448,23 +463,17 @@ impl CompactTxStreamer for GrpcClient {
} else {
false
};
if end
< JsonRpcConnector::new(
self.zebrad_uri.clone(),
Some("xxxxxx".to_string()),
Some("xxxxxx".to_string()),
)
.await?
.get_blockchain_info()
.await
.map_err(|e| e.to_grpc_status())?
.blocks
.0
{
return Err(tonic::Status::invalid_argument(
"Error: Blockrange out of range. Block height requested are greater than the best chain tip.",
));
}
let chain_height = JsonRpcConnector::new(
self.zebrad_uri.clone(),
Some("xxxxxx".to_string()),
Some("xxxxxx".to_string()),
)
.await?
.get_blockchain_info()
.await
.map_err(|e| e.to_grpc_status())?
.blocks
.0;
let (channel_tx, channel_rx) = tokio::sync::mpsc::channel(32);
tokio::spawn(async move {
// NOTE: This timeout is so slow due to the blockcache not being implemented. This should be reduced to 30s once functionality is in place.
Expand All @@ -483,13 +492,30 @@ impl CompactTxStreamer for GrpcClient {
}
}
Err(e) => {
// TODO: Hide server error from clients before release. Currently useful for dev purposes.
if channel_tx
.send(Err(tonic::Status::internal(e.to_string())))
.await
.is_err()
{
break;
if height >= chain_height {
match channel_tx
.send(Err(tonic::Status::out_of_range(format!(
"Error: Height out of range [{}]. Height requested is greater than the best chain tip [{}].",
height, chain_height,
))))
.await

{
Ok(_) => break,
Err(e) => {
eprintln!("Error: Channel closed unexpectedly: {}", e.to_string());
break;
}
}
} else {
// TODO: Hide server error from clients before release. Currently useful for dev purposes.
if channel_tx
.send(Err(tonic::Status::unknown(e.to_string())))
.await
.is_err()
{
break;
}
}
}
}
Expand All @@ -500,8 +526,8 @@ impl CompactTxStreamer for GrpcClient {
Ok(_) => {}
Err(_) => {
channel_tx
.send(Err(tonic::Status::internal(
"get_block_range_nullifiers gRPC request timed out",
.send(Err(tonic::Status::deadline_exceeded(
"Error: get_block_range_nullifiers gRPC request timed out.",
)))
.await
.ok();
Expand Down Expand Up @@ -1180,7 +1206,7 @@ impl CompactTxStreamer for GrpcClient {
})
}

// /// Testing-only, requires lightwalletd --ping-very-insecure (do not enable in production) [from zebrad]
/// Testing-only, requires lightwalletd --ping-very-insecure (do not enable in production) [from zebrad]
/// This RPC has not been implemented as it is not currently used by zingolib.
/// If you require this RPC please open an issue or PR at the Zingo-Indexer github (https://github.com/zingolabs/zingo-indexer).
fn ping<'life0, 'async_trait>(
Expand Down
Loading