diff --git a/common/mixnet-contract/src/delegation.rs b/common/mixnet-contract/src/delegation.rs index 12b1ac80d4..5aab311db5 100644 --- a/common/mixnet-contract/src/delegation.rs +++ b/common/mixnet-contract/src/delegation.rs @@ -2,11 +2,26 @@ #![allow(clippy::field_reassign_with_default)] use crate::{Addr, IdentityKey}; -use cosmwasm_std::Coin; +use cosmwasm_std::{Coin, Uint128}; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; use std::fmt::Display; +#[derive(Debug, Deserialize, PartialEq, Serialize)] +pub struct RawDelegationData { + pub amount: Uint128, + pub block_height: u64, +} + +impl RawDelegationData { + pub fn new(amount: Uint128, block_height: u64) -> Self { + RawDelegationData { + amount, + block_height, + } + } +} + #[derive(Clone, Debug, Deserialize, PartialEq, Serialize, JsonSchema)] pub struct Delegation { owner: Addr, diff --git a/common/mixnet-contract/src/lib.rs b/common/mixnet-contract/src/lib.rs index e259065e31..73a3769e01 100644 --- a/common/mixnet-contract/src/lib.rs +++ b/common/mixnet-contract/src/lib.rs @@ -10,7 +10,7 @@ mod types; pub use cosmwasm_std::{Addr, Coin}; pub use delegation::{ Delegation, PagedGatewayDelegationsResponse, PagedMixDelegationsResponse, - PagedReverseGatewayDelegationsResponse, PagedReverseMixDelegationsResponse, + PagedReverseGatewayDelegationsResponse, PagedReverseMixDelegationsResponse, RawDelegationData, }; pub use gateway::{Gateway, GatewayBond, GatewayOwnershipResponse, PagedGatewayResponse}; pub use mixnode::{Layer, MixNode, MixNodeBond, MixOwnershipResponse, PagedMixnodeResponse}; diff --git a/contracts/mixnet/src/contract.rs b/contracts/mixnet/src/contract.rs index 32af49cf66..62cd403093 100644 --- a/contracts/mixnet/src/contract.rs +++ b/contracts/mixnet/src/contract.rs @@ -2,18 +2,19 @@ // SPDX-License-Identifier: Apache-2.0 use crate::helpers::calculate_epoch_reward_rate; +use crate::queries::DELEGATION_PAGE_MAX_LIMIT; use crate::state::State; -use crate::storage::{ - config, layer_distribution, reverse_gateway_delegations, reverse_mix_delegations, -}; +use crate::storage::{config, gateway_delegations, layer_distribution, mix_delegations}; use crate::{error::ContractError, queries, transactions}; -use config::defaults::NETWORK_MONITOR_ADDRESS; +use config::defaults::{DENOM, NETWORK_MONITOR_ADDRESS}; use cosmwasm_std::{ - entry_point, to_binary, Addr, Decimal, Deps, DepsMut, Env, MessageInfo, QueryResponse, - Response, Uint128, + coin, entry_point, to_binary, Addr, Decimal, Deps, DepsMut, Env, MessageInfo, Order, + QueryResponse, Response, StdResult, Storage, Uint128, }; +use cosmwasm_storage::ReadonlyBucket; use mixnet_contract::{ - Delegation, ExecuteMsg, IdentityKey, IdentityKeyRef, InstantiateMsg, MigrateMsg, QueryMsg, + Delegation, ExecuteMsg, IdentityKey, IdentityKeyRef, InstantiateMsg, MigrateMsg, + PagedGatewayDelegationsResponse, PagedMixDelegationsResponse, QueryMsg, RawDelegationData, StateParams, }; @@ -94,7 +95,7 @@ pub fn instantiate( #[entry_point] pub fn execute( deps: DepsMut, - _env: Env, + env: Env, info: MessageInfo, msg: ExecuteMsg, ) -> Result { @@ -113,13 +114,13 @@ pub fn execute( transactions::try_reward_gateway(deps, info, identity, uptime) } ExecuteMsg::DelegateToMixnode { mix_identity } => { - transactions::try_delegate_to_mixnode(deps, info, mix_identity) + transactions::try_delegate_to_mixnode(deps, env, info, mix_identity) } ExecuteMsg::UndelegateFromMixnode { mix_identity } => { transactions::try_remove_delegation_from_mixnode(deps, info, mix_identity) } ExecuteMsg::DelegateToGateway { gateway_identity } => { - transactions::try_delegate_to_gateway(deps, info, gateway_identity) + transactions::try_delegate_to_gateway(deps, env, info, gateway_identity) } ExecuteMsg::UndelegateFromGateway { gateway_identity } => { transactions::try_remove_delegation_from_gateway(deps, info, gateway_identity) @@ -206,7 +207,110 @@ pub fn query(deps: Deps, _env: Env, msg: QueryMsg) -> Result Result { +pub fn migrate(deps: DepsMut, env: Env, _msg: MigrateMsg) -> Result { + const PREFIX_MIX_DELEGATION: &[u8] = b"md"; + const PREFIX_GATEWAY_DELEGATION: &[u8] = b"gd"; + const DELEGATION_PAGE_DEFAULT_LIMIT: u32 = 500; + + fn calculate_start_value>(start_after: Option) -> Option> { + start_after.as_ref().map(|identity| { + identity + .as_ref() + .as_bytes() + .iter() + .cloned() + .chain(std::iter::once(0)) + .collect() + }) + } + + fn query_mixnode_old_delegations_paged( + deps: Deps, + mix_identity: IdentityKey, + start_after: Option, + limit: Option, + ) -> StdResult { + let limit = limit + .unwrap_or(DELEGATION_PAGE_DEFAULT_LIMIT) + .min(DELEGATION_PAGE_MAX_LIMIT) as usize; + let start = calculate_start_value(start_after); + + let delegations = mix_old_delegations_read(deps.storage, &mix_identity) + .range(start.as_deref(), None, Order::Ascending) + .take(limit) + .map(|res| { + res.map(|entry| { + Delegation::new( + Addr::unchecked(String::from_utf8(entry.0).expect( + "Non-UTF8 address used as key in bucket. The storage is corrupted!", + )), + coin(entry.1.u128(), DENOM), + ) + }) + }) + .collect::>>()?; + + let start_next_after = delegations.last().map(|delegation| delegation.owner()); + + Ok(PagedMixDelegationsResponse::new( + mix_identity, + delegations, + start_next_after, + )) + } + + fn query_gateway_old_delegations_paged( + deps: Deps, + gateway_identity: IdentityKey, + start_after: Option, + limit: Option, + ) -> StdResult { + let limit = limit + .unwrap_or(DELEGATION_PAGE_DEFAULT_LIMIT) + .min(DELEGATION_PAGE_MAX_LIMIT) as usize; + let start = calculate_start_value(start_after); + + let delegations = gateway_old_delegations_read(deps.storage, &gateway_identity) + .range(start.as_deref(), None, Order::Ascending) + .take(limit) + .map(|res| { + res.map(|entry| { + Delegation::new( + Addr::unchecked(String::from_utf8(entry.0).expect( + "Non-UTF8 address used as key in bucket. The storage is corrupted!", + )), + coin(entry.1.u128(), DENOM), + ) + }) + }) + .collect::>>()?; + + let start_next_after = delegations.last().map(|delegation| delegation.owner()); + + Ok(PagedGatewayDelegationsResponse::new( + gateway_identity, + delegations, + start_next_after, + )) + } + + fn mix_old_delegations_read<'a>( + storage: &'a dyn Storage, + mix_identity: IdentityKeyRef, + ) -> ReadonlyBucket<'a, Uint128> { + ReadonlyBucket::multilevel(storage, &[PREFIX_MIX_DELEGATION, mix_identity.as_bytes()]) + } + + fn gateway_old_delegations_read<'a>( + storage: &'a dyn Storage, + gateway_identity: IdentityKeyRef, + ) -> ReadonlyBucket<'a, Uint128> { + ReadonlyBucket::multilevel( + storage, + &[PREFIX_GATEWAY_DELEGATION, gateway_identity.as_bytes()], + ) + } + fn get_all_mixnodes_identities(deps: &DepsMut) -> Result, ContractError> { let mut mixnode_bonds = Vec::new(); let mut start_after = None; @@ -258,7 +362,7 @@ pub fn migrate(deps: DepsMut, _env: Env, _msg: MigrateMsg) -> Result Result Result Result Ok(Delegation::new( address, - coin(delegation_value.u128(), DENOM), + coin(delegation_value.amount.u128(), DENOM), )), None => Err(ContractError::NoMixnodeDelegationFound { identity: mix_identity, @@ -212,7 +212,7 @@ pub(crate) fn query_gateway_delegations_paged( Addr::unchecked(String::from_utf8(entry.0).expect( "Non-UTF8 address used as key in bucket. The storage is corrupted!", )), - coin(entry.1.u128(), DENOM), + coin(entry.1.amount.u128(), DENOM), ) }) }) @@ -267,7 +267,7 @@ pub(crate) fn query_gateway_delegation( match gateway_delegations_read(deps.storage, &gateway_identity).may_load(address.as_bytes())? { Some(delegation_value) => Ok(Delegation::new( address, - coin(delegation_value.u128(), DENOM), + coin(delegation_value.amount.u128(), DENOM), )), None => Err(ContractError::NoGatewayDelegationFound { identity: gateway_identity, @@ -282,10 +282,12 @@ mod tests { use crate::state::State; use crate::storage::{config, gateway_delegations, gateways, mix_delegations, mixnodes}; use crate::support::tests::helpers; - use crate::support::tests::helpers::{good_gateway_bond, good_mixnode_bond}; + use crate::support::tests::helpers::{ + good_gateway_bond, good_mixnode_bond, raw_delegation_fixture, + }; use crate::transactions; use cosmwasm_std::testing::mock_info; - use cosmwasm_std::{Addr, Storage, Uint128}; + use cosmwasm_std::{Addr, Storage}; use mixnet_contract::{Gateway, MixNode}; #[test] @@ -632,14 +634,12 @@ mod tests { #[cfg(test)] mod querying_for_mixnode_delegations_paged { use super::*; - use crate::storage::mix_delegations; - use cosmwasm_std::Uint128; fn store_n_delegations(n: u32, storage: &mut dyn Storage, node_identity: &IdentityKey) { for i in 0..n { let address = format!("address{}", i); mix_delegations(storage, node_identity) - .save(address.as_bytes(), &Uint128(42)) + .save(address.as_bytes(), &raw_delegation_fixture(42)) .unwrap(); } } @@ -711,7 +711,7 @@ mod tests { let node_identity: IdentityKey = "foo".into(); mix_delegations(&mut deps.storage, &node_identity) - .save("1".as_bytes(), &Uint128(42)) + .save("1".as_bytes(), &raw_delegation_fixture(42)) .unwrap(); let per_page = 2; @@ -728,7 +728,7 @@ mod tests { // save another mix_delegations(&mut deps.storage, &node_identity) - .save("2".as_bytes(), &Uint128(42)) + .save("2".as_bytes(), &raw_delegation_fixture(42)) .unwrap(); // page1 should have 2 results on it @@ -742,7 +742,7 @@ mod tests { assert_eq!(2, page1.delegations.len()); mix_delegations(&mut deps.storage, &node_identity) - .save("3".as_bytes(), &Uint128(42)) + .save("3".as_bytes(), &raw_delegation_fixture(42)) .unwrap(); // page1 still has 2 results @@ -769,7 +769,7 @@ mod tests { // save another one mix_delegations(&mut deps.storage, &node_identity) - .save("4".as_bytes(), &Uint128(42)) + .save("4".as_bytes(), &raw_delegation_fixture(42)) .unwrap(); let start_after = Addr::unchecked("2"); @@ -793,7 +793,7 @@ mod tests { let delegation_owner = Addr::unchecked("bar"); mix_delegations(&mut deps.storage, &node_identity) - .save(delegation_owner.as_bytes(), &Uint128(42)) + .save(delegation_owner.as_bytes(), &raw_delegation_fixture(42)) .unwrap(); assert_eq!( @@ -825,7 +825,7 @@ mod tests { // add delegation from a different address mix_delegations(&mut deps.storage, &node_identity1) - .save(delegation_owner2.as_bytes(), &Uint128(42)) + .save(delegation_owner2.as_bytes(), &raw_delegation_fixture(42)) .unwrap(); assert_eq!( @@ -842,7 +842,7 @@ mod tests { // add delegation for a different node mix_delegations(&mut deps.storage, &node_identity2) - .save(delegation_owner1.as_bytes(), &Uint128(42)) + .save(delegation_owner1.as_bytes(), &raw_delegation_fixture(42)) .unwrap(); assert_eq!( @@ -1019,13 +1019,12 @@ mod tests { mod querying_for_gateway_delegations_paged { use super::*; use crate::storage::gateway_delegations; - use cosmwasm_std::Uint128; fn store_n_delegations(n: u32, storage: &mut dyn Storage, node_identity: &IdentityKey) { for i in 0..n { let address = format!("address{}", i); gateway_delegations(storage, node_identity) - .save(address.as_bytes(), &Uint128(42)) + .save(address.as_bytes(), &raw_delegation_fixture(42)) .unwrap(); } } @@ -1097,7 +1096,7 @@ mod tests { let node_identity: IdentityKey = "foo".into(); gateway_delegations(&mut deps.storage, &node_identity) - .save("1".as_bytes(), &Uint128(42)) + .save("1".as_bytes(), &raw_delegation_fixture(42)) .unwrap(); let per_page = 2; @@ -1114,7 +1113,7 @@ mod tests { // save another gateway_delegations(&mut deps.storage, &node_identity) - .save("2".as_bytes(), &Uint128(42)) + .save("2".as_bytes(), &raw_delegation_fixture(42)) .unwrap(); // page1 should have 2 results on it @@ -1128,7 +1127,7 @@ mod tests { assert_eq!(2, page1.delegations.len()); gateway_delegations(&mut deps.storage, &node_identity) - .save("3".as_bytes(), &Uint128(42)) + .save("3".as_bytes(), &raw_delegation_fixture(42)) .unwrap(); // page1 still has 2 results @@ -1155,7 +1154,7 @@ mod tests { // save another one gateway_delegations(&mut deps.storage, &node_identity) - .save("4".as_bytes(), &Uint128(42)) + .save("4".as_bytes(), &raw_delegation_fixture(42)) .unwrap(); let start_after = Addr::unchecked("2"); @@ -1179,7 +1178,7 @@ mod tests { let delegation_owner = Addr::unchecked("bar"); gateway_delegations(&mut deps.storage, &node_identity) - .save(delegation_owner.as_bytes(), &Uint128(42)) + .save(delegation_owner.as_bytes(), &raw_delegation_fixture(42)) .unwrap(); assert_eq!( @@ -1211,7 +1210,7 @@ mod tests { // add delegation from a different address gateway_delegations(&mut deps.storage, &node_identity1) - .save(delegation_owner2.as_bytes(), &Uint128(42)) + .save(delegation_owner2.as_bytes(), &raw_delegation_fixture(42)) .unwrap(); assert_eq!( @@ -1228,7 +1227,7 @@ mod tests { // add delegation for a different node gateway_delegations(&mut deps.storage, &node_identity2) - .save(delegation_owner1.as_bytes(), &Uint128(42)) + .save(delegation_owner1.as_bytes(), &raw_delegation_fixture(42)) .unwrap(); assert_eq!( diff --git a/contracts/mixnet/src/storage.rs b/contracts/mixnet/src/storage.rs index e778cfc250..3de3b08c9b 100644 --- a/contracts/mixnet/src/storage.rs +++ b/contracts/mixnet/src/storage.rs @@ -10,7 +10,7 @@ use cosmwasm_storage::{ }; use mixnet_contract::{ Addr, GatewayBond, IdentityKey, IdentityKeyRef, Layer, LayerDistribution, MixNodeBond, - StateParams, + RawDelegationData, StateParams, }; // storage prefixes @@ -193,11 +193,11 @@ pub(crate) fn increase_mix_delegated_stakes( ); // and for each of them increase the stake proportionally to the reward - for (delegator_address, amount) in delegations_chunk.into_iter() { - let reward = amount * scaled_reward_rate; - let new_amount = amount + reward; + for (delegator_address, mut delegation) in delegations_chunk.into_iter() { + let reward = delegation.amount * scaled_reward_rate; + delegation.amount += reward; total_rewarded += reward; - mix_delegations(storage, mix_identity).save(&delegator_address, &new_amount)?; + mix_delegations(storage, mix_identity).save(&delegator_address, &delegation)?; } } @@ -237,11 +237,11 @@ pub(crate) fn increase_gateway_delegated_stakes( ); // and for each of them increase the stake proportionally to the reward - for (delegator_address, amount) in delegations_chunk.into_iter() { - let reward = amount * scaled_reward_rate; - let new_amount = amount + reward; + for (delegator_address, mut delegation) in delegations_chunk.into_iter() { + let reward = delegation.amount * scaled_reward_rate; + delegation.amount += reward; total_rewarded += reward; - gateway_delegations(storage, gateway_identity).save(&delegator_address, &new_amount)?; + gateway_delegations(storage, gateway_identity).save(&delegator_address, &delegation)?; } } @@ -293,14 +293,14 @@ pub fn gateways_owners_read(storage: &dyn Storage) -> ReadonlyBucket( storage: &'a mut dyn Storage, mix_identity: IdentityKeyRef, -) -> Bucket<'a, Uint128> { +) -> Bucket<'a, RawDelegationData> { Bucket::multilevel(storage, &[PREFIX_MIX_DELEGATION, mix_identity.as_bytes()]) } pub fn mix_delegations_read<'a>( storage: &'a dyn Storage, mix_identity: IdentityKeyRef, -) -> ReadonlyBucket<'a, Uint128> { +) -> ReadonlyBucket<'a, RawDelegationData> { ReadonlyBucket::multilevel(storage, &[PREFIX_MIX_DELEGATION, mix_identity.as_bytes()]) } @@ -318,7 +318,7 @@ pub fn reverse_mix_delegations_read<'a>( pub fn gateway_delegations<'a>( storage: &'a mut dyn Storage, gateway_identity: IdentityKeyRef, -) -> Bucket<'a, Uint128> { +) -> Bucket<'a, RawDelegationData> { Bucket::multilevel( storage, &[PREFIX_GATEWAY_DELEGATION, gateway_identity.as_bytes()], @@ -328,7 +328,7 @@ pub fn gateway_delegations<'a>( pub fn gateway_delegations_read<'a>( storage: &'a dyn Storage, gateway_identity: IdentityKeyRef, -) -> ReadonlyBucket<'a, Uint128> { +) -> ReadonlyBucket<'a, RawDelegationData> { ReadonlyBucket::multilevel( storage, &[PREFIX_GATEWAY_DELEGATION, gateway_identity.as_bytes()], @@ -382,6 +382,7 @@ mod tests { use super::*; use crate::support::tests::helpers::{ gateway_bond_fixture, gateway_fixture, mix_node_fixture, mixnode_bond_fixture, + raw_delegation_fixture, }; use config::defaults::DENOM; use cosmwasm_std::testing::MockStorage; @@ -523,7 +524,10 @@ mod tests { let delegator_address = Addr::unchecked("bob"); mix_delegations(&mut deps.storage, &node_identity) - .save(delegator_address.as_bytes(), &Uint128(1000)) + .save( + delegator_address.as_bytes(), + &RawDelegationData::new(1000u128.into(), 42), + ) .unwrap(); let total_increase = @@ -532,8 +536,9 @@ mod tests { assert_eq!(Uint128(1), total_increase); + // amount is incremented, block height remains the same assert_eq!( - Uint128(1001), + RawDelegationData::new(1001u128.into(), 42), mix_delegations_read(&mut deps.storage, &node_identity) .load(delegator_address.as_bytes()) .unwrap() @@ -551,7 +556,7 @@ mod tests { for i in 0..100 { let delegator_address = Addr::unchecked(format!("address{}", i)); mix_delegations(&mut deps.storage, &node_identity) - .save(delegator_address.as_bytes(), &Uint128(1000)) + .save(delegator_address.as_bytes(), &raw_delegation_fixture(1000)) .unwrap(); } @@ -564,7 +569,7 @@ mod tests { for i in 0..100 { let delegator_address = Addr::unchecked(format!("address{}", i)); assert_eq!( - Uint128(1001), + raw_delegation_fixture(1001), mix_delegations_read(&mut deps.storage, &node_identity) .load(delegator_address.as_bytes()) .unwrap() @@ -583,7 +588,7 @@ mod tests { for i in 0..queries::DELEGATION_PAGE_MAX_LIMIT * 10 { let delegator_address = Addr::unchecked(format!("address{}", i)); mix_delegations(&mut deps.storage, &node_identity) - .save(delegator_address.as_bytes(), &Uint128(1000)) + .save(delegator_address.as_bytes(), &raw_delegation_fixture(1000)) .unwrap(); } @@ -599,7 +604,7 @@ mod tests { for i in 0..queries::DELEGATION_PAGE_MAX_LIMIT * 10 { let delegator_address = Addr::unchecked(format!("address{}", i)); assert_eq!( - Uint128(1001), + raw_delegation_fixture(1001), mix_delegations_read(&mut deps.storage, &node_identity) .load(delegator_address.as_bytes()) .unwrap() @@ -716,7 +721,10 @@ mod tests { let delegator_address = Addr::unchecked("bob"); gateway_delegations(&mut deps.storage, &node_identity) - .save(delegator_address.as_bytes(), &Uint128(1000)) + .save( + delegator_address.as_bytes(), + &RawDelegationData::new(1000u128.into(), 42), + ) .unwrap(); let total_increase = increase_gateway_delegated_stakes( @@ -728,8 +736,9 @@ mod tests { assert_eq!(Uint128(1), total_increase); + // amount is incremented, block height remains the same assert_eq!( - Uint128(1001), + RawDelegationData::new(1001u128.into(), 42), gateway_delegations_read(&mut deps.storage, &node_identity) .load(delegator_address.as_bytes()) .unwrap() @@ -747,7 +756,7 @@ mod tests { for i in 0..100 { let delegator_address = Addr::unchecked(format!("address{}", i)); gateway_delegations(&mut deps.storage, &node_identity) - .save(delegator_address.as_bytes(), &Uint128(1000)) + .save(delegator_address.as_bytes(), &raw_delegation_fixture(1000)) .unwrap(); } @@ -763,7 +772,7 @@ mod tests { for i in 0..100 { let delegator_address = Addr::unchecked(format!("address{}", i)); assert_eq!( - Uint128(1001), + raw_delegation_fixture(1001), gateway_delegations_read(&mut deps.storage, &node_identity) .load(delegator_address.as_bytes()) .unwrap() @@ -782,7 +791,7 @@ mod tests { for i in 0..queries::DELEGATION_PAGE_MAX_LIMIT * 10 { let delegator_address = Addr::unchecked(format!("address{}", i)); gateway_delegations(&mut deps.storage, &node_identity) - .save(delegator_address.as_bytes(), &Uint128(1000)) + .save(delegator_address.as_bytes(), &raw_delegation_fixture(1000)) .unwrap(); } @@ -801,7 +810,7 @@ mod tests { for i in 0..queries::DELEGATION_PAGE_MAX_LIMIT * 10 { let delegator_address = Addr::unchecked(format!("address{}", i)); assert_eq!( - Uint128(1001), + raw_delegation_fixture(1001), gateway_delegations_read(&mut deps.storage, &node_identity) .load(delegator_address.as_bytes()) .unwrap() diff --git a/contracts/mixnet/src/support/tests.rs b/contracts/mixnet/src/support/tests.rs index 72993e6721..fd1ac7fade 100644 --- a/contracts/mixnet/src/support/tests.rs +++ b/contracts/mixnet/src/support/tests.rs @@ -5,7 +5,6 @@ pub mod helpers { use crate::contract::{instantiate, INITIAL_MIXNODE_BOND}; use crate::transactions::{try_add_gateway, try_add_mixnode}; use config::defaults::DENOM; - use cosmwasm_std::coin; use cosmwasm_std::from_binary; use cosmwasm_std::testing::mock_dependencies; use cosmwasm_std::testing::mock_env; @@ -16,10 +15,11 @@ pub mod helpers { use cosmwasm_std::Addr; use cosmwasm_std::Coin; use cosmwasm_std::OwnedDeps; + use cosmwasm_std::{coin, Uint128}; use cosmwasm_std::{Empty, MemoryStorage}; use mixnet_contract::{ Gateway, GatewayBond, InstantiateMsg, Layer, MixNode, MixNodeBond, PagedGatewayResponse, - PagedMixnodeResponse, QueryMsg, + PagedMixnodeResponse, QueryMsg, RawDelegationData, }; pub fn add_mixnode( @@ -159,6 +159,10 @@ pub mod helpers { GatewayBond::new(coin(50, DENOM), Addr::unchecked("foo"), gateway) } + pub fn raw_delegation_fixture(amount: u128) -> RawDelegationData { + RawDelegationData::new(Uint128(amount), 42) + } + pub fn query_contract_balance( address: Addr, deps: OwnedDeps, diff --git a/contracts/mixnet/src/transactions.rs b/contracts/mixnet/src/transactions.rs index 5f1f41b3c3..7260f751aa 100644 --- a/contracts/mixnet/src/transactions.rs +++ b/contracts/mixnet/src/transactions.rs @@ -7,11 +7,12 @@ use crate::queries; use crate::storage::*; use config::defaults::DENOM; use cosmwasm_std::{ - attr, coins, BankMsg, Coin, Decimal, DepsMut, MessageInfo, Order, Response, StdResult, Uint128, + attr, coins, BankMsg, Coin, Decimal, DepsMut, Env, MessageInfo, Order, Response, StdResult, + Uint128, }; use cosmwasm_storage::ReadonlyBucket; use mixnet_contract::{ - Gateway, GatewayBond, IdentityKey, Layer, MixNode, MixNodeBond, StateParams, + Gateway, GatewayBond, IdentityKey, Layer, MixNode, MixNodeBond, RawDelegationData, StateParams, }; const OLD_DELEGATIONS_CHUNK_SIZE: usize = 500; @@ -23,7 +24,7 @@ const OLD_DELEGATIONS_CHUNK_SIZE: usize = 500; // 3. The node unbonds // 4. Some of the addresses that delegated in the past have not removed the delegation yet // 5. The node rebonds with the same identity -fn find_old_delegations(delegations_bucket: ReadonlyBucket) -> StdResult { +fn find_old_delegations(delegations_bucket: ReadonlyBucket) -> StdResult { // I think it's incredibly unlikely to ever read more than that // but in case we do, we should guard ourselves against possible // out of memory errors (wasm contracts can only allocate at most 2MB @@ -45,7 +46,7 @@ fn find_old_delegations(delegations_bucket: ReadonlyBucket) -> StdResul continue; } - let value = delegation?.1; + let value = delegation?.1.amount; total_delegation.amount += value; } @@ -540,6 +541,7 @@ fn validate_delegation_stake(delegation: &[Coin]) -> Result<(), ContractError> { pub(crate) fn try_delegate_to_mixnode( deps: DepsMut, + env: Env, info: MessageInfo, mix_identity: IdentityKey, ) -> Result { @@ -565,12 +567,13 @@ pub(crate) fn try_delegate_to_mixnode( let sender_bytes = info.sender.as_bytes(); // write the delegation - match delegation_bucket.may_load(sender_bytes)? { - Some(existing_delegation) => { - delegation_bucket.save(sender_bytes, &(existing_delegation + info.funds[0].amount))? - } - None => delegation_bucket.save(sender_bytes, &info.funds[0].amount)?, - } + let new_amount = match delegation_bucket.may_load(sender_bytes)? { + Some(existing_delegation) => existing_delegation.amount + info.funds[0].amount, + None => info.funds[0].amount, + }; + // the block height is reset, if it existed + let new_delegation = RawDelegationData::new(new_amount, env.block.height); + delegation_bucket.save(sender_bytes, &new_delegation)?; reverse_mix_delegations(deps.storage, &info.sender).save(mix_identity.as_bytes(), &())?; @@ -593,7 +596,7 @@ pub(crate) fn try_remove_delegation_from_mixnode( // send delegated funds back to the delegation owner let messages = vec![BankMsg::Send { to_address: info.sender.to_string(), - amount: coins(delegation.u128(), DENOM), + amount: coins(delegation.amount.u128(), DENOM), } .into()]; @@ -606,7 +609,7 @@ pub(crate) fn try_remove_delegation_from_mixnode( existing_bond.total_delegation.amount = existing_bond .total_delegation .amount - .checked_sub(delegation) + .checked_sub(delegation.amount) .unwrap(); mixnodes_bucket.save(mix_identity.as_bytes(), &existing_bond)?; } @@ -627,6 +630,7 @@ pub(crate) fn try_remove_delegation_from_mixnode( pub(crate) fn try_delegate_to_gateway( deps: DepsMut, + env: Env, info: MessageInfo, gateway_identity: IdentityKey, ) -> Result { @@ -652,12 +656,13 @@ pub(crate) fn try_delegate_to_gateway( let sender_bytes = info.sender.as_bytes(); // write the delegation - match delegation_bucket.may_load(sender_bytes)? { - Some(existing_delegation) => { - delegation_bucket.save(sender_bytes, &(existing_delegation + info.funds[0].amount))? - } - None => delegation_bucket.save(sender_bytes, &info.funds[0].amount)?, - } + let new_amount = match delegation_bucket.may_load(sender_bytes)? { + Some(existing_delegation) => existing_delegation.amount + info.funds[0].amount, + None => info.funds[0].amount, + }; + // the block height is reset, if it existed + let new_delegation = RawDelegationData::new(new_amount, env.block.height); + delegation_bucket.save(sender_bytes, &new_delegation)?; reverse_gateway_delegations(deps.storage, &info.sender) .save(gateway_identity.as_bytes(), &())?; @@ -682,7 +687,7 @@ pub(crate) fn try_remove_delegation_from_gateway( // send delegated funds back to the delegation owner let messages = vec![BankMsg::Send { to_address: info.sender.to_string(), - amount: coins(delegation.u128(), DENOM), + amount: coins(delegation.amount.u128(), DENOM), } .into()]; @@ -697,7 +702,7 @@ pub(crate) fn try_remove_delegation_from_gateway( existing_bond.total_delegation.amount = existing_bond .total_delegation .amount - .checked_sub(delegation) + .checked_sub(delegation.amount) .unwrap(); gateways_bucket.save(gateway_identity.as_bytes(), &existing_bond)?; } @@ -734,7 +739,7 @@ pub mod tests { use crate::support::tests::helpers; use crate::support::tests::helpers::{ add_gateway, add_mixnode, gateway_fixture, good_gateway_bond, good_mixnode_bond, - mix_node_fixture, + mix_node_fixture, raw_delegation_fixture, }; use cosmwasm_std::testing::{mock_env, mock_info}; use cosmwasm_std::{coin, coins, from_binary, Addr, Uint128}; @@ -1802,7 +1807,7 @@ pub mod tests { .unwrap(); mix_delegations(&mut deps.storage, &node_identity) - .save(b"delegator", &Uint128(initial_delegation)) + .save(b"delegator", &raw_delegation_fixture(initial_delegation)) .unwrap(); let bond_reward_rate = read_mixnode_epoch_bond_reward_rate(deps.as_ref().storage); @@ -1901,7 +1906,7 @@ pub mod tests { .unwrap(); gateway_delegations(&mut deps.storage, &node_identity) - .save(b"delegator", &Uint128(initial_delegation)) + .save(b"delegator", &raw_delegation_fixture(initial_delegation)) .unwrap(); let bond_reward_rate = read_gateway_epoch_bond_reward_rate(deps.as_ref().storage); @@ -2027,6 +2032,7 @@ pub mod tests { }), try_delegate_to_mixnode( deps.as_mut(), + mock_env(), mock_info("sender", &coins(123, DENOM)), "non-existent-mix-identity".into() ) @@ -2043,13 +2049,14 @@ pub mod tests { let delegation = coin(123, DENOM); assert!(try_delegate_to_mixnode( deps.as_mut(), + mock_env(), mock_info(delegation_owner.as_str(), &vec![delegation.clone()]), identity.clone() ) .is_ok()); assert_eq!( - delegation.amount, + RawDelegationData::new(delegation.amount, mock_env().block.height), mix_delegations_read(&deps.storage, &identity) .load(delegation_owner.as_bytes()) .unwrap() @@ -2086,6 +2093,7 @@ pub mod tests { }), try_delegate_to_mixnode( deps.as_mut(), + mock_env(), mock_info(delegation_owner.as_str(), &coins(123, DENOM)), identity ) @@ -2105,13 +2113,14 @@ pub mod tests { assert!(try_delegate_to_mixnode( deps.as_mut(), + mock_env(), mock_info(delegation_owner.as_str(), &vec![delegation.clone()]), identity.clone() ) .is_ok()); assert_eq!( - delegation.amount, + RawDelegationData::new(delegation.amount, mock_env().block.height), mix_delegations_read(&deps.storage, &identity) .load(delegation_owner.as_bytes()) .unwrap() @@ -2144,6 +2153,7 @@ pub mod tests { try_delegate_to_mixnode( deps.as_mut(), + mock_env(), mock_info(delegation_owner.as_str(), &vec![delegation1.clone()]), identity.clone(), ) @@ -2151,13 +2161,17 @@ pub mod tests { try_delegate_to_mixnode( deps.as_mut(), + mock_env(), mock_info(delegation_owner.as_str(), &vec![delegation2.clone()]), identity.clone(), ) .unwrap(); assert_eq!( - delegation1.amount + delegation2.amount, + RawDelegationData::new( + delegation1.amount + delegation2.amount, + mock_env().block.height + ), mix_delegations_read(&deps.storage, &identity) .load(delegation_owner.as_bytes()) .unwrap() @@ -2179,6 +2193,106 @@ pub mod tests { ) } + #[test] + fn block_height_is_updated_on_new_delegation() { + let mut deps = helpers::init_contract(); + let mixnode_owner = "bob"; + let identity = add_mixnode(mixnode_owner, good_mixnode_bond(), &mut deps); + let delegation_owner = Addr::unchecked("sender"); + let delegation = coin(100, DENOM); + + let env1 = mock_env(); + let mut env2 = mock_env(); + let initial_height = env1.block.height; + let updated_height = initial_height + 42; + // second env has grown in block height + env2.block.height = updated_height; + + try_delegate_to_mixnode( + deps.as_mut(), + env1, + mock_info(delegation_owner.as_str(), &vec![delegation.clone()]), + identity.clone(), + ) + .unwrap(); + + assert_eq!( + RawDelegationData::new(delegation.amount, initial_height), + mix_delegations_read(&deps.storage, &identity) + .load(delegation_owner.as_bytes()) + .unwrap() + ); + + try_delegate_to_mixnode( + deps.as_mut(), + env2, + mock_info(delegation_owner.as_str(), &vec![delegation.clone()]), + identity.clone(), + ) + .unwrap(); + + assert_eq!( + RawDelegationData::new(delegation.amount + delegation.amount, updated_height), + mix_delegations_read(&deps.storage, &identity) + .load(delegation_owner.as_bytes()) + .unwrap() + ); + } + + #[test] + fn block_height_is_not_updated_on_different_delegator() { + let mut deps = helpers::init_contract(); + let mixnode_owner = "bob"; + let identity = add_mixnode(mixnode_owner, good_mixnode_bond(), &mut deps); + let delegation_owner1 = Addr::unchecked("sender1"); + let delegation_owner2 = Addr::unchecked("sender2"); + let delegation1 = coin(100, DENOM); + let delegation2 = coin(120, DENOM); + + let env1 = mock_env(); + let mut env2 = mock_env(); + let initial_height = env1.block.height; + let second_height = initial_height + 42; + // second env has grown in block height + env2.block.height = second_height; + + try_delegate_to_mixnode( + deps.as_mut(), + env1, + mock_info(delegation_owner1.as_str(), &vec![delegation1.clone()]), + identity.clone(), + ) + .unwrap(); + + assert_eq!( + RawDelegationData::new(delegation1.amount, initial_height), + mix_delegations_read(&deps.storage, &identity) + .load(delegation_owner1.as_bytes()) + .unwrap() + ); + + try_delegate_to_mixnode( + deps.as_mut(), + env2, + mock_info(delegation_owner2.as_str(), &vec![delegation2.clone()]), + identity.clone(), + ) + .unwrap(); + + assert_eq!( + RawDelegationData::new(delegation1.amount, initial_height), + mix_delegations_read(&deps.storage, &identity) + .load(delegation_owner1.as_bytes()) + .unwrap() + ); + assert_eq!( + RawDelegationData::new(delegation2.amount, second_height), + mix_delegations_read(&deps.storage, &identity) + .load(delegation_owner2.as_bytes()) + .unwrap() + ); + } + #[test] fn is_disallowed_for_already_delegated_node_if_it_unbonded() { let mut deps = helpers::init_contract(); @@ -2189,6 +2303,7 @@ pub mod tests { try_delegate_to_mixnode( deps.as_mut(), + mock_env(), mock_info(delegation_owner.as_str(), &coins(100, DENOM)), identity.clone(), ) @@ -2202,6 +2317,7 @@ pub mod tests { }), try_delegate_to_mixnode( deps.as_mut(), + mock_env(), mock_info(delegation_owner.as_str(), &coins(50, DENOM)), identity ) @@ -2219,6 +2335,7 @@ pub mod tests { assert!(try_delegate_to_mixnode( deps.as_mut(), + mock_env(), mock_info(delegation_owner.as_str(), &coins(123, DENOM)), identity1.clone() ) @@ -2226,17 +2343,17 @@ pub mod tests { assert!(try_delegate_to_mixnode( deps.as_mut(), + mock_env(), mock_info(delegation_owner.as_str(), &coins(42, DENOM)), identity2.clone() ) .is_ok()); assert_eq!( - 123, + RawDelegationData::new(123u128.into(), mock_env().block.height), mix_delegations_read(&deps.storage, &identity1) .load(delegation_owner.as_bytes()) .unwrap() - .u128() ); assert!( reverse_mix_delegations_read(&deps.storage, &delegation_owner) @@ -2245,11 +2362,10 @@ pub mod tests { ); assert_eq!( - 42, + RawDelegationData::new(42u128.into(), mock_env().block.height), mix_delegations_read(&deps.storage, &identity2) .load(delegation_owner.as_bytes()) .unwrap() - .u128() ); assert!( reverse_mix_delegations_read(&deps.storage, &delegation_owner) @@ -2269,6 +2385,7 @@ pub mod tests { assert!(try_delegate_to_mixnode( deps.as_mut(), + mock_env(), mock_info("sender1", &vec![delegation1.clone()]), identity.clone() ) @@ -2276,6 +2393,7 @@ pub mod tests { assert!(try_delegate_to_mixnode( deps.as_mut(), + mock_env(), mock_info("sender2", &vec![delegation2.clone()]), identity.clone() ) @@ -2302,6 +2420,7 @@ pub mod tests { try_delegate_to_mixnode( deps.as_mut(), + mock_env(), mock_info(delegation_owner.as_str(), &coins(100, DENOM)), identity.clone(), ) @@ -2310,11 +2429,10 @@ pub mod tests { try_remove_mixnode(deps.as_mut(), mock_info(mixnode_owner, &[])).unwrap(); assert_eq!( - 100, + RawDelegationData::new(100u128.into(), mock_env().block.height), mix_delegations_read(&deps.storage, &identity) .load(delegation_owner.as_bytes()) .unwrap() - .u128() ); assert!( reverse_mix_delegations_read(&deps.storage, &delegation_owner) @@ -2361,6 +2479,7 @@ pub mod tests { try_delegate_to_mixnode( deps.as_mut(), + mock_env(), mock_info(delegation_owner.as_str(), &coins(100, DENOM)), identity.clone(), ) @@ -2416,6 +2535,7 @@ pub mod tests { try_delegate_to_mixnode( deps.as_mut(), + mock_env(), mock_info(delegation_owner.as_str(), &coins(100, DENOM)), identity.clone(), ) @@ -2466,6 +2586,7 @@ pub mod tests { assert!(try_delegate_to_mixnode( deps.as_mut(), + mock_env(), mock_info(delegation_owner1.as_str(), &vec![delegation1.clone()]), identity.clone() ) @@ -2473,6 +2594,7 @@ pub mod tests { assert!(try_delegate_to_mixnode( deps.as_mut(), + mock_env(), mock_info(delegation_owner2.as_str(), &vec![delegation2.clone()]), identity.clone() ) @@ -2513,13 +2635,13 @@ pub mod tests { let identity = add_mixnode(node_owner, good_mixnode_bond(), &mut deps); mix_delegations(&mut deps.storage, &identity) - .save(b"delegator1", &Uint128(initial_delegation1)) + .save(b"delegator1", &raw_delegation_fixture(initial_delegation1)) .unwrap(); mix_delegations(&mut deps.storage, &identity) - .save(b"delegator2", &Uint128(initial_delegation2)) + .save(b"delegator2", &raw_delegation_fixture(initial_delegation2)) .unwrap(); mix_delegations(&mut deps.storage, &identity) - .save(b"delegator3", &Uint128(initial_delegation3)) + .save(b"delegator3", &raw_delegation_fixture(initial_delegation3)) .unwrap(); let bond_reward = read_mixnode_epoch_bond_reward_rate(deps.as_ref().storage); @@ -2550,6 +2672,7 @@ pub mod tests { mix_delegations_read(deps.as_ref().storage, &identity) .load("delegator1".as_bytes()) .unwrap() + .amount ); assert_eq!( @@ -2557,6 +2680,7 @@ pub mod tests { mix_delegations_read(deps.as_ref().storage, &identity) .load("delegator2".as_bytes()) .unwrap() + .amount ); assert_eq!( @@ -2564,6 +2688,7 @@ pub mod tests { mix_delegations_read(deps.as_ref().storage, &identity) .load("delegator3".as_bytes()) .unwrap() + .amount ); assert_eq!( @@ -2606,6 +2731,7 @@ pub mod tests { mix_delegations_read(deps.as_ref().storage, &identity) .load("delegator1".as_bytes()) .unwrap() + .amount ); assert_eq!( @@ -2613,6 +2739,7 @@ pub mod tests { mix_delegations_read(deps.as_ref().storage, &identity) .load("delegator2".as_bytes()) .unwrap() + .amount ); assert_eq!( @@ -2620,6 +2747,7 @@ pub mod tests { mix_delegations_read(deps.as_ref().storage, &identity) .load("delegator3".as_bytes()) .unwrap() + .amount ); assert_eq!( @@ -2649,6 +2777,7 @@ pub mod tests { mix_delegations_read(deps.as_ref().storage, &identity) .load("delegator1".as_bytes()) .unwrap() + .amount ); assert_eq!( @@ -2656,6 +2785,7 @@ pub mod tests { mix_delegations_read(deps.as_ref().storage, &identity) .load("delegator2".as_bytes()) .unwrap() + .amount ); assert_eq!( @@ -2663,6 +2793,7 @@ pub mod tests { mix_delegations_read(deps.as_ref().storage, &identity) .load("delegator3".as_bytes()) .unwrap() + .amount ); assert_eq!( @@ -2689,6 +2820,7 @@ pub mod tests { }), try_delegate_to_gateway( deps.as_mut(), + mock_env(), mock_info("sender", &coins(123, DENOM)), "non-existent-gateway-identity".into() ) @@ -2705,13 +2837,14 @@ pub mod tests { let delegation = coin(123, DENOM); assert!(try_delegate_to_gateway( deps.as_mut(), + mock_env(), mock_info(delegation_owner.as_str(), &vec![delegation.clone()]), identity.clone() ) .is_ok()); assert_eq!( - delegation.amount, + RawDelegationData::new(delegation.amount, mock_env().block.height), gateway_delegations_read(&deps.storage, &identity) .load(delegation_owner.as_bytes()) .unwrap() @@ -2748,6 +2881,7 @@ pub mod tests { }), try_delegate_to_gateway( deps.as_mut(), + mock_env(), mock_info(delegation_owner.as_str(), &coins(123, DENOM)), identity ) @@ -2767,13 +2901,14 @@ pub mod tests { assert!(try_delegate_to_gateway( deps.as_mut(), + mock_env(), mock_info(delegation_owner.as_str(), &vec![delegation.clone()]), identity.clone() ) .is_ok()); assert_eq!( - delegation.amount, + RawDelegationData::new(delegation.amount, mock_env().block.height), gateway_delegations_read(&deps.storage, &identity) .load(delegation_owner.as_bytes()) .unwrap() @@ -2806,6 +2941,7 @@ pub mod tests { try_delegate_to_gateway( deps.as_mut(), + mock_env(), mock_info(delegation_owner.as_str(), &vec![delegation1.clone()]), identity.clone(), ) @@ -2813,13 +2949,17 @@ pub mod tests { try_delegate_to_gateway( deps.as_mut(), + mock_env(), mock_info(delegation_owner.as_str(), &vec![delegation2.clone()]), identity.clone(), ) .unwrap(); assert_eq!( - delegation1.amount + delegation2.amount, + RawDelegationData::new( + delegation1.amount + delegation2.amount, + mock_env().block.height + ), gateway_delegations_read(&deps.storage, &identity) .load(delegation_owner.as_bytes()) .unwrap() @@ -2841,6 +2981,106 @@ pub mod tests { ) } + #[test] + fn block_height_is_updated_on_new_delegation() { + let mut deps = helpers::init_contract(); + let gateway_owner = "bob"; + let identity = add_gateway(gateway_owner, good_gateway_bond(), &mut deps); + let delegation_owner = Addr::unchecked("sender"); + let delegation = coin(100, DENOM); + + let env1 = mock_env(); + let mut env2 = mock_env(); + let initial_height = env1.block.height; + let updated_height = initial_height + 42; + // second env has grown in block height + env2.block.height = updated_height; + + try_delegate_to_gateway( + deps.as_mut(), + env1, + mock_info(delegation_owner.as_str(), &vec![delegation.clone()]), + identity.clone(), + ) + .unwrap(); + + assert_eq!( + RawDelegationData::new(delegation.amount, initial_height), + gateway_delegations_read(&deps.storage, &identity) + .load(delegation_owner.as_bytes()) + .unwrap() + ); + + try_delegate_to_gateway( + deps.as_mut(), + env2, + mock_info(delegation_owner.as_str(), &vec![delegation.clone()]), + identity.clone(), + ) + .unwrap(); + + assert_eq!( + RawDelegationData::new(delegation.amount + delegation.amount, updated_height), + gateway_delegations_read(&deps.storage, &identity) + .load(delegation_owner.as_bytes()) + .unwrap() + ); + } + + #[test] + fn block_height_is_not_updated_on_different_delegator() { + let mut deps = helpers::init_contract(); + let gateway_owner = "bob"; + let identity = add_gateway(gateway_owner, good_gateway_bond(), &mut deps); + let delegation_owner1 = Addr::unchecked("sender1"); + let delegation_owner2 = Addr::unchecked("sender2"); + let delegation1 = coin(100, DENOM); + let delegation2 = coin(120, DENOM); + + let env1 = mock_env(); + let mut env2 = mock_env(); + let initial_height = env1.block.height; + let second_height = initial_height + 42; + // second env has grown in block height + env2.block.height = second_height; + + try_delegate_to_gateway( + deps.as_mut(), + env1, + mock_info(delegation_owner1.as_str(), &vec![delegation1.clone()]), + identity.clone(), + ) + .unwrap(); + + assert_eq!( + RawDelegationData::new(delegation1.amount, initial_height), + gateway_delegations_read(&deps.storage, &identity) + .load(delegation_owner1.as_bytes()) + .unwrap() + ); + + try_delegate_to_gateway( + deps.as_mut(), + env2, + mock_info(delegation_owner2.as_str(), &vec![delegation2.clone()]), + identity.clone(), + ) + .unwrap(); + + assert_eq!( + RawDelegationData::new(delegation1.amount, initial_height), + gateway_delegations_read(&deps.storage, &identity) + .load(delegation_owner1.as_bytes()) + .unwrap() + ); + assert_eq!( + RawDelegationData::new(delegation2.amount, second_height), + gateway_delegations_read(&deps.storage, &identity) + .load(delegation_owner2.as_bytes()) + .unwrap() + ); + } + #[test] fn is_disallowed_for_already_delegated_node_if_it_unbonded() { let mut deps = helpers::init_contract(); @@ -2851,6 +3091,7 @@ pub mod tests { try_delegate_to_gateway( deps.as_mut(), + mock_env(), mock_info(delegation_owner.as_str(), &coins(100, DENOM)), identity.clone(), ) @@ -2864,6 +3105,7 @@ pub mod tests { }), try_delegate_to_gateway( deps.as_mut(), + mock_env(), mock_info(delegation_owner.as_str(), &coins(50, DENOM)), identity.clone() ) @@ -2881,6 +3123,7 @@ pub mod tests { assert!(try_delegate_to_gateway( deps.as_mut(), + mock_env(), mock_info(delegation_owner.as_str(), &coins(123, DENOM)), identity1.clone() ) @@ -2888,17 +3131,17 @@ pub mod tests { assert!(try_delegate_to_gateway( deps.as_mut(), + mock_env(), mock_info(delegation_owner.as_str(), &coins(42, DENOM)), identity2.clone() ) .is_ok()); assert_eq!( - 123, + RawDelegationData::new(123u128.into(), mock_env().block.height), gateway_delegations_read(&deps.storage, &identity1) .load(delegation_owner.as_bytes()) .unwrap() - .u128() ); assert!( reverse_gateway_delegations_read(&deps.storage, &delegation_owner) @@ -2907,11 +3150,10 @@ pub mod tests { ); assert_eq!( - 42, + RawDelegationData::new(42u128.into(), mock_env().block.height), gateway_delegations_read(&deps.storage, &identity2) .load(delegation_owner.as_bytes()) .unwrap() - .u128() ); assert!( reverse_gateway_delegations_read(&deps.storage, &delegation_owner) @@ -2931,6 +3173,7 @@ pub mod tests { assert!(try_delegate_to_gateway( deps.as_mut(), + mock_env(), mock_info("sender1", &vec![delegation1.clone()]), identity.clone() ) @@ -2938,6 +3181,7 @@ pub mod tests { assert!(try_delegate_to_gateway( deps.as_mut(), + mock_env(), mock_info("sender2", &vec![delegation2.clone()]), identity.clone() ) @@ -2964,6 +3208,7 @@ pub mod tests { try_delegate_to_gateway( deps.as_mut(), + mock_env(), mock_info(delegation_owner.as_str(), &coins(100, DENOM)), identity.clone(), ) @@ -2972,11 +3217,10 @@ pub mod tests { try_remove_gateway(deps.as_mut(), mock_info(gateway_owner, &[])).unwrap(); assert_eq!( - 100, + RawDelegationData::new(100u128.into(), mock_env().block.height), gateway_delegations_read(&deps.storage, &identity) .load(delegation_owner.as_bytes()) .unwrap() - .u128() ); assert!( reverse_gateway_delegations_read(&deps.storage, &delegation_owner) @@ -3023,6 +3267,7 @@ pub mod tests { try_delegate_to_gateway( deps.as_mut(), + mock_env(), mock_info(delegation_owner.as_str(), &coins(100, DENOM)), identity.clone(), ) @@ -3078,6 +3323,7 @@ pub mod tests { try_delegate_to_gateway( deps.as_mut(), + mock_env(), mock_info(delegation_owner.as_str(), &coins(100, DENOM)), identity.clone(), ) @@ -3128,6 +3374,7 @@ pub mod tests { assert!(try_delegate_to_gateway( deps.as_mut(), + mock_env(), mock_info(delegation_owner1.as_str(), &vec![delegation1.clone()]), identity.clone() ) @@ -3135,6 +3382,7 @@ pub mod tests { assert!(try_delegate_to_gateway( deps.as_mut(), + mock_env(), mock_info(delegation_owner2.as_str(), &vec![delegation2.clone()]), identity.clone() ) @@ -3175,13 +3423,13 @@ pub mod tests { let identity = add_gateway(node_owner, good_gateway_bond(), &mut deps); gateway_delegations(&mut deps.storage, &identity) - .save(b"delegator1", &Uint128(initial_delegation1)) + .save(b"delegator1", &raw_delegation_fixture(initial_delegation1)) .unwrap(); gateway_delegations(&mut deps.storage, &identity) - .save(b"delegator2", &Uint128(initial_delegation2)) + .save(b"delegator2", &raw_delegation_fixture(initial_delegation2)) .unwrap(); gateway_delegations(&mut deps.storage, &identity) - .save(b"delegator3", &Uint128(initial_delegation3)) + .save(b"delegator3", &raw_delegation_fixture(initial_delegation3)) .unwrap(); let bond_reward = read_gateway_epoch_bond_reward_rate(deps.as_ref().storage); @@ -3212,6 +3460,7 @@ pub mod tests { gateway_delegations_read(deps.as_ref().storage, &identity) .load("delegator1".as_bytes()) .unwrap() + .amount ); assert_eq!( @@ -3219,6 +3468,7 @@ pub mod tests { gateway_delegations_read(deps.as_ref().storage, &identity) .load("delegator2".as_bytes()) .unwrap() + .amount ); assert_eq!( @@ -3226,6 +3476,7 @@ pub mod tests { gateway_delegations_read(deps.as_ref().storage, &identity) .load("delegator3".as_bytes()) .unwrap() + .amount ); assert_eq!( @@ -3268,6 +3519,7 @@ pub mod tests { gateway_delegations_read(deps.as_ref().storage, &identity) .load("delegator1".as_bytes()) .unwrap() + .amount ); assert_eq!( @@ -3275,6 +3527,7 @@ pub mod tests { gateway_delegations_read(deps.as_ref().storage, &identity) .load("delegator2".as_bytes()) .unwrap() + .amount ); assert_eq!( @@ -3282,6 +3535,7 @@ pub mod tests { gateway_delegations_read(deps.as_ref().storage, &identity) .load("delegator3".as_bytes()) .unwrap() + .amount ); assert_eq!( @@ -3311,6 +3565,7 @@ pub mod tests { gateway_delegations_read(deps.as_ref().storage, &identity) .load("delegator1".as_bytes()) .unwrap() + .amount ); assert_eq!( @@ -3318,6 +3573,7 @@ pub mod tests { gateway_delegations_read(deps.as_ref().storage, &identity) .load("delegator2".as_bytes()) .unwrap() + .amount ); assert_eq!( @@ -3325,6 +3581,7 @@ pub mod tests { gateway_delegations_read(deps.as_ref().storage, &identity) .load("delegator3".as_bytes()) .unwrap() + .amount ); assert_eq!( @@ -3373,7 +3630,7 @@ pub mod tests { let mut write_bucket = mix_delegations(&mut deps.storage, &node_identity); for i in 1..=total_delegations { let delegator = Addr::unchecked(format!("delegator{}", i)); - let delegation = Uint128(i as u128); + let delegation = raw_delegation_fixture(i as u128); write_bucket .save(delegator.as_bytes(), &delegation) .unwrap();