Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

scan(test): Implement scanner format round-trip tests #8071

Merged
merged 3 commits into from
Dec 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions zebra-chain/src/block/height.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down Expand Up @@ -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.
Expand Down
9 changes: 9 additions & 0 deletions zebra-state/src/service/finalized_state/disk_format/scan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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 {
Expand All @@ -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,
Expand All @@ -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,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
//! Tests for scanner database serialization.

mod prop;
Original file line number Diff line number Diff line change
@@ -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 changes: 14 additions & 12 deletions zebra-state/src/service/finalized_state/disk_format/tests/prop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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)
}
);
Expand Down Expand Up @@ -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)
}
);
Expand Down Expand Up @@ -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)
}
);
Expand All @@ -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)
}
);
Expand All @@ -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)
}
);
Expand All @@ -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)
}
Expand All @@ -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)
}
Expand Down Expand Up @@ -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)
});
Expand Down
Loading