use std::time::{Duration, Instant};
use chrono::Utc;
use zebra_chain::{
parameters::Network::*,
serialization::{DateTime32, Duration32},
};
use crate::{
constants::{CONCURRENT_ADDRESS_CHANGE_PERIOD, MAX_PEER_ACTIVE_FOR_GOSSIP},
protocol::types::PeerServices,
PeerSocketAddr,
};
use super::{super::MetaAddr, check};
const TEST_TIME_ERROR_MARGIN: Duration32 = Duration32::from_seconds(1);
#[test]
fn sanitize_extremes() {
let _init_guard = zebra_test::init();
let min_time_entry = MetaAddr {
addr: "127.0.0.1:8233".parse().unwrap(),
services: Default::default(),
untrusted_last_seen: Some(u32::MIN.into()),
last_response: Some(u32::MIN.into()),
rtt: Some(Duration::ZERO),
ping_sent_at: None,
last_attempt: None,
last_failure: None,
last_connection_state: Default::default(),
misbehavior_score: Default::default(),
is_inbound: false,
};
let max_time_entry = MetaAddr {
addr: "127.0.0.1:8233".parse().unwrap(),
services: Default::default(),
untrusted_last_seen: Some(u32::MAX.into()),
last_response: Some(u32::MAX.into()),
rtt: Some(Duration::ZERO),
ping_sent_at: None,
last_attempt: None,
last_failure: None,
last_connection_state: Default::default(),
misbehavior_score: Default::default(),
is_inbound: false,
};
if let Some(min_sanitized) = min_time_entry.sanitize(&Mainnet) {
check::sanitize_avoids_leaks(&min_time_entry, &min_sanitized);
}
if let Some(max_sanitized) = max_time_entry.sanitize(&Mainnet) {
check::sanitize_avoids_leaks(&max_time_entry, &max_sanitized);
}
}
#[test]
fn new_local_listener_is_gossipable() {
let _init_guard = zebra_test::init();
let instant_now = Instant::now();
let chrono_now = Utc::now();
let local_now: DateTime32 = chrono_now.try_into().expect("will succeed until 2038");
let address = PeerSocketAddr::from(([192, 168, 180, 9], 10_000));
let peer =
MetaAddr::new_local_listener_change(address).into_new_meta_addr(instant_now, local_now);
assert!(peer.is_active_for_gossip(chrono_now));
}
#[test]
fn gossiped_peer_reportedly_to_be_seen_recently_is_gossipable() {
let _init_guard = zebra_test::init();
let chrono_now = Utc::now();
let address = PeerSocketAddr::from(([192, 168, 180, 9], 10_000));
let offset = MAX_PEER_ACTIVE_FOR_GOSSIP
.checked_sub(TEST_TIME_ERROR_MARGIN)
.expect("Test margin is too large");
let last_seen = DateTime32::now()
.checked_sub(offset)
.expect("Offset is too large");
let peer = MetaAddr::new_gossiped_meta_addr(address, PeerServices::NODE_NETWORK, last_seen);
assert!(peer.is_active_for_gossip(chrono_now));
}
#[test]
fn gossiped_peer_reportedly_seen_in_the_future_is_gossipable() {
let _init_guard = zebra_test::init();
let chrono_now = Utc::now();
let address = PeerSocketAddr::from(([192, 168, 180, 9], 10_000));
let last_seen = DateTime32::now()
.checked_add(MAX_PEER_ACTIVE_FOR_GOSSIP)
.expect("Reachable peer duration is too large");
let peer = MetaAddr::new_gossiped_meta_addr(address, PeerServices::NODE_NETWORK, last_seen);
assert!(peer.is_active_for_gossip(chrono_now));
}
#[test]
fn gossiped_peer_reportedly_seen_long_ago_is_not_gossipable() {
let _init_guard = zebra_test::init();
let chrono_now = Utc::now();
let address = PeerSocketAddr::from(([192, 168, 180, 9], 10_000));
let offset = MAX_PEER_ACTIVE_FOR_GOSSIP
.checked_add(TEST_TIME_ERROR_MARGIN)
.expect("Test margin is too large");
let last_seen = DateTime32::now()
.checked_sub(offset)
.expect("Offset is too large");
let peer = MetaAddr::new_gossiped_meta_addr(address, PeerServices::NODE_NETWORK, last_seen);
assert!(!peer.is_active_for_gossip(chrono_now));
}
#[test]
fn recently_responded_peer_is_gossipable() {
let _init_guard = zebra_test::init();
let instant_now = Instant::now();
let chrono_now = Utc::now();
let local_now: DateTime32 = chrono_now.try_into().expect("will succeed until 2038");
let address = PeerSocketAddr::from(([192, 168, 180, 9], 10_000));
let peer_seed = MetaAddr::new_initial_peer(address).into_new_meta_addr(instant_now, local_now);
let peer = MetaAddr::new_responded(address, None)
.apply_to_meta_addr(peer_seed, instant_now, chrono_now)
.expect("Failed to create MetaAddr for responded peer");
assert!(peer.is_active_for_gossip(chrono_now));
}
#[test]
fn not_so_recently_responded_peer_is_still_gossipable() {
let _init_guard = zebra_test::init();
let instant_now = Instant::now();
let chrono_now = Utc::now();
let local_now: DateTime32 = chrono_now.try_into().expect("will succeed until 2038");
let address = PeerSocketAddr::from(([192, 168, 180, 9], 10_000));
let peer_seed = MetaAddr::new_initial_peer(address).into_new_meta_addr(instant_now, local_now);
let mut peer = MetaAddr::new_responded(address, None)
.apply_to_meta_addr(peer_seed, instant_now, chrono_now)
.expect("Failed to create MetaAddr for responded peer");
let offset = MAX_PEER_ACTIVE_FOR_GOSSIP
.checked_sub(TEST_TIME_ERROR_MARGIN)
.expect("Test margin is too large");
let last_response = DateTime32::now()
.checked_sub(offset)
.expect("Offset is too large");
peer.set_last_response(last_response);
assert!(peer.is_active_for_gossip(chrono_now));
}
#[test]
fn responded_long_ago_peer_is_not_gossipable() {
let _init_guard = zebra_test::init();
let instant_now = Instant::now();
let chrono_now = Utc::now();
let local_now: DateTime32 = chrono_now.try_into().expect("will succeed until 2038");
let address = PeerSocketAddr::from(([192, 168, 180, 9], 10_000));
let peer_seed = MetaAddr::new_initial_peer(address).into_new_meta_addr(instant_now, local_now);
let mut peer = MetaAddr::new_responded(address, None)
.apply_to_meta_addr(peer_seed, instant_now, chrono_now)
.expect("Failed to create MetaAddr for responded peer");
let offset = MAX_PEER_ACTIVE_FOR_GOSSIP
.checked_add(TEST_TIME_ERROR_MARGIN)
.expect("Test margin is too large");
let last_response = DateTime32::now()
.checked_sub(offset)
.expect("Offset is too large");
peer.set_last_response(last_response);
assert!(!peer.is_active_for_gossip(chrono_now));
}
#[test]
fn long_delayed_change_is_not_applied() {
let _init_guard = zebra_test::init();
let instant_now = Instant::now();
let chrono_now = Utc::now();
let local_now: DateTime32 = chrono_now.try_into().expect("will succeed until 2038");
let address = PeerSocketAddr::from(([192, 168, 180, 9], 10_000));
let peer_seed = MetaAddr::new_initial_peer(address).into_new_meta_addr(instant_now, local_now);
let peer = MetaAddr::new_responded(address, None)
.apply_to_meta_addr(peer_seed, instant_now, chrono_now)
.expect("Failed to create MetaAddr for responded peer");
let instant_early = instant_now - (CONCURRENT_ADDRESS_CHANGE_PERIOD * 3);
let chrono_early = chrono_now
- chrono::Duration::from_std(CONCURRENT_ADDRESS_CHANGE_PERIOD * 3)
.expect("constant is valid");
let change = MetaAddr::new_errored(address, PeerServices::NODE_NETWORK);
let outcome = change.apply_to_meta_addr(peer, instant_early, chrono_early);
assert_eq!(
outcome, None,
"\n\
unexpected application of a much earlier change to a peer:\n\
change: {change:?}\n\
times: {instant_early:?} {chrono_early}\n\
peer: {peer:?}"
);
}
#[test]
fn later_revert_change_is_applied() {
let _init_guard = zebra_test::init();
let instant_now = Instant::now();
let chrono_now = Utc::now();
let local_now: DateTime32 = chrono_now.try_into().expect("will succeed until 2038");
let address = PeerSocketAddr::from(([192, 168, 180, 9], 10_000));
let peer_seed = MetaAddr::new_initial_peer(address).into_new_meta_addr(instant_now, local_now);
let peer = MetaAddr::new_responded(address, None)
.apply_to_meta_addr(peer_seed, instant_now, chrono_now)
.expect("Failed to create MetaAddr for responded peer");
let instant_late = instant_now + (CONCURRENT_ADDRESS_CHANGE_PERIOD * 3);
let chrono_late = chrono_now
+ chrono::Duration::from_std(CONCURRENT_ADDRESS_CHANGE_PERIOD * 3)
.expect("constant is valid");
let change = MetaAddr::new_reconnect(address);
let outcome = change.apply_to_meta_addr(peer, instant_late, chrono_late);
assert!(
outcome.is_some(),
"\n\
unexpected skipped much later change to a peer:\n\
change: {change:?}\n\
times: {instant_late:?} {chrono_late}\n\
peer: {peer:?}"
);
}
#[test]
fn concurrent_state_revert_change_is_not_applied() {
let _init_guard = zebra_test::init();
let instant_now = Instant::now();
let chrono_now = Utc::now();
let local_now: DateTime32 = chrono_now.try_into().expect("will succeed until 2038");
let address = PeerSocketAddr::from(([192, 168, 180, 9], 10_000));
let peer_seed = MetaAddr::new_initial_peer(address).into_new_meta_addr(instant_now, local_now);
let peer = MetaAddr::new_responded(address, None)
.apply_to_meta_addr(peer_seed, instant_now, chrono_now)
.expect("Failed to create MetaAddr for responded peer");
let instant_early = instant_now - (CONCURRENT_ADDRESS_CHANGE_PERIOD / 2);
let chrono_early = chrono_now
- chrono::Duration::from_std(CONCURRENT_ADDRESS_CHANGE_PERIOD / 2)
.expect("constant is valid");
let change = MetaAddr::new_reconnect(address);
let outcome = change.apply_to_meta_addr(peer, instant_early, chrono_early);
assert_eq!(
outcome, None,
"\n\
unexpected application of an early concurrent change to a peer:\n\
change: {change:?}\n\
times: {instant_early:?} {chrono_early}\n\
peer: {peer:?}"
);
let instant_late = instant_now + (CONCURRENT_ADDRESS_CHANGE_PERIOD / 2);
let chrono_late = chrono_now
+ chrono::Duration::from_std(CONCURRENT_ADDRESS_CHANGE_PERIOD / 2)
.expect("constant is valid");
let change = MetaAddr::new_reconnect(address);
let outcome = change.apply_to_meta_addr(peer, instant_late, chrono_late);
assert_eq!(
outcome, None,
"\n\
unexpected application of a late concurrent change to a peer:\n\
change: {change:?}\n\
times: {instant_late:?} {chrono_late}\n\
peer: {peer:?}"
);
}
#[test]
fn concurrent_state_progress_change_is_applied() {
let _init_guard = zebra_test::init();
let instant_now = Instant::now();
let chrono_now = Utc::now();
let local_now: DateTime32 = chrono_now.try_into().expect("will succeed until 2038");
let address = PeerSocketAddr::from(([192, 168, 180, 9], 10_000));
let peer_seed = MetaAddr::new_initial_peer(address).into_new_meta_addr(instant_now, local_now);
let peer = MetaAddr::new_responded(address, None)
.apply_to_meta_addr(peer_seed, instant_now, chrono_now)
.expect("Failed to create MetaAddr for responded peer");
let instant_early = instant_now - (CONCURRENT_ADDRESS_CHANGE_PERIOD / 2);
let chrono_early = chrono_now
- chrono::Duration::from_std(CONCURRENT_ADDRESS_CHANGE_PERIOD / 2)
.expect("constant is valid");
let change = MetaAddr::new_errored(address, None);
let outcome = change.apply_to_meta_addr(peer, instant_early, chrono_early);
assert!(
outcome.is_some(),
"\n\
unexpected skipped early concurrent change to a peer:\n\
change: {change:?}\n\
times: {instant_early:?} {chrono_early}\n\
peer: {peer:?}"
);
let instant_late = instant_now + (CONCURRENT_ADDRESS_CHANGE_PERIOD / 2);
let chrono_late = chrono_now
+ chrono::Duration::from_std(CONCURRENT_ADDRESS_CHANGE_PERIOD / 2)
.expect("constant is valid");
let change = MetaAddr::new_errored(address, None);
let outcome = change.apply_to_meta_addr(peer, instant_late, chrono_late);
assert!(
outcome.is_some(),
"\n\
unexpected skipped late concurrent change to a peer:\n\
change: {change:?}\n\
times: {instant_late:?} {chrono_late}\n\
peer: {peer:?}"
);
}
#[test]
fn rtt_is_stored_correctly_in_meta_addr() {
let _init_guard = zebra_test::init();
let instant_now = Instant::now();
let chrono_now = Utc::now();
let local_now: DateTime32 = chrono_now.try_into().expect("will succeed until 2038");
let address = PeerSocketAddr::from(([192, 168, 180, 9], 10_000));
let peer_seed = MetaAddr::new_initial_peer(address).into_new_meta_addr(instant_now, local_now);
let rtt = Duration::from_millis(128);
let peer = MetaAddr::new_responded(address, Some(rtt))
.apply_to_meta_addr(peer_seed, instant_now, chrono_now)
.expect("Failed to create MetaAddr for responded peer");
assert_eq!(peer.rtt, Some(rtt));
}