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