sp_session_validator_management_query/
get_registrations.rs

1//! Module implementing getting candidate registrations for epoch
2use crate::*;
3use authority_selection_inherents::{CandidateValidationApi, RegistrationDataError, StakeError};
4use sidechain_domain::{
5	CandidateRegistrations, MainchainAddress, McEpochNumber, RegistrationData, StakeDelegation,
6};
7use sp_core::bytes::to_hex;
8use sp_sidechain::GetGenesisUtxo;
9
10impl<
11	C,
12	Block,
13	AuthorityId: parity_scale_codec::Decode + Send + Sync + 'static,
14	SessionKeys: parity_scale_codec::Decode + Send + Sync + 'static,
15> SessionValidatorManagementQuery<C, Block, AuthorityId, SessionKeys>
16where
17	Block: BlockT,
18	C: HeaderBackend<Block>,
19	C: 'static + ProvideRuntimeApi<Block> + Send + Sync,
20	C::Api: GetGenesisUtxo<Block>,
21	C::Api: CandidateValidationApi<Block>,
22{
23	async fn registrations_to_rpc_response(
24		&self,
25		candidate_registrations: Vec<CandidateRegistrations>,
26	) -> Result<GetRegistrationsResponseMap, String> {
27		let api = self.client.runtime_api();
28		let best_block = self.client.info().best_hash;
29
30		let registration_data_validation =
31			|pub_key: &StakePoolPublicKey, registration_data: &RegistrationData| {
32				api.validate_registered_candidate_data(best_block, pub_key, registration_data)
33			};
34		let stake_validation = |stake_delegation: &Option<StakeDelegation>| {
35			api.validate_stake(best_block, *stake_delegation)
36		};
37		get_registrations_response_map(
38			candidate_registrations,
39			registration_data_validation,
40			stake_validation,
41		)
42		.map_err(|err| format!("{err:?}"))
43	}
44
45	pub(crate) async fn candidates_registrations_for_epoch(
46		&self,
47		mc_epoch_number: McEpochNumber,
48		committee_candidate_address: MainchainAddress,
49	) -> Result<GetRegistrationsResponseMap, String> {
50		let candidates = get_candidates_for_epoch(
51			mc_epoch_number,
52			self.candidate_data_source.as_ref(),
53			committee_candidate_address,
54		)
55		.await?;
56		self.registrations_to_rpc_response(candidates).await
57	}
58}
59
60/// Creates a map that maps a Candidate's Mainchain Public Key to its Registration Information
61fn get_registrations_response_map(
62	candidates: Vec<CandidateRegistrations>,
63	validate_registration_data: impl Fn(
64		&StakePoolPublicKey,
65		&RegistrationData,
66	) -> Result<Option<RegistrationDataError>, sp_api::ApiError>,
67	validate_stake: impl Fn(&Option<StakeDelegation>) -> Result<Option<StakeError>, sp_api::ApiError>,
68) -> Result<GetRegistrationsResponseMap, sp_api::ApiError> {
69	let mut map = GetRegistrationsResponseMap::new();
70
71	for candidate in candidates {
72		let mainchain_pub_key = candidate.mainchain_pub_key().clone();
73
74		let mut registration_entries: Vec<CandidateRegistrationEntry> = candidate
75			.registrations
76			.iter()
77			.map(|registration_data| {
78				let registration_data_validation_result =
79					validate_registration_data(&mainchain_pub_key, registration_data)?;
80				Ok::<CandidateRegistrationEntry, sp_api::ApiError>(CandidateRegistrationEntry::new(
81					registration_data.clone(),
82					mainchain_pub_key.clone(),
83					candidate.stake_delegation,
84					registration_data_validation_result,
85				))
86			})
87			.collect::<Result<Vec<_>, _>>()?;
88
89		registration_entries.sort_by_key(|entry| entry.utxo.ordering_key());
90		let latest_valid_or_zero = registration_entries
91			.iter()
92			.rposition(|registration| registration.is_valid)
93			.unwrap_or(0);
94
95		registration_entries.drain(..latest_valid_or_zero);
96		if let Some(err) = validate_stake(&candidate.stake_delegation)? {
97			if let Some(first) = registration_entries.first_mut() {
98				if first.is_valid {
99					first.is_valid = false;
100					first.invalid_reasons = Some(err.into());
101				}
102			}
103		}
104
105		map.insert(to_hex(&mainchain_pub_key.0, false), registration_entries);
106	}
107
108	Ok(map)
109}
110
111pub(crate) async fn get_candidates_for_epoch(
112	mainchain_epoch: McEpochNumber,
113	candidate_data_source: &(dyn AuthoritySelectionDataSource + Send + Sync),
114	committee_candidate_address: MainchainAddress,
115) -> Result<Vec<CandidateRegistrations>, String> {
116	candidate_data_source
117		.get_candidates(mainchain_epoch, committee_candidate_address)
118		.await
119		.map_err(|err| format!("{err:?}"))
120}