pallet_msa_rpc/
lib.rs

1#![allow(deprecated)]
2// Strong Documentation Lints
3#![deny(
4	rustdoc::broken_intra_doc_links,
5	rustdoc::missing_crate_level_docs,
6	rustdoc::invalid_codeblock_attributes,
7	missing_docs
8)]
9
10//! Custom APIs for [MSA](../pallet_msa/index.html)
11
12use 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
41/// A key used to sign the payloads for offchain key overrides
42static AUTH_PUBLIC_KEY: &str = "0x90aa6dfa192c0999ea47397c137507a4f11d45371c54bd5cdbba6f13da24b416";
43
44/// Frequency MSA Custom RPC API
45#[rpc(client, server)]
46pub trait MsaApi<BlockHash, AccountId> {
47	/// Check for a list of delegations
48	/// Given a single provider, test a list of potential delegators
49	/// At a given block number
50	#[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	/// Retrieve the list of currently granted schemas given a delegator and provider pair
64	#[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	/// Retrieve the list of all delegations for a MsaId
76	#[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	/// Retrieve the list of keys for msa id
87	#[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	/// Set the list of keys for msa id
98	#[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
107/// The client handler for the API used by Frequency Service RPC with `jsonrpsee`
108pub 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	/// Create new instance with the given reference to the client.
119	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/// Errors that occur on the client RPC
125#[derive(Debug)]
126pub enum MsaOffchainRpcError {
127	/// Error acquiring lock
128	ErrorAcquiringLock,
129	/// Error decoding data
130	ErrorDecodingData,
131	/// Offchain indexing is not enabled
132	OffchainIndexingNotEnabled,
133	/// Invalid signature
134	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				// api.has_delegation returns  Result<bool, ApiError>), so _or(false) should not happen,
176				// but just in case, protect against panic
177				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}