Derive Arbitrary impls for a bunch of chain and network types (#2179)
Enable proptests for internal and external network protocol messages, using times with the correct protocol-specific ranges. (4 or 8 bytes.)
This commit is contained in:
parent
6797f4167d
commit
f0549b2f7c
|
@ -3,11 +3,11 @@ use proptest::{
|
||||||
prelude::*,
|
prelude::*,
|
||||||
};
|
};
|
||||||
|
|
||||||
use chrono::{TimeZone, Utc};
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
parameters::{Network, NetworkUpgrade},
|
parameters::{Network, NetworkUpgrade},
|
||||||
|
serialization,
|
||||||
work::{difficulty::CompactDifficulty, equihash},
|
work::{difficulty::CompactDifficulty, equihash},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -186,8 +186,7 @@ impl Arbitrary for Header {
|
||||||
any::<Hash>(),
|
any::<Hash>(),
|
||||||
any::<merkle::Root>(),
|
any::<merkle::Root>(),
|
||||||
any::<[u8; 32]>(),
|
any::<[u8; 32]>(),
|
||||||
// time is interpreted as u32 in the spec, but rust timestamps are i64
|
serialization::arbitrary::datetime_u32(),
|
||||||
(0i64..(u32::MAX as i64)),
|
|
||||||
any::<CompactDifficulty>(),
|
any::<CompactDifficulty>(),
|
||||||
any::<[u8; 32]>(),
|
any::<[u8; 32]>(),
|
||||||
any::<equihash::Solution>(),
|
any::<equihash::Solution>(),
|
||||||
|
@ -198,7 +197,7 @@ impl Arbitrary for Header {
|
||||||
previous_block_hash,
|
previous_block_hash,
|
||||||
merkle_root,
|
merkle_root,
|
||||||
commitment_bytes,
|
commitment_bytes,
|
||||||
timestamp,
|
time,
|
||||||
difficulty_threshold,
|
difficulty_threshold,
|
||||||
nonce,
|
nonce,
|
||||||
solution,
|
solution,
|
||||||
|
@ -207,7 +206,7 @@ impl Arbitrary for Header {
|
||||||
previous_block_hash,
|
previous_block_hash,
|
||||||
merkle_root,
|
merkle_root,
|
||||||
commitment_bytes,
|
commitment_bytes,
|
||||||
time: Utc.timestamp(timestamp, 0),
|
time,
|
||||||
difficulty_threshold,
|
difficulty_threshold,
|
||||||
nonce,
|
nonce,
|
||||||
solution,
|
solution,
|
||||||
|
|
|
@ -10,6 +10,9 @@ use crate::{
|
||||||
|
|
||||||
use super::{merkle, Hash, Height};
|
use super::{merkle, Hash, Height};
|
||||||
|
|
||||||
|
#[cfg(any(test, feature = "proptest-impl"))]
|
||||||
|
use proptest_derive::Arbitrary;
|
||||||
|
|
||||||
/// A block header, containing metadata about a block.
|
/// A block header, containing metadata about a block.
|
||||||
///
|
///
|
||||||
/// How are blocks chained together? They are chained together via the
|
/// How are blocks chained together? They are chained together via the
|
||||||
|
@ -121,6 +124,7 @@ impl Header {
|
||||||
///
|
///
|
||||||
/// This structure is used in the Bitcoin network protocol.
|
/// This structure is used in the Bitcoin network protocol.
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
#[cfg_attr(any(test, feature = "proptest-impl"), derive(Arbitrary))]
|
||||||
pub struct CountedHeader {
|
pub struct CountedHeader {
|
||||||
pub header: Header,
|
pub header: Header,
|
||||||
pub transaction_count: usize,
|
pub transaction_count: usize,
|
||||||
|
|
|
@ -17,6 +17,9 @@ pub(crate) mod serde_helpers;
|
||||||
|
|
||||||
pub mod sha256d;
|
pub mod sha256d;
|
||||||
|
|
||||||
|
#[cfg(any(test, feature = "proptest-impl"))]
|
||||||
|
pub mod arbitrary;
|
||||||
|
|
||||||
pub use constraint::AtLeastOne;
|
pub use constraint::AtLeastOne;
|
||||||
pub use error::SerializationError;
|
pub use error::SerializationError;
|
||||||
pub use read_zcash::ReadZcashExt;
|
pub use read_zcash::ReadZcashExt;
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
use chrono::{TimeZone, Utc, MAX_DATETIME, MIN_DATETIME};
|
||||||
|
use proptest::{arbitrary::any, prelude::*};
|
||||||
|
|
||||||
|
/// Returns a strategy that produces an arbitrary [`chrono::DateTime<Utc>`],
|
||||||
|
/// based on the full valid range of the type.
|
||||||
|
///
|
||||||
|
/// Both the seconds and nanoseconds values are randomised. But leap nanoseconds
|
||||||
|
/// are never present.
|
||||||
|
/// https://docs.rs/chrono/0.4.19/chrono/struct.DateTime.html#method.timestamp_subsec_nanos
|
||||||
|
///
|
||||||
|
/// Zebra uses these times internally, via [`Utc::now`].
|
||||||
|
///
|
||||||
|
/// Some parts of the Zcash network protocol ([`Version`] messages) also use times
|
||||||
|
/// with an 8-byte seconds value. Unlike this function, they have zero
|
||||||
|
/// nanoseconds values.
|
||||||
|
pub fn datetime_full() -> impl Strategy<Value = chrono::DateTime<Utc>> {
|
||||||
|
(
|
||||||
|
MIN_DATETIME.timestamp()..=MAX_DATETIME.timestamp(),
|
||||||
|
0..1_000_000_000_u32,
|
||||||
|
)
|
||||||
|
.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
|
||||||
|
/// [`Version`] message.
|
||||||
|
pub fn datetime_u32() -> impl Strategy<Value = chrono::DateTime<Utc>> {
|
||||||
|
any::<u32>().prop_map(|secs| Utc.timestamp(secs.into(), 0))
|
||||||
|
}
|
|
@ -106,7 +106,7 @@ impl From<Root> for [u8; 32] {
|
||||||
|
|
||||||
/// Sprout Note Commitment Tree
|
/// Sprout Note Commitment Tree
|
||||||
#[derive(Clone, Debug, Default, Eq, PartialEq)]
|
#[derive(Clone, Debug, Default, Eq, PartialEq)]
|
||||||
#[cfg_attr(test, derive(Arbitrary))]
|
#[cfg_attr(any(test, feature = "proptest-impl"), derive(Arbitrary))]
|
||||||
struct NoteCommitmentTree {
|
struct NoteCommitmentTree {
|
||||||
/// The root node of the tree (often used as an anchor).
|
/// The root node of the tree (often used as an anchor).
|
||||||
root: Root,
|
root: Root,
|
||||||
|
|
|
@ -40,4 +40,5 @@ proptest = "0.10"
|
||||||
proptest-derive = "0.3"
|
proptest-derive = "0.3"
|
||||||
toml = "0.5"
|
toml = "0.5"
|
||||||
|
|
||||||
|
zebra-chain = { path = "../zebra-chain", features = ["proptest-impl"] }
|
||||||
zebra-test = { path = "../zebra-test/" }
|
zebra-test = { path = "../zebra-test/" }
|
||||||
|
|
|
@ -14,6 +14,11 @@ use super::inv::InventoryHash;
|
||||||
use super::types::*;
|
use super::types::*;
|
||||||
use crate::meta_addr::MetaAddr;
|
use crate::meta_addr::MetaAddr;
|
||||||
|
|
||||||
|
#[cfg(any(test, feature = "proptest-impl"))]
|
||||||
|
use proptest_derive::Arbitrary;
|
||||||
|
#[cfg(any(test, feature = "proptest-impl"))]
|
||||||
|
use zebra_chain::serialization::arbitrary::datetime_full;
|
||||||
|
|
||||||
/// A Bitcoin-like network message for the Zcash protocol.
|
/// A Bitcoin-like network message for the Zcash protocol.
|
||||||
///
|
///
|
||||||
/// The Zcash network protocol is mostly inherited from Bitcoin, and a list of
|
/// The Zcash network protocol is mostly inherited from Bitcoin, and a list of
|
||||||
|
@ -31,6 +36,7 @@ use crate::meta_addr::MetaAddr;
|
||||||
///
|
///
|
||||||
/// [btc_wiki_protocol]: https://en.bitcoin.it/wiki/Protocol_documentation
|
/// [btc_wiki_protocol]: https://en.bitcoin.it/wiki/Protocol_documentation
|
||||||
#[derive(Clone, Eq, PartialEq, Debug)]
|
#[derive(Clone, Eq, PartialEq, Debug)]
|
||||||
|
#[cfg_attr(any(test, feature = "proptest-impl"), derive(Arbitrary))]
|
||||||
pub enum Message {
|
pub enum Message {
|
||||||
/// A `version` message.
|
/// A `version` message.
|
||||||
///
|
///
|
||||||
|
@ -47,6 +53,12 @@ pub enum Message {
|
||||||
services: PeerServices,
|
services: PeerServices,
|
||||||
|
|
||||||
/// The time when the version message was sent.
|
/// The time when the version message was sent.
|
||||||
|
///
|
||||||
|
/// This is a 64-bit field. Zebra rejects out-of-range times as invalid.
|
||||||
|
#[cfg_attr(
|
||||||
|
any(test, feature = "proptest-impl"),
|
||||||
|
proptest(strategy = "datetime_full()")
|
||||||
|
)]
|
||||||
timestamp: DateTime<Utc>,
|
timestamp: DateTime<Utc>,
|
||||||
|
|
||||||
/// The network address of the node receiving this message, and its
|
/// The network address of the node receiving this message, and its
|
||||||
|
@ -307,6 +319,7 @@ where
|
||||||
///
|
///
|
||||||
/// [Bitcoin reference](https://en.bitcoin.it/wiki/Protocol_documentation#reject)
|
/// [Bitcoin reference](https://en.bitcoin.it/wiki/Protocol_documentation#reject)
|
||||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||||
|
#[cfg_attr(any(test, feature = "proptest-impl"), derive(Arbitrary))]
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
pub enum RejectReason {
|
pub enum RejectReason {
|
||||||
|
|
|
@ -17,7 +17,7 @@ use proptest_derive::Arbitrary;
|
||||||
|
|
||||||
/// A magic number identifying the network.
|
/// A magic number identifying the network.
|
||||||
#[derive(Copy, Clone, Eq, PartialEq)]
|
#[derive(Copy, Clone, Eq, PartialEq)]
|
||||||
#[cfg_attr(test, derive(Arbitrary))]
|
#[cfg_attr(any(test, feature = "proptest-impl"), derive(Arbitrary))]
|
||||||
pub struct Magic(pub [u8; 4]);
|
pub struct Magic(pub [u8; 4]);
|
||||||
|
|
||||||
impl fmt::Debug for Magic {
|
impl fmt::Debug for Magic {
|
||||||
|
@ -38,6 +38,7 @@ impl From<Network> for Magic {
|
||||||
|
|
||||||
/// A protocol version number.
|
/// A protocol version number.
|
||||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
|
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
|
||||||
|
#[cfg_attr(any(test, feature = "proptest-impl"), derive(Arbitrary))]
|
||||||
pub struct Version(pub u32);
|
pub struct Version(pub u32);
|
||||||
|
|
||||||
impl Version {
|
impl Version {
|
||||||
|
@ -89,6 +90,7 @@ bitflags! {
|
||||||
|
|
||||||
/// A nonce used in the networking layer to identify messages.
|
/// A nonce used in the networking layer to identify messages.
|
||||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
|
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
|
||||||
|
#[cfg_attr(any(test, feature = "proptest-impl"), derive(Arbitrary))]
|
||||||
pub struct Nonce(pub u64);
|
pub struct Nonce(pub u64);
|
||||||
|
|
||||||
impl Default for Nonce {
|
impl Default for Nonce {
|
||||||
|
@ -100,6 +102,7 @@ impl Default for Nonce {
|
||||||
|
|
||||||
/// A random value to add to the seed value in a hash function.
|
/// A random value to add to the seed value in a hash function.
|
||||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
|
#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
|
||||||
|
#[cfg_attr(any(test, feature = "proptest-impl"), derive(Arbitrary))]
|
||||||
pub struct Tweak(pub u32);
|
pub struct Tweak(pub u32);
|
||||||
|
|
||||||
impl Default for Tweak {
|
impl Default for Tweak {
|
||||||
|
@ -112,6 +115,7 @@ impl Default for Tweak {
|
||||||
/// A Bloom filter consisting of a bit field of arbitrary byte-aligned
|
/// A Bloom filter consisting of a bit field of arbitrary byte-aligned
|
||||||
/// size, maximum size is 36,000 bytes.
|
/// size, maximum size is 36,000 bytes.
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||||
|
#[cfg_attr(any(test, feature = "proptest-impl"), derive(Arbitrary))]
|
||||||
pub struct Filter(pub Vec<u8>);
|
pub struct Filter(pub Vec<u8>);
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
|
@ -7,6 +7,9 @@ use zebra_chain::{
|
||||||
|
|
||||||
use super::super::types::Nonce;
|
use super::super::types::Nonce;
|
||||||
|
|
||||||
|
#[cfg(any(test, feature = "proptest-impl"))]
|
||||||
|
use proptest_derive::Arbitrary;
|
||||||
|
|
||||||
/// A network request, represented in internal format.
|
/// A network request, represented in internal format.
|
||||||
///
|
///
|
||||||
/// The network layer aims to abstract away the details of the Bitcoin wire
|
/// The network layer aims to abstract away the details of the Bitcoin wire
|
||||||
|
@ -27,6 +30,7 @@ use super::super::types::Nonce;
|
||||||
/// a best-effort attempt to ignore any messages responsive to the cancelled
|
/// a best-effort attempt to ignore any messages responsive to the cancelled
|
||||||
/// request, subject to limitations in the underlying Zcash protocol.
|
/// request, subject to limitations in the underlying Zcash protocol.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
#[cfg_attr(any(test, feature = "proptest-impl"), derive(Arbitrary))]
|
||||||
pub enum Request {
|
pub enum Request {
|
||||||
/// Requests additional peers from the server.
|
/// Requests additional peers from the server.
|
||||||
///
|
///
|
||||||
|
|
|
@ -4,10 +4,15 @@ use zebra_chain::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::meta_addr::MetaAddr;
|
use crate::meta_addr::MetaAddr;
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
#[cfg(any(test, feature = "proptest-impl"))]
|
||||||
|
use proptest_derive::Arbitrary;
|
||||||
|
|
||||||
/// A response to a network request, represented in internal format.
|
/// A response to a network request, represented in internal format.
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
|
#[cfg_attr(any(test, feature = "proptest-impl"), derive(Arbitrary))]
|
||||||
pub enum Response {
|
pub enum Response {
|
||||||
/// Do not send any response to this request.
|
/// Do not send any response to this request.
|
||||||
///
|
///
|
||||||
|
|
Loading…
Reference in New Issue