Feature/use delegation rates (#741)

* Rename storage read functions for bond reward rates

* Add reward values per epoch in State

Calculate delegation rewards per epoch for mixnodes and gateways, which
are used when the delegators are rewarded for their stake.

* Migration commit, will be reverted after the testnet contract is updated
This commit is contained in:
Bogdan-Ștefan Neacşu
2021-08-18 16:24:00 +03:00
committed by GitHub
parent f5f888a0aa
commit eec211e038
7 changed files with 289 additions and 84 deletions
+2
View File
@@ -13,3 +13,5 @@ pub use gateway::{Gateway, GatewayBond, GatewayOwnershipResponse, PagedGatewayRe
pub use mixnode::{Layer, MixNode, MixNodeBond, MixOwnershipResponse, PagedMixnodeResponse};
pub use msg::{ExecuteMsg, InstantiateMsg, MigrateMsg, QueryMsg};
pub use types::{IdentityKey, IdentityKeyRef, LayerDistribution, SphinxKey, StateParams};
pub use types::default_delegation_reward;
+6
View File
@@ -26,6 +26,10 @@ impl LayerDistribution {
}
}
pub fn default_delegation_reward() -> Decimal {
Decimal::percent(110)
}
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
pub struct StateParams {
pub epoch_length: u32, // length of an epoch, expressed in hours
@@ -34,7 +38,9 @@ pub struct StateParams {
pub minimum_gateway_bond: Uint128, // minimum amount a gateway must bond to get into the system
pub mixnode_bond_reward_rate: Decimal, // annual reward rate, expressed as a decimal like 1.25
pub gateway_bond_reward_rate: Decimal, // annual reward rate, expressed as a decimal like 1.25
#[serde(default = "default_delegation_reward")]
pub mixnode_delegation_reward_rate: Decimal, // annual reward rate, expressed as a decimal like 1.25
#[serde(default = "default_delegation_reward")]
pub gateway_delegation_reward_rate: Decimal, // annual reward rate, expressed as a decimal like 1.25
pub mixnode_active_set_size: u32,
}
+12 -2
View File
@@ -3,7 +3,7 @@
use crate::helpers::calculate_epoch_reward_rate;
use crate::state::State;
use crate::storage::{config, layer_distribution};
use crate::storage::{config, config_read, layer_distribution};
use crate::{error::ContractError, queries, transactions};
use config::defaults::NETWORK_MONITOR_ADDRESS;
use cosmwasm_std::{
@@ -55,6 +55,14 @@ fn default_initial_state(owner: Addr) -> State {
INITIAL_DEFAULT_EPOCH_LENGTH,
gateway_bond_reward_rate,
),
mixnode_epoch_delegation_reward: calculate_epoch_reward_rate(
INITIAL_DEFAULT_EPOCH_LENGTH,
mixnode_delegation_reward_rate,
),
gateway_epoch_delegation_reward: calculate_epoch_reward_rate(
INITIAL_DEFAULT_EPOCH_LENGTH,
gateway_delegation_reward_rate,
),
}
}
@@ -173,7 +181,9 @@ pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> Result<QueryResponse, Cont
}
#[entry_point]
pub fn migrate(_deps: DepsMut, _env: Env, _msg: MigrateMsg) -> Result<Response, ContractError> {
pub fn migrate(deps: DepsMut, _env: Env, _msg: MigrateMsg) -> Result<Response, ContractError> {
let state = config_read(deps.storage).load().unwrap();
config(deps.storage).save(&state)?;
Ok(Default::default())
}
+2
View File
@@ -552,6 +552,8 @@ mod tests {
},
mixnode_epoch_bond_reward: "1.23".parse().unwrap(),
gateway_epoch_bond_reward: "4.56".parse().unwrap(),
mixnode_epoch_delegation_reward: "7.89".parse().unwrap(),
gateway_epoch_delegation_reward: "0.12".parse().unwrap(),
};
config(deps.as_mut().storage).save(&dummy_state).unwrap();
+6
View File
@@ -6,6 +6,8 @@ use mixnet_contract::StateParams;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use mixnet_contract::default_delegation_reward;
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, JsonSchema)]
pub struct State {
pub owner: Addr, // only the owner account can update state
@@ -15,4 +17,8 @@ pub struct State {
// helper values to avoid having to recalculate them on every single payment operation
pub mixnode_epoch_bond_reward: Decimal, // reward per epoch expressed as a decimal like 0.05
pub gateway_epoch_bond_reward: Decimal, // reward per epoch expressed as a decimal like 0.05
#[serde(default = "default_delegation_reward")]
pub mixnode_epoch_delegation_reward: Decimal, // reward per epoch expressed as a decimal like 0.05
#[serde(default = "default_delegation_reward")]
pub gateway_epoch_delegation_reward: Decimal, // reward per epoch expressed as a decimal like 0.05
}
+40 -2
View File
@@ -47,7 +47,7 @@ pub(crate) fn read_state_params(storage: &dyn Storage) -> StateParams {
config_read(storage).load().unwrap().params
}
pub(crate) fn read_mixnode_epoch_reward_rate(storage: &dyn Storage) -> Decimal {
pub(crate) fn read_mixnode_epoch_bond_reward_rate(storage: &dyn Storage) -> Decimal {
// same justification as in `read_state_params` for the unwrap
config_read(storage)
.load()
@@ -55,7 +55,7 @@ pub(crate) fn read_mixnode_epoch_reward_rate(storage: &dyn Storage) -> Decimal {
.mixnode_epoch_bond_reward
}
pub(crate) fn read_gateway_epoch_reward_rate(storage: &dyn Storage) -> Decimal {
pub(crate) fn read_gateway_epoch_bond_reward_rate(storage: &dyn Storage) -> Decimal {
// same justification as in `read_state_params` for the unwrap
config_read(storage)
.load()
@@ -63,6 +63,22 @@ pub(crate) fn read_gateway_epoch_reward_rate(storage: &dyn Storage) -> Decimal {
.gateway_epoch_bond_reward
}
pub(crate) fn read_mixnode_epoch_delegation_reward_rate(storage: &dyn Storage) -> Decimal {
// same justification as in `read_state_params` for the unwrap
config_read(storage)
.load()
.unwrap()
.mixnode_epoch_delegation_reward
}
pub(crate) fn read_gateway_epoch_delegation_reward_rate(storage: &dyn Storage) -> Decimal {
// same justification as in `read_state_params` for the unwrap
config_read(storage)
.load()
.unwrap()
.gateway_epoch_delegation_reward
}
pub fn layer_distribution(storage: &mut dyn Storage) -> Singleton<LayerDistribution> {
singleton(storage, LAYER_DISTRIBUTION_KEY)
}
@@ -240,6 +256,17 @@ pub(crate) fn read_mixnode_bond(
Ok(node.bond_amount.amount)
}
// currently not used outside tests
#[cfg(test)]
pub(crate) fn read_mixnode_delegation(
storage: &dyn Storage,
identity: &[u8],
) -> StdResult<cosmwasm_std::Uint128> {
let bucket = mixnodes_read(storage);
let node = bucket.load(identity)?;
Ok(node.total_delegation.amount)
}
// Gateway-related stuff
pub fn gateways(storage: &mut dyn Storage) -> Bucket<GatewayBond> {
@@ -305,6 +332,17 @@ pub(crate) fn read_gateway_bond(
Ok(node.bond_amount.amount)
}
// currently not used outside tests
#[cfg(test)]
pub(crate) fn read_gateway_delegation(
storage: &dyn Storage,
identity: &[u8],
) -> StdResult<cosmwasm_std::Uint128> {
let bucket = gateways_read(storage);
let node = bucket.load(identity)?;
Ok(node.total_delegation.amount)
}
#[cfg(test)]
mod tests {
use super::*;
+221 -80
View File
@@ -353,6 +353,10 @@ pub(crate) fn try_update_state_params(
calculate_epoch_reward_rate(params.epoch_length, params.mixnode_bond_reward_rate);
state.gateway_epoch_bond_reward =
calculate_epoch_reward_rate(params.epoch_length, params.gateway_bond_reward_rate);
state.mixnode_epoch_delegation_reward =
calculate_epoch_reward_rate(params.epoch_length, params.mixnode_delegation_reward_rate);
state.gateway_epoch_delegation_reward =
calculate_epoch_reward_rate(params.epoch_length, params.gateway_delegation_reward_rate);
} else {
// if mixnode or gateway rewards changed, recalculate respective values
if state.params.mixnode_bond_reward_rate != params.mixnode_bond_reward_rate {
@@ -363,6 +367,18 @@ pub(crate) fn try_update_state_params(
state.gateway_epoch_bond_reward =
calculate_epoch_reward_rate(params.epoch_length, params.gateway_bond_reward_rate);
}
if state.params.mixnode_delegation_reward_rate != params.mixnode_delegation_reward_rate {
state.mixnode_epoch_delegation_reward = calculate_epoch_reward_rate(
params.epoch_length,
params.mixnode_delegation_reward_rate,
);
}
if state.params.gateway_delegation_reward_rate != params.gateway_delegation_reward_rate {
state.gateway_epoch_delegation_reward = calculate_epoch_reward_rate(
params.epoch_length,
params.gateway_delegation_reward_rate,
);
}
}
state.params = params;
@@ -409,12 +425,14 @@ pub(crate) fn try_reward_mixnode(
}
};
let reward_rate = read_mixnode_epoch_reward_rate(deps.storage);
let scaled_reward_rate = scale_reward_by_uptime(reward_rate, uptime)?;
let bond_reward_rate = read_mixnode_epoch_bond_reward_rate(deps.storage);
let delegation_reward_rate = read_mixnode_epoch_delegation_reward_rate(deps.storage);
let bond_scaled_reward_rate = scale_reward_by_uptime(bond_reward_rate, uptime)?;
let delegation_scaled_reward_rate = scale_reward_by_uptime(delegation_reward_rate, uptime)?;
let node_reward = current_bond.bond_amount.amount * scaled_reward_rate;
let node_reward = current_bond.bond_amount.amount * bond_scaled_reward_rate;
let total_delegation_reward =
increase_mix_delegated_stakes(deps.storage, &mix_identity, scaled_reward_rate)?;
increase_mix_delegated_stakes(deps.storage, &mix_identity, delegation_scaled_reward_rate)?;
// update current bond with the reward given to the node and the delegators
current_bond.bond_amount.amount += node_reward;
@@ -469,12 +487,17 @@ pub(crate) fn try_reward_gateway(
}
};
let reward_rate = read_gateway_epoch_reward_rate(deps.storage);
let scaled_reward_rate = scale_reward_by_uptime(reward_rate, uptime)?;
let bond_reward_rate = read_gateway_epoch_bond_reward_rate(deps.storage);
let delegation_reward_rate = read_gateway_epoch_delegation_reward_rate(deps.storage);
let scaled_bond_reward_rate = scale_reward_by_uptime(bond_reward_rate, uptime)?;
let scaled_delegation_reward_rate = scale_reward_by_uptime(delegation_reward_rate, uptime)?;
let node_reward = current_bond.bond_amount.amount * scaled_reward_rate;
let total_delegation_reward =
increase_gateway_delegated_stakes(deps.storage, &gateway_identity, scaled_reward_rate)?;
let node_reward = current_bond.bond_amount.amount * scaled_bond_reward_rate;
let total_delegation_reward = increase_gateway_delegated_stakes(
deps.storage,
&gateway_identity,
scaled_delegation_reward_rate,
)?;
// update current bond with the reward given to the node and the delegators
current_bond.bond_amount.amount += node_reward;
@@ -697,7 +720,8 @@ pub mod tests {
use crate::helpers::calculate_epoch_reward_rate;
use crate::storage::{
gateway_delegations, gateway_delegations_read, layer_distribution_read,
mix_delegations_read, read_gateway_bond, read_gateway_epoch_reward_rate, read_mixnode_bond,
mix_delegations_read, read_gateway_bond, read_gateway_epoch_bond_reward_rate,
read_mixnode_bond,
};
use crate::support::tests::helpers;
use crate::support::tests::helpers::{
@@ -1576,44 +1600,81 @@ pub mod tests {
let current_state = config_read(deps.as_ref().storage).load().unwrap();
assert_eq!(current_state.params, new_params);
// mixnode_epoch_bond_reward is recalculated if annual reward is changed
let current_mix_reward_rate = read_mixnode_epoch_reward_rate(deps.as_ref().storage);
// mixnode_epoch_rewards are recalculated if annual reward is changed
let current_mix_bond_reward_rate =
read_mixnode_epoch_bond_reward_rate(deps.as_ref().storage);
let current_mix_delegation_reward_rate =
read_mixnode_epoch_delegation_reward_rate(deps.as_ref().storage);
let new_mixnode_bond_reward_rate = Decimal::percent(120);
let new_mixnode_delegation_reward_rate = Decimal::percent(120);
// sanity check to make sure we are actually updating the value (in case we changed defaults at some point)
assert_ne!(new_mixnode_bond_reward_rate, current_mix_reward_rate);
// sanity check to make sure we are actually updating the values (in case we changed defaults at some point)
assert_ne!(new_mixnode_bond_reward_rate, current_mix_bond_reward_rate);
assert_ne!(
new_mixnode_delegation_reward_rate,
current_mix_delegation_reward_rate
);
let mut new_params = current_state.params.clone();
new_params.mixnode_bond_reward_rate = new_mixnode_bond_reward_rate;
new_params.mixnode_delegation_reward_rate = new_mixnode_delegation_reward_rate;
let info = mock_info("creator", &[]);
try_update_state_params(deps.as_mut(), info, new_params.clone()).unwrap();
let new_state = config_read(deps.as_ref().storage).load().unwrap();
let expected =
let expected_bond =
calculate_epoch_reward_rate(new_params.epoch_length, new_mixnode_bond_reward_rate);
assert_eq!(expected, new_state.mixnode_epoch_bond_reward);
let expected_delegation = calculate_epoch_reward_rate(
new_params.epoch_length,
new_mixnode_delegation_reward_rate,
);
assert_eq!(expected_bond, new_state.mixnode_epoch_bond_reward);
assert_eq!(
expected_delegation,
new_state.mixnode_epoch_delegation_reward
);
// gateway_epoch_bond_reward is recalculated if annual reward rate is changed
let current_gateway_reward_rate = read_gateway_epoch_reward_rate(deps.as_ref().storage);
// gateway_epoch_rewards are recalculated if annual reward rate is changed
let current_gateway_bond_reward_rate =
read_gateway_epoch_bond_reward_rate(deps.as_ref().storage);
let current_gateway_delegation_reward_rate =
read_gateway_epoch_delegation_reward_rate(deps.as_ref().storage);
let new_gateway_bond_reward_rate = Decimal::percent(120);
let new_gateway_delegation_reward_rate = Decimal::percent(120);
// sanity check to make sure we are actually updating the value (in case we changed defaults at some point)
assert_ne!(new_gateway_bond_reward_rate, current_gateway_reward_rate);
// sanity check to make sure we are actually updating the values (in case we changed defaults at some point)
assert_ne!(
new_gateway_bond_reward_rate,
current_gateway_bond_reward_rate
);
assert_ne!(
new_gateway_delegation_reward_rate,
current_gateway_delegation_reward_rate
);
let mut new_params = current_state.params.clone();
new_params.gateway_bond_reward_rate = new_gateway_bond_reward_rate;
new_params.gateway_delegation_reward_rate = new_gateway_delegation_reward_rate;
let info = mock_info("creator", &[]);
try_update_state_params(deps.as_mut(), info, new_params.clone()).unwrap();
let new_state = config_read(deps.as_ref().storage).load().unwrap();
let expected =
let expected_bond =
calculate_epoch_reward_rate(new_params.epoch_length, new_gateway_bond_reward_rate);
assert_eq!(expected, new_state.gateway_epoch_bond_reward);
let expected_delegation = calculate_epoch_reward_rate(
new_params.epoch_length,
new_gateway_delegation_reward_rate,
);
assert_eq!(expected_bond, new_state.gateway_epoch_bond_reward);
assert_eq!(
expected_delegation,
new_state.gateway_epoch_delegation_reward
);
// if annual reward rate is changed for both mixnodes and gateways in a single update operation,
// both mixnode_epoch_bond_reward and gateway_epoch_bond_reward are recalculated
// both mixnode_epoch_rewards and gateway_epoch_rewards are recalculated
let current_state = config_read(deps.as_ref().storage).load().unwrap();
let new_mixnode_bond_reward_rate = Decimal::percent(130);
let new_gateway_bond_reward_rate = Decimal::percent(130);
@@ -1628,21 +1689,39 @@ pub mod tests {
let mut new_params = current_state.params.clone();
new_params.mixnode_bond_reward_rate = new_mixnode_bond_reward_rate;
new_params.mixnode_delegation_reward_rate = new_mixnode_delegation_reward_rate;
new_params.gateway_bond_reward_rate = new_gateway_bond_reward_rate;
new_params.gateway_delegation_reward_rate = new_gateway_delegation_reward_rate;
let info = mock_info("creator", &[]);
try_update_state_params(deps.as_mut(), info, new_params.clone()).unwrap();
let new_state = config_read(deps.as_ref().storage).load().unwrap();
let expected_mixnode =
let expected_mixnode_bond =
calculate_epoch_reward_rate(new_params.epoch_length, new_mixnode_bond_reward_rate);
assert_eq!(expected_mixnode, new_state.mixnode_epoch_bond_reward);
let expected_mixnode_delegation = calculate_epoch_reward_rate(
new_params.epoch_length,
new_mixnode_delegation_reward_rate,
);
assert_eq!(expected_mixnode_bond, new_state.mixnode_epoch_bond_reward);
assert_eq!(
expected_mixnode_delegation,
new_state.mixnode_epoch_delegation_reward
);
let expected_gateway =
let expected_gateway_bond =
calculate_epoch_reward_rate(new_params.epoch_length, new_gateway_bond_reward_rate);
assert_eq!(expected_gateway, new_state.gateway_epoch_bond_reward);
let expected_gateway_delegation = calculate_epoch_reward_rate(
new_params.epoch_length,
new_gateway_delegation_reward_rate,
);
assert_eq!(expected_gateway_bond, new_state.gateway_epoch_bond_reward);
assert_eq!(
expected_gateway_delegation,
new_state.gateway_epoch_delegation_reward
);
// both mixnode_epoch_bond_reward and gateway_epoch_bond_reward are updated on epoch length change
// both mixnode_epoch_rewards and gateway_epoch_rewards are updated on epoch length change
let new_epoch_length = 42;
// sanity check to make sure we are actually updating the value (in case we changed defaults at some point)
assert_ne!(new_epoch_length, current_state.params.epoch_length);
@@ -1653,13 +1732,29 @@ pub mod tests {
try_update_state_params(deps.as_mut(), info, new_params.clone()).unwrap();
let new_state = config_read(deps.as_ref().storage).load().unwrap();
let expected_mixnode =
let expected_mixnode_bond =
calculate_epoch_reward_rate(new_epoch_length, new_params.mixnode_bond_reward_rate);
assert_eq!(expected_mixnode, new_state.mixnode_epoch_bond_reward);
let expected_mixnode_delegation = calculate_epoch_reward_rate(
new_epoch_length,
new_params.mixnode_delegation_reward_rate,
);
assert_eq!(expected_mixnode_bond, new_state.mixnode_epoch_bond_reward);
assert_eq!(
expected_mixnode_delegation,
new_state.mixnode_epoch_delegation_reward
);
let expected_gateway =
let expected_gateway_bond =
calculate_epoch_reward_rate(new_epoch_length, new_params.gateway_bond_reward_rate);
assert_eq!(expected_gateway, new_state.gateway_epoch_bond_reward);
let expected_gateway_delegation = calculate_epoch_reward_rate(
new_epoch_length,
new_params.gateway_delegation_reward_rate,
);
assert_eq!(expected_gateway_bond, new_state.gateway_epoch_bond_reward);
assert_eq!(
expected_gateway_delegation,
new_state.gateway_epoch_delegation_reward
);
}
#[test]
@@ -1682,9 +1777,10 @@ pub mod tests {
assert_eq!(vec![attr("result", "bond not found")], res.attributes);
let initial_bond = 100_000000;
let initial_delegation = 200_000000;
let mixnode_bond = MixNodeBond {
bond_amount: coin(initial_bond, DENOM),
total_delegation: coin(0, DENOM),
total_delegation: coin(initial_delegation, DENOM),
owner: node_owner.clone(),
layer: Layer::One,
mix_node: MixNode {
@@ -1697,12 +1793,20 @@ pub mod tests {
.save(node_identity.as_bytes(), &mixnode_bond)
.unwrap();
let reward_rate = read_mixnode_epoch_reward_rate(deps.as_ref().storage);
let expected_reward = Uint128(initial_bond) * reward_rate;
mix_delegations(&mut deps.storage, &node_identity)
.save(b"delegator", &Uint128(initial_delegation))
.unwrap();
// the node's bond is correctly increased and scaled by uptime
let bond_reward_rate = read_mixnode_epoch_bond_reward_rate(deps.as_ref().storage);
let delegation_reward_rate =
read_mixnode_epoch_delegation_reward_rate(deps.as_ref().storage);
let expected_bond_reward = Uint128(initial_bond) * bond_reward_rate;
let expected_delegation_reward = Uint128(initial_delegation) * delegation_reward_rate;
// the node's bond and delegations are correctly increased and scaled by uptime
// if node was 100% up, it will get full epoch reward
let expected_bond = expected_reward + Uint128(initial_bond);
let expected_bond = expected_bond_reward + Uint128(initial_bond);
let expected_delegation = expected_delegation_reward + Uint128(initial_delegation);
let info = mock_info(network_monitor_address.as_ref(), &[]);
let res = try_reward_mixnode(deps.as_mut(), info, node_identity.clone(), 100).unwrap();
@@ -1711,19 +1815,26 @@ pub mod tests {
expected_bond,
read_mixnode_bond(deps.as_ref().storage, node_identity.as_bytes()).unwrap()
);
assert_eq!(
expected_delegation,
read_mixnode_delegation(deps.as_ref().storage, node_identity.as_bytes()).unwrap()
);
assert_eq!(
vec![
attr("bond increase", expected_reward),
attr("total delegation increase", Uint128(0)),
attr("bond increase", expected_bond_reward),
attr("total delegation increase", expected_delegation_reward),
],
res.attributes
);
// if node was 20% up, it will get 1/5th of epoch reward
let scaled_reward = scale_reward_by_uptime(reward_rate, 20).unwrap();
let expected_reward = expected_bond * scaled_reward;
let expected_bond = expected_reward + expected_bond;
let scaled_bond_reward = scale_reward_by_uptime(bond_reward_rate, 20).unwrap();
let scaled_delegation_reward = scale_reward_by_uptime(delegation_reward_rate, 20).unwrap();
let expected_bond_reward = expected_bond * scaled_bond_reward;
let expected_delegation_reward = expected_delegation * scaled_delegation_reward;
let expected_bond = expected_bond_reward + expected_bond;
let expected_delegation = expected_delegation_reward + expected_delegation;
let info = mock_info(network_monitor_address.as_ref(), &[]);
let res = try_reward_mixnode(deps.as_mut(), info, node_identity.clone(), 20).unwrap();
@@ -1732,11 +1843,15 @@ pub mod tests {
expected_bond,
read_mixnode_bond(deps.as_ref().storage, node_identity.as_bytes()).unwrap()
);
assert_eq!(
expected_delegation,
read_mixnode_delegation(deps.as_ref().storage, node_identity.as_bytes()).unwrap()
);
assert_eq!(
vec![
attr("bond increase", expected_reward),
attr("total delegation increase", Uint128(0)),
attr("bond increase", expected_bond_reward),
attr("total delegation increase", expected_delegation_reward),
],
res.attributes
);
@@ -1762,9 +1877,10 @@ pub mod tests {
assert_eq!(vec![attr("result", "bond not found")], res.attributes);
let initial_bond = 100_000000;
let initial_delegation = 200_000000;
let gateway_bond = GatewayBond {
bond_amount: coin(initial_bond, DENOM),
total_delegation: coin(0, DENOM),
total_delegation: coin(initial_delegation, DENOM),
owner: node_owner.clone(),
gateway: Gateway {
identity_key: node_identity.clone(),
@@ -1776,12 +1892,20 @@ pub mod tests {
.save(node_identity.as_bytes(), &gateway_bond)
.unwrap();
let reward_rate = read_gateway_epoch_reward_rate(deps.as_ref().storage);
let expected_reward = Uint128(initial_bond) * reward_rate;
gateway_delegations(&mut deps.storage, &node_identity)
.save(b"delegator", &Uint128(initial_delegation))
.unwrap();
// the node's bond is correctly increased and scaled by uptime
let bond_reward_rate = read_gateway_epoch_bond_reward_rate(deps.as_ref().storage);
let delegation_reward_rate =
read_gateway_epoch_delegation_reward_rate(deps.as_ref().storage);
let expected_bond_reward = Uint128(initial_bond) * bond_reward_rate;
let expected_delegation_reward = Uint128(initial_delegation) * delegation_reward_rate;
// the node's bond and delegations are correctly increased and scaled by uptime
// if node was 100% up, it will get full epoch reward
let expected_bond = expected_reward + Uint128(initial_bond);
let expected_bond = expected_bond_reward + Uint128(initial_bond);
let expected_delegation = expected_delegation_reward + Uint128(initial_delegation);
let info = mock_info(network_monitor_address.as_ref(), &[]);
let res = try_reward_gateway(deps.as_mut(), info, node_identity.clone(), 100).unwrap();
@@ -1791,18 +1915,26 @@ pub mod tests {
read_gateway_bond(deps.as_ref().storage, node_identity.as_bytes()).unwrap()
);
assert_eq!(
expected_delegation,
read_gateway_delegation(deps.as_ref().storage, node_identity.as_bytes()).unwrap()
);
assert_eq!(
vec![
attr("bond increase", expected_reward),
attr("total delegation increase", Uint128(0)),
attr("bond increase", expected_bond_reward),
attr("total delegation increase", expected_delegation_reward),
],
res.attributes
);
// if node was 20% up, it will get 1/5th of epoch reward
let scaled_reward = scale_reward_by_uptime(reward_rate, 20).unwrap();
let expected_reward = expected_bond * scaled_reward;
let expected_bond = expected_reward + expected_bond;
let scaled_bond_reward = scale_reward_by_uptime(bond_reward_rate, 20).unwrap();
let scaled_delegation_reward = scale_reward_by_uptime(delegation_reward_rate, 20).unwrap();
let expected_bond_reward = expected_bond * scaled_bond_reward;
let expected_delegation_reward = expected_delegation * scaled_delegation_reward;
let expected_bond = expected_bond_reward + expected_bond;
let expected_delegation = expected_delegation_reward + expected_delegation;
let info = mock_info(network_monitor_address.as_ref(), &[]);
let res = try_reward_gateway(deps.as_mut(), info, node_identity.clone(), 20).unwrap();
@@ -1812,10 +1944,15 @@ pub mod tests {
read_gateway_bond(deps.as_ref().storage, node_identity.as_bytes()).unwrap()
);
assert_eq!(
expected_delegation,
read_gateway_delegation(deps.as_ref().storage, node_identity.as_bytes()).unwrap()
);
assert_eq!(
vec![
attr("bond increase", expected_reward),
attr("total delegation increase", Uint128(0)),
attr("bond increase", expected_bond_reward),
attr("total delegation increase", expected_delegation_reward),
],
res.attributes
);
@@ -2300,7 +2437,7 @@ pub mod tests {
}
#[test]
fn delegators_share_the_same_reward_rate_as_mix_nodes() {
fn delegators_on_mix_node_reward_rate() {
let mut deps = helpers::init_contract();
let current_state = config(deps.as_mut().storage).load().unwrap();
let network_monitor_address = current_state.network_monitor_address;
@@ -2323,14 +2460,15 @@ pub mod tests {
.save(b"delegator3", &Uint128(initial_delegation3))
.unwrap();
let reward = read_mixnode_epoch_reward_rate(deps.as_ref().storage);
let bond_reward = read_mixnode_epoch_bond_reward_rate(deps.as_ref().storage);
let delegation_reward = read_mixnode_epoch_delegation_reward_rate(deps.as_ref().storage);
// the node's bond is correctly increased and scaled by uptime
// the node's bond and delegations are correctly increased and scaled by uptime
// if node was 100% up, it will get full epoch reward
let expected_mix_reward = Uint128(initial_mix_bond) * reward;
let expected_delegation1_reward = Uint128(initial_delegation1) * reward;
let expected_delegation2_reward = Uint128(initial_delegation2) * reward;
let expected_delegation3_reward = Uint128(initial_delegation3) * reward;
let expected_mix_reward = Uint128(initial_mix_bond) * bond_reward;
let expected_delegation1_reward = Uint128(initial_delegation1) * delegation_reward;
let expected_delegation2_reward = Uint128(initial_delegation2) * delegation_reward;
let expected_delegation3_reward = Uint128(initial_delegation3) * delegation_reward;
let expected_bond = expected_mix_reward + Uint128(initial_mix_bond);
let expected_delegation1 = expected_delegation1_reward + Uint128(initial_delegation1);
@@ -2380,12 +2518,13 @@ pub mod tests {
);
// if node was 20% up, it will get 1/5th of epoch reward
let scaled_reward = scale_reward_by_uptime(reward, 20).unwrap();
let scaled_bond_reward = scale_reward_by_uptime(bond_reward, 20).unwrap();
let scaled_delegation_reward = scale_reward_by_uptime(delegation_reward, 20).unwrap();
let expected_mix_reward = expected_bond * scaled_reward;
let expected_delegation1_reward = expected_delegation1 * scaled_reward;
let expected_delegation2_reward = expected_delegation2 * scaled_reward;
let expected_delegation3_reward = expected_delegation3 * scaled_reward;
let expected_mix_reward = expected_bond * scaled_bond_reward;
let expected_delegation1_reward = expected_delegation1 * scaled_delegation_reward;
let expected_delegation2_reward = expected_delegation2 * scaled_delegation_reward;
let expected_delegation3_reward = expected_delegation3 * scaled_delegation_reward;
let expected_bond = expected_mix_reward + expected_bond;
let expected_delegation1 = expected_delegation1_reward + expected_delegation1;
@@ -2904,7 +3043,7 @@ pub mod tests {
}
#[test]
fn delegators_share_the_same_reward_rate_as_gateways() {
fn delegators_on_gateway_reward_rate() {
let mut deps = helpers::init_contract();
let current_state = config(deps.as_mut().storage).load().unwrap();
let network_monitor_address = current_state.network_monitor_address;
@@ -2927,14 +3066,15 @@ pub mod tests {
.save(b"delegator3", &Uint128(initial_delegation3))
.unwrap();
let reward = read_gateway_epoch_reward_rate(deps.as_ref().storage);
let bond_reward = read_gateway_epoch_bond_reward_rate(deps.as_ref().storage);
let delegation_reward = read_gateway_epoch_delegation_reward_rate(deps.as_ref().storage);
// the node's bond is correctly increased and scaled by uptime
// the node's bond and delegations are correctly increased and scaled by uptime
// if node was 100% up, it will get full epoch reward
let expected_gateway_reward = Uint128(initial_gateway_bond) * reward;
let expected_delegation1_reward = Uint128(initial_delegation1) * reward;
let expected_delegation2_reward = Uint128(initial_delegation2) * reward;
let expected_delegation3_reward = Uint128(initial_delegation3) * reward;
let expected_gateway_reward = Uint128(initial_gateway_bond) * bond_reward;
let expected_delegation1_reward = Uint128(initial_delegation1) * delegation_reward;
let expected_delegation2_reward = Uint128(initial_delegation2) * delegation_reward;
let expected_delegation3_reward = Uint128(initial_delegation3) * delegation_reward;
let expected_bond = expected_gateway_reward + Uint128(initial_gateway_bond);
let expected_delegation1 = expected_delegation1_reward + Uint128(initial_delegation1);
@@ -2984,12 +3124,13 @@ pub mod tests {
);
// if node was 20% up, it will get 1/5th of epoch reward
let scaled_reward = scale_reward_by_uptime(reward, 20).unwrap();
let scaled_bond_reward = scale_reward_by_uptime(bond_reward, 20).unwrap();
let scaled_delegation_reward = scale_reward_by_uptime(delegation_reward, 20).unwrap();
let expected_gateway_reward = expected_bond * scaled_reward;
let expected_delegation1_reward = expected_delegation1 * scaled_reward;
let expected_delegation2_reward = expected_delegation2 * scaled_reward;
let expected_delegation3_reward = expected_delegation3 * scaled_reward;
let expected_gateway_reward = expected_bond * scaled_bond_reward;
let expected_delegation1_reward = expected_delegation1 * scaled_delegation_reward;
let expected_delegation2_reward = expected_delegation2 * scaled_delegation_reward;
let expected_delegation3_reward = expected_delegation3 * scaled_delegation_reward;
let expected_bond = expected_gateway_reward + expected_bond;
let expected_delegation1 = expected_delegation1_reward + expected_delegation1;