1#![deny(
3 rustdoc::broken_intra_doc_links,
4 rustdoc::missing_crate_level_docs,
5 rustdoc::invalid_codeblock_attributes,
6 missing_docs
7)]
8
9use 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#[rpc(client, server)]
41pub trait MsaApi<BlockHash, AccountId> {
42 #[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 #[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 #[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 #[method(name = "msa_getKeysByMsaId")]
71 fn get_keys_by_msa_id(
72 &self,
73 msa_id: MessageSourceId,
74 ) -> RpcResult<Option<KeyInfoResponse<AccountId>>>;
75}
76
77pub 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 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#[derive(Debug)]
96pub enum MsaOffchainRpcError {
97 ErrorAcquiringLock,
99 ErrorDecodingData,
101 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 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}