Skip to content

Commit

Permalink
Error handling (#70)
Browse files Browse the repository at this point in the history
  • Loading branch information
piotr-iohk authored Nov 20, 2024
1 parent 2762c15 commit 2d9d77c
Show file tree
Hide file tree
Showing 11 changed files with 805 additions and 248 deletions.
1 change: 0 additions & 1 deletion src/api/account_balance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,6 @@ impl MinaMesh {
}]))
}
Some(account_balance_info) => {
println!("B");
let last_relevant_command_balance = account_balance_info.balance.parse::<u64>()?;
let timing_info = sqlx::query_file!("sql/queries/timing_info.sql", account_balance_info.timing_id)
.fetch_optional(&self.pg_pool)
Expand Down
4 changes: 2 additions & 2 deletions src/api/network_list.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ use anyhow::Result;
use coinbase_mesh::models::{NetworkIdentifier, NetworkListResponse};
use cynic::QueryBuilder;

use crate::{graphql::QueryNetworkId, MinaMesh};
use crate::{graphql::QueryNetworkId, MinaMesh, MinaMeshError};

/// https://github.com/MinaProtocol/mina/blob/985eda49bdfabc046ef9001d3c406e688bc7ec45/src/app/rosetta/lib/network.ml#L162
impl MinaMesh {
pub async fn network_list(&self) -> Result<NetworkListResponse> {
pub async fn network_list(&self) -> Result<NetworkListResponse, MinaMeshError> {
let QueryNetworkId { network_id } = self.graphql_client.send(QueryNetworkId::build(())).await?;
let (chain_id, network_id) = network_id.split_once(':').map_or_else(
|| ("unknown".to_string(), "unknown".to_string()),
Expand Down
220 changes: 3 additions & 217 deletions src/api/network_options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ use crate::{MinaMesh, MinaMeshError};
/// https://github.com/MinaProtocol/mina/blob/985eda49bdfabc046ef9001d3c406e688bc7ec45/src/app/rosetta/lib/network.ml#L444
impl MinaMesh {
pub async fn network_options(&self) -> Result<NetworkOptionsResponse, MinaMeshError> {
let errors: Vec<Error> = MinaMeshError::all_errors().into_iter().map(Error::from).collect();

Ok(NetworkOptionsResponse::new(Version::new("1.4.9".to_string(), "1.0.0".to_string()), Allow {
operation_statuses: vec![
OperationStatus::new("Success".to_string(), true),
Expand All @@ -32,223 +34,7 @@ impl MinaMesh {
.into_iter()
.map(|s| s.to_string())
.collect(),
errors: vec![
Error {
code: 1,
message: "SQL failure".to_string(),
description: Some("We encountered a SQL failure.".to_string()),
retriable: false,
details: None,
},
Error {
code: 2,
message: "JSON parse error".to_string(),
description: Some("We encountered an error while parsing JSON.".to_string()),
retriable: false,
details: None,
},
Error {
code: 3,
message: "GraphQL query failed".to_string(),
description: Some("The GraphQL query failed.".to_string()),
retriable: true,
details: None,
},
Error {
code: 4,
message: "Network doesn't exist".to_string(),
description: Some("The network doesn't exist.".to_string()),
retriable: false,
details: None,
},
Error {
code: 5,
message: "Chain info missing".to_string(),
description: Some("Some chain info is missing.".to_string()),
retriable: true,
details: None,
},
Error {
code: 6,
message: "Account not found".to_string(),
description: Some("That account could not be found.".to_string()),
retriable: true,
details: None,
},
Error {
code: 7,
message: "Internal invariant violation (you found a bug)".to_string(),
description: Some("One of our internal invariants was violated. (That means you found a bug!)".to_string()),
retriable: false,
details: None,
},
Error {
code: 8,
message: "Transaction not found".to_string(),
description: Some("That transaction could not be found.".to_string()),
retriable: true,
details: None,
},
Error {
code: 9,
message: "Block not found".to_string(),
description: Some(
"We couldn't find the block in the archive node, specified by . Ask a friend for the missing data."
.to_string(),
),
retriable: true,
details: None,
},
Error {
code: 10,
message: "Malformed public key".to_string(),
description: Some("The public key you provided was malformed.".to_string()),
retriable: false,
details: None,
},
Error {
code: 11,
message: "Cannot convert operations to valid transaction".to_string(),
description: Some("We could not convert those operations to a valid transaction.".to_string()),
retriable: false,
details: None,
},
Error {
code: 12,
message: "Unsupported operation for construction".to_string(),
description: Some("An operation you provided isn't supported for construction.".to_string()),
retriable: false,
details: None,
},
Error {
code: 13,
message: "Signature missing".to_string(),
description: Some("Your request is missing a signature.".to_string()),
retriable: false,
details: None,
},
Error {
code: 14,
message: "Invalid public key format".to_string(),
description: Some("The public key you provided had an invalid format.".to_string()),
retriable: false,
details: None,
},
Error {
code: 15,
message: "No options provided".to_string(),
description: Some("Your request is missing options.".to_string()),
retriable: false,
details: None,
},
Error {
code: 16,
message: "Exception".to_string(),
description: Some(
"We encountered an internal exception while processing your request. (That means you found a bug!)"
.to_string(),
),
retriable: false,
details: None,
},
Error {
code: 17,
message: "Invalid signature".to_string(),
description: Some("Your request has an invalid signature.".to_string()),
retriable: false,
details: None,
},
Error {
code: 18,
message: "Invalid memo".to_string(),
description: Some("Your request has an invalid memo.".to_string()),
retriable: false,
details: None,
},
Error {
code: 19,
message: "No GraphQL URI set".to_string(),
description: Some(
"This Rosetta instance is running without a GraphQL URI set but this request requires one.".to_string(),
),
retriable: false,
details: None,
},
Error {
code: 20,
message: "Can't send transaction: No sender found in ledger".to_string(),
description: Some(
#[allow(clippy::useless_vec)]
vec![
"This could occur because the node isn't fully synced",
"or the account doesn't actually exist in the ledger yet.",
]
.join(" "),
),
retriable: true,
details: None,
},
Error {
code: 21,
message: "Can't send transaction: A duplicate is detected".to_string(),
description: Some(
#[allow(clippy::useless_vec)]
vec![
"This could occur if you've already sent this transaction.",
"Please report a bug if you are confident you didn't already send this exact transaction.",
]
.join(" "),
),
retriable: false,
details: None,
},
Error {
code: 22,
message: "Can't send transaction: Nonce invalid".to_string(),
description: Some(
#[allow(clippy::useless_vec)]
vec![
"You must use the current nonce in your account in the ledger",
"or one that is inferred based on pending transactions in the transaction pool.",
]
.join(" "),
),
retriable: false,
details: None,
},
Error {
code: 23,
message: "Can't send transaction: Fee too small".to_string(),
description: Some(
"The minimum fee on transactions is 0.001 . Please increase your fee to at least this amount.".to_string(),
),
retriable: false,
details: None,
},
Error {
code: 24,
message: "Can't send transaction: Invalid signature".to_string(),
description: Some("An invalid signature is attached to this transaction".to_string()),
retriable: false,
details: None,
},
Error {
code: 25,
message: "Can't send transaction: Insufficient balance".to_string(),
description: Some(
"This account do not have sufficient balance perform the requested transaction.".to_string(),
),
retriable: false,
details: None,
},
Error {
code: 26,
message: "Can't send transaction: Expired".to_string(),
description: Some("This transaction is expired. Please try again with a larger valid_until.".to_string()),
retriable: false,
details: None,
},
],
errors,
historical_balance_lookup: true,
timestamp_start_index: None,
call_methods: vec![],
Expand Down
21 changes: 12 additions & 9 deletions src/commands/serve.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use clap::Args;
use paste::paste;
use tokio::net::TcpListener;

use crate::{playground::handle_playground, util::Wrapper, MinaMesh, MinaMeshConfig};
use crate::{playground::handle_playground, util::Wrapper, MinaMesh, MinaMeshConfig, MinaMeshError};

#[derive(Debug, Args)]
#[command(about = "Start the Mina Mesh Server.")]
Expand Down Expand Up @@ -64,18 +64,21 @@ impl ServeCommand {

macro_rules! create_handler {
($name:ident, $request_type:ty) => {
paste! {
async fn [<handle _ $name>](mina_mesh: State<Arc<MinaMesh>>, Json(req): Json<coinbase_mesh::models::$request_type>) -> impl IntoResponse {
Wrapper(mina_mesh.$name(req).await)
paste! {
async fn [<handle _ $name>](mina_mesh: State<Arc<MinaMesh>>, req: Result<Json<coinbase_mesh::models::$request_type>, axum::extract::rejection::JsonRejection>) -> impl IntoResponse {
match req {
Ok(Json(req)) => Wrapper(mina_mesh.$name(req).await.map_err(MinaMeshError::from)), // Normalize errors to MinaMeshError
Err(err) => Wrapper(Err(MinaMeshError::from(err))), // Convert JsonRejection to MinaMeshError
}
}
}
}
};
($name:ident) => {
paste! {
async fn [<handle _ $name>](mina_mesh: State<Arc<MinaMesh>>) -> impl IntoResponse {
Wrapper(mina_mesh.$name().await)
paste! {
async fn [<handle _ $name>](mina_mesh: State<Arc<MinaMesh>>) -> impl IntoResponse {
Wrapper(mina_mesh.$name().await.map_err(MinaMeshError::from)) // Normalize errors to MinaMeshError
}
}
}
};
}

Expand Down
8 changes: 6 additions & 2 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use clap::{Args, Parser};
use coinbase_mesh::models::BlockIdentifier;
use sqlx::postgres::PgPoolOptions;

use crate::{graphql::GraphQLClient, util::default_mina_proxy_url, MinaMesh};
use crate::{graphql::GraphQLClient, util::default_mina_proxy_url, MinaMesh, MinaMeshError};

#[derive(Debug, Args)]
pub struct MinaMeshConfig {
Expand Down Expand Up @@ -51,7 +51,11 @@ impl MinaMeshConfig {
}
}

pub async fn to_mina_mesh(self) -> Result<MinaMesh> {
pub async fn to_mina_mesh(self) -> Result<MinaMesh, MinaMeshError> {
if self.proxy_url.is_empty() {
return Err(MinaMeshError::GraphqlUriNotSet);
}

Ok(MinaMesh {
graphql_client: GraphQLClient::new(self.proxy_url.to_owned()),
pg_pool: PgPoolOptions::new()
Expand Down
Loading

0 comments on commit 2d9d77c

Please sign in to comment.