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 + 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 { let mut key = SLOW_CLAP_DB_PREFIX.to_vec(); key.extend(first); key.extend(second); key }