Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

test(P2P): add test for peer time sync validation #2304

Merged
merged 11 commits into from
Jan 7, 2025
1 change: 1 addition & 0 deletions mm2src/common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ path = "common.rs"
doctest = false

[features]
for-tests = []
track-ctx-pointer = ["shared_ref_counter/enable", "shared_ref_counter/log"]

[dependencies]
Expand Down
12 changes: 11 additions & 1 deletion mm2src/common/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1080,7 +1080,17 @@ impl<Id> Default for PagingOptionsEnum<Id> {
}

#[inline(always)]
pub fn get_utc_timestamp() -> i64 { Utc::now().timestamp() }
pub fn get_utc_timestamp() -> i64 {
// get_utc_timestamp for tests allowing to add some bias to 'now'
#[cfg(feature = "for-tests")]
return Utc::now().timestamp()
+ std::env::var("TEST_TIMESTAMP_OFFSET")
.map(|s| s.as_str().parse::<i64>().unwrap_or_default())
.unwrap_or_default();

#[cfg(not(feature = "for-tests"))]
return Utc::now().timestamp();
}

#[inline(always)]
pub fn get_utc_timestamp_nanos() -> i64 { Utc::now().timestamp_nanos() }
Expand Down
1 change: 1 addition & 0 deletions mm2src/mm2_main/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ winapi = "0.3"
[dev-dependencies]
coins = { path = "../coins", features = ["for-tests"] }
coins_activation = { path = "../coins_activation", features = ["for-tests"] }
common = { path = "../common", features = ["for-tests"] }
mm2_test_helpers = { path = "../mm2_test_helpers" }
trading_api = { path = "../trading_api", features = ["mocktopus"] }
mocktopus = "0.8.0"
Expand Down
81 changes: 81 additions & 0 deletions mm2src/mm2_main/tests/docker_tests/docker_tests_inner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use common::{block_on, block_on_f01, executor::Timer, get_utc_timestamp, now_sec
use crypto::privkey::key_pair_from_seed;
use crypto::{CryptoCtx, DerivationPath, KeyPairPolicy};
use http::StatusCode;
use mm2_libp2p::behaviours::atomicdex::MAX_TIME_GAP_FOR_CONNECTED_PEER;
use mm2_number::{BigDecimal, BigRational, MmNumber};
use mm2_test_helpers::for_tests::{check_my_swap_status_amounts, disable_coin, disable_coin_err, enable_eth_coin,
enable_eth_with_tokens_v2, erc20_dev_conf, eth_dev_conf, get_locked_amount,
Expand All @@ -25,6 +26,7 @@ use mm2_test_helpers::for_tests::{check_my_swap_status_amounts, disable_coin, di
use mm2_test_helpers::{get_passphrase, structs::*};
use serde_json::Value as Json;
use std::collections::{HashMap, HashSet};
use std::convert::TryInto;
use std::env;
use std::iter::FromIterator;
use std::str::FromStr;
Expand Down Expand Up @@ -5471,3 +5473,82 @@ fn test_approve_erc20() {

block_on(mm.stop()).unwrap();
}

#[test]
fn test_peer_time_sync_validation() {
let timeoffset_tolerable = TryInto::<i64>::try_into(MAX_TIME_GAP_FOR_CONNECTED_PEER).unwrap() - 1;
let timeoffset_too_big = TryInto::<i64>::try_into(MAX_TIME_GAP_FOR_CONNECTED_PEER).unwrap() + 1;
Comment on lines +5479 to +5480
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: casting to i64 with TryIntos and unwraps seems unnecessary since we are only using this value to convert it into a String.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I intended to have it as i64 to indicate it's possible to emulate time deviation in both directions, if anyone needs


let start_peers_with_time_offset = |offset: i64| -> (Json, Json) {
let (_ctx, _, bob_priv_key) = generate_utxo_coin_with_random_privkey("MYCOIN", 10.into());
let (_ctx, _, alice_priv_key) = generate_utxo_coin_with_random_privkey("MYCOIN1", 10.into());
let coins = json!([mycoin_conf(1000), mycoin1_conf(1000)]);
let bob_conf = Mm2TestConf::seednode(&hex::encode(bob_priv_key), &coins);
let mut mm_bob = block_on(MarketMakerIt::start_with_envs(
bob_conf.conf,
bob_conf.rpc_password,
None,
&[],
))
.unwrap();
let (_bob_dump_log, _bob_dump_dashboard) = mm_dump(&mm_bob.log_path);
block_on(mm_bob.wait_for_log(22., |log| log.contains(">>>>>>>>> DEX stats "))).unwrap();
let alice_conf =
Mm2TestConf::light_node(&hex::encode(alice_priv_key), &coins, &[mm_bob.ip.to_string().as_str()]);
let mut mm_alice = block_on(MarketMakerIt::start_with_envs(
alice_conf.conf,
alice_conf.rpc_password,
None,
&[("TEST_TIMESTAMP_OFFSET", offset.to_string().as_str())],
))
.unwrap();
let (_alice_dump_log, _alice_dump_dashboard) = mm_dump(&mm_alice.log_path);
block_on(mm_alice.wait_for_log(22., |log| log.contains(">>>>>>>>> DEX stats "))).unwrap();

let res_bob = block_on(mm_bob.rpc(&json!({
"userpass": mm_bob.userpass,
"method": "get_directly_connected_peers",
})))
.unwrap();
assert!(res_bob.0.is_success(), "!get_directly_connected_peers: {}", res_bob.1);
let bob_peers = serde_json::from_str::<Json>(&res_bob.1).unwrap();

let res_alice = block_on(mm_alice.rpc(&json!({
"userpass": mm_alice.userpass,
"method": "get_directly_connected_peers",
})))
.unwrap();
assert!(
res_alice.0.is_success(),
"!get_directly_connected_peers: {}",
res_alice.1
);
let alice_peers = serde_json::from_str::<Json>(&res_alice.1).unwrap();

block_on(mm_bob.stop()).unwrap();
block_on(mm_alice.stop()).unwrap();
(bob_peers, alice_peers)
};

// check with small time offset:
let (bob_peers, alice_peers) = start_peers_with_time_offset(timeoffset_tolerable);
assert!(
bob_peers["result"].as_object().unwrap().len() == 1,
"bob must have one peer"
);
assert!(
alice_peers["result"].as_object().unwrap().len() == 1,
"alice must have one peer"
);

// check with too big time offset:
let (bob_peers, alice_peers) = start_peers_with_time_offset(timeoffset_too_big);
assert!(
bob_peers["result"].as_object().unwrap().is_empty(),
"bob must have no peers"
);
assert!(
alice_peers["result"].as_object().unwrap().is_empty(),
"alice must have no peers"
);
}
1 change: 1 addition & 0 deletions mm2src/mm2_p2p/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,4 @@ timed-map = { version = "1.1.1", features = ["rustc-hash"] }
[dev-dependencies]
async-std = "1.6.2"
env_logger = "0.9.3"
common = { path = "../common", features = ["for-tests"] }
Loading