Make nullifier tests faster and consistent with UTXO tests (#2513)
* Make some NonFinalizedState methods test-only * Rename nullifier tests for clarity * Reduce test times by reducing default proptest cases The state tests should be about 4x faster after these changes. They reduce total state test "user CPU" time to 20-30 seconds on my machine. Previously it was around 2 minutes. * Replace multiple pushes with extend Co-authored-by: Alfredo Garcia <oxarbitrage@gmail.com>
This commit is contained in:
parent
fba8a63912
commit
236388909e
|
@ -1,6 +1,6 @@
|
||||||
//! Randomised property tests for nullifier contextual validation
|
//! Randomised property tests for nullifier contextual validation
|
||||||
|
|
||||||
use std::{convert::TryInto, sync::Arc};
|
use std::{convert::TryInto, env, sync::Arc};
|
||||||
|
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use proptest::prelude::*;
|
use proptest::prelude::*;
|
||||||
|
@ -34,15 +34,24 @@ use crate::{
|
||||||
// because we're only interested in spend validation,
|
// because we're only interested in spend validation,
|
||||||
// (and passing various other state checks).
|
// (and passing various other state checks).
|
||||||
|
|
||||||
// sprout
|
const DEFAULT_NULLIFIER_PROPTEST_CASES: u32 = 16;
|
||||||
|
|
||||||
proptest! {
|
proptest! {
|
||||||
|
#![proptest_config(
|
||||||
|
proptest::test_runner::Config::with_cases(env::var("PROPTEST_CASES")
|
||||||
|
.ok()
|
||||||
|
.and_then(|v| v.parse().ok())
|
||||||
|
.unwrap_or(DEFAULT_NULLIFIER_PROPTEST_CASES))
|
||||||
|
)]
|
||||||
|
|
||||||
|
// sprout
|
||||||
|
|
||||||
/// Make sure an arbitrary sprout nullifier is accepted by state contextual validation.
|
/// Make sure an arbitrary sprout nullifier is accepted by state contextual validation.
|
||||||
///
|
///
|
||||||
/// This test makes sure there are no spurious rejections that might hide bugs in the other tests.
|
/// This test makes sure there are no spurious rejections that might hide bugs in the other tests.
|
||||||
/// (And that the test infrastructure generally works.)
|
/// (And that the test infrastructure generally works.)
|
||||||
#[test]
|
#[test]
|
||||||
fn accept_distinct_arbitrary_sprout_nullifiers(
|
fn accept_distinct_arbitrary_sprout_nullifiers_in_one_block(
|
||||||
mut joinsplit in TypeNameToDebug::<JoinSplit::<Groth16Proof>>::arbitrary(),
|
mut joinsplit in TypeNameToDebug::<JoinSplit::<Groth16Proof>>::arbitrary(),
|
||||||
joinsplit_data in TypeNameToDebug::<JoinSplitData::<Groth16Proof>>::arbitrary(),
|
joinsplit_data in TypeNameToDebug::<JoinSplitData::<Groth16Proof>>::arbitrary(),
|
||||||
use_finalized_state in any::<bool>(),
|
use_finalized_state in any::<bool>(),
|
||||||
|
@ -230,10 +239,7 @@ proptest! {
|
||||||
|
|
||||||
block1
|
block1
|
||||||
.transactions
|
.transactions
|
||||||
.push(transaction1.into());
|
.extend([transaction1.into(), transaction2.into()]);
|
||||||
block1
|
|
||||||
.transactions
|
|
||||||
.push(transaction2.into());
|
|
||||||
|
|
||||||
let (mut state, genesis) = new_state_with_mainnet_genesis();
|
let (mut state, genesis) = new_state_with_mainnet_genesis();
|
||||||
let previous_mem = state.mem.clone();
|
let previous_mem = state.mem.clone();
|
||||||
|
@ -341,17 +347,15 @@ proptest! {
|
||||||
prop_assert_eq!(Some((Height(1), block1_hash)), state.best_tip());
|
prop_assert_eq!(Some((Height(1), block1_hash)), state.best_tip());
|
||||||
prop_assert!(state.mem.eq_internal_state(&previous_mem));
|
prop_assert!(state.mem.eq_internal_state(&previous_mem));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// sapling
|
// sapling
|
||||||
|
|
||||||
proptest! {
|
|
||||||
/// Make sure an arbitrary sapling nullifier is accepted by state contextual validation.
|
/// Make sure an arbitrary sapling nullifier is accepted by state contextual validation.
|
||||||
///
|
///
|
||||||
/// This test makes sure there are no spurious rejections that might hide bugs in the other tests.
|
/// This test makes sure there are no spurious rejections that might hide bugs in the other tests.
|
||||||
/// (And that the test infrastructure generally works.)
|
/// (And that the test infrastructure generally works.)
|
||||||
#[test]
|
#[test]
|
||||||
fn accept_distinct_arbitrary_sapling_nullifiers(
|
fn accept_distinct_arbitrary_sapling_nullifiers_in_one_block(
|
||||||
spend in TypeNameToDebug::<sapling::Spend::<PerSpendAnchor>>::arbitrary(),
|
spend in TypeNameToDebug::<sapling::Spend::<PerSpendAnchor>>::arbitrary(),
|
||||||
sapling_shielded_data in TypeNameToDebug::<sapling::ShieldedData::<PerSpendAnchor>>::arbitrary(),
|
sapling_shielded_data in TypeNameToDebug::<sapling::ShieldedData::<PerSpendAnchor>>::arbitrary(),
|
||||||
use_finalized_state in any::<bool>(),
|
use_finalized_state in any::<bool>(),
|
||||||
|
@ -481,10 +485,7 @@ proptest! {
|
||||||
|
|
||||||
block1
|
block1
|
||||||
.transactions
|
.transactions
|
||||||
.push(transaction1.into());
|
.extend([transaction1.into(), transaction2.into()]);
|
||||||
block1
|
|
||||||
.transactions
|
|
||||||
.push(transaction2.into());
|
|
||||||
|
|
||||||
let (mut state, genesis) = new_state_with_mainnet_genesis();
|
let (mut state, genesis) = new_state_with_mainnet_genesis();
|
||||||
let previous_mem = state.mem.clone();
|
let previous_mem = state.mem.clone();
|
||||||
|
@ -593,17 +594,15 @@ proptest! {
|
||||||
prop_assert_eq!(Some((Height(1), block1_hash)), state.best_tip());
|
prop_assert_eq!(Some((Height(1), block1_hash)), state.best_tip());
|
||||||
prop_assert!(state.mem.eq_internal_state(&previous_mem));
|
prop_assert!(state.mem.eq_internal_state(&previous_mem));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// orchard
|
// orchard
|
||||||
|
|
||||||
proptest! {
|
|
||||||
/// Make sure an arbitrary orchard nullifier is accepted by state contextual validation.
|
/// Make sure an arbitrary orchard nullifier is accepted by state contextual validation.
|
||||||
///
|
///
|
||||||
/// This test makes sure there are no spurious rejections that might hide bugs in the other tests.
|
/// This test makes sure there are no spurious rejections that might hide bugs in the other tests.
|
||||||
/// (And that the test infrastructure generally works.)
|
/// (And that the test infrastructure generally works.)
|
||||||
#[test]
|
#[test]
|
||||||
fn accept_distinct_arbitrary_orchard_nullifiers(
|
fn accept_distinct_arbitrary_orchard_nullifiers_in_one_block(
|
||||||
authorized_action in TypeNameToDebug::<orchard::AuthorizedAction>::arbitrary(),
|
authorized_action in TypeNameToDebug::<orchard::AuthorizedAction>::arbitrary(),
|
||||||
orchard_shielded_data in TypeNameToDebug::<orchard::ShieldedData>::arbitrary(),
|
orchard_shielded_data in TypeNameToDebug::<orchard::ShieldedData>::arbitrary(),
|
||||||
use_finalized_state in any::<bool>(),
|
use_finalized_state in any::<bool>(),
|
||||||
|
@ -733,10 +732,7 @@ proptest! {
|
||||||
|
|
||||||
block1
|
block1
|
||||||
.transactions
|
.transactions
|
||||||
.push(transaction1.into());
|
.extend([transaction1.into(), transaction2.into()]);
|
||||||
block1
|
|
||||||
.transactions
|
|
||||||
.push(transaction2.into());
|
|
||||||
|
|
||||||
let (mut state, genesis) = new_state_with_mainnet_genesis();
|
let (mut state, genesis) = new_state_with_mainnet_genesis();
|
||||||
let previous_mem = state.mem.clone();
|
let previous_mem = state.mem.clone();
|
||||||
|
|
|
@ -14,13 +14,14 @@ use std::{collections::BTreeSet, mem, ops::Deref, sync::Arc};
|
||||||
|
|
||||||
use zebra_chain::{
|
use zebra_chain::{
|
||||||
block::{self, Block},
|
block::{self, Block},
|
||||||
orchard,
|
|
||||||
parameters::Network,
|
parameters::Network,
|
||||||
sapling, sprout,
|
|
||||||
transaction::{self, Transaction},
|
transaction::{self, Transaction},
|
||||||
transparent,
|
transparent,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
use zebra_chain::{orchard, sapling, sprout};
|
||||||
|
|
||||||
use crate::{FinalizedBlock, HashOrHeight, PreparedBlock, ValidateContextError};
|
use crate::{FinalizedBlock, HashOrHeight, PreparedBlock, ValidateContextError};
|
||||||
|
|
||||||
use self::chain::Chain;
|
use self::chain::Chain;
|
||||||
|
@ -309,7 +310,7 @@ impl NonFinalizedState {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns `true` if the best chain contains `sprout_nullifier`.
|
/// Returns `true` if the best chain contains `sprout_nullifier`.
|
||||||
#[allow(dead_code)]
|
#[cfg(test)]
|
||||||
pub fn best_contains_sprout_nullifier(&self, sprout_nullifier: &sprout::Nullifier) -> bool {
|
pub fn best_contains_sprout_nullifier(&self, sprout_nullifier: &sprout::Nullifier) -> bool {
|
||||||
self.best_chain()
|
self.best_chain()
|
||||||
.map(|best_chain| best_chain.sprout_nullifiers.contains(sprout_nullifier))
|
.map(|best_chain| best_chain.sprout_nullifiers.contains(sprout_nullifier))
|
||||||
|
@ -317,7 +318,7 @@ impl NonFinalizedState {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns `true` if the best chain contains `sapling_nullifier`.
|
/// Returns `true` if the best chain contains `sapling_nullifier`.
|
||||||
#[allow(dead_code)]
|
#[cfg(test)]
|
||||||
pub fn best_contains_sapling_nullifier(&self, sapling_nullifier: &sapling::Nullifier) -> bool {
|
pub fn best_contains_sapling_nullifier(&self, sapling_nullifier: &sapling::Nullifier) -> bool {
|
||||||
self.best_chain()
|
self.best_chain()
|
||||||
.map(|best_chain| best_chain.sapling_nullifiers.contains(sapling_nullifier))
|
.map(|best_chain| best_chain.sapling_nullifiers.contains(sapling_nullifier))
|
||||||
|
@ -325,7 +326,7 @@ impl NonFinalizedState {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns `true` if the best chain contains `orchard_nullifier`.
|
/// Returns `true` if the best chain contains `orchard_nullifier`.
|
||||||
#[allow(dead_code)]
|
#[cfg(test)]
|
||||||
pub fn best_contains_orchard_nullifier(&self, orchard_nullifier: &orchard::Nullifier) -> bool {
|
pub fn best_contains_orchard_nullifier(&self, orchard_nullifier: &orchard::Nullifier) -> bool {
|
||||||
self.best_chain()
|
self.best_chain()
|
||||||
.map(|best_chain| best_chain.orchard_nullifiers.contains(orchard_nullifier))
|
.map(|best_chain| best_chain.orchard_nullifiers.contains(orchard_nullifier))
|
||||||
|
|
|
@ -14,7 +14,7 @@ use crate::{
|
||||||
Config,
|
Config,
|
||||||
};
|
};
|
||||||
|
|
||||||
const DEFAULT_PARTIAL_CHAIN_PROPTEST_CASES: u32 = 32;
|
const DEFAULT_PARTIAL_CHAIN_PROPTEST_CASES: u32 = 16;
|
||||||
|
|
||||||
/// Check that a forked chain is the same as a chain that had the same blocks appended.
|
/// Check that a forked chain is the same as a chain that had the same blocks appended.
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
@ -175,17 +175,6 @@ fn state_behaves_when_blocks_are_committed_in_order() -> Result<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn state_behaves_when_blocks_are_committed_out_of_order() -> Result<()> {
|
|
||||||
zebra_test::init();
|
|
||||||
|
|
||||||
proptest!(|(blocks in out_of_order_committing_strategy())| {
|
|
||||||
populate_and_check(blocks).unwrap();
|
|
||||||
});
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
const DEFAULT_PARTIAL_CHAIN_PROPTEST_CASES: u32 = 2;
|
const DEFAULT_PARTIAL_CHAIN_PROPTEST_CASES: u32 = 2;
|
||||||
const BLOCKS_AFTER_NU5: u32 = 101;
|
const BLOCKS_AFTER_NU5: u32 = 101;
|
||||||
|
|
||||||
|
@ -197,6 +186,14 @@ proptest! {
|
||||||
.unwrap_or(DEFAULT_PARTIAL_CHAIN_PROPTEST_CASES))
|
.unwrap_or(DEFAULT_PARTIAL_CHAIN_PROPTEST_CASES))
|
||||||
)]
|
)]
|
||||||
|
|
||||||
|
/// Test out of order commits of continuous block test vectors from genesis onward.
|
||||||
|
#[test]
|
||||||
|
fn state_behaves_when_blocks_are_committed_out_of_order(blocks in out_of_order_committing_strategy()) {
|
||||||
|
zebra_test::init();
|
||||||
|
|
||||||
|
populate_and_check(blocks).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
/// Test blocks that are less than the NU5 activation height.
|
/// Test blocks that are less than the NU5 activation height.
|
||||||
#[test]
|
#[test]
|
||||||
fn some_block_less_than_network_upgrade(
|
fn some_block_less_than_network_upgrade(
|
||||||
|
|
Loading…
Reference in New Issue