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

Error handling #70

Merged
merged 9 commits into from
Nov 20, 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
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