sp_session_validator_management_query/
get_registrations.rs

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