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