Test the manual eq impl on sapling::ShieldedData<PerSpend> (#1989)

This commit is contained in:
teor 2021-04-08 01:30:50 +10:00 committed by GitHub
parent 375c8d8700
commit f8094cdf5c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 131 additions and 7 deletions

View File

@ -86,7 +86,11 @@ proptest! {
}
}
/// Return the
/// Return the following calculations on `spend`:
/// smallest_disallowed_vec_len
/// smallest_disallowed_serialized_len
/// largest_allowed_vec_len
/// largest_allowed_serialized_len
fn spend_max_allocation_is_big_enough<AnchorV>(
spend: Spend<AnchorV>,
) -> (usize, usize, usize, usize)

View File

@ -1,16 +1,18 @@
use proptest::prelude::*;
use super::super::super::transaction::*;
use super::super::shielded_data::*;
use crate::{
block,
sapling::{self, PerSpendAnchor},
serialization::{ZcashDeserializeInto, ZcashSerialize},
transaction::{LockTime, Transaction},
};
use futures::future::Either;
proptest! {
// TODO: generalise this test for `ShieldedData<SharedAnchor>` (#1829)
#[test]
fn shielded_data_roundtrip(shielded in any::<ShieldedData<PerSpendAnchor>>()) {
fn shielded_data_roundtrip(shielded in any::<sapling::ShieldedData<PerSpendAnchor>>()) {
zebra_test::init();
// shielded data doesn't serialize by itself, so we have to stick it in
@ -30,9 +32,70 @@ proptest! {
prop_assert_eq![tx, tx_parsed];
}
/// Check that ShieldedData serialization is equal if `shielded1 == shielded2`
/// Check that ShieldedData<PerSpendAnchor> is equal when `first` is swapped
/// between a spend and an output
//
// TODO: generalise this test for `ShieldedData<SharedAnchor>` (#1829)
#[test]
fn shielded_data_serialize_eq(shielded1 in any::<ShieldedData<PerSpendAnchor>>(), shielded2 in any::<ShieldedData<PerSpendAnchor>>()) {
fn shielded_data_per_spend_swap_first_eq(shielded1 in any::<sapling::ShieldedData<PerSpendAnchor>>()) {
use Either::*;
zebra_test::init();
// we need at least one spend and one output to swap them
prop_assume!(shielded1.spends().count() > 0 && shielded1.outputs().count() > 0);
let mut shielded2 = shielded1.clone();
let mut spends: Vec<_> = shielded2.spends().cloned().collect();
let mut outputs: Vec<_> = shielded2.outputs().cloned().collect();
match shielded2.first {
Left(_spend) => {
shielded2.first = Right(outputs.remove(0));
shielded2.rest_outputs = outputs;
shielded2.rest_spends = spends;
}
Right(_output) => {
shielded2.first = Left(spends.remove(0));
shielded2.rest_spends = spends;
shielded2.rest_outputs = outputs;
}
}
prop_assert_eq![&shielded1, &shielded2];
// shielded data doesn't serialize by itself, so we have to stick it in
// a transaction
let tx1 = Transaction::V4 {
inputs: Vec::new(),
outputs: Vec::new(),
lock_time: LockTime::min_lock_time(),
expiry_height: block::Height(0),
joinsplit_data: None,
sapling_shielded_data: Some(shielded1),
};
let tx2 = Transaction::V4 {
inputs: Vec::new(),
outputs: Vec::new(),
lock_time: LockTime::min_lock_time(),
expiry_height: block::Height(0),
joinsplit_data: None,
sapling_shielded_data: Some(shielded2),
};
prop_assert_eq![&tx1, &tx2];
let data1 = tx1.zcash_serialize_to_vec().expect("tx1 should serialize");
let data2 = tx2.zcash_serialize_to_vec().expect("tx2 should serialize");
prop_assert_eq![data1, data2];
}
/// Check that ShieldedData<PerSpendAnchor> serialization is equal if
/// `shielded1 == shielded2`
//
// TODO: generalise this test for `ShieldedData<SharedAnchor>` (#1829)
#[test]
fn shielded_data_per_spend_serialize_eq(shielded1 in any::<sapling::ShieldedData<PerSpendAnchor>>(), shielded2 in any::<sapling::ShieldedData<PerSpendAnchor>>()) {
zebra_test::init();
let shielded_eq = shielded1 == shielded2;
@ -56,6 +119,12 @@ proptest! {
sapling_shielded_data: Some(shielded2),
};
if shielded_eq {
prop_assert_eq![&tx1, &tx2];
} else {
prop_assert_ne![&tx1, &tx2];
}
let data1 = tx1.zcash_serialize_to_vec().expect("tx1 should serialize");
let data2 = tx2.zcash_serialize_to_vec().expect("tx2 should serialize");
@ -65,4 +134,55 @@ proptest! {
prop_assert_ne![data1, data2];
}
}
/// Check that ShieldedData<PerSpendAnchor> serialization is equal when we
/// replace all the known fields.
///
/// This test checks for extra fields that are not in `ShieldedData::eq`.
//
// TODO: generalise this test for `ShieldedData<SharedAnchor>` (#1829)
#[test]
fn shielded_data_per_spend_field_assign_eq(shielded1 in any::<sapling::ShieldedData<PerSpendAnchor>>(), shielded2 in any::<sapling::ShieldedData<PerSpendAnchor>>()) {
zebra_test::init();
let mut shielded2 = shielded2;
// these fields must match ShieldedData::eq
// the spends() and outputs() checks cover first, rest_spends, and rest_outputs
shielded2.first = shielded1.first.clone();
shielded2.rest_spends = shielded1.rest_spends.clone();
shielded2.rest_outputs = shielded1.rest_outputs.clone();
// now for the fields that are checked literally
shielded2.value_balance = shielded1.value_balance;
shielded2.shared_anchor = shielded1.shared_anchor;
shielded2.binding_sig = shielded1.binding_sig;
prop_assert_eq![&shielded1, &shielded2];
// shielded data doesn't serialize by itself, so we have to stick it in
// a transaction
let tx1 = Transaction::V4 {
inputs: Vec::new(),
outputs: Vec::new(),
lock_time: LockTime::min_lock_time(),
expiry_height: block::Height(0),
joinsplit_data: None,
sapling_shielded_data: Some(shielded1),
};
let tx2 = Transaction::V4 {
inputs: Vec::new(),
outputs: Vec::new(),
lock_time: LockTime::min_lock_time(),
expiry_height: block::Height(0),
joinsplit_data: None,
sapling_shielded_data: Some(shielded2),
};
prop_assert_eq![&tx1, &tx2];
let data1 = tx1.zcash_serialize_to_vec().expect("tx1 should serialize");
let data2 = tx2.zcash_serialize_to_vec().expect("tx2 should serialize");
prop_assert_eq![data1, data2];
}
}