zebra/zebra-network/src/meta_addr/arbitrary.rs

119 lines
3.9 KiB
Rust

//! Randomised test data generation for MetaAddr.
use std::net::IpAddr;
use proptest::{collection::vec, prelude::*};
use zebra_chain::{parameters::Network::*, serialization::DateTime32};
use crate::protocol::external::arbitrary::canonical_peer_addr_strategy;
use super::{MetaAddr, MetaAddrChange, PeerServices, PeerSocketAddr};
/// The largest number of random changes we want to apply to a [`MetaAddr`].
///
/// This should be at least twice the number of [`PeerAddrState`][1]s, so the
/// tests can cover multiple transitions through every state.
///
/// [1]: super::PeerAddrState
#[allow(dead_code)]
pub const MAX_ADDR_CHANGE: usize = 15;
/// The largest number of random addresses we want to add to an [`AddressBook`][2].
///
/// This should be at least the number of [`PeerAddrState`][1]s, so the tests
/// can cover interactions between addresses in different states.
///
/// [1]: super::PeerAddrState
/// [2]: crate::AddressBook
#[allow(dead_code)]
pub const MAX_META_ADDR: usize = 8;
impl MetaAddr {
/// Create a strategy that generates [`MetaAddr`]s in the
/// [`NeverAttemptedGossiped`][1] state.
///
/// [1]: super::PeerAddrState::NeverAttemptedGossiped
pub fn gossiped_strategy() -> BoxedStrategy<Self> {
(
canonical_peer_addr_strategy(),
any::<PeerServices>(),
any::<DateTime32>(),
)
.prop_map(|(addr, untrusted_services, untrusted_last_seen)| {
MetaAddr::new_gossiped_meta_addr(addr, untrusted_services, untrusted_last_seen)
})
.boxed()
}
}
impl MetaAddrChange {
/// Returns a strategy which generates changes for `addr`.
///
/// `addr` is typically generated by the `canonical_peer_addr` strategy.
pub fn addr_strategy(addr: PeerSocketAddr) -> BoxedStrategy<Self> {
any::<MetaAddrChange>()
.prop_map(move |mut change| {
change.set_addr(addr);
change
})
.boxed()
}
/// Returns a strategy which generates a `MetaAddr`, and a vector of up to
/// `max_addr_change` changes.
///
/// The address and the changes all have matching `PeerSocketAddr`s.
pub fn addr_changes_strategy(
max_addr_change: usize,
) -> BoxedStrategy<(MetaAddr, Vec<MetaAddrChange>)> {
any::<MetaAddr>()
.prop_flat_map(move |addr| {
(
Just(addr),
vec(MetaAddrChange::addr_strategy(addr.addr), 1..max_addr_change),
)
})
.boxed()
}
/// Create a strategy that generates [`IpAddr`]s for [`MetaAddrChange`]s which are ready for
/// outbound connections.
pub fn ready_outbound_strategy_ip() -> BoxedStrategy<IpAddr> {
any::<IpAddr>()
.prop_filter("failed MetaAddr::is_valid_for_outbound", |ip| {
!ip.is_unspecified()
})
.boxed()
}
/// Create a strategy that generates port numbers for [`MetaAddr`]s which are ready for
/// outbound connections.
///
/// Currently, all generated [`MetaAddr`]s are the [`NeverAttemptedGossiped`][1] variant.
///
/// TODO: Generate all [`MetaAddr`] variants, and give them ready fields.
///
/// [1]: super::NeverAttemptedGossiped
pub fn ready_outbound_strategy_port() -> BoxedStrategy<u16> {
(
canonical_peer_addr_strategy(),
any::<PeerServices>(),
any::<DateTime32>(),
)
.prop_filter_map(
"failed MetaAddr::is_valid_for_outbound",
|(addr, services, local_now)| {
let addr = MetaAddr::new_gossiped_meta_addr(addr, services, local_now);
if addr.last_known_info_is_valid_for_outbound(&Mainnet) {
Some(addr.addr.port())
} else {
None
}
},
)
.boxed()
}
}