authority_selection_inherents/
authority_selection_inputs.rs

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