common_primitives/
msa.rs

1use core::fmt::Debug;
2use frame_support::{dispatch::DispatchResult, traits::Get, BoundedBTreeMap, BoundedVec};
3use parity_scale_codec::{Decode, DecodeWithMemTracking, Encode, EncodeLike, Error, MaxEncodedLen};
4use scale_info::TypeInfo;
5#[cfg(feature = "std")]
6use serde::{Deserialize, Serialize};
7use sp_runtime::{
8	traits::{AtLeast32BitUnsigned, Zero},
9	DispatchError, MultiSignature, RuntimeDebug,
10};
11extern crate alloc;
12use alloc::vec::Vec;
13
14pub use crate::schema::SchemaId;
15
16/// ApplicationIndex type
17pub type ApplicationIndex = u16;
18
19/// ApplicationContext is type of ProviderRegistryEntry
20pub type ApplicationContext<NameSize, LangSize, CidSize, MaxLocaleCount> =
21	ProviderRegistryEntry<NameSize, LangSize, CidSize, MaxLocaleCount>;
22
23/// Message Source Id or msaId is the unique identifier for Message Source Accounts
24pub type MessageSourceId = u64;
25
26/// Ethereum address type alias
27pub use sp_core::H160;
28
29/// Response type for getting Ethereum address as a 20-byte array and checksummed hex string
30#[derive(TypeInfo, Encode, Decode)]
31pub struct AccountId20Response {
32	/// Ethereum address as a 20-byte array
33	pub account_id: H160,
34
35	/// Ethereum address as a checksummed 42-byte hex string (including 0x prefix)
36	pub account_id_checksummed: alloc::string::String,
37}
38
39/// A DelegatorId an MSA Id serving the role of a Delegator.
40/// Delegators delegate to Providers.
41/// Encodes and Decodes as just a `u64`
42#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
43#[derive(TypeInfo, Default, Debug, Clone, Copy, PartialEq, MaxEncodedLen, Eq)]
44pub struct DelegatorId(pub MessageSourceId);
45
46impl EncodeLike for DelegatorId {}
47
48impl Encode for DelegatorId {
49	fn encode(&self) -> Vec<u8> {
50		self.0.encode()
51	}
52}
53
54impl DecodeWithMemTracking for DelegatorId {}
55
56impl Decode for DelegatorId {
57	fn decode<I: parity_scale_codec::Input>(
58		input: &mut I,
59	) -> Result<Self, parity_scale_codec::Error> {
60		match <u64>::decode(input) {
61			Ok(x) => Ok(DelegatorId(x)),
62			_ => Err(Error::from("Could not decode DelegatorId")),
63		}
64	}
65}
66
67impl From<MessageSourceId> for DelegatorId {
68	fn from(t: MessageSourceId) -> Self {
69		DelegatorId(t)
70	}
71}
72
73impl From<DelegatorId> for MessageSourceId {
74	fn from(t: DelegatorId) -> MessageSourceId {
75		t.0
76	}
77}
78
79/// RPC response for getting delegated providers with their permissions
80#[cfg_attr(feature = "std", derive(Deserialize, Serialize))]
81#[derive(TypeInfo, RuntimeDebug, Clone, Decode, Encode, MaxEncodedLen, Eq)]
82pub struct DelegationResponse<SchemaId, BlockNumber> {
83	/// SchemaId of schema for which permission is/was granted
84	pub provider_id: ProviderId,
85	/// The list of schema permissions grants
86	pub permissions: Vec<SchemaGrant<SchemaId, BlockNumber>>,
87}
88
89/// RPC response for getting schema permission grants
90#[cfg_attr(feature = "std", derive(Deserialize, Serialize))]
91#[derive(TypeInfo, RuntimeDebug, Clone, Decode, Encode, MaxEncodedLen, Eq)]
92pub struct SchemaGrant<SchemaId, BlockNumber> {
93	/// SchemaId of schema for which permission is/was granted
94	pub schema_id: SchemaId,
95	/// Block number the permission was/will be revoked (0 = not revoked)
96	pub revoked_at: BlockNumber,
97}
98
99impl<SchemaId, BlockNumber> PartialEq for DelegationResponse<SchemaId, BlockNumber>
100where
101	SchemaId: PartialEq,
102	BlockNumber: PartialEq,
103{
104	fn eq(&self, other: &Self) -> bool {
105		self.provider_id == other.provider_id && self.permissions == other.permissions
106	}
107}
108
109impl<SchemaId, BlockNumber> SchemaGrant<SchemaId, BlockNumber> {
110	/// Create a new SchemaGrant struct
111	pub fn new(schema_id: SchemaId, revoked_at: BlockNumber) -> Self {
112		SchemaGrant { schema_id, revoked_at }
113	}
114}
115
116impl<SchemaId, BlockNumber> PartialEq for SchemaGrant<SchemaId, BlockNumber>
117where
118	SchemaId: PartialEq,
119	BlockNumber: PartialEq,
120{
121	fn eq(&self, other: &Self) -> bool {
122		self.schema_id == other.schema_id && self.revoked_at == other.revoked_at
123	}
124}
125
126/// Struct for the information of the relationship between an MSA and a Provider
127#[derive(TypeInfo, RuntimeDebug, Clone, Decode, Encode, MaxEncodedLen, Eq)]
128#[scale_info(skip_type_params(MaxSchemaGrantsPerDelegation))]
129pub struct Delegation<SchemaId, BlockNumber, MaxSchemaGrantsPerDelegation>
130where
131	MaxSchemaGrantsPerDelegation: Get<u32>,
132{
133	/// Block number the grant will be revoked.
134	pub revoked_at: BlockNumber,
135	/// Schemas that the provider is allowed to use for a delegated message.
136	pub schema_permissions: BoundedBTreeMap<SchemaId, BlockNumber, MaxSchemaGrantsPerDelegation>,
137}
138
139// Cannot derive the PartialEq without a mess of impl PartialEq for MaxSchemaGrantsPerDelegation
140impl<SchemaId, BlockNumber, MaxSchemaGrantsPerDelegation> PartialEq
141	for Delegation<SchemaId, BlockNumber, MaxSchemaGrantsPerDelegation>
142where
143	SchemaId: PartialEq,
144	BlockNumber: PartialEq,
145	MaxSchemaGrantsPerDelegation: Get<u32>,
146{
147	fn eq(&self, other: &Self) -> bool {
148		self.revoked_at == other.revoked_at && self.schema_permissions == other.schema_permissions
149	}
150}
151
152impl<
153		SchemaId: Ord + Default,
154		BlockNumber: Ord + Copy + Zero + AtLeast32BitUnsigned + Default,
155		MaxSchemaGrantsPerDelegation: Get<u32>,
156	> Default for Delegation<SchemaId, BlockNumber, MaxSchemaGrantsPerDelegation>
157{
158	/// Provides the default values for Delegation type.
159	fn default() -> Self {
160		Delegation {
161			revoked_at: BlockNumber::default(),
162			schema_permissions: BoundedBTreeMap::<
163				SchemaId,
164				BlockNumber,
165				MaxSchemaGrantsPerDelegation,
166			>::new(),
167		}
168	}
169}
170
171/// Provider is the recipient of a delegation.
172/// It is a subset of an MSA
173/// Encodes and Decodes as just a `u64`
174#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
175#[derive(TypeInfo, Default, Debug, Clone, Copy, PartialEq, MaxEncodedLen, Eq)]
176pub struct ProviderId(pub MessageSourceId);
177
178impl EncodeLike for ProviderId {}
179
180impl Encode for ProviderId {
181	fn encode(&self) -> Vec<u8> {
182		self.0.encode()
183	}
184}
185
186impl DecodeWithMemTracking for ProviderId {}
187
188impl Decode for ProviderId {
189	fn decode<I: parity_scale_codec::Input>(
190		input: &mut I,
191	) -> Result<Self, parity_scale_codec::Error> {
192		match <u64>::decode(input) {
193			Ok(x) => Ok(ProviderId(x)),
194			_ => Err(Error::from("Could not decode ProviderId")),
195		}
196	}
197}
198
199impl From<MessageSourceId> for ProviderId {
200	fn from(t: MessageSourceId) -> Self {
201		ProviderId(t)
202	}
203}
204
205impl From<ProviderId> for MessageSourceId {
206	fn from(t: ProviderId) -> MessageSourceId {
207		t.0
208	}
209}
210
211/// This is the metadata associated with a provider. As of now it is just a
212/// name, but it will likely be expanded in the future
213/// Generic over size constraints to be used in common types.
214#[derive(
215	MaxEncodedLen, TypeInfo, Clone, Debug, Decode, DecodeWithMemTracking, Encode, PartialEq, Eq,
216)]
217#[scale_info(skip_type_params(NameSize, LangSize, CidSize, MaxLocaleCount))]
218#[codec(mel_bound(
219	NameSize: Get<u32> + Debug + PartialEq + Eq,
220	LangSize: Get<u32> + Debug + PartialEq + Eq,
221	CidSize: Get<u32> + Debug + PartialEq + Eq,
222	MaxLocaleCount: Get<u32> + Debug + PartialEq + Eq,
223))]
224pub struct ProviderRegistryEntry<
225	NameSize: Get<u32> + Debug + PartialEq + Eq,
226	LangSize: Get<u32> + Debug + PartialEq + Eq,
227	CidSize: Get<u32> + Debug + PartialEq + Eq,
228	MaxLocaleCount: Get<u32> + Debug + PartialEq + Eq,
229> {
230	/// Default name (display name) of the provider or application.
231	pub default_name: BoundedVec<u8, NameSize>,
232
233	/// Localized names keyed by BCP 47 language code (e.g., "en-US").
234	pub localized_names:
235		BoundedBTreeMap<BoundedVec<u8, LangSize>, BoundedVec<u8, NameSize>, MaxLocaleCount>,
236
237	/// Default logo (PNG 250x100) content-addressed CID (e.g., IPFS hash).
238	pub default_logo_250_100_png_cid: BoundedVec<u8, CidSize>,
239
240	/// Localized logo CIDs keyed by BCP 47 language code.
241	pub localized_logo_250_100_png_cids:
242		BoundedBTreeMap<BoundedVec<u8, LangSize>, BoundedVec<u8, CidSize>, MaxLocaleCount>,
243}
244
245impl<NameSize, LangSize, CidSize, MaxLocaleCount> Default
246	for ProviderRegistryEntry<NameSize, LangSize, CidSize, MaxLocaleCount>
247where
248	NameSize: Get<u32> + Debug + PartialEq + Eq,
249	LangSize: Get<u32> + Debug + PartialEq + Eq,
250	CidSize: Get<u32> + Debug + PartialEq + Eq,
251	MaxLocaleCount: Get<u32> + Debug + PartialEq + Eq,
252{
253	fn default() -> Self {
254		Self {
255			default_name: BoundedVec::default(),
256			localized_names: BoundedBTreeMap::default(),
257			default_logo_250_100_png_cid: BoundedVec::default(),
258			localized_logo_250_100_png_cids: BoundedBTreeMap::default(),
259		}
260	}
261}
262
263/// RPC Response for getting ProviderApplicationContext
264#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
265#[derive(TypeInfo, Debug, Clone, Decode, Encode, PartialEq, Default)]
266pub struct ProviderApplicationContext {
267	/// The default name associated with this entry
268	pub default_name: Vec<u8>,
269	/// The provider associated with the `key`
270	pub provider_id: ProviderId,
271	/// The default Application/Provider logo
272	pub default_logo_250_100_png_bytes: Option<Vec<u8>>,
273	/// The optional application id
274	pub application_id: Option<ApplicationIndex>,
275	/// The optional localized name
276	pub localized_name: Option<Vec<u8>>,
277	/// The optional localized logo bytes
278	pub localized_logo_250_100_png_bytes: Option<Vec<u8>>,
279}
280
281/// The pointer value for the Signature Registry
282#[derive(MaxEncodedLen, TypeInfo, Debug, Clone, Decode, Encode, PartialEq, Eq)]
283pub struct SignatureRegistryPointer<BlockNumber> {
284	/// The newest signature that will be added to the registry when we get the next newest
285	pub newest: MultiSignature,
286
287	/// Block number that `newest` expires at
288	pub newest_expires_at: BlockNumber,
289
290	/// Pointer to the oldest signature in the list
291	pub oldest: MultiSignature,
292
293	/// Count of signatures in the registry
294	/// Will eventually match the `MaxSignaturesStored`, but during initialization is needed to fill the list
295	pub count: u32,
296}
297
298/// A behavior that allows looking up an MSA id
299pub trait MsaLookup {
300	/// The association between key and MSA
301	type AccountId;
302
303	/// Gets the MSA Id associated with this `AccountId` if any
304	fn get_msa_id(key: &Self::AccountId) -> Option<MessageSourceId>;
305}
306
307/// A behavior that allows for validating an MSA
308pub trait MsaValidator {
309	/// The association between key and MSA
310	type AccountId;
311
312	/// Check that a key is associated to an MSA and returns key information.
313	/// Returns a [`DispatchError`] if there is no MSA associated with the key
314	fn ensure_valid_msa_key(key: &Self::AccountId) -> Result<MessageSourceId, DispatchError>;
315}
316
317/// A behavior that allows for looking up delegator-provider relationships
318pub trait ProviderLookup {
319	/// Type for block number.
320	type BlockNumber;
321	/// Type for maximum number of schemas that can be granted to a provider.
322	type MaxSchemaGrantsPerDelegation: Get<u32>;
323	/// Schema Id is the unique identifier for a Schema
324	type SchemaId;
325
326	/// Gets the relationship information for this delegator, provider pair
327	fn get_delegation_of(
328		delegator: DelegatorId,
329		provider: ProviderId,
330	) -> Option<Delegation<Self::SchemaId, Self::BlockNumber, Self::MaxSchemaGrantsPerDelegation>>;
331}
332
333/// A behavior that allows for validating a delegator-provider relationship
334pub trait DelegationValidator {
335	/// Type for block number.
336	type BlockNumber;
337	/// Type for maximum number of schemas that can be granted to a provider.
338	type MaxSchemaGrantsPerDelegation: Get<u32>;
339	/// Schema Id is the unique identifier for a Schema
340	type SchemaId;
341
342	/// Validates that the delegator and provider have a relationship at this point
343	fn ensure_valid_delegation(
344		provider: ProviderId,
345		delegator: DelegatorId,
346		block_number: Option<Self::BlockNumber>,
347	) -> Result<
348		Delegation<Self::SchemaId, Self::BlockNumber, Self::MaxSchemaGrantsPerDelegation>,
349		DispatchError,
350	>;
351}
352
353/// A behavior that allows for validating a schema grant
354pub trait SchemaGrantValidator<BlockNumber> {
355	/// Validates if the provider is allowed to use the particular schema id currently
356	fn ensure_valid_schema_grant(
357		provider_id: ProviderId,
358		delegator_id: DelegatorId,
359		schema_id: SchemaId,
360		block_number: BlockNumber,
361	) -> DispatchResult;
362}
363
364/// A trait that allows checking whether adding a key may be subsidized
365pub trait MsaKeyProvider {
366	/// the type to use for looking up keys in storage.
367	type AccountId;
368	/// Returns whether adding `new_key` to `msa_id` may be subsidized
369	fn key_eligible_for_subsidized_addition(
370		old_key: Self::AccountId,
371		new_key: Self::AccountId,
372		msa_id: MessageSourceId,
373	) -> bool;
374}
375
376/// RPC Response for getting MSA keys
377#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
378#[derive(TypeInfo, Debug, Clone, Decode, Encode, PartialEq, Default, MaxEncodedLen)]
379pub struct KeyInfoResponse<AccountId> {
380	/// The MSA associated with the `key`
381	pub msa_id: MessageSourceId,
382	/// The list of `AccountId` associated with the `msa_id`
383	pub msa_keys: Vec<AccountId>,
384}
385
386#[cfg(test)]
387mod tests {
388	use super::*;
389
390	#[test]
391	fn decoding_provider_id_failure() {
392		let mut da: &[u8] = b"\xf6\xf5";
393		let decoded = DelegatorId::decode(&mut da);
394		assert!(decoded.is_err());
395	}
396
397	#[test]
398	fn decoding_provider_id_success() {
399		let val = 16777215_u64.encode();
400		let decoded = ProviderId::decode(&mut &val[..]);
401		assert_eq!(decoded, Ok(ProviderId(16777215)))
402	}
403
404	#[test]
405	fn decoding_delegate_id_failure() {
406		let mut da: &[u8] = b"\xf6\xf5";
407		let decoded = DelegatorId::decode(&mut da);
408		assert!(decoded.is_err());
409	}
410
411	#[test]
412	fn decoding_delegator_id_success() {
413		let val = 42_u64.encode();
414		let decoded = DelegatorId::decode(&mut &val[..]);
415		assert_eq!(decoded, Ok(DelegatorId(42)))
416	}
417}