214 lines
5.8 KiB
Rust
214 lines
5.8 KiB
Rust
use subxt::ext::sp_runtime::Perbill;
|
|
|
|
const SLOW_CLAP_DB_PREFIX: &[u8] = b"slow_clap::";
|
|
|
|
// generated outside, based on params
|
|
// MIN_INFLATION: u32 = 0_006_900;
|
|
// MAX_INFLATION: u32 = 0_690_000;
|
|
// IDEAL_STAKE: u32 = 0_690_000;
|
|
// FALLOFF: u32 = 0_050_000;
|
|
// MAX_PIECE_COUNT: u32 = 40;
|
|
const PIECEWISE_LINEAR_POUNTS: [(Perbill, Perbill); 32] = [
|
|
(Perbill::from_parts(0), Perbill::from_parts(6900000)),
|
|
(
|
|
Perbill::from_parts(690000000),
|
|
Perbill::from_parts(690000000),
|
|
),
|
|
(
|
|
Perbill::from_parts(692740000),
|
|
Perbill::from_parts(664536000),
|
|
),
|
|
(
|
|
Perbill::from_parts(695588000),
|
|
Perbill::from_parts(639072000),
|
|
),
|
|
(
|
|
Perbill::from_parts(698554000),
|
|
Perbill::from_parts(613608000),
|
|
),
|
|
(
|
|
Perbill::from_parts(701647000),
|
|
Perbill::from_parts(588144000),
|
|
),
|
|
(
|
|
Perbill::from_parts(704879000),
|
|
Perbill::from_parts(562680000),
|
|
),
|
|
(
|
|
Perbill::from_parts(708262000),
|
|
Perbill::from_parts(537216000),
|
|
),
|
|
(
|
|
Perbill::from_parts(711811000),
|
|
Perbill::from_parts(511752000),
|
|
),
|
|
(
|
|
Perbill::from_parts(715545000),
|
|
Perbill::from_parts(486288000),
|
|
),
|
|
(
|
|
Perbill::from_parts(719482000),
|
|
Perbill::from_parts(460824000),
|
|
),
|
|
(
|
|
Perbill::from_parts(723646000),
|
|
Perbill::from_parts(435360000),
|
|
),
|
|
(
|
|
Perbill::from_parts(728066000),
|
|
Perbill::from_parts(409896000),
|
|
),
|
|
(
|
|
Perbill::from_parts(732774000),
|
|
Perbill::from_parts(384432000),
|
|
),
|
|
(
|
|
Perbill::from_parts(737811000),
|
|
Perbill::from_parts(358968000),
|
|
),
|
|
(
|
|
Perbill::from_parts(743227000),
|
|
Perbill::from_parts(333504000),
|
|
),
|
|
(
|
|
Perbill::from_parts(749083000),
|
|
Perbill::from_parts(308040000),
|
|
),
|
|
(
|
|
Perbill::from_parts(755456000),
|
|
Perbill::from_parts(282576000),
|
|
),
|
|
(
|
|
Perbill::from_parts(762447000),
|
|
Perbill::from_parts(257112000),
|
|
),
|
|
(
|
|
Perbill::from_parts(770189000),
|
|
Perbill::from_parts(231648000),
|
|
),
|
|
(
|
|
Perbill::from_parts(778863000),
|
|
Perbill::from_parts(206184000),
|
|
),
|
|
(
|
|
Perbill::from_parts(788725000),
|
|
Perbill::from_parts(180720000),
|
|
),
|
|
(
|
|
Perbill::from_parts(800151000),
|
|
Perbill::from_parts(155256000),
|
|
),
|
|
(
|
|
Perbill::from_parts(813735000),
|
|
Perbill::from_parts(129792000),
|
|
),
|
|
(
|
|
Perbill::from_parts(830484000),
|
|
Perbill::from_parts(104328000),
|
|
),
|
|
(
|
|
Perbill::from_parts(852337000),
|
|
Perbill::from_parts(78864000),
|
|
),
|
|
(
|
|
Perbill::from_parts(877801000),
|
|
Perbill::from_parts(57460000),
|
|
),
|
|
(
|
|
Perbill::from_parts(903265000),
|
|
Perbill::from_parts(42422000),
|
|
),
|
|
(
|
|
Perbill::from_parts(928728000),
|
|
Perbill::from_parts(31857000),
|
|
),
|
|
(
|
|
Perbill::from_parts(954189000),
|
|
Perbill::from_parts(24435000),
|
|
),
|
|
(
|
|
Perbill::from_parts(979651000),
|
|
Perbill::from_parts(19220000),
|
|
),
|
|
(
|
|
Perbill::from_parts(1000000000),
|
|
Perbill::from_parts(16291000),
|
|
),
|
|
];
|
|
const MAXIMUM_INFLATION: Perbill = Perbill::from_parts(690000000);
|
|
|
|
pub fn calculate_for_fraction(n: u128, d: u128) -> (Perbill, Perbill) {
|
|
let n = n.min(d.clone());
|
|
|
|
if PIECEWISE_LINEAR_POUNTS.is_empty() {
|
|
return (MAXIMUM_INFLATION, Perbill::zero());
|
|
}
|
|
|
|
let next_point_index = PIECEWISE_LINEAR_POUNTS
|
|
.iter()
|
|
.position(|p| n < p.0 * d.clone());
|
|
|
|
let (prev, next) = if let Some(next_point_index) = next_point_index {
|
|
if let Some(previous_point_index) = next_point_index.checked_sub(1) {
|
|
(
|
|
PIECEWISE_LINEAR_POUNTS[previous_point_index],
|
|
PIECEWISE_LINEAR_POUNTS[next_point_index],
|
|
)
|
|
} else {
|
|
// There is no previous points, take first point ordinate
|
|
let fraction = PIECEWISE_LINEAR_POUNTS
|
|
.first()
|
|
.map(|p| p.1)
|
|
.unwrap_or_else(Perbill::zero);
|
|
return (MAXIMUM_INFLATION, fraction);
|
|
}
|
|
} else {
|
|
// There is no next points, take last point ordinate
|
|
let fraction = PIECEWISE_LINEAR_POUNTS
|
|
.last()
|
|
.map(|p| p.1)
|
|
.unwrap_or_else(Perbill::zero);
|
|
return (MAXIMUM_INFLATION, fraction);
|
|
};
|
|
|
|
let delta_y = multiply_by_rational_saturating(
|
|
abs_sub(n.clone(), prev.0 * d.clone()),
|
|
abs_sub(next.1.deconstruct(), prev.1.deconstruct()),
|
|
// Must not saturate as prev abscissa > next abscissa
|
|
next.0.deconstruct().saturating_sub(prev.0.deconstruct()),
|
|
);
|
|
|
|
// If both subtractions are same sign then result is positive
|
|
let fraction = if (n > prev.0 * d.clone()) == (next.1.deconstruct() > prev.1.deconstruct()) {
|
|
(prev.1 * d).saturating_add(delta_y)
|
|
} else {
|
|
// Otherwise result is negative
|
|
(prev.1 * d).saturating_sub(delta_y)
|
|
};
|
|
|
|
(MAXIMUM_INFLATION, Perbill::from_rational(fraction, d))
|
|
}
|
|
|
|
fn abs_sub<N: Ord + core::ops::Sub<Output = N> + Clone>(a: N, b: N) -> N where {
|
|
a.clone().max(b.clone()) - a.min(b)
|
|
}
|
|
|
|
fn multiply_by_rational_saturating(value: u128, p: u32, q: u32) -> u128 {
|
|
let q = q.max(1);
|
|
let result_divisor_part = (value / q as u128).saturating_mul(p as u128);
|
|
let result_remainder_part = {
|
|
let rem = value % q as u128;
|
|
let rem_u32 = rem as u32;
|
|
let rem_part = rem_u32 as u64 * p as u64 / q as u64;
|
|
rem_part as u128
|
|
};
|
|
result_divisor_part.saturating_add(result_remainder_part)
|
|
}
|
|
|
|
pub fn get_slow_clap_storage_key(first: &[u8], second: &[u8]) -> Vec<u8> {
|
|
let mut key = SLOW_CLAP_DB_PREFIX.to_vec();
|
|
key.extend(first);
|
|
key.extend(second);
|
|
key
|
|
}
|