authority_selection_inherents/
select_authorities.rs

1//! Functionality related to selecting the validators from the valid candidates
2
3use crate::authority_selection_inputs::AuthoritySelectionInputs;
4use crate::filter_invalid_candidates::{
5	Candidate, filter_invalid_permissioned_candidates, filter_trustless_candidates_registrations,
6};
7use log::{info, warn};
8use plutus::*;
9use sidechain_domain::{EpochNonce, ScEpochNumber, UtxoId};
10use sp_core::{U256, ecdsa, ed25519, sr25519};
11
12/// Selects authorities using the Ariadne selection algorithm and data sourced from Partner Chains smart contracts on Cardano.
13/// Seed is constructed from the MC epoch nonce and the sidechain epoch.
14pub fn select_authorities<
15	TAccountId: Clone + Ord + TryFrom<sidechain_domain::SidechainPublicKey> + From<ecdsa::Public>,
16	TAccountKeys: Clone + Ord + From<(sr25519::Public, ed25519::Public)>,
17>(
18	genesis_utxo: UtxoId,
19	input: AuthoritySelectionInputs,
20	sidechain_epoch: ScEpochNumber,
21) -> Option<Vec<Candidate<TAccountId, TAccountKeys>>> {
22	let valid_registered_candidates = filter_trustless_candidates_registrations::<
23		TAccountId,
24		TAccountKeys,
25	>(input.registered_candidates, genesis_utxo);
26	let valid_permissioned_candidates =
27		filter_invalid_permissioned_candidates(input.permissioned_candidates);
28	let valid_permissioned_count = valid_permissioned_candidates.len();
29	let valid_registered_count = valid_registered_candidates.len();
30
31	let random_seed = seed_from_nonce_and_sc_epoch(&input.epoch_nonce, &sidechain_epoch);
32
33	if let Some(validators) = selection::ariadne_v2::select_authorities(
34		input.d_parameter.num_registered_candidates,
35		input.d_parameter.num_permissioned_candidates,
36		valid_registered_candidates,
37		valid_permissioned_candidates,
38		random_seed,
39	) {
40		info!(
41			"💼 Selected committee of {} seats for epoch {} from {valid_permissioned_count} permissioned and {valid_registered_count} registered candidates",
42			validators.len(),
43			sidechain_epoch
44		);
45		Some(validators)
46	} else {
47		warn!("🚫 Failed to select validators for epoch {}", sidechain_epoch);
48		None
49	}
50}
51
52/// Generate 32 byte seed from epoch nonce and Partner Chain epoch number
53pub fn seed_from_nonce_and_sc_epoch(
54	epoch_nonce: &EpochNonce,
55	partner_chain_epoch_number: &ScEpochNumber,
56) -> [u8; 32] {
57	U256::from_big_endian(&epoch_nonce.as_array())
58		.overflowing_add(U256::from(partner_chain_epoch_number.0))
59		.0
60		.to_big_endian()
61}
62
63#[cfg(test)]
64mod tests {
65	use super::*;
66	use sidechain_domain::{EpochNonce, ScEpochNumber};
67	use sp_core::U256;
68
69	#[test]
70	fn should_create_correct_seed() {
71		let nonce_vec = Vec::from(U256::from(10).to_big_endian());
72		assert_eq!(
73			seed_from_nonce_and_sc_epoch(&EpochNonce(nonce_vec), &ScEpochNumber(2)),
74			U256::from(12).to_big_endian()
75		);
76	}
77}