sp_session_validator_management/
lib.rs

1//! # Primitives for Partner Chain committee selection.
2//!
3//! This crate implements shared types and traits used to implement Partner Chain committee rotation.
4
5#![cfg_attr(not(feature = "std"), no_std)]
6#![deny(missing_docs)]
7
8#[cfg(feature = "std")]
9use core::str::FromStr;
10
11use scale_info::TypeInfo;
12use sidechain_domain::{MainchainAddress, PolicyId, byte_string::SizedByteString};
13use sp_core::{Decode, Encode, MaxEncodedLen};
14use sp_inherents::{InherentIdentifier, IsFatalError};
15
16/// Inherent identifier used by the Committee Selection pallet
17pub const INHERENT_IDENTIFIER: InherentIdentifier = *b"/ariadne";
18
19#[derive(Encode, sp_runtime::RuntimeDebug, PartialEq, Eq)]
20#[cfg_attr(feature = "std", derive(Decode, thiserror::Error))]
21/// Error type used for failing calls of the Committee Selection inherent.
22pub enum InherentError {
23	#[deprecated(
24		since = "1.5.0",
25		note = "Use InvalidValidatorsMatchingHash or InvalidValidatorsHashMismatch"
26	)]
27	#[cfg_attr(
28		feature = "std",
29		error("The validators in the block do not match the calculated validators")
30	)]
31	/// The validators in the block do not match the calculated validators
32	InvalidValidators,
33	#[cfg_attr(
34		feature = "std",
35		error("Candidates inherent required: committee needs to be stored one epoch in advance")
36	)]
37	/// Candidates inherent required: committee needs to be stored one epoch in advance
38	CommitteeNeedsToBeStoredOneEpochInAdvance,
39	#[cfg_attr(
40		feature = "std",
41		error("The validators in the block do not match the calculated validators. Input data hash ({}) is valid.", .0.to_hex_string())
42	)]
43	/// The validators in the block do not match the calculated validators, but the input data hash is valid.
44	InvalidValidatorsMatchingHash(SizedByteString<32>),
45	#[cfg_attr(
46		feature = "std",
47		error("The validators and input data hash in the block do not match the calculated values. Expected hash: {}, got: {}",
48			.0.to_hex_string(),
49			.1.to_hex_string())
50	)]
51	/// The validators and input data hash in the block do not match the calculated values.
52	InvalidValidatorsHashMismatch(SizedByteString<32>, SizedByteString<32>),
53}
54
55impl IsFatalError for InherentError {
56	fn is_fatal_error(&self) -> bool {
57		true
58	}
59}
60
61/// Signifies that a type represents a committee member
62pub trait CommitteeMember {
63	/// Type representing authority id
64	type AuthorityId;
65	/// Type representing authority keys
66	type AuthorityKeys;
67	/// Returns authority id
68	fn authority_id(&self) -> Self::AuthorityId;
69	/// Returns authority keys
70	fn authority_keys(&self) -> Self::AuthorityKeys;
71}
72impl<AuthorityId: Clone, AuthorityKeys: Clone> CommitteeMember for (AuthorityId, AuthorityKeys) {
73	type AuthorityId = AuthorityId;
74	type AuthorityKeys = AuthorityKeys;
75	fn authority_id(&self) -> AuthorityId {
76		self.0.clone()
77	}
78	fn authority_keys(&self) -> AuthorityKeys {
79		self.1.clone()
80	}
81}
82
83#[cfg(feature = "std")]
84impl From<InherentError> for sp_inherents::Error {
85	fn from(value: InherentError) -> Self {
86		sp_inherents::Error::Application(Box::from(value))
87	}
88}
89
90#[derive(Default, Debug, Clone, PartialEq, Eq, TypeInfo, Encode, Decode, MaxEncodedLen)]
91#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
92/// Collection of all mainchain script info needed for committee selection
93pub struct MainChainScripts {
94	/// [MainchainAddress] where registration UTXOs are located
95	pub committee_candidate_address: MainchainAddress,
96	/// [PolicyId] of D-parameter script
97	pub d_parameter_policy_id: PolicyId,
98	/// [PolicyId] of Permissioned Candidates script
99	pub permissioned_candidates_policy_id: PolicyId,
100}
101
102#[cfg(feature = "std")]
103impl MainChainScripts {
104	/// Reads [MainChainScripts] from env vars:
105	/// - COMMITTEE_CANDIDATE_ADDRESS
106	/// - D_PARAMETER_POLICY_ID
107	/// - PERMISSIONED_CANDIDATES_POLICY_ID
108	pub fn read_from_env() -> Result<MainChainScripts, envy::Error> {
109		#[derive(serde::Serialize, serde::Deserialize)]
110		pub struct MainChainScriptsEnvConfig {
111			pub committee_candidate_address: String,
112			pub d_parameter_policy_id: PolicyId,
113			pub permissioned_candidates_policy_id: PolicyId,
114		}
115
116		let MainChainScriptsEnvConfig {
117			committee_candidate_address,
118			d_parameter_policy_id,
119			permissioned_candidates_policy_id,
120		} = envy::from_env::<MainChainScriptsEnvConfig>()?;
121
122		let committee_candidate_address = FromStr::from_str(&committee_candidate_address)
123			.map_err(|err| envy::Error::Custom(format!("Incorrect main chain address: {}", err)))?;
124
125		Ok(Self {
126			committee_candidate_address,
127			d_parameter_policy_id,
128			permissioned_candidates_policy_id,
129		})
130	}
131}
132
133sp_api::decl_runtime_apis! {
134	#[api_version(2)]
135	/// Runtime API declaration for Session Validator Management
136	pub trait SessionValidatorManagementApi<
137		CommitteeMember: parity_scale_codec::Decode + parity_scale_codec::Encode + crate::CommitteeMember,
138		AuthoritySelectionInputs: parity_scale_codec::Encode,
139		ScEpochNumber: parity_scale_codec::Encode + parity_scale_codec::Decode
140	> where
141	CommitteeMember::AuthorityId: Encode + Decode,
142	CommitteeMember::AuthorityKeys: Encode + Decode,
143	{
144		/// Returns main chain scripts
145		fn get_main_chain_scripts() -> MainChainScripts;
146		/// Returns next unset [sidechain_domain::ScEpochNumber]
147		fn get_next_unset_epoch_number() -> ScEpochNumber;
148
149		#[changed_in(2)]
150		/// Returns current committee
151		fn get_current_committee() -> (ScEpochNumber, sp_std::vec::Vec<CommitteeMember::AuthorityId>);
152		/// Returns current committee
153		fn get_current_committee() -> (ScEpochNumber, sp_std::vec::Vec<CommitteeMember>);
154
155		#[changed_in(2)]
156		/// Returns next committee
157		fn get_next_committee() -> Option<(ScEpochNumber, sp_std::vec::Vec<CommitteeMember::AuthorityId>)>;
158		/// Returns next committee
159		fn get_next_committee() -> Option<(ScEpochNumber, sp_std::vec::Vec<CommitteeMember>)>;
160
161		#[changed_in(2)]
162		/// Calculates committee
163		fn calculate_committee(
164			authority_selection_inputs: AuthoritySelectionInputs,
165			sidechain_epoch: ScEpochNumber
166		) -> Option<sp_std::vec::Vec<(CommitteeMember::AuthorityId, CommitteeMember::AuthorityKeys)>>;
167
168		/// Calculates committee
169		fn calculate_committee(
170			authority_selection_inputs: AuthoritySelectionInputs,
171			sidechain_epoch: ScEpochNumber
172		) -> Option<sp_std::vec::Vec<CommitteeMember>>;
173	}
174}