hashiverse_lib/protocol/posting/
amplification.rs1use crate::tools::config;
18use crate::tools::time::{DurationMillis, MILLIS_IN_MINUTE, MILLIS_IN_MONTH};
19use crate::tools::types::Pow;
20
21pub fn get_minimum_post_pow(post_length: usize, linked_base_ids_len: usize, duration: DurationMillis) -> Pow {
22 assert!(duration > MILLIS_IN_MINUTE);
23
24 let pow_amplification_post_length = if post_length <= 1024 { 1.0f64 } else { 1.0f64 + 1.75 * (post_length as f64 / 1024f64).log2() };
25 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) };
26 let pow_amplification_bucket = 1.0f64 + (MILLIS_IN_MONTH.0 as f64 / duration.0 as f64).log2();
27
28 let pow_amplification = pow_amplification_post_length * pow_amplification_linked_base_ids * pow_amplification_bucket;
29 let additional_pow_bits = pow_amplification.log2().ceil();
30 Pow(config::POW_MINIMUM_PER_POST.0 + additional_pow_bits as u8)
31}
32
33
34#[cfg(test)]
35mod tests {
36 use super::*;
37 use crate::tools::config;
38 use crate::tools::time::{MILLIS_IN_DAY, MILLIS_IN_HOUR, MILLIS_IN_MONTH};
39 use crate::tools::types::Pow;
40
41 #[test]
43 fn baseline() {
44 let pow = get_minimum_post_pow(512, 1, MILLIS_IN_MONTH);
45 assert_eq!(pow, config::POW_MINIMUM_PER_POST);
46 }
47
48 #[test]
50 fn day_bucket() {
51 let pow = get_minimum_post_pow(512, 1, MILLIS_IN_DAY);
52 assert_eq!(pow, Pow(config::POW_MINIMUM_PER_POST.0 + 3));
53 }
54
55 #[test]
57 fn hour_bucket() {
58 let pow = get_minimum_post_pow(512, 1, MILLIS_IN_HOUR);
59 assert_eq!(pow, Pow(config::POW_MINIMUM_PER_POST.0 + 4));
60 }
61
62 #[test]
64 fn linked_ids() {
65 let pow = get_minimum_post_pow(512, 3, MILLIS_IN_MONTH);
66 assert_eq!(pow, Pow(config::POW_MINIMUM_PER_POST.0 + 2));
67 }
68
69 #[test]
71 fn combined() {
72 let pow = get_minimum_post_pow(4096, 3, MILLIS_IN_DAY);
73 assert_eq!(pow, Pow(config::POW_MINIMUM_PER_POST.0 + 7));
74 }
75
76 #[test]
78 fn medium_post_4kb() {
79 let pow = get_minimum_post_pow(4 * 1024, 1, MILLIS_IN_MONTH);
80 assert_eq!(pow, Pow(config::POW_MINIMUM_PER_POST.0 + 3));
81 }
82
83 #[test]
85 fn large_post_64kb() {
86 let pow = get_minimum_post_pow(64 * 1024, 1, MILLIS_IN_MONTH);
87 assert_eq!(pow, Pow(config::POW_MINIMUM_PER_POST.0 + 4));
88 }
89
90 #[test]
92 fn large_post_512kb() {
93 let pow = get_minimum_post_pow(512 * 1024, 1, MILLIS_IN_MONTH);
94 assert_eq!(pow, Pow(config::POW_MINIMUM_PER_POST.0 + 5));
95 }
96
97 #[test]
99 fn minute_granularity_5min() {
100 let pow = get_minimum_post_pow(512, 1, MILLIS_IN_MINUTE.const_mul(5));
101 assert_eq!(pow, Pow(config::POW_MINIMUM_PER_POST.0 + 4));
102 }
103
104 #[test]
106 fn many_linked_ids_10() {
107 let pow = get_minimum_post_pow(512, 10, MILLIS_IN_MONTH);
108 assert_eq!(pow, Pow(config::POW_MINIMUM_PER_POST.0 + 5));
109 }
110
111 #[test]
113 fn monotone_duration() {
114 let pow_month = get_minimum_post_pow(512, 1, MILLIS_IN_MONTH);
115 let pow_day = get_minimum_post_pow(512, 1, MILLIS_IN_DAY);
116 let pow_hour = get_minimum_post_pow(512, 1, MILLIS_IN_HOUR);
117 assert!(pow_month <= pow_day);
118 assert!(pow_day <= pow_hour);
119 assert!(pow_month < pow_hour);
120 }
121
122 #[test]
124 fn monotone_linked_ids() {
125 let pow_1 = get_minimum_post_pow(512, 1, MILLIS_IN_DAY);
126 let pow_2 = get_minimum_post_pow(512, 2, MILLIS_IN_DAY);
127 let pow_3 = get_minimum_post_pow(512, 3, MILLIS_IN_DAY);
128 let pow_4 = get_minimum_post_pow(512, 4, MILLIS_IN_DAY);
129 assert!(pow_1 <= pow_2);
130 assert!(pow_2 <= pow_3);
131 assert!(pow_3 <= pow_4);
132 assert!(pow_1 < pow_4);
133 }
134
135 #[test]
137 fn monotone_post_length() {
138 let pow_small = get_minimum_post_pow(1024, 1, MILLIS_IN_DAY);
139 let pow_medium = get_minimum_post_pow(8192, 1, MILLIS_IN_DAY);
140 let pow_large = get_minimum_post_pow(1024 * 1024, 1, MILLIS_IN_DAY);
141 assert!(pow_small <= pow_medium);
142 assert!(pow_medium <= pow_large);
143 assert!(pow_small < pow_large);
144 }
145
146 #[test]
148 fn never_below_minimum() {
149 let lengths = [1, 512, 1024, 4096, 64 * 1024];
150 let links = [1, 2, 5, 10];
151 let durations = [MILLIS_IN_HOUR, MILLIS_IN_DAY, MILLIS_IN_MONTH];
152 for post_length in lengths {
153 for linked_base_ids_len in links {
154 for duration in durations {
155 let pow = get_minimum_post_pow(post_length, linked_base_ids_len, duration);
156 assert!(
157 pow >= config::POW_MINIMUM_PER_POST,
158 "pow={:?} below minimum for post_length={} links={} duration={:?}",
159 pow, post_length, linked_base_ids_len, duration
160 );
161 }
162 }
163 }
164 }
165
166 #[test]
168 #[should_panic]
169 fn panic_on_short_duration() {
170 get_minimum_post_pow(512, 1, MILLIS_IN_MINUTE);
171 }
172}