authority_selection_inherents/
select_authorities.rs1use crate::MaybeFromCandidateKeys;
4use crate::authority_selection_inputs::AuthoritySelectionInputs;
5use crate::filter_invalid_candidates::{
6 filter_invalid_permissioned_candidates, filter_trustless_candidates_registrations,
7};
8use log::{info, warn};
9use plutus::*;
10use sidechain_domain::{EpochNonce, ScEpochNumber, UtxoId};
11use sp_core::{Get, U256, ecdsa};
12use sp_runtime::BoundedVec;
13use sp_session_validator_management::CommitteeMember;
14
15pub fn select_authorities<
18 TAccountId: Clone + Ord + From<ecdsa::Public>,
19 TAccountKeys: Clone + Ord + MaybeFromCandidateKeys,
20 MaxAuthorities: Get<u32>,
21>(
22 genesis_utxo: UtxoId,
23 input: AuthoritySelectionInputs,
24 sidechain_epoch: ScEpochNumber,
25) -> Option<BoundedVec<CommitteeMember<TAccountId, TAccountKeys>, MaxAuthorities>> {
26 Some(BoundedVec::truncate_from(select_candidates::<TAccountId, TAccountKeys>(
27 genesis_utxo,
28 input,
29 sidechain_epoch,
30 )?))
31}
32
33fn select_candidates<
34 TAccountId: Clone + Ord + From<ecdsa::Public>,
35 TAccountKeys: Clone + Ord + MaybeFromCandidateKeys,
36>(
37 genesis_utxo: UtxoId,
38 input: AuthoritySelectionInputs,
39 sidechain_epoch: ScEpochNumber,
40) -> Option<Vec<CommitteeMember<TAccountId, TAccountKeys>>> {
41 let valid_registered_candidates = filter_trustless_candidates_registrations::<
42 TAccountId,
43 TAccountKeys,
44 >(input.registered_candidates, genesis_utxo);
45 let valid_permissioned_candidates = filter_invalid_permissioned_candidates::<
46 TAccountId,
47 TAccountKeys,
48 >(input.permissioned_candidates);
49 let valid_permissioned_count = valid_permissioned_candidates.len();
50 let valid_registered_count = valid_registered_candidates.len();
51
52 let random_seed = seed_from_nonce_and_sc_epoch(&input.epoch_nonce, &sidechain_epoch);
53
54 if let Some(validators) = selection::ariadne_v2::select_authorities(
55 input.d_parameter.num_registered_candidates,
56 input.d_parameter.num_permissioned_candidates,
57 valid_registered_candidates,
58 valid_permissioned_candidates,
59 random_seed,
60 ) {
61 info!(
62 "💼 Selected committee of {} seats for epoch {} from {valid_permissioned_count} permissioned and {valid_registered_count} registered candidates",
63 validators.len(),
64 sidechain_epoch
65 );
66 Some(validators.into_iter().map(|member| member.into()).collect())
67 } else {
68 warn!("🚫 Failed to select validators for epoch {}", sidechain_epoch);
69 None
70 }
71}
72
73pub fn seed_from_nonce_and_sc_epoch(
75 epoch_nonce: &EpochNonce,
76 partner_chain_epoch_number: &ScEpochNumber,
77) -> [u8; 32] {
78 U256::from_big_endian(&epoch_nonce.as_array())
79 .overflowing_add(U256::from(partner_chain_epoch_number.0))
80 .0
81 .to_big_endian()
82}
83
84#[cfg(test)]
85mod tests {
86 use super::*;
87 use sidechain_domain::{EpochNonce, ScEpochNumber};
88 use sp_core::U256;
89
90 #[test]
91 fn should_create_correct_seed() {
92 let nonce_vec = Vec::from(U256::from(10).to_big_endian());
93 assert_eq!(
94 seed_from_nonce_and_sc_epoch(&EpochNonce(nonce_vec), &ScEpochNumber(2)),
95 U256::from(12).to_big_endian()
96 );
97 }
98}