2021-06-03 15:48:40 -07:00
|
|
|
//! Arbitrary data generation for serialization proptests
|
|
|
|
|
2021-11-09 12:47:50 -08:00
|
|
|
use std::convert::TryInto;
|
2021-11-04 08:57:30 -07:00
|
|
|
|
2022-08-28 10:08:27 -07:00
|
|
|
use chrono::{DateTime, TimeZone, Utc};
|
2021-05-24 08:10:07 -07:00
|
|
|
use proptest::{arbitrary::any, prelude::*};
|
2021-11-04 08:57:30 -07:00
|
|
|
|
2021-11-10 13:53:21 -08:00
|
|
|
use super::{
|
|
|
|
CompactSizeMessage, DateTime32, TrustedPreallocate, ZcashSerialize, MAX_PROTOCOL_MESSAGE_LEN,
|
|
|
|
};
|
2021-05-24 08:10:07 -07:00
|
|
|
|
2021-05-30 19:52:34 -07:00
|
|
|
impl Arbitrary for DateTime32 {
|
|
|
|
type Parameters = ();
|
|
|
|
|
|
|
|
fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
|
|
|
|
any::<u32>().prop_map(Into::into).boxed()
|
|
|
|
}
|
|
|
|
|
|
|
|
type Strategy = BoxedStrategy<Self>;
|
|
|
|
}
|
|
|
|
|
2021-05-24 08:10:07 -07:00
|
|
|
/// Returns a strategy that produces an arbitrary [`chrono::DateTime<Utc>`],
|
|
|
|
/// based on the full valid range of the type.
|
|
|
|
///
|
2021-05-24 20:42:45 -07:00
|
|
|
/// Both the seconds and nanoseconds values are randomised, including leap seconds:
|
2021-05-25 10:21:06 -07:00
|
|
|
/// <https://docs.rs/chrono/0.4.19/chrono/naive/struct.NaiveTime.html#leap-second-handling>
|
2021-05-24 08:10:07 -07:00
|
|
|
///
|
2021-05-24 20:42:45 -07:00
|
|
|
/// Wherever possible, Zebra should handle leap seconds by:
|
|
|
|
/// - making durations and intervals 3 seconds or longer,
|
|
|
|
/// - avoiding complex time-based calculations, and
|
|
|
|
/// - avoiding relying on subsecond precision or time order.
|
|
|
|
/// When monotonic times are needed, use the opaque `std::time::Instant` type.
|
|
|
|
///
|
|
|
|
/// # Usage
|
|
|
|
///
|
|
|
|
/// Zebra uses these times internally, typically via [`Utc::now`].
|
2021-05-24 08:10:07 -07:00
|
|
|
///
|
2022-06-02 08:07:35 -07:00
|
|
|
/// Some parts of the Zcash network protocol (`Version` messages) also use times
|
2021-05-24 08:10:07 -07:00
|
|
|
/// with an 8-byte seconds value. Unlike this function, they have zero
|
2021-05-24 20:42:45 -07:00
|
|
|
/// nanoseconds values. (So they never have `chrono` leap seconds.)
|
2021-05-24 08:10:07 -07:00
|
|
|
pub fn datetime_full() -> impl Strategy<Value = chrono::DateTime<Utc>> {
|
|
|
|
(
|
2021-05-24 20:42:45 -07:00
|
|
|
// TODO: should we be subtracting 1 from the maximum timestamp?
|
2022-08-28 10:08:27 -07:00
|
|
|
DateTime::<Utc>::MIN_UTC.timestamp()..=DateTime::<Utc>::MAX_UTC.timestamp(),
|
2021-05-24 20:42:45 -07:00
|
|
|
0..2_000_000_000_u32,
|
2021-05-24 08:10:07 -07:00
|
|
|
)
|
|
|
|
.prop_map(|(secs, nsecs)| Utc.timestamp(secs, nsecs))
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns a strategy that produces an arbitrary time from a [`u32`] number
|
|
|
|
/// of seconds past the epoch.
|
|
|
|
///
|
|
|
|
/// The nanoseconds value is always zero.
|
|
|
|
///
|
|
|
|
/// The Zcash protocol typically uses 4-byte seconds values, except for the
|
2022-06-02 08:07:35 -07:00
|
|
|
/// `Version` message.
|
2021-05-30 19:52:34 -07:00
|
|
|
///
|
|
|
|
/// TODO: replace this strategy with `any::<DateTime32>()`.
|
2021-05-24 08:10:07 -07:00
|
|
|
pub fn datetime_u32() -> impl Strategy<Value = chrono::DateTime<Utc>> {
|
2021-05-30 19:52:34 -07:00
|
|
|
any::<DateTime32>().prop_map(Into::into)
|
2021-05-24 08:10:07 -07:00
|
|
|
}
|
2021-05-25 21:55:07 -07:00
|
|
|
|
2021-11-04 08:57:30 -07:00
|
|
|
impl Arbitrary for CompactSizeMessage {
|
|
|
|
type Parameters = ();
|
|
|
|
|
|
|
|
fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
|
|
|
|
(0..=MAX_PROTOCOL_MESSAGE_LEN)
|
|
|
|
.prop_map(|size| {
|
|
|
|
size.try_into()
|
|
|
|
.expect("MAX_PROTOCOL_MESSAGE_LEN fits in CompactSizeMessage")
|
|
|
|
})
|
|
|
|
.boxed()
|
|
|
|
}
|
|
|
|
|
|
|
|
type Strategy = BoxedStrategy<Self>;
|
|
|
|
}
|
2021-11-10 13:53:21 -08:00
|
|
|
|
|
|
|
/// Allocate a maximum-sized vector of cloned `item`s, and serialize that array.
|
|
|
|
///
|
|
|
|
/// Returns the following calculations on `item`:
|
|
|
|
/// smallest_disallowed_vec_len
|
|
|
|
/// smallest_disallowed_serialized_len
|
|
|
|
/// largest_allowed_vec_len
|
|
|
|
/// largest_allowed_serialized_len
|
|
|
|
///
|
|
|
|
/// For varible-size types, `largest_allowed_serialized_len` might not fit within
|
|
|
|
/// `MAX_PROTOCOL_MESSAGE_LEN` or `MAX_BLOCK_SIZE`.
|
|
|
|
pub fn max_allocation_is_big_enough<T>(item: T) -> (usize, usize, usize, usize)
|
|
|
|
where
|
|
|
|
T: TrustedPreallocate + ZcashSerialize + Clone,
|
|
|
|
{
|
|
|
|
let max_allocation: usize = T::max_allocation().try_into().unwrap();
|
|
|
|
let mut smallest_disallowed_vec = vec![item; max_allocation + 1];
|
|
|
|
|
|
|
|
let smallest_disallowed_serialized = smallest_disallowed_vec
|
|
|
|
.zcash_serialize_to_vec()
|
|
|
|
.expect("Serialization to vec must succeed");
|
|
|
|
let smallest_disallowed_vec_len = smallest_disallowed_vec.len();
|
|
|
|
|
|
|
|
// Create largest_allowed_vec by removing one element from smallest_disallowed_vec without copying (for efficiency)
|
|
|
|
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");
|
|
|
|
|
|
|
|
(
|
|
|
|
smallest_disallowed_vec_len,
|
|
|
|
smallest_disallowed_serialized.len(),
|
|
|
|
largest_allowed_vec.len(),
|
|
|
|
largest_allowed_serialized.len(),
|
|
|
|
)
|
|
|
|
}
|