use crate::keyring::Keyring;
use itertools::Itertools;
use polkadot_primitives::{AssignmentId, AuthorityDiscoveryId, ValidatorId, ValidatorPair};
use rand::thread_rng;
use rand_distr::{Distribution, Normal, Uniform};
use sc_network_types::PeerId;
use serde::{Deserialize, Serialize};
use sp_consensus_babe::AuthorityId;
use sp_core::Pair;
use std::collections::HashMap;
#[derive(Clone, Debug, Default, Serialize, Deserialize)]
pub struct PeerLatency {
pub mean_latency_ms: usize,
pub std_dev: f64,
}
fn default_n_validators() -> usize {
300
}
fn default_n_cores() -> usize {
60
}
fn default_pov_size() -> usize {
5 * 1024
}
fn default_bandwidth() -> usize {
42 * 1024 * 1024
}
fn default_peer_latency() -> Option<PeerLatency> {
Some(PeerLatency { mean_latency_ms: 30, std_dev: 2.0 })
}
fn default_connectivity() -> usize {
90
}
fn default_backing_group_size() -> usize {
5
}
fn default_needed_approvals() -> usize {
30
}
fn default_zeroth_delay_tranche_width() -> usize {
0
}
fn default_relay_vrf_modulo_samples() -> usize {
6
}
fn default_n_delay_tranches() -> usize {
89
}
fn default_no_show_slots() -> usize {
3
}
fn default_minimum_backing_votes() -> u32 {
2
}
fn default_max_candidate_depth() -> u32 {
3
}
fn default_allowed_ancestry_len() -> u32 {
2
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct TestConfiguration {
#[serde(default = "default_n_validators")]
pub n_validators: usize,
#[serde(default = "default_n_cores")]
pub n_cores: usize,
#[serde(default = "default_needed_approvals")]
pub needed_approvals: usize,
#[serde(default = "default_zeroth_delay_tranche_width")]
pub zeroth_delay_tranche_width: usize,
#[serde(default = "default_relay_vrf_modulo_samples")]
pub relay_vrf_modulo_samples: usize,
#[serde(default = "default_n_delay_tranches")]
pub n_delay_tranches: usize,
#[serde(default = "default_no_show_slots")]
pub no_show_slots: usize,
#[serde(default = "default_backing_group_size")]
pub max_validators_per_core: usize,
#[serde(default = "default_pov_size")]
pub min_pov_size: usize,
#[serde(default = "default_pov_size")]
pub max_pov_size: usize,
#[serde(skip)]
pub pov_sizes: Vec<usize>,
#[serde(default = "default_bandwidth")]
pub peer_bandwidth: usize,
#[serde(default = "default_bandwidth")]
pub bandwidth: usize,
#[serde(default = "default_peer_latency")]
pub latency: Option<PeerLatency>,
#[serde(default = "default_connectivity")]
pub connectivity: usize,
pub num_blocks: usize,
#[serde(default = "default_minimum_backing_votes")]
pub minimum_backing_votes: u32,
#[serde(default = "default_max_candidate_depth")]
pub max_candidate_depth: u32,
#[serde(default = "default_allowed_ancestry_len")]
pub allowed_ancestry_len: u32,
}
impl Default for TestConfiguration {
fn default() -> Self {
Self {
n_validators: default_n_validators(),
n_cores: default_n_cores(),
needed_approvals: default_needed_approvals(),
zeroth_delay_tranche_width: default_zeroth_delay_tranche_width(),
relay_vrf_modulo_samples: default_relay_vrf_modulo_samples(),
n_delay_tranches: default_n_delay_tranches(),
no_show_slots: default_no_show_slots(),
max_validators_per_core: default_backing_group_size(),
min_pov_size: default_pov_size(),
max_pov_size: default_pov_size(),
pov_sizes: Default::default(),
peer_bandwidth: default_bandwidth(),
bandwidth: default_bandwidth(),
latency: default_peer_latency(),
connectivity: default_connectivity(),
num_blocks: Default::default(),
minimum_backing_votes: default_minimum_backing_votes(),
max_candidate_depth: default_max_candidate_depth(),
allowed_ancestry_len: default_allowed_ancestry_len(),
}
}
}
impl TestConfiguration {
pub fn generate_pov_sizes(&mut self) {
self.pov_sizes = generate_pov_sizes(self.n_cores, self.min_pov_size, self.max_pov_size);
}
pub fn pov_sizes(&self) -> &[usize] {
&self.pov_sizes
}
pub fn connected_count(&self) -> usize {
((self.n_validators - 1) as f64 / (100.0 / self.connectivity as f64)) as usize
}
pub fn generate_authorities(&self) -> TestAuthorities {
let keyring = Keyring::default();
let key_seeds = (0..self.n_validators)
.map(|peer_index| format!("//Node{}", peer_index))
.collect_vec();
let keys = key_seeds
.iter()
.map(|seed| keyring.sr25519_new(seed.as_str()))
.collect::<Vec<_>>();
let validator_public: Vec<ValidatorId> =
keys.iter().map(|key| (*key).into()).collect::<Vec<_>>();
let validator_authority_id: Vec<AuthorityDiscoveryId> =
keys.iter().map(|key| (*key).into()).collect::<Vec<_>>();
let validator_babe_id: Vec<AuthorityId> =
keys.iter().map(|key| (*key).into()).collect::<Vec<_>>();
let validator_assignment_id: Vec<AssignmentId> =
keys.iter().map(|key| (*key).into()).collect::<Vec<_>>();
let peer_ids: Vec<PeerId> = keys.iter().map(|_| PeerId::random()).collect::<Vec<_>>();
let peer_id_to_authority = peer_ids
.iter()
.zip(validator_authority_id.iter())
.map(|(peer_id, authority_id)| (*peer_id, authority_id.clone()))
.collect();
let validator_pairs = key_seeds
.iter()
.map(|seed| ValidatorPair::from_string_with_seed(seed, None).unwrap().0)
.collect();
TestAuthorities {
keyring,
validator_public,
validator_authority_id,
peer_ids,
validator_babe_id,
validator_assignment_id,
key_seeds,
peer_id_to_authority,
validator_pairs,
}
}
}
fn random_uniform_sample<T: Into<usize> + From<usize>>(min_value: T, max_value: T) -> T {
Uniform::from(min_value.into()..=max_value.into())
.sample(&mut thread_rng())
.into()
}
fn random_pov_size(min_pov_size: usize, max_pov_size: usize) -> usize {
random_uniform_sample(min_pov_size, max_pov_size)
}
fn generate_pov_sizes(count: usize, min_kib: usize, max_kib: usize) -> Vec<usize> {
(0..count).map(|_| random_pov_size(min_kib * 1024, max_kib * 1024)).collect()
}
#[derive(Clone)]
pub struct TestAuthorities {
pub keyring: Keyring,
pub validator_public: Vec<ValidatorId>,
pub validator_authority_id: Vec<AuthorityDiscoveryId>,
pub validator_babe_id: Vec<AuthorityId>,
pub validator_assignment_id: Vec<AssignmentId>,
pub key_seeds: Vec<String>,
pub peer_ids: Vec<PeerId>,
pub peer_id_to_authority: HashMap<PeerId, AuthorityDiscoveryId>,
pub validator_pairs: Vec<ValidatorPair>,
}
pub fn random_latency(maybe_peer_latency: Option<&PeerLatency>) -> usize {
maybe_peer_latency
.map(|latency_config| {
Normal::new(latency_config.mean_latency_ms as f64, latency_config.std_dev)
.expect("normal distribution parameters are good")
.sample(&mut thread_rng())
})
.unwrap_or(0.0) as usize
}