From 12709261d315174d67f3c7dc4eb07d3c2b7e41cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bogdan-=C8=98tefan=20Neac=C8=99u?= Date: Mon, 16 Aug 2021 12:10:03 +0300 Subject: [PATCH 1/3] Rename storage read functions for bond reward rates --- contracts/mixnet/src/storage.rs | 4 ++-- contracts/mixnet/src/transactions.rs | 20 +++++++++++--------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/contracts/mixnet/src/storage.rs b/contracts/mixnet/src/storage.rs index 677a4416256..407f32be7e6 100644 --- a/contracts/mixnet/src/storage.rs +++ b/contracts/mixnet/src/storage.rs @@ -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() diff --git a/contracts/mixnet/src/transactions.rs b/contracts/mixnet/src/transactions.rs index 6653aeba820..a607ab1de2d 100644 --- a/contracts/mixnet/src/transactions.rs +++ b/contracts/mixnet/src/transactions.rs @@ -409,7 +409,7 @@ pub(crate) fn try_reward_mixnode( } }; - let reward_rate = read_mixnode_epoch_reward_rate(deps.storage); + let reward_rate = read_mixnode_epoch_bond_reward_rate(deps.storage); let scaled_reward_rate = scale_reward_by_uptime(reward_rate, uptime)?; let node_reward = current_bond.bond_amount.amount * scaled_reward_rate; @@ -469,7 +469,7 @@ pub(crate) fn try_reward_gateway( } }; - let reward_rate = read_gateway_epoch_reward_rate(deps.storage); + let reward_rate = read_gateway_epoch_bond_reward_rate(deps.storage); let scaled_reward_rate = scale_reward_by_uptime(reward_rate, uptime)?; let node_reward = current_bond.bond_amount.amount * scaled_reward_rate; @@ -697,7 +697,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::{ @@ -1577,7 +1578,7 @@ pub mod tests { 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); + let current_mix_reward_rate = read_mixnode_epoch_bond_reward_rate(deps.as_ref().storage); let new_mixnode_bond_reward_rate = Decimal::percent(120); // sanity check to make sure we are actually updating the value (in case we changed defaults at some point) @@ -1595,7 +1596,8 @@ pub mod tests { assert_eq!(expected, new_state.mixnode_epoch_bond_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); + let current_gateway_reward_rate = + read_gateway_epoch_bond_reward_rate(deps.as_ref().storage); let new_gateway_bond_reward_rate = Decimal::percent(120); // sanity check to make sure we are actually updating the value (in case we changed defaults at some point) @@ -1697,7 +1699,7 @@ pub mod tests { .save(node_identity.as_bytes(), &mixnode_bond) .unwrap(); - let reward_rate = read_mixnode_epoch_reward_rate(deps.as_ref().storage); + let reward_rate = read_mixnode_epoch_bond_reward_rate(deps.as_ref().storage); let expected_reward = Uint128(initial_bond) * reward_rate; // the node's bond is correctly increased and scaled by uptime @@ -1776,7 +1778,7 @@ pub mod tests { .save(node_identity.as_bytes(), &gateway_bond) .unwrap(); - let reward_rate = read_gateway_epoch_reward_rate(deps.as_ref().storage); + let reward_rate = read_gateway_epoch_bond_reward_rate(deps.as_ref().storage); let expected_reward = Uint128(initial_bond) * reward_rate; // the node's bond is correctly increased and scaled by uptime @@ -2323,7 +2325,7 @@ pub mod tests { .save(b"delegator3", &Uint128(initial_delegation3)) .unwrap(); - let reward = read_mixnode_epoch_reward_rate(deps.as_ref().storage); + let reward = read_mixnode_epoch_bond_reward_rate(deps.as_ref().storage); // the node's bond is correctly increased and scaled by uptime // if node was 100% up, it will get full epoch reward @@ -2927,7 +2929,7 @@ pub mod tests { .save(b"delegator3", &Uint128(initial_delegation3)) .unwrap(); - let reward = read_gateway_epoch_reward_rate(deps.as_ref().storage); + let reward = read_gateway_epoch_bond_reward_rate(deps.as_ref().storage); // the node's bond is correctly increased and scaled by uptime // if node was 100% up, it will get full epoch reward From 34c97252a242236e4ce0c27015db843b889826ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bogdan-=C8=98tefan=20Neac=C8=99u?= Date: Mon, 16 Aug 2021 14:54:46 +0300 Subject: [PATCH 2/3] 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. --- contracts/mixnet/src/contract.rs | 8 + contracts/mixnet/src/queries.rs | 2 + contracts/mixnet/src/state.rs | 2 + contracts/mixnet/src/storage.rs | 38 ++++ contracts/mixnet/src/transactions.rs | 297 ++++++++++++++++++++------- 5 files changed, 268 insertions(+), 79 deletions(-) diff --git a/contracts/mixnet/src/contract.rs b/contracts/mixnet/src/contract.rs index 26f82da9d97..5487ea451e3 100644 --- a/contracts/mixnet/src/contract.rs +++ b/contracts/mixnet/src/contract.rs @@ -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, + ), } } diff --git a/contracts/mixnet/src/queries.rs b/contracts/mixnet/src/queries.rs index 0152f22e91f..ed546a72d38 100644 --- a/contracts/mixnet/src/queries.rs +++ b/contracts/mixnet/src/queries.rs @@ -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(); diff --git a/contracts/mixnet/src/state.rs b/contracts/mixnet/src/state.rs index 36ef8fbd5a4..c537366f074 100644 --- a/contracts/mixnet/src/state.rs +++ b/contracts/mixnet/src/state.rs @@ -15,4 +15,6 @@ 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 + pub mixnode_epoch_delegation_reward: Decimal, // reward per epoch expressed as a decimal like 0.05 + pub gateway_epoch_delegation_reward: Decimal, // reward per epoch expressed as a decimal like 0.05 } diff --git a/contracts/mixnet/src/storage.rs b/contracts/mixnet/src/storage.rs index 407f32be7e6..76eb357f864 100644 --- a/contracts/mixnet/src/storage.rs +++ b/contracts/mixnet/src/storage.rs @@ -63,6 +63,22 @@ pub(crate) fn read_gateway_epoch_bond_reward_rate(storage: &dyn Storage) -> Deci .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 { 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 { + 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 { @@ -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 { + let bucket = gateways_read(storage); + let node = bucket.load(identity)?; + Ok(node.total_delegation.amount) +} + #[cfg(test)] mod tests { use super::*; diff --git a/contracts/mixnet/src/transactions.rs b/contracts/mixnet/src/transactions.rs index a607ab1de2d..70c30f014d3 100644 --- a/contracts/mixnet/src/transactions.rs +++ b/contracts/mixnet/src/transactions.rs @@ -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_bond_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_bond_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; @@ -1577,45 +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_bond_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 = + // 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); @@ -1630,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); @@ -1655,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] @@ -1684,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 { @@ -1699,12 +1793,20 @@ pub mod tests { .save(node_identity.as_bytes(), &mixnode_bond) .unwrap(); - let reward_rate = read_mixnode_epoch_bond_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(); + + 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 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_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(); @@ -1713,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(); @@ -1734,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 ); @@ -1764,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(), @@ -1778,12 +1892,20 @@ pub mod tests { .save(node_identity.as_bytes(), &gateway_bond) .unwrap(); - let reward_rate = read_gateway_epoch_bond_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(); + + 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 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_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(); @@ -1793,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(); @@ -1814,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 ); @@ -2302,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; @@ -2325,14 +2460,15 @@ pub mod tests { .save(b"delegator3", &Uint128(initial_delegation3)) .unwrap(); - let reward = read_mixnode_epoch_bond_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); @@ -2382,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; @@ -2906,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; @@ -2929,14 +3066,15 @@ pub mod tests { .save(b"delegator3", &Uint128(initial_delegation3)) .unwrap(); - let reward = read_gateway_epoch_bond_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); @@ -2986,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; From 38d868bcce3738c00d0f60bbc40373efd3cf7c6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bogdan-=C8=98tefan=20Neac=C8=99u?= Date: Wed, 18 Aug 2021 13:55:21 +0300 Subject: [PATCH 3/3] Migration commit, will be reverted after the testnet contract is updated --- common/mixnet-contract/src/lib.rs | 2 ++ common/mixnet-contract/src/types.rs | 6 ++++++ contracts/mixnet/src/contract.rs | 6 ++++-- contracts/mixnet/src/state.rs | 4 ++++ 4 files changed, 16 insertions(+), 2 deletions(-) diff --git a/common/mixnet-contract/src/lib.rs b/common/mixnet-contract/src/lib.rs index 785497197b9..6779514b291 100644 --- a/common/mixnet-contract/src/lib.rs +++ b/common/mixnet-contract/src/lib.rs @@ -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; diff --git a/common/mixnet-contract/src/types.rs b/common/mixnet-contract/src/types.rs index 9d0404daf08..8a202fde610 100644 --- a/common/mixnet-contract/src/types.rs +++ b/common/mixnet-contract/src/types.rs @@ -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, } diff --git a/contracts/mixnet/src/contract.rs b/contracts/mixnet/src/contract.rs index 5487ea451e3..9dd24a7eb64 100644 --- a/contracts/mixnet/src/contract.rs +++ b/contracts/mixnet/src/contract.rs @@ -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::{ @@ -181,7 +181,9 @@ pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> Result Result { +pub fn migrate(deps: DepsMut, _env: Env, _msg: MigrateMsg) -> Result { + let state = config_read(deps.storage).load().unwrap(); + config(deps.storage).save(&state)?; Ok(Default::default()) } diff --git a/contracts/mixnet/src/state.rs b/contracts/mixnet/src/state.rs index c537366f074..d4f0034ff61 100644 --- a/contracts/mixnet/src/state.rs +++ b/contracts/mixnet/src/state.rs @@ -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,6 +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 }