common_primitives/
schema.rs

1extern crate alloc;
2use crate::impl_codec_bitflags;
3#[cfg(feature = "std")]
4use crate::utils;
5use alloc::{vec, vec::Vec};
6use enumflags2::{bitflags, BitFlags};
7use parity_scale_codec::{Decode, DecodeWithMemTracking, Encode, EncodeLike, MaxEncodedLen};
8use scale_info::{build::Fields, meta_type, Path, Type, TypeInfo, TypeParameter};
9use serde::{Deserialize, Serialize};
10use sp_runtime::RuntimeDebug;
11#[cfg(feature = "std")]
12use utils::*;
13
14/// DelegationGrpup Id is the unique identifier for a DelegationGroup
15pub type IntentGroupId = u16;
16
17/// Intent Id is the unique identifier for an Intent
18pub type IntentId = u16;
19
20/// Schema Id is the unique identifier for a Schema
21pub type SchemaId = u16;
22
23/// Schema version number
24// TODO: Remove once all traces of this are gone (ie, removed from runtime API)
25pub type SchemaVersion = u8;
26
27/// Types of modeling in which a message payload may be defined
28#[derive(
29	Copy,
30	Clone,
31	Encode,
32	Decode,
33	DecodeWithMemTracking,
34	PartialEq,
35	Debug,
36	TypeInfo,
37	Eq,
38	MaxEncodedLen,
39	Serialize,
40	Deserialize,
41)]
42pub enum ModelType {
43	/// Message payload modeled with Apache Avro: <https://avro.apache.org/docs/current/spec.html>
44	AvroBinary,
45	/// Message payload modeled with Apache Parquet: <https://parquet.apache.org/>
46	Parquet,
47}
48
49/// Types of payload locations
50#[derive(
51	Copy,
52	Clone,
53	Encode,
54	Decode,
55	DecodeWithMemTracking,
56	PartialEq,
57	Debug,
58	TypeInfo,
59	Eq,
60	MaxEncodedLen,
61	Serialize,
62	Deserialize,
63)]
64pub enum PayloadLocation {
65	/// Message payload is located on chain
66	OnChain,
67	/// Message payload is located on IPFS
68	IPFS,
69	/// Itemized payload location for onchain storage in itemized form
70	Itemized,
71	/// Paginated payload location for onchain storage in paginated form
72	Paginated,
73	/// Message payload is located off-chain, other than IPFS
74	OffChain,
75}
76
77/// Support for up to 16 user-enabled features on a collection.
78#[bitflags]
79#[repr(u16)]
80#[derive(
81	Copy,
82	Clone,
83	RuntimeDebug,
84	PartialEq,
85	Eq,
86	Encode,
87	Decode,
88	DecodeWithMemTracking,
89	MaxEncodedLen,
90	TypeInfo,
91	Serialize,
92	Deserialize,
93)]
94pub enum SchemaSetting {
95	/// Intent setting to enforce append-only behavior on payload.
96	/// Applied to Intents of type `PayloadLocation::Itemized`.
97	AppendOnly,
98	/// Intent may enforce signature requirement on payload.
99	/// Applied to Intents of type `PayloadLocation::Itemized` or `PayloadLocation::Paginated`.
100	SignatureRequired,
101}
102
103/// Wrapper type for `BitFlags<IntentSetting>` that implements `Codec`.
104#[derive(Clone, Copy, PartialEq, Eq, Default, RuntimeDebug)]
105pub struct SchemaSettings(pub BitFlags<IntentSetting>);
106
107/// TODO: temporary alias until we can remove this type from the public API
108pub type IntentSetting = SchemaSetting;
109
110/// TODO: temporary alias until we can remove this type from the public API
111pub type IntentSettings = SchemaSettings;
112
113/// Status of a Schema
114#[derive(
115	Copy,
116	Clone,
117	Encode,
118	Decode,
119	DecodeWithMemTracking,
120	PartialEq,
121	Debug,
122	TypeInfo,
123	Eq,
124	MaxEncodedLen,
125	Serialize,
126	Deserialize,
127)]
128pub enum SchemaStatus {
129	/// Schema is current and approved for writing
130	Active,
131	/// Schema is viable for writing, but is deprecated and may become unsupported soon
132	Deprecated,
133	/// Schema is unsupported; writing to this schema is prohibited
134	Unsupported,
135}
136
137/// RPC response structure for an IntentGroup
138#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
139#[derive(Clone, Encode, Decode, PartialEq, Debug, TypeInfo, Eq)]
140pub struct IntentGroupResponse {
141	/// The unique identifier for this IntentGroup
142	pub intent_group_id: IntentGroupId,
143	/// The list of currently supported IntentIds for this IntentGroup
144	pub intent_ids: Vec<IntentId>,
145}
146
147/// RPC response structure for an Intent
148#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
149#[derive(Clone, Encode, Decode, PartialEq, Debug, TypeInfo, Eq)]
150pub struct IntentResponse {
151	/// The unique identifier for this Intent
152	pub intent_id: IntentId,
153	/// The payload location
154	pub payload_location: PayloadLocation,
155	/// settings for the Intent
156	pub settings: Vec<IntentSetting>,
157	/// The list of currently-supported SchemaIds for this Intent
158	pub schema_ids: Option<Vec<SchemaId>>,
159}
160
161/// RPC Response form for a Schema
162#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
163#[derive(Clone, Encode, Decode, PartialEq, Debug, TypeInfo, Eq)]
164pub struct SchemaResponse {
165	/// The unique identifier for this Schema
166	pub schema_id: SchemaId,
167	/// The data that represents how this schema is structured
168	#[cfg_attr(feature = "std", serde(with = "as_string"))]
169	pub model: Vec<u8>,
170	/// The model format type for how the schema model is represented
171	pub model_type: ModelType,
172	/// The payload location associated with this Schema's associated Intent
173	pub payload_location: PayloadLocation,
174	/// The settings for this Schema's associated Intent
175	pub settings: Vec<SchemaSetting>,
176}
177
178/// RPC Response form for a Schema V2
179#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
180#[derive(Clone, Encode, Decode, PartialEq, Debug, TypeInfo, Eq)]
181pub struct SchemaResponseV2 {
182	/// The unique identifier for this Schema
183	pub schema_id: SchemaId,
184	/// The IntentId of the Intent that this Schema implements
185	pub intent_id: IntentId,
186	/// The data that represents how this schema is structured
187	#[cfg_attr(feature = "std", serde(with = "as_string"))]
188	pub model: Vec<u8>,
189	/// The model format type for how the schema model is represented
190	pub model_type: ModelType,
191	/// The status of this Schema (Active, Deprecated, Unsupported)
192	pub status: SchemaStatus,
193	/// The payload location associated with this Schema's associated Intent
194	pub payload_location: PayloadLocation,
195	/// The settings for this Schema's associated Intent
196	pub settings: Vec<IntentSetting>,
197}
198
199impl Into<SchemaResponse> for SchemaResponseV2 {
200	/// Convert SchemaResponseV2 into SchemaResponse
201	fn into(self) -> SchemaResponse {
202		SchemaResponse {
203			schema_id: self.schema_id,
204			model: self.model,
205			model_type: self.model_type,
206			payload_location: self.payload_location,
207			settings: self.settings,
208		}
209	}
210}
211
212/// RPC Response form for a Schema Info
213#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
214#[derive(Clone, Encode, Decode, PartialEq, Debug, TypeInfo, Eq)]
215pub struct SchemaInfoResponse {
216	/// The unique identifier for this Schema
217	pub schema_id: SchemaId,
218	/// The model format type for how the schema model is represented
219	pub model_type: ModelType,
220	/// The payload location associated with this Schema's associated Intent
221	pub payload_location: PayloadLocation,
222	/// The settings for this Schema's associated Intent
223	pub settings: Vec<IntentSetting>,
224	/// The IntentId of the Intent that this Schema implements
225	pub intent_id: IntentId,
226	/// The status of this Schema (Active, Deprecated, Unsupported)
227	/// Currently has no runtime effect; intended for future use.
228	pub status: SchemaStatus,
229}
230
231#[derive(
232	Copy,
233	Clone,
234	Encode,
235	Decode,
236	DecodeWithMemTracking,
237	PartialEq,
238	Debug,
239	TypeInfo,
240	Eq,
241	MaxEncodedLen,
242	Serialize,
243	Deserialize,
244)]
245/// Enum type for the different types of entities that a FullyQualifiedName can represent
246pub enum MappedEntityIdentifier {
247	/// An Intent
248	Intent(IntentId),
249	/// An IntentGroup
250	IntentGroup(IntentGroupId),
251}
252
253impl Default for MappedEntityIdentifier {
254	fn default() -> Self {
255		Self::Intent(Default::default())
256	}
257}
258
259/// RPC response form for a name resolution lookup
260#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
261#[derive(Clone, Encode, Decode, PartialEq, Debug, TypeInfo, Eq)]
262pub struct NameLookupResponse {
263	/// The name for this entity
264	pub name: Vec<u8>,
265	/// The resolved entity
266	pub entity_id: MappedEntityIdentifier,
267}
268
269/// This allows other pallets to resolve Schema information. With generic SchemaId
270pub trait SchemaProvider<SchemaId> {
271	/// Gets the Schema details associated with this `SchemaId` if any
272	fn get_schema_by_id(schema_id: SchemaId) -> Option<SchemaResponseV2>;
273
274	/// Gets the Schema Info associated with this `SchemaId` if any
275	fn get_schema_info_by_id(schema_id: SchemaId) -> Option<SchemaInfoResponse>;
276
277	/// Gets the Intent associated with this `IntentId`, if any
278	fn get_intent_by_id(intent_id: IntentId) -> Option<IntentResponse>;
279}
280
281/// This allows other Pallets to check the validity of schema ids.
282pub trait SchemaValidator<SchemaId> {
283	/// Checks that all IntentIds in a collection are valid.
284	fn are_all_intent_ids_valid(intent_ids: &[IntentId]) -> bool;
285
286	/// Set the schema counter for testing purposes.
287	#[cfg(any(feature = "std", feature = "runtime-benchmarks", test))]
288	fn set_schema_count(n: SchemaId);
289
290	/// Set the Intent counter for testing purposes.
291	#[cfg(any(feature = "std", feature = "runtime-benchmarks", test))]
292	fn set_intent_count(n: IntentId);
293}
294
295impl IntentSettings {
296	/// Returns new SchemaSettings with all settings disabled
297	pub fn all_disabled() -> Self {
298		Self(BitFlags::EMPTY)
299	}
300	/// Get all setting enabled
301	pub fn get_enabled(&self) -> BitFlags<IntentSetting> {
302		self.0
303	}
304	/// Check if a setting is enabled
305	pub fn is_enabled(&self, grant: IntentSetting) -> bool {
306		self.0.contains(grant)
307	}
308	/// Enable a setting
309	pub fn set(&mut self, grant: IntentSetting) {
310		self.0.insert(grant)
311	}
312	/// Copy the settings from a BitFlags
313	pub fn from(settings: BitFlags<IntentSetting>) -> Self {
314		Self(settings)
315	}
316}
317impl_codec_bitflags!(IntentSettings, u16, IntentSetting);
318
319impl From<Vec<IntentSetting>> for IntentSettings {
320	/// Copy the settings from a vector of individual settings enums
321	fn from(settings: Vec<IntentSetting>) -> Self {
322		Self(BitFlags::from_iter(settings))
323	}
324}
325
326/// RPC Response from a schema name query
327#[cfg_attr(feature = "std", derive(Serialize, Deserialize))]
328#[derive(Clone, Encode, Decode, PartialEq, Debug, TypeInfo, Eq)]
329pub struct SchemaVersionResponse {
330	/// Schema name in following format: namespace.descriptor
331	#[cfg_attr(feature = "std", serde(with = "as_string"))]
332	pub schema_name: Vec<u8>,
333	/// The version for this schema
334	pub schema_version: SchemaVersion,
335	/// The unique identifier for this Schema
336	pub schema_id: SchemaId,
337}
338
339#[cfg(test)]
340mod tests {
341	use super::*;
342
343	#[test]
344	fn intent_settings_when_disabled_has_no_enabled() {
345		let settings = IntentSettings::all_disabled();
346		assert_eq!(settings.get_enabled(), BitFlags::EMPTY);
347	}
348
349	#[test]
350	fn intent_settings_set_from_all_enabled_check() {
351		let settings = IntentSettings::from(BitFlags::ALL);
352		assert!(settings.is_enabled(IntentSetting::AppendOnly));
353		assert!(settings.is_enabled(IntentSetting::SignatureRequired));
354	}
355}