use num_bigint::BigInt;
pub const EFFECTIVE_SIZE_BREAKPOINTS: &[(i32, f64)] = &[
(17, 0.00004089),
(18, 0.00609),
(19, 0.10249),
(20, 0.62891),
(21, 2.38),
(22, 7.07),
(23, 18.24),
(24, 43.04),
(25, 96.5),
(26, 208.52),
(27, 435.98),
(28, 908.81),
(29, 1870.0),
(30, 3810.0),
(31, 7730.0),
(32, 15610.0),
(33, 31430.0),
(34, 63150.0),
];
pub fn get_stamp_usage(utilization: u32, depth: u8, bucket_depth: u8) -> f64 {
let denom = 1u64 << (depth - bucket_depth);
f64::from(utilization) / (denom as f64)
}
pub fn get_stamp_theoretical_bytes(depth: i32) -> i64 {
4096i64 * (1i64 << depth)
}
pub fn get_stamp_cost(depth: i32, amount: &BigInt) -> BigInt {
BigInt::from(2u32).pow(depth as u32) * amount
}
pub fn get_stamp_effective_bytes(depth: i32) -> i64 {
if depth < 17 {
return 0;
}
for (d, gb) in EFFECTIVE_SIZE_BREAKPOINTS {
if *d == depth {
return (gb * 1_000_000_000.0) as i64;
}
}
let theoretical = get_stamp_theoretical_bytes(depth);
((theoretical as f64) * 0.9) as i64
}
pub fn get_depth_for_size(bytes: i64) -> i32 {
for (d, gb) in EFFECTIVE_SIZE_BREAKPOINTS {
if (bytes as f64) <= gb * 1_000_000_000.0 {
return *d;
}
}
35
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn theoretical_bytes_at_depth_17() {
assert_eq!(get_stamp_theoretical_bytes(17), 536_870_912);
}
#[test]
fn cost_at_depth_zero_is_amount() {
let amt = BigInt::from(100);
assert_eq!(get_stamp_cost(0, &amt), amt);
}
#[test]
fn cost_at_depth_three_is_eight_amount() {
let amt = BigInt::from(100);
assert_eq!(get_stamp_cost(3, &amt), BigInt::from(800));
}
#[test]
fn effective_bytes_uses_table_at_depth_17() {
assert_eq!(get_stamp_effective_bytes(17), 40_890);
}
#[test]
fn effective_bytes_below_17_is_zero() {
assert_eq!(get_stamp_effective_bytes(16), 0);
}
#[test]
fn depth_for_size_smallest_covering() {
assert_eq!(get_depth_for_size(1_000_000), 18);
}
#[test]
fn usage_fraction() {
assert!((get_stamp_usage(8, 20, 16) - 0.5).abs() < 1e-9);
}
}