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, Encode};
28use parking_lot::RwLock;
29use rayon::prelude::*;
30use sp_api::ProvideRuntimeApi;
31use sp_blockchain::HeaderBackend;
32use sp_core::{bytes::from_hex, sr25519, Bytes};
33use sp_runtime::traits::{Block as BlockT, Verify};
34use std::sync::Arc;
35
36#[cfg(test)]
37mod tests;
38
39static AUTH_PUBLIC_KEY: &str = "0x90aa6dfa192c0999ea47397c137507a4f11d45371c54bd5cdbba6f13da24b416";
41
42#[rpc(client, server)]
44pub trait MsaApi<BlockHash, AccountId> {
45 #[method(name = "msa_checkDelegations")]
49 fn check_delegations(
50 &self,
51 delegator_msa_ids: Vec<DelegatorId>,
52 provider_msa_id: ProviderId,
53 block_number: BlockNumber,
54 schema_id: Option<SchemaId>,
55 ) -> RpcResult<Vec<(DelegatorId, bool)>>;
56
57 #[method(name = "msa_grantedSchemaIdsByMsaId")]
59 fn get_granted_schemas_by_msa_id(
60 &self,
61 delegator_msa_id: DelegatorId,
62 provider_msa_id: ProviderId,
63 ) -> RpcResult<Option<Vec<SchemaGrant<SchemaId, BlockNumber>>>>;
64
65 #[method(name = "msa_getAllGrantedDelegationsByMsaId")]
67 fn get_all_granted_delegations_by_msa_id(
68 &self,
69 delegator_msa_id: DelegatorId,
70 ) -> RpcResult<Vec<DelegationResponse<SchemaId, BlockNumber>>>;
71
72 #[method(name = "msa_getKeysByMsaId")]
74 fn get_keys_by_msa_id(
75 &self,
76 msa_id: MessageSourceId,
77 ) -> RpcResult<Option<KeyInfoResponse<AccountId>>>;
78
79 #[method(name = "msa_setKeysByMsaId")]
81 fn set_keys_by_msa_id(
82 &self,
83 msa_id: MessageSourceId,
84 public_keys: Vec<AccountId>,
85 signature_hex: String,
86 ) -> RpcResult<()>;
87}
88
89pub struct MsaHandler<C, M, OffchainDB> {
91 client: Arc<C>,
92 offchain: Arc<RwLock<Option<OffchainDB>>>,
93 _marker: std::marker::PhantomData<M>,
94}
95
96impl<C, M, OffchainDB> MsaHandler<C, M, OffchainDB>
97where
98 OffchainDB: Send + Sync,
99{
100 pub fn new(client: Arc<C>, offchain: Option<OffchainDB>) -> Self {
102 Self { client, offchain: Arc::new(RwLock::new(offchain)), _marker: Default::default() }
103 }
104}
105
106#[derive(Debug)]
108pub enum MsaOffchainRpcError {
109 ErrorAcquiringLock,
111 ErrorDecodingData,
113 OffchainIndexingNotEnabled,
115 InvalidSignature,
117}
118
119impl From<MsaOffchainRpcError> for ErrorObjectOwned {
120 fn from(e: MsaOffchainRpcError) -> Self {
121 let msg = format!("{e:?}");
122
123 match e {
124 MsaOffchainRpcError::ErrorAcquiringLock => ErrorObject::owned(1, msg, None::<()>),
125 MsaOffchainRpcError::ErrorDecodingData => ErrorObject::owned(2, msg, None::<()>),
126 MsaOffchainRpcError::OffchainIndexingNotEnabled =>
127 ErrorObject::owned(3, msg, None::<()>),
128 MsaOffchainRpcError::InvalidSignature => ErrorObject::owned(4, msg, None::<()>),
129 }
130 }
131}
132
133#[async_trait]
134impl<C, Block, OffchainDB, AccountId> MsaApiServer<<Block as BlockT>::Hash, AccountId>
135 for MsaHandler<C, Block, OffchainDB>
136where
137 Block: BlockT,
138 C: Send + Sync + 'static,
139 C: ProvideRuntimeApi<Block>,
140 C: HeaderBackend<Block>,
141 C::Api: MsaRuntimeApi<Block, AccountId>,
142 AccountId: Codec,
143 OffchainDB: sp_core::offchain::OffchainStorage + 'static,
144{
145 fn check_delegations(
146 &self,
147 delegator_msa_ids: Vec<DelegatorId>,
148 provider_msa_id: ProviderId,
149 block_number: BlockNumber,
150 schema_id: Option<SchemaId>,
151 ) -> RpcResult<Vec<(DelegatorId, bool)>> {
152 let at = self.client.info().best_hash;
153 let results = delegator_msa_ids
154 .par_iter()
155 .map(|delegator_msa_id| {
156 let api = self.client.runtime_api();
157 let has_delegation: bool = match api.has_delegation(
160 at,
161 *delegator_msa_id,
162 provider_msa_id,
163 block_number,
164 schema_id,
165 ) {
166 Ok(result) => result,
167 Err(e) => {
168 warn!("ApiError from has_delegation! {:?}", e);
169 false
170 },
171 };
172 (*delegator_msa_id, has_delegation)
173 })
174 .collect();
175 Ok(results)
176 }
177
178 fn get_granted_schemas_by_msa_id(
179 &self,
180 delegator_msa_id: DelegatorId,
181 provider_msa_id: ProviderId,
182 ) -> RpcResult<Option<Vec<SchemaGrant<SchemaId, BlockNumber>>>> {
183 let api = self.client.runtime_api();
184 let at = self.client.info().best_hash;
185 let runtime_api_result =
186 api.get_granted_schemas_by_msa_id(at, delegator_msa_id, provider_msa_id);
187 map_rpc_result(runtime_api_result)
188 }
189
190 fn get_all_granted_delegations_by_msa_id(
191 &self,
192 delegator_msa_id: DelegatorId,
193 ) -> RpcResult<Vec<DelegationResponse<SchemaId, BlockNumber>>> {
194 let api = self.client.runtime_api();
195 let at = self.client.info().best_hash;
196 let runtime_api_result = api.get_all_granted_delegations_by_msa_id(at, delegator_msa_id);
197 map_rpc_result(runtime_api_result)
198 }
199
200 fn get_keys_by_msa_id(
201 &self,
202 msa_id: MessageSourceId,
203 ) -> RpcResult<Option<KeyInfoResponse<AccountId>>> {
204 let msa_key = get_msa_account_storage_key_name(msa_id);
205 let reader = self.offchain.try_read().ok_or(MsaOffchainRpcError::ErrorAcquiringLock)?;
206 let raw: Option<Bytes> = reader
207 .as_ref()
208 .ok_or(MsaOffchainRpcError::OffchainIndexingNotEnabled)?
209 .get(sp_offchain::STORAGE_PREFIX, &msa_key)
210 .map(Into::into);
211 if let Some(rr) = raw {
212 let inside = rr.0;
213 let keys = Vec::<AccountId>::decode(&mut &inside[..])
214 .map_err(|_| MsaOffchainRpcError::ErrorDecodingData)?;
215 return Ok(Some(KeyInfoResponse { msa_id, msa_keys: keys }))
216 }
217 Ok(None)
218 }
219
220 fn set_keys_by_msa_id(
221 &self,
222 msa_id: MessageSourceId,
223 public_keys: Vec<AccountId>,
224 signature_hex: String,
225 ) -> RpcResult<()> {
226 let sig = sr25519::Signature::from_raw(
227 from_hex(&signature_hex)
228 .map_err(|_| MsaOffchainRpcError::ErrorDecodingData)?
229 .try_into()
230 .map_err(|_| MsaOffchainRpcError::ErrorDecodingData)?,
231 );
232 let auth_key = from_hex(AUTH_PUBLIC_KEY)
233 .map_err(|_| MsaOffchainRpcError::ErrorDecodingData)?
234 .try_into()
235 .map_err(|_| MsaOffchainRpcError::ErrorDecodingData)?;
236 let auth_key = sr25519::Public::from_raw(auth_key);
237
238 let payload = (msa_id, &public_keys).encode();
239
240 if sig.verify(&payload[..], &auth_key) {
241 let msa_key = get_msa_account_storage_key_name(msa_id);
242 let mut writer =
243 self.offchain.try_write().ok_or(MsaOffchainRpcError::ErrorAcquiringLock)?;
244 writer.as_mut().ok_or(MsaOffchainRpcError::OffchainIndexingNotEnabled)?.set(
245 sp_offchain::STORAGE_PREFIX,
246 &msa_key,
247 &public_keys.encode(),
248 );
249 return Ok(())
250 }
251
252 Err(MsaOffchainRpcError::InvalidSignature.into())
253 }
254}