Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor apply_inflation #2295

Merged
merged 2 commits into from
Dec 29, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
- Move the inflation code for PoS and PGF into their own native modules.
([\#2295](https://github.com/anoma/namada/pull/2295))
190 changes: 17 additions & 173 deletions apps/src/lib/node/ledger/shell/finalize_block.rs
Original file line number Diff line number Diff line change
@@ -1,23 +1,19 @@
//! Implementation of the `FinalizeBlock` ABCI++ method for the Shell

use data_encoding::HEXUPPER;
use namada::core::ledger::inflation;
use namada::core::ledger::masp_conversions::update_allowed_conversions;
use namada::core::ledger::pgf::ADDRESS as pgf_address;
use namada::core::ledger::pgf::inflation as pgf_inflation;
use namada::ledger::events::EventType;
use namada::ledger::gas::{GasMetering, TxGasMeter};
use namada::ledger::parameters::storage as params_storage;
use namada::ledger::pos::{namada_proof_of_stake, staking_token_address};
use namada::ledger::pos::namada_proof_of_stake;
use namada::ledger::protocol;
use namada::ledger::storage::wl_storage::WriteLogAndStorage;
use namada::ledger::storage::EPOCH_SWITCH_BLOCKS_DELAY;
use namada::ledger::storage_api::token::credit_tokens;
use namada::ledger::storage_api::{pgf, StorageRead, StorageWrite};
use namada::ledger::storage_api::StorageRead;
use namada::proof_of_stake::{
find_validator_by_raw_hash, read_last_block_proposer_address,
read_pos_params, read_total_stake, write_last_block_proposer_address,
write_last_block_proposer_address,
};
use namada::types::dec::Dec;
use namada::types::key::tm_raw_hash_to_string;
use namada::types::storage::{BlockHash, BlockResults, Epoch, Header};
use namada::types::transaction::protocol::{
Expand Down Expand Up @@ -636,58 +632,6 @@ where
/// with respect to the previous epoch.
fn apply_inflation(&mut self, current_epoch: Epoch) -> Result<()> {
let last_epoch = current_epoch.prev();
// Get input values needed for the PD controller for PoS.
// Run the PD controllers to calculate new rates.

let params = read_pos_params(&self.wl_storage)?;

// Read from Parameters storage
let epochs_per_year: u64 = self
.read_storage_key(&params_storage::get_epochs_per_year_key())
.expect("Epochs per year should exist in storage");
let pos_p_gain_nom: Dec = self
.read_storage_key(&params_storage::get_pos_gain_p_key())
.expect("PoS P-gain factor should exist in storage");
let pos_d_gain_nom: Dec = self
.read_storage_key(&params_storage::get_pos_gain_d_key())
.expect("PoS D-gain factor should exist in storage");

let pos_last_staked_ratio: Dec = self
.read_storage_key(&params_storage::get_staked_ratio_key())
.expect("PoS staked ratio should exist in storage");
let pos_last_inflation_amount: token::Amount = self
.read_storage_key(&params_storage::get_pos_inflation_amount_key())
.expect("PoS inflation amount should exist in storage");
// Read from PoS storage
let total_tokens: token::Amount = self
.read_storage_key(&token::minted_balance_key(
&staking_token_address(&self.wl_storage),
))
.expect("Total NAM balance should exist in storage");
let pos_locked_supply =
read_total_stake(&self.wl_storage, &params, last_epoch)?;
let pos_locked_ratio_target = params.target_staked_ratio;
let pos_max_inflation_rate = params.max_inflation_rate;

// Run rewards PD controller
let pos_controller = inflation::RewardsController {
locked_tokens: pos_locked_supply.raw_amount(),
total_tokens: total_tokens.raw_amount(),
total_native_tokens: total_tokens.raw_amount(),
locked_ratio_target: pos_locked_ratio_target,
locked_ratio_last: pos_last_staked_ratio,
max_reward_rate: pos_max_inflation_rate,
last_inflation_amount: pos_last_inflation_amount.raw_amount(),
p_gain_nom: pos_p_gain_nom,
d_gain_nom: pos_d_gain_nom,
epochs_per_year,
};

// Run the rewards controllers
let inflation::ValsToUpdate {
locked_ratio,
inflation,
} = pos_controller.run();

// Get the number of blocks in the last epoch
let first_block_of_last_epoch = self
Expand All @@ -700,116 +644,15 @@ where
let num_blocks_in_last_epoch =
self.wl_storage.storage.block.height.0 - first_block_of_last_epoch;

let staking_token = staking_token_address(&self.wl_storage);

let inflation = token::Amount::from_uint(inflation, 0)
.expect("Should not fail Uint -> Amount conversion");
namada_proof_of_stake::update_rewards_products_and_mint_inflation(
// PoS inflation
namada_proof_of_stake::apply_inflation(
&mut self.wl_storage,
&params,
last_epoch,
num_blocks_in_last_epoch,
inflation,
&staking_token,
)
.expect(
"Must be able to update PoS rewards products and mint inflation",
);

// Write new rewards parameters that will be used for the inflation of
// the current new epoch
self.wl_storage
.write(&params_storage::get_pos_inflation_amount_key(), inflation)
.expect("unable to write new reward rate");
self.wl_storage
.write(&params_storage::get_staked_ratio_key(), locked_ratio)
.expect("unable to write new locked ratio");

// Pgf inflation
let pgf_parameters = pgf::get_parameters(&self.wl_storage)?;

let pgf_pd_rate =
pgf_parameters.pgf_inflation_rate / Dec::from(epochs_per_year);
let pgf_inflation = Dec::from(total_tokens) * pgf_pd_rate;
let pgf_inflation_amount = token::Amount::from(pgf_inflation);

credit_tokens(
&mut self.wl_storage,
&staking_token,
&pgf_address,
pgf_inflation_amount,
)?;

tracing::info!(
"Minting {} tokens for PGF rewards distribution into the PGF \
account.",
pgf_inflation_amount.to_string_native()
);

let mut pgf_fundings = pgf::get_payments(&self.wl_storage)?;
// we want to pay first the oldest fundings
pgf_fundings.sort_by(|a, b| a.id.cmp(&b.id));

for funding in pgf_fundings {
if storage_api::token::transfer(
&mut self.wl_storage,
&staking_token,
&pgf_address,
&funding.detail.target,
funding.detail.amount,
)
.is_ok()
{
tracing::info!(
"Paying {} tokens for {} project.",
funding.detail.amount.to_string_native(),
&funding.detail.target,
);
} else {
tracing::warn!(
"Failed to pay {} tokens for {} project.",
funding.detail.amount.to_string_native(),
&funding.detail.target,
);
}
}

// Pgf steward inflation
let stewards = pgf::get_stewards(&self.wl_storage)?;
let pgf_stewards_pd_rate =
pgf_parameters.stewards_inflation_rate / Dec::from(epochs_per_year);
let pgf_steward_inflation =
Dec::from(total_tokens) * pgf_stewards_pd_rate;

for steward in stewards {
for (address, percentage) in steward.reward_distribution {
let pgf_steward_reward = pgf_steward_inflation
.checked_mul(&percentage)
.unwrap_or_default();
let reward_amount = token::Amount::from(pgf_steward_reward);

if credit_tokens(
&mut self.wl_storage,
&staking_token,
&address,
reward_amount,
)
.is_ok()
{
tracing::info!(
"Minting {} tokens for steward {}.",
reward_amount.to_string_native(),
address,
);
} else {
tracing::warn!(
"Failed minting {} tokens for steward {}.",
reward_amount.to_string_native(),
address,
);
}
}
}
// Pgf inflation
pgf_inflation::apply_inflation(&mut self.wl_storage)?;

Ok(())
}
Expand Down Expand Up @@ -969,14 +812,14 @@ mod test_finalize_block {
};
use namada::proof_of_stake::{
enqueued_slashes_handle, get_num_consensus_validators,
read_consensus_validator_set_addresses_with_stake,
read_consensus_validator_set_addresses_with_stake, read_total_stake,
read_validator_stake, rewards_accumulator_handle, unjail_validator,
validator_consensus_key_handle, validator_rewards_products_handle,
validator_slashes_handle, validator_state_handle, write_pos_params,
ADDRESS as pos_address,
};
use namada::proto::{Code, Data, Section, Signature};
use namada::types::dec::POS_DECIMAL_PRECISION;
use namada::types::dec::{Dec, POS_DECIMAL_PRECISION};
use namada::types::ethereum_events::{EthAddress, Uint as ethUint};
use namada::types::hash::Hash;
use namada::types::keccak::KeccakHash;
Expand Down Expand Up @@ -2504,7 +2347,7 @@ mod test_finalize_block {
let delegator = address::testing::gen_implicit_address();
let del_amount = init_stake;
let staking_token = shell.wl_storage.storage.native_token.clone();
credit_tokens(
storage_api::token::credit_tokens(
&mut shell.wl_storage,
&staking_token,
&delegator,
Expand Down Expand Up @@ -2629,21 +2472,21 @@ mod test_finalize_block {

// Give the validators some tokens for txs
let staking_token = shell.wl_storage.storage.native_token.clone();
credit_tokens(
storage_api::token::credit_tokens(
&mut shell.wl_storage,
&staking_token,
&validator1.address,
init_stake,
)
.unwrap();
credit_tokens(
storage_api::token::credit_tokens(
&mut shell.wl_storage,
&staking_token,
&validator2.address,
init_stake,
)
.unwrap();
credit_tokens(
storage_api::token::credit_tokens(
&mut shell.wl_storage,
&staking_token,
&validator3.address,
Expand Down Expand Up @@ -4001,7 +3844,7 @@ mod test_finalize_block {
let delegator = address::testing::gen_implicit_address();
let del_1_amount = token::Amount::native_whole(67_231);
let staking_token = shell.wl_storage.storage.native_token.clone();
credit_tokens(
storage_api::token::credit_tokens(
&mut shell.wl_storage,
&staking_token,
&delegator,
Expand Down Expand Up @@ -5270,7 +5113,8 @@ mod test_finalize_block {
misbehaviors: Option<Vec<Misbehavior>>,
) -> (Epoch, token::Amount) {
let current_epoch = shell.wl_storage.storage.block.epoch;
let staking_token = staking_token_address(&shell.wl_storage);
let staking_token =
namada_proof_of_stake::staking_token_address(&shell.wl_storage);

// NOTE: assumed that the only change in pos address balance by
// advancing to the next epoch is minted inflation - no change occurs
Expand Down
104 changes: 104 additions & 0 deletions core/src/ledger/pgf/inflation.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
//! PGF lib code.

use crate::ledger::parameters::storage as params_storage;
use crate::ledger::storage_api::pgf::{
get_parameters, get_payments, get_stewards,
};
use crate::ledger::storage_api::token::credit_tokens;
use crate::ledger::storage_api::{self, StorageRead, StorageWrite};
use crate::types::dec::Dec;
use crate::types::token;

/// Apply the PGF inflation.
pub fn apply_inflation<S>(storage: &mut S) -> storage_api::Result<()>
where
S: StorageRead + StorageWrite,
{
let pgf_parameters = get_parameters(storage)?;
let staking_token = storage.get_native_token()?;

let epochs_per_year: u64 = storage
.read(&params_storage::get_epochs_per_year_key())?
.expect("Epochs per year should exist in storage");
let total_tokens: token::Amount = storage
.read(&token::minted_balance_key(&staking_token))?
.expect("Total NAM balance should exist in storage");

let pgf_pd_rate =
pgf_parameters.pgf_inflation_rate / Dec::from(epochs_per_year);
let pgf_inflation = Dec::from(total_tokens) * pgf_pd_rate;
let pgf_inflation_amount = token::Amount::from(pgf_inflation);

credit_tokens(
storage,
&staking_token,
&super::ADDRESS,
pgf_inflation_amount,
)?;

tracing::info!(
"Minting {} tokens for PGF rewards distribution into the PGF account.",
pgf_inflation_amount.to_string_native()
);

let mut pgf_fundings = get_payments(storage)?;
// we want to pay first the oldest fundings
pgf_fundings.sort_by(|a, b| a.id.cmp(&b.id));

for funding in pgf_fundings {
if storage_api::token::transfer(
storage,
&staking_token,
&super::ADDRESS,
&funding.detail.target,
funding.detail.amount,
)
.is_ok()
{
tracing::info!(
"Paying {} tokens for {} project.",
funding.detail.amount.to_string_native(),
&funding.detail.target,
);
} else {
tracing::warn!(
"Failed to pay {} tokens for {} project.",
funding.detail.amount.to_string_native(),
&funding.detail.target,
);
}
}

// Pgf steward inflation
let stewards = get_stewards(storage)?;
let pgf_stewards_pd_rate =
pgf_parameters.stewards_inflation_rate / Dec::from(epochs_per_year);
let pgf_steward_inflation = Dec::from(total_tokens) * pgf_stewards_pd_rate;

for steward in stewards {
for (address, percentage) in steward.reward_distribution {
let pgf_steward_reward = pgf_steward_inflation
.checked_mul(&percentage)
.unwrap_or_default();
let reward_amount = token::Amount::from(pgf_steward_reward);

if credit_tokens(storage, &staking_token, &address, reward_amount)
.is_ok()
{
tracing::info!(
"Minting {} tokens for steward {}.",
reward_amount.to_string_native(),
address,
);
} else {
tracing::warn!(
"Failed minting {} tokens for steward {}.",
reward_amount.to_string_native(),
address,
);
}
}
}

Ok(())
}
2 changes: 2 additions & 0 deletions core/src/ledger/pgf/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ use crate::types::address::{Address, InternalAddress};

/// Pgf CLI
pub mod cli;
/// Pgf inflation code
pub mod inflation;
/// Pgf parameters
pub mod parameters;
/// Pgf storage
Expand Down
Loading