fixed existing mixnet unit tests

This commit is contained in:
Jędrzej Stuczyński
2023-02-28 11:48:36 +00:00
parent 7e9187ced6
commit 542e9baacf
8 changed files with 613 additions and 620 deletions
+62 -50
View File
@@ -305,71 +305,77 @@ mod test {
use crate::families::queries::{get_family_by_head, get_family_by_label};
use crate::families::storage::is_family_member;
use crate::mixnet_contract_settings::storage::minimum_mixnode_pledge;
use crate::support::tests::{fixtures, test_helpers};
use cosmwasm_std::testing::{mock_env, mock_info};
use crate::support::tests::fixtures;
use crate::support::tests::test_helpers::TestSetup;
use cosmwasm_std::testing::mock_info;
#[test]
fn test_family_crud() {
let mut deps = test_helpers::init_contract();
let env = mock_env();
let mut rng = test_helpers::test_rng();
let mut test = TestSetup::new();
let env = test.env();
let head = "alice";
let malicious_head = "timmy";
let member = "bob";
let minimum_pledge = minimum_mixnode_pledge(deps.as_ref().storage).unwrap();
let (head_mixnode, head_sig, head_keypair) =
test_helpers::mixnode_with_signature(&mut rng, head);
let (malicious_mixnode, malicious_sig, _malicious_keypair) =
test_helpers::mixnode_with_signature(&mut rng, malicious_head);
let minimum_pledge = minimum_mixnode_pledge(test.deps().storage).unwrap();
let cost_params = fixtures::mix_node_cost_params_fixture();
let member = "bob";
let (member_mixnode, member_sig, _) =
test_helpers::mixnode_with_signature(&mut rng, member);
let (head_mixnode, head_bond_sig, head_keypair) = test.mixnode_with_signature(head, None);
let (malicious_mixnode, malicious_bond_sig, malicious_keypair) =
test.mixnode_with_signature(malicious_head, None);
let (member_mixnode, member_bond_sig, member_keypair) =
test.mixnode_with_signature(member, None);
// we are informed that we didn't send enough funds
crate::mixnodes::transactions::try_add_mixnode(
deps.as_mut(),
test.deps_mut(),
env.clone(),
mock_info(head, &[minimum_pledge.clone()]),
head_mixnode.clone(),
cost_params.clone(),
head_sig.clone(),
head_bond_sig,
)
.unwrap();
crate::mixnodes::transactions::try_add_mixnode(
deps.as_mut(),
test.deps_mut(),
env.clone(),
mock_info(malicious_head, &[minimum_pledge.clone()]),
malicious_mixnode,
cost_params.clone(),
malicious_sig.clone(),
malicious_bond_sig,
)
.unwrap();
crate::mixnodes::transactions::try_add_mixnode(
deps.as_mut(),
test.deps_mut(),
env,
mock_info(member, &[minimum_pledge]),
member_mixnode.clone(),
cost_params,
member_sig.clone(),
member_bond_sig,
)
.unwrap();
try_create_family(deps.as_mut(), mock_info(head, &[]), head_sig, "test").unwrap();
let old_style_head_sig = head_keypair.private_key().sign_text(head);
let old_style_malicious_head_sig =
malicious_keypair.private_key().sign_text(malicious_head);
let old_style_member_sig = member_keypair.private_key().sign_text(member);
try_create_family(
test.deps_mut(),
mock_info(head, &[]),
old_style_head_sig,
"test",
)
.unwrap();
let family_head = FamilyHead::new(&head_mixnode.identity_key);
assert!(get_family(&family_head, &deps.storage).is_ok());
assert!(get_family(&family_head, test.deps().storage).is_ok());
let nope = try_create_family(
deps.as_mut(),
test.deps_mut(),
mock_info(malicious_head, &[]),
malicious_sig,
old_style_malicious_head_sig,
"test",
);
@@ -381,11 +387,11 @@ mod test {
},
}
let family = get_family_by_label("test", &deps.storage).unwrap();
let family = get_family_by_label("test", test.deps().storage).unwrap();
assert!(family.is_some());
assert_eq!(family.unwrap().head_identity(), family_head.identity());
let family = get_family_by_head(family_head.identity(), &deps.storage).unwrap();
let family = get_family_by_head(family_head.identity(), test.deps().storage).unwrap();
assert_eq!(family.head_identity(), family_head.identity());
let join_signature = head_keypair
@@ -394,41 +400,47 @@ mod test {
.to_base58_string();
try_join_family(
deps.as_mut(),
test.deps_mut(),
mock_info(member, &[]),
Some(member_sig.clone()),
Some(old_style_member_sig.clone()),
join_signature.clone(),
head_mixnode.identity_key.clone(),
)
.unwrap();
let family = get_family(&family_head, &deps.storage).unwrap();
let family = get_family(&family_head, test.deps().storage).unwrap();
assert!(is_family_member(&deps.storage, &family, &member_mixnode.identity_key).unwrap());
assert!(
is_family_member(test.deps().storage, &family, &member_mixnode.identity_key).unwrap()
);
try_leave_family(
deps.as_mut(),
test.deps_mut(),
mock_info(member, &[]),
member_sig.clone(),
old_style_member_sig.clone(),
head_mixnode.identity_key.clone(),
)
.unwrap();
let family = get_family(&family_head, &deps.storage).unwrap();
assert!(!is_family_member(&deps.storage, &family, &member_mixnode.identity_key).unwrap());
let family = get_family(&family_head, test.deps().storage).unwrap();
assert!(
!is_family_member(test.deps().storage, &family, &member_mixnode.identity_key).unwrap()
);
try_join_family(
deps.as_mut(),
test.deps_mut(),
mock_info(member, &[]),
Some(member_sig.clone()),
join_signature.clone(),
head_mixnode.identity_key.clone(),
Some(old_style_member_sig),
join_signature,
head_mixnode.identity_key,
)
.unwrap();
let family = get_family(&family_head, &deps.storage).unwrap();
let family = get_family(&family_head, test.deps().storage).unwrap();
assert!(is_family_member(&deps.storage, &family, &member_mixnode.identity_key).unwrap());
assert!(
is_family_member(test.deps().storage, &family, &member_mixnode.identity_key).unwrap()
);
// try_head_kick_member(
// deps.as_mut(),
@@ -438,8 +450,8 @@ mod test {
// )
// .unwrap();
// let family = get_family(&family_head, &deps.storage).unwrap();
// assert!(!is_family_member(&deps.storage, &family, &member_mixnode.identity_key).unwrap());
// let family = get_family(&family_head, test.deps().storage).unwrap();
// assert!(!is_family_member(test.deps().storage, &family, &member_mixnode.identity_key).unwrap());
}
#[cfg(test)]
@@ -456,7 +468,7 @@ mod test {
let head = "alice";
let (_, keypair) = test.add_dummy_mixnode_with_keypair(head, None);
let (_, keypair) = test.add_dummy_mixnode_with_proxy_and_keypair(head, None);
let sig = keypair.private_key().sign_text(head);
let res = try_create_family_on_behalf(
@@ -495,7 +507,7 @@ mod test {
let new_member = "vin-diesel";
let (_, head_keys) = test.create_dummy_mixnode_with_new_family(head, label);
let (_, member_keys) = test.add_dummy_mixnode_with_keypair(new_member, None);
let (_, member_keys) = test.add_dummy_mixnode_with_proxy_and_keypair(new_member, None);
// TODO: those signatures are WRONG and have to be c hanged
let join_signature = head_keys
@@ -542,7 +554,7 @@ mod test {
let new_member = "vin-diesel";
let (_, head_keys) = test.create_dummy_mixnode_with_new_family(head, label);
let (_, member_keys) = test.add_dummy_mixnode_with_keypair(new_member, None);
let (_, member_keys) = test.add_dummy_mixnode_with_proxy_and_keypair(new_member, None);
// TODO: those signatures are WRONG and have to be changed
let join_signature = head_keys
@@ -599,7 +611,7 @@ mod test {
let new_member = "vin-diesel";
let (_, head_keys) = test.create_dummy_mixnode_with_new_family(head, label);
let (_, member_keys) = test.add_dummy_mixnode_with_keypair(new_member, None);
let (_, member_keys) = test.add_dummy_mixnode_with_proxy_and_keypair(new_member, None);
// TODO: those signatures are WRONG and have to be c hanged
let join_signature = head_keys
@@ -613,7 +625,7 @@ mod test {
test.deps_mut(),
mock_info(vesting_contract.as_ref(), &[]),
new_member.to_string(),
Some(member_sig.clone()),
Some(member_sig),
join_signature,
head_identity,
)
+27 -46
View File
@@ -62,6 +62,7 @@ pub(crate) mod tests {
use crate::contract::execute;
use crate::support::tests;
use crate::support::tests::test_helpers;
use crate::support::tests::test_helpers::TestSetup;
use cosmwasm_std::testing::{mock_env, mock_info};
#[test]
@@ -73,27 +74,22 @@ pub(crate) mod tests {
#[test]
fn gateways_paged_retrieval_obeys_limits() {
let mut deps = test_helpers::init_contract();
let env = mock_env();
let mut rng = test_helpers::test_rng();
let mut test = TestSetup::new();
test.add_dummy_gateways(1000);
let limit = 2;
test_helpers::add_dummy_gateways(&mut rng, deps.as_mut(), env, 1000);
let page1 = query_gateways_paged(deps.as_ref(), None, Option::from(limit)).unwrap();
let page1 = query_gateways_paged(test.deps(), None, Option::from(limit)).unwrap();
assert_eq!(limit, page1.nodes.len() as u32);
}
#[test]
fn gateways_paged_retrieval_has_default_limit() {
let mut deps = test_helpers::init_contract();
let env = mock_env();
let mut rng = test_helpers::test_rng();
test_helpers::add_dummy_gateways(&mut rng, deps.as_mut(), env, 1000);
let mut test = TestSetup::new();
test.add_dummy_gateways(1000);
// query without explicitly setting a limit
let page1 = query_gateways_paged(deps.as_ref(), None, None).unwrap();
let page1 = query_gateways_paged(test.deps(), None, None).unwrap();
assert_eq!(
GATEWAY_BOND_DEFAULT_RETRIEVAL_LIMIT,
@@ -103,15 +99,12 @@ pub(crate) mod tests {
#[test]
fn gateways_paged_retrieval_has_max_limit() {
let mut deps = test_helpers::init_contract();
let env = mock_env();
let mut rng = test_helpers::test_rng();
test_helpers::add_dummy_gateways(&mut rng, deps.as_mut(), env, 1000);
let mut test = TestSetup::new();
test.add_dummy_gateways(1000);
// query with a crazily high limit in an attempt to use too many resources
let crazy_limit = 1000 * GATEWAY_BOND_DEFAULT_RETRIEVAL_LIMIT;
let page1 = query_gateways_paged(deps.as_ref(), None, Option::from(crazy_limit)).unwrap();
let page1 = query_gateways_paged(test.deps(), None, Option::from(crazy_limit)).unwrap();
// we default to a decent sized upper bound instead
let expected_limit = GATEWAY_BOND_MAX_RETRIEVAL_LIMIT;
@@ -121,25 +114,27 @@ pub(crate) mod tests {
#[test]
fn gateway_pagination_works() {
let mut deps = test_helpers::init_contract();
let _env = mock_env();
let mut rng = test_helpers::test_rng();
let stake = tests::fixtures::good_gateway_pledge();
// prepare 4 messages and identities that are sorted by the generated identities
// (because we query them in an ascended manner)
let mut exec_data = (0..4)
.map(|i| {
let sender = format!("nym-addr{}", i);
let (msg, identity) = tests::messages::valid_bond_gateway_msg(&mut rng, &sender);
let (msg, identity) = tests::messages::valid_bond_gateway_msg(
&mut rng,
deps.as_ref(),
stake.clone(),
&sender,
);
(msg, (sender, identity))
})
.collect::<Vec<_>>();
exec_data.sort_by(|(_, (_, id1)), (_, (_, id2))| id1.cmp(id2));
let (messages, sender_identities): (Vec<_>, Vec<_>) = exec_data.into_iter().unzip();
let info = mock_info(
&sender_identities[0].0.clone(),
&tests::fixtures::good_gateway_pledge(),
);
let info = mock_info(&sender_identities[0].0.clone(), &stake);
execute(deps.as_mut(), mock_env(), info, messages[0].clone()).unwrap();
let per_page = 2;
@@ -200,43 +195,29 @@ pub(crate) mod tests {
#[test]
fn query_for_gateway_owner_works() {
let mut deps = test_helpers::init_contract();
let env = mock_env();
let mut rng = test_helpers::test_rng();
let mut test = TestSetup::new();
// "fred" does not own a mixnode if there are no mixnodes
let res = query_owned_gateway(deps.as_ref(), "fred".to_string()).unwrap();
let res = query_owned_gateway(test.deps(), "fred".to_string()).unwrap();
assert!(res.gateway.is_none());
// mixnode was added to "bob", "fred" still does not own one
test_helpers::add_gateway(
&mut rng,
deps.as_mut(),
env.clone(),
"bob",
tests::fixtures::good_gateway_pledge(),
);
// gateway was added to "bob", "fred" still does not own one
test.add_dummy_gateway("bob", None);
let res = query_owned_gateway(deps.as_ref(), "fred".to_string()).unwrap();
let res = query_owned_gateway(test.deps(), "fred".to_string()).unwrap();
assert!(res.gateway.is_none());
// "fred" now owns a gateway!
test_helpers::add_gateway(
&mut rng,
deps.as_mut(),
env,
"fred",
tests::fixtures::good_gateway_pledge(),
);
test.add_dummy_gateway("fred", None);
let res = query_owned_gateway(deps.as_ref(), "fred".to_string()).unwrap();
let res = query_owned_gateway(test.deps(), "fred".to_string()).unwrap();
assert!(res.gateway.is_some());
// but after unbonding it, he doesn't own one anymore
crate::gateways::transactions::try_remove_gateway(deps.as_mut(), mock_info("fred", &[]))
crate::gateways::transactions::try_remove_gateway(test.deps_mut(), mock_info("fred", &[]))
.unwrap();
let res = query_owned_gateway(deps.as_ref(), "fred".to_string()).unwrap();
let res = query_owned_gateway(test.deps(), "fred".to_string()).unwrap();
assert!(res.gateway.is_none());
}
}
+43 -67
View File
@@ -192,38 +192,39 @@ pub(crate) fn _try_remove_gateway(
#[cfg(test)]
pub mod tests {
use crate::contract::execute;
use crate::gateways::queries;
use crate::gateways::transactions::{
try_add_gateway, try_add_gateway_on_behalf, try_remove_gateway_on_behalf,
};
use crate::interval::pending_events;
use crate::mixnet_contract_settings::storage::minimum_gateway_pledge;
use crate::support::tests;
use crate::support::tests::fixtures::{good_gateway_pledge, TEST_COIN_DENOM};
use crate::support::tests::fixtures;
use crate::support::tests::fixtures::good_gateway_pledge;
use crate::support::tests::test_helpers::TestSetup;
use crate::support::tests::{fixtures, test_helpers};
use cosmwasm_std::testing::{mock_env, mock_info};
use cosmwasm_std::{coin, Addr, BankMsg, Response, Uint128};
use cosmwasm_std::testing::mock_info;
use cosmwasm_std::{Addr, BankMsg, Response, Uint128};
use mixnet_contract_common::error::MixnetContractError;
use mixnet_contract_common::events::new_gateway_unbonding_event;
use mixnet_contract_common::ExecuteMsg;
#[test]
fn gateway_add() {
let mut deps = test_helpers::init_contract();
let env = mock_env();
let mut rng = test_helpers::test_rng();
let mut test = TestSetup::new();
// if we fail validation (by say not sending enough funds
let sender = "alice";
let minimum_pledge = minimum_gateway_pledge(deps.as_ref().storage).unwrap();
let minimum_pledge = minimum_gateway_pledge(test.deps().storage).unwrap();
let mut insufficient_pledge = minimum_pledge.clone();
insufficient_pledge.amount -= Uint128::new(1000);
let info = mock_info(sender, &[insufficient_pledge.clone()]);
let (gateway, sig) = test_helpers::gateway_with_signature(&mut rng, sender);
let (gateway, sig) =
test.gateway_with_signature(sender, Some(vec![insufficient_pledge.clone()]));
let env = test.env();
let result = try_add_gateway(
deps.as_mut(),
test.deps_mut(),
env.clone(),
info,
gateway.clone(),
@@ -242,47 +243,23 @@ pub mod tests {
// if the signature provided is invalid, the bonding also fails
let info = mock_info(sender, &[minimum_pledge]);
let result = try_add_gateway(
deps.as_mut(),
env.clone(),
info.clone(),
gateway.clone(),
"bad-signature".into(),
);
assert!(matches!(
result,
Err(MixnetContractError::MalformedEd25519Signature(..))
));
// if there was already a gateway bonded by particular user
test_helpers::add_gateway(
&mut rng,
deps.as_mut(),
env.clone(),
sender,
fixtures::good_gateway_pledge(),
);
test.add_dummy_gateway(sender, None);
// it fails
let result = try_add_gateway(deps.as_mut(), env.clone(), info, gateway, sig);
let result = try_add_gateway(test.deps_mut(), env.clone(), info, gateway, sig);
assert_eq!(Err(MixnetContractError::AlreadyOwnsGateway), result);
// the same holds if the user already owns a mixnode
let sender2 = "mixnode-owner";
let mix_id = test_helpers::add_mixnode(
&mut rng,
deps.as_mut(),
env.clone(),
sender2,
vec![coin(100_000_000, TEST_COIN_DENOM)],
);
let mix_id = test.add_dummy_mixnode(sender2, None);
let info = mock_info(sender2, &fixtures::good_gateway_pledge());
let (gateway, sig) = test_helpers::gateway_with_signature(&mut rng, sender2);
let (gateway, sig) = test.gateway_with_signature(sender2, None);
let result = try_add_gateway(
deps.as_mut(),
test.deps_mut(),
env.clone(),
info.clone(),
gateway.clone(),
@@ -291,12 +268,17 @@ pub mod tests {
assert_eq!(Err(MixnetContractError::AlreadyOwnsMixnode), result);
// but after he unbonds it, it's all fine again
pending_events::unbond_mixnode(deps.as_mut(), &env, 123, mix_id).unwrap();
pending_events::unbond_mixnode(test.deps_mut(), &env, 123, mix_id).unwrap();
let result = try_add_gateway(deps.as_mut(), env, info, gateway, sig);
let result = try_add_gateway(test.deps_mut(), env, info, gateway, sig);
assert!(result.is_ok());
}
#[test]
fn adding_gateway_with_invalid_signatures() {
todo!()
}
#[test]
fn gateway_add_with_illegal_proxy() {
let mut test = TestSetup::new();
@@ -306,7 +288,7 @@ pub mod tests {
let vesting_contract = test.vesting_contract();
let owner = "alice";
let (gateway, sig) = test_helpers::gateway_with_signature(&mut test.rng, owner);
let (gateway, sig) = test.gateway_with_signature(owner, None);
let res = try_add_gateway_on_behalf(
test.deps_mut(),
@@ -329,14 +311,13 @@ pub mod tests {
#[test]
fn gateway_remove() {
let mut deps = test_helpers::init_contract();
let mut rng = test_helpers::test_rng();
let env = mock_env();
let mut test = TestSetup::new();
let env = test.env();
// try unbond when no nodes exist yet
let info = mock_info("anyone", &[]);
let msg = ExecuteMsg::UnbondGateway {};
let result = execute(deps.as_mut(), mock_env(), info, msg);
let result = execute(test.deps_mut(), env.clone(), info, msg);
// we're told that there is no node for our address
assert_eq!(
@@ -347,18 +328,12 @@ pub mod tests {
);
// let's add a node owned by bob
test_helpers::add_gateway(
&mut rng,
deps.as_mut(),
env.clone(),
"bob",
fixtures::good_gateway_pledge(),
);
test.add_dummy_gateway("bob", None);
// attempt to unbond fred's node, which doesn't exist
let info = mock_info("fred", &[]);
let msg = ExecuteMsg::UnbondGateway {};
let result = execute(deps.as_mut(), mock_env(), info, msg);
let result = execute(test.deps_mut(), env.clone(), info, msg);
assert_eq!(
result,
Err(MixnetContractError::NoAssociatedGatewayBond {
@@ -367,28 +342,27 @@ pub mod tests {
);
// bob's node is still there
let nodes = tests::queries::get_gateways(&mut deps);
let nodes = queries::query_gateways_paged(test.deps(), None, None)
.unwrap()
.nodes;
assert_eq!(1, nodes.len());
let first_node = &nodes[0];
assert_eq!(&Addr::unchecked("bob"), first_node.owner());
// add a node owned by fred
let fred_identity = test_helpers::add_gateway(
&mut rng,
deps.as_mut(),
env,
"fred",
tests::fixtures::good_gateway_pledge(),
);
let fred_identity = test.add_dummy_gateway("fred", None);
// let's make sure we now have 2 nodes:
assert_eq!(2, tests::queries::get_gateways(&mut deps).len());
let nodes = queries::query_gateways_paged(test.deps(), None, None)
.unwrap()
.nodes;
assert_eq!(2, nodes.len());
// unbond fred's node
let info = mock_info("fred", &[]);
let msg = ExecuteMsg::UnbondGateway {};
let remove_fred = execute(deps.as_mut(), mock_env(), info.clone(), msg).unwrap();
let remove_fred = execute(test.deps_mut(), env.clone(), info.clone(), msg).unwrap();
// we should see a funds transfer from the contract back to fred
let expected_message = BankMsg::Send {
@@ -410,9 +384,11 @@ pub mod tests {
assert_eq!(expected_response, remove_fred);
// only 1 node now exists, owned by bob:
let gateway_bonds = tests::queries::get_gateways(&mut deps);
assert_eq!(1, gateway_bonds.len());
assert_eq!(&Addr::unchecked("bob"), gateway_bonds[0].owner());
let nodes = queries::query_gateways_paged(test.deps(), None, None)
.unwrap()
.nodes;
assert_eq!(1, nodes.len());
assert_eq!(&Addr::unchecked("bob"), nodes[0].owner());
}
#[test]
+71 -147
View File
@@ -273,30 +273,24 @@ pub(crate) mod tests {
#[cfg(test)]
mod mixnode_bonds {
use super::*;
use crate::support::tests::fixtures::good_mixnode_pledge;
#[test]
fn obeys_limits() {
let mut deps = test_helpers::init_contract();
let env = mock_env();
let mut rng = test_helpers::test_rng();
let mut test = TestSetup::new();
test.add_dummy_mixnodes(1000);
let limit = 2;
test_helpers::add_dummy_mixnodes(&mut rng, deps.as_mut(), env, 1000);
let page1 = query_mixnode_bonds_paged(deps.as_ref(), None, Some(limit)).unwrap();
let page1 = query_mixnode_bonds_paged(test.deps(), None, Some(limit)).unwrap();
assert_eq!(limit, page1.nodes.len() as u32);
}
#[test]
fn has_default_limit() {
let mut deps = test_helpers::init_contract();
let env = mock_env();
let mut rng = test_helpers::test_rng();
test_helpers::add_dummy_mixnodes(&mut rng, deps.as_mut(), env, 1000);
let mut test = TestSetup::new();
test.add_dummy_mixnodes(1000);
// query without explicitly setting a limit
let page1 = query_mixnode_bonds_paged(deps.as_ref(), None, None).unwrap();
let page1 = query_mixnode_bonds_paged(test.deps(), None, None).unwrap();
assert_eq!(
MIXNODE_BOND_DEFAULT_RETRIEVAL_LIMIT,
@@ -306,14 +300,12 @@ pub(crate) mod tests {
#[test]
fn has_max_limit() {
let mut deps = test_helpers::init_contract();
let env = mock_env();
let mut rng = test_helpers::test_rng();
test_helpers::add_dummy_mixnodes(&mut rng, deps.as_mut(), env, 1000);
let mut test = TestSetup::new();
test.add_dummy_mixnodes(1000);
// query with a crazily high limit in an attempt to use too many resources
let crazy_limit = 1000;
let page1 = query_mixnode_bonds_paged(deps.as_ref(), None, Some(crazy_limit)).unwrap();
let page1 = query_mixnode_bonds_paged(test.deps(), None, Some(crazy_limit)).unwrap();
// we default to a decent sized upper bound instead
assert_eq!(MIXNODE_BOND_MAX_RETRIEVAL_LIMIT, page1.nodes.len() as u32);
@@ -322,63 +314,43 @@ pub(crate) mod tests {
#[test]
fn pagination_works() {
// as we add mixnodes, we're always inserting them in ascending manner due to monotonically increasing id
let mut deps = test_helpers::init_contract();
let env = mock_env();
let mut rng = test_helpers::test_rng();
let mut test = TestSetup::new();
test_helpers::add_mixnode(
&mut rng,
deps.as_mut(),
env.clone(),
"addr1",
good_mixnode_pledge(),
);
test.add_dummy_mixnode("addr1", None);
let per_page = 2;
let page1 = query_mixnode_bonds_paged(deps.as_ref(), None, Some(per_page)).unwrap();
let page1 = query_mixnode_bonds_paged(test.deps(), None, Some(per_page)).unwrap();
// page should have 1 result on it
assert_eq!(1, page1.nodes.len());
// save another
test_helpers::add_mixnode(
&mut rng,
deps.as_mut(),
env.clone(),
"addr2",
good_mixnode_pledge(),
);
test.add_dummy_mixnode("addr2", None);
// page1 should have 2 results on it
let page1 = query_mixnode_bonds_paged(deps.as_ref(), None, Some(per_page)).unwrap();
let page1 = query_mixnode_bonds_paged(test.deps(), None, Some(per_page)).unwrap();
assert_eq!(2, page1.nodes.len());
test_helpers::add_mixnode(
&mut rng,
deps.as_mut(),
env.clone(),
"addr3",
good_mixnode_pledge(),
);
test.add_dummy_mixnode("addr3", None);
// page1 still has the same 2 results
let another_page1 =
query_mixnode_bonds_paged(deps.as_ref(), None, Some(per_page)).unwrap();
query_mixnode_bonds_paged(test.deps(), None, Some(per_page)).unwrap();
assert_eq!(2, another_page1.nodes.len());
assert_eq!(page1, another_page1);
// retrieving the next page should start after the last key on this page
let start_after = page1.start_next_after.unwrap();
let page2 = query_mixnode_bonds_paged(deps.as_ref(), Some(start_after), Some(per_page))
.unwrap();
let page2 =
query_mixnode_bonds_paged(test.deps(), Some(start_after), Some(per_page)).unwrap();
assert_eq!(1, page2.nodes.len());
// save another one
test_helpers::add_mixnode(&mut rng, deps.as_mut(), env, "addr4", good_mixnode_pledge());
test.add_dummy_mixnode("addr4", None);
let page2 = query_mixnode_bonds_paged(deps.as_ref(), Some(start_after), Some(per_page))
.unwrap();
let page2 =
query_mixnode_bonds_paged(test.deps(), Some(start_after), Some(per_page)).unwrap();
// now we have 2 pages, with 2 results on the second page
assert_eq!(2, page2.nodes.len());
@@ -388,29 +360,24 @@ pub(crate) mod tests {
#[cfg(test)]
mod mixnode_details {
use super::*;
use crate::support::tests::fixtures::good_mixnode_pledge;
#[test]
fn obeys_limits() {
let mut deps = test_helpers::init_contract();
let env = mock_env();
let mut rng = test_helpers::test_rng();
let mut test = TestSetup::new();
test.add_dummy_mixnodes(1000);
let limit = 2;
test_helpers::add_dummy_mixnodes(&mut rng, deps.as_mut(), env, 1000);
let page1 = query_mixnodes_details_paged(deps.as_ref(), None, Some(limit)).unwrap();
let page1 = query_mixnodes_details_paged(test.deps(), None, Some(limit)).unwrap();
assert_eq!(limit, page1.nodes.len() as u32);
}
#[test]
fn has_default_limit() {
let mut deps = test_helpers::init_contract();
let env = mock_env();
let mut rng = test_helpers::test_rng();
test_helpers::add_dummy_mixnodes(&mut rng, deps.as_mut(), env, 1000);
let mut test = TestSetup::new();
test.add_dummy_mixnodes(1000);
// query without explicitly setting a limit
let page1 = query_mixnodes_details_paged(deps.as_ref(), None, None).unwrap();
let page1 = query_mixnodes_details_paged(test.deps(), None, None).unwrap();
assert_eq!(
MIXNODE_DETAILS_DEFAULT_RETRIEVAL_LIMIT,
@@ -420,15 +387,12 @@ pub(crate) mod tests {
#[test]
fn has_max_limit() {
let mut deps = test_helpers::init_contract();
let env = mock_env();
let mut rng = test_helpers::test_rng();
test_helpers::add_dummy_mixnodes(&mut rng, deps.as_mut(), env, 1000);
let mut test = TestSetup::new();
test.add_dummy_mixnodes(1000);
// query with a crazily high limit in an attempt to use too many resources
let crazy_limit = 1000;
let page1 =
query_mixnodes_details_paged(deps.as_ref(), None, Some(crazy_limit)).unwrap();
let page1 = query_mixnodes_details_paged(test.deps(), None, Some(crazy_limit)).unwrap();
// we default to a decent sized upper bound instead
assert_eq!(
@@ -440,64 +404,44 @@ pub(crate) mod tests {
#[test]
fn pagination_works() {
// as we add mixnodes, we're always inserting them in ascending manner due to monotonically increasing id
let mut deps = test_helpers::init_contract();
let env = mock_env();
let mut rng = test_helpers::test_rng();
let mut test = TestSetup::new();
test_helpers::add_mixnode(
&mut rng,
deps.as_mut(),
env.clone(),
"addr1",
good_mixnode_pledge(),
);
test.add_dummy_mixnode("addr1", None);
let per_page = 2;
let page1 = query_mixnodes_details_paged(deps.as_ref(), None, Some(per_page)).unwrap();
let page1 = query_mixnodes_details_paged(test.deps(), None, Some(per_page)).unwrap();
// page should have 1 result on it
assert_eq!(1, page1.nodes.len());
// save another
test_helpers::add_mixnode(
&mut rng,
deps.as_mut(),
env.clone(),
"addr2",
good_mixnode_pledge(),
);
test.add_dummy_mixnode("addr2", None);
// page1 should have 2 results on it
let page1 = query_mixnodes_details_paged(deps.as_ref(), None, Some(per_page)).unwrap();
let page1 = query_mixnodes_details_paged(test.deps(), None, Some(per_page)).unwrap();
assert_eq!(2, page1.nodes.len());
test_helpers::add_mixnode(
&mut rng,
deps.as_mut(),
env.clone(),
"addr3",
good_mixnode_pledge(),
);
test.add_dummy_mixnode("addr3", None);
// page1 still has the same 2 results
let another_page1 =
query_mixnodes_details_paged(deps.as_ref(), None, Some(per_page)).unwrap();
query_mixnodes_details_paged(test.deps(), None, Some(per_page)).unwrap();
assert_eq!(2, another_page1.nodes.len());
assert_eq!(page1, another_page1);
// retrieving the next page should start after the last key on this page
let start_after = page1.start_next_after.unwrap();
let page2 =
query_mixnodes_details_paged(deps.as_ref(), Some(start_after), Some(per_page))
query_mixnodes_details_paged(test.deps(), Some(start_after), Some(per_page))
.unwrap();
assert_eq!(1, page2.nodes.len());
// save another one
test_helpers::add_mixnode(&mut rng, deps.as_mut(), env, "addr4", good_mixnode_pledge());
test.add_dummy_mixnode("addr4", None);
let page2 =
query_mixnodes_details_paged(deps.as_ref(), Some(start_after), Some(per_page))
query_mixnodes_details_paged(test.deps(), Some(start_after), Some(per_page))
.unwrap();
// now we have 2 pages, with 2 results on the second page
@@ -1135,26 +1079,18 @@ pub(crate) mod tests {
#[test]
fn query_for_owned_mixnode() {
let mut deps = test_helpers::init_contract();
let env = mock_env();
let mut rng = test_helpers::test_rng();
let mut test = TestSetup::new();
let address = "mix-owner".to_string();
// when it doesnt exist
let res = query_owned_mixnode(deps.as_ref(), address.clone()).unwrap();
let res = query_owned_mixnode(test.deps(), address.clone()).unwrap();
assert!(res.mixnode_details.is_none());
assert_eq!(address, res.address);
// when it [fully] exists
let id = test_helpers::add_mixnode(
&mut rng,
deps.as_mut(),
env,
&address,
good_mixnode_pledge(),
);
let res = query_owned_mixnode(deps.as_ref(), address.clone()).unwrap();
let id = test.add_dummy_mixnode(&address, None);
let res = query_owned_mixnode(test.deps(), address.clone()).unwrap();
let details = res.mixnode_details.unwrap();
assert_eq!(address, details.bond_information.owner);
assert_eq!(
@@ -1171,30 +1107,27 @@ pub(crate) mod tests {
rewarding_details.delegates = Decimal::raw(12345);
rewarding_details.unique_delegations = 1;
rewards_storage::MIXNODE_REWARDING
.save(deps.as_mut().storage, id, &rewarding_details)
.save(test.deps_mut().storage, id, &rewarding_details)
.unwrap();
pending_events::unbond_mixnode(deps.as_mut(), &mock_env(), 123, id).unwrap();
let res = query_owned_mixnode(deps.as_ref(), address.clone()).unwrap();
pending_events::unbond_mixnode(test.deps_mut(), &mock_env(), 123, id).unwrap();
let res = query_owned_mixnode(test.deps(), address.clone()).unwrap();
assert!(res.mixnode_details.is_none());
assert_eq!(address, res.address);
}
#[test]
fn query_for_mixnode_details() {
let mut deps = test_helpers::init_contract();
let env = mock_env();
let mut rng = test_helpers::test_rng();
let mut test = TestSetup::new();
// no node under this id
let res = query_mixnode_details(deps.as_ref(), 42).unwrap();
let res = query_mixnode_details(test.deps(), 42).unwrap();
assert!(res.mixnode_details.is_none());
assert_eq!(42, res.mix_id);
// it exists
let mix_id =
test_helpers::add_mixnode(&mut rng, deps.as_mut(), env, "foomp", good_mixnode_pledge());
let res = query_mixnode_details(deps.as_ref(), mix_id).unwrap();
let mix_id = test.add_dummy_mixnode("foomp", None);
let res = query_mixnode_details(test.deps(), mix_id).unwrap();
let details = res.mixnode_details.unwrap();
assert_eq!(mix_id, details.bond_information.mix_id);
assert_eq!(
@@ -1227,18 +1160,15 @@ pub(crate) mod tests {
#[test]
fn query_for_mixnode_rewarding_details() {
let mut deps = test_helpers::init_contract();
let env = mock_env();
let mut rng = test_helpers::test_rng();
let mut test = TestSetup::new();
// no node under this id
let res = query_mixnode_rewarding_details(deps.as_ref(), 42).unwrap();
let res = query_mixnode_rewarding_details(test.deps(), 42).unwrap();
assert!(res.rewarding_details.is_none());
assert_eq!(42, res.mix_id);
let mix_id =
test_helpers::add_mixnode(&mut rng, deps.as_mut(), env, "foomp", good_mixnode_pledge());
let res = query_mixnode_rewarding_details(deps.as_ref(), mix_id).unwrap();
let mix_id = test.add_dummy_mixnode("foomp", None);
let res = query_mixnode_rewarding_details(test.deps(), mix_id).unwrap();
let details = res.rewarding_details.unwrap();
assert_eq!(
fixtures::mix_node_cost_params_fixture(),
@@ -1249,80 +1179,74 @@ pub(crate) mod tests {
#[test]
fn query_for_unbonded_mixnode() {
let mut deps = test_helpers::init_contract();
let env = mock_env();
let mut rng = test_helpers::test_rng();
let mut test = TestSetup::new();
let sender = "mix-owner";
// no node under this id
let res = query_unbonded_mixnode(deps.as_ref(), 42).unwrap();
let res = query_unbonded_mixnode(test.deps(), 42).unwrap();
assert!(res.unbonded_info.is_none());
assert_eq!(42, res.mix_id);
// add and unbond the mixnode
let mix_id =
test_helpers::add_mixnode(&mut rng, deps.as_mut(), env, sender, good_mixnode_pledge());
pending_events::unbond_mixnode(deps.as_mut(), &mock_env(), 123, mix_id).unwrap();
let mix_id = test.add_dummy_mixnode(sender, None);
pending_events::unbond_mixnode(test.deps_mut(), &mock_env(), 123, mix_id).unwrap();
let res = query_unbonded_mixnode(deps.as_ref(), mix_id).unwrap();
let res = query_unbonded_mixnode(test.deps(), mix_id).unwrap();
assert_eq!(res.unbonded_info.unwrap().owner, sender);
assert_eq!(mix_id, res.mix_id);
}
#[test]
fn query_for_stake_saturation() {
let mut deps = test_helpers::init_contract();
let env = mock_env();
let mut rng = test_helpers::test_rng();
let mut test = TestSetup::new();
// no node under this id
let res = query_stake_saturation(deps.as_ref(), 42).unwrap();
let res = query_stake_saturation(test.deps(), 42).unwrap();
assert!(res.current_saturation.is_none());
assert!(res.uncapped_saturation.is_none());
assert_eq!(42, res.mix_id);
let rewarding_params = rewards_storage::REWARDING_PARAMS
.load(deps.as_ref().storage)
.load(test.deps().storage)
.unwrap();
let saturation_point = rewarding_params.interval.stake_saturation_point;
let mix_id =
test_helpers::add_mixnode(&mut rng, deps.as_mut(), env, "foomp", good_mixnode_pledge());
let mix_id = test.add_dummy_mixnode("foomp", None);
// below saturation point
// there's only the base pledge without any delegation
let expected =
Decimal::from_atomics(good_mixnode_pledge()[0].amount, 0).unwrap() / saturation_point;
let res = query_stake_saturation(deps.as_ref(), mix_id).unwrap();
let res = query_stake_saturation(test.deps(), mix_id).unwrap();
assert_eq!(expected, res.current_saturation.unwrap());
assert_eq!(expected, res.uncapped_saturation.unwrap());
assert_eq!(mix_id, res.mix_id);
// exactly at saturation point
let mut mix_rewarding = rewards_storage::MIXNODE_REWARDING
.load(deps.as_ref().storage, mix_id)
.load(test.deps().storage, mix_id)
.unwrap();
mix_rewarding.operator = saturation_point;
rewards_storage::MIXNODE_REWARDING
.save(deps.as_mut().storage, mix_id, &mix_rewarding)
.save(test.deps_mut().storage, mix_id, &mix_rewarding)
.unwrap();
let res = query_stake_saturation(deps.as_ref(), mix_id).unwrap();
let res = query_stake_saturation(test.deps(), mix_id).unwrap();
assert_eq!(Decimal::one(), res.current_saturation.unwrap());
assert_eq!(Decimal::one(), res.uncapped_saturation.unwrap());
assert_eq!(mix_id, res.mix_id);
// above the saturation point
let mut mix_rewarding = rewards_storage::MIXNODE_REWARDING
.load(deps.as_ref().storage, mix_id)
.load(test.deps().storage, mix_id)
.unwrap();
mix_rewarding.delegates = mix_rewarding.operator * Decimal::percent(150);
rewards_storage::MIXNODE_REWARDING
.save(deps.as_mut().storage, mix_id, &mix_rewarding)
.save(test.deps_mut().storage, mix_id, &mix_rewarding)
.unwrap();
let res = query_stake_saturation(deps.as_ref(), mix_id).unwrap();
let res = query_stake_saturation(test.deps(), mix_id).unwrap();
assert_eq!(Decimal::one(), res.current_saturation.unwrap());
assert_eq!(Decimal::percent(250), res.uncapped_saturation.unwrap());
assert_eq!(mix_id, res.mix_id);
+50 -73
View File
@@ -404,7 +404,7 @@ pub mod tests {
use crate::support::tests::fixtures::{good_mixnode_pledge, TEST_COIN_DENOM};
use crate::support::tests::test_helpers::TestSetup;
use crate::support::tests::{fixtures, test_helpers};
use cosmwasm_std::testing::{mock_env, mock_info};
use cosmwasm_std::testing::mock_info;
use cosmwasm_std::{Order, StdResult, Uint128};
use mixnet_contract_common::{
EpochState, EpochStatus, ExecuteMsg, Layer, LayerDistribution, Percent,
@@ -412,23 +412,23 @@ pub mod tests {
#[test]
fn mixnode_add() {
let mut deps = test_helpers::init_contract();
let env = mock_env();
let mut rng = test_helpers::test_rng();
let mut test = TestSetup::new();
let env = test.env();
let sender = "alice";
let minimum_pledge = minimum_mixnode_pledge(deps.as_ref().storage).unwrap();
let minimum_pledge = minimum_mixnode_pledge(test.deps().storage).unwrap();
let mut insufficient_pledge = minimum_pledge.clone();
insufficient_pledge.amount -= Uint128::new(1000);
// if we don't send enough funds
let info = mock_info(sender, &[insufficient_pledge.clone()]);
let (mixnode, sig, _) = test_helpers::mixnode_with_signature(&mut rng, sender);
let (mixnode, sig, _) =
test.mixnode_with_signature(sender, Some(vec![insufficient_pledge.clone()]));
let cost_params = fixtures::mix_node_cost_params_fixture();
// we are informed that we didn't send enough funds
let result = try_add_mixnode(
deps.as_mut(),
test.deps_mut(),
env.clone(),
info,
mixnode.clone(),
@@ -446,31 +446,12 @@ pub mod tests {
// if the signature provided is invalid, the bonding also fails
let info = mock_info(sender, &[minimum_pledge]);
let result = try_add_mixnode(
deps.as_mut(),
env.clone(),
info.clone(),
mixnode.clone(),
cost_params.clone(),
"bad-signature".into(),
);
assert!(matches!(
result,
Err(MixnetContractError::MalformedEd25519Signature(..))
));
// if there was already a mixnode bonded by particular user
test_helpers::add_mixnode(
&mut rng,
deps.as_mut(),
env.clone(),
sender,
fixtures::good_mixnode_pledge(),
);
test.add_dummy_mixnode(sender, None);
// it fails
let result = try_add_mixnode(
deps.as_mut(),
test.deps_mut(),
env.clone(),
info,
mixnode,
@@ -482,19 +463,13 @@ pub mod tests {
// the same holds if the user already owns a gateway
let sender2 = "gateway-owner";
test_helpers::add_gateway(
&mut rng,
deps.as_mut(),
env.clone(),
sender2,
tests::fixtures::good_gateway_pledge(),
);
test.add_dummy_gateway(sender2, None);
let info = mock_info(sender2, &tests::fixtures::good_mixnode_pledge());
let (mixnode, sig, _) = test_helpers::mixnode_with_signature(&mut rng, sender2);
let (mixnode, sig, _) = test.mixnode_with_signature(sender2, None);
let result = try_add_mixnode(
deps.as_mut(),
test.deps_mut(),
env.clone(),
info.clone(),
mixnode.clone(),
@@ -505,14 +480,14 @@ pub mod tests {
// but after he unbonds it, it's all fine again
let msg = ExecuteMsg::UnbondGateway {};
execute(deps.as_mut(), mock_env(), info.clone(), msg).unwrap();
execute(test.deps_mut(), env.clone(), info.clone(), msg).unwrap();
let result = try_add_mixnode(deps.as_mut(), env, info, mixnode, cost_params, sig);
let result = try_add_mixnode(test.deps_mut(), env, info, mixnode, cost_params, sig);
assert!(result.is_ok());
// make sure we got assigned the next id (note: we have already bonded a mixnode before in this test)
let bond = must_get_mixnode_bond_by_owner(deps.as_ref().storage, &Addr::unchecked(sender2))
.unwrap();
let bond =
must_get_mixnode_bond_by_owner(test.deps().storage, &Addr::unchecked(sender2)).unwrap();
assert_eq!(2, bond.mix_id);
// and make sure we're on layer 2 (because it was the next empty one)
@@ -524,10 +499,12 @@ pub mod tests {
layer2: 1,
layer3: 0,
};
assert_eq!(
expected,
storage::LAYERS.load(deps.as_ref().storage).unwrap()
)
assert_eq!(expected, storage::LAYERS.load(test.deps().storage).unwrap())
}
#[test]
fn adding_mixnode_with_invalid_signatures() {
todo!()
}
#[test]
@@ -539,10 +516,9 @@ pub mod tests {
let vesting_contract = test.vesting_contract();
let owner = "alice";
let (mixnode, sig, _) = test_helpers::mixnode_with_signature(&mut test.rng, owner);
let (mixnode, sig, _) = test.mixnode_with_signature(owner, None);
let cost_params = fixtures::mix_node_cost_params_fixture();
// we are informed that we didn't send enough funds
let res = try_add_mixnode_on_behalf(
test.deps_mut(),
env,
@@ -931,52 +907,53 @@ pub mod tests {
#[test]
fn adding_mixnode_with_duplicate_sphinx_key_errors_out() {
let mut deps = test_helpers::init_contract();
let mut rng = test_helpers::test_rng();
let mut test = TestSetup::new();
let env = test.env();
let keypair1 = nym_crypto::asymmetric::identity::KeyPair::new(&mut rng);
let keypair2 = nym_crypto::asymmetric::identity::KeyPair::new(&mut rng);
let sig1 = keypair1.private_key().sign_text("alice");
let sig2 = keypair1.private_key().sign_text("bob");
let keypair1 = nym_crypto::asymmetric::identity::KeyPair::new(&mut test.rng);
let keypair2 = nym_crypto::asymmetric::identity::KeyPair::new(&mut test.rng);
let info_alice = mock_info("alice", &tests::fixtures::good_mixnode_pledge());
let info_bob = mock_info("bob", &tests::fixtures::good_mixnode_pledge());
let mut mixnode = MixNode {
let cost_params = fixtures::mix_node_cost_params_fixture();
let mixnode1 = MixNode {
host: "1.2.3.4".to_string(),
mix_port: 1234,
verloc_port: 1234,
http_api_port: 1234,
sphinx_key: nym_crypto::asymmetric::encryption::KeyPair::new(&mut rng)
sphinx_key: nym_crypto::asymmetric::encryption::KeyPair::new(&mut test.rng)
.public_key()
.to_base58_string(),
identity_key: keypair1.public_key().to_base58_string(),
version: "v0.1.2.3".to_string(),
};
let cost_params = fixtures::mix_node_cost_params_fixture();
// change identity but reuse sphinx key
let mut mixnode2 = mixnode1.clone();
mixnode2.sphinx_key = nym_crypto::asymmetric::encryption::KeyPair::new(&mut test.rng)
.public_key()
.to_base58_string();
let sig1 =
test.mixnode_bonding_signature(keypair1.private_key(), "alice", mixnode1.clone(), None);
let sig2 =
test.mixnode_bonding_signature(keypair2.private_key(), "bob", mixnode2.clone(), None);
let info_alice = mock_info("alice", &tests::fixtures::good_mixnode_pledge());
let info_bob = mock_info("bob", &tests::fixtures::good_mixnode_pledge());
assert!(try_add_mixnode(
deps.as_mut(),
mock_env(),
test.deps_mut(),
env.clone(),
info_alice,
mixnode.clone(),
mixnode1,
cost_params.clone(),
sig1
)
.is_ok());
mixnode.identity_key = keypair2.public_key().to_base58_string();
// change identity but reuse sphinx key
assert!(try_add_mixnode(
deps.as_mut(),
mock_env(),
info_bob,
mixnode,
cost_params,
sig2
)
.is_err());
assert!(
try_add_mixnode(test.deps_mut(), env, info_bob, mixnode2, cost_params, sig2).is_err()
);
}
#[cfg(test)]
+18 -9
View File
@@ -1,25 +1,34 @@
use cosmwasm_std::{Coin, Deps};
use mixnet_contract_common::{ExecuteMsg, Gateway, IdentityKey};
use nym_crypto::asymmetric::identity;
use rand_chacha::rand_core::{CryptoRng, RngCore};
use crate::support::tests;
use crate::support::tests::test_helpers::{ed25519_sign_message, gateway_bonding_sign_payload};
pub(crate) fn valid_bond_gateway_msg(
mut rng: impl RngCore + CryptoRng,
deps: Deps<'_>,
stake: Vec<Coin>,
sender: &str,
) -> (ExecuteMsg, IdentityKey) {
let keypair = nym_crypto::asymmetric::identity::KeyPair::new(&mut rng);
let owner_signature = keypair
.private_key()
.sign(sender.as_bytes())
.to_base58_string();
let keypair = identity::KeyPair::new(&mut rng);
let identity_key = keypair.public_key().to_base58_string();
let legit_sphinx_keys = nym_crypto::asymmetric::encryption::KeyPair::new(&mut rng);
let gateway = Gateway {
identity_key,
sphinx_key: legit_sphinx_keys.public_key().to_base58_string(),
..tests::fixtures::gateway_fixture()
};
let msg = gateway_bonding_sign_payload(deps, sender, None, gateway.clone(), stake);
let owner_signature = ed25519_sign_message(msg, keypair.private_key());
let identity_key = keypair.public_key().to_base58_string();
(
ExecuteMsg::BondGateway {
gateway: Gateway {
identity_key: identity_key.clone(),
..tests::fixtures::gateway_fixture()
},
gateway,
owner_signature,
},
identity_key,
+342 -189
View File
@@ -5,8 +5,6 @@
pub mod fixtures;
#[cfg(test)]
pub mod messages;
#[cfg(test)]
pub mod queries;
#[cfg(test)]
pub mod test_helpers {
@@ -24,7 +22,8 @@ pub mod test_helpers {
use crate::interval::{pending_events, storage as interval_storage};
use crate::mixnet_contract_settings::storage as mixnet_params_storage;
use crate::mixnet_contract_settings::storage::{
minimum_mixnode_pledge, rewarding_denom, rewarding_validator_address,
minimum_gateway_pledge, minimum_mixnode_pledge, rewarding_denom,
rewarding_validator_address,
};
use crate::mixnodes::storage as mixnodes_storage;
use crate::mixnodes::storage::mixnode_bonds;
@@ -36,8 +35,11 @@ pub mod test_helpers {
};
use crate::rewards::storage as rewards_storage;
use crate::rewards::transactions::try_reward_mixnode;
use crate::signing::storage as signing_storage;
use crate::support::tests;
use crate::support::tests::fixtures::TEST_COIN_DENOM;
use crate::support::tests::fixtures::{
good_gateway_pledge, good_mixnode_pledge, TEST_COIN_DENOM,
};
use cosmwasm_std::testing::mock_dependencies;
use cosmwasm_std::testing::mock_env;
use cosmwasm_std::testing::mock_info;
@@ -59,13 +61,19 @@ pub mod test_helpers {
use mixnet_contract_common::rewarding::simulator::Simulator;
use mixnet_contract_common::rewarding::RewardDistribution;
use mixnet_contract_common::{
Delegation, EpochState, EpochStatus, Gateway, IdentityKey, InitialRewardingParams,
InstantiateMsg, Interval, MixId, MixNode, MixNodeBond, Percent, RewardedSetNodeStatus,
Delegation, EpochState, EpochStatus, Gateway, GatewayBondingPayload, IdentityKey,
InitialRewardingParams, InstantiateMsg, Interval, MixId, MixNode, MixNodeBond,
MixnodeBondingPayload, Percent, RewardedSetNodeStatus, SignableGatewayBondingMsg,
SignableMixNodeBondingMsg,
};
use nym_contracts_common::signing::{
ContractMessageContent, MessageSignature, SignableMessage, SigningAlgorithm,
};
use nym_crypto::asymmetric::identity;
use nym_crypto::asymmetric::identity::KeyPair;
use rand_chacha::rand_core::{CryptoRng, RngCore, SeedableRng};
use rand_chacha::ChaCha20Rng;
use serde::Serialize;
use std::time::Duration;
pub fn assert_eq_with_leeway(a: Uint128, b: Uint128, leeway: Uint128) {
@@ -190,7 +198,7 @@ pub mod test_helpers {
head: &str,
label: &str,
) -> (MixId, identity::KeyPair) {
let (mix_id, keys) = self.add_dummy_mixnode_with_keypair(head, None);
let (mix_id, keys) = self.add_dummy_mixnode_with_proxy_and_keypair(head, None);
let sig = keys.private_key().sign_text(head);
try_create_family(self.deps_mut(), mock_info(head, &[]), sig, label).unwrap();
@@ -198,6 +206,57 @@ pub mod test_helpers {
}
pub fn add_dummy_mixnode(&mut self, owner: &str, stake: Option<Uint128>) -> MixId {
let stake = self.make_mix_pledge(stake);
let (mixnode, owner_signature, _) =
self.mixnode_with_signature(owner, Some(stake.clone()));
let info = mock_info(owner, stake.as_ref());
let current_id_counter = mixnodes_storage::MIXNODE_ID_COUNTER
.may_load(self.deps().storage)
.unwrap()
.unwrap_or_default();
let env = self.env();
try_add_mixnode(
self.deps_mut(),
env,
info,
mixnode,
tests::fixtures::mix_node_cost_params_fixture(),
owner_signature,
)
.unwrap();
// newly added mixnode gets assigned the current counter + 1
current_id_counter + 1
}
pub fn add_dummy_gateway(&mut self, sender: &str, stake: Option<Uint128>) -> IdentityKey {
let stake = self.make_gateway_pledge(stake);
let (gateway, owner_signature) =
self.gateway_with_signature(sender, Some(stake.clone()));
let info = mock_info(sender, &stake);
let key = gateway.identity_key.clone();
let env = self.env();
try_add_gateway(self.deps_mut(), env, info, gateway, owner_signature).unwrap();
key
}
pub fn add_dummy_mixnodes(&mut self, n: usize) {
for i in 0..n {
self.add_dummy_mixnode(&format!("owner{i}"), None);
}
}
pub fn add_dummy_gateways(&mut self, n: usize) {
for i in 0..n {
self.add_dummy_gateway(&format!("owner{i}"), None);
}
}
pub fn make_mix_pledge(&self, stake: Option<Uint128>) -> Vec<Coin> {
let stake = match stake {
Some(amount) => {
let denom = rewarding_denom(self.deps().storage).unwrap();
@@ -205,36 +264,61 @@ pub mod test_helpers {
}
None => minimum_mixnode_pledge(self.deps.as_ref().storage).unwrap(),
};
let env = self.env();
add_mixnode(&mut self.rng, self.deps.as_mut(), env, owner, vec![stake])
vec![stake]
}
pub fn add_dummy_mixnode_with_keypair(
pub fn make_gateway_pledge(&self, stake: Option<Uint128>) -> Vec<Coin> {
let stake = match stake {
Some(amount) => {
let denom = rewarding_denom(self.deps().storage).unwrap();
Coin { denom, amount }
}
None => minimum_gateway_pledge(self.deps.as_ref().storage).unwrap(),
};
vec![stake]
}
pub fn mixnode_bonding_signature(
&mut self,
key: &identity::PrivateKey,
owner: &str,
mixnode: MixNode,
stake: Option<Uint128>,
) -> MessageSignature {
let stake = self.make_mix_pledge(stake);
let msg = mixnode_bonding_sign_payload(self.deps(), owner, None, mixnode, stake);
ed25519_sign_message(msg, key)
}
pub fn add_dummy_mixnode_with_proxy_and_keypair(
&mut self,
owner: &str,
stake: Option<Uint128>,
) -> (MixId, identity::KeyPair) {
let stake = match stake {
Some(amount) => {
let denom = rewarding_denom(self.deps().storage).unwrap();
Coin { denom, amount }
}
None => minimum_mixnode_pledge(self.deps.as_ref().storage).unwrap(),
};
let stake = self.make_mix_pledge(stake);
let proxy = self.vesting_contract();
let keypair = identity::KeyPair::new(&mut self.rng);
let owner_signature = keypair
.private_key()
.sign(owner.as_bytes())
.to_base58_string();
let identity_key = keypair.public_key().to_base58_string();
let legit_sphinx_keys = nym_crypto::asymmetric::encryption::KeyPair::new(&mut self.rng);
let legit_sphinx_key = nym_crypto::asymmetric::encryption::KeyPair::new(&mut self.rng);
let mixnode = MixNode {
identity_key,
sphinx_key: legit_sphinx_keys.public_key().to_base58_string(),
..tests::fixtures::mix_node_fixture()
};
let info = mock_info(proxy.as_str(), &[stake]);
let key = keypair.public_key().to_base58_string();
let msg = mixnode_bonding_sign_payload(
self.deps(),
owner,
Some(proxy.clone()),
mixnode.clone(),
stake.clone(),
);
let owner_signature = ed25519_sign_message(msg, keypair.private_key());
let info = mock_info(proxy.as_str(), &stake);
let current_id_counter = mixnodes_storage::MIXNODE_ID_COUNTER
.may_load(self.deps().storage)
.unwrap()
@@ -245,11 +329,7 @@ pub mod test_helpers {
self.deps_mut(),
env,
info,
MixNode {
identity_key: key,
sphinx_key: legit_sphinx_key.public_key().to_base58_string(),
..tests::fixtures::mix_node_fixture()
},
mixnode,
tests::fixtures::mix_node_cost_params_fixture(),
owner.to_string(),
owner_signature,
@@ -265,7 +345,8 @@ pub mod test_helpers {
owner: &str,
stake: Option<Uint128>,
) -> MixId {
self.add_dummy_mixnode_with_keypair(owner, stake).0
self.add_dummy_mixnode_with_proxy_and_keypair(owner, stake)
.0
}
pub fn set_illegal_mixnode_proxy(&mut self, mix_id: MixId, proxy: Addr) {
@@ -312,14 +393,26 @@ pub mod test_helpers {
None => minimum_mixnode_pledge(self.deps.as_ref().storage).unwrap(),
};
let keypair = identity::KeyPair::new(&mut self.rng);
let identity_key = keypair.public_key().to_base58_string();
let legit_sphinx_keys = nym_crypto::asymmetric::encryption::KeyPair::new(&mut self.rng);
let proxy = self.vesting_contract();
let legit_sphinx_key = nym_crypto::asymmetric::encryption::KeyPair::new(&mut self.rng);
let keypair = nym_crypto::asymmetric::identity::KeyPair::new(&mut self.rng);
let owner_signature = keypair
.private_key()
.sign(owner.as_bytes())
.to_base58_string();
let gateway = Gateway {
identity_key,
sphinx_key: legit_sphinx_keys.public_key().to_base58_string(),
..tests::fixtures::gateway_fixture()
};
let msg = gateway_bonding_sign_payload(
self.deps(),
owner,
Some(proxy.clone()),
gateway.clone(),
vec![stake.clone()],
);
let owner_signature = ed25519_sign_message(msg, keypair.private_key());
let env = self.env();
let info = mock_info(proxy.as_ref(), &[stake]);
@@ -328,11 +421,7 @@ pub mod test_helpers {
self.deps_mut(),
env,
info,
Gateway {
identity_key: keypair.public_key().to_base58_string(),
sphinx_key: legit_sphinx_key.public_key().to_base58_string(),
..tests::fixtures::gateway_fixture()
},
gateway,
owner.to_string(),
owner_signature,
)
@@ -351,6 +440,63 @@ pub mod test_helpers {
mix_id
}
pub fn mixnode_with_signature(
&mut self,
sender: &str,
stake: Option<Vec<Coin>>,
) -> (MixNode, MessageSignature, KeyPair) {
let stake = stake.unwrap_or(good_mixnode_pledge());
let keypair = identity::KeyPair::new(&mut self.rng);
let identity_key = keypair.public_key().to_base58_string();
let legit_sphinx_keys = nym_crypto::asymmetric::encryption::KeyPair::new(&mut self.rng);
let mixnode = MixNode {
identity_key,
sphinx_key: legit_sphinx_keys.public_key().to_base58_string(),
..tests::fixtures::mix_node_fixture()
};
let msg = mixnode_bonding_sign_payload(
self.deps(),
sender,
None,
mixnode.clone(),
stake.clone(),
);
let owner_signature = ed25519_sign_message(msg, keypair.private_key());
(mixnode, owner_signature, keypair)
}
pub fn gateway_with_signature(
&mut self,
sender: &str,
stake: Option<Vec<Coin>>,
) -> (Gateway, MessageSignature) {
let stake = stake.unwrap_or(good_gateway_pledge());
let keypair = identity::KeyPair::new(&mut self.rng);
let identity_key = keypair.public_key().to_base58_string();
let legit_sphinx_keys = nym_crypto::asymmetric::encryption::KeyPair::new(&mut self.rng);
let gateway = Gateway {
identity_key,
sphinx_key: legit_sphinx_keys.public_key().to_base58_string(),
..tests::fixtures::gateway_fixture()
};
let msg = gateway_bonding_sign_payload(
self.deps(),
sender,
None,
gateway.clone(),
stake.clone(),
);
let owner_signature = ed25519_sign_message(msg, keypair.private_key());
(gateway, owner_signature)
}
pub fn start_unbonding_mixnode(&mut self, mix_id: MixId) {
let bond_details = mixnodes_storage::mixnode_bonds()
.load(self.deps().storage, mix_id)
@@ -714,6 +860,22 @@ pub mod test_helpers {
}
}
pub fn ed25519_sign_message<T: Serialize>(
message: SignableMessage<T>,
private_key: &identity::PrivateKey,
) -> MessageSignature {
match message.algorithm {
SigningAlgorithm::Ed25519 => {
let plaintext = message.to_plaintext().unwrap();
let signature = private_key.sign(&plaintext);
MessageSignature::from(signature.to_bytes().as_ref())
}
SigningAlgorithm::Secp256k1 => {
unimplemented!()
}
}
}
pub fn simulator_from_single_node_state(deps: Deps<'_>, node: MixId) -> Simulator {
let mix_rewarding = rewards_storage::MIXNODE_REWARDING
.load(deps.storage, node)
@@ -800,54 +962,54 @@ pub mod test_helpers {
perform_pending_interval_actions(deps.branch(), &env, None).unwrap();
}
pub fn mixnode_with_signature(
mut rng: impl RngCore + CryptoRng,
sender: &str,
) -> (MixNode, String, KeyPair) {
let keypair = nym_crypto::asymmetric::identity::KeyPair::new(&mut rng);
let legit_sphinx_key = nym_crypto::asymmetric::encryption::KeyPair::new(&mut rng);
let owner_signature = keypair
.private_key()
.sign(sender.as_bytes())
.to_base58_string();
// pub fn mixnode_with_signature(
// mut rng: impl RngCore + CryptoRng,
// deps: Deps<'_>,
// sender: &str,
// stake: Option<Vec<Coin>>,
// ) -> (MixNode, MessageSignature, KeyPair) {
// // hehe stupid workaround for bypassing the immutable borrow and removing duplicate code
//
// let stake = stake.unwrap_or(good_mixnode_pledge());
//
// let keypair = identity::KeyPair::new(&mut rng);
// let identity_key = keypair.public_key().to_base58_string();
// let legit_sphinx_keys = nym_crypto::asymmetric::encryption::KeyPair::new(&mut rng);
//
// let mixnode = MixNode {
// identity_key,
// sphinx_key: legit_sphinx_keys.public_key().to_base58_string(),
// ..tests::fixtures::mix_node_fixture()
// };
// let msg = mixnode_bonding_sign_payload(deps, sender, None, mixnode.clone(), stake.clone());
// let owner_signature = ed25519_sign_message(msg, keypair.private_key());
//
// (mixnode, owner_signature, keypair)
// }
let identity_key = keypair.public_key().to_base58_string();
let sphinx_key = legit_sphinx_key.public_key().to_base58_string();
(
MixNode {
identity_key,
sphinx_key,
..tests::fixtures::mix_node_fixture()
},
owner_signature,
keypair,
)
}
pub fn gateway_with_signature(
mut rng: impl RngCore + CryptoRng,
sender: &str,
) -> (Gateway, String) {
let keypair = nym_crypto::asymmetric::identity::KeyPair::new(&mut rng);
let legit_sphinx_key = nym_crypto::asymmetric::encryption::KeyPair::new(&mut rng);
let owner_signature = keypair
.private_key()
.sign(sender.as_bytes())
.to_base58_string();
let identity_key = keypair.public_key().to_base58_string();
let sphinx_key = legit_sphinx_key.public_key().to_base58_string();
(
Gateway {
identity_key,
sphinx_key,
..tests::fixtures::gateway_fixture()
},
owner_signature,
)
}
// pub fn gateway_with_signature(
// mut rng: impl RngCore + CryptoRng,
// deps: Deps<'_>,
// sender: &str,
// stake: Option<Vec<Coin>>,
// ) -> (Gateway, MessageSignature) {
// let stake = stake.unwrap_or(good_gateway_pledge());
//
// let keypair = identity::KeyPair::new(&mut rng);
// let identity_key = keypair.public_key().to_base58_string();
// let legit_sphinx_keys = nym_crypto::asymmetric::encryption::KeyPair::new(&mut rng);
//
// let gateway = Gateway {
// identity_key,
// sphinx_key: legit_sphinx_keys.public_key().to_base58_string(),
// ..tests::fixtures::gateway_fixture()
// };
//
// let msg = gateway_bonding_sign_payload(deps, sender, None, gateway.clone(), stake.clone());
// let owner_signature = ed25519_sign_message(msg, keypair.private_key());
//
// (gateway, owner_signature)
// }
pub fn add_dummy_delegations(mut deps: DepsMut<'_>, env: Env, mix_id: MixId, n: usize) {
for i in 0..n {
@@ -864,39 +1026,22 @@ pub mod test_helpers {
}
}
pub fn add_dummy_mixnodes(
mut rng: impl RngCore + CryptoRng,
mut deps: DepsMut<'_>,
env: Env,
n: usize,
) {
for i in 0..n {
add_mixnode(
&mut rng,
deps.branch(),
env.clone(),
&format!("owner{}", i),
tests::fixtures::good_mixnode_pledge(),
);
}
}
pub fn add_dummy_gateways(
mut rng: impl RngCore + CryptoRng,
mut deps: DepsMut<'_>,
env: Env,
n: usize,
) {
for i in 0..n {
add_gateway(
&mut rng,
deps.branch(),
env.clone(),
&format!("owner{}", i),
tests::fixtures::good_mixnode_pledge(),
);
}
}
// pub fn add_dummy_mixnodes(
// mut rng: impl RngCore + CryptoRng,
// mut deps: DepsMut<'_>,
// env: Env,
// n: usize,
// ) {
// for i in 0..n {
// add_mixnode(
// &mut rng,
// deps.branch(),
// env.clone(),
// &format!("owner{}", i),
// tests::fixtures::good_mixnode_pledge(),
// );
// }
// }
pub fn add_dummy_unbonded_mixnodes(
mut rng: impl RngCore + CryptoRng,
@@ -968,81 +1113,89 @@ pub mod test_helpers {
id
}
// note to whoever wants to refactor this function, you dont want to grab rng here directly
// via `let rng = test_rng()`
// because it's extremely likely you might end up calling `add_mixnode()` multiple times
// in the same test and thus you're going to get mixnodes with the same keys and that's
// not what you want (presumably)
pub fn add_mixnode(
mut rng: impl RngCore + CryptoRng,
deps: DepsMut<'_>,
env: Env,
sender: &str,
pub fn mixnode_bonding_sign_payload(
deps: Deps<'_>,
owner: &str,
proxy: Option<Addr>,
mixnode: MixNode,
stake: Vec<Coin>,
) -> MixId {
let keypair = nym_crypto::asymmetric::identity::KeyPair::new(&mut rng);
let owner_signature = keypair
.private_key()
.sign(sender.as_bytes())
.to_base58_string();
) -> SignableMixNodeBondingMsg {
let cost_params = tests::fixtures::mix_node_cost_params_fixture();
let nonce =
signing_storage::get_signing_nonce(deps.storage, Addr::unchecked(owner)).unwrap();
let legit_sphinx_key = nym_crypto::asymmetric::encryption::KeyPair::new(&mut rng);
let info = mock_info(sender, &stake);
let key = keypair.public_key().to_base58_string();
let current_id_counter = mixnodes_storage::MIXNODE_ID_COUNTER
.may_load(deps.storage)
.unwrap()
.unwrap_or_default();
try_add_mixnode(
deps,
env,
info,
MixNode {
identity_key: key,
sphinx_key: legit_sphinx_key.public_key().to_base58_string(),
..tests::fixtures::mix_node_fixture()
},
tests::fixtures::mix_node_cost_params_fixture(),
owner_signature,
)
.unwrap();
// newly added mixnode gets assigned the current counter + 1
current_id_counter + 1
let payload = MixnodeBondingPayload::new(mixnode, cost_params);
let content = ContractMessageContent::new(Addr::unchecked(owner), proxy, stake, payload);
SignableMixNodeBondingMsg::new(nonce, content)
}
// same note as with `add_mixnode`
pub fn add_gateway(
mut rng: impl RngCore + CryptoRng,
deps: DepsMut<'_>,
env: Env,
sender: &str,
pub fn gateway_bonding_sign_payload(
deps: Deps<'_>,
owner: &str,
proxy: Option<Addr>,
gateway: Gateway,
stake: Vec<Coin>,
) -> String {
let keypair = nym_crypto::asymmetric::identity::KeyPair::new(&mut rng);
let owner_signature = keypair
.private_key()
.sign(sender.as_bytes())
.to_base58_string();
) -> SignableGatewayBondingMsg {
let nonce =
signing_storage::get_signing_nonce(deps.storage, Addr::unchecked(owner)).unwrap();
let info = mock_info(sender, &stake);
let key = keypair.public_key().to_base58_string();
try_add_gateway(
deps,
env,
info,
Gateway {
identity_key: key.clone(),
..tests::fixtures::gateway_fixture()
},
owner_signature,
)
.unwrap();
key
let payload = GatewayBondingPayload::new(gateway);
let content = ContractMessageContent::new(Addr::unchecked(owner), proxy, stake, payload);
SignableGatewayBondingMsg::new(nonce, content)
}
// // note to whoever wants to refactor this function, you dont want to grab rng here directly
// // via `let rng = test_rng()`
// // because it's extremely likely you might end up calling `add_mixnode()` multiple times
// // in the same test and thus you're going to get mixnodes with the same keys and that's
// // not what you want (presumably)
// pub fn add_mixnode(
// rng: impl RngCore + CryptoRng,
// deps: DepsMut<'_>,
// env: Env,
// sender: &str,
// stake: Vec<Coin>,
// ) -> MixId {
// let (mixnode, owner_signature, keypair) =
// mixnode_with_signature(rng, deps.as_ref(), sender, Some(stake));
//
// let info = mock_info(sender, stake.as_ref());
// let current_id_counter = mixnodes_storage::MIXNODE_ID_COUNTER
// .may_load(deps.storage)
// .unwrap()
// .unwrap_or_default();
//
// try_add_mixnode(
// deps,
// env,
// info,
// mixnode,
// tests::fixtures::mix_node_cost_params_fixture(),
// owner_signature,
// )
// .unwrap();
//
// // newly added mixnode gets assigned the current counter + 1
// current_id_counter + 1
// }
//
// // same note as with `add_mixnode`
// pub fn add_gateway(
// rng: impl RngCore + CryptoRng,
// deps: DepsMut<'_>,
// env: Env,
// sender: &str,
// stake: Vec<Coin>,
// ) -> String {
// let (gateway, owner_signature) =
// gateway_with_signature(rng, deps.as_ref(), sender, Some(stake.clone()));
//
// let info = mock_info(sender, &stake);
// let key = gateway.identity_key.clone();
// try_add_gateway(deps, env, info, gateway, owner_signature).unwrap();
// key
// }
fn initial_rewarding_params() -> InitialRewardingParams {
let reward_pool = 250_000_000_000_000u128;
let staking_supply = 100_000_000_000_000u128;
@@ -1,39 +0,0 @@
use crate::contract::query;
use cosmwasm_std::{
from_binary,
testing::{mock_env, MockApi, MockQuerier, MockStorage},
OwnedDeps,
};
use mixnet_contract_common::{GatewayBond, PagedGatewayResponse, QueryMsg};
// I honestly don't know why we're using this way of querying in tests, but I couldn't be bothered to change it
// since I haven't done anything to gateways
pub fn get_gateways(deps: &mut OwnedDeps<MockStorage, MockApi, MockQuerier>) -> Vec<GatewayBond> {
let result = query(
deps.as_ref(),
mock_env(),
QueryMsg::GetGateways {
start_after: None,
limit: None,
},
)
.unwrap();
let page: PagedGatewayResponse = from_binary(&result).unwrap();
if page.start_next_after.is_some() {
let next_page = query(
deps.as_ref(),
mock_env(),
QueryMsg::GetGateways {
start_after: page.start_next_after,
limit: None,
},
)
.unwrap();
let next_page: PagedGatewayResponse = from_binary(&next_page).unwrap();
if !next_page.nodes.is_empty() {
panic!("we didn't manage to get all gateways in a single query")
}
}
page.nodes
}