sp_session_validator_management/
lib.rs

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