common_primitives/
msa.rs

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