scan(test): Implement scanner format round-trip tests (#8071)
* Implement scanner format round-trip tests * Limit random heights to database range * Increase coverage of state height serialization proptests #7443
This commit is contained in:
parent
6306a755de
commit
1ccf5fba46
|
@ -23,6 +23,7 @@ pub mod json_conversion;
|
|||
/// There are multiple formats for serializing a height, so we don't implement
|
||||
/// `ZcashSerialize` or `ZcashDeserialize` for `Height`.
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
|
||||
#[cfg_attr(any(test, feature = "proptest-impl"), derive(Default))]
|
||||
pub struct Height(pub u32);
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
|
|
|
@ -65,7 +65,7 @@ pub const TRANSACTION_LOCATION_DISK_BYTES: usize = HEIGHT_DISK_BYTES + TX_INDEX_
|
|||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||
#[cfg_attr(
|
||||
any(test, feature = "proptest-impl"),
|
||||
derive(Arbitrary, Serialize, Deserialize)
|
||||
derive(Arbitrary, Default, Serialize, Deserialize)
|
||||
)]
|
||||
pub struct TransactionIndex(pub(super) u16);
|
||||
|
||||
|
@ -126,7 +126,7 @@ impl TransactionIndex {
|
|||
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||
#[cfg_attr(
|
||||
any(test, feature = "proptest-impl"),
|
||||
derive(Arbitrary, Serialize, Deserialize)
|
||||
derive(Arbitrary, Default, Serialize, Deserialize)
|
||||
)]
|
||||
pub struct TransactionLocation {
|
||||
/// The block height of the transaction.
|
||||
|
|
|
@ -13,6 +13,12 @@ use crate::{FromDisk, IntoDisk, TransactionLocation};
|
|||
|
||||
use super::block::TRANSACTION_LOCATION_DISK_BYTES;
|
||||
|
||||
#[cfg(any(test, feature = "proptest-impl"))]
|
||||
use proptest_derive::Arbitrary;
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
/// The type used in Zebra to store Sapling scanning keys.
|
||||
/// It can represent a full viewing key or an individual viewing key.
|
||||
pub type SaplingScanningKey = String;
|
||||
|
@ -22,6 +28,7 @@ pub type SaplingScanningKey = String;
|
|||
/// Currently contains a TXID in "display order", which is big-endian byte order following the u256
|
||||
/// convention set by Bitcoin and zcashd.
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
#[cfg_attr(any(test, feature = "proptest-impl"), derive(Arbitrary, Default))]
|
||||
pub struct SaplingScannedResult([u8; 32]);
|
||||
|
||||
impl From<SaplingScannedResult> for transaction::Hash {
|
||||
|
@ -38,6 +45,7 @@ impl From<&[u8; 32]> for SaplingScannedResult {
|
|||
|
||||
/// A database column family entry for a block scanned with a Sapling vieweing key.
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
#[cfg_attr(any(test, feature = "proptest-impl"), derive(Arbitrary, Default))]
|
||||
pub struct SaplingScannedDatabaseEntry {
|
||||
/// The database column family key. Must be unique for each scanning key and scanned block.
|
||||
pub index: SaplingScannedDatabaseIndex,
|
||||
|
@ -48,6 +56,7 @@ pub struct SaplingScannedDatabaseEntry {
|
|||
|
||||
/// A database column family key for a block scanned with a Sapling vieweing key.
|
||||
#[derive(Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
|
||||
#[cfg_attr(any(test, feature = "proptest-impl"), derive(Arbitrary, Default))]
|
||||
pub struct SaplingScannedDatabaseIndex {
|
||||
/// The Sapling viewing key used to scan the block.
|
||||
pub sapling_key: SaplingScanningKey,
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
//! Tests for scanner database serialization.
|
||||
|
||||
mod prop;
|
|
@ -0,0 +1,44 @@
|
|||
//! Randomised proptests for scanner database formats.
|
||||
|
||||
use proptest::{arbitrary::any, prelude::*};
|
||||
|
||||
use crate::{
|
||||
service::finalized_state::arbitrary::assert_value_properties, SaplingScannedDatabaseIndex,
|
||||
SaplingScannedResult, SaplingScanningKey, MAX_ON_DISK_HEIGHT,
|
||||
};
|
||||
|
||||
#[test]
|
||||
fn roundtrip_sapling_scanning_key() {
|
||||
let _init_guard = zebra_test::init();
|
||||
|
||||
proptest!(|(val in any::<SaplingScanningKey>())| assert_value_properties(val));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn roundtrip_sapling_db_index() {
|
||||
let _init_guard = zebra_test::init();
|
||||
|
||||
proptest!(
|
||||
|(mut val in any::<SaplingScannedDatabaseIndex>())| {
|
||||
// Limit the random height to the valid on-disk range.
|
||||
// Blocks outside this range are rejected before they reach the state.
|
||||
// (It would take decades to generate a valid chain this high.)
|
||||
val.tx_loc.height.0 %= MAX_ON_DISK_HEIGHT.0 + 1;
|
||||
assert_value_properties(val)
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn roundtrip_sapling_result() {
|
||||
let _init_guard = zebra_test::init();
|
||||
|
||||
proptest!(|(val in any::<SaplingScannedResult>())| assert_value_properties(val));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn roundtrip_option_sapling_result() {
|
||||
let _init_guard = zebra_test::init();
|
||||
|
||||
proptest!(|(val in any::<Option<SaplingScannedResult>>())| assert_value_properties(val));
|
||||
}
|
|
@ -26,12 +26,15 @@ use crate::service::finalized_state::{
|
|||
|
||||
// Common
|
||||
|
||||
// TODO: turn this into a unit test, it has a fixed value
|
||||
/// This test has a fixed value, so testing it once is sufficient.
|
||||
#[test]
|
||||
fn roundtrip_unit_type() {
|
||||
let _init_guard = zebra_test::init();
|
||||
|
||||
proptest!(|(val in any::<()>())| assert_value_properties(val));
|
||||
// The unit type `()` is serialized to the empty (zero-length) array `[]`.
|
||||
#[allow(clippy::let_unit_value)]
|
||||
let value = ();
|
||||
assert_value_properties(value);
|
||||
}
|
||||
|
||||
// Block
|
||||
|
@ -46,7 +49,7 @@ fn roundtrip_block_height() {
|
|||
// Limit the random height to the valid on-disk range.
|
||||
// Blocks outside this range are rejected before they reach the state.
|
||||
// (It would take decades to generate a valid chain this high.)
|
||||
val = val.clamp(Height(0), MAX_ON_DISK_HEIGHT);
|
||||
val.0 %= MAX_ON_DISK_HEIGHT.0 + 1;
|
||||
assert_value_properties(val)
|
||||
}
|
||||
);
|
||||
|
@ -74,7 +77,7 @@ fn roundtrip_transaction_location() {
|
|||
|
||||
proptest!(
|
||||
|(mut val in any::<TransactionLocation>())| {
|
||||
val.height = val.height.clamp(Height(0), MAX_ON_DISK_HEIGHT);
|
||||
val.height.0 %= MAX_ON_DISK_HEIGHT.0 + 1;
|
||||
assert_value_properties(val)
|
||||
}
|
||||
);
|
||||
|
@ -142,7 +145,7 @@ fn roundtrip_output_location() {
|
|||
|
||||
proptest!(
|
||||
|(mut val in any::<OutputLocation>())| {
|
||||
*val.height_mut() = val.height().clamp(Height(0), MAX_ON_DISK_HEIGHT);
|
||||
val.height_mut().0 %= MAX_ON_DISK_HEIGHT.0 + 1;
|
||||
assert_value_properties(val)
|
||||
}
|
||||
);
|
||||
|
@ -154,7 +157,7 @@ fn roundtrip_address_location() {
|
|||
|
||||
proptest!(
|
||||
|(mut val in any::<AddressLocation>())| {
|
||||
*val.height_mut() = val.height().clamp(Height(0), MAX_ON_DISK_HEIGHT);
|
||||
val.height_mut().0 %= MAX_ON_DISK_HEIGHT.0 + 1;
|
||||
assert_value_properties(val)
|
||||
}
|
||||
);
|
||||
|
@ -166,7 +169,7 @@ fn roundtrip_address_balance_location() {
|
|||
|
||||
proptest!(
|
||||
|(mut val in any::<AddressBalanceLocation>())| {
|
||||
*val.height_mut() = val.address_location().height().clamp(Height(0), MAX_ON_DISK_HEIGHT);
|
||||
val.height_mut().0 %= MAX_ON_DISK_HEIGHT.0 + 1;
|
||||
assert_value_properties(val)
|
||||
}
|
||||
);
|
||||
|
@ -185,8 +188,8 @@ fn roundtrip_address_unspent_output() {
|
|||
|
||||
proptest!(
|
||||
|(mut val in any::<AddressUnspentOutput>())| {
|
||||
*val.address_location_mut().height_mut() = val.address_location().height().clamp(Height(0), MAX_ON_DISK_HEIGHT);
|
||||
*val.unspent_output_location_mut().height_mut() = val.unspent_output_location().height().clamp(Height(0), MAX_ON_DISK_HEIGHT);
|
||||
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)
|
||||
}
|
||||
|
@ -199,8 +202,8 @@ fn roundtrip_address_transaction() {
|
|||
|
||||
proptest!(
|
||||
|(mut val in any::<AddressTransaction>())| {
|
||||
*val.address_location_mut().height_mut() = val.address_location().height().clamp(Height(0), MAX_ON_DISK_HEIGHT);
|
||||
val.transaction_location_mut().height = val.transaction_location().height.clamp(Height(0), MAX_ON_DISK_HEIGHT);
|
||||
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)
|
||||
}
|
||||
|
@ -461,7 +464,6 @@ fn roundtrip_orchard_subtree_data() {
|
|||
let _init_guard = zebra_test::init();
|
||||
|
||||
proptest!(|(mut val in any::<NoteCommitmentSubtreeData<orchard::tree::Node>>())| {
|
||||
val.end_height = val.end_height.clamp(Height(0), MAX_ON_DISK_HEIGHT);
|
||||
val.end_height.0 %= MAX_ON_DISK_HEIGHT.0 + 1;
|
||||
assert_value_properties(val)
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue