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