use std::str::FromStr;
use fvm_shared::bigint::{BigInt, Integer};
use fvm_shared::clock::ChainEpoch;
use fvm_shared::econ::TokenAmount;
use fvm_shared::math::PRECISION;
use fvm_shared::sector::StoragePower;
use fvm_shared::FILECOIN_PRECISION;
use lazy_static::lazy_static;
use super::expneg::expneg;
lazy_static! {
pub static ref BASELINE_EXPONENT: StoragePower =
StoragePower::from_str("340282591298641078465964189926313473653").unwrap();
pub static ref BASELINE_INITIAL_VALUE: StoragePower = StoragePower::from(2_888_888_880_000_000_000u128);
pub static ref INIT_BASELINE_POWER: StoragePower =
((BASELINE_INITIAL_VALUE.clone() << (2*PRECISION)) / &*BASELINE_EXPONENT) >> PRECISION;
pub(super) static ref SIMPLE_TOTAL: BigInt = BigInt::from(330_000_000) * FILECOIN_PRECISION;
pub(super) static ref BASELINE_TOTAL: BigInt = BigInt::from(770_000_000) * FILECOIN_PRECISION;
static ref EXP_LAM_SUB_ONE: BigInt = BigInt::from(37396273494747879394193016954629u128);
static ref LAMBDA: BigInt = BigInt::from(37396271439864487274534522888786u128);
}
pub(crate) fn baseline_power_from_prev(prev_power: &StoragePower) -> StoragePower {
(prev_power * &*BASELINE_EXPONENT) >> PRECISION
}
pub(crate) fn compute_r_theta(
effective_network_time: ChainEpoch,
baseline_power_at_effective_network_time: &BigInt,
cumsum_realized: &BigInt,
cumsum_baseline: &BigInt,
) -> BigInt {
if effective_network_time != 0 {
let reward_theta = BigInt::from(effective_network_time) << PRECISION;
let diff = ((cumsum_baseline - cumsum_realized) << PRECISION)
.div_floor(baseline_power_at_effective_network_time);
reward_theta - diff
} else {
Default::default()
}
}
pub(crate) fn compute_reward(
epoch: ChainEpoch,
prev_theta: BigInt,
curr_theta: BigInt,
simple_total: &BigInt,
baseline_total: &BigInt,
) -> TokenAmount {
let mut simple_reward = simple_total * &*EXP_LAM_SUB_ONE;
let epoch_lam = &*LAMBDA * epoch;
simple_reward *= expneg(&epoch_lam);
simple_reward >>= PRECISION;
let baseline_reward = compute_baseline_supply(curr_theta, baseline_total)
- compute_baseline_supply(prev_theta, baseline_total);
(simple_reward + baseline_reward) >> PRECISION
}
fn compute_baseline_supply(theta: BigInt, baseline_total: &BigInt) -> BigInt {
let theta_lam = (theta * &*LAMBDA) >> PRECISION;
let etl = expneg(&theta_lam);
let one = BigInt::from(1) << PRECISION;
let one_sub = one - etl;
one_sub * baseline_total
}