Zebra/zebra-chain/src/transaction/tests/preallocate.rs

115 lines
5.5 KiB
Rust

//! Tests for trusted preallocation during deserialization.
use proptest::prelude::*;
use crate::{
block::MAX_BLOCK_BYTES,
serialization::{arbitrary::max_allocation_is_big_enough, TrustedPreallocate, ZcashSerialize},
transaction::{
serialize::{
MIN_TRANSPARENT_INPUT_SIZE, MIN_TRANSPARENT_OUTPUT_SIZE, MIN_TRANSPARENT_TX_SIZE,
},
transparent::Input,
transparent::Output,
Transaction,
},
};
proptest! {
/// Confirm that each spend takes at least MIN_TRANSPARENT_TX_SIZE bytes when serialized.
/// This verifies that our calculated [`TrustedPreallocate::max_allocation`] is indeed an upper bound.
#[test]
fn tx_size_is_small_enough(tx in Transaction::arbitrary()) {
let serialized = tx.zcash_serialize_to_vec().expect("Serialization to vec must succeed");
prop_assert!(serialized.len() as u64 >= MIN_TRANSPARENT_TX_SIZE)
}
/// Confirm that each spend takes at least MIN_TRANSPARENT_TX_SIZE bytes when serialized.
/// This verifies that our calculated [`TrustedPreallocate::max_allocation`] is indeed an upper bound.
#[test]
fn transparent_input_size_is_small_enough(input in Input::arbitrary()) {
let serialized = input.zcash_serialize_to_vec().expect("Serialization to vec must succeed");
prop_assert!(serialized.len() as u64 >= MIN_TRANSPARENT_INPUT_SIZE)
}
/// Confirm that each spend takes at least MIN_TRANSPARENT_TX_SIZE bytes when serialized.
/// This verifies that our calculated [`TrustedPreallocate::max_allocation`] is indeed an upper bound.
#[test]
fn transparent_output_size_is_small_enough(output in Output::arbitrary()) {
let serialized = output.zcash_serialize_to_vec().expect("Serialization to vec must succeed");
prop_assert!(serialized.len() as u64 >= MIN_TRANSPARENT_OUTPUT_SIZE)
}
}
proptest! {
// This test is pretty slow, so only run a few cases
#![proptest_config(ProptestConfig::with_cases(8))]
/// Verify the smallest disallowed vector of `Transaction`s is too large to fit in a Zcash block
#[test]
fn tx_max_allocation_is_big_enough(tx in Transaction::arbitrary()) {
let (
smallest_disallowed_vec_len,
smallest_disallowed_serialized_len,
largest_allowed_vec_len,
_largest_allowed_serialized_len,
) = max_allocation_is_big_enough(tx);
// Check that our smallest_disallowed_vec is only one item larger than the limit
prop_assert!(((smallest_disallowed_vec_len - 1) as u64) == Transaction::max_allocation());
// Check that our smallest_disallowed_vec is too big to send in a valid Zcash Block
prop_assert!(smallest_disallowed_serialized_len as u64 > MAX_BLOCK_BYTES);
// Check that our largest_allowed_vec contains the maximum number of Transactions
prop_assert!((largest_allowed_vec_len as u64) == Transaction::max_allocation());
// This is a variable-sized type, so largest_allowed_serialized_len can exceed the length limit
}
/// Verify the smallest disallowed vector of `Input`s is too large to fit in a Zcash block
#[test]
fn input_max_allocation_is_big_enough(input in Input::arbitrary()) {
let (
smallest_disallowed_vec_len,
smallest_disallowed_serialized_len,
largest_allowed_vec_len,
_largest_allowed_serialized_len,
) = max_allocation_is_big_enough(input);
// Check that our smallest_disallowed_vec is only one item larger than the limit
prop_assert!(((smallest_disallowed_vec_len - 1) as u64) == Input::max_allocation());
// Check that our smallest_disallowed_vec is too big to be included in a valid block
// Note that a serialized block always includes at least one byte for the number of transactions,
// so any serialized Vec<Input> at least MAX_BLOCK_BYTES long is too large to fit in a block.
prop_assert!(smallest_disallowed_serialized_len as u64 >= MAX_BLOCK_BYTES);
// Check that our largest_allowed_vec contains the maximum number of Inputs
prop_assert!((largest_allowed_vec_len as u64) == Input::max_allocation());
// This is a variable-sized type, so largest_allowed_serialized_len can exceed the length limit
}
/// Verify the smallest disallowed vector of `Output`s is too large to fit in a Zcash block
#[test]
fn output_max_allocation_is_big_enough(output in Output::arbitrary()) {
let (
smallest_disallowed_vec_len,
smallest_disallowed_serialized_len,
largest_allowed_vec_len,
_largest_allowed_serialized_len,
) = max_allocation_is_big_enough(output);
// Check that our smallest_disallowed_vec is only one item larger than the limit
prop_assert!(((smallest_disallowed_vec_len - 1) as u64) == Output::max_allocation());
// Check that our smallest_disallowed_vec is too big to be included in a valid block
// Note that a serialized block always includes at least one byte for the number of transactions,
// so any serialized Vec<Output> at least MAX_BLOCK_BYTES long is too large to fit in a block.
prop_assert!(smallest_disallowed_serialized_len as u64 >= MAX_BLOCK_BYTES);
// Check that our largest_allowed_vec contains the maximum number of Outputs
prop_assert!((largest_allowed_vec_len as u64) == Output::max_allocation());
// This is a variable-sized type, so largest_allowed_serialized_len can exceed the length limit
}
}