use std::{cmp::min, env};
use proptest::prelude::*;
use zebra_chain::{
parameters::Network::*,
serialization::{
arbitrary::max_allocation_is_big_enough, TrustedPreallocate, ZcashSerialize,
MAX_PROTOCOL_MESSAGE_LEN,
},
};
use crate::{
constants::MAX_ADDRS_IN_MESSAGE,
meta_addr::MetaAddr,
protocol::external::{
addr::{AddrV1, AddrV2},
inv::{InventoryHash, MAX_INV_IN_RECEIVED_MESSAGE},
},
};
const ADDR_V1_SIZE: usize = 4 + 8 + 16 + 2;
#[allow(clippy::identity_op)]
const ADDR_V2_MIN_SIZE: usize = 4 + 1 + 1 + 1 + 0 + 2;
const DEFAULT_PROPTEST_CASES: u32 = 8;
proptest! {
#![proptest_config(proptest::test_runner::Config::with_cases(env::var("PROPTEST_CASES")
.ok()
.and_then(|v| v.parse().ok())
.unwrap_or(DEFAULT_PROPTEST_CASES)))]
#[test]
fn inv_hash_size_is_correct(inv in any::<InventoryHash>()) {
let serialized_inv = inv
.zcash_serialize_to_vec()
.expect("Serialization to vec must succeed");
let expected_size = match inv {
InventoryHash::Error
| InventoryHash::Tx(_)
| InventoryHash::Block(_)
| InventoryHash::FilteredBlock(_) => 32 + 4,
InventoryHash::Wtx(_) => 32 + 32 + 4,
};
prop_assert_eq!(serialized_inv.len(), expected_size);
}
#[test]
fn inv_hash_max_allocation_is_correct(inv in InventoryHash::smallest_types_strategy()) {
let max_allocation: usize = InventoryHash::max_allocation().try_into().unwrap();
let mut smallest_disallowed_vec = vec![inv; max_allocation + 1];
let smallest_disallowed_serialized = smallest_disallowed_vec
.zcash_serialize_to_vec()
.expect("Serialization to vec must succeed");
prop_assert!(((smallest_disallowed_vec.len() - 1) as u64) == InventoryHash::max_allocation());
prop_assert!(smallest_disallowed_serialized.len() > min(MAX_PROTOCOL_MESSAGE_LEN, usize::try_from(MAX_INV_IN_RECEIVED_MESSAGE).expect("fits in usize")));
smallest_disallowed_vec.pop();
let largest_allowed_vec = smallest_disallowed_vec;
let largest_allowed_serialized = largest_allowed_vec
.zcash_serialize_to_vec()
.expect("Serialization to vec must succeed");
prop_assert!((largest_allowed_vec.len() as u64) == InventoryHash::max_allocation());
prop_assert!(largest_allowed_serialized.len() <= MAX_PROTOCOL_MESSAGE_LEN);
}
}
proptest! {
#![proptest_config(proptest::test_runner::Config::with_cases(env::var("PROPTEST_CASES")
.ok()
.and_then(|v| v.parse().ok())
.unwrap_or(DEFAULT_PROPTEST_CASES)))]
#[test]
fn addr_v1_size_is_correct(addr in MetaAddr::arbitrary()) {
let _init_guard = zebra_test::init();
let addr = addr.sanitize(&Mainnet);
prop_assume!(addr.is_some());
let addr: AddrV1 = addr.unwrap().into();
let serialized = addr
.zcash_serialize_to_vec()
.expect("Serialization to vec must succeed");
prop_assert!(serialized.len() == ADDR_V1_SIZE)
}
#[test]
fn addr_v1_max_allocation_is_correct(addr in MetaAddr::arbitrary()) {
let _init_guard = zebra_test::init();
let addr = addr.sanitize(&Mainnet);
prop_assume!(addr.is_some());
let addr: AddrV1 = addr.unwrap().into();
let (
_smallest_disallowed_vec_len,
_smallest_disallowed_serialized_len,
largest_allowed_vec_len,
largest_allowed_serialized_len,
) = max_allocation_is_big_enough(addr);
prop_assert_eq!(AddrV1::max_allocation(), MAX_ADDRS_IN_MESSAGE as u64);
prop_assert!((largest_allowed_vec_len as u64) == AddrV1::max_allocation());
prop_assert!(largest_allowed_serialized_len <= MAX_PROTOCOL_MESSAGE_LEN);
}
}
proptest! {
#![proptest_config(proptest::test_runner::Config::with_cases(env::var("PROPTEST_CASES")
.ok()
.and_then(|v| v.parse().ok())
.unwrap_or(DEFAULT_PROPTEST_CASES)))]
#[test]
fn addr_v2_size_is_correct(addr in MetaAddr::arbitrary()) {
let _init_guard = zebra_test::init();
let addr = addr.sanitize(&Mainnet);
prop_assume!(addr.is_some());
let addr: AddrV2 = addr.unwrap().into();
let serialized = addr
.zcash_serialize_to_vec()
.expect("Serialization to vec must succeed");
prop_assert!(serialized.len() >= ADDR_V2_MIN_SIZE)
}
#[test]
fn addr_v2_max_allocation_is_correct(addr in MetaAddr::arbitrary()) {
let _init_guard = zebra_test::init();
let addr = addr.sanitize(&Mainnet);
prop_assume!(addr.is_some());
let addr: AddrV2 = addr.unwrap().into();
let (
_smallest_disallowed_vec_len,
_smallest_disallowed_serialized_len,
largest_allowed_vec_len,
_largest_allowed_serialized_len,
) = max_allocation_is_big_enough(addr);
prop_assert_eq!(AddrV2::max_allocation(), MAX_ADDRS_IN_MESSAGE as u64);
prop_assert!((largest_allowed_vec_len as u64) == AddrV2::max_allocation());
}
}