| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108 |
- /* This file is part of DarkFi (https://dark.fi)
- *
- * Copyright (C) 2020-2023 Dyne.org foundation
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with this program. If not, see <https://www.gnu.org/licenses/>.
- */
- use darkfi_sdk::{blockchain::Slot, pasta::pallas};
- use lazy_static::lazy_static;
- use super::float_10::{
- fbig2base, Float10, FLOAT10_NEG_ONE, FLOAT10_NEG_TWO, FLOAT10_ONE, FLOAT10_TWO, FLOAT10_ZERO,
- };
- /// PID controller configuration
- const P: &str = "28948022309329048855892746252171976963363056481941560715954676764349967630337";
- lazy_static! {
- static ref FIELD_P: Float10 = Float10::try_from(P).unwrap();
- static ref KP: Float10 = Float10::try_from("0.18").unwrap();
- static ref KI: Float10 = Float10::try_from("0.02").unwrap();
- static ref KD: Float10 = Float10::try_from("-0.1").unwrap();
- static ref MAX_F: Float10 = Float10::try_from("0.99").unwrap();
- static ref MIN_F: Float10 = Float10::try_from("0.01").unwrap();
- static ref EPSILON: Float10 = Float10::try_from("1").unwrap();
- }
- /// Return 2-term target approximation sigma coefficients,
- /// alogn with the inverse probability `f` of becoming a
- /// block producer and the feedback error, corresponding
- /// to provided slot consensus state,
- pub fn slot_pid_output(
- previous_slot: &Slot,
- previous_producers: u64,
- ) -> (f64, f64, pallas::Base, pallas::Base) {
- let (f, error) = calculate_f(previous_slot, previous_producers);
- let total_tokens =
- Float10::try_from(previous_slot.total_tokens + previous_slot.reward).unwrap();
- let (sigma1, sigma2) = calculate_sigmas(f.clone(), total_tokens);
- // TODO: log values
- (f.to_f64(), error.to_f64(), sigma1, sigma2)
- }
- /// Calculate the inverse probability `f` of becoming a block producer (winning the lottery)
- /// having all the tokens, and the feedback error, represented as Float10.
- fn calculate_f(previous_slot: &Slot, previous_producers: u64) -> (Float10, Float10) {
- // PID controller K values based on constants
- let k1 = KP.clone() + KI.clone() + KD.clone();
- let k2 = FLOAT10_NEG_ONE.clone() * KP.clone() + FLOAT10_NEG_TWO.clone() * KD.clone();
- let k3 = KD.clone();
- // Convert slot values to Float10
- let previous_slot_f = Float10::try_from(previous_slot.pid.f).unwrap();
- let previous_slot_error = Float10::try_from(previous_slot.pid.error).unwrap();
- let previous_slot_previous_slot_error =
- Float10::try_from(previous_slot.previous.error).unwrap();
- // Calculate feedback error based on previous block producers.
- let feedback = Float10::try_from(previous_producers).unwrap();
- let error = FLOAT10_ONE.clone() - feedback;
- // Calculate f
- let mut f = previous_slot_f +
- k1 * error.clone() +
- k2 * previous_slot_error +
- k3 * previous_slot_previous_slot_error;
- // Boundaries control
- if f <= *FLOAT10_ZERO {
- f = MIN_F.clone()
- } else if f >= *FLOAT10_ONE {
- f = MAX_F.clone()
- }
- (f, error)
- }
- /// Return 2-term target approximation sigma coefficients,
- /// corresponding to provided `f` and `total_tokens` values.
- fn calculate_sigmas(f: Float10, total_tokens: Float10) -> (pallas::Base, pallas::Base) {
- // Calculate `neg_c` value
- let x = FLOAT10_ONE.clone() - f;
- let c = x.ln();
- let neg_c = FLOAT10_NEG_ONE.clone() * c;
- // Calculate sigma 1
- let sigma1_fbig = neg_c.clone() / (total_tokens.clone() + EPSILON.clone()) * FIELD_P.clone();
- let sigma1 = fbig2base(sigma1_fbig);
- // Calculate sigma 2
- let sigma2_fbig = (neg_c / (total_tokens + EPSILON.clone())).powf(FLOAT10_TWO.clone()) *
- (FIELD_P.clone() / FLOAT10_TWO.clone());
- let sigma2 = fbig2base(sigma2_fbig);
- (sigma1, sigma2)
- }
|