Skip to content

Commit

Permalink
remove BasisPoints and change relevant parameters to Decimal type
Browse files Browse the repository at this point in the history
  • Loading branch information
brentstone committed Sep 8, 2022
1 parent 1329579 commit 309c4ce
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 90 deletions.
36 changes: 17 additions & 19 deletions apps/src/lib/config/genesis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,14 @@ pub mod genesis_config {
use hex;
use namada::ledger::governance::parameters::GovParams;
use namada::ledger::parameters::{EpochDuration, Parameters};
use namada::ledger::pos::types::BasisPoints;
use namada::ledger::pos::{GenesisValidator, PosParams};
use namada::ledger::treasury::parameters::TreasuryParams;
use namada::types::address::Address;
use namada::types::key::dkg_session_keys::DkgPublicKey;
use namada::types::key::*;
use namada::types::time::Rfc3339String;
use namada::types::{storage, token};
use rust_decimal::Decimal;
use serde::{Deserialize, Serialize};
use thiserror::Error;

Expand Down Expand Up @@ -265,24 +265,24 @@ pub mod genesis_config {
pub unbonding_len: u64,
// Votes per token (in basis points).
// XXX: u64 doesn't work with toml-rs!
pub votes_per_token: u64,
pub votes_per_token: Decimal,
// Reward for proposing a block.
// XXX: u64 doesn't work with toml-rs!
pub block_proposer_reward: u64,
pub block_proposer_reward: Decimal,
// Reward for voting on a block.
// XXX: u64 doesn't work with toml-rs!
pub block_vote_reward: u64,
pub block_vote_reward: Decimal,
// Maximum staking APY
// XXX: u64 doesn't work with toml-rs!
pub max_staking_rewards_rate: u64,
pub max_staking_rewards_rate: Decimal,
// Portion of a validator's stake that should be slashed on a
// duplicate vote (in basis points).
// XXX: u64 doesn't work with toml-rs!
pub duplicate_vote_slash_rate: u64,
pub duplicate_vote_slash_rate: Decimal,
// Portion of a validator's stake that should be slashed on a
// light client attack (in basis points).
// XXX: u64 doesn't work with toml-rs!
pub light_client_attack_slash_rate: u64,
pub light_client_attack_slash_rate: Decimal,
}

#[derive(Clone, Debug, Deserialize, Serialize)]
Expand Down Expand Up @@ -569,20 +569,18 @@ pub mod genesis_config {
max_validator_slots: config.pos_params.max_validator_slots,
pipeline_len: config.pos_params.pipeline_len,
unbonding_len: config.pos_params.unbonding_len,
votes_per_token: BasisPoints::new(
config.pos_params.votes_per_token,
),
votes_per_token: config.pos_params.votes_per_token,
block_proposer_reward: config.pos_params.block_proposer_reward,
block_vote_reward: config.pos_params.block_vote_reward,
max_staking_rewards_rate: BasisPoints::new(
config.pos_params.max_staking_rewards_rate,
),
duplicate_vote_slash_rate: BasisPoints::new(
config.pos_params.duplicate_vote_slash_rate,
),
light_client_attack_slash_rate: BasisPoints::new(
config.pos_params.light_client_attack_slash_rate,
),
max_staking_rewards_rate: config
.pos_params
.max_staking_rewards_rate,
duplicate_vote_slash_rate: config
.pos_params
.duplicate_vote_slash_rate,
light_client_attack_slash_rate: config
.pos_params
.light_client_attack_slash_rate,
};

let mut genesis = Genesis {
Expand Down
42 changes: 22 additions & 20 deletions proof_of_stake/src/parameters.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
//! Proof-of-Stake system parameters
use borsh::{BorshDeserialize, BorshSerialize};
use rust_decimal::prelude::ToPrimitive;
use rust_decimal::Decimal;
use rust_decimal_macros::dec;
use thiserror::Error;

use crate::types::BasisPoints;

/// Proof-of-Stake system parameters
#[derive(Debug, Clone, BorshDeserialize, BorshSerialize)]
pub struct PosParams {
Expand All @@ -20,20 +21,20 @@ pub struct PosParams {
pub unbonding_len: u64,
/// Used in validators' voting power calculation. Given in basis points
/// (voting power per ten thousand tokens).
pub votes_per_token: BasisPoints,
pub votes_per_token: Decimal,
/// Amount of tokens rewarded to a validator for proposing a block
pub block_proposer_reward: u64,
pub block_proposer_reward: Decimal,
/// Amount of tokens rewarded to each validator that voted on a block
/// proposal
pub block_vote_reward: u64,
pub block_vote_reward: Decimal,
/// Maximum staking rewards rate per annum
pub max_staking_rewards_rate: BasisPoints,
pub max_staking_rewards_rate: Decimal,
/// Portion of validator's stake that should be slashed on a duplicate
/// vote. Given in basis points (slashed amount per ten thousand tokens).
pub duplicate_vote_slash_rate: BasisPoints,
pub duplicate_vote_slash_rate: Decimal,
/// Portion of validator's stake that should be slashed on a light client
/// attack. Given in basis points (slashed amount per ten thousand tokens).
pub light_client_attack_slash_rate: BasisPoints,
pub light_client_attack_slash_rate: Decimal,
}

impl Default for PosParams {
Expand All @@ -42,16 +43,17 @@ impl Default for PosParams {
max_validator_slots: 128,
pipeline_len: 2,
unbonding_len: 6,
// 1 voting power per 1 fundamental token (10^6 per NAM or 1 per namnam)
votes_per_token: BasisPoints::new(10000),
block_proposer_reward: 100,
block_vote_reward: 1,
// 1 voting power per 1 fundamental token (10^6 per NAM or 1 per
// namnam)
votes_per_token: dec!(1.0),
block_proposer_reward: dec!(0.0625),
block_vote_reward: dec!(0.05),
// staking APY 20%
max_staking_rewards_rate: BasisPoints::new(2000),
max_staking_rewards_rate: dec!(0.2),
// slash 5%
duplicate_vote_slash_rate: BasisPoints::new(500),
duplicate_vote_slash_rate: dec!(0.05),
// slash 5%
light_client_attack_slash_rate: BasisPoints::new(500),
light_client_attack_slash_rate: dec!(0.05),
}
}
}
Expand All @@ -65,7 +67,7 @@ pub enum ValidationError {
)]
TotalVotingPowerTooLarge(u64),
#[error("Votes per token cannot be greater than 1, got {0}")]
VotesPerTokenGreaterThanOne(BasisPoints),
VotesPerTokenGreaterThanOne(Decimal),
#[error("Pipeline length must be >= 2, got {0}")]
PipelineLenTooShort(u64),
#[error(
Expand Down Expand Up @@ -105,8 +107,8 @@ impl PosParams {

// Check maximum total voting power cannot get larger than what
// Tendermint allows
let max_total_voting_power = self.max_validator_slots
* (self.votes_per_token * TOKEN_MAX_AMOUNT);
let max_total_voting_power = Decimal::from(self.max_validator_slots)
* self.votes_per_token * Decimal::from(TOKEN_MAX_AMOUNT);
match i64::try_from(max_total_voting_power) {
Ok(max_total_voting_power_i64) => {
if max_total_voting_power_i64 > MAX_TOTAL_VOTING_POWER {
Expand All @@ -121,7 +123,7 @@ impl PosParams {
}

// Check that there is no more than 1 vote per token
if self.votes_per_token > BasisPoints::new(10_000) {
if self.votes_per_token > dec!(1.0) {
errors.push(ValidationError::VotesPerTokenGreaterThanOne(
self.votes_per_token,
))
Expand Down Expand Up @@ -174,7 +176,7 @@ pub mod testing {
max_validator_slots,
pipeline_len,
unbonding_len,
votes_per_token: BasisPoints::new(votes_per_token),
votes_per_token: Decimal::from(votes_per_token) / dec!(10_000),
// The rest of the parameters that are not being used in the PoS
// VP are constant for now
..Default::default()
Expand Down
9 changes: 5 additions & 4 deletions proof_of_stake/src/rewards.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
//! PoS rewards
use rust_decimal::Decimal;
use rust_decimal_macros::dec;
use thiserror::Error;

use crate::types::VotingPower;
Expand Down Expand Up @@ -29,20 +30,20 @@ pub struct PosRewards {
/// bing
#[derive(Debug, Copy, Clone)]
pub struct PosRewardsCalculator {
proposer_param: u64,
signer_param: u64,
signing_stake: VotingPower,
total_stake: VotingPower,
proposer_param: Decimal,
signer_param: Decimal,
pos_rewards: Option<PosRewards>,
}

impl PosRewardsCalculator {
/// new
pub fn new(
proposer_param: u64,
signer_param: u64,
signing_stake: VotingPower,
total_stake: VotingPower,
proposer_param: Decimal,
signer_param: Decimal,
) -> Self {
Self {
proposer_param,
Expand Down
52 changes: 5 additions & 47 deletions proof_of_stake/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@ use std::convert::TryFrom;
use std::fmt::Display;
use std::hash::Hash;
use std::num::TryFromIntError;
use std::ops::{Add, AddAssign, Mul, Sub, SubAssign};
use std::ops::{Add, AddAssign, Sub, SubAssign};

use borsh::{BorshDeserialize, BorshSchema, BorshSerialize};
use rust_decimal::prelude::ToPrimitive;
use rust_decimal::Decimal;

use crate::epoched::{
Epoched, EpochedDelta, OffsetPipelineLen, OffsetUnbondingLen,
Expand Down Expand Up @@ -324,7 +326,7 @@ pub struct Slash {
/// A type of slashsable event.
pub r#type: SlashType,
/// A rate is the portion of staked tokens that are slashed.
pub rate: BasisPoints,
pub rate: Decimal,
}

/// Slashes applied to validator, to punish byzantine behavior by removing
Expand Down Expand Up @@ -362,23 +364,6 @@ impl From<tendermint_proto::abci::VoteInfo> for VoteInfo {
}
}

/// ‱ (Parts per ten thousand). This can be multiplied by any type that
/// implements [`Into<u64>`] or [`Into<i128>`].
#[derive(
Debug,
Clone,
Copy,
BorshDeserialize,
BorshSerialize,
BorshSchema,
PartialOrd,
Ord,
PartialEq,
Eq,
Hash,
)]
pub struct BasisPoints(u64);

/// Derive Tendermint raw hash from the public key
pub trait PublicKeyTmRawHash {
/// Derive Tendermint raw hash from the public key
Expand Down Expand Up @@ -737,7 +722,7 @@ where
impl SlashType {
/// Get the slash rate applicable to the given slash type from the PoS
/// parameters.
pub fn get_slash_rate(&self, params: &PosParams) -> BasisPoints {
pub fn get_slash_rate(&self, params: &PosParams) -> Decimal {
match self {
SlashType::DuplicateVote => params.duplicate_vote_slash_rate,
SlashType::LightClientAttack => {
Expand All @@ -756,35 +741,8 @@ impl Display for SlashType {
}
}

impl BasisPoints {
/// Initialize basis points from an integer.
pub fn new(value: u64) -> Self {
Self(value)
}
}

impl Display for BasisPoints {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}‱", self.0)
}
}

impl Mul<u64> for BasisPoints {
type Output = u64;

fn mul(self, rhs: u64) -> Self::Output {
// TODO checked arithmetics
rhs * self.0 / 10_000
}
}

impl Mul<i128> for BasisPoints {
type Output = i128;

fn mul(self, rhs: i128) -> Self::Output {
// TODO checked arithmetics
rhs * self.0 as i128 / 10_000
}
}

#[cfg(test)]
Expand Down

0 comments on commit 309c4ce

Please sign in to comment.