pallet_msa_rpc/
lib.rs

1// Strong Documentation Lints
2#![deny(
3	rustdoc::broken_intra_doc_links,
4	rustdoc::missing_crate_level_docs,
5	rustdoc::invalid_codeblock_attributes,
6	missing_docs
7)]
8
9//! Custom APIs for [MSA](../pallet_msa/index.html)
10
11use common_helpers::rpc::map_rpc_result;
12use common_primitives::{
13	msa::{
14		DelegationResponse, DelegatorId, KeyInfoResponse, MessageSourceId, ProviderId, SchemaGrant,
15	},
16	node::BlockNumber,
17	offchain::get_msa_account_storage_key_name,
18	schema::SchemaId,
19};
20use jsonrpsee::{
21	core::{async_trait, RpcResult},
22	proc_macros::rpc,
23	tracing::warn,
24	types::{error::ErrorObjectOwned, ErrorObject},
25};
26use pallet_msa_runtime_api::MsaRuntimeApi;
27use parity_scale_codec::{Codec, Decode};
28use parking_lot::RwLock;
29use rayon::prelude::*;
30use sp_api::ProvideRuntimeApi;
31use sp_blockchain::HeaderBackend;
32use sp_core::Bytes;
33use sp_runtime::traits::Block as BlockT;
34use std::sync::Arc;
35
36#[cfg(test)]
37mod tests;
38
39/// Frequency MSA Custom RPC API
40#[rpc(client, server)]
41pub trait MsaApi<BlockHash, AccountId> {
42	/// Check for a list of delegations
43	/// Given a single provider, test a list of potential delegators
44	/// At a given block number
45	#[method(name = "msa_checkDelegations")]
46	fn check_delegations(
47		&self,
48		delegator_msa_ids: Vec<DelegatorId>,
49		provider_msa_id: ProviderId,
50		block_number: BlockNumber,
51		schema_id: Option<SchemaId>,
52	) -> RpcResult<Vec<(DelegatorId, bool)>>;
53
54	/// Retrieve the list of currently granted schemas given a delegator and provider pair
55	#[method(name = "msa_grantedSchemaIdsByMsaId")]
56	fn get_granted_schemas_by_msa_id(
57		&self,
58		delegator_msa_id: DelegatorId,
59		provider_msa_id: ProviderId,
60	) -> RpcResult<Option<Vec<SchemaGrant<SchemaId, BlockNumber>>>>;
61
62	/// Retrieve the list of all delegations for a MsaId
63	#[method(name = "msa_getAllGrantedDelegationsByMsaId")]
64	fn get_all_granted_delegations_by_msa_id(
65		&self,
66		delegator_msa_id: DelegatorId,
67	) -> RpcResult<Vec<DelegationResponse<SchemaId, BlockNumber>>>;
68
69	/// Retrieve the list of keys for msa id
70	#[method(name = "msa_getKeysByMsaId")]
71	fn get_keys_by_msa_id(
72		&self,
73		msa_id: MessageSourceId,
74	) -> RpcResult<Option<KeyInfoResponse<AccountId>>>;
75}
76
77/// The client handler for the API used by Frequency Service RPC with `jsonrpsee`
78pub struct MsaHandler<C, M, OffchainDB> {
79	client: Arc<C>,
80	offchain: Arc<RwLock<Option<OffchainDB>>>,
81	_marker: std::marker::PhantomData<M>,
82}
83
84impl<C, M, OffchainDB> MsaHandler<C, M, OffchainDB>
85where
86	OffchainDB: Send + Sync,
87{
88	/// Create new instance with the given reference to the client.
89	pub fn new(client: Arc<C>, offchain: Option<OffchainDB>) -> Self {
90		Self { client, offchain: Arc::new(RwLock::new(offchain)), _marker: Default::default() }
91	}
92}
93
94/// Errors that occur on the client RPC
95#[derive(Debug)]
96pub enum MsaOffchainRpcError {
97	/// Error acquiring lock
98	ErrorAcquiringLock,
99	/// Error decoding data
100	ErrorDecodingData,
101	/// Offchain indexing is not enabled
102	OffchainIndexingNotEnabled,
103}
104
105impl From<MsaOffchainRpcError> for ErrorObjectOwned {
106	fn from(e: MsaOffchainRpcError) -> Self {
107		let msg = format!("{e:?}");
108
109		match e {
110			MsaOffchainRpcError::ErrorAcquiringLock => ErrorObject::owned(1, msg, None::<()>),
111			MsaOffchainRpcError::ErrorDecodingData => ErrorObject::owned(2, msg, None::<()>),
112			MsaOffchainRpcError::OffchainIndexingNotEnabled =>
113				ErrorObject::owned(3, msg, None::<()>),
114		}
115	}
116}
117
118#[async_trait]
119impl<C, Block, OffchainDB, AccountId> MsaApiServer<<Block as BlockT>::Hash, AccountId>
120	for MsaHandler<C, Block, OffchainDB>
121where
122	Block: BlockT,
123	C: Send + Sync + 'static,
124	C: ProvideRuntimeApi<Block>,
125	C: HeaderBackend<Block>,
126	C::Api: MsaRuntimeApi<Block, AccountId>,
127	AccountId: Codec,
128	OffchainDB: sp_core::offchain::OffchainStorage + 'static,
129{
130	fn check_delegations(
131		&self,
132		delegator_msa_ids: Vec<DelegatorId>,
133		provider_msa_id: ProviderId,
134		block_number: BlockNumber,
135		schema_id: Option<SchemaId>,
136	) -> RpcResult<Vec<(DelegatorId, bool)>> {
137		let at = self.client.info().best_hash;
138		let results = delegator_msa_ids
139			.par_iter()
140			.map(|delegator_msa_id| {
141				let api = self.client.runtime_api();
142				// api.has_delegation returns  Result<bool, ApiError>), so _or(false) should not happen,
143				// but just in case, protect against panic
144				let has_delegation: bool = match api.has_delegation(
145					at,
146					*delegator_msa_id,
147					provider_msa_id,
148					block_number,
149					schema_id,
150				) {
151					Ok(result) => result,
152					Err(e) => {
153						warn!("ApiError from has_delegation! {:?}", e);
154						false
155					},
156				};
157				(*delegator_msa_id, has_delegation)
158			})
159			.collect();
160		Ok(results)
161	}
162
163	fn get_granted_schemas_by_msa_id(
164		&self,
165		delegator_msa_id: DelegatorId,
166		provider_msa_id: ProviderId,
167	) -> RpcResult<Option<Vec<SchemaGrant<SchemaId, BlockNumber>>>> {
168		let api = self.client.runtime_api();
169		let at = self.client.info().best_hash;
170		let runtime_api_result =
171			api.get_granted_schemas_by_msa_id(at, delegator_msa_id, provider_msa_id);
172		map_rpc_result(runtime_api_result)
173	}
174
175	fn get_all_granted_delegations_by_msa_id(
176		&self,
177		delegator_msa_id: DelegatorId,
178	) -> RpcResult<Vec<DelegationResponse<SchemaId, BlockNumber>>> {
179		let api = self.client.runtime_api();
180		let at = self.client.info().best_hash;
181		let runtime_api_result = api.get_all_granted_delegations_by_msa_id(at, delegator_msa_id);
182		map_rpc_result(runtime_api_result)
183	}
184
185	fn get_keys_by_msa_id(
186		&self,
187		msa_id: MessageSourceId,
188	) -> RpcResult<Option<KeyInfoResponse<AccountId>>> {
189		let msa_key = get_msa_account_storage_key_name(msa_id);
190		let reader = self.offchain.try_read().ok_or(MsaOffchainRpcError::ErrorAcquiringLock)?;
191		let raw: Option<Bytes> = reader
192			.as_ref()
193			.ok_or(MsaOffchainRpcError::OffchainIndexingNotEnabled)?
194			.get(sp_offchain::STORAGE_PREFIX, &msa_key)
195			.map(Into::into);
196		if let Some(rr) = raw {
197			let inside = rr.0;
198			let keys = Vec::<AccountId>::decode(&mut &inside[..])
199				.map_err(|_| MsaOffchainRpcError::ErrorDecodingData)?;
200			return Ok(Some(KeyInfoResponse { msa_id, msa_keys: keys }))
201		}
202		Ok(None)
203	}
204}