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

Implemented compounding inflation for native tokens. #1985

Merged
merged 6 commits into from
Oct 24, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
6 changes: 3 additions & 3 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,8 @@ libc = "0.2.97"
libloading = "0.7.2"
libsecp256k1 = {git = "https://github.com/heliaxdev/libsecp256k1", rev = "bbb3bd44a49db361f21d9db80f9a087c194c0ae9", default-features = false, features = ["std", "static-context"]}
# branch = "murisi/namada-integration"
masp_primitives = { git = "https://github.com/anoma/masp", rev = "50acc5028fbcd52a05970fe7991c7850ab04358e" }
masp_proofs = { git = "https://github.com/anoma/masp", rev = "50acc5028fbcd52a05970fe7991c7850ab04358e", default-features = false, features = ["local-prover"] }
masp_primitives = { git = "https://github.com/anoma/masp", rev = "1345b463e8fa3b3a6fa13e4a43fb1c410690ad62" }
masp_proofs = { git = "https://github.com/anoma/masp", rev = "1345b463e8fa3b3a6fa13e4a43fb1c410690ad62", default-features = false, features = ["local-prover"] }
num256 = "0.3.5"
num_cpus = "1.13.0"
num-derive = "0.3.3"
Expand Down
4 changes: 2 additions & 2 deletions apps/src/lib/client/rpc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2126,7 +2126,7 @@ pub async fn query_conversions<
// Track whether any non-sentinel conversions are found
let mut conversions_found = false;
for ((addr, _), epoch, conv, _) in conv_state.assets.values() {
let amt: masp_primitives::transaction::components::I32Sum =
let amt: masp_primitives::transaction::components::I128Sum =
conv.clone().into();
// If the user has specified any targets, then meet them
// If we have a sentinel conversion, then skip printing
Expand Down Expand Up @@ -2181,7 +2181,7 @@ pub async fn query_conversion<C: namada::ledger::queries::Client + Sync>(
Address,
MaspDenom,
Epoch,
masp_primitives::transaction::components::I32Sum,
masp_primitives::transaction::components::I128Sum,
MerklePath<Node>,
)> {
namada::sdk::rpc::query_conversion(client, asset_type).await
Expand Down
4 changes: 2 additions & 2 deletions apps/src/lib/config/genesis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1012,8 +1012,8 @@ pub fn genesis(num_validators: u64) -> Genesis {
implicit_vp_code_path: vp_implicit_path.into(),
implicit_vp_sha256: Default::default(),
max_signatures_per_transaction: 15,
epochs_per_year: 525_600, /* seconds in yr (60*60*24*365) div seconds
* per epoch (60 = min_duration) */
epochs_per_year: 365, /* seconds in yr (60*60*24*365) div seconds
murisi marked this conversation as resolved.
Show resolved Hide resolved
* per epoch (60 = min_duration) */
pos_gain_p: Dec::new(1, 1).expect("This can't fail"),
pos_gain_d: Dec::new(1, 1).expect("This can't fail"),
staked_ratio: Dec::zero(),
Expand Down
28 changes: 1 addition & 27 deletions apps/src/lib/node/ledger/shell/finalize_block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -618,10 +618,8 @@ 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 and MASP.
// Get input values needed for the PD controller for PoS.
// Run the PD controllers to calculate new rates.
//
// MASP is included below just for some completeness.

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

Expand Down Expand Up @@ -653,15 +651,6 @@ where
let pos_locked_ratio_target = params.target_staked_ratio;
let pos_max_inflation_rate = params.max_inflation_rate;

// TODO: properly fetch these values (arbitrary for now)
let masp_locked_supply: Amount = Amount::default();
let masp_locked_ratio_target = Dec::new(5, 1).expect("Cannot fail");
let masp_locked_ratio_last = Dec::new(5, 1).expect("Cannot fail");
let masp_max_inflation_rate = Dec::new(2, 1).expect("Cannot fail");
let masp_last_inflation_rate = Dec::new(12, 2).expect("Cannot fail");
let masp_p_gain = Dec::new(1, 1).expect("Cannot fail");
let masp_d_gain = Dec::new(1, 1).expect("Cannot fail");

// Run rewards PD controller
let pos_controller = inflation::RewardsController {
locked_tokens: pos_locked_supply,
Expand All @@ -675,27 +664,12 @@ where
d_gain_nom: pos_d_gain_nom,
epochs_per_year,
};
let _masp_controller = inflation::RewardsController {
locked_tokens: masp_locked_supply,
total_tokens,
total_native_tokens: total_tokens,
locked_ratio_target: masp_locked_ratio_target,
locked_ratio_last: masp_locked_ratio_last,
max_reward_rate: masp_max_inflation_rate,
last_inflation_amount: token::Amount::from(
masp_last_inflation_rate,
),
p_gain_nom: masp_p_gain,
d_gain_nom: masp_d_gain,
epochs_per_year,
};

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

// Get the number of blocks in the last epoch
let first_block_of_last_epoch = self
Expand Down
7 changes: 5 additions & 2 deletions apps/src/lib/node/ledger/shell/init_chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -338,11 +338,14 @@ where
// Init token parameters and last inflation and caching rates
parameters.init_storage(&address, &mut self.wl_storage);
self.wl_storage
.write(&token::masp_last_inflation(&address), last_inflation)
.write(
&token::masp_last_inflation_key(&address),
last_inflation,
)
.unwrap();
self.wl_storage
.write(
&token::masp_last_locked_ratio(&address),
&token::masp_last_locked_ratio_key(&address),
last_locked_ratio,
)
.unwrap();
Expand Down
90 changes: 43 additions & 47 deletions core/src/ledger/storage/masp_conversions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,25 +10,19 @@ use masp_primitives::sapling::Node;

use crate::ledger::inflation::{RewardsController, ValsToUpdate};
use crate::ledger::parameters;
use crate::ledger::storage_api::token::read_denom;
use crate::ledger::storage_api::{StorageRead, StorageWrite};
use crate::types::address::Address;
use crate::types::dec::Dec;
use crate::types::storage::Epoch;
use crate::types::token::MaspDenom;
use crate::types::{address, token};

/// Inflation is implicitly denominated by this value. The lower this figure,
/// the less precise inflation computations are. The higher this figure, the
/// larger the fixed-width types that are required to carry out inflation
/// computations. This value should be fixed constant for each asset type - here
/// we have simplified it and made it constant across asset types.
const PRECISION: u64 = 100;

/// A representation of the conversion state
#[derive(Debug, Default, BorshSerialize, BorshDeserialize)]
pub struct ConversionState {
/// The last amount of the native token distributed
pub normed_inflation: Option<u32>,
pub normed_inflation: Option<u128>,
/// The tree currently containing all the conversions
pub tree: FrozenCommitmentTree<Node>,
/// Map assets to their latest conversion and position in Merkle tree
Expand All @@ -44,11 +38,20 @@ pub struct ConversionState {
pub fn calculate_masp_rewards<D, H>(
wl_storage: &mut super::WlStorage<D, H>,
addr: &Address,
) -> crate::ledger::storage_api::Result<(u32, u32)>
) -> crate::ledger::storage_api::Result<(u128, u128)>
where
D: 'static + super::DB + for<'iter> super::DBIter<'iter>,
H: 'static + super::StorageHasher,
{
let denomination = read_denom(wl_storage, addr).unwrap().unwrap();
// Inflation is implicitly denominated by this value. The lower this
// figure, the less precise inflation computations are. This is especially
// problematic when inflation is coming from a token with much higher
// denomination than the native token. The higher this figure, the higher
// the threshold of holdings required in order to receive non-zero rewards.
// This value should be fixed constant for each asset type.
let precision = 10u128.pow(std::cmp::max(u32::from(denomination.0), 3) - 3);

let masp_addr = address::masp();
// Query the storage for information

Expand All @@ -69,38 +72,33 @@ where

let epochs_per_year: u64 = wl_storage
.read(&parameters::storage::get_epochs_per_year_key())?
.expect("");
.expect("epochs per year should properly decode");

//// Values from the last epoch
let last_inflation: token::Amount = wl_storage
.read(&token::masp_last_inflation(addr))
.expect("failure to read last inflation")
.expect("");
.read(&token::masp_last_inflation_key(addr))?
.expect("failure to read last inflation");

let last_locked_ratio: Dec = wl_storage
.read(&token::masp_last_locked_ratio(addr))
.expect("failure to read last inflation")
.expect("");
.read(&token::masp_last_locked_ratio_key(addr))?
.expect("failure to read last inflation");

//// Parameters for each token
let max_reward_rate: Dec = wl_storage
.read(&token::masp_max_reward_rate(addr))
.expect("max reward should properly decode")
.expect("");
.read(&token::masp_max_reward_rate_key(addr))?
.expect("max reward should properly decode");

let kp_gain_nom: Dec = wl_storage
.read(&token::masp_kp_gain(addr))
.expect("kp_gain_nom reward should properly decode")
.expect("");
.read(&token::masp_kp_gain_key(addr))?
.expect("kp_gain_nom reward should properly decode");

let kd_gain_nom: Dec = wl_storage
.read(&token::masp_kd_gain(addr))
.expect("kd_gain_nom reward should properly decode")
.expect("");
.read(&token::masp_kd_gain_key(addr))?
.expect("kd_gain_nom reward should properly decode");

let locked_target_ratio: Dec = wl_storage
.read(&token::masp_locked_ratio_target(addr))?
.expect("");
.read(&token::masp_locked_ratio_target_key(addr))?
.expect("locked ratio target should properly decode");

// Creating the PD controller for handing out tokens
let controller = RewardsController {
Expand All @@ -126,10 +124,11 @@ where
// Since we must put the notes in a compatible format with the
// note format, we must make the inflation amount discrete.
let noterized_inflation = if total_token_in_masp.is_zero() {
0u32
0u128
} else {
crate::types::uint::Uint::try_into(
(inflation.raw_amount() * PRECISION)
(inflation.raw_amount()
* crate::types::uint::Uint::from(precision))
/ total_token_in_masp.raw_amount(),
)
.unwrap()
Expand Down Expand Up @@ -163,24 +162,21 @@ where
// otherwise we will have an inaccurate view of inflation
wl_storage
.write(
&token::masp_last_inflation(addr),
(total_token_in_masp / PRECISION) * u64::from(noterized_inflation),
&token::masp_last_inflation_key(addr),
token::Amount::from_uint(
(total_token_in_masp.raw_amount() / precision)
* crate::types::uint::Uint::from(noterized_inflation),
0,
)
.unwrap(),
murisi marked this conversation as resolved.
Show resolved Hide resolved
)
.expect("unable to encode new inflation rate (Decimal)");

wl_storage
.write(&token::masp_last_locked_ratio(addr), locked_ratio)
.write(&token::masp_last_locked_ratio_key(addr), locked_ratio)
.expect("unable to encode new locked ratio (Decimal)");

// to make it conform with the expected output, we need to
// move it to a ratio of x/100 to match the masp_rewards
// function This may be unneeded, as we could describe it as a
// ratio of x/1

Ok((
noterized_inflation,
PRECISION.try_into().expect("inflation precision too large"),
))
Ok((noterized_inflation, precision))
}

// This is only enabled when "wasm-runtime" is on, because we're using rayon
Expand All @@ -196,7 +192,7 @@ where
use std::cmp::Ordering;

use masp_primitives::ff::PrimeField;
use masp_primitives::transaction::components::I32Sum as MaspAmount;
use masp_primitives::transaction::components::I128Sum as MaspAmount;
use rayon::iter::{
IndexedParallelIterator, IntoParallelIterator, ParallelIterator,
};
Expand Down Expand Up @@ -288,12 +284,12 @@ where
(addr.clone(), denom),
(MaspAmount::from_pair(
old_asset,
-(*normed_inflation as i32),
-(*normed_inflation as i128),
)
.unwrap()
+ MaspAmount::from_pair(
new_asset,
new_normed_inflation as i32,
new_normed_inflation as i128,
)
.unwrap())
.into(),
Expand All @@ -320,13 +316,13 @@ where
// intermediate tokens cancel/ telescope out
current_convs.insert(
(addr.clone(), denom),
(MaspAmount::from_pair(old_asset, -(reward.1 as i32))
(MaspAmount::from_pair(old_asset, -(reward.1 as i128))
.unwrap()
+ MaspAmount::from_pair(new_asset, reward.1 as i32)
+ MaspAmount::from_pair(new_asset, reward.1 as i128)
.unwrap()
+ MaspAmount::from_pair(
reward_assets[denom as usize],
real_reward as i32,
real_reward as i128,
)
.unwrap())
.into(),
Expand Down
17 changes: 0 additions & 17 deletions core/src/types/address.rs
Original file line number Diff line number Diff line change
Expand Up @@ -681,23 +681,6 @@ pub fn tokens() -> HashMap<Address, (&'static str, Denomination)> {
.collect()
}

/// Temporary helper for testing, a hash map of tokens addresses with their
/// MASP XAN incentive schedules. If the reward is (a, b) then a rewarded tokens
/// are dispensed for every b possessed tokens.
pub fn masp_rewards() -> HashMap<Address, (u32, u32)> {
vec![
(nam(), (0, 100)),
(btc(), (1, 100)),
(eth(), (2, 100)),
(dot(), (3, 100)),
(schnitzel(), (4, 100)),
(apfel(), (5, 100)),
(kartoffel(), (6, 100)),
]
.into_iter()
.collect()
}

#[cfg(test)]
pub mod tests {
use proptest::prelude::*;
Expand Down
Loading
Loading