diff --git a/substrate/node/src/rpc/blockchain.rs b/substrate/node/src/rpc/blockchain.rs index 2a76ae3b..2c5e6bd8 100644 --- a/substrate/node/src/rpc/blockchain.rs +++ b/substrate/node/src/rpc/blockchain.rs @@ -15,7 +15,7 @@ use serai_runtime::SeraiApi; use jsonrpsee::RpcModule; -use super::utils::block_hash; +use super::utils::{Error, block_hash}; pub(crate) fn module< C: 'static @@ -34,50 +34,37 @@ pub(crate) fn module< client.info().finalized_number }); - module.register_method("blockchain/is_finalized", |params, client, _ext| { - let block_hash = block_hash(&**client, ¶ms)?; - let finalized = client.info().finalized_number; - let Ok(Some(number)) = client.number(block_hash) else { - return Err(jsonrpsee::types::error::ErrorObjectOwned::owned( - -2, - "failed to fetch block's number", - Option::<()>::None, - )); - }; - let Ok(status) = client.block_status(block_hash) else { - return Err(jsonrpsee::types::error::ErrorObjectOwned::owned( - -3, - "failed to fetch block's status", - Option::<()>::None, - )); - }; - Ok( - matches!(status, BlockStatus::InChainWithState | BlockStatus::InChainPruned) && - (number <= finalized), - ) - })?; + module.register_method( + "blockchain/is_finalized", + |params, client, _ext| -> Result<_, Error> { + let block_hash = block_hash(&**client, ¶ms)?; + let finalized = client.info().finalized_number; + let Ok(Some(number)) = client.number(block_hash) else { + Err(Error::Missing("failed to fetch block's number"))? + }; + let Ok(status) = client.block_status(block_hash) else { + Err(Error::Internal("failed to fetch block's status"))? + }; + Ok( + matches!(status, BlockStatus::InChainWithState | BlockStatus::InChainPruned) && + (number <= finalized), + ) + }, + )?; - module.register_method("blockchain/block", |params, client, _ext| { + module.register_method("blockchain/block", |params, client, _ext| -> Result<_, Error> { let block_hash = block_hash(&**client, ¶ms)?; let Ok(Some(block)) = client.block(block_hash) else { - return Err(jsonrpsee::types::error::ErrorObjectOwned::owned( - -2, - "couldn't find requested block", - Option::<()>::None, - )); + Err(Error::Missing("couldn't find requested block"))? }; Ok(hex::encode(borsh::to_vec(&serai_abi::Block::from(block.block)).unwrap())) })?; - module.register_method("blockchain/events", |params, client, _ext| { + module.register_method("blockchain/events", |params, client, _ext| -> Result<_, Error> { let block_hash = block_hash(&**client, ¶ms)?; let Ok(events) = client.runtime_api().events(block_hash) else { - return Err(jsonrpsee::types::error::ErrorObjectOwned::owned( - -2, - "couldn't fetch the events for the requested block", - Option::<()>::None, - )); + Err(Error::Missing("couldn't fetch the events for the requested block"))? }; Ok(events.into_iter().map(hex::encode).collect::>()) })?; diff --git a/substrate/node/src/rpc/p2p_validators.rs b/substrate/node/src/rpc/p2p_validators.rs index f25f89b2..58d493a2 100644 --- a/substrate/node/src/rpc/p2p_validators.rs +++ b/substrate/node/src/rpc/p2p_validators.rs @@ -13,6 +13,8 @@ use tokio::sync::RwLock; use jsonrpsee::RpcModule; +use super::utils::Error; + pub(crate) fn module< C: 'static + Send + Sync + HeaderBackend + ProvideRuntimeApi>, >( @@ -22,34 +24,28 @@ pub(crate) fn module< ) -> Result, Box> { let mut module = RpcModule::new((id, client, RwLock::new(authority_discovery))); module.register_async_method("p2p_validators", |params, context, _ext| async move { - let [network]: [String; 1] = params.parse()?; + let network = match params.parse::<[String; 1]>() { + Ok([network]) => network, + Err(e) => return Err(e), + }; + let network = match network.to_lowercase().as_str() { "serai" => NetworkId::Serai, "bitcoin" => ExternalNetworkId::Bitcoin.into(), "ethereum" => ExternalNetworkId::Ethereum.into(), "monero" => ExternalNetworkId::Monero.into(), - _ => Err(jsonrpsee::types::error::ErrorObjectOwned::owned( - -1, - "network to fetch the `p2p_validators` of was unrecognized".to_string(), - Option::<()>::None, - ))?, + _ => Err(Error::InvalidRequest("network to fetch the `p2p_validators` of was unrecognized"))?, }; let (id, client, authority_discovery) = &*context; let latest_block = client.info().best_hash; - let validators = client.runtime_api().validators(latest_block, network).map_err(|_| { - jsonrpsee::types::error::ErrorObjectOwned::owned( - -2, - format!( - "couldn't get validators from the latest block, which is likely a fatal bug. {}", - "please report this at https://github.com/serai-dex/serai", - ), - Option::<()>::None, - ) - }); + let validators = client + .runtime_api() + .validators(latest_block, network) + .map_err(|_| Error::Internal("couldn't get validators from the latest block")); let validators = match validators { Ok(validators) => validators, - Err(e) => return Err(e), + Err(e) => Err(e)?, }; // Always return the protocol's bootnodes let mut all_p2p_addresses = crate::chain_spec::bootnode_multiaddrs(id); diff --git a/substrate/node/src/rpc/utils.rs b/substrate/node/src/rpc/utils.rs index df14308b..dc164ae2 100644 --- a/substrate/node/src/rpc/utils.rs +++ b/substrate/node/src/rpc/utils.rs @@ -3,12 +3,34 @@ use sc_client_api::BlockBackend; use serai_abi::{primitives::prelude::*, SubstrateBlock as Block}; +pub(super) enum Error { + Internal(&'static str), + InvalidRequest(&'static str), + Missing(&'static str), +} + +impl From for jsonrpsee::types::error::ErrorObjectOwned { + fn from(error: Error) -> Self { + match error { + Error::Internal(str) => { + jsonrpsee::types::error::ErrorObjectOwned::owned(-1, str, Option::<()>::None) + } + Error::InvalidRequest(str) => { + jsonrpsee::types::error::ErrorObjectOwned::owned(-2, str, Option::<()>::None) + } + Error::Missing(str) => { + jsonrpsee::types::error::ErrorObjectOwned::owned(-3, str, Option::<()>::None) + } + } + } +} + pub(super) fn block_hash< C: HeaderMetadata + HeaderBackend + BlockBackend, >( client: &C, params: &jsonrpsee::types::params::Params, -) -> Result<::Hash, jsonrpsee::types::error::ErrorObjectOwned> { +) -> Result<::Hash, Error> { #[derive(sp_core::serde::Deserialize)] #[serde(crate = "sp_core::serde")] struct BlockByHash { @@ -26,27 +48,15 @@ pub(super) fn block_hash< .map(::Hash::from) .ok() }) else { - return Err(jsonrpsee::types::error::ErrorObjectOwned::owned( - -1, - "requested block hash wasn't a valid hash", - Option::<()>::None, - )); + return Err(Error::InvalidRequest("requested block hash wasn't a valid hash")); }; block_hash } else { let Ok(block_number) = params.parse::() else { - return Err(jsonrpsee::types::error::ErrorObjectOwned::owned( - -1, - "requested block wasn't a valid hash nor number", - Option::<()>::None, - )); + return Err(Error::InvalidRequest("requested block wasn't a valid hash nor number")); }; let Ok(Some(block_hash)) = client.block_hash(block_number.block) else { - return Err(jsonrpsee::types::error::ErrorObjectOwned::owned( - -2, - "couldn't find requested block's hash", - Option::<()>::None, - )); + return Err(Error::Missing("no block hash for that block number")); }; block_hash }) diff --git a/substrate/node/src/rpc/validator_sets.rs b/substrate/node/src/rpc/validator_sets.rs index e3385513..b3f9569d 100644 --- a/substrate/node/src/rpc/validator_sets.rs +++ b/substrate/node/src/rpc/validator_sets.rs @@ -15,11 +15,9 @@ use serai_runtime::SeraiApi; use jsonrpsee::RpcModule; -use super::utils::block_hash; +use super::utils::{Error, block_hash}; -pub(super) fn network( - params: &jsonrpsee::types::params::Params, -) -> Result { +pub(super) fn network(params: &jsonrpsee::types::params::Params) -> Result { #[derive(sp_core::serde::Deserialize)] #[serde(crate = "sp_core::serde")] struct Network { @@ -27,11 +25,7 @@ pub(super) fn network( } let Ok(network) = params.parse::() else { - return Err(jsonrpsee::types::error::ErrorObjectOwned::owned( - -1, - r#"missing `string` "network" field"#, - Option::<()>::None, - )); + Err(Error::InvalidRequest(r#"missing `string` "network" field"#))? }; Ok(match network.network.to_lowercase().as_str() { @@ -39,17 +33,11 @@ pub(super) fn network( "bitcoin" => NetworkId::External(ExternalNetworkId::Bitcoin), "ethereum" => NetworkId::External(ExternalNetworkId::Ethereum), "monero" => NetworkId::External(ExternalNetworkId::Monero), - _ => Err(jsonrpsee::types::error::ErrorObjectOwned::owned( - -1, - "unrecognized network requested", - Option::<()>::None, - ))?, + _ => Err(Error::InvalidRequest("unrecognized network requested"))?, }) } -pub(super) fn set( - params: &jsonrpsee::types::params::Params, -) -> Result { +pub(super) fn set(params: &jsonrpsee::types::params::Params) -> Result { #[derive(sp_core::serde::Deserialize)] #[serde(crate = "sp_core::serde")] struct Set { @@ -58,11 +46,7 @@ pub(super) fn set( } let Ok(set) = params.parse::() else { - return Err(jsonrpsee::types::error::ErrorObjectOwned::owned( - -1, - r#"missing `object` "set" field"#, - Option::<()>::None, - )); + Err(Error::InvalidRequest(r#"missing `object` "set" field"#))? }; let network = match set.network.to_lowercase().as_str() { @@ -70,11 +54,7 @@ pub(super) fn set( "bitcoin" => NetworkId::External(ExternalNetworkId::Bitcoin), "ethereum" => NetworkId::External(ExternalNetworkId::Ethereum), "monero" => NetworkId::External(ExternalNetworkId::Monero), - _ => Err(jsonrpsee::types::error::ErrorObjectOwned::owned( - -1, - "unrecognized network requested", - Option::<()>::None, - ))?, + _ => Err(Error::InvalidRequest("unrecognized network requested"))?, }; Ok(ValidatorSet { network, session: Session(set.session) }) @@ -93,48 +73,38 @@ pub(crate) fn module< ) -> RpcModule { let mut module = RpcModule::new(client); - module.register_method("validator-sets/current_session", |params, client, _ext| { - let block_hash = block_hash(&**client, ¶ms)?; - let network = network(¶ms)?; - let Ok(session) = client.runtime_api().current_session(block_hash, network) else { - return Err(jsonrpsee::types::error::ErrorObjectOwned::owned( - -2, - "couldn't fetch the session for the requested network", - Option::<()>::None, - )); - }; - Ok(session.map(|session| session.0)) - }); + module.register_method( + "validator-sets/current_session", + |params, client, _ext| -> Result<_, Error> { + let block_hash = block_hash(&**client, ¶ms)?; + let network = network(¶ms)?; + let Ok(session) = client.runtime_api().current_session(block_hash, network) else { + Err(Error::Internal("couldn't fetch the session for the requested network"))? + }; + Ok(session.map(|session| session.0)) + }, + ); - module.register_method("validator-sets/current_stake", |params, client, _ext| { - let block_hash = block_hash(&**client, ¶ms)?; - let network = network(¶ms)?; - let Ok(stake) = client.runtime_api().current_stake(block_hash, network) else { - return Err(jsonrpsee::types::error::ErrorObjectOwned::owned( - -2, - "couldn't fetch the total allocated stake for the requested network", - Option::<()>::None, - )); - }; - Ok(stake.map(|stake| stake.0)) - }); + module.register_method( + "validator-sets/current_stake", + |params, client, _ext| -> Result<_, Error> { + let block_hash = block_hash(&**client, ¶ms)?; + let network = network(¶ms)?; + let Ok(stake) = client.runtime_api().current_stake(block_hash, network) else { + Err(Error::Internal("couldn't fetch the total allocated stake for the requested network"))? + }; + Ok(stake.map(|stake| stake.0)) + }, + ); - module.register_method("validator-sets/keys", |params, client, _ext| { + module.register_method("validator-sets/keys", |params, client, _ext| -> Result<_, Error> { let block_hash = block_hash(&**client, ¶ms)?; let set = set(¶ms)?; let Ok(set) = ExternalValidatorSet::try_from(set) else { - return Err(jsonrpsee::types::error::ErrorObjectOwned::owned( - -1, - "requested keys for a non-extenral validator set", - Option::<()>::None, - )); + Err(Error::InvalidRequest("requested keys for a non-external validator set"))? }; let Ok(key_pair) = client.runtime_api().keys(block_hash, set) else { - return Err(jsonrpsee::types::error::ErrorObjectOwned::owned( - -2, - "couldn't fetch the keys for the requested validator set", - Option::<()>::None, - )); + Err(Error::Internal("couldn't fetch the keys for the requested validator set"))? }; Ok(hex::encode(borsh::to_vec(&key_pair).unwrap())) });