mirror of
https://github.com/serai-dex/serai.git
synced 2025-12-09 12:49:23 +00:00
We could've added a storage API, and fetched fields that way, except we want the storage to be opaque. That meant we needed to add the RPC routes to the node, which also simplifies other people writing RPC code and fetching these fields. Then the node could've used the storage API, except a lot of the storage in validator-sets is marked opaque and to only be read via functions, so extending the runtime made the most sense.
87 lines
2.6 KiB
Rust
87 lines
2.6 KiB
Rust
use std::{sync::Arc, ops::Deref, collections::HashSet};
|
|
|
|
use rand_core::{RngCore, OsRng};
|
|
|
|
use sp_core::Encode;
|
|
use sp_blockchain::{Error as BlockchainError, HeaderMetadata, HeaderBackend};
|
|
use sp_consensus::BlockStatus;
|
|
use sp_block_builder::BlockBuilder;
|
|
use sp_api::ProvideRuntimeApi;
|
|
use sc_client_api::BlockBackend;
|
|
|
|
use serai_abi::{primitives::prelude::*, SubstrateBlock as Block};
|
|
|
|
use serai_runtime::SeraiApi;
|
|
|
|
use jsonrpsee::RpcModule;
|
|
|
|
use super::utils::block_hash;
|
|
|
|
pub(crate) fn module<
|
|
C: 'static
|
|
+ Send
|
|
+ Sync
|
|
+ HeaderMetadata<Block, Error = BlockchainError>
|
|
+ HeaderBackend<Block>
|
|
+ BlockBackend<Block>
|
|
+ ProvideRuntimeApi<Block, Api: SeraiApi<Block>>,
|
|
>(
|
|
client: Arc<C>,
|
|
) -> Result<RpcModule<impl 'static + Send + Sync>, Box<dyn std::error::Error + Send + Sync>> {
|
|
let mut module = RpcModule::new(client);
|
|
|
|
module.register_method("blockchain/latest_finalized_block_number", |_params, client, _ext| {
|
|
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/block", |params, client, _ext| {
|
|
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,
|
|
));
|
|
};
|
|
|
|
Ok(hex::encode(borsh::to_vec(&serai_abi::Block::from(block.block)).unwrap()))
|
|
})?;
|
|
|
|
module.register_method("blockchain/events", |params, client, _ext| {
|
|
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,
|
|
));
|
|
};
|
|
Ok(events.into_iter().map(hex::encode).collect::<Vec<String>>())
|
|
})?;
|
|
|
|
Ok(module)
|
|
}
|