use crate::tools::config;
use crate::tools::time::{DurationMillis, MILLIS_IN_MINUTE, MILLIS_IN_MONTH};
use crate::tools::types::Pow;
pub fn get_minimum_post_pow(post_length: usize, linked_base_ids_len: usize, duration: DurationMillis) -> Pow {
assert!(duration > MILLIS_IN_MINUTE);
let pow_amplification_post_length = if post_length <= 1024 { 1.0f64 } else { 1.0f64 + 1.75 * (post_length as f64 / 1024f64).log2() };
let pow_amplification_linked_base_ids = if linked_base_ids_len < 2 {1.0f64} else { 1.0f64 + 0.2f64 * (linked_base_ids_len as f64).powi(2) };
let pow_amplification_bucket = 1.0f64 + (MILLIS_IN_MONTH.0 as f64 / duration.0 as f64).log2();
let pow_amplification = pow_amplification_post_length * pow_amplification_linked_base_ids * pow_amplification_bucket;
let additional_pow_bits = pow_amplification.log2().ceil();
Pow(config::POW_MINIMUM_PER_POST.0 + additional_pow_bits as u8)
}
#[cfg(test)]
mod tests {
use super::*;
use crate::tools::config;
use crate::tools::time::{MILLIS_IN_DAY, MILLIS_IN_HOUR, MILLIS_IN_MONTH};
use crate::tools::types::Pow;
#[test]
fn baseline() {
let pow = get_minimum_post_pow(512, 1, MILLIS_IN_MONTH);
assert_eq!(pow, config::POW_MINIMUM_PER_POST);
}
#[test]
fn day_bucket() {
let pow = get_minimum_post_pow(512, 1, MILLIS_IN_DAY);
assert_eq!(pow, Pow(config::POW_MINIMUM_PER_POST.0 + 3));
}
#[test]
fn hour_bucket() {
let pow = get_minimum_post_pow(512, 1, MILLIS_IN_HOUR);
assert_eq!(pow, Pow(config::POW_MINIMUM_PER_POST.0 + 4));
}
#[test]
fn linked_ids() {
let pow = get_minimum_post_pow(512, 3, MILLIS_IN_MONTH);
assert_eq!(pow, Pow(config::POW_MINIMUM_PER_POST.0 + 2));
}
#[test]
fn combined() {
let pow = get_minimum_post_pow(4096, 3, MILLIS_IN_DAY);
assert_eq!(pow, Pow(config::POW_MINIMUM_PER_POST.0 + 7));
}
#[test]
fn medium_post_4kb() {
let pow = get_minimum_post_pow(4 * 1024, 1, MILLIS_IN_MONTH);
assert_eq!(pow, Pow(config::POW_MINIMUM_PER_POST.0 + 3));
}
#[test]
fn large_post_64kb() {
let pow = get_minimum_post_pow(64 * 1024, 1, MILLIS_IN_MONTH);
assert_eq!(pow, Pow(config::POW_MINIMUM_PER_POST.0 + 4));
}
#[test]
fn large_post_512kb() {
let pow = get_minimum_post_pow(512 * 1024, 1, MILLIS_IN_MONTH);
assert_eq!(pow, Pow(config::POW_MINIMUM_PER_POST.0 + 5));
}
#[test]
fn minute_granularity_5min() {
let pow = get_minimum_post_pow(512, 1, MILLIS_IN_MINUTE.const_mul(5));
assert_eq!(pow, Pow(config::POW_MINIMUM_PER_POST.0 + 4));
}
#[test]
fn many_linked_ids_10() {
let pow = get_minimum_post_pow(512, 10, MILLIS_IN_MONTH);
assert_eq!(pow, Pow(config::POW_MINIMUM_PER_POST.0 + 5));
}
#[test]
fn monotone_duration() {
let pow_month = get_minimum_post_pow(512, 1, MILLIS_IN_MONTH);
let pow_day = get_minimum_post_pow(512, 1, MILLIS_IN_DAY);
let pow_hour = get_minimum_post_pow(512, 1, MILLIS_IN_HOUR);
assert!(pow_month <= pow_day);
assert!(pow_day <= pow_hour);
assert!(pow_month < pow_hour);
}
#[test]
fn monotone_linked_ids() {
let pow_1 = get_minimum_post_pow(512, 1, MILLIS_IN_DAY);
let pow_2 = get_minimum_post_pow(512, 2, MILLIS_IN_DAY);
let pow_3 = get_minimum_post_pow(512, 3, MILLIS_IN_DAY);
let pow_4 = get_minimum_post_pow(512, 4, MILLIS_IN_DAY);
assert!(pow_1 <= pow_2);
assert!(pow_2 <= pow_3);
assert!(pow_3 <= pow_4);
assert!(pow_1 < pow_4);
}
#[test]
fn monotone_post_length() {
let pow_small = get_minimum_post_pow(1024, 1, MILLIS_IN_DAY);
let pow_medium = get_minimum_post_pow(8192, 1, MILLIS_IN_DAY);
let pow_large = get_minimum_post_pow(1024 * 1024, 1, MILLIS_IN_DAY);
assert!(pow_small <= pow_medium);
assert!(pow_medium <= pow_large);
assert!(pow_small < pow_large);
}
#[test]
fn never_below_minimum() {
let lengths = [1, 512, 1024, 4096, 64 * 1024];
let links = [1, 2, 5, 10];
let durations = [MILLIS_IN_HOUR, MILLIS_IN_DAY, MILLIS_IN_MONTH];
for post_length in lengths {
for linked_base_ids_len in links {
for duration in durations {
let pow = get_minimum_post_pow(post_length, linked_base_ids_len, duration);
assert!(
pow >= config::POW_MINIMUM_PER_POST,
"pow={:?} below minimum for post_length={} links={} duration={:?}",
pow, post_length, linked_base_ids_len, duration
);
}
}
}
}
#[test]
#[should_panic]
fn panic_on_short_duration() {
get_minimum_post_pow(512, 1, MILLIS_IN_MINUTE);
}
}