authority_selection_inherents/
authority_selection_inputs.rs

1//! Types for authority selection
2use parity_scale_codec::{Decode, DecodeWithMemTracking, Encode};
3use plutus::*;
4use scale_info::TypeInfo;
5use sidechain_domain::*;
6
7/// The part of data for selection of authorities that comes from the main chain.
8/// It is unfiltered, so the selection algorithm should filter out invalid candidates.
9#[derive(Clone, Debug, Encode, Decode, DecodeWithMemTracking, TypeInfo, PartialEq, Eq)]
10pub struct AuthoritySelectionInputs {
11	/// D-parameter for Ariadne committee selection. See [DParameter] for details.
12	pub d_parameter: DParameter,
13	/// List of permissioned candidates for committee selection.
14	pub permissioned_candidates: Vec<PermissionedCandidateData>,
15	/// List of registered candidates for committee selection
16	pub registered_candidates: Vec<CandidateRegistrations>,
17	/// Nonce for queried epoch.
18	pub epoch_nonce: EpochNonce,
19}
20
21#[cfg(feature = "std")]
22#[derive(Debug, thiserror::Error)]
23/// Error type for creation of [AuthoritySelectionInputs]
24pub enum AuthoritySelectionInputsCreationError {
25	#[cfg_attr(
26		feature = "std",
27		error(
28			"Failed to get Ariadne parameters for epoch: {0}, D-parameter: {1:?}, permissioned candidates: {2:?}: {3}"
29		)
30	)]
31	/// Failed to get Ariadne parameters for epoch
32	AriadneParametersQuery(
33		McEpochNumber,
34		PolicyId,
35		PolicyId,
36		Box<dyn std::error::Error + Send + Sync>,
37	),
38	#[cfg_attr(
39		feature = "std",
40		error(
41			"Failed to get registered candidates for epoch: {0}, committee candidate address: {1}: {2}."
42		)
43	)]
44	/// Failed to get registered candidates for epoch
45	GetCandidatesQuery(McEpochNumber, String, Box<dyn std::error::Error + Send + Sync>),
46	#[cfg_attr(feature = "std", error("Failed to get epoch nonce for epoch: {0}: {1}."))]
47	/// Failed to get epoch nonce for epoch
48	GetEpochNonceQuery(McEpochNumber, Box<dyn std::error::Error + Send + Sync>),
49}
50
51#[derive(Debug, Clone, PartialEq, serde::Serialize)]
52/// Permissioned candidate data from Cardano main chain
53pub struct RawPermissionedCandidateData {
54	/// Unvalidated Partner Chain public key of permissioned candidate
55	pub sidechain_public_key: SidechainPublicKey,
56	/// Unvalidated Aura public key of permissioned candidate
57	pub aura_public_key: AuraPublicKey,
58	/// Unvalidated Grandpa public key of permissioned candidate
59	pub grandpa_public_key: GrandpaPublicKey,
60}
61
62#[derive(Debug, Clone, PartialEq, serde::Serialize)]
63/// Ariadne selection algorithm parameters owned by the Partner Chain Governance Authority.
64pub struct AriadneParameters {
65	/// D-parameter for Ariadne committee selection. See [DParameter] for details.
66	pub d_parameter: DParameter,
67	/// List of permissioned candidates for committee selection.
68	/// [None] means that a list of permissioned candidates has not been set on the mainchain.
69	pub permissioned_candidates: Option<Vec<RawPermissionedCandidateData>>,
70}
71
72/// Queries about the Authority Candidates
73#[cfg(feature = "std")]
74#[async_trait::async_trait]
75pub trait AuthoritySelectionDataSource {
76	/// Returns D-parameter and list of permissioned candidates that is effective for the given epoch.
77	/// The data from the latest block of `data_epoch(epoch)` will be used if available, otherwise returns data at the latest block of the chain.
78	async fn get_ariadne_parameters(
79		&self,
80		epoch_number: McEpochNumber,
81		d_parameter: PolicyId,
82		permissioned_candidates: PolicyId,
83	) -> Result<AriadneParameters, Box<dyn std::error::Error + Send + Sync>>;
84
85	/// Returns the list of registrations that is effective for the given epoch.
86	/// The data from the latest block of `data_epoch(epoch)` will be used if available, otherwise returns data at the latest block of the chain.
87	/// Each item is a list of one candidate registrations.
88	async fn get_candidates(
89		&self,
90		epoch: McEpochNumber,
91		committee_candidate_address: MainchainAddress,
92	) -> Result<Vec<CandidateRegistrations>, Box<dyn std::error::Error + Send + Sync>>;
93
94	/// Returns Cardano Epoch Nonce. None, if the nonce for given epoch is not known yet.
95	async fn get_epoch_nonce(
96		&self,
97		epoch: McEpochNumber,
98	) -> Result<Option<EpochNonce>, Box<dyn std::error::Error + Send + Sync>>;
99
100	///
101	/// # Arguments
102	///
103	/// * `for_epoch`: main chain epoch number during which candidate data is meant to be used
104	///
105	/// returns: Result<McEpochNumber, Box<dyn std::error::Error + Send + Sync>> - data source methods called with `for_epoch` will query only for data which was stored on main chain in the returned epoch or earlier
106	///
107	///
108	async fn data_epoch(
109		&self,
110		for_epoch: McEpochNumber,
111	) -> Result<McEpochNumber, Box<dyn std::error::Error + Send + Sync>>;
112}
113
114impl AuthoritySelectionInputs {
115	#[cfg(feature = "std")]
116	pub(crate) async fn from_mc_data(
117		candidate_data_source: &(dyn AuthoritySelectionDataSource + Send + Sync),
118		for_epoch: McEpochNumber,
119		scripts: sp_session_validator_management::MainChainScripts,
120	) -> Result<Self, AuthoritySelectionInputsCreationError> {
121		let ariadne_parameters_response = candidate_data_source
122			.get_ariadne_parameters(
123				for_epoch,
124				scripts.d_parameter_policy_id.clone(),
125				scripts.permissioned_candidates_policy_id.clone(),
126			)
127			.await
128			.map_err(|err| {
129				AuthoritySelectionInputsCreationError::AriadneParametersQuery(
130					for_epoch,
131					scripts.d_parameter_policy_id.clone(),
132					scripts.permissioned_candidates_policy_id.clone(),
133					err,
134				)
135			})?;
136
137		let d_parameter = ariadne_parameters_response.d_parameter;
138		let no_permissioned_candidates_expected = d_parameter.num_permissioned_candidates == 0;
139		let permissioned_candidates = match ariadne_parameters_response.permissioned_candidates {
140			None if no_permissioned_candidates_expected => Vec::new(),
141			None => {
142				return Err(AuthoritySelectionInputsCreationError::AriadneParametersQuery(
143					for_epoch,
144					scripts.d_parameter_policy_id,
145					scripts.permissioned_candidates_policy_id,
146					("Expected Data Not Found: Permissioned Candidates List".to_string()).into(),
147				));
148			},
149			Some(permissioned_candidates) => permissioned_candidates
150				.into_iter()
151				.map(|candidate| PermissionedCandidateData {
152					sidechain_public_key: candidate.sidechain_public_key,
153					aura_public_key: candidate.aura_public_key,
154					grandpa_public_key: candidate.grandpa_public_key,
155				})
156				.collect::<Vec<PermissionedCandidateData>>(),
157		};
158
159		let registered_candidates: Vec<CandidateRegistrations> = candidate_data_source
160			.get_candidates(for_epoch, scripts.committee_candidate_address.clone())
161			.await
162			.map_err(|err| {
163				AuthoritySelectionInputsCreationError::GetCandidatesQuery(
164					for_epoch,
165					scripts.committee_candidate_address.to_string(),
166					err,
167				)
168			})?;
169		let epoch_nonce_response =
170			candidate_data_source.get_epoch_nonce(for_epoch).await.map_err(|err| {
171				AuthoritySelectionInputsCreationError::GetEpochNonceQuery(for_epoch, err)
172			})?;
173		let epoch_nonce = epoch_nonce_response.unwrap_or(EpochNonce(vec![]));
174
175		Ok(Self { d_parameter, permissioned_candidates, registered_candidates, epoch_nonce })
176	}
177}