use proptest::prelude::*;
use zakura_chain::{
amount::{Amount, NonNegative},
block::{self, Height},
block_info::BlockInfo,
ironwood, orchard, sapling, sprout,
subtree::{NoteCommitmentSubtreeData, NoteCommitmentSubtreeIndex},
transaction::{self, Transaction},
transparent,
value_balance::ValueBalance,
};
use crate::service::finalized_state::{
arbitrary::assert_value_properties,
disk_format::{
block::MAX_ON_DISK_HEIGHT,
transparent::{
AddressBalanceLocation, AddressLocation, AddressTransaction, AddressUnspentOutput,
OutputLocation,
},
FromDisk, IntoDisk, TransactionLocation,
},
};
#[test]
fn roundtrip_unit_type() {
let _init_guard = zakura_test::init();
#[allow(clippy::let_unit_value)]
let value = ();
assert_value_properties(value);
}
#[test]
fn roundtrip_block_height() {
let _init_guard = zakura_test::init();
proptest!(
|(mut val in any::<Height>())| {
val.0 %= MAX_ON_DISK_HEIGHT.0 + 1;
assert_value_properties(val)
}
);
}
#[test]
fn roundtrip_block_hash() {
let _init_guard = zakura_test::init();
proptest!(|(val in any::<block::Hash>())| assert_value_properties(val));
}
#[test]
fn roundtrip_block_header() {
let _init_guard = zakura_test::init();
proptest!(|(val in any::<block::Header>())| assert_value_properties(val));
}
#[test]
fn roundtrip_transaction_location() {
let _init_guard = zakura_test::init();
proptest!(
|(mut val in any::<TransactionLocation>())| {
val.height.0 %= MAX_ON_DISK_HEIGHT.0 + 1;
assert_value_properties(val)
}
);
}
#[test]
fn roundtrip_transaction_hash() {
let _init_guard = zakura_test::init();
proptest!(|(val in any::<transaction::Hash>())| assert_value_properties(val));
}
#[test]
fn roundtrip_transaction() {
let _init_guard = zakura_test::init();
proptest!(|(val in any::<Transaction>())| {
prop_assume!(!(val.is_coinbase() && val.sapling_spends_per_anchor().count() > 0));
assert_value_properties(val)
});
}
#[test]
fn serialized_transparent_address_equal() {
let _init_guard = zakura_test::init();
proptest!(|(val1 in any::<transparent::Address>(), val2 in any::<transparent::Address>())| {
if val1 == val2 {
prop_assert_eq!(
val1.as_bytes(),
val2.as_bytes(),
"struct values were equal, but serialized bytes were not.\n\
Values:\n\
{:?}\n\
{:?}",
val1,
val2,
);
} else {
prop_assert_ne!(
val1.as_bytes(),
val2.as_bytes(),
"struct values were not equal, but serialized bytes were equal.\n\
Values:\n\
{:?}\n\
{:?}",
val1,
val2,
);
}
}
);
}
#[test]
fn roundtrip_transparent_address() {
let _init_guard = zakura_test::init();
proptest!(|(val in any::<transparent::Address>())| assert_value_properties(val));
}
#[test]
fn roundtrip_output_location() {
let _init_guard = zakura_test::init();
proptest!(
|(mut val in any::<OutputLocation>())| {
val.height_mut().0 %= MAX_ON_DISK_HEIGHT.0 + 1;
assert_value_properties(val)
}
);
}
#[test]
fn roundtrip_address_location() {
let _init_guard = zakura_test::init();
proptest!(
|(mut val in any::<AddressLocation>())| {
val.height_mut().0 %= MAX_ON_DISK_HEIGHT.0 + 1;
assert_value_properties(val)
}
);
}
#[test]
fn roundtrip_address_balance_location() {
let _init_guard = zakura_test::init();
proptest!(
|(mut val in any::<AddressBalanceLocation>())| {
val.height_mut().0 %= MAX_ON_DISK_HEIGHT.0 + 1;
assert_value_properties(val)
}
);
}
#[test]
fn roundtrip_transparent_output() {
let _init_guard = zakura_test::init();
proptest!(|(val in any::<transparent::Output>())| assert_value_properties(val));
}
#[test]
fn roundtrip_address_unspent_output() {
let _init_guard = zakura_test::init();
proptest!(
|(mut val in any::<AddressUnspentOutput>())| {
val.address_location_mut().height_mut().0 %= MAX_ON_DISK_HEIGHT.0 + 1;
val.unspent_output_location_mut().height_mut().0 %= MAX_ON_DISK_HEIGHT.0 + 1;
assert_value_properties(val)
}
);
}
#[test]
fn roundtrip_address_transaction() {
let _init_guard = zakura_test::init();
proptest!(
|(mut val in any::<AddressTransaction>())| {
val.address_location_mut().height_mut().0 %= MAX_ON_DISK_HEIGHT.0 + 1;
val.transaction_location_mut().height.0 %= MAX_ON_DISK_HEIGHT.0 + 1;
assert_value_properties(val)
}
);
}
#[test]
fn roundtrip_amount() {
let _init_guard = zakura_test::init();
proptest!(|(val in any::<Amount::<NonNegative>>())| assert_value_properties(val));
}
#[test]
fn roundtrip_note_commitment_subtree_index() {
let _init_guard = zakura_test::init();
proptest!(|(val in any::<NoteCommitmentSubtreeIndex>())| {
assert_value_properties(val)
});
}
#[test]
fn serialized_sprout_nullifier_equal() {
let _init_guard = zakura_test::init();
proptest!(|(val1 in any::<sprout::Nullifier>(), val2 in any::<sprout::Nullifier>())| {
if val1 == val2 {
prop_assert_eq!(
val1.as_bytes(),
val2.as_bytes(),
"struct values were equal, but serialized bytes were not.\n\
Values:\n\
{:?}\n\
{:?}",
val1,
val2,
);
} else {
prop_assert_ne!(
val1.as_bytes(),
val2.as_bytes(),
"struct values were not equal, but serialized bytes were equal.\n\
Values:\n\
{:?}\n\
{:?}",
val1,
val2,
);
}
}
);
}
#[test]
fn serialized_sprout_tree_root_equal() {
let _init_guard = zakura_test::init();
proptest!(|(val1 in any::<sprout::tree::Root>(), val2 in any::<sprout::tree::Root>())| {
if val1 == val2 {
prop_assert_eq!(
val1.as_bytes(),
val2.as_bytes(),
"struct values were equal, but serialized bytes were not.\n\
Values:\n\
{:?}\n\
{:?}",
val1,
val2,
);
} else {
prop_assert_ne!(
val1.as_bytes(),
val2.as_bytes(),
"struct values were not equal, but serialized bytes were equal.\n\
Values:\n\
{:?}\n\
{:?}",
val1,
val2,
);
}
}
);
}
#[test]
fn roundtrip_sprout_tree_root() {
let _init_guard = zakura_test::init();
proptest!(|(val in any::<sprout::tree::Root>())| assert_value_properties(val));
}
#[test]
fn serialized_sapling_nullifier_equal() {
let _init_guard = zakura_test::init();
proptest!(|(val1 in any::<sapling::Nullifier>(), val2 in any::<sapling::Nullifier>())| {
if val1 == val2 {
prop_assert_eq!(
val1.as_bytes(),
val2.as_bytes(),
"struct values were equal, but serialized bytes were not.\n\
Values:\n\
{:?}\n\
{:?}",
val1,
val2,
);
} else {
prop_assert_ne!(
val1.as_bytes(),
val2.as_bytes(),
"struct values were not equal, but serialized bytes were equal.\n\
Values:\n\
{:?}\n\
{:?}",
val1,
val2,
);
}
}
);
}
#[test]
fn serialized_sapling_tree_root_equal() {
let _init_guard = zakura_test::init();
proptest!(|(val1 in any::<sapling::tree::Root>(), val2 in any::<sapling::tree::Root>())| {
if val1 == val2 {
prop_assert_eq!(
val1.as_bytes(),
val2.as_bytes(),
"struct values were equal, but serialized bytes were not.\n\
Values:\n\
{:?}\n\
{:?}",
val1,
val2,
);
} else {
prop_assert_ne!(
val1.as_bytes(),
val2.as_bytes(),
"struct values were not equal, but serialized bytes were equal.\n\
Values:\n\
{:?}\n\
{:?}",
val1,
val2,
);
}
}
);
}
#[test]
fn roundtrip_sapling_tree_root() {
let _init_guard = zakura_test::init();
proptest!(|(val in any::<sapling::tree::Root>())| assert_value_properties(val));
}
#[test]
fn roundtrip_sapling_subtree_data() {
let _init_guard = zakura_test::init();
proptest!(|(mut val in any::<NoteCommitmentSubtreeData<sapling::tree::legacy::Node>>())| {
val.end_height.0 %= MAX_ON_DISK_HEIGHT.0 + 1;
assert_value_properties(val.root.0)
});
}
#[test]
fn serialized_orchard_nullifier_equal() {
let _init_guard = zakura_test::init();
proptest!(|(val1 in any::<orchard::Nullifier>(), val2 in any::<orchard::Nullifier>())| {
if val1 == val2 {
prop_assert_eq!(
val1.as_bytes(),
val2.as_bytes(),
"struct values were equal, but serialized bytes were not.\n\
Values:\n\
{:?}\n\
{:?}",
val1,
val2,
);
} else {
prop_assert_ne!(
val1.as_bytes(),
val2.as_bytes(),
"struct values were not equal, but serialized bytes were equal.\n\
Values:\n\
{:?}\n\
{:?}",
val1,
val2,
);
}
}
);
}
#[test]
fn serialized_orchard_tree_root_equal() {
let _init_guard = zakura_test::init();
proptest!(|(val1 in any::<orchard::tree::Root>(), val2 in any::<orchard::tree::Root>())| {
if val1 == val2 {
prop_assert_eq!(
val1.as_bytes(),
val2.as_bytes(),
"struct values were equal, but serialized bytes were not.\n\
Values:\n\
{:?}\n\
{:?}",
val1,
val2,
);
} else {
prop_assert_ne!(
val1.as_bytes(),
val2.as_bytes(),
"struct values were not equal, but serialized bytes were equal.\n\
Values:\n\
{:?}\n\
{:?}",
val1,
val2,
);
}
}
);
}
#[test]
fn roundtrip_orchard_tree_root() {
let _init_guard = zakura_test::init();
proptest!(|(val in any::<orchard::tree::Root>())| assert_value_properties(val));
}
#[test]
fn roundtrip_orchard_subtree_data() {
let _init_guard = zakura_test::init();
proptest!(|(mut val in any::<NoteCommitmentSubtreeData<orchard::tree::Node>>())| {
val.end_height.0 %= MAX_ON_DISK_HEIGHT.0 + 1;
assert_value_properties(val)
});
}
#[test]
fn serialized_ironwood_nullifier_equal() {
let _init_guard = zakura_test::init();
proptest!(|(val1 in any::<ironwood::Nullifier>(), val2 in any::<ironwood::Nullifier>())| {
if val1 == val2 {
prop_assert_eq!(
val1.as_bytes(),
val2.as_bytes(),
"struct values were equal, but serialized bytes were not.\n\
Values:\n\
{:?}\n\
{:?}",
val1,
val2,
);
} else {
prop_assert_ne!(
val1.as_bytes(),
val2.as_bytes(),
"struct values were not equal, but serialized bytes were equal.\n\
Values:\n\
{:?}\n\
{:?}",
val1,
val2,
);
}
}
);
}
#[test]
fn serialized_ironwood_tree_root_equal() {
let _init_guard = zakura_test::init();
proptest!(|(val1 in any::<ironwood::tree::Root>(), val2 in any::<ironwood::tree::Root>())| {
if val1 == val2 {
prop_assert_eq!(
val1.as_bytes(),
val2.as_bytes(),
"struct values were equal, but serialized bytes were not.\n\
Values:\n\
{:?}\n\
{:?}",
val1,
val2,
);
} else {
prop_assert_ne!(
val1.as_bytes(),
val2.as_bytes(),
"struct values were not equal, but serialized bytes were equal.\n\
Values:\n\
{:?}\n\
{:?}",
val1,
val2,
);
}
}
);
}
#[test]
fn roundtrip_ironwood_tree_root() {
let _init_guard = zakura_test::init();
proptest!(|(val in any::<ironwood::tree::Root>())| assert_value_properties(val));
}
#[test]
fn roundtrip_ironwood_subtree_data() {
let _init_guard = zakura_test::init();
proptest!(|(mut val in any::<NoteCommitmentSubtreeData<ironwood::tree::Node>>())| {
val.end_height.0 %= MAX_ON_DISK_HEIGHT.0 + 1;
assert_value_properties(val)
});
}
#[test]
fn roundtrip_value_balance() {
let _init_guard = zakura_test::init();
proptest!(|(val in any::<ValueBalance::<NonNegative>>())| assert_value_properties(val));
}
#[test]
fn roundtrip_block_info_with_ironwood_value_pool() {
let _init_guard = zakura_test::init();
let ironwood_amount = Amount::<NonNegative>::try_from(7).expect("7 zatoshi is a valid amount");
let block_info = BlockInfo::new(ValueBalance::from_ironwood_amount(ironwood_amount), 123);
assert_eq!(block_info.as_bytes().len(), 52);
assert_value_properties(block_info);
}
#[test]
fn block_info_decodes_legacy_value_pools() {
let _init_guard = zakura_test::init();
let orchard_amount = Amount::<NonNegative>::try_from(5).expect("5 zatoshi is a valid amount");
let deferred_amount =
Amount::<NonNegative>::try_from(11).expect("11 zatoshi is a valid amount");
let mut legacy_value_pools = ValueBalance::from_orchard_amount(orchard_amount);
legacy_value_pools.set_deferred_amount(deferred_amount);
let mut legacy_bytes = legacy_value_pools.as_bytes()[..40].to_vec();
legacy_bytes.extend_from_slice(&123_u32.to_le_bytes());
let block_info = BlockInfo::from_bytes(legacy_bytes);
assert_eq!(block_info.value_pools().orchard_amount(), orchard_amount);
assert_eq!(block_info.value_pools().deferred_amount(), deferred_amount);
assert_eq!(
block_info.value_pools().ironwood_amount(),
Amount::<NonNegative>::zero()
);
assert_eq!(block_info.size(), 123);
}