mirror of
https://github.com/serai-dex/serai.git
synced 2025-12-08 04:09:23 +00:00
Update the block RPCs to return null when missing, not an error
Promotes clarity.
This commit is contained in:
@@ -134,25 +134,29 @@ impl Serai {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn block_internal(
|
async fn block_internal(
|
||||||
block: impl Future<Output = Result<String, RpcError>>,
|
block: impl Future<Output = Result<Option<String>, RpcError>>,
|
||||||
) -> Result<Block, RpcError> {
|
) -> Result<Option<Block>, RpcError> {
|
||||||
let bin = block.await?;
|
let bin = block.await?;
|
||||||
Block::deserialize(
|
bin
|
||||||
&mut hex::decode(&bin)
|
.map(|bin| {
|
||||||
.map_err(|_| RpcError::InvalidNode("node returned non-hex-encoded block".to_string()))?
|
Block::deserialize(
|
||||||
.as_slice(),
|
&mut hex::decode(&bin)
|
||||||
)
|
.map_err(|_| RpcError::InvalidNode("node returned non-hex-encoded block".to_string()))?
|
||||||
.map_err(|_| RpcError::InvalidNode("node returned invalid block".to_string()))
|
.as_slice(),
|
||||||
|
)
|
||||||
|
.map_err(|_| RpcError::InvalidNode("node returned invalid block".to_string()))
|
||||||
|
})
|
||||||
|
.transpose()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Fetch a block from the Serai blockchain.
|
/// Fetch a block from the Serai blockchain.
|
||||||
pub async fn block(&self, block: BlockHash) -> Result<Block, RpcError> {
|
pub async fn block(&self, block: BlockHash) -> Result<Option<Block>, RpcError> {
|
||||||
Self::block_internal(self.call("blockchain/block", &format!(r#"{{ "block": "{block}" }}"#)))
|
Self::block_internal(self.call("blockchain/block", &format!(r#"{{ "block": "{block}" }}"#)))
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Fetch a block from the Serai blockchain by its number.
|
/// Fetch a block from the Serai blockchain by its number.
|
||||||
pub async fn block_by_number(&self, block: u64) -> Result<Block, RpcError> {
|
pub async fn block_by_number(&self, block: u64) -> Result<Option<Block>, RpcError> {
|
||||||
Self::block_internal(self.call("blockchain/block", &format!(r#"{{ "block": {block} }}"#))).await
|
Self::block_internal(self.call("blockchain/block", &format!(r#"{{ "block": {block} }}"#))).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -49,8 +49,8 @@ async fn blockchain() {
|
|||||||
let test_finalized_block = |number| {
|
let test_finalized_block = |number| {
|
||||||
let serai = &serai;
|
let serai = &serai;
|
||||||
async move {
|
async move {
|
||||||
let block = serai.block_by_number(number).await.unwrap();
|
let block = serai.block_by_number(number).await.unwrap().unwrap();
|
||||||
assert_eq!(serai.block(block.header.hash()).await.unwrap(), block);
|
assert_eq!(serai.block(block.header.hash()).await.unwrap().unwrap(), block);
|
||||||
assert!(serai.finalized(block.header.hash()).await.unwrap());
|
assert!(serai.finalized(block.header.hash()).await.unwrap());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -70,7 +70,7 @@ async fn blockchain() {
|
|||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
// Check if it's considered finalized
|
// Check if it's considered finalized
|
||||||
let considered_finalized = serai.finalized(block.header.hash()).await.unwrap();
|
let considered_finalized = serai.finalized(block.unwrap().header.hash()).await.unwrap();
|
||||||
// Ensure the finalized block is the same, meaning this block didn't become finalized as
|
// Ensure the finalized block is the same, meaning this block didn't become finalized as
|
||||||
// we made these RPC requests
|
// we made these RPC requests
|
||||||
if latest_finalized != serai.latest_finalized_block_number().await.unwrap() {
|
if latest_finalized != serai.latest_finalized_block_number().await.unwrap() {
|
||||||
@@ -108,7 +108,7 @@ async fn blockchain() {
|
|||||||
let mut observed_consensus_commitments = HashSet::new();
|
let mut observed_consensus_commitments = HashSet::new();
|
||||||
let mut tagged_block_hashes = vec![];
|
let mut tagged_block_hashes = vec![];
|
||||||
for i in 0 ..= last_block_number {
|
for i in 0 ..= last_block_number {
|
||||||
let block = serai.block_by_number(i).await.unwrap();
|
let block = serai.block_by_number(i).await.unwrap().unwrap();
|
||||||
|
|
||||||
assert_eq!(block.header.number(), i);
|
assert_eq!(block.header.number(), i);
|
||||||
|
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ async fn validator_sets() {
|
|||||||
// The genesis block should have the expected events
|
// The genesis block should have the expected events
|
||||||
{
|
{
|
||||||
let mut events = serai
|
let mut events = serai
|
||||||
.as_of(serai.block_by_number(0).await.unwrap().header.hash())
|
.as_of(serai.block_by_number(0).await.unwrap().unwrap().header.hash())
|
||||||
.await
|
.await
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.validator_sets()
|
.validator_sets()
|
||||||
@@ -98,7 +98,7 @@ async fn validator_sets() {
|
|||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
serai
|
serai
|
||||||
.as_of(serai.block_by_number(0).await.unwrap().header.hash())
|
.as_of(serai.block_by_number(0).await.unwrap().unwrap().header.hash())
|
||||||
.await
|
.await
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.validator_sets()
|
.validator_sets()
|
||||||
@@ -115,7 +115,7 @@ async fn validator_sets() {
|
|||||||
{
|
{
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
serai
|
serai
|
||||||
.as_of(serai.block_by_number(1).await.unwrap().header.hash())
|
.as_of(serai.block_by_number(1).await.unwrap().unwrap().header.hash())
|
||||||
.await
|
.await
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.validator_sets()
|
.validator_sets()
|
||||||
@@ -126,7 +126,7 @@ async fn validator_sets() {
|
|||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
serai
|
serai
|
||||||
.as_of(serai.block_by_number(1).await.unwrap().header.hash())
|
.as_of(serai.block_by_number(1).await.unwrap().unwrap().header.hash())
|
||||||
.await
|
.await
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.validator_sets()
|
.validator_sets()
|
||||||
@@ -138,8 +138,10 @@ async fn validator_sets() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
let serai =
|
let serai = serai
|
||||||
serai.as_of(serai.block_by_number(0).await.unwrap().header.hash()).await.unwrap();
|
.as_of(serai.block_by_number(0).await.unwrap().unwrap().header.hash())
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
let serai = serai.validator_sets();
|
let serai = serai.validator_sets();
|
||||||
for network in NetworkId::all() {
|
for network in NetworkId::all() {
|
||||||
match network {
|
match network {
|
||||||
|
|||||||
@@ -37,10 +37,12 @@ pub(crate) fn module<
|
|||||||
module.register_method(
|
module.register_method(
|
||||||
"blockchain/is_finalized",
|
"blockchain/is_finalized",
|
||||||
|params, client, _ext| -> Result<_, Error> {
|
|params, client, _ext| -> Result<_, Error> {
|
||||||
let block_hash = block_hash(&**client, ¶ms)?;
|
let Some(block_hash) = block_hash(&**client, ¶ms)? else {
|
||||||
|
return Ok(false);
|
||||||
|
};
|
||||||
let finalized = client.info().finalized_number;
|
let finalized = client.info().finalized_number;
|
||||||
let Ok(Some(number)) = client.number(block_hash) else {
|
let Ok(Some(number)) = client.number(block_hash) else {
|
||||||
Err(Error::Missing("failed to fetch block's number"))?
|
return Ok(false);
|
||||||
};
|
};
|
||||||
let Ok(status) = client.block_status(block_hash) else {
|
let Ok(status) = client.block_status(block_hash) else {
|
||||||
Err(Error::Internal("failed to fetch block's status"))?
|
Err(Error::Internal("failed to fetch block's status"))?
|
||||||
@@ -53,18 +55,22 @@ pub(crate) fn module<
|
|||||||
)?;
|
)?;
|
||||||
|
|
||||||
module.register_method("blockchain/block", |params, client, _ext| -> Result<_, Error> {
|
module.register_method("blockchain/block", |params, client, _ext| -> Result<_, Error> {
|
||||||
let block_hash = block_hash(&**client, ¶ms)?;
|
let Some(block_hash) = block_hash(&**client, ¶ms)? else {
|
||||||
|
return Ok(None);
|
||||||
|
};
|
||||||
let Ok(Some(block)) = client.block(block_hash) else {
|
let Ok(Some(block)) = client.block(block_hash) else {
|
||||||
Err(Error::Missing("couldn't find requested block"))?
|
return Ok(None);
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(hex::encode(borsh::to_vec(&serai_abi::Block::from(block.block)).unwrap()))
|
Ok(Some(hex::encode(borsh::to_vec(&serai_abi::Block::from(block.block)).unwrap())))
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
module.register_method("blockchain/events", |params, client, _ext| -> Result<_, Error> {
|
module.register_method("blockchain/events", |params, client, _ext| -> Result<_, Error> {
|
||||||
let block_hash = block_hash(&**client, ¶ms)?;
|
let Some(block_hash) = block_hash(&**client, ¶ms)? else {
|
||||||
|
Err(Error::InvalidStateReference)?
|
||||||
|
};
|
||||||
let Ok(events) = client.runtime_api().events(block_hash) else {
|
let Ok(events) = client.runtime_api().events(block_hash) else {
|
||||||
Err(Error::Missing("couldn't fetch the events for the requested block"))?
|
Err(Error::InvalidStateReference)?
|
||||||
};
|
};
|
||||||
Ok(
|
Ok(
|
||||||
events
|
events
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ use serai_abi::{primitives::prelude::*, SubstrateBlock as Block};
|
|||||||
pub(super) enum Error {
|
pub(super) enum Error {
|
||||||
Internal(&'static str),
|
Internal(&'static str),
|
||||||
InvalidRequest(&'static str),
|
InvalidRequest(&'static str),
|
||||||
Missing(&'static str),
|
InvalidStateReference,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<Error> for jsonrpsee::types::error::ErrorObjectOwned {
|
impl From<Error> for jsonrpsee::types::error::ErrorObjectOwned {
|
||||||
@@ -18,9 +18,11 @@ impl From<Error> for jsonrpsee::types::error::ErrorObjectOwned {
|
|||||||
Error::InvalidRequest(str) => {
|
Error::InvalidRequest(str) => {
|
||||||
jsonrpsee::types::error::ErrorObjectOwned::owned(-2, str, Option::<()>::None)
|
jsonrpsee::types::error::ErrorObjectOwned::owned(-2, str, Option::<()>::None)
|
||||||
}
|
}
|
||||||
Error::Missing(str) => {
|
Error::InvalidStateReference => jsonrpsee::types::error::ErrorObjectOwned::owned(
|
||||||
jsonrpsee::types::error::ErrorObjectOwned::owned(-3, str, Option::<()>::None)
|
-4,
|
||||||
}
|
"the block used as the reference was not locally held",
|
||||||
|
Option::<()>::None,
|
||||||
|
),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -30,7 +32,7 @@ pub(super) fn block_hash<
|
|||||||
>(
|
>(
|
||||||
client: &C,
|
client: &C,
|
||||||
params: &jsonrpsee::types::params::Params,
|
params: &jsonrpsee::types::params::Params,
|
||||||
) -> Result<<Block as sp_runtime::traits::Block>::Hash, Error> {
|
) -> Result<Option<<Block as sp_runtime::traits::Block>::Hash>, Error> {
|
||||||
#[derive(sp_core::serde::Deserialize)]
|
#[derive(sp_core::serde::Deserialize)]
|
||||||
#[serde(crate = "sp_core::serde")]
|
#[serde(crate = "sp_core::serde")]
|
||||||
struct BlockByHash {
|
struct BlockByHash {
|
||||||
@@ -50,13 +52,13 @@ pub(super) fn block_hash<
|
|||||||
}) else {
|
}) else {
|
||||||
return Err(Error::InvalidRequest("requested block hash wasn't a valid hash"));
|
return Err(Error::InvalidRequest("requested block hash wasn't a valid hash"));
|
||||||
};
|
};
|
||||||
block_hash
|
Some(block_hash)
|
||||||
} else {
|
} else {
|
||||||
let Ok(block_number) = params.parse::<BlockByNumber>() else {
|
let Ok(block_number) = params.parse::<BlockByNumber>() else {
|
||||||
return Err(Error::InvalidRequest("requested block wasn't a valid hash nor number"));
|
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 {
|
let Ok(block_hash) = client.block_hash(block_number.block) else {
|
||||||
return Err(Error::Missing("no block hash for that block number"));
|
return Err(Error::Internal("couldn't fetch block hash for block number"));
|
||||||
};
|
};
|
||||||
block_hash
|
block_hash
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -72,7 +72,9 @@ pub(crate) fn module<
|
|||||||
module.register_method(
|
module.register_method(
|
||||||
"validator-sets/current_session",
|
"validator-sets/current_session",
|
||||||
|params, client, _ext| -> Result<_, Error> {
|
|params, client, _ext| -> Result<_, Error> {
|
||||||
let block_hash = block_hash(&**client, ¶ms)?;
|
let Some(block_hash) = block_hash(&**client, ¶ms)? else {
|
||||||
|
Err(Error::InvalidStateReference)?
|
||||||
|
};
|
||||||
let network = network(¶ms)?;
|
let network = network(¶ms)?;
|
||||||
let Ok(session) = client.runtime_api().current_session(block_hash, network) else {
|
let Ok(session) = client.runtime_api().current_session(block_hash, network) else {
|
||||||
Err(Error::Internal("couldn't fetch the session for the requested network"))?
|
Err(Error::Internal("couldn't fetch the session for the requested network"))?
|
||||||
@@ -84,7 +86,9 @@ pub(crate) fn module<
|
|||||||
module.register_method(
|
module.register_method(
|
||||||
"validator-sets/current_stake",
|
"validator-sets/current_stake",
|
||||||
|params, client, _ext| -> Result<_, Error> {
|
|params, client, _ext| -> Result<_, Error> {
|
||||||
let block_hash = block_hash(&**client, ¶ms)?;
|
let Some(block_hash) = block_hash(&**client, ¶ms)? else {
|
||||||
|
Err(Error::InvalidStateReference)?
|
||||||
|
};
|
||||||
let network = network(¶ms)?;
|
let network = network(¶ms)?;
|
||||||
let Ok(stake) = client.runtime_api().current_stake(block_hash, network) else {
|
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"))?
|
Err(Error::Internal("couldn't fetch the total allocated stake for the requested network"))?
|
||||||
@@ -94,7 +98,9 @@ pub(crate) fn module<
|
|||||||
);
|
);
|
||||||
|
|
||||||
module.register_method("validator-sets/keys", |params, client, _ext| -> Result<_, Error> {
|
module.register_method("validator-sets/keys", |params, client, _ext| -> Result<_, Error> {
|
||||||
let block_hash = block_hash(&**client, ¶ms)?;
|
let Some(block_hash) = block_hash(&**client, ¶ms)? else {
|
||||||
|
Err(Error::InvalidStateReference)?
|
||||||
|
};
|
||||||
let set = set(¶ms)?;
|
let set = set(¶ms)?;
|
||||||
let Ok(set) = ExternalValidatorSet::try_from(set) else {
|
let Ok(set) = ExternalValidatorSet::try_from(set) else {
|
||||||
Err(Error::InvalidRequest("requested keys for a non-external validator set"))?
|
Err(Error::InvalidRequest("requested keys for a non-external validator set"))?
|
||||||
|
|||||||
Reference in New Issue
Block a user