zebra-network 5.0.1

Networking code for Zebra
Documentation
//! 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()
    }
}