additional unit tests for compatibility-based txs + bug fixes
This commit is contained in:
+18
-14
@@ -886,50 +886,54 @@ mod tests {
|
||||
MixnetQueryMsg::GetSigningNonce { address } => {
|
||||
client.get_signing_nonce(&address.parse().unwrap()).ignore()
|
||||
}
|
||||
QueryMsg::GetPreassignedGatewayIds { start_after, limit } => client
|
||||
MixnetQueryMsg::GetPreassignedGatewayIds { start_after, limit } => client
|
||||
.get_preassigned_gateway_ids_paged(start_after, limit)
|
||||
.ignore(),
|
||||
QueryMsg::GetNymNodeBondsPaged { limit, start_after } => {
|
||||
MixnetQueryMsg::GetNymNodeBondsPaged { limit, start_after } => {
|
||||
client.get_nymnode_bonds_paged(limit, start_after).ignore()
|
||||
}
|
||||
QueryMsg::GetNymNodesDetailedPaged { limit, start_after } => client
|
||||
MixnetQueryMsg::GetNymNodesDetailedPaged { limit, start_after } => client
|
||||
.get_nymnodes_detailed_paged(limit, start_after)
|
||||
.ignore(),
|
||||
QueryMsg::GetUnbondedNymNode { node_id } => {
|
||||
MixnetQueryMsg::GetUnbondedNymNode { node_id } => {
|
||||
client.get_unbonded_nymnode_information(node_id).ignore()
|
||||
}
|
||||
QueryMsg::GetUnbondedNymNodesPaged { limit, start_after } => client
|
||||
MixnetQueryMsg::GetUnbondedNymNodesPaged { limit, start_after } => client
|
||||
.get_unbonded_nymnodes_paged(limit, start_after)
|
||||
.ignore(),
|
||||
QueryMsg::GetUnbondedNymNodesByOwnerPaged {
|
||||
MixnetQueryMsg::GetUnbondedNymNodesByOwnerPaged {
|
||||
owner,
|
||||
limit,
|
||||
start_after,
|
||||
} => client
|
||||
.get_unbonded_nymnodes_by_owner_paged(&owner.parse().unwrap(), limit, start_after)
|
||||
.ignore(),
|
||||
QueryMsg::GetUnbondedNymNodesByIdentityKeyPaged {
|
||||
MixnetQueryMsg::GetUnbondedNymNodesByIdentityKeyPaged {
|
||||
identity_key,
|
||||
limit,
|
||||
start_after,
|
||||
} => client
|
||||
.get_unbonded_nymnodes_by_identity_paged(&identity_key, limit, start_after)
|
||||
.ignore(),
|
||||
QueryMsg::GetOwnedNymNode { address } => {
|
||||
MixnetQueryMsg::GetOwnedNymNode { address } => {
|
||||
client.get_owned_nymnode(&address.parse().unwrap()).ignore()
|
||||
}
|
||||
QueryMsg::GetNymNodeDetails { node_id } => client.get_nymnode_details(node_id).ignore(),
|
||||
QueryMsg::GetNymNodeDetailsByIdentityKey { node_identity } => client
|
||||
MixnetQueryMsg::GetNymNodeDetails { node_id } => {
|
||||
client.get_nymnode_details(node_id).ignore()
|
||||
}
|
||||
MixnetQueryMsg::GetNymNodeDetailsByIdentityKey { node_identity } => client
|
||||
.get_nymnode_details_by_identity(node_identity)
|
||||
.ignore(),
|
||||
QueryMsg::GetNodeRewardingDetails { node_id } => {
|
||||
MixnetQueryMsg::GetNodeRewardingDetails { node_id } => {
|
||||
client.get_nymnode_rewarding_details(node_id).ignore()
|
||||
}
|
||||
QueryMsg::GetNodeStakeSaturation { node_id } => {
|
||||
MixnetQueryMsg::GetNodeStakeSaturation { node_id } => {
|
||||
client.get_node_stake_saturation(node_id).ignore()
|
||||
}
|
||||
QueryMsg::GetRoleAssignment { role } => client.get_role_assignment(role).ignore(),
|
||||
QueryMsg::GetRewardedSetMetadata {} => client.get_rewarded_set_metadata().ignore(),
|
||||
MixnetQueryMsg::GetRoleAssignment { role } => client.get_role_assignment(role).ignore(),
|
||||
MixnetQueryMsg::GetRewardedSetMetadata {} => {
|
||||
client.get_rewarded_set_metadata().ignore()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -672,6 +672,7 @@ pub enum QueryMsg {
|
||||
// delegation-related:
|
||||
/// Gets all delegations associated with particular node
|
||||
#[cfg_attr(feature = "schema", returns(PagedNodeDelegationsResponse))]
|
||||
#[serde(alias = "GetMixnodeDelegations", alias = "get_mixnode_delegations")]
|
||||
GetNodeDelegations {
|
||||
/// Id of the node to query.
|
||||
#[serde(alias = "mix_id")]
|
||||
|
||||
@@ -166,6 +166,10 @@ impl<T> RangedValue<T>
|
||||
where
|
||||
T: Copy + PartialOrd + PartialEq,
|
||||
{
|
||||
pub fn new(minimum: T, maximum: T) -> Self {
|
||||
RangedValue { minimum, maximum }
|
||||
}
|
||||
|
||||
pub fn normalise(&self, value: T) -> T {
|
||||
if value < self.minimum {
|
||||
self.minimum
|
||||
|
||||
@@ -142,3 +142,436 @@ pub fn may_get_bond(
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use anyhow::bail;
|
||||
|
||||
#[cfg(test)]
|
||||
mod reward_withdrawing_permission {
|
||||
use super::*;
|
||||
use crate::support::tests::test_helpers::TestSetup;
|
||||
|
||||
#[test]
|
||||
fn for_legacy_mixnode() -> anyhow::Result<()> {
|
||||
let mut test = TestSetup::new();
|
||||
let node_id = test.add_legacy_mixnode("owner", None);
|
||||
let details = test.mixnode_by_id(node_id).unwrap();
|
||||
|
||||
// node must not be in the process of unbonding
|
||||
assert!(ensure_can_withdraw_rewards(&details).is_ok());
|
||||
|
||||
test.start_unbonding_mixnode(node_id);
|
||||
let details = test.mixnode_by_id(node_id).unwrap();
|
||||
let res = ensure_can_withdraw_rewards(&details).unwrap_err();
|
||||
assert_eq!(res, MixnetContractError::NodeIsUnbonding { node_id });
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn for_nymnode() -> anyhow::Result<()> {
|
||||
let mut test = TestSetup::new();
|
||||
let node_id = test.add_dummy_nymnode("owner", None);
|
||||
let details = test.nymnode_by_id(node_id).unwrap();
|
||||
|
||||
// node must not be in the process of unbonding
|
||||
assert!(ensure_can_withdraw_rewards(&details).is_ok());
|
||||
|
||||
test.start_unbonding_nymnode(node_id);
|
||||
let details = test.nymnode_by_id(node_id).unwrap();
|
||||
let res = ensure_can_withdraw_rewards(&details).unwrap_err();
|
||||
assert_eq!(res, MixnetContractError::NodeIsUnbonding { node_id });
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod modifying_cost_params_permission {
|
||||
use super::*;
|
||||
use crate::support::tests::test_helpers::TestSetup;
|
||||
|
||||
#[test]
|
||||
fn for_legacy_mixnode() -> anyhow::Result<()> {
|
||||
let mut test = TestSetup::new();
|
||||
let node_id = test.add_legacy_mixnode("owner", None);
|
||||
|
||||
let details = test.mixnode_by_id(node_id).unwrap();
|
||||
assert!(ensure_can_modify_cost_params(test.deps().storage, &details).is_ok());
|
||||
|
||||
// epoch must not be mid-transition
|
||||
test.skip_to_current_epoch_end();
|
||||
test.start_epoch_transition();
|
||||
let details = test.mixnode_by_id(node_id).unwrap();
|
||||
let res = ensure_can_modify_cost_params(test.deps().storage, &details).unwrap_err();
|
||||
assert!(matches!(
|
||||
res,
|
||||
MixnetContractError::EpochAdvancementInProgress { .. }
|
||||
));
|
||||
test.set_epoch_in_progress_state();
|
||||
|
||||
// node must not be in the process of unbonding
|
||||
test.start_unbonding_mixnode(node_id);
|
||||
let details = test.mixnode_by_id(node_id).unwrap();
|
||||
let res = ensure_can_modify_cost_params(test.deps().storage, &details).unwrap_err();
|
||||
assert_eq!(res, MixnetContractError::NodeIsUnbonding { node_id });
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn for_nymnode() -> anyhow::Result<()> {
|
||||
let mut test = TestSetup::new();
|
||||
let node_id = test.add_dummy_nymnode("owner", None);
|
||||
|
||||
let details = test.nymnode_by_id(node_id).unwrap();
|
||||
assert!(ensure_can_modify_cost_params(test.deps().storage, &details).is_ok());
|
||||
|
||||
// epoch must not be mid-transition
|
||||
test.skip_to_current_epoch_end();
|
||||
test.start_epoch_transition();
|
||||
let details = test.nymnode_by_id(node_id).unwrap();
|
||||
let res = ensure_can_modify_cost_params(test.deps().storage, &details).unwrap_err();
|
||||
assert!(matches!(
|
||||
res,
|
||||
MixnetContractError::EpochAdvancementInProgress { .. }
|
||||
));
|
||||
test.set_epoch_in_progress_state();
|
||||
|
||||
// node must not be in the process of unbonding
|
||||
test.start_unbonding_nymnode(node_id);
|
||||
let details = test.nymnode_by_id(node_id).unwrap();
|
||||
let res = ensure_can_modify_cost_params(test.deps().storage, &details).unwrap_err();
|
||||
assert_eq!(res, MixnetContractError::NodeIsUnbonding { node_id });
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod increasing_pledge_permission {
|
||||
use super::*;
|
||||
use crate::compat::transactions::{try_decrease_pledge, try_increase_pledge};
|
||||
use crate::support::tests::test_helpers::TestSetup;
|
||||
use cosmwasm_std::testing::mock_info;
|
||||
|
||||
#[test]
|
||||
fn for_legacy_mixnode() -> anyhow::Result<()> {
|
||||
let mut test = TestSetup::new();
|
||||
let node_id = test.add_legacy_mixnode("owner", None);
|
||||
|
||||
let details = test.mixnode_by_id(node_id).unwrap();
|
||||
assert!(ensure_can_increase_pledge(test.deps().storage, &details).is_ok());
|
||||
|
||||
// epoch must not be mid-transition
|
||||
test.skip_to_current_epoch_end();
|
||||
test.start_epoch_transition();
|
||||
let details = test.mixnode_by_id(node_id).unwrap();
|
||||
let res = ensure_can_increase_pledge(test.deps().storage, &details).unwrap_err();
|
||||
assert!(matches!(
|
||||
res,
|
||||
MixnetContractError::EpochAdvancementInProgress { .. }
|
||||
));
|
||||
test.set_epoch_in_progress_state();
|
||||
|
||||
// node must not be in the process of unbonding
|
||||
test.start_unbonding_mixnode(node_id);
|
||||
let details = test.mixnode_by_id(node_id).unwrap();
|
||||
let res = ensure_can_increase_pledge(test.deps().storage, &details).unwrap_err();
|
||||
assert_eq!(res, MixnetContractError::NodeIsUnbonding { node_id });
|
||||
|
||||
// node can't have any pending pledge changes:
|
||||
// - increase
|
||||
let node_id = test.add_legacy_mixnode("owner2", Some(100_000_000_000u128.into()));
|
||||
let pledge_change = test.coin(100000);
|
||||
test.execute_fn(try_increase_pledge, mock_info("owner2", &[pledge_change]))?;
|
||||
let details = test.mixnode_by_id(node_id).unwrap();
|
||||
let res = ensure_can_increase_pledge(test.deps().storage, &details).unwrap_err();
|
||||
assert_eq!(
|
||||
res,
|
||||
MixnetContractError::PendingPledgeChange {
|
||||
pending_event_id: details.pending_changes.pledge_change.unwrap()
|
||||
}
|
||||
);
|
||||
|
||||
// - decrease
|
||||
let node_id = test.add_legacy_mixnode("owner3", Some(100_000_000_000u128.into()));
|
||||
let pledge_change = test.coin(100000);
|
||||
let env = test.env();
|
||||
try_decrease_pledge(
|
||||
test.deps_mut(),
|
||||
env,
|
||||
mock_info("owner3", &[]),
|
||||
pledge_change,
|
||||
)?;
|
||||
let details = test.mixnode_by_id(node_id).unwrap();
|
||||
let res = ensure_can_increase_pledge(test.deps().storage, &details).unwrap_err();
|
||||
assert_eq!(
|
||||
res,
|
||||
MixnetContractError::PendingPledgeChange {
|
||||
pending_event_id: details.pending_changes.pledge_change.unwrap()
|
||||
}
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn for_nymnode() -> anyhow::Result<()> {
|
||||
let mut test = TestSetup::new();
|
||||
let node_id = test.add_dummy_nymnode("owner", None);
|
||||
|
||||
let details = test.nymnode_by_id(node_id).unwrap();
|
||||
assert!(ensure_can_increase_pledge(test.deps().storage, &details).is_ok());
|
||||
|
||||
// epoch must not be mid-transition
|
||||
test.skip_to_current_epoch_end();
|
||||
test.start_epoch_transition();
|
||||
let details = test.nymnode_by_id(node_id).unwrap();
|
||||
let res = ensure_can_increase_pledge(test.deps().storage, &details).unwrap_err();
|
||||
assert!(matches!(
|
||||
res,
|
||||
MixnetContractError::EpochAdvancementInProgress { .. }
|
||||
));
|
||||
test.set_epoch_in_progress_state();
|
||||
|
||||
// node must not be in the process of unbonding
|
||||
test.start_unbonding_nymnode(node_id);
|
||||
let details = test.nymnode_by_id(node_id).unwrap();
|
||||
let res = ensure_can_increase_pledge(test.deps().storage, &details).unwrap_err();
|
||||
assert_eq!(res, MixnetContractError::NodeIsUnbonding { node_id });
|
||||
|
||||
// node can't have any pending pledge changes:
|
||||
// - increase
|
||||
let node_id = test.add_dummy_nymnode("owner2", Some(100_000_000_000u128.into()));
|
||||
let pledge_change = test.coin(100000);
|
||||
test.execute_fn(try_increase_pledge, mock_info("owner2", &[pledge_change]))?;
|
||||
let details = test.nymnode_by_id(node_id).unwrap();
|
||||
let res = ensure_can_increase_pledge(test.deps().storage, &details).unwrap_err();
|
||||
assert_eq!(
|
||||
res,
|
||||
MixnetContractError::PendingPledgeChange {
|
||||
pending_event_id: details.pending_changes.pledge_change.unwrap()
|
||||
}
|
||||
);
|
||||
|
||||
// - decrease
|
||||
let node_id = test.add_dummy_nymnode("owner3", Some(100_000_000_000u128.into()));
|
||||
let pledge_change = test.coin(100000);
|
||||
let env = test.env();
|
||||
try_decrease_pledge(
|
||||
test.deps_mut(),
|
||||
env,
|
||||
mock_info("owner3", &[]),
|
||||
pledge_change,
|
||||
)?;
|
||||
let details = test.nymnode_by_id(node_id).unwrap();
|
||||
let res = ensure_can_increase_pledge(test.deps().storage, &details).unwrap_err();
|
||||
assert_eq!(
|
||||
res,
|
||||
MixnetContractError::PendingPledgeChange {
|
||||
pending_event_id: details.pending_changes.pledge_change.unwrap()
|
||||
}
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod decreasing_pledge_permission {
|
||||
use super::*;
|
||||
use crate::compat::transactions::{try_decrease_pledge, try_increase_pledge};
|
||||
use crate::support::tests::test_helpers::TestSetup;
|
||||
use cosmwasm_std::coin;
|
||||
use cosmwasm_std::testing::mock_info;
|
||||
|
||||
#[test]
|
||||
fn for_legacy_mixnode() -> anyhow::Result<()> {
|
||||
let mut test = TestSetup::new();
|
||||
let node_id = test.add_legacy_mixnode("owner", Some(100_000_000_000u128.into()));
|
||||
let valid_decrease = test.coin(100);
|
||||
|
||||
let details = test.mixnode_by_id(node_id).unwrap();
|
||||
assert!(
|
||||
ensure_can_decrease_pledge(test.deps().storage, &details, &valid_decrease).is_ok()
|
||||
);
|
||||
|
||||
// epoch must not be mid-transition
|
||||
test.skip_to_current_epoch_end();
|
||||
test.start_epoch_transition();
|
||||
let details = test.mixnode_by_id(node_id).unwrap();
|
||||
let res = ensure_can_decrease_pledge(test.deps().storage, &details, &valid_decrease)
|
||||
.unwrap_err();
|
||||
assert!(matches!(
|
||||
res,
|
||||
MixnetContractError::EpochAdvancementInProgress { .. }
|
||||
));
|
||||
test.set_epoch_in_progress_state();
|
||||
|
||||
// node must not be in the process of unbonding
|
||||
test.start_unbonding_mixnode(node_id);
|
||||
let details = test.mixnode_by_id(node_id).unwrap();
|
||||
let res = ensure_can_decrease_pledge(test.deps().storage, &details, &valid_decrease)
|
||||
.unwrap_err();
|
||||
assert_eq!(res, MixnetContractError::NodeIsUnbonding { node_id });
|
||||
|
||||
// node can't have any pending pledge changes:
|
||||
// - increase
|
||||
let node_id = test.add_legacy_mixnode("owner2", Some(100_000_000_000u128.into()));
|
||||
let pledge_change = test.coin(100000);
|
||||
test.execute_fn(try_increase_pledge, mock_info("owner2", &[pledge_change]))?;
|
||||
let details = test.mixnode_by_id(node_id).unwrap();
|
||||
let res = ensure_can_decrease_pledge(test.deps().storage, &details, &valid_decrease)
|
||||
.unwrap_err();
|
||||
assert_eq!(
|
||||
res,
|
||||
MixnetContractError::PendingPledgeChange {
|
||||
pending_event_id: details.pending_changes.pledge_change.unwrap()
|
||||
}
|
||||
);
|
||||
|
||||
// - decrease
|
||||
let node_id = test.add_legacy_mixnode("owner3", Some(100_000_000_000u128.into()));
|
||||
let pledge_change = test.coin(100000);
|
||||
let env = test.env();
|
||||
try_decrease_pledge(
|
||||
test.deps_mut(),
|
||||
env,
|
||||
mock_info("owner3", &[]),
|
||||
pledge_change,
|
||||
)?;
|
||||
let details = test.mixnode_by_id(node_id).unwrap();
|
||||
let res = ensure_can_decrease_pledge(test.deps().storage, &details, &valid_decrease)
|
||||
.unwrap_err();
|
||||
assert_eq!(
|
||||
res,
|
||||
MixnetContractError::PendingPledgeChange {
|
||||
pending_event_id: details.pending_changes.pledge_change.unwrap()
|
||||
}
|
||||
);
|
||||
|
||||
// denom must match
|
||||
let node_id = test.add_legacy_mixnode("owner4", Some(100_000_000_000u128.into()));
|
||||
let details = test.mixnode_by_id(node_id).unwrap();
|
||||
let bad_decrease = coin(123, "weird-denom");
|
||||
let res = ensure_can_decrease_pledge(test.deps().storage, &details, &bad_decrease)
|
||||
.unwrap_err();
|
||||
assert!(matches!(res, MixnetContractError::WrongDenom { .. }));
|
||||
|
||||
// value must be non-zero
|
||||
let node_id = test.add_legacy_mixnode("owner5", Some(100_000_000_000u128.into()));
|
||||
let details = test.mixnode_by_id(node_id).unwrap();
|
||||
let bad_decrease = test.coin(0);
|
||||
let res = ensure_can_decrease_pledge(test.deps().storage, &details, &bad_decrease)
|
||||
.unwrap_err();
|
||||
assert_eq!(res, MixnetContractError::ZeroCoinAmount);
|
||||
|
||||
// new pledge must be bigger than minimum
|
||||
let node_id = test.add_legacy_mixnode("owner6", Some(100_000_100u128.into()));
|
||||
let details = test.mixnode_by_id(node_id).unwrap();
|
||||
let bad_decrease = test.coin(101);
|
||||
let res = ensure_can_decrease_pledge(test.deps().storage, &details, &bad_decrease)
|
||||
.unwrap_err();
|
||||
assert!(matches!(
|
||||
res,
|
||||
MixnetContractError::InvalidPledgeReduction { .. }
|
||||
));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn for_nymnode() -> anyhow::Result<()> {
|
||||
let mut test = TestSetup::new();
|
||||
let node_id = test.add_dummy_nymnode("owner", Some(100_000_000_000u128.into()));
|
||||
let valid_decrease = test.coin(100);
|
||||
|
||||
let details = test.nymnode_by_id(node_id).unwrap();
|
||||
assert!(
|
||||
ensure_can_decrease_pledge(test.deps().storage, &details, &valid_decrease).is_ok()
|
||||
);
|
||||
|
||||
// epoch must not be mid-transition
|
||||
test.skip_to_current_epoch_end();
|
||||
test.start_epoch_transition();
|
||||
let details = test.nymnode_by_id(node_id).unwrap();
|
||||
let res = ensure_can_decrease_pledge(test.deps().storage, &details, &valid_decrease)
|
||||
.unwrap_err();
|
||||
assert!(matches!(
|
||||
res,
|
||||
MixnetContractError::EpochAdvancementInProgress { .. }
|
||||
));
|
||||
test.set_epoch_in_progress_state();
|
||||
|
||||
// node must not be in the process of unbonding
|
||||
test.start_unbonding_nymnode(node_id);
|
||||
let details = test.nymnode_by_id(node_id).unwrap();
|
||||
let res = ensure_can_decrease_pledge(test.deps().storage, &details, &valid_decrease)
|
||||
.unwrap_err();
|
||||
assert_eq!(res, MixnetContractError::NodeIsUnbonding { node_id });
|
||||
|
||||
// node can't have any pending pledge changes:
|
||||
// - increase
|
||||
let node_id = test.add_dummy_nymnode("owner2", Some(100_000_000_000u128.into()));
|
||||
let pledge_change = test.coin(100000);
|
||||
test.execute_fn(try_increase_pledge, mock_info("owner2", &[pledge_change]))?;
|
||||
let details = test.nymnode_by_id(node_id).unwrap();
|
||||
let res = ensure_can_decrease_pledge(test.deps().storage, &details, &valid_decrease)
|
||||
.unwrap_err();
|
||||
assert_eq!(
|
||||
res,
|
||||
MixnetContractError::PendingPledgeChange {
|
||||
pending_event_id: details.pending_changes.pledge_change.unwrap()
|
||||
}
|
||||
);
|
||||
|
||||
// - decrease
|
||||
let node_id = test.add_dummy_nymnode("owner3", Some(100_000_000_000u128.into()));
|
||||
let pledge_change = test.coin(100000);
|
||||
let env = test.env();
|
||||
try_decrease_pledge(
|
||||
test.deps_mut(),
|
||||
env,
|
||||
mock_info("owner3", &[]),
|
||||
pledge_change,
|
||||
)?;
|
||||
let details = test.nymnode_by_id(node_id).unwrap();
|
||||
let res = ensure_can_decrease_pledge(test.deps().storage, &details, &valid_decrease)
|
||||
.unwrap_err();
|
||||
assert_eq!(
|
||||
res,
|
||||
MixnetContractError::PendingPledgeChange {
|
||||
pending_event_id: details.pending_changes.pledge_change.unwrap()
|
||||
}
|
||||
);
|
||||
|
||||
// denom must match
|
||||
let node_id = test.add_dummy_nymnode("owner4", Some(100_000_000_000u128.into()));
|
||||
let details = test.nymnode_by_id(node_id).unwrap();
|
||||
let bad_decrease = coin(123, "weird-denom");
|
||||
let res = ensure_can_decrease_pledge(test.deps().storage, &details, &bad_decrease)
|
||||
.unwrap_err();
|
||||
assert!(matches!(res, MixnetContractError::WrongDenom { .. }));
|
||||
|
||||
// value must be non-zero
|
||||
let node_id = test.add_dummy_nymnode("owner5", Some(100_000_000_000u128.into()));
|
||||
let details = test.nymnode_by_id(node_id).unwrap();
|
||||
let bad_decrease = test.coin(0);
|
||||
let res = ensure_can_decrease_pledge(test.deps().storage, &details, &bad_decrease)
|
||||
.unwrap_err();
|
||||
assert_eq!(res, MixnetContractError::ZeroCoinAmount);
|
||||
|
||||
// new pledge must be bigger than minimum
|
||||
let node_id = test.add_dummy_nymnode("owner6", Some(100_000_100u128.into()));
|
||||
let details = test.nymnode_by_id(node_id).unwrap();
|
||||
let bad_decrease = test.coin(101);
|
||||
let res = ensure_can_decrease_pledge(test.deps().storage, &details, &bad_decrease)
|
||||
.unwrap_err();
|
||||
assert!(matches!(
|
||||
res,
|
||||
MixnetContractError::InvalidPledgeReduction { .. }
|
||||
));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,3 +93,571 @@ pub(crate) fn try_withdraw_operator_reward(
|
||||
Err(MixnetContractError::NoAssociatedNodeBond { owner: info.sender })
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[cfg(test)]
|
||||
mod increasing_pledge {
|
||||
use super::*;
|
||||
use crate::support::tests::test_helpers::TestSetup;
|
||||
use cosmwasm_std::testing::mock_info;
|
||||
use cosmwasm_std::Addr;
|
||||
|
||||
#[test]
|
||||
fn when_there_are_no_nodes() -> anyhow::Result<()> {
|
||||
let mut test = TestSetup::new();
|
||||
|
||||
let sender = mock_info("owner", &[test.coin(100000)]);
|
||||
let err = test.execute_fn(try_increase_pledge, sender).unwrap_err();
|
||||
|
||||
assert_eq!(
|
||||
MixnetContractError::NoAssociatedNodeBond {
|
||||
owner: Addr::unchecked("owner"),
|
||||
},
|
||||
err
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn for_legacy_mixnode() -> anyhow::Result<()> {
|
||||
let mut test = TestSetup::new();
|
||||
|
||||
let node_id = test.add_legacy_mixnode("owner", Some(100_000_000u128.into()));
|
||||
let sender = mock_info("owner", &[test.coin(100_000)]);
|
||||
test.assert_simple_execution(try_increase_pledge, sender);
|
||||
|
||||
let after = test.mixnode_by_id(node_id).unwrap();
|
||||
let event_id = after.pending_changes.pledge_change.unwrap();
|
||||
assert_eq!(event_id, 1);
|
||||
|
||||
test.execute_all_pending_events();
|
||||
|
||||
let after = test.mixnode_by_id(node_id).unwrap();
|
||||
assert_eq!(
|
||||
after.bond_information.original_pledge.amount.u128(),
|
||||
100_100_000u128
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn for_legacy_gateway() -> anyhow::Result<()> {
|
||||
let mut test = TestSetup::new();
|
||||
|
||||
test.add_legacy_gateway("owner", None);
|
||||
let sender = mock_info("owner", &[test.coin(100000)]);
|
||||
let err = test.execute_fn(try_increase_pledge, sender).unwrap_err();
|
||||
|
||||
// it's illegal to increase pledge for legacy gateways
|
||||
assert_eq!(
|
||||
MixnetContractError::NoAssociatedNodeBond {
|
||||
owner: Addr::unchecked("owner"),
|
||||
},
|
||||
err
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn for_nymnode() -> anyhow::Result<()> {
|
||||
let mut test = TestSetup::new();
|
||||
|
||||
let node_id = test.add_dummy_nymnode("owner", Some(100_000_000u128.into()));
|
||||
let sender = mock_info("owner", &[test.coin(100_000)]);
|
||||
test.assert_simple_execution(try_increase_pledge, sender);
|
||||
|
||||
let after = test.nymnode_by_id(node_id).unwrap();
|
||||
let event_id = after.pending_changes.pledge_change.unwrap();
|
||||
assert_eq!(event_id, 1);
|
||||
|
||||
test.execute_all_pending_events();
|
||||
|
||||
let after = test.nymnode_by_id(node_id).unwrap();
|
||||
assert_eq!(
|
||||
after.bond_information.original_pledge.amount.u128(),
|
||||
100_100_000u128
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod decreasing_pledge {
|
||||
use super::*;
|
||||
use crate::support::tests::test_helpers::TestSetup;
|
||||
use cosmwasm_std::testing::mock_info;
|
||||
use cosmwasm_std::Addr;
|
||||
|
||||
#[test]
|
||||
fn when_there_are_no_nodes() -> anyhow::Result<()> {
|
||||
let mut test = TestSetup::new();
|
||||
|
||||
let sender = mock_info("owner", &[]);
|
||||
let env = test.env();
|
||||
let decrease_by = test.coin(1000);
|
||||
let err = try_decrease_pledge(test.deps_mut(), env, sender, decrease_by).unwrap_err();
|
||||
|
||||
assert_eq!(
|
||||
MixnetContractError::NoAssociatedNodeBond {
|
||||
owner: Addr::unchecked("owner"),
|
||||
},
|
||||
err
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn for_legacy_mixnode() -> anyhow::Result<()> {
|
||||
let mut test = TestSetup::new();
|
||||
|
||||
let node_id = test.add_legacy_mixnode("owner", Some(120_000_000u128.into()));
|
||||
let sender = mock_info("owner", &[]);
|
||||
let env = test.env();
|
||||
let decrease_by = test.coin(1000);
|
||||
try_decrease_pledge(test.deps_mut(), env, sender, decrease_by)?;
|
||||
|
||||
let after = test.mixnode_by_id(node_id).unwrap();
|
||||
let event_id = after.pending_changes.pledge_change.unwrap();
|
||||
assert_eq!(event_id, 1);
|
||||
|
||||
test.execute_all_pending_events();
|
||||
|
||||
let after = test.mixnode_by_id(node_id).unwrap();
|
||||
assert_eq!(
|
||||
after.bond_information.original_pledge.amount.u128(),
|
||||
119_999_000u128
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn for_legacy_gateway() -> anyhow::Result<()> {
|
||||
let mut test = TestSetup::new();
|
||||
|
||||
test.add_legacy_gateway("owner", None);
|
||||
let sender = mock_info("owner", &[]);
|
||||
let env = test.env();
|
||||
let decrease_by = test.coin(1000);
|
||||
let err = try_decrease_pledge(test.deps_mut(), env, sender, decrease_by).unwrap_err();
|
||||
|
||||
// it's illegal to decrease pledge for legacy gateways
|
||||
assert_eq!(
|
||||
MixnetContractError::NoAssociatedNodeBond {
|
||||
owner: Addr::unchecked("owner"),
|
||||
},
|
||||
err
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn for_nymnode() -> anyhow::Result<()> {
|
||||
let mut test = TestSetup::new();
|
||||
|
||||
let node_id = test.add_dummy_nymnode("owner", Some(120_000_000u128.into()));
|
||||
let sender = mock_info("owner", &[]);
|
||||
let env = test.env();
|
||||
let decrease_by = test.coin(1000);
|
||||
|
||||
try_decrease_pledge(test.deps_mut(), env, sender, decrease_by)?;
|
||||
|
||||
let after = test.nymnode_by_id(node_id).unwrap();
|
||||
let event_id = after.pending_changes.pledge_change.unwrap();
|
||||
assert_eq!(event_id, 1);
|
||||
|
||||
test.execute_all_pending_events();
|
||||
|
||||
let after = test.nymnode_by_id(node_id).unwrap();
|
||||
assert_eq!(
|
||||
after.bond_information.original_pledge.amount.u128(),
|
||||
119_999_000u128
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod updating_cost_params {
|
||||
use super::*;
|
||||
use crate::support::tests::fixtures::TEST_COIN_DENOM;
|
||||
use crate::support::tests::test_helpers::TestSetup;
|
||||
use cosmwasm_std::testing::mock_info;
|
||||
use cosmwasm_std::{Addr, Uint128};
|
||||
use mixnet_contract_common::{OperatingCostRange, ProfitMarginRange};
|
||||
use nym_contracts_common::Percent;
|
||||
|
||||
fn new_dummy_params() -> NodeCostParams {
|
||||
NodeCostParams {
|
||||
profit_margin_percent: Percent::from_percentage_value(69).unwrap(),
|
||||
interval_operating_cost: Coin {
|
||||
denom: TEST_COIN_DENOM.to_string(),
|
||||
amount: 123456789u128.into(),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn profit_margin_must_be_within_range() -> anyhow::Result<()> {
|
||||
let mut test = TestSetup::new();
|
||||
|
||||
let minimum = Percent::from_percentage_value(10)?;
|
||||
let maximum = Percent::from_percentage_value(80)?;
|
||||
let range = ProfitMarginRange::new(minimum, maximum);
|
||||
test.update_profit_margin_range(range);
|
||||
|
||||
// below lower
|
||||
test.add_dummy_nymnode("owner1", None);
|
||||
let sender = mock_info("owner1", &[]);
|
||||
let env = test.env();
|
||||
let mut update = new_dummy_params();
|
||||
update.profit_margin_percent = Percent::from_percentage_value(9)?;
|
||||
let err =
|
||||
try_update_cost_params(test.deps_mut(), env, sender, update.clone()).unwrap_err();
|
||||
assert!(matches!(
|
||||
err,
|
||||
MixnetContractError::ProfitMarginOutsideRange { .. }
|
||||
));
|
||||
|
||||
// zero
|
||||
test.add_dummy_nymnode("owner2", None);
|
||||
let sender = mock_info("owner2", &[]);
|
||||
let env = test.env();
|
||||
let mut update = new_dummy_params();
|
||||
update.profit_margin_percent = Percent::zero();
|
||||
let err =
|
||||
try_update_cost_params(test.deps_mut(), env, sender, update.clone()).unwrap_err();
|
||||
assert!(matches!(
|
||||
err,
|
||||
MixnetContractError::ProfitMarginOutsideRange { .. }
|
||||
));
|
||||
|
||||
// exactly at lower
|
||||
test.add_dummy_nymnode("owner3", None);
|
||||
let sender = mock_info("owner3", &[]);
|
||||
let env = test.env();
|
||||
let mut update = new_dummy_params();
|
||||
update.profit_margin_percent = minimum;
|
||||
let res = try_update_cost_params(test.deps_mut(), env, sender, update.clone());
|
||||
assert!(res.is_ok());
|
||||
|
||||
// above upper
|
||||
test.add_dummy_nymnode("owner4", None);
|
||||
let sender = mock_info("owner4", &[]);
|
||||
let env = test.env();
|
||||
let mut update = new_dummy_params();
|
||||
update.profit_margin_percent = Percent::from_percentage_value(81)?;
|
||||
let err =
|
||||
try_update_cost_params(test.deps_mut(), env, sender, update.clone()).unwrap_err();
|
||||
assert!(matches!(
|
||||
err,
|
||||
MixnetContractError::ProfitMarginOutsideRange { .. }
|
||||
));
|
||||
|
||||
// hundred
|
||||
test.add_dummy_nymnode("owner5", None);
|
||||
let sender = mock_info("owner5", &[]);
|
||||
let env = test.env();
|
||||
let mut update = new_dummy_params();
|
||||
update.profit_margin_percent = Percent::hundred();
|
||||
let err =
|
||||
try_update_cost_params(test.deps_mut(), env, sender, update.clone()).unwrap_err();
|
||||
assert!(matches!(
|
||||
err,
|
||||
MixnetContractError::ProfitMarginOutsideRange { .. }
|
||||
));
|
||||
|
||||
// exactly at upper
|
||||
test.add_dummy_nymnode("owner6", None);
|
||||
let sender = mock_info("owner6", &[]);
|
||||
let env = test.env();
|
||||
let mut update = new_dummy_params();
|
||||
update.profit_margin_percent = maximum;
|
||||
let res = try_update_cost_params(test.deps_mut(), env, sender, update.clone());
|
||||
assert!(res.is_ok());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn operating_cost_must_be_within_range() -> anyhow::Result<()> {
|
||||
let mut test = TestSetup::new();
|
||||
|
||||
let minimum = Uint128::new(1000);
|
||||
let maximum = Uint128::new(100_000_000);
|
||||
let range = OperatingCostRange::new(minimum, maximum);
|
||||
test.update_operating_cost_range(range);
|
||||
|
||||
// below lower
|
||||
test.add_dummy_nymnode("owner1", None);
|
||||
let sender = mock_info("owner1", &[]);
|
||||
let env = test.env();
|
||||
let mut update = new_dummy_params();
|
||||
update.interval_operating_cost = test.coin(999);
|
||||
let err =
|
||||
try_update_cost_params(test.deps_mut(), env, sender, update.clone()).unwrap_err();
|
||||
assert!(matches!(
|
||||
err,
|
||||
MixnetContractError::OperatingCostOutsideRange { .. }
|
||||
));
|
||||
|
||||
// zero
|
||||
test.add_dummy_nymnode("owner2", None);
|
||||
let sender = mock_info("owner2", &[]);
|
||||
let env = test.env();
|
||||
let mut update = new_dummy_params();
|
||||
update.interval_operating_cost = test.coin(0);
|
||||
let err =
|
||||
try_update_cost_params(test.deps_mut(), env, sender, update.clone()).unwrap_err();
|
||||
assert!(matches!(
|
||||
err,
|
||||
MixnetContractError::OperatingCostOutsideRange { .. }
|
||||
));
|
||||
|
||||
// exactly at lower
|
||||
test.add_dummy_nymnode("owner3", None);
|
||||
let sender = mock_info("owner3", &[]);
|
||||
let env = test.env();
|
||||
let mut update = new_dummy_params();
|
||||
update.interval_operating_cost = test.coin(minimum.u128());
|
||||
let res = try_update_cost_params(test.deps_mut(), env, sender, update.clone());
|
||||
assert!(res.is_ok());
|
||||
|
||||
// above upper
|
||||
test.add_dummy_nymnode("owner4", None);
|
||||
let sender = mock_info("owner4", &[]);
|
||||
let env = test.env();
|
||||
let mut update = new_dummy_params();
|
||||
update.interval_operating_cost = test.coin(100_000_001);
|
||||
let err =
|
||||
try_update_cost_params(test.deps_mut(), env, sender, update.clone()).unwrap_err();
|
||||
assert!(matches!(
|
||||
err,
|
||||
MixnetContractError::OperatingCostOutsideRange { .. }
|
||||
));
|
||||
|
||||
// max
|
||||
test.add_dummy_nymnode("owner5", None);
|
||||
let sender = mock_info("owner5", &[]);
|
||||
let env = test.env();
|
||||
let mut update = new_dummy_params();
|
||||
update.interval_operating_cost = test.coin(u128::MAX);
|
||||
let err =
|
||||
try_update_cost_params(test.deps_mut(), env, sender, update.clone()).unwrap_err();
|
||||
assert!(matches!(
|
||||
err,
|
||||
MixnetContractError::OperatingCostOutsideRange { .. }
|
||||
));
|
||||
|
||||
// exactly at upper
|
||||
test.add_dummy_nymnode("owner6", None);
|
||||
let sender = mock_info("owner6", &[]);
|
||||
let env = test.env();
|
||||
let mut update = new_dummy_params();
|
||||
update.interval_operating_cost = test.coin(100_000_000);
|
||||
let res = try_update_cost_params(test.deps_mut(), env, sender, update.clone());
|
||||
assert!(res.is_ok());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn when_there_are_no_nodes() -> anyhow::Result<()> {
|
||||
let mut test = TestSetup::new();
|
||||
|
||||
let sender = mock_info("owner", &[]);
|
||||
let env = test.env();
|
||||
let err = try_update_cost_params(test.deps_mut(), env, sender, new_dummy_params())
|
||||
.unwrap_err();
|
||||
|
||||
assert_eq!(
|
||||
MixnetContractError::NoAssociatedNodeBond {
|
||||
owner: Addr::unchecked("owner"),
|
||||
},
|
||||
err
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn for_legacy_mixnode() -> anyhow::Result<()> {
|
||||
let mut test = TestSetup::new();
|
||||
|
||||
let node_id = test.add_legacy_mixnode("owner", None);
|
||||
let sender = mock_info("owner", &[]);
|
||||
let env = test.env();
|
||||
|
||||
let update = new_dummy_params();
|
||||
try_update_cost_params(test.deps_mut(), env, sender, update.clone())?;
|
||||
|
||||
let after = test.mixnode_by_id(node_id).unwrap();
|
||||
let event_id = after.pending_changes.cost_params_change.unwrap();
|
||||
assert_eq!(event_id, 1);
|
||||
|
||||
test.execute_all_pending_events();
|
||||
|
||||
let after = test.mixnode_by_id(node_id).unwrap();
|
||||
assert_eq!(update, after.rewarding_details.cost_params);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn for_legacy_gateway() -> anyhow::Result<()> {
|
||||
let mut test = TestSetup::new();
|
||||
|
||||
test.add_legacy_gateway("owner", None);
|
||||
|
||||
let sender = mock_info("owner", &[]);
|
||||
let env = test.env();
|
||||
let err = try_update_cost_params(test.deps_mut(), env, sender, new_dummy_params())
|
||||
.unwrap_err();
|
||||
|
||||
// it's illegal to update cost parameters for legacy gateways
|
||||
assert_eq!(
|
||||
MixnetContractError::NoAssociatedNodeBond {
|
||||
owner: Addr::unchecked("owner"),
|
||||
},
|
||||
err
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn for_nymnode() -> anyhow::Result<()> {
|
||||
let mut test = TestSetup::new();
|
||||
|
||||
let node_id = test.add_dummy_nymnode("owner", None);
|
||||
let sender = mock_info("owner", &[]);
|
||||
let env = test.env();
|
||||
|
||||
let update = new_dummy_params();
|
||||
try_update_cost_params(test.deps_mut(), env, sender, update.clone())?;
|
||||
|
||||
let after = test.nymnode_by_id(node_id).unwrap();
|
||||
let event_id = after.pending_changes.cost_params_change.unwrap();
|
||||
assert_eq!(event_id, 1);
|
||||
|
||||
test.execute_all_pending_events();
|
||||
|
||||
let after = test.nymnode_by_id(node_id).unwrap();
|
||||
assert_eq!(update, after.rewarding_details.cost_params);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod withdrawing_operator_reward {
|
||||
use super::*;
|
||||
use crate::support::tests::test_helpers;
|
||||
use crate::support::tests::test_helpers::{ExtractBankMsg, TestSetup};
|
||||
use cosmwasm_std::testing::mock_info;
|
||||
use cosmwasm_std::Addr;
|
||||
|
||||
#[test]
|
||||
fn when_there_are_no_nodes() -> anyhow::Result<()> {
|
||||
let mut test = TestSetup::new();
|
||||
|
||||
let sender = mock_info("owner", &[]);
|
||||
let err = try_withdraw_operator_reward(test.deps_mut(), sender).unwrap_err();
|
||||
|
||||
assert_eq!(
|
||||
MixnetContractError::NoAssociatedNodeBond {
|
||||
owner: Addr::unchecked("owner"),
|
||||
},
|
||||
err
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn for_legacy_mixnode() -> anyhow::Result<()> {
|
||||
let mut test = TestSetup::new();
|
||||
|
||||
// no rewards
|
||||
test.add_legacy_mixnode("owner1", None);
|
||||
let sender = mock_info("owner1", &[]);
|
||||
|
||||
let res = try_withdraw_operator_reward(test.deps_mut(), sender)?;
|
||||
let maybe_bank = res.unwrap_bank_msg();
|
||||
assert!(maybe_bank.is_none());
|
||||
|
||||
let node_id = test.add_legacy_mixnode("owner2", None);
|
||||
let sender = mock_info("owner2", &[]);
|
||||
test.skip_to_next_epoch_end();
|
||||
test.force_change_rewarded_set(vec![node_id]);
|
||||
test.start_epoch_transition();
|
||||
test.legacy_reward_with_distribution_and_legacy_work_factor(
|
||||
node_id,
|
||||
test_helpers::performance(100.),
|
||||
);
|
||||
|
||||
let res = try_withdraw_operator_reward(test.deps_mut(), sender)?;
|
||||
let maybe_bank = res.unwrap_bank_msg();
|
||||
assert!(maybe_bank.is_some());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn for_legacy_gateway() -> anyhow::Result<()> {
|
||||
let mut test = TestSetup::new();
|
||||
|
||||
test.add_legacy_gateway("owner", None);
|
||||
|
||||
let sender = mock_info("owner", &[]);
|
||||
let err = try_withdraw_operator_reward(test.deps_mut(), sender).unwrap_err();
|
||||
|
||||
// no rewards for legacy gateways...
|
||||
assert_eq!(
|
||||
MixnetContractError::NoAssociatedNodeBond {
|
||||
owner: Addr::unchecked("owner"),
|
||||
},
|
||||
err
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn for_nymnode() -> anyhow::Result<()> {
|
||||
let mut test = TestSetup::new();
|
||||
|
||||
// no rewards
|
||||
test.add_dummy_nymnode("owner1", None);
|
||||
let sender = mock_info("owner1", &[]);
|
||||
|
||||
let res = try_withdraw_operator_reward(test.deps_mut(), sender)?;
|
||||
let maybe_bank = res.unwrap_bank_msg();
|
||||
assert!(maybe_bank.is_none());
|
||||
|
||||
let node_id = test.add_dummy_nymnode("owner2", None);
|
||||
let sender = mock_info("owner2", &[]);
|
||||
test.skip_to_next_epoch_end();
|
||||
test.force_change_rewarded_set(vec![node_id]);
|
||||
test.start_epoch_transition();
|
||||
test.legacy_reward_with_distribution_and_legacy_work_factor(
|
||||
node_id,
|
||||
test_helpers::performance(100.),
|
||||
);
|
||||
|
||||
let res = try_withdraw_operator_reward(test.deps_mut(), sender)?;
|
||||
let maybe_bank = res.unwrap_bank_msg();
|
||||
assert!(maybe_bank.is_some());
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,7 +143,7 @@ pub mod tests {
|
||||
use crate::gateways::queries;
|
||||
use crate::interval::pending_events;
|
||||
use crate::mixnet_contract_settings::storage::minimum_node_pledge;
|
||||
use crate::nodes::helpers::get_node_details_by_identity;
|
||||
use crate::nodes::helpers::{get_node_details_by_identity, must_get_node_bond_by_owner};
|
||||
use crate::signing::storage as signing_storage;
|
||||
use crate::support::tests;
|
||||
use crate::support::tests::fixtures::{good_gateway_pledge, good_mixnode_pledge};
|
||||
@@ -153,7 +153,7 @@ pub mod tests {
|
||||
use mixnet_contract_common::ExecuteMsg;
|
||||
|
||||
#[test]
|
||||
fn gateway_add() {
|
||||
fn gateway_add() -> anyhow::Result<()> {
|
||||
let mut test = TestSetup::new();
|
||||
|
||||
// if we fail validation (by say not sending enough funds
|
||||
@@ -218,10 +218,22 @@ pub mod tests {
|
||||
assert!(result.is_ok());
|
||||
|
||||
// and the node has been added as a nym-node
|
||||
let nym_node = get_node_details_by_identity(test.deps().storage, gateway.identity_key)
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
assert_eq!(nym_node.bond_information.owner, info.sender)
|
||||
let nym_node =
|
||||
get_node_details_by_identity(test.deps().storage, gateway.identity_key.clone())
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
assert_eq!(nym_node.bond_information.owner, info.sender);
|
||||
|
||||
let maybe_legacy =
|
||||
storage::gateways().may_load(test.deps().storage, &gateway.identity_key)?;
|
||||
assert!(maybe_legacy.is_none());
|
||||
|
||||
// make sure we got assigned the next id (note: we have already bonded a mixnode and a gateway before in this test)
|
||||
let bond =
|
||||
must_get_node_bond_by_owner(test.deps().storage, &Addr::unchecked(sender2)).unwrap();
|
||||
assert_eq!(3, bond.node_id);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -34,7 +34,7 @@ pub(crate) fn profit_margin_range(
|
||||
.map(|state| state.params.profit_margin)?)
|
||||
}
|
||||
|
||||
pub(crate) fn interval_oprating_cost_range(
|
||||
pub(crate) fn interval_operating_cost_range(
|
||||
storage: &dyn Storage,
|
||||
) -> Result<OperatingCostRange, MixnetContractError> {
|
||||
Ok(CONTRACT_STATE
|
||||
|
||||
@@ -257,12 +257,10 @@ pub fn try_migrate_to_nymnode(
|
||||
#[cfg(test)]
|
||||
pub mod tests {
|
||||
use super::*;
|
||||
use crate::compat::transactions::{
|
||||
try_decrease_pledge, try_increase_pledge, try_update_cost_params,
|
||||
};
|
||||
use crate::compat::transactions::try_increase_pledge;
|
||||
use crate::contract::execute;
|
||||
use crate::mixnet_contract_settings::storage::minimum_node_pledge;
|
||||
use crate::mixnodes::helpers::get_mixnode_details_by_id;
|
||||
use crate::mixnodes::helpers::{get_mixnode_details_by_id, get_mixnode_details_by_identity};
|
||||
use crate::nodes::helpers::{get_node_details_by_identity, must_get_node_bond_by_owner};
|
||||
use crate::signing::storage as signing_storage;
|
||||
use crate::support::tests::fixtures::{good_mixnode_pledge, TEST_COIN_DENOM};
|
||||
@@ -275,7 +273,7 @@ pub mod tests {
|
||||
use mixnet_contract_common::{EpochState, EpochStatus, ExecuteMsg, Percent};
|
||||
|
||||
#[test]
|
||||
fn mixnode_add() {
|
||||
fn mixnode_add() -> anyhow::Result<()> {
|
||||
let mut test = TestSetup::new();
|
||||
let env = test.env();
|
||||
|
||||
@@ -357,15 +355,22 @@ pub mod tests {
|
||||
assert!(result.is_ok());
|
||||
|
||||
// and the node has been added as a nym-node
|
||||
let nym_node = get_node_details_by_identity(test.deps().storage, mixnode.identity_key)
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
let nym_node =
|
||||
get_node_details_by_identity(test.deps().storage, mixnode.identity_key.clone())
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
assert_eq!(nym_node.bond_information.owner, info.sender);
|
||||
|
||||
let maybe_legacy =
|
||||
get_mixnode_details_by_identity(test.deps().storage, mixnode.identity_key)?;
|
||||
assert!(maybe_legacy.is_none());
|
||||
|
||||
// make sure we got assigned the next id (note: we have already bonded a mixnode and a gateway before in this test)
|
||||
let bond =
|
||||
must_get_node_bond_by_owner(test.deps().storage, &Addr::unchecked(sender2)).unwrap();
|
||||
assert_eq!(3, bond.node_id);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -524,7 +529,9 @@ pub mod tests {
|
||||
|
||||
// prior increase
|
||||
let owner = "mix-owner1";
|
||||
test.add_legacy_mixnode(owner, None);
|
||||
let node_id = test.add_legacy_mixnode(owner, None);
|
||||
let details = test.mixnode_by_id(node_id).unwrap();
|
||||
|
||||
let sender = mock_info(owner, &[test.coin(1000)]);
|
||||
try_increase_pledge(test.deps_mut(), env.clone(), sender.clone()).unwrap();
|
||||
|
||||
@@ -538,10 +545,10 @@ pub mod tests {
|
||||
|
||||
// prior decrease
|
||||
let owner = "mix-owner2";
|
||||
test.add_legacy_mixnode(owner, Some(Uint128::new(10000000000)));
|
||||
let sender = mock_info(owner, &[]);
|
||||
let node_id = test.add_legacy_mixnode(owner, Some(Uint128::new(10000000000)));
|
||||
let details = test.mixnode_by_id(node_id).unwrap();
|
||||
let amount = test.coin(1000);
|
||||
try_decrease_pledge(test.deps_mut(), env.clone(), sender, amount).unwrap();
|
||||
try_decrease_mixnode_pledge(test.deps_mut(), env.clone(), amount, details).unwrap();
|
||||
|
||||
let sender = mock_info(owner, &[test.coin(1000)]);
|
||||
let res = try_remove_mixnode(test.deps_mut(), env.clone(), sender);
|
||||
@@ -640,15 +647,20 @@ pub mod tests {
|
||||
let mut test = TestSetup::new();
|
||||
let env = test.env();
|
||||
let owner = "alice";
|
||||
let info = mock_info(owner, &[]);
|
||||
|
||||
test.add_legacy_mixnode(owner, None);
|
||||
let node_id = test.add_legacy_mixnode(owner, None);
|
||||
let details = test.mixnode_by_id(node_id).unwrap();
|
||||
|
||||
let mut status = EpochStatus::new(test.rewarding_validator().sender);
|
||||
status.state = bad_state;
|
||||
interval_storage::save_current_epoch_status(test.deps_mut().storage, &status).unwrap();
|
||||
|
||||
let res = try_update_cost_params(test.deps_mut(), env.clone(), info, update.clone());
|
||||
let res = try_update_mixnode_cost_params(
|
||||
test.deps_mut(),
|
||||
env.clone(),
|
||||
update.clone(),
|
||||
details,
|
||||
);
|
||||
assert!(matches!(
|
||||
res,
|
||||
Err(MixnetContractError::EpochAdvancementInProgress { .. })
|
||||
@@ -668,21 +680,16 @@ pub mod tests {
|
||||
interval_operating_cost: Coin::new(12345678, TEST_COIN_DENOM),
|
||||
};
|
||||
|
||||
// try updating a non-existing mixnode bond
|
||||
let res =
|
||||
try_update_cost_params(test.deps_mut(), env.clone(), info.clone(), update.clone());
|
||||
assert_eq!(
|
||||
res,
|
||||
Err(MixnetContractError::NoAssociatedNodeBond {
|
||||
owner: Addr::unchecked(owner)
|
||||
})
|
||||
);
|
||||
|
||||
let mix_id = test.add_legacy_mixnode(owner, None);
|
||||
let node_id = test.add_legacy_mixnode(owner, None);
|
||||
let details = test.mixnode_by_id(node_id).unwrap();
|
||||
|
||||
// "normal" update succeeds
|
||||
let res =
|
||||
try_update_cost_params(test.deps_mut(), env.clone(), info.clone(), update.clone());
|
||||
let res = try_update_mixnode_cost_params(
|
||||
test.deps_mut(),
|
||||
env.clone(),
|
||||
update.clone(),
|
||||
details.clone(),
|
||||
);
|
||||
assert!(res.is_ok());
|
||||
|
||||
// see if the event has been pushed onto the queue
|
||||
@@ -695,7 +702,7 @@ pub mod tests {
|
||||
assert_eq!(1, event.0);
|
||||
assert_eq!(
|
||||
PendingIntervalEventKind::ChangeMixCostParams {
|
||||
mix_id,
|
||||
mix_id: node_id,
|
||||
new_costs: update.clone(),
|
||||
},
|
||||
event.1.kind
|
||||
@@ -705,18 +712,16 @@ pub mod tests {
|
||||
test_helpers::execute_all_pending_events(test.deps_mut(), env.clone());
|
||||
|
||||
// and see if the config has actually been updated
|
||||
let mix = get_mixnode_details_by_id(test.deps().storage, mix_id)
|
||||
let mix = get_mixnode_details_by_id(test.deps().storage, node_id)
|
||||
.unwrap()
|
||||
.unwrap();
|
||||
assert_eq!(mix.rewarding_details.cost_params, update);
|
||||
|
||||
// but we cannot perform any updates whilst the mixnode is already unbonding
|
||||
try_remove_mixnode(test.deps_mut(), env.clone(), info.clone()).unwrap();
|
||||
let res = try_update_cost_params(test.deps_mut(), env, info, update);
|
||||
assert_eq!(
|
||||
res,
|
||||
Err(MixnetContractError::NodeIsUnbonding { node_id: mix_id })
|
||||
)
|
||||
let details = test.mixnode_by_id(node_id).unwrap();
|
||||
let res = try_update_mixnode_cost_params(test.deps_mut(), env, update, details);
|
||||
assert_eq!(res, Err(MixnetContractError::NodeIsUnbonding { node_id }))
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -796,15 +801,15 @@ pub mod tests {
|
||||
let env = test.env();
|
||||
let owner = "mix-owner";
|
||||
|
||||
test.add_legacy_mixnode(owner, None);
|
||||
|
||||
let mut status = EpochStatus::new(test.rewarding_validator().sender);
|
||||
status.state = bad_state;
|
||||
interval_storage::save_current_epoch_status(test.deps_mut().storage, &status)
|
||||
.unwrap();
|
||||
|
||||
let sender = mock_info(owner, &[test.coin(1000)]);
|
||||
let res = try_increase_pledge(test.deps_mut(), env, sender);
|
||||
let node_id = test.add_legacy_mixnode(owner, None);
|
||||
let details = test.mixnode_by_id(node_id).unwrap();
|
||||
let increase = test.coins(1000);
|
||||
let res = try_increase_mixnode_pledge(test.deps_mut(), env, increase, details);
|
||||
|
||||
assert!(matches!(
|
||||
res,
|
||||
@@ -814,38 +819,21 @@ pub mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_not_allowed_if_account_doesnt_own_mixnode() {
|
||||
fn is_not_allowed_if_mixnode_has_unbonded() {
|
||||
let mut test = TestSetup::new();
|
||||
let env = test.env();
|
||||
let sender = mock_info("not-mix-owner", &[]);
|
||||
|
||||
let res = try_increase_pledge(test.deps_mut(), env, sender);
|
||||
assert_eq!(
|
||||
res,
|
||||
Err(MixnetContractError::NoAssociatedNodeBond {
|
||||
owner: Addr::unchecked("not-mix-owner")
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_not_allowed_if_mixnode_has_unbonded_or_is_unbonding() {
|
||||
let mut test = TestSetup::new();
|
||||
let env = test.env();
|
||||
|
||||
// TODO: I dislike this cross-test access, but it provides us with exactly what we need
|
||||
// perhaps it should be refactored a bit?
|
||||
let owner_unbonding = Addr::unchecked(OWNER_UNBONDING);
|
||||
let owner_unbonded = Addr::unchecked(OWNER_UNBONDED);
|
||||
let owner_unbonded_leftover = Addr::unchecked(OWNER_UNBONDED_LEFTOVER);
|
||||
|
||||
let ids = setup_mix_combinations(&mut test, None);
|
||||
let mix_id_unbonding = ids[1].mix_id;
|
||||
|
||||
let res = try_increase_pledge(
|
||||
let increase = test.coins(1000);
|
||||
let details = test.mixnode_by_id(mix_id_unbonding).unwrap();
|
||||
|
||||
let res = try_increase_mixnode_pledge(
|
||||
test.deps_mut(),
|
||||
env.clone(),
|
||||
mock_info(owner_unbonding.as_str(), &[]),
|
||||
increase.clone(),
|
||||
details,
|
||||
);
|
||||
assert_eq!(
|
||||
res,
|
||||
@@ -853,32 +841,6 @@ pub mod tests {
|
||||
node_id: mix_id_unbonding
|
||||
})
|
||||
);
|
||||
|
||||
// if the nodes are gone we treat them as tey never existed in the first place
|
||||
// (regardless of if there's some leftover data)
|
||||
let res = try_increase_pledge(
|
||||
test.deps_mut(),
|
||||
env.clone(),
|
||||
mock_info(owner_unbonded_leftover.as_str(), &[]),
|
||||
);
|
||||
assert_eq!(
|
||||
res,
|
||||
Err(MixnetContractError::NoAssociatedNodeBond {
|
||||
owner: owner_unbonded_leftover
|
||||
})
|
||||
);
|
||||
|
||||
let res = try_increase_pledge(
|
||||
test.deps_mut(),
|
||||
env,
|
||||
mock_info(owner_unbonded.as_str(), &[]),
|
||||
);
|
||||
assert_eq!(
|
||||
res,
|
||||
Err(MixnetContractError::NoAssociatedNodeBond {
|
||||
owner: owner_unbonded
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -887,14 +849,21 @@ pub mod tests {
|
||||
let env = test.env();
|
||||
let owner = "mix-owner";
|
||||
|
||||
test.add_legacy_mixnode(owner, None);
|
||||
let node_id = test.add_legacy_mixnode(owner, None);
|
||||
let details = test.mixnode_by_id(node_id).unwrap();
|
||||
|
||||
let sender_empty = mock_info(owner, &[]);
|
||||
let res = try_increase_pledge(test.deps_mut(), env.clone(), sender_empty);
|
||||
let sender_empty = Vec::new();
|
||||
let res = try_increase_mixnode_pledge(
|
||||
test.deps_mut(),
|
||||
env.clone(),
|
||||
sender_empty,
|
||||
details.clone(),
|
||||
);
|
||||
assert_eq!(res, Err(MixnetContractError::NoBondFound));
|
||||
|
||||
let sender_zero = mock_info(owner, &[test.coin(0)]);
|
||||
let res = try_increase_pledge(test.deps_mut(), env, sender_zero);
|
||||
let sender_zero = test.coins(0);
|
||||
let res =
|
||||
try_increase_mixnode_pledge(test.deps_mut(), env, sender_zero, details.clone());
|
||||
assert_eq!(
|
||||
res,
|
||||
Err(MixnetContractError::InsufficientPledge {
|
||||
@@ -911,11 +880,19 @@ pub mod tests {
|
||||
|
||||
// prior increase
|
||||
let owner = "mix-owner1";
|
||||
test.add_legacy_mixnode(owner, None);
|
||||
let sender = mock_info(owner, &[test.coin(1000)]);
|
||||
try_increase_pledge(test.deps_mut(), env.clone(), sender.clone()).unwrap();
|
||||
let node_id = test.add_legacy_mixnode(owner, None);
|
||||
let details = test.mixnode_by_id(node_id).unwrap();
|
||||
let sender = test.coins(1000);
|
||||
try_increase_mixnode_pledge(
|
||||
test.deps_mut(),
|
||||
env.clone(),
|
||||
sender.clone(),
|
||||
details.clone(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
let res = try_increase_pledge(test.deps_mut(), env.clone(), sender);
|
||||
let details = test.mixnode_by_id(node_id).unwrap();
|
||||
let res = try_increase_mixnode_pledge(test.deps_mut(), env.clone(), sender, details);
|
||||
assert_eq!(
|
||||
res,
|
||||
Err(MixnetContractError::PendingPledgeChange {
|
||||
@@ -925,39 +902,22 @@ pub mod tests {
|
||||
|
||||
// prior decrease
|
||||
let owner = "mix-owner2";
|
||||
test.add_legacy_mixnode(owner, Some(Uint128::new(10000000000)));
|
||||
let sender = mock_info(owner, &[]);
|
||||
let amount = test.coin(1000);
|
||||
try_decrease_pledge(test.deps_mut(), env.clone(), sender, amount).unwrap();
|
||||
let node_id = test.add_legacy_mixnode(owner, Some(Uint128::new(10000000000)));
|
||||
let details = test.mixnode_by_id(node_id).unwrap();
|
||||
|
||||
let sender = mock_info(owner, &[test.coin(1000)]);
|
||||
let res = try_increase_pledge(test.deps_mut(), env.clone(), sender);
|
||||
let amount = test.coin(1000);
|
||||
try_decrease_mixnode_pledge(test.deps_mut(), env.clone(), amount, details.clone())
|
||||
.unwrap();
|
||||
|
||||
let sender = test.coins(10000);
|
||||
let details = test.mixnode_by_id(node_id).unwrap();
|
||||
let res = try_increase_mixnode_pledge(test.deps_mut(), env.clone(), sender, details);
|
||||
assert_eq!(
|
||||
res,
|
||||
Err(MixnetContractError::PendingPledgeChange {
|
||||
pending_event_id: 2
|
||||
})
|
||||
);
|
||||
|
||||
// artificial event
|
||||
let owner = "mix-owner3";
|
||||
let mix_id = test.add_legacy_mixnode(owner, None);
|
||||
let pending_change = PendingMixNodeChanges {
|
||||
pledge_change: Some(1234),
|
||||
cost_params_change: None,
|
||||
};
|
||||
storage::PENDING_MIXNODE_CHANGES
|
||||
.save(test.deps_mut().storage, mix_id, &pending_change)
|
||||
.unwrap();
|
||||
|
||||
let sender = mock_info(owner, &[test.coin(1000)]);
|
||||
let res = try_increase_pledge(test.deps_mut(), env, sender);
|
||||
assert_eq!(
|
||||
res,
|
||||
Err(MixnetContractError::PendingPledgeChange {
|
||||
pending_event_id: 1234
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -966,12 +926,13 @@ pub mod tests {
|
||||
let env = test.env();
|
||||
let owner = "mix-owner";
|
||||
let mix_id = test.add_legacy_mixnode(owner, None);
|
||||
let details = test.mixnode_by_id(mix_id).unwrap();
|
||||
|
||||
let events = test.pending_epoch_events();
|
||||
assert!(events.is_empty());
|
||||
|
||||
let sender = mock_info(owner, &[test.coin(1000)]);
|
||||
try_increase_pledge(test.deps_mut(), env, sender).unwrap();
|
||||
let sender = test.coins(1000);
|
||||
try_increase_mixnode_pledge(test.deps_mut(), env, sender, details).unwrap();
|
||||
|
||||
let events = test.pending_epoch_events();
|
||||
|
||||
@@ -1012,15 +973,15 @@ pub mod tests {
|
||||
let owner = "mix-owner";
|
||||
let decrease = test.coin(1000);
|
||||
|
||||
test.add_legacy_mixnode(owner, Some(Uint128::new(100_000_000_000)));
|
||||
let node_id = test.add_legacy_mixnode(owner, Some(Uint128::new(100_000_000_000)));
|
||||
let details = test.mixnode_by_id(node_id).unwrap();
|
||||
|
||||
let mut status = EpochStatus::new(test.rewarding_validator().sender);
|
||||
status.state = bad_state;
|
||||
interval_storage::save_current_epoch_status(test.deps_mut().storage, &status)
|
||||
.unwrap();
|
||||
|
||||
let sender = mock_info(owner, &[]);
|
||||
let res = try_decrease_pledge(test.deps_mut(), env, sender, decrease);
|
||||
let res = try_decrease_mixnode_pledge(test.deps_mut(), env, decrease, details);
|
||||
|
||||
assert!(matches!(
|
||||
res,
|
||||
@@ -1030,44 +991,21 @@ pub mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_not_allowed_if_account_doesnt_own_mixnode() {
|
||||
let mut test = TestSetup::new();
|
||||
let env = test.env();
|
||||
let sender = mock_info("not-mix-owner", &[]);
|
||||
let decrease = test.coin(1000);
|
||||
|
||||
let res = try_decrease_pledge(test.deps_mut(), env, sender, decrease);
|
||||
assert_eq!(
|
||||
res,
|
||||
Err(MixnetContractError::NoAssociatedNodeBond {
|
||||
owner: Addr::unchecked("not-mix-owner")
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn is_not_allowed_if_mixnode_has_unbonded_or_is_unbonding() {
|
||||
fn is_not_allowed_if_mixnode_is_unbonding() {
|
||||
let mut test = TestSetup::new();
|
||||
let env = test.env();
|
||||
|
||||
// just to make sure that after decrease the value would still be above the minimum
|
||||
let stake = Uint128::new(100_000_000_000);
|
||||
let decrease = test.coin(1000);
|
||||
|
||||
// TODO: I dislike this cross-test access, but it provides us with exactly what we need
|
||||
// perhaps it should be refactored a bit?
|
||||
let owner_unbonding = Addr::unchecked(OWNER_UNBONDING);
|
||||
let owner_unbonded = Addr::unchecked(OWNER_UNBONDED);
|
||||
let owner_unbonded_leftover = Addr::unchecked(OWNER_UNBONDED_LEFTOVER);
|
||||
|
||||
let ids = setup_mix_combinations(&mut test, Some(stake));
|
||||
let ids = setup_mix_combinations(&mut test, None);
|
||||
let mix_id_unbonding = ids[1].mix_id;
|
||||
|
||||
let res = try_decrease_pledge(
|
||||
let decrease = test.coin(1000);
|
||||
let details = test.mixnode_by_id(mix_id_unbonding).unwrap();
|
||||
|
||||
let res = try_decrease_mixnode_pledge(
|
||||
test.deps_mut(),
|
||||
env.clone(),
|
||||
mock_info(owner_unbonding.as_str(), &[]),
|
||||
decrease.clone(),
|
||||
details,
|
||||
);
|
||||
assert_eq!(
|
||||
res,
|
||||
@@ -1075,34 +1013,6 @@ pub mod tests {
|
||||
node_id: mix_id_unbonding
|
||||
})
|
||||
);
|
||||
|
||||
// if the nodes are gone we treat them as tey never existed in the first place
|
||||
// (regardless of if there's some leftover data)
|
||||
let res = try_decrease_pledge(
|
||||
test.deps_mut(),
|
||||
env.clone(),
|
||||
mock_info(owner_unbonded_leftover.as_str(), &[]),
|
||||
decrease.clone(),
|
||||
);
|
||||
assert_eq!(
|
||||
res,
|
||||
Err(MixnetContractError::NoAssociatedNodeBond {
|
||||
owner: owner_unbonded_leftover
|
||||
})
|
||||
);
|
||||
|
||||
let res = try_decrease_pledge(
|
||||
test.deps_mut(),
|
||||
env,
|
||||
mock_info(owner_unbonded.as_str(), &[]),
|
||||
decrease,
|
||||
);
|
||||
assert_eq!(
|
||||
res,
|
||||
Err(MixnetContractError::NoAssociatedNodeBond {
|
||||
owner: owner_unbonded
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -1114,17 +1024,17 @@ pub mod tests {
|
||||
let minimum_pledge = minimum_node_pledge(test.deps().storage).unwrap();
|
||||
let pledge_amount = minimum_pledge.amount + Uint128::new(100);
|
||||
let pledged = test.coin(pledge_amount.u128());
|
||||
test.add_legacy_mixnode(owner, Some(pledge_amount));
|
||||
let node_id = test.add_legacy_mixnode(owner, Some(pledge_amount));
|
||||
let details = test.mixnode_by_id(node_id).unwrap();
|
||||
|
||||
let invalid_decrease = test.coin(150);
|
||||
let valid_decrease = test.coin(50);
|
||||
|
||||
let sender = mock_info(owner, &[]);
|
||||
let res = try_decrease_pledge(
|
||||
let res = try_decrease_mixnode_pledge(
|
||||
test.deps_mut(),
|
||||
env.clone(),
|
||||
sender.clone(),
|
||||
invalid_decrease.clone(),
|
||||
details.clone(),
|
||||
);
|
||||
assert_eq!(
|
||||
res,
|
||||
@@ -1136,7 +1046,7 @@ pub mod tests {
|
||||
})
|
||||
);
|
||||
|
||||
let res = try_decrease_pledge(test.deps_mut(), env, sender, valid_decrease);
|
||||
let res = try_decrease_mixnode_pledge(test.deps_mut(), env, valid_decrease, details);
|
||||
assert!(res.is_ok())
|
||||
}
|
||||
|
||||
@@ -1149,10 +1059,10 @@ pub mod tests {
|
||||
let decrease = test.coin(0);
|
||||
|
||||
let owner = "mix-owner";
|
||||
test.add_legacy_mixnode(owner, Some(stake));
|
||||
let node_id = test.add_legacy_mixnode(owner, Some(stake));
|
||||
let details = test.mixnode_by_id(node_id).unwrap();
|
||||
|
||||
let sender = mock_info(owner, &[]);
|
||||
let res = try_decrease_pledge(test.deps_mut(), env, sender, decrease);
|
||||
let res = try_decrease_mixnode_pledge(test.deps_mut(), env, decrease, details);
|
||||
assert_eq!(res, Err(MixnetContractError::ZeroCoinAmount))
|
||||
}
|
||||
|
||||
@@ -1165,11 +1075,20 @@ pub mod tests {
|
||||
|
||||
// prior increase
|
||||
let owner = "mix-owner1";
|
||||
test.add_legacy_mixnode(owner, Some(stake));
|
||||
let sender = mock_info(owner, &[test.coin(1000)]);
|
||||
try_increase_pledge(test.deps_mut(), env.clone(), sender.clone()).unwrap();
|
||||
let node_id = test.add_legacy_mixnode(owner, Some(stake));
|
||||
let details = test.mixnode_by_id(node_id).unwrap();
|
||||
|
||||
let res = try_decrease_pledge(test.deps_mut(), env.clone(), sender, decrease.clone());
|
||||
let sender = test.coins(1000);
|
||||
try_increase_mixnode_pledge(test.deps_mut(), env.clone(), sender.clone(), details)
|
||||
.unwrap();
|
||||
|
||||
let details = test.mixnode_by_id(node_id).unwrap();
|
||||
let res = try_decrease_mixnode_pledge(
|
||||
test.deps_mut(),
|
||||
env.clone(),
|
||||
decrease.clone(),
|
||||
details,
|
||||
);
|
||||
assert_eq!(
|
||||
res,
|
||||
Err(MixnetContractError::PendingPledgeChange {
|
||||
@@ -1179,13 +1098,18 @@ pub mod tests {
|
||||
|
||||
// prior decrease
|
||||
let owner = "mix-owner2";
|
||||
test.add_legacy_mixnode(owner, Some(stake));
|
||||
let sender = mock_info(owner, &[]);
|
||||
let node_id = test.add_legacy_mixnode(owner, Some(stake));
|
||||
let details = test.mixnode_by_id(node_id).unwrap();
|
||||
let amount = test.coin(1000);
|
||||
try_decrease_pledge(test.deps_mut(), env.clone(), sender, amount).unwrap();
|
||||
try_decrease_mixnode_pledge(test.deps_mut(), env.clone(), amount, details).unwrap();
|
||||
|
||||
let sender = mock_info(owner, &[test.coin(1000)]);
|
||||
let res = try_decrease_pledge(test.deps_mut(), env.clone(), sender, decrease.clone());
|
||||
let details = test.mixnode_by_id(node_id).unwrap();
|
||||
let res = try_decrease_mixnode_pledge(
|
||||
test.deps_mut(),
|
||||
env.clone(),
|
||||
decrease.clone(),
|
||||
details,
|
||||
);
|
||||
assert_eq!(
|
||||
res,
|
||||
Err(MixnetContractError::PendingPledgeChange {
|
||||
@@ -1204,8 +1128,8 @@ pub mod tests {
|
||||
.save(test.deps_mut().storage, mix_id, &pending_change)
|
||||
.unwrap();
|
||||
|
||||
let sender = mock_info(owner, &[test.coin(1000)]);
|
||||
let res = try_decrease_pledge(test.deps_mut(), env, sender, decrease);
|
||||
let details = test.mixnode_by_id(mix_id).unwrap();
|
||||
let res = try_decrease_mixnode_pledge(test.deps_mut(), env, decrease, details);
|
||||
assert_eq!(
|
||||
res,
|
||||
Err(MixnetContractError::PendingPledgeChange {
|
||||
@@ -1225,12 +1149,13 @@ pub mod tests {
|
||||
|
||||
let owner = "mix-owner";
|
||||
let mix_id = test.add_legacy_mixnode(owner, Some(stake));
|
||||
let details = test.mixnode_by_id(mix_id).unwrap();
|
||||
|
||||
let events = test.pending_epoch_events();
|
||||
assert!(events.is_empty());
|
||||
|
||||
let sender = mock_info(owner, &[]);
|
||||
try_decrease_pledge(test.deps_mut(), env, sender, decrease.clone()).unwrap();
|
||||
try_decrease_mixnode_pledge(test.deps_mut(), env, decrease.clone(), details).unwrap();
|
||||
|
||||
let events = test.pending_epoch_events();
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ use crate::rewards::helpers::update_and_save_last_rewarded;
|
||||
use crate::rewards::storage::RewardingStorage;
|
||||
use crate::support::helpers::{
|
||||
ensure_any_node_bonded, ensure_can_advance_epoch, ensure_epoch_in_progress_state,
|
||||
AttachSendTokens,
|
||||
AttachSendTokens,
|
||||
};
|
||||
use cosmwasm_std::{DepsMut, Env, MessageInfo, Response};
|
||||
use mixnet_contract_common::error::MixnetContractError;
|
||||
@@ -149,14 +149,20 @@ pub(crate) fn try_withdraw_nym_node_operator_reward(
|
||||
deps: DepsMut<'_>,
|
||||
node_details: NymNodeDetails,
|
||||
) -> Result<Response, MixnetContractError> {
|
||||
ensure_can_withdraw_rewards(&node_details)?;
|
||||
|
||||
let node_id = node_details.node_id();
|
||||
let owner = node_details.bond_information.owner.clone();
|
||||
|
||||
let reward = helpers::withdraw_operator_reward(deps.storage, node_details)?;
|
||||
ensure_can_withdraw_rewards(&node_details)?;
|
||||
|
||||
Ok(Response::new().add_event(new_withdraw_operator_reward_event(&owner, reward, node_id)))
|
||||
let reward = helpers::withdraw_operator_reward(deps.storage, node_details)?;
|
||||
let mut response = Response::new();
|
||||
|
||||
// if the reward is zero, don't track or send anything - there's no point
|
||||
if !reward.amount.is_zero() {
|
||||
response = response.send_tokens(&owner, reward.clone())
|
||||
}
|
||||
|
||||
Ok(response.add_event(new_withdraw_operator_reward_event(&owner, reward, node_id)))
|
||||
}
|
||||
|
||||
pub(crate) fn try_withdraw_mixnode_operator_reward(
|
||||
|
||||
@@ -301,7 +301,7 @@ pub fn ensure_operating_cost_within_range(
|
||||
storage: &dyn Storage,
|
||||
operating_cost: &Coin,
|
||||
) -> Result<(), MixnetContractError> {
|
||||
let range = mixnet_params_storage::interval_oprating_cost_range(storage)?;
|
||||
let range = mixnet_params_storage::interval_operating_cost_range(storage)?;
|
||||
if !range.within_range(operating_cost.amount) {
|
||||
return Err(MixnetContractError::OperatingCostOutsideRange {
|
||||
denom: operating_cost.denom.clone(),
|
||||
|
||||
@@ -16,14 +16,18 @@ pub mod test_helpers {
|
||||
perform_pending_epoch_actions, perform_pending_interval_actions, try_begin_epoch_transition,
|
||||
};
|
||||
use crate::interval::{pending_events, storage as interval_storage};
|
||||
use crate::mixnet_contract_settings::queries::query_contract_settings_params;
|
||||
use crate::mixnet_contract_settings::storage::{
|
||||
self as mixnet_params_storage, minimum_node_pledge,
|
||||
};
|
||||
use crate::mixnet_contract_settings::storage::{rewarding_denom, rewarding_validator_address};
|
||||
use crate::mixnodes::helpers::get_mixnode_details_by_id;
|
||||
use crate::mixnodes::storage as mixnodes_storage;
|
||||
use crate::mixnodes::storage::mixnode_bonds;
|
||||
use crate::mixnodes::transactions::try_remove_mixnode;
|
||||
use crate::nodes::helpers::{get_node_details_by_identity, must_get_node_bond_by_owner};
|
||||
use crate::nodes::helpers::{
|
||||
get_node_details_by_id, get_node_details_by_identity, must_get_node_bond_by_owner,
|
||||
};
|
||||
use crate::nodes::storage as nymnodes_storage;
|
||||
use crate::nodes::storage::helpers::RoleStorageBucket;
|
||||
use crate::nodes::storage::rewarded_set::{ACTIVE_ROLES_BUCKET, ROLES, ROLES_METADATA};
|
||||
@@ -68,10 +72,11 @@ pub mod test_helpers {
|
||||
use mixnet_contract_common::rewarding::simulator::Simulator;
|
||||
use mixnet_contract_common::rewarding::RewardDistribution;
|
||||
use mixnet_contract_common::{
|
||||
Delegation, EpochEventId, EpochState, EpochStatus, ExecuteMsg, Gateway,
|
||||
GatewayBondingPayload, IdentityKey, IdentityKeyRef, InitialRewardingParams, InstantiateMsg,
|
||||
Interval, MixNode, MixNodeBond, MixnodeBondingPayload, NodeId, NymNode, NymNodeBond,
|
||||
NymNodeBondingPayload, Percent, RoleAssignment, SignableGatewayBondingMsg,
|
||||
ContractStateParams, Delegation, EpochEventId, EpochState, EpochStatus, ExecuteMsg,
|
||||
Gateway, GatewayBondingPayload, IdentityKey, IdentityKeyRef, InitialRewardingParams,
|
||||
InstantiateMsg, Interval, MixNode, MixNodeBond, MixNodeDetails, MixnodeBondingPayload,
|
||||
NodeId, NymNode, NymNodeBond, NymNodeBondingPayload, NymNodeDetails, OperatingCostRange,
|
||||
Percent, ProfitMarginRange, RoleAssignment, SignableGatewayBondingMsg,
|
||||
SignableMixNodeBondingMsg, SignableNymNodeBondingMsg,
|
||||
};
|
||||
use nym_contracts_common::signing::{
|
||||
@@ -87,6 +92,23 @@ pub mod test_helpers {
|
||||
use std::str::FromStr;
|
||||
use std::time::Duration;
|
||||
|
||||
pub(crate) trait ExtractBankMsg {
|
||||
fn unwrap_bank_msg(self) -> Option<BankMsg>;
|
||||
}
|
||||
|
||||
impl ExtractBankMsg for Response {
|
||||
fn unwrap_bank_msg(self) -> Option<BankMsg> {
|
||||
for msg in self.messages {
|
||||
match msg.msg {
|
||||
CosmosMsg::Bank(bank_msg) => return Some(bank_msg),
|
||||
_ => continue,
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub enum NodeQueryType {
|
||||
ById(NodeId),
|
||||
ByIdentity(IdentityKey),
|
||||
@@ -168,7 +190,6 @@ pub mod test_helpers {
|
||||
self.env.clone()
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn execute(
|
||||
&mut self,
|
||||
info: MessageInfo,
|
||||
@@ -187,7 +208,6 @@ pub mod test_helpers {
|
||||
self.execute(self.mock_info(sender), msg)
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
pub fn execute_fn<F>(
|
||||
&mut self,
|
||||
exec_fn: F,
|
||||
@@ -213,7 +233,6 @@ pub mod test_helpers {
|
||||
self.execute_fn(exec_fn, info)
|
||||
}
|
||||
|
||||
#[allow(unused)]
|
||||
#[track_caller]
|
||||
pub fn assert_simple_execution<F>(&mut self, exec_fn: F, info: MessageInfo) -> Response
|
||||
where
|
||||
@@ -239,6 +258,36 @@ pub mod test_helpers {
|
||||
.unwrap_or_else(|err| panic!("{caller} failed with: '{err}' ({err:?})"))
|
||||
}
|
||||
|
||||
pub fn update_profit_margin_range(&mut self, range: ProfitMarginRange) {
|
||||
let current = query_contract_settings_params(self.deps()).unwrap();
|
||||
|
||||
self.execute(
|
||||
self.owner(),
|
||||
ExecuteMsg::UpdateContractStateParams {
|
||||
updated_parameters: ContractStateParams {
|
||||
profit_margin: range,
|
||||
..current
|
||||
},
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
pub fn update_operating_cost_range(&mut self, range: OperatingCostRange) {
|
||||
let current = query_contract_settings_params(self.deps()).unwrap();
|
||||
|
||||
self.execute(
|
||||
self.owner(),
|
||||
ExecuteMsg::UpdateContractStateParams {
|
||||
updated_parameters: ContractStateParams {
|
||||
interval_operating_cost: range,
|
||||
..current
|
||||
},
|
||||
},
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
pub fn get_node_id(&self, query_type: impl Into<NodeQueryType>) -> NodeId {
|
||||
match query_type.into() {
|
||||
NodeQueryType::ById(id) => id,
|
||||
@@ -452,6 +501,7 @@ pub mod test_helpers {
|
||||
(bond.node_id, keypair)
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
pub fn add_legacy_mixnode(&mut self, owner: &str, stake: Option<Uint128>) -> NodeId {
|
||||
let stake = self.make_mix_pledge(stake);
|
||||
let (mixnode, _, _) = self.mixnode_with_signature(owner, Some(stake.clone()));
|
||||
@@ -547,6 +597,14 @@ pub mod test_helpers {
|
||||
self.make_node_pledge(stake)
|
||||
}
|
||||
|
||||
pub fn mixnode_by_id(&self, node_id: NodeId) -> Option<MixNodeDetails> {
|
||||
get_mixnode_details_by_id(self.deps().storage, node_id).unwrap()
|
||||
}
|
||||
|
||||
pub fn nymnode_by_id(&self, node_id: NodeId) -> Option<NymNodeDetails> {
|
||||
get_node_details_by_id(self.deps().storage, node_id).unwrap()
|
||||
}
|
||||
|
||||
pub fn mixnode_bonding_signature(
|
||||
&mut self,
|
||||
key: &identity::PrivateKey,
|
||||
@@ -657,6 +715,7 @@ pub mod test_helpers {
|
||||
(gateway, owner_signature)
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
pub fn start_unbonding_mixnode(&mut self, mix_id: NodeId) {
|
||||
let bond_details = mixnodes_storage::mixnode_bonds()
|
||||
.load(self.deps().storage, mix_id)
|
||||
@@ -671,6 +730,7 @@ pub mod test_helpers {
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
pub fn start_unbonding_nymnode(&mut self, node_id: NodeId) {
|
||||
let bond_details = nymnodes_storage::nym_nodes()
|
||||
.load(self.deps().storage, node_id)
|
||||
|
||||
Reference in New Issue
Block a user