use std::{sync::Arc, time::Duration};
use crate::UnitCreationDelay;
pub const MAX_ROUNDS: u16 = 7000;
fn exponential_slowdown(
t: usize,
base_delay: f64,
start_exp_delay: usize,
exp_base: f64,
) -> Duration {
let delay = if t < start_exp_delay {
base_delay
} else {
let power = t - start_exp_delay;
base_delay * exp_base.powf(power as f64)
};
let delay = delay.round() as u64;
Duration::from_millis(delay)
}
pub type DelaySchedule = Arc<dyn Fn(usize) -> Duration + Sync + Send + 'static>;
pub fn unit_creation_delay_fn(unit_creation_delay: UnitCreationDelay) -> DelaySchedule {
Arc::new(move |t| match t {
0 => Duration::from_millis(2000),
_ => exponential_slowdown(t, unit_creation_delay.0 as f64, 5000, 1.005),
})
}
const SESSION_LEN_LOWER_BOUND_MS: u128 = 1000 * 60 * 60 * 24 * 7;
pub fn sanity_check_round_delays(max_rounds: u16, round_delays: DelaySchedule) {
let delays_ok = sanity_check_round_delays_inner(max_rounds, round_delays);
assert!(
delays_ok,
"Incorrect setting of delays. Make sure the total AlephBFT session time is at least {SESSION_LEN_LOWER_BOUND_MS}ms."
);
}
fn sanity_check_round_delays_inner(max_rounds: u16, round_delays: DelaySchedule) -> bool {
let mut total_delay = Duration::from_millis(0);
for t in 0..=max_rounds {
total_delay += round_delays(t as usize);
}
total_delay.as_millis() > SESSION_LEN_LOWER_BOUND_MS
}
#[test]
fn sanity_check_fails_on_bad_config() {
let round_delays = unit_creation_delay_fn(UnitCreationDelay(300));
assert!(!sanity_check_round_delays_inner(5000, round_delays));
}
#[test]
fn sanity_check_passes_on_good_config() {
let round_delays = unit_creation_delay_fn(UnitCreationDelay(300));
assert!(sanity_check_round_delays_inner(7000, round_delays));
}