1#![allow(deprecated)]
2#![deny(
4 rustdoc::broken_intra_doc_links,
5 rustdoc::missing_crate_level_docs,
6 rustdoc::invalid_codeblock_attributes,
7 missing_docs
8)]
9
10use common_helpers::rpc::map_rpc_result;
13use common_primitives::{
14 msa::{
15 DelegationGrant, DelegationResponse, DelegatorId, KeyInfoResponse, MessageSourceId,
16 ProviderId,
17 },
18 node::BlockNumber,
19 offchain::get_msa_account_storage_key_name,
20 schema::IntentId,
21};
22use jsonrpsee::{
23 core::{async_trait, RpcResult},
24 proc_macros::rpc,
25 tracing::warn,
26 types::{error::ErrorObjectOwned, ErrorObject},
27};
28use pallet_msa_runtime_api::MsaRuntimeApi;
29use parity_scale_codec::{Codec, Decode, Encode};
30use parking_lot::RwLock;
31use rayon::prelude::*;
32use sp_api::ProvideRuntimeApi;
33use sp_blockchain::HeaderBackend;
34use sp_core::{bytes::from_hex, sr25519, Bytes};
35use sp_runtime::traits::{Block as BlockT, Verify};
36use std::sync::Arc;
37
38#[cfg(test)]
39mod tests;
40
41static AUTH_PUBLIC_KEY: &str = "0x90aa6dfa192c0999ea47397c137507a4f11d45371c54bd5cdbba6f13da24b416";
43
44#[rpc(client, server)]
46pub trait MsaApi<BlockHash, AccountId> {
47 #[deprecated(
51 since = "1.17.6",
52 note = "All custom RPCs are deprecated. Use the state_call RPC instead."
53 )]
54 #[method(name = "msa_checkDelegations")]
55 fn check_delegations(
56 &self,
57 delegator_msa_ids: Vec<DelegatorId>,
58 provider_msa_id: ProviderId,
59 block_number: BlockNumber,
60 intent_id: Option<IntentId>,
61 ) -> RpcResult<Vec<(DelegatorId, bool)>>;
62
63 #[deprecated(
65 since = "1.17.6",
66 note = "All custom RPCs are deprecated. Use the state_call RPC instead."
67 )]
68 #[method(name = "msa_grantedSchemaIdsByMsaId")]
69 fn get_granted_intents_by_msa_id(
70 &self,
71 delegator_msa_id: DelegatorId,
72 provider_msa_id: ProviderId,
73 ) -> RpcResult<Option<Vec<DelegationGrant<IntentId, BlockNumber>>>>;
74
75 #[deprecated(
77 since = "1.17.6",
78 note = "All custom RPCs are deprecated. Use the state_call RPC instead."
79 )]
80 #[method(name = "msa_getAllGrantedDelegationsByMsaId")]
81 fn get_all_granted_delegations_by_msa_id(
82 &self,
83 delegator_msa_id: DelegatorId,
84 ) -> RpcResult<Vec<DelegationResponse<IntentId, BlockNumber>>>;
85
86 #[deprecated(
88 since = "1.17.6",
89 note = "All custom RPCs are deprecated. Use the state_call RPC instead."
90 )]
91 #[method(name = "msa_getKeysByMsaId")]
92 fn get_keys_by_msa_id(
93 &self,
94 msa_id: MessageSourceId,
95 ) -> RpcResult<Option<KeyInfoResponse<AccountId>>>;
96
97 #[method(name = "msa_setKeysByMsaId")]
99 fn set_keys_by_msa_id(
100 &self,
101 msa_id: MessageSourceId,
102 public_keys: Vec<AccountId>,
103 signature_hex: String,
104 ) -> RpcResult<()>;
105}
106
107pub struct MsaHandler<C, M, OffchainDB> {
109 client: Arc<C>,
110 offchain: Arc<RwLock<Option<OffchainDB>>>,
111 _marker: std::marker::PhantomData<M>,
112}
113
114impl<C, M, OffchainDB> MsaHandler<C, M, OffchainDB>
115where
116 OffchainDB: Send + Sync,
117{
118 pub fn new(client: Arc<C>, offchain: Option<OffchainDB>) -> Self {
120 Self { client, offchain: Arc::new(RwLock::new(offchain)), _marker: Default::default() }
121 }
122}
123
124#[derive(Debug)]
126pub enum MsaOffchainRpcError {
127 ErrorAcquiringLock,
129 ErrorDecodingData,
131 OffchainIndexingNotEnabled,
133 InvalidSignature,
135}
136
137impl From<MsaOffchainRpcError> for ErrorObjectOwned {
138 fn from(e: MsaOffchainRpcError) -> Self {
139 let msg = format!("{e:?}");
140
141 match e {
142 MsaOffchainRpcError::ErrorAcquiringLock => ErrorObject::owned(1, msg, None::<()>),
143 MsaOffchainRpcError::ErrorDecodingData => ErrorObject::owned(2, msg, None::<()>),
144 MsaOffchainRpcError::OffchainIndexingNotEnabled =>
145 ErrorObject::owned(3, msg, None::<()>),
146 MsaOffchainRpcError::InvalidSignature => ErrorObject::owned(4, msg, None::<()>),
147 }
148 }
149}
150
151#[async_trait]
152impl<C, Block, OffchainDB, AccountId> MsaApiServer<<Block as BlockT>::Hash, AccountId>
153 for MsaHandler<C, Block, OffchainDB>
154where
155 Block: BlockT,
156 C: Send + Sync + 'static,
157 C: ProvideRuntimeApi<Block>,
158 C: HeaderBackend<Block>,
159 C::Api: MsaRuntimeApi<Block, AccountId>,
160 AccountId: Codec,
161 OffchainDB: sp_core::offchain::OffchainStorage + 'static,
162{
163 fn check_delegations(
164 &self,
165 delegator_msa_ids: Vec<DelegatorId>,
166 provider_msa_id: ProviderId,
167 block_number: BlockNumber,
168 intent_id: Option<IntentId>,
169 ) -> RpcResult<Vec<(DelegatorId, bool)>> {
170 let at = self.client.info().best_hash;
171 let results = delegator_msa_ids
172 .par_iter()
173 .map(|delegator_msa_id| {
174 let api = self.client.runtime_api();
175 let has_delegation: bool = match api.has_delegation(
178 at,
179 *delegator_msa_id,
180 provider_msa_id,
181 block_number,
182 intent_id,
183 ) {
184 Ok(result) => result,
185 Err(e) => {
186 warn!("ApiError from has_delegation! {:?}", e);
187 false
188 },
189 };
190 (*delegator_msa_id, has_delegation)
191 })
192 .collect();
193 Ok(results)
194 }
195
196 fn get_granted_intents_by_msa_id(
197 &self,
198 delegator_msa_id: DelegatorId,
199 provider_msa_id: ProviderId,
200 ) -> RpcResult<Option<Vec<DelegationGrant<IntentId, BlockNumber>>>> {
201 let api = self.client.runtime_api();
202 let at = self.client.info().best_hash;
203 let runtime_api_result =
204 api.get_granted_schemas_by_msa_id(at, delegator_msa_id, provider_msa_id);
205 map_rpc_result(runtime_api_result)
206 }
207
208 fn get_all_granted_delegations_by_msa_id(
209 &self,
210 delegator_msa_id: DelegatorId,
211 ) -> RpcResult<Vec<DelegationResponse<IntentId, BlockNumber>>> {
212 let api = self.client.runtime_api();
213 let at = self.client.info().best_hash;
214 let runtime_api_result = api.get_all_granted_delegations_by_msa_id(at, delegator_msa_id);
215 map_rpc_result(runtime_api_result)
216 }
217
218 fn get_keys_by_msa_id(
219 &self,
220 msa_id: MessageSourceId,
221 ) -> RpcResult<Option<KeyInfoResponse<AccountId>>> {
222 let msa_key = get_msa_account_storage_key_name(msa_id);
223 let reader = self.offchain.try_read().ok_or(MsaOffchainRpcError::ErrorAcquiringLock)?;
224 let raw: Option<Bytes> = reader
225 .as_ref()
226 .ok_or(MsaOffchainRpcError::OffchainIndexingNotEnabled)?
227 .get(sp_offchain::STORAGE_PREFIX, &msa_key)
228 .map(Into::into);
229 if let Some(rr) = raw {
230 let inside = rr.0;
231 let keys = Vec::<AccountId>::decode(&mut &inside[..])
232 .map_err(|_| MsaOffchainRpcError::ErrorDecodingData)?;
233 return Ok(Some(KeyInfoResponse { msa_id, msa_keys: keys }))
234 }
235 Ok(None)
236 }
237
238 fn set_keys_by_msa_id(
239 &self,
240 msa_id: MessageSourceId,
241 public_keys: Vec<AccountId>,
242 signature_hex: String,
243 ) -> RpcResult<()> {
244 let sig = sr25519::Signature::from_raw(
245 from_hex(&signature_hex)
246 .map_err(|_| MsaOffchainRpcError::ErrorDecodingData)?
247 .try_into()
248 .map_err(|_| MsaOffchainRpcError::ErrorDecodingData)?,
249 );
250 let auth_key = from_hex(AUTH_PUBLIC_KEY)
251 .map_err(|_| MsaOffchainRpcError::ErrorDecodingData)?
252 .try_into()
253 .map_err(|_| MsaOffchainRpcError::ErrorDecodingData)?;
254 let auth_key = sr25519::Public::from_raw(auth_key);
255
256 let payload = (msa_id, &public_keys).encode();
257
258 if sig.verify(&payload[..], &auth_key) {
259 let msa_key = get_msa_account_storage_key_name(msa_id);
260 let mut writer =
261 self.offchain.try_write().ok_or(MsaOffchainRpcError::ErrorAcquiringLock)?;
262 writer.as_mut().ok_or(MsaOffchainRpcError::OffchainIndexingNotEnabled)?.set(
263 sp_offchain::STORAGE_PREFIX,
264 &msa_key,
265 &public_keys.encode(),
266 );
267 return Ok(())
268 }
269
270 Err(MsaOffchainRpcError::InvalidSignature.into())
271 }
272}