From 4f7c59c6d04d13547b88c0f041048167f0548447 Mon Sep 17 00:00:00 2001 From: Dmitry Kuzmin Date: Wed, 15 Apr 2026 13:58:39 +0300 Subject: [PATCH 1/2] feat: initial error PR | refactor error --- ethexe/rpc/src/apis/injected/promise_manager.rs | 6 +++--- ethexe/rpc/src/apis/injected/relay.rs | 1 + ethexe/rpc/src/apis/injected/server.rs | 2 +- ethexe/rpc/src/errors.rs | 14 +++++++++++--- 4 files changed, 16 insertions(+), 7 deletions(-) diff --git a/ethexe/rpc/src/apis/injected/promise_manager.rs b/ethexe/rpc/src/apis/injected/promise_manager.rs index d55f454eef7..c58dfd6e746 100644 --- a/ethexe/rpc/src/apis/injected/promise_manager.rs +++ b/ethexe/rpc/src/apis/injected/promise_manager.rs @@ -47,8 +47,8 @@ pub struct PromiseSubscriptionManager { #[derive(Debug, Clone, thiserror::Error)] pub enum RegisterSubscriberError { - #[error("Subscriber for this transaction already exists, tx_hash={0}")] - AlreadyRegistered(HashOf), + #[error("Subscriber for the transaction already exists")] + AlreadyRegistered, } type TimeoutReceiver = tokio::time::Timeout>; @@ -92,7 +92,7 @@ impl PromiseSubscriptionManager { tx_hash: HashOf, ) -> Result { match self.subscribers.entry(tx_hash) { - Entry::Occupied(_) => Err(RegisterSubscriberError::AlreadyRegistered(tx_hash)), + Entry::Occupied(_) => Err(RegisterSubscriberError::AlreadyRegistered), Entry::Vacant(entry) => { let (sender, receiver) = oneshot::channel(); entry.insert(sender); diff --git a/ethexe/rpc/src/apis/injected/relay.rs b/ethexe/rpc/src/apis/injected/relay.rs index 5a52fa8d2a6..ca23006a30a 100644 --- a/ethexe/rpc/src/apis/injected/relay.rs +++ b/ethexe/rpc/src/apis/injected/relay.rs @@ -53,6 +53,7 @@ impl TransactionsRelayer { ); return Err(errors::bad_request( "Injected transactions with non-zero value are not supported", + None::<&str>, )); } diff --git a/ethexe/rpc/src/apis/injected/server.rs b/ethexe/rpc/src/apis/injected/server.rs index 117aed18e57..9480b9c3934 100644 --- a/ethexe/rpc/src/apis/injected/server.rs +++ b/ethexe/rpc/src/apis/injected/server.rs @@ -118,7 +118,7 @@ impl InjectedApi { let pending_subscriber = match self.manager.try_register_subscriber(tx_hash) { Ok(subscriber) => subscriber, Err(err) => { - return Err(errors::bad_request(err).into()); + return Err(errors::bad_request(err.to_string(), Some(tx_hash)).into()); } }; diff --git a/ethexe/rpc/src/errors.rs b/ethexe/rpc/src/errors.rs index 73c7f4cae00..933319ca7cf 100644 --- a/ethexe/rpc/src/errors.rs +++ b/ethexe/rpc/src/errors.rs @@ -16,7 +16,11 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -use jsonrpsee::types::{ErrorObject, error::INVALID_PARAMS_CODE}; +use jsonrpsee::types::{ + ErrorObject, + error::{INVALID_PARAMS_CODE, INVALID_REQUEST_CODE}, +}; +use serde::Serialize; // TODO #4364: https://github.com/gear-tech/gear/issues/4364 @@ -28,8 +32,12 @@ pub fn runtime(err: impl ToString) -> ErrorObject<'static> { ErrorObject::owned(8000, "Runtime error", Some(err.to_string())) } -pub fn bad_request(err: impl ToString) -> ErrorObject<'static> { - ErrorObject::owned(8000, "Bad request", Some(err.to_string())) +pub fn bad_request(message: M, data: Option) -> ErrorObject<'static> +where + M: Into, + D: Serialize, +{ + ErrorObject::owned(INVALID_REQUEST_CODE, message, data) } pub fn internal() -> ErrorObject<'static> { From bdc2172c3664d82f30d618835d02a47225a70072 Mon Sep 17 00:00:00 2001 From: Dmitry Kuzmin Date: Wed, 15 Apr 2026 15:16:41 +0300 Subject: [PATCH 2/2] chore: redesign error --- .../rpc/src/apis/injected/promise_manager.rs | 9 ++--- ethexe/rpc/src/apis/injected/relay.rs | 3 +- ethexe/rpc/src/apis/injected/server.rs | 4 +-- ethexe/rpc/src/errors.rs | 33 +++++++++++-------- 4 files changed, 28 insertions(+), 21 deletions(-) diff --git a/ethexe/rpc/src/apis/injected/promise_manager.rs b/ethexe/rpc/src/apis/injected/promise_manager.rs index c58dfd6e746..f8b9401a2f7 100644 --- a/ethexe/rpc/src/apis/injected/promise_manager.rs +++ b/ethexe/rpc/src/apis/injected/promise_manager.rs @@ -26,6 +26,7 @@ use ethexe_common::{ }, }; use ethexe_db::Database; +use serde::{Deserialize, Serialize}; use std::{sync::Arc, time::Duration}; use tokio::sync::oneshot; use tracing::trace; @@ -45,10 +46,10 @@ pub struct PromiseSubscriptionManager { waiting_for_compute: PromisesComputationWaiting, } -#[derive(Debug, Clone, thiserror::Error)] +#[derive(Debug, Clone, thiserror::Error, Serialize, Deserialize)] pub enum RegisterSubscriberError { - #[error("Subscriber for the transaction already exists")] - AlreadyRegistered, + #[error("Subscriber for this transaction already exists, tx_hash={0}")] + AlreadyRegistered(HashOf), } type TimeoutReceiver = tokio::time::Timeout>; @@ -92,7 +93,7 @@ impl PromiseSubscriptionManager { tx_hash: HashOf, ) -> Result { match self.subscribers.entry(tx_hash) { - Entry::Occupied(_) => Err(RegisterSubscriberError::AlreadyRegistered), + Entry::Occupied(_) => Err(RegisterSubscriberError::AlreadyRegistered(tx_hash)), Entry::Vacant(entry) => { let (sender, receiver) = oneshot::channel(); entry.insert(sender); diff --git a/ethexe/rpc/src/apis/injected/relay.rs b/ethexe/rpc/src/apis/injected/relay.rs index ca23006a30a..b9f8d9fb3b0 100644 --- a/ethexe/rpc/src/apis/injected/relay.rs +++ b/ethexe/rpc/src/apis/injected/relay.rs @@ -51,9 +51,8 @@ impl TransactionsRelayer { value = transaction.tx.data().value, "Injected transaction with non-zero value is not supported" ); - return Err(errors::bad_request( + return Err(errors::invalid_params_with( "Injected transactions with non-zero value are not supported", - None::<&str>, )); } diff --git a/ethexe/rpc/src/apis/injected/server.rs b/ethexe/rpc/src/apis/injected/server.rs index 9480b9c3934..3c8ced2c12b 100644 --- a/ethexe/rpc/src/apis/injected/server.rs +++ b/ethexe/rpc/src/apis/injected/server.rs @@ -118,7 +118,7 @@ impl InjectedApi { let pending_subscriber = match self.manager.try_register_subscriber(tx_hash) { Ok(subscriber) => subscriber, Err(err) => { - return Err(errors::bad_request(err.to_string(), Some(tx_hash)).into()); + return Err(errors::bad_request(Some(err)).into()); } }; @@ -181,7 +181,7 @@ impl InjectedApi { tracing::trace!(?transaction_ids, "Called injected_getTransactions"); if transaction_ids.len() > MAX_TRANSACTION_IDS { - return Err(errors::invalid_params(format!( + return Err(errors::invalid_params_with(format!( "Too many transaction ids requested. Maximum is {MAX_TRANSACTION_IDS}.", ))); } diff --git a/ethexe/rpc/src/errors.rs b/ethexe/rpc/src/errors.rs index 933319ca7cf..3f9c56c6ddf 100644 --- a/ethexe/rpc/src/errors.rs +++ b/ethexe/rpc/src/errors.rs @@ -18,32 +18,39 @@ use jsonrpsee::types::{ ErrorObject, - error::{INVALID_PARAMS_CODE, INVALID_REQUEST_CODE}, + error::{ + CALL_EXECUTION_FAILED_CODE, INTERNAL_ERROR_CODE, INTERNAL_ERROR_MSG, INVALID_PARAMS_CODE, + INVALID_PARAMS_MSG, INVALID_REQUEST_CODE, INVALID_REQUEST_MSG, + }, }; use serde::Serialize; -// TODO #4364: https://github.com/gear-tech/gear/issues/4364 - +// TODO: db errors are cause when we do not found some data in data, so maybe rename it to `not_found`. pub fn db(err: &'static str) -> ErrorObject<'static> { ErrorObject::owned(8000, "Database error", Some(err)) } pub fn runtime(err: impl ToString) -> ErrorObject<'static> { - ErrorObject::owned(8000, "Runtime error", Some(err.to_string())) + ErrorObject::owned( + CALL_EXECUTION_FAILED_CODE, + "Runtime error", + Some(err.to_string()), + ) } -pub fn bad_request(message: M, data: Option) -> ErrorObject<'static> -where - M: Into, - D: Serialize, -{ - ErrorObject::owned(INVALID_REQUEST_CODE, message, data) +pub fn bad_request(data: Option) -> ErrorObject<'static> { + ErrorObject::owned(INVALID_REQUEST_CODE, INVALID_REQUEST_MSG, data) } pub fn internal() -> ErrorObject<'static> { - ErrorObject::owned(8000, "Internal error", None::<&str>) + ErrorObject::owned(INTERNAL_ERROR_CODE, INTERNAL_ERROR_MSG, None::<&str>) +} + +#[allow(unused)] +pub fn invalid_params() -> ErrorObject<'static> { + ErrorObject::owned(INVALID_PARAMS_CODE, INVALID_PARAMS_MSG, None::<&str>) } -pub fn invalid_params(err: impl ToString) -> ErrorObject<'static> { - ErrorObject::owned(INVALID_PARAMS_CODE, "Invalid params", Some(err.to_string())) +pub fn invalid_params_with(data: D) -> ErrorObject<'static> { + ErrorObject::owned(INVALID_PARAMS_CODE, INVALID_PARAMS_MSG, Some(data)) }