mirror of
https://github.com/serai-dex/serai.git
synced 2025-12-08 04:09:23 +00:00
Type the errors yielded by serai-node's RPC
This commit is contained in:
@@ -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| {
|
||||
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 {
|
||||
return Err(jsonrpsee::types::error::ErrorObjectOwned::owned(
|
||||
-2,
|
||||
"failed to fetch block's number",
|
||||
Option::<()>::None,
|
||||
));
|
||||
Err(Error::Missing("failed to fetch block's number"))?
|
||||
};
|
||||
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,
|
||||
));
|
||||
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::<Vec<String>>())
|
||||
})?;
|
||||
|
||||
@@ -13,6 +13,8 @@ use tokio::sync::RwLock;
|
||||
|
||||
use jsonrpsee::RpcModule;
|
||||
|
||||
use super::utils::Error;
|
||||
|
||||
pub(crate) fn module<
|
||||
C: 'static + Send + Sync + HeaderBackend<Block> + ProvideRuntimeApi<Block, Api: SeraiApi<Block>>,
|
||||
>(
|
||||
@@ -22,34 +24,28 @@ pub(crate) fn module<
|
||||
) -> Result<RpcModule<impl 'static + Send + Sync>, Box<dyn std::error::Error + Send + Sync>> {
|
||||
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);
|
||||
|
||||
@@ -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<Error> 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<Block, Error = BlockchainError> + HeaderBackend<Block> + BlockBackend<Block>,
|
||||
>(
|
||||
client: &C,
|
||||
params: &jsonrpsee::types::params::Params,
|
||||
) -> Result<<Block as sp_runtime::traits::Block>::Hash, jsonrpsee::types::error::ErrorObjectOwned> {
|
||||
) -> Result<<Block as sp_runtime::traits::Block>::Hash, Error> {
|
||||
#[derive(sp_core::serde::Deserialize)]
|
||||
#[serde(crate = "sp_core::serde")]
|
||||
struct BlockByHash {
|
||||
@@ -26,27 +48,15 @@ pub(super) fn block_hash<
|
||||
.map(<Block as sp_runtime::traits::Block>::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::<BlockByNumber>() 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
|
||||
})
|
||||
|
||||
@@ -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<NetworkId, jsonrpsee::types::error::ErrorObjectOwned> {
|
||||
pub(super) fn network(params: &jsonrpsee::types::params::Params) -> Result<NetworkId, Error> {
|
||||
#[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::<Network>() 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<ValidatorSet, jsonrpsee::types::error::ErrorObjectOwned> {
|
||||
pub(super) fn set(params: &jsonrpsee::types::params::Params) -> Result<ValidatorSet, Error> {
|
||||
#[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::<Set>() 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<impl 'static + Send + Sync> {
|
||||
let mut module = RpcModule::new(client);
|
||||
|
||||
module.register_method("validator-sets/current_session", |params, client, _ext| {
|
||||
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 {
|
||||
return Err(jsonrpsee::types::error::ErrorObjectOwned::owned(
|
||||
-2,
|
||||
"couldn't fetch the session for the requested network",
|
||||
Option::<()>::None,
|
||||
));
|
||||
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| {
|
||||
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 {
|
||||
return Err(jsonrpsee::types::error::ErrorObjectOwned::owned(
|
||||
-2,
|
||||
"couldn't fetch the total allocated stake for the requested network",
|
||||
Option::<()>::None,
|
||||
));
|
||||
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()))
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user