Skip to content

Commit

Permalink
Increased the precision of MASP rewards.
Browse files Browse the repository at this point in the history
  • Loading branch information
murisi committed Oct 18, 2023
1 parent a9964d6 commit c0f2add
Show file tree
Hide file tree
Showing 34 changed files with 135 additions and 243 deletions.
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
* 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
71 changes: 36 additions & 35 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 @@ -73,33 +76,33 @@ where

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

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

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

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

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

let locked_target_ratio: Dec = wl_storage
.read(&token::masp_locked_ratio_target(addr))?
.read(&token::masp_locked_ratio_target_key(addr))?
.expect("");

// Creating the PD controller for handing out tokens
Expand All @@ -126,10 +129,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 +167,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(),
)
.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 +197,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 +289,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 +321,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

0 comments on commit c0f2add

Please sign in to comment.