rustfmt inside nullifier and utxo proptests (#2515)

* rustfmt inside nullifier and utxo proptests

* Fix a comment typo

* Use a `chain` binding to simplify test assertions
This commit is contained in:
teor 2021-07-26 13:10:24 +10:00 committed by GitHub
parent 064bef62a5
commit a7b0a521d5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 292 additions and 289 deletions

View File

@ -44,7 +44,7 @@ proptest! {
.unwrap_or(DEFAULT_NULLIFIER_PROPTEST_CASES)) .unwrap_or(DEFAULT_NULLIFIER_PROPTEST_CASES))
)] )]
// sprout // 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.
/// ///
@ -52,8 +52,8 @@ proptest! {
/// (And that the test infrastructure generally works.) /// (And that the test infrastructure generally works.)
#[test] #[test]
fn accept_distinct_arbitrary_sprout_nullifiers_in_one_block( 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>(),
) { ) {
zebra_test::init(); zebra_test::init();
@ -70,9 +70,7 @@ proptest! {
// convert the coinbase transaction to a version that the non-finalized state will accept // convert the coinbase transaction to a version that the non-finalized state will accept
block1.transactions[0] = transaction_v4_from_coinbase(&block1.transactions[0]).into(); block1.transactions[0] = transaction_v4_from_coinbase(&block1.transactions[0]).into();
block1 block1.transactions.push(transaction.into());
.transactions
.push(transaction.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();
@ -90,12 +88,15 @@ proptest! {
prop_assert!(state.mem.eq_internal_state(&previous_mem)); prop_assert!(state.mem.eq_internal_state(&previous_mem));
// the finalized state has the nullifiers // the finalized state has the nullifiers
prop_assert!(state.disk.contains_sprout_nullifier(&expected_nullifiers[0])); prop_assert!(state
prop_assert!(state.disk.contains_sprout_nullifier(&expected_nullifiers[1])); .disk
.contains_sprout_nullifier(&expected_nullifiers[0]));
prop_assert!(state
.disk
.contains_sprout_nullifier(&expected_nullifiers[1]));
} else { } else {
let block1 = Arc::new(block1).prepare(); let block1 = Arc::new(block1).prepare();
let commit_result = let commit_result = state.validate_and_commit(block1.clone());
state.validate_and_commit(block1.clone());
// the block was committed // the block was committed
prop_assert_eq!(commit_result, Ok(())); prop_assert_eq!(commit_result, Ok(()));
@ -106,8 +107,12 @@ proptest! {
// the non-finalized state has the nullifiers // the non-finalized state has the nullifiers
prop_assert_eq!(state.mem.chain_set.len(), 1); prop_assert_eq!(state.mem.chain_set.len(), 1);
prop_assert!(state.mem.best_contains_sprout_nullifier(&expected_nullifiers[0])); prop_assert!(state
prop_assert!(state.mem.best_contains_sprout_nullifier(&expected_nullifiers[1])); .mem
.best_contains_sprout_nullifier(&expected_nullifiers[0]));
prop_assert!(state
.mem
.best_contains_sprout_nullifier(&expected_nullifiers[1]));
} }
} }
@ -115,8 +120,8 @@ proptest! {
/// if they come from the same JoinSplit. /// if they come from the same JoinSplit.
#[test] #[test]
fn reject_duplicate_sprout_nullifiers_in_joinsplit( fn reject_duplicate_sprout_nullifiers_in_joinsplit(
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(),
) { ) {
zebra_test::init(); zebra_test::init();
@ -133,27 +138,23 @@ proptest! {
block1.transactions[0] = transaction_v4_from_coinbase(&block1.transactions[0]).into(); block1.transactions[0] = transaction_v4_from_coinbase(&block1.transactions[0]).into();
block1 block1.transactions.push(transaction.into());
.transactions
.push(transaction.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();
let block1 = Arc::new(block1).prepare(); let block1 = Arc::new(block1).prepare();
let commit_result = let commit_result = state.validate_and_commit(block1);
state.validate_and_commit(block1);
// if the random proptest data produces other errors, // if the random proptest data produces other errors,
// we might need to just check `is_err()` here // we might need to just check `is_err()` here
prop_assert_eq!( prop_assert_eq!(
commit_result, commit_result,
Err( Err(DuplicateSproutNullifier {
DuplicateSproutNullifier { nullifier: duplicate_nullifier,
nullifier: duplicate_nullifier, in_finalized_state: false,
in_finalized_state: false, }
}.into() .into())
)
); );
// block was rejected // block was rejected
prop_assert_eq!(Some((Height(0), genesis.hash)), state.best_tip()); prop_assert_eq!(Some((Height(0), genesis.hash)), state.best_tip());
@ -164,9 +165,9 @@ proptest! {
/// if they come from different JoinSplits in the same JoinSplitData/Transaction. /// if they come from different JoinSplits in the same JoinSplitData/Transaction.
#[test] #[test]
fn reject_duplicate_sprout_nullifiers_in_transaction( fn reject_duplicate_sprout_nullifiers_in_transaction(
mut joinsplit1 in TypeNameToDebug::<JoinSplit::<Groth16Proof>>::arbitrary(), mut joinsplit1 in TypeNameToDebug::<JoinSplit<Groth16Proof>>::arbitrary(),
mut joinsplit2 in TypeNameToDebug::<JoinSplit::<Groth16Proof>>::arbitrary(), mut joinsplit2 in TypeNameToDebug::<JoinSplit<Groth16Proof>>::arbitrary(),
joinsplit_data in TypeNameToDebug::<JoinSplitData::<Groth16Proof>>::arbitrary(), joinsplit_data in TypeNameToDebug::<JoinSplitData<Groth16Proof>>::arbitrary(),
) { ) {
zebra_test::init(); zebra_test::init();
@ -174,38 +175,37 @@ proptest! {
.zcash_deserialize_into::<Block>() .zcash_deserialize_into::<Block>()
.expect("block should deserialize"); .expect("block should deserialize");
make_distinct_nullifiers(&mut joinsplit1.nullifiers.iter_mut().chain(joinsplit2.nullifiers.iter_mut())); make_distinct_nullifiers(
&mut joinsplit1
.nullifiers
.iter_mut()
.chain(joinsplit2.nullifiers.iter_mut()),
);
// create a double-spend across two joinsplits // create a double-spend across two joinsplits
let duplicate_nullifier = joinsplit1.nullifiers[0]; let duplicate_nullifier = joinsplit1.nullifiers[0];
joinsplit2.nullifiers[0] = duplicate_nullifier; joinsplit2.nullifiers[0] = duplicate_nullifier;
let transaction = transaction_v4_with_joinsplit_data( let transaction =
joinsplit_data.0, transaction_v4_with_joinsplit_data(joinsplit_data.0, [joinsplit1.0, joinsplit2.0]);
[joinsplit1.0, joinsplit2.0]
);
block1.transactions[0] = transaction_v4_from_coinbase(&block1.transactions[0]).into(); block1.transactions[0] = transaction_v4_from_coinbase(&block1.transactions[0]).into();
block1 block1.transactions.push(transaction.into());
.transactions
.push(transaction.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();
let block1 = Arc::new(block1).prepare(); let block1 = Arc::new(block1).prepare();
let commit_result = let commit_result = state.validate_and_commit(block1);
state.validate_and_commit(block1);
prop_assert_eq!( prop_assert_eq!(
commit_result, commit_result,
Err( Err(DuplicateSproutNullifier {
DuplicateSproutNullifier { nullifier: duplicate_nullifier,
nullifier: duplicate_nullifier, in_finalized_state: false,
in_finalized_state: false, }
}.into() .into())
)
); );
prop_assert_eq!(Some((Height(0), genesis.hash)), state.best_tip()); prop_assert_eq!(Some((Height(0), genesis.hash)), state.best_tip());
prop_assert!(state.mem.eq_internal_state(&previous_mem)); prop_assert!(state.mem.eq_internal_state(&previous_mem));
@ -215,10 +215,10 @@ proptest! {
/// if they come from different transactions in the same block. /// if they come from different transactions in the same block.
#[test] #[test]
fn reject_duplicate_sprout_nullifiers_in_block( fn reject_duplicate_sprout_nullifiers_in_block(
mut joinsplit1 in TypeNameToDebug::<JoinSplit::<Groth16Proof>>::arbitrary(), mut joinsplit1 in TypeNameToDebug::<JoinSplit<Groth16Proof>>::arbitrary(),
mut joinsplit2 in TypeNameToDebug::<JoinSplit::<Groth16Proof>>::arbitrary(), mut joinsplit2 in TypeNameToDebug::<JoinSplit<Groth16Proof>>::arbitrary(),
joinsplit_data1 in TypeNameToDebug::<JoinSplitData::<Groth16Proof>>::arbitrary(), joinsplit_data1 in TypeNameToDebug::<JoinSplitData<Groth16Proof>>::arbitrary(),
joinsplit_data2 in TypeNameToDebug::<JoinSplitData::<Groth16Proof>>::arbitrary(), joinsplit_data2 in TypeNameToDebug::<JoinSplitData<Groth16Proof>>::arbitrary(),
) { ) {
zebra_test::init(); zebra_test::init();
@ -226,7 +226,12 @@ proptest! {
.zcash_deserialize_into::<Block>() .zcash_deserialize_into::<Block>()
.expect("block should deserialize"); .expect("block should deserialize");
make_distinct_nullifiers(&mut joinsplit1.nullifiers.iter_mut().chain(joinsplit2.nullifiers.iter_mut())); make_distinct_nullifiers(
&mut joinsplit1
.nullifiers
.iter_mut()
.chain(joinsplit2.nullifiers.iter_mut()),
);
// create a double-spend across two transactions // create a double-spend across two transactions
let duplicate_nullifier = joinsplit1.nullifiers[0]; let duplicate_nullifier = joinsplit1.nullifiers[0];
@ -245,17 +250,15 @@ proptest! {
let previous_mem = state.mem.clone(); let previous_mem = state.mem.clone();
let block1 = Arc::new(block1).prepare(); let block1 = Arc::new(block1).prepare();
let commit_result = let commit_result = state.validate_and_commit(block1);
state.validate_and_commit(block1);
prop_assert_eq!( prop_assert_eq!(
commit_result, commit_result,
Err( Err(DuplicateSproutNullifier {
DuplicateSproutNullifier { nullifier: duplicate_nullifier,
nullifier: duplicate_nullifier, in_finalized_state: false,
in_finalized_state: false, }
}.into() .into())
)
); );
prop_assert_eq!(Some((Height(0), genesis.hash)), state.best_tip()); prop_assert_eq!(Some((Height(0), genesis.hash)), state.best_tip());
prop_assert!(state.mem.eq_internal_state(&previous_mem)); prop_assert!(state.mem.eq_internal_state(&previous_mem));
@ -265,10 +268,10 @@ proptest! {
/// if they come from different blocks in the same chain. /// if they come from different blocks in the same chain.
#[test] #[test]
fn reject_duplicate_sprout_nullifiers_in_chain( fn reject_duplicate_sprout_nullifiers_in_chain(
mut joinsplit1 in TypeNameToDebug::<JoinSplit::<Groth16Proof>>::arbitrary(), mut joinsplit1 in TypeNameToDebug::<JoinSplit<Groth16Proof>>::arbitrary(),
mut joinsplit2 in TypeNameToDebug::<JoinSplit::<Groth16Proof>>::arbitrary(), mut joinsplit2 in TypeNameToDebug::<JoinSplit<Groth16Proof>>::arbitrary(),
joinsplit_data1 in TypeNameToDebug::<JoinSplitData::<Groth16Proof>>::arbitrary(), joinsplit_data1 in TypeNameToDebug::<JoinSplitData<Groth16Proof>>::arbitrary(),
joinsplit_data2 in TypeNameToDebug::<JoinSplitData::<Groth16Proof>>::arbitrary(), joinsplit_data2 in TypeNameToDebug::<JoinSplitData<Groth16Proof>>::arbitrary(),
duplicate_in_finalized_state in any::<bool>(), duplicate_in_finalized_state in any::<bool>(),
) { ) {
zebra_test::init(); zebra_test::init();
@ -280,7 +283,12 @@ proptest! {
.zcash_deserialize_into::<Block>() .zcash_deserialize_into::<Block>()
.expect("block should deserialize"); .expect("block should deserialize");
make_distinct_nullifiers(&mut joinsplit1.nullifiers.iter_mut().chain(joinsplit2.nullifiers.iter_mut())); make_distinct_nullifiers(
&mut joinsplit1
.nullifiers
.iter_mut()
.chain(joinsplit2.nullifiers.iter_mut()),
);
let expected_nullifiers = joinsplit1.nullifiers; let expected_nullifiers = joinsplit1.nullifiers;
// create a double-spend across two blocks // create a double-spend across two blocks
@ -293,12 +301,8 @@ proptest! {
block1.transactions[0] = transaction_v4_from_coinbase(&block1.transactions[0]).into(); block1.transactions[0] = transaction_v4_from_coinbase(&block1.transactions[0]).into();
block2.transactions[0] = transaction_v4_from_coinbase(&block2.transactions[0]).into(); block2.transactions[0] = transaction_v4_from_coinbase(&block2.transactions[0]).into();
block1 block1.transactions.push(transaction1.into());
.transactions block2.transactions.push(transaction2.into());
.push(transaction1.into());
block2
.transactions
.push(transaction2.into());
let (mut state, _genesis) = new_state_with_mainnet_genesis(); let (mut state, _genesis) = new_state_with_mainnet_genesis();
let mut previous_mem = state.mem.clone(); let mut previous_mem = state.mem.clone();
@ -312,43 +316,48 @@ 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!(commit_result.is_ok()); prop_assert!(commit_result.is_ok());
prop_assert!(state.mem.eq_internal_state(&previous_mem)); prop_assert!(state.mem.eq_internal_state(&previous_mem));
prop_assert!(state.disk.contains_sprout_nullifier(&expected_nullifiers[0])); prop_assert!(state
prop_assert!(state.disk.contains_sprout_nullifier(&expected_nullifiers[1])); .disk
.contains_sprout_nullifier(&expected_nullifiers[0]));
prop_assert!(state
.disk
.contains_sprout_nullifier(&expected_nullifiers[1]));
block1_hash = block1.hash; block1_hash = block1.hash;
} else { } else {
let block1 = Arc::new(block1).prepare(); let block1 = Arc::new(block1).prepare();
let commit_result = let commit_result = state.validate_and_commit(block1.clone());
state.validate_and_commit(block1.clone());
prop_assert_eq!(commit_result, Ok(())); prop_assert_eq!(commit_result, Ok(()));
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));
prop_assert!(state.mem.best_contains_sprout_nullifier(&expected_nullifiers[0])); prop_assert!(state
prop_assert!(state.mem.best_contains_sprout_nullifier(&expected_nullifiers[1])); .mem
.best_contains_sprout_nullifier(&expected_nullifiers[0]));
prop_assert!(state
.mem
.best_contains_sprout_nullifier(&expected_nullifiers[1]));
block1_hash = block1.hash; block1_hash = block1.hash;
previous_mem = state.mem.clone(); previous_mem = state.mem.clone();
} }
let block2 = Arc::new(block2).prepare(); let block2 = Arc::new(block2).prepare();
let commit_result = let commit_result = state.validate_and_commit(block2);
state.validate_and_commit(block2);
prop_assert_eq!( prop_assert_eq!(
commit_result, commit_result,
Err( Err(DuplicateSproutNullifier {
DuplicateSproutNullifier { nullifier: duplicate_nullifier,
nullifier: duplicate_nullifier, in_finalized_state: duplicate_in_finalized_state,
in_finalized_state: duplicate_in_finalized_state, }
}.into() .into())
)
); );
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
/// Make sure an arbitrary sapling nullifier is accepted by state contextual validation. /// Make sure an arbitrary sapling nullifier is accepted by state contextual validation.
/// ///
@ -356,8 +365,8 @@ proptest! {
/// (And that the test infrastructure generally works.) /// (And that the test infrastructure generally works.)
#[test] #[test]
fn accept_distinct_arbitrary_sapling_nullifiers_in_one_block( 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>(),
) { ) {
zebra_test::init(); zebra_test::init();
@ -368,17 +377,13 @@ proptest! {
let expected_nullifier = spend.nullifier; let expected_nullifier = spend.nullifier;
let transaction = transaction_v4_with_sapling_shielded_data( let transaction =
sapling_shielded_data.0, transaction_v4_with_sapling_shielded_data(sapling_shielded_data.0, [spend.0]);
[spend.0]
);
// convert the coinbase transaction to a version that the non-finalized state will accept // convert the coinbase transaction to a version that the non-finalized state will accept
block1.transactions[0] = transaction_v4_from_coinbase(&block1.transactions[0]).into(); block1.transactions[0] = transaction_v4_from_coinbase(&block1.transactions[0]).into();
block1 block1.transactions.push(transaction.into());
.transactions
.push(transaction.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();
@ -394,13 +399,14 @@ proptest! {
prop_assert!(state.disk.contains_sapling_nullifier(&expected_nullifier)); prop_assert!(state.disk.contains_sapling_nullifier(&expected_nullifier));
} else { } else {
let block1 = Arc::new(block1).prepare(); let block1 = Arc::new(block1).prepare();
let commit_result = let commit_result = state.validate_and_commit(block1.clone());
state.validate_and_commit(block1.clone());
prop_assert_eq!(commit_result, Ok(())); prop_assert_eq!(commit_result, Ok(()));
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));
prop_assert!(state.mem.best_contains_sapling_nullifier(&expected_nullifier)); prop_assert!(state
.mem
.best_contains_sapling_nullifier(&expected_nullifier));
} }
} }
@ -408,9 +414,9 @@ proptest! {
/// if they come from different Spends in the same sapling::ShieldedData/Transaction. /// if they come from different Spends in the same sapling::ShieldedData/Transaction.
#[test] #[test]
fn reject_duplicate_sapling_nullifiers_in_transaction( fn reject_duplicate_sapling_nullifiers_in_transaction(
spend1 in TypeNameToDebug::<sapling::Spend::<PerSpendAnchor>>::arbitrary(), spend1 in TypeNameToDebug::<sapling::Spend<PerSpendAnchor>>::arbitrary(),
mut spend2 in TypeNameToDebug::<sapling::Spend::<PerSpendAnchor>>::arbitrary(), mut spend2 in TypeNameToDebug::<sapling::Spend<PerSpendAnchor>>::arbitrary(),
sapling_shielded_data in TypeNameToDebug::<sapling::ShieldedData::<PerSpendAnchor>>::arbitrary(), sapling_shielded_data in TypeNameToDebug::<sapling::ShieldedData<PerSpendAnchor>>::arbitrary(),
) { ) {
zebra_test::init(); zebra_test::init();
@ -429,25 +435,21 @@ proptest! {
block1.transactions[0] = transaction_v4_from_coinbase(&block1.transactions[0]).into(); block1.transactions[0] = transaction_v4_from_coinbase(&block1.transactions[0]).into();
block1 block1.transactions.push(transaction.into());
.transactions
.push(transaction.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();
let block1 = Arc::new(block1).prepare(); let block1 = Arc::new(block1).prepare();
let commit_result = let commit_result = state.validate_and_commit(block1);
state.validate_and_commit(block1);
prop_assert_eq!( prop_assert_eq!(
commit_result, commit_result,
Err( Err(DuplicateSaplingNullifier {
DuplicateSaplingNullifier { nullifier: duplicate_nullifier,
nullifier: duplicate_nullifier, in_finalized_state: false,
in_finalized_state: false, }
}.into() .into())
)
); );
prop_assert_eq!(Some((Height(0), genesis.hash)), state.best_tip()); prop_assert_eq!(Some((Height(0), genesis.hash)), state.best_tip());
prop_assert!(state.mem.eq_internal_state(&previous_mem)); prop_assert!(state.mem.eq_internal_state(&previous_mem));
@ -457,10 +459,10 @@ proptest! {
/// if they come from different transactions in the same block. /// if they come from different transactions in the same block.
#[test] #[test]
fn reject_duplicate_sapling_nullifiers_in_block( fn reject_duplicate_sapling_nullifiers_in_block(
spend1 in TypeNameToDebug::<sapling::Spend::<PerSpendAnchor>>::arbitrary(), spend1 in TypeNameToDebug::<sapling::Spend<PerSpendAnchor>>::arbitrary(),
mut spend2 in TypeNameToDebug::<sapling::Spend::<PerSpendAnchor>>::arbitrary(), mut spend2 in TypeNameToDebug::<sapling::Spend<PerSpendAnchor>>::arbitrary(),
sapling_shielded_data1 in TypeNameToDebug::<sapling::ShieldedData::<PerSpendAnchor>>::arbitrary(), sapling_shielded_data1 in TypeNameToDebug::<sapling::ShieldedData<PerSpendAnchor>>::arbitrary(),
sapling_shielded_data2 in TypeNameToDebug::<sapling::ShieldedData::<PerSpendAnchor>>::arbitrary(), sapling_shielded_data2 in TypeNameToDebug::<sapling::ShieldedData<PerSpendAnchor>>::arbitrary(),
) { ) {
zebra_test::init(); zebra_test::init();
@ -472,14 +474,10 @@ proptest! {
let duplicate_nullifier = spend1.nullifier; let duplicate_nullifier = spend1.nullifier;
spend2.nullifier = duplicate_nullifier; spend2.nullifier = duplicate_nullifier;
let transaction1 = transaction_v4_with_sapling_shielded_data( let transaction1 =
sapling_shielded_data1.0, transaction_v4_with_sapling_shielded_data(sapling_shielded_data1.0, [spend1.0]);
[spend1.0] let transaction2 =
); transaction_v4_with_sapling_shielded_data(sapling_shielded_data2.0, [spend2.0]);
let transaction2 = transaction_v4_with_sapling_shielded_data(
sapling_shielded_data2.0,
[spend2.0]
);
block1.transactions[0] = transaction_v4_from_coinbase(&block1.transactions[0]).into(); block1.transactions[0] = transaction_v4_from_coinbase(&block1.transactions[0]).into();
@ -491,17 +489,15 @@ proptest! {
let previous_mem = state.mem.clone(); let previous_mem = state.mem.clone();
let block1 = Arc::new(block1).prepare(); let block1 = Arc::new(block1).prepare();
let commit_result = let commit_result = state.validate_and_commit(block1);
state.validate_and_commit(block1);
prop_assert_eq!( prop_assert_eq!(
commit_result, commit_result,
Err( Err(DuplicateSaplingNullifier {
DuplicateSaplingNullifier { nullifier: duplicate_nullifier,
nullifier: duplicate_nullifier, in_finalized_state: false,
in_finalized_state: false, }
}.into() .into())
)
); );
prop_assert_eq!(Some((Height(0), genesis.hash)), state.best_tip()); prop_assert_eq!(Some((Height(0), genesis.hash)), state.best_tip());
prop_assert!(state.mem.eq_internal_state(&previous_mem)); prop_assert!(state.mem.eq_internal_state(&previous_mem));
@ -511,10 +507,10 @@ proptest! {
/// if they come from different blocks in the same chain. /// if they come from different blocks in the same chain.
#[test] #[test]
fn reject_duplicate_sapling_nullifiers_in_chain( fn reject_duplicate_sapling_nullifiers_in_chain(
spend1 in TypeNameToDebug::<sapling::Spend::<PerSpendAnchor>>::arbitrary(), spend1 in TypeNameToDebug::<sapling::Spend<PerSpendAnchor>>::arbitrary(),
mut spend2 in TypeNameToDebug::<sapling::Spend::<PerSpendAnchor>>::arbitrary(), mut spend2 in TypeNameToDebug::<sapling::Spend<PerSpendAnchor>>::arbitrary(),
sapling_shielded_data1 in TypeNameToDebug::<sapling::ShieldedData::<PerSpendAnchor>>::arbitrary(), sapling_shielded_data1 in TypeNameToDebug::<sapling::ShieldedData<PerSpendAnchor>>::arbitrary(),
sapling_shielded_data2 in TypeNameToDebug::<sapling::ShieldedData::<PerSpendAnchor>>::arbitrary(), sapling_shielded_data2 in TypeNameToDebug::<sapling::ShieldedData<PerSpendAnchor>>::arbitrary(),
duplicate_in_finalized_state in any::<bool>(), duplicate_in_finalized_state in any::<bool>(),
) { ) {
zebra_test::init(); zebra_test::init();
@ -530,24 +526,16 @@ proptest! {
let duplicate_nullifier = spend1.nullifier; let duplicate_nullifier = spend1.nullifier;
spend2.nullifier = duplicate_nullifier; spend2.nullifier = duplicate_nullifier;
let transaction1 = transaction_v4_with_sapling_shielded_data( let transaction1 =
sapling_shielded_data1.0, transaction_v4_with_sapling_shielded_data(sapling_shielded_data1.0, [spend1.0]);
[spend1.0] let transaction2 =
); transaction_v4_with_sapling_shielded_data(sapling_shielded_data2.0, [spend2.0]);
let transaction2 = transaction_v4_with_sapling_shielded_data(
sapling_shielded_data2.0,
[spend2.0]
);
block1.transactions[0] = transaction_v4_from_coinbase(&block1.transactions[0]).into(); block1.transactions[0] = transaction_v4_from_coinbase(&block1.transactions[0]).into();
block2.transactions[0] = transaction_v4_from_coinbase(&block2.transactions[0]).into(); block2.transactions[0] = transaction_v4_from_coinbase(&block2.transactions[0]).into();
block1 block1.transactions.push(transaction1.into());
.transactions block2.transactions.push(transaction2.into());
.push(transaction1.into());
block2
.transactions
.push(transaction2.into());
let (mut state, _genesis) = new_state_with_mainnet_genesis(); let (mut state, _genesis) = new_state_with_mainnet_genesis();
let mut previous_mem = state.mem.clone(); let mut previous_mem = state.mem.clone();
@ -566,36 +554,35 @@ proptest! {
block1_hash = block1.hash; block1_hash = block1.hash;
} else { } else {
let block1 = Arc::new(block1).prepare(); let block1 = Arc::new(block1).prepare();
let commit_result = let commit_result = state.validate_and_commit(block1.clone());
state.validate_and_commit(block1.clone());
prop_assert_eq!(commit_result, Ok(())); prop_assert_eq!(commit_result, Ok(()));
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));
prop_assert!(state.mem.best_contains_sapling_nullifier(&duplicate_nullifier)); prop_assert!(state
.mem
.best_contains_sapling_nullifier(&duplicate_nullifier));
block1_hash = block1.hash; block1_hash = block1.hash;
previous_mem = state.mem.clone(); previous_mem = state.mem.clone();
} }
let block2 = Arc::new(block2).prepare(); let block2 = Arc::new(block2).prepare();
let commit_result = let commit_result = state.validate_and_commit(block2);
state.validate_and_commit(block2);
prop_assert_eq!( prop_assert_eq!(
commit_result, commit_result,
Err( Err(DuplicateSaplingNullifier {
DuplicateSaplingNullifier { nullifier: duplicate_nullifier,
nullifier: duplicate_nullifier, in_finalized_state: duplicate_in_finalized_state,
in_finalized_state: duplicate_in_finalized_state, }
}.into() .into())
)
); );
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
/// Make sure an arbitrary orchard nullifier is accepted by state contextual validation. /// Make sure an arbitrary orchard nullifier is accepted by state contextual validation.
/// ///
@ -617,15 +604,13 @@ proptest! {
let transaction = transaction_v5_with_orchard_shielded_data( let transaction = transaction_v5_with_orchard_shielded_data(
orchard_shielded_data.0, orchard_shielded_data.0,
[authorized_action.0] [authorized_action.0],
); );
// convert the coinbase transaction to a version that the non-finalized state will accept // convert the coinbase transaction to a version that the non-finalized state will accept
block1.transactions[0] = transaction_v4_from_coinbase(&block1.transactions[0]).into(); block1.transactions[0] = transaction_v4_from_coinbase(&block1.transactions[0]).into();
block1 block1.transactions.push(transaction.into());
.transactions
.push(transaction.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();
@ -641,13 +626,14 @@ proptest! {
prop_assert!(state.disk.contains_orchard_nullifier(&expected_nullifier)); prop_assert!(state.disk.contains_orchard_nullifier(&expected_nullifier));
} else { } else {
let block1 = Arc::new(block1).prepare(); let block1 = Arc::new(block1).prepare();
let commit_result = let commit_result = state.validate_and_commit(block1.clone());
state.validate_and_commit(block1.clone());
prop_assert_eq!(commit_result, Ok(())); prop_assert_eq!(commit_result, Ok(()));
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));
prop_assert!(state.mem.best_contains_orchard_nullifier(&expected_nullifier)); prop_assert!(state
.mem
.best_contains_orchard_nullifier(&expected_nullifier));
} }
} }
@ -676,25 +662,21 @@ proptest! {
block1.transactions[0] = transaction_v4_from_coinbase(&block1.transactions[0]).into(); block1.transactions[0] = transaction_v4_from_coinbase(&block1.transactions[0]).into();
block1 block1.transactions.push(transaction.into());
.transactions
.push(transaction.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();
let block1 = Arc::new(block1).prepare(); let block1 = Arc::new(block1).prepare();
let commit_result = let commit_result = state.validate_and_commit(block1);
state.validate_and_commit(block1);
prop_assert_eq!( prop_assert_eq!(
commit_result, commit_result,
Err( Err(DuplicateOrchardNullifier {
DuplicateOrchardNullifier { nullifier: duplicate_nullifier,
nullifier: duplicate_nullifier, in_finalized_state: false,
in_finalized_state: false, }
}.into() .into())
)
); );
prop_assert_eq!(Some((Height(0), genesis.hash)), state.best_tip()); prop_assert_eq!(Some((Height(0), genesis.hash)), state.best_tip());
prop_assert!(state.mem.eq_internal_state(&previous_mem)); prop_assert!(state.mem.eq_internal_state(&previous_mem));
@ -721,11 +703,11 @@ proptest! {
let transaction1 = transaction_v5_with_orchard_shielded_data( let transaction1 = transaction_v5_with_orchard_shielded_data(
orchard_shielded_data1.0, orchard_shielded_data1.0,
[authorized_action1.0] [authorized_action1.0],
); );
let transaction2 = transaction_v5_with_orchard_shielded_data( let transaction2 = transaction_v5_with_orchard_shielded_data(
orchard_shielded_data2.0, orchard_shielded_data2.0,
[authorized_action2.0] [authorized_action2.0],
); );
block1.transactions[0] = transaction_v4_from_coinbase(&block1.transactions[0]).into(); block1.transactions[0] = transaction_v4_from_coinbase(&block1.transactions[0]).into();
@ -738,17 +720,15 @@ proptest! {
let previous_mem = state.mem.clone(); let previous_mem = state.mem.clone();
let block1 = Arc::new(block1).prepare(); let block1 = Arc::new(block1).prepare();
let commit_result = let commit_result = state.validate_and_commit(block1);
state.validate_and_commit(block1);
prop_assert_eq!( prop_assert_eq!(
commit_result, commit_result,
Err( Err(DuplicateOrchardNullifier {
DuplicateOrchardNullifier { nullifier: duplicate_nullifier,
nullifier: duplicate_nullifier, in_finalized_state: false,
in_finalized_state: false, }
}.into() .into())
)
); );
prop_assert_eq!(Some((Height(0), genesis.hash)), state.best_tip()); prop_assert_eq!(Some((Height(0), genesis.hash)), state.best_tip());
prop_assert!(state.mem.eq_internal_state(&previous_mem)); prop_assert!(state.mem.eq_internal_state(&previous_mem));
@ -779,22 +759,18 @@ proptest! {
let transaction1 = transaction_v5_with_orchard_shielded_data( let transaction1 = transaction_v5_with_orchard_shielded_data(
orchard_shielded_data1.0, orchard_shielded_data1.0,
[authorized_action1.0] [authorized_action1.0],
); );
let transaction2 = transaction_v5_with_orchard_shielded_data( let transaction2 = transaction_v5_with_orchard_shielded_data(
orchard_shielded_data2.0, orchard_shielded_data2.0,
[authorized_action2.0] [authorized_action2.0],
); );
block1.transactions[0] = transaction_v4_from_coinbase(&block1.transactions[0]).into(); block1.transactions[0] = transaction_v4_from_coinbase(&block1.transactions[0]).into();
block2.transactions[0] = transaction_v4_from_coinbase(&block2.transactions[0]).into(); block2.transactions[0] = transaction_v4_from_coinbase(&block2.transactions[0]).into();
block1 block1.transactions.push(transaction1.into());
.transactions block2.transactions.push(transaction2.into());
.push(transaction1.into());
block2
.transactions
.push(transaction2.into());
let (mut state, _genesis) = new_state_with_mainnet_genesis(); let (mut state, _genesis) = new_state_with_mainnet_genesis();
let mut previous_mem = state.mem.clone(); let mut previous_mem = state.mem.clone();
@ -813,30 +789,29 @@ proptest! {
block1_hash = block1.hash; block1_hash = block1.hash;
} else { } else {
let block1 = Arc::new(block1).prepare(); let block1 = Arc::new(block1).prepare();
let commit_result = let commit_result = state.validate_and_commit(block1.clone());
state.validate_and_commit(block1.clone());
prop_assert_eq!(commit_result, Ok(())); prop_assert_eq!(commit_result, Ok(()));
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));
prop_assert!(state.mem.best_contains_orchard_nullifier(&duplicate_nullifier)); prop_assert!(state
.mem
.best_contains_orchard_nullifier(&duplicate_nullifier));
block1_hash = block1.hash; block1_hash = block1.hash;
previous_mem = state.mem.clone(); previous_mem = state.mem.clone();
} }
let block2 = Arc::new(block2).prepare(); let block2 = Arc::new(block2).prepare();
let commit_result = let commit_result = state.validate_and_commit(block2);
state.validate_and_commit(block2);
prop_assert_eq!( prop_assert_eq!(
commit_result, commit_result,
Err( Err(DuplicateOrchardNullifier {
DuplicateOrchardNullifier { nullifier: duplicate_nullifier,
nullifier: duplicate_nullifier, in_finalized_state: duplicate_in_finalized_state,
in_finalized_state: duplicate_in_finalized_state, }
}.into() .into())
)
); );
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));

View File

@ -66,7 +66,10 @@ proptest! {
let output_transaction = transaction_v4_with_transparent_data([], [output.0]); let output_transaction = transaction_v4_with_transparent_data([], [output.0]);
// create a spend // create a spend
let expected_outpoint = transparent::OutPoint { hash: output_transaction.hash(), index: 0 }; let expected_outpoint = transparent::OutPoint {
hash: output_transaction.hash(),
index: 0,
};
prevout_input.set_outpoint(expected_outpoint); prevout_input.set_outpoint(expected_outpoint);
let spend_transaction = transaction_v4_with_transparent_data([prevout_input.0], []); let spend_transaction = transaction_v4_with_transparent_data([prevout_input.0], []);
@ -98,8 +101,7 @@ proptest! {
prop_assert!(state.mem.any_utxo(&expected_outpoint).is_none()); prop_assert!(state.mem.any_utxo(&expected_outpoint).is_none());
} else { } else {
let block1 = Arc::new(block1).prepare(); let block1 = Arc::new(block1).prepare();
let commit_result = let commit_result = state.validate_and_commit(block1.clone());
state.validate_and_commit(block1.clone());
// the block was committed // the block was committed
prop_assert_eq!(commit_result, Ok(())); prop_assert_eq!(commit_result, Ok(()));
@ -108,11 +110,17 @@ proptest! {
// the block data is in the non-finalized state // the block data is in the non-finalized state
prop_assert!(!state.mem.eq_internal_state(&previous_mem)); prop_assert!(!state.mem.eq_internal_state(&previous_mem));
// the non-finalized state has the spent its own UTXO // the non-finalized state has created and spent the UTXO
prop_assert_eq!(state.mem.chain_set.len(), 1); prop_assert_eq!(state.mem.chain_set.len(), 1);
prop_assert!(!state.mem.chain_set.iter().next().unwrap().unspent_utxos().contains_key(&expected_outpoint)); let chain = state
prop_assert!(state.mem.chain_set.iter().next().unwrap().created_utxos.contains_key(&expected_outpoint)); .mem
prop_assert!(state.mem.chain_set.iter().next().unwrap().spent_utxos.contains(&expected_outpoint)); .chain_set
.iter()
.next()
.unwrap();
prop_assert!(!chain.unspent_utxos().contains_key(&expected_outpoint));
prop_assert!(chain.created_utxos.contains_key(&expected_outpoint));
prop_assert!(chain.spent_utxos.contains(&expected_outpoint));
// the finalized state does not have the UTXO // the finalized state does not have the UTXO
prop_assert!(state.disk.utxo(&expected_outpoint).is_none()); prop_assert!(state.disk.utxo(&expected_outpoint).is_none());
@ -140,10 +148,15 @@ proptest! {
.zcash_deserialize_into::<Block>() .zcash_deserialize_into::<Block>()
.expect("block should deserialize"); .expect("block should deserialize");
let TestState { mut state, block1, .. } = new_state_with_mainnet_transparent_data([], [output.0], use_finalized_state_output); let TestState {
mut state, block1, ..
} = new_state_with_mainnet_transparent_data([], [output.0], use_finalized_state_output);
let previous_mem = state.mem.clone(); let previous_mem = state.mem.clone();
let expected_outpoint = transparent::OutPoint { hash: block1.transactions[1].hash(), index: 0 }; let expected_outpoint = transparent::OutPoint {
hash: block1.transactions[1].hash(),
index: 0,
};
prevout_input.set_outpoint(expected_outpoint); prevout_input.set_outpoint(expected_outpoint);
let spend_transaction = transaction_v4_with_transparent_data([prevout_input.0], []); let spend_transaction = transaction_v4_with_transparent_data([prevout_input.0], []);
@ -151,9 +164,7 @@ proptest! {
// convert the coinbase transaction to a version that the non-finalized state will accept // convert the coinbase transaction to a version that the non-finalized state will accept
block2.transactions[0] = transaction_v4_from_coinbase(&block2.transactions[0]).into(); block2.transactions[0] = transaction_v4_from_coinbase(&block2.transactions[0]).into();
block2 block2.transactions.push(spend_transaction.into());
.transactions
.push(spend_transaction.into());
if use_finalized_state_spend { if use_finalized_state_spend {
let block2 = FinalizedBlock::from(Arc::new(block2)); let block2 = FinalizedBlock::from(Arc::new(block2));
@ -170,8 +181,7 @@ proptest! {
prop_assert!(state.disk.utxo(&expected_outpoint).is_none()); prop_assert!(state.disk.utxo(&expected_outpoint).is_none());
} else { } else {
let block2 = Arc::new(block2).prepare(); let block2 = Arc::new(block2).prepare();
let commit_result = let commit_result = state.validate_and_commit(block2.clone());
state.validate_and_commit(block2.clone());
// the block was committed // the block was committed
prop_assert_eq!(commit_result, Ok(())); prop_assert_eq!(commit_result, Ok(()));
@ -182,19 +192,25 @@ proptest! {
// the UTXO is spent // the UTXO is spent
prop_assert_eq!(state.mem.chain_set.len(), 1); prop_assert_eq!(state.mem.chain_set.len(), 1);
prop_assert!(!state.mem.chain_set.iter().next().unwrap().unspent_utxos().contains_key(&expected_outpoint)); let chain = state
.mem
.chain_set
.iter()
.next()
.unwrap();
prop_assert!(!chain.unspent_utxos().contains_key(&expected_outpoint));
if use_finalized_state_output { if use_finalized_state_output {
// the chain has spent the UTXO from the finalized state // the chain has spent the UTXO from the finalized state
prop_assert!(!state.mem.chain_set.iter().next().unwrap().created_utxos.contains_key(&expected_outpoint)); prop_assert!(!chain.created_utxos.contains_key(&expected_outpoint));
prop_assert!(state.mem.chain_set.iter().next().unwrap().spent_utxos.contains(&expected_outpoint)); prop_assert!(chain.spent_utxos.contains(&expected_outpoint));
// the finalized state has the UTXO, but it will get deleted on commit // the finalized state has the UTXO, but it will get deleted on commit
prop_assert!(state.disk.utxo(&expected_outpoint).is_some()); prop_assert!(state.disk.utxo(&expected_outpoint).is_some());
} else { } else {
// the chain has spent its own UTXO // the chain has spent its own UTXO
prop_assert!(!state.mem.chain_set.iter().next().unwrap().unspent_utxos().contains_key(&expected_outpoint)); prop_assert!(!chain.unspent_utxos().contains_key(&expected_outpoint));
prop_assert!(state.mem.chain_set.iter().next().unwrap().created_utxos.contains_key(&expected_outpoint)); prop_assert!(chain.created_utxos.contains_key(&expected_outpoint));
prop_assert!(state.mem.chain_set.iter().next().unwrap().spent_utxos.contains(&expected_outpoint)); prop_assert!(chain.spent_utxos.contains(&expected_outpoint));
// the finalized state does not have the UTXO // the finalized state does not have the UTXO
prop_assert!(state.disk.utxo(&expected_outpoint).is_none()); prop_assert!(state.disk.utxo(&expected_outpoint).is_none());
} }
@ -218,11 +234,15 @@ proptest! {
let output_transaction = transaction_v4_with_transparent_data([], [output.0]); let output_transaction = transaction_v4_with_transparent_data([], [output.0]);
let expected_outpoint = transparent::OutPoint { hash: output_transaction.hash(), index: 0 }; let expected_outpoint = transparent::OutPoint {
hash: output_transaction.hash(),
index: 0,
};
prevout_input1.set_outpoint(expected_outpoint); prevout_input1.set_outpoint(expected_outpoint);
prevout_input2.set_outpoint(expected_outpoint); prevout_input2.set_outpoint(expected_outpoint);
let spend_transaction = transaction_v4_with_transparent_data([prevout_input1.0, prevout_input2.0], []); let spend_transaction =
transaction_v4_with_transparent_data([prevout_input1.0, prevout_input2.0], []);
// convert the coinbase transaction to a version that the non-finalized state will accept // convert the coinbase transaction to a version that the non-finalized state will accept
block1.transactions[0] = transaction_v4_from_coinbase(&block1.transactions[0]).into(); block1.transactions[0] = transaction_v4_from_coinbase(&block1.transactions[0]).into();
@ -243,7 +263,8 @@ proptest! {
Err(DuplicateTransparentSpend { Err(DuplicateTransparentSpend {
outpoint: expected_outpoint, outpoint: expected_outpoint,
location: "the same block", location: "the same block",
}.into()) }
.into())
); );
prop_assert_eq!(Some((Height(0), genesis.hash)), state.best_tip()); prop_assert_eq!(Some((Height(0), genesis.hash)), state.best_tip());
@ -270,21 +291,25 @@ proptest! {
.zcash_deserialize_into::<Block>() .zcash_deserialize_into::<Block>()
.expect("block should deserialize"); .expect("block should deserialize");
let TestState { mut state, block1, .. } = new_state_with_mainnet_transparent_data([], [output.0], use_finalized_state_output); let TestState {
mut state, block1, ..
} = new_state_with_mainnet_transparent_data([], [output.0], use_finalized_state_output);
let previous_mem = state.mem.clone(); let previous_mem = state.mem.clone();
let expected_outpoint = transparent::OutPoint { hash: block1.transactions[1].hash(), index: 0 }; let expected_outpoint = transparent::OutPoint {
hash: block1.transactions[1].hash(),
index: 0,
};
prevout_input1.set_outpoint(expected_outpoint); prevout_input1.set_outpoint(expected_outpoint);
prevout_input2.set_outpoint(expected_outpoint); prevout_input2.set_outpoint(expected_outpoint);
let spend_transaction = transaction_v4_with_transparent_data([prevout_input1.0, prevout_input2.0], []); let spend_transaction =
transaction_v4_with_transparent_data([prevout_input1.0, prevout_input2.0], []);
// convert the coinbase transaction to a version that the non-finalized state will accept // convert the coinbase transaction to a version that the non-finalized state will accept
block2.transactions[0] = transaction_v4_from_coinbase(&block2.transactions[0]).into(); block2.transactions[0] = transaction_v4_from_coinbase(&block2.transactions[0]).into();
block2 block2.transactions.push(spend_transaction.into());
.transactions
.push(spend_transaction.into());
let block2 = Arc::new(block2).prepare(); let block2 = Arc::new(block2).prepare();
let commit_result = state.validate_and_commit(block2); let commit_result = state.validate_and_commit(block2);
@ -295,7 +320,8 @@ proptest! {
Err(DuplicateTransparentSpend { Err(DuplicateTransparentSpend {
outpoint: expected_outpoint, outpoint: expected_outpoint,
location: "the same block", location: "the same block",
}.into()) }
.into())
); );
prop_assert_eq!(Some((Height(1), block1.hash())), state.best_tip()); prop_assert_eq!(Some((Height(1), block1.hash())), state.best_tip());
@ -308,8 +334,14 @@ proptest! {
// the non-finalized state has no chains (so it can't have the UTXO) // the non-finalized state has no chains (so it can't have the UTXO)
prop_assert!(state.mem.chain_set.iter().next().is_none()); prop_assert!(state.mem.chain_set.iter().next().is_none());
} else { } else {
let chain = state
.mem
.chain_set
.iter()
.next()
.unwrap();
// the non-finalized state has the UTXO // the non-finalized state has the UTXO
prop_assert!(state.mem.chain_set.iter().next().unwrap().unspent_utxos().contains_key(&expected_outpoint)); prop_assert!(chain.unspent_utxos().contains_key(&expected_outpoint));
// the finalized state does not have the UTXO // the finalized state does not have the UTXO
prop_assert!(state.disk.utxo(&expected_outpoint).is_none()); prop_assert!(state.disk.utxo(&expected_outpoint).is_none());
} }
@ -332,10 +364,15 @@ proptest! {
.zcash_deserialize_into::<Block>() .zcash_deserialize_into::<Block>()
.expect("block should deserialize"); .expect("block should deserialize");
let TestState { mut state, block1, .. } = new_state_with_mainnet_transparent_data([], [output.0], use_finalized_state_output); let TestState {
mut state, block1, ..
} = new_state_with_mainnet_transparent_data([], [output.0], use_finalized_state_output);
let previous_mem = state.mem.clone(); let previous_mem = state.mem.clone();
let expected_outpoint = transparent::OutPoint { hash: block1.transactions[1].hash(), index: 0 }; let expected_outpoint = transparent::OutPoint {
hash: block1.transactions[1].hash(),
index: 0,
};
prevout_input1.set_outpoint(expected_outpoint); prevout_input1.set_outpoint(expected_outpoint);
prevout_input2.set_outpoint(expected_outpoint); prevout_input2.set_outpoint(expected_outpoint);
@ -358,7 +395,8 @@ proptest! {
Err(DuplicateTransparentSpend { Err(DuplicateTransparentSpend {
outpoint: expected_outpoint, outpoint: expected_outpoint,
location: "the same block", location: "the same block",
}.into()) }
.into())
); );
prop_assert_eq!(Some((Height(1), block1.hash())), state.best_tip()); prop_assert_eq!(Some((Height(1), block1.hash())), state.best_tip());
@ -371,8 +409,14 @@ proptest! {
// the non-finalized state has no chains (so it can't have the UTXO) // the non-finalized state has no chains (so it can't have the UTXO)
prop_assert!(state.mem.chain_set.iter().next().is_none()); prop_assert!(state.mem.chain_set.iter().next().is_none());
} else { } else {
let chain = state
.mem
.chain_set
.iter()
.next()
.unwrap();
// the non-finalized state has the UTXO // the non-finalized state has the UTXO
prop_assert!(state.mem.chain_set.iter().next().unwrap().unspent_utxos().contains_key(&expected_outpoint)); prop_assert!(chain.unspent_utxos().contains_key(&expected_outpoint));
// the finalized state does not have the UTXO // the finalized state does not have the UTXO
prop_assert!(state.disk.utxo(&expected_outpoint).is_none()); prop_assert!(state.disk.utxo(&expected_outpoint).is_none());
} }
@ -405,10 +449,15 @@ proptest! {
.zcash_deserialize_into::<Block>() .zcash_deserialize_into::<Block>()
.expect("block should deserialize"); .expect("block should deserialize");
let TestState { mut state, block1, .. } = new_state_with_mainnet_transparent_data([], [output.0], use_finalized_state_output); let TestState {
mut state, block1, ..
} = new_state_with_mainnet_transparent_data([], [output.0], use_finalized_state_output);
let mut previous_mem = state.mem.clone(); let mut previous_mem = state.mem.clone();
let expected_outpoint = transparent::OutPoint { hash: block1.transactions[1].hash(), index: 0 }; let expected_outpoint = transparent::OutPoint {
hash: block1.transactions[1].hash(),
index: 0,
};
prevout_input1.set_outpoint(expected_outpoint); prevout_input1.set_outpoint(expected_outpoint);
prevout_input2.set_outpoint(expected_outpoint); prevout_input2.set_outpoint(expected_outpoint);
@ -419,12 +468,8 @@ proptest! {
block2.transactions[0] = transaction_v4_from_coinbase(&block2.transactions[0]).into(); block2.transactions[0] = transaction_v4_from_coinbase(&block2.transactions[0]).into();
block3.transactions[0] = transaction_v4_from_coinbase(&block3.transactions[0]).into(); block3.transactions[0] = transaction_v4_from_coinbase(&block3.transactions[0]).into();
block2 block2.transactions.push(spend_transaction1.into());
.transactions block3.transactions.push(spend_transaction2.into());
.push(spend_transaction1.into());
block3
.transactions
.push(spend_transaction2.into());
let block2 = Arc::new(block2); let block2 = Arc::new(block2);
@ -455,45 +500,23 @@ proptest! {
prop_assert!(!state.mem.eq_internal_state(&previous_mem)); prop_assert!(!state.mem.eq_internal_state(&previous_mem));
prop_assert_eq!(state.mem.chain_set.len(), 1); prop_assert_eq!(state.mem.chain_set.len(), 1);
let chain = state
.mem
.chain_set
.iter()
.next()
.unwrap();
if use_finalized_state_output { if use_finalized_state_output {
// the finalized state has the unspent UTXO // the finalized state has the unspent UTXO
prop_assert!(state.disk.utxo(&expected_outpoint).is_some()); prop_assert!(state.disk.utxo(&expected_outpoint).is_some());
// the non-finalized state has spent the UTXO // the non-finalized state has spent the UTXO
prop_assert!(state prop_assert!(chain.spent_utxos.contains(&expected_outpoint));
.mem
.chain_set
.iter()
.next()
.unwrap()
.spent_utxos
.contains(&expected_outpoint));
} else { } else {
// the non-finalized state has created and spent the UTXO // the non-finalized state has created and spent the UTXO
prop_assert!(!state prop_assert!(!chain.unspent_utxos().contains_key(&expected_outpoint));
.mem prop_assert!(chain.created_utxos.contains_key(&expected_outpoint));
.chain_set prop_assert!(chain.spent_utxos.contains(&expected_outpoint));
.iter()
.next()
.unwrap()
.unspent_utxos()
.contains_key(&expected_outpoint));
prop_assert!(state
.mem
.chain_set
.iter()
.next()
.unwrap()
.created_utxos
.contains_key(&expected_outpoint));
prop_assert!(state
.mem
.chain_set
.iter()
.next()
.unwrap()
.spent_utxos
.contains(&expected_outpoint));
// the finalized state does not have the UTXO // the finalized state does not have the UTXO
prop_assert!(state.disk.utxo(&expected_outpoint).is_none()); prop_assert!(state.disk.utxo(&expected_outpoint).is_none());
} }
@ -511,7 +534,8 @@ proptest! {
Err(MissingTransparentOutput { Err(MissingTransparentOutput {
outpoint: expected_outpoint, outpoint: expected_outpoint,
location: "the non-finalized and finalized chain", location: "the non-finalized and finalized chain",
}.into()) }
.into())
); );
} else { } else {
prop_assert_eq!( prop_assert_eq!(
@ -519,7 +543,8 @@ proptest! {
Err(DuplicateTransparentSpend { Err(DuplicateTransparentSpend {
outpoint: expected_outpoint, outpoint: expected_outpoint,
location: "the non-finalized chain", location: "the non-finalized chain",
}.into()) }
.into())
); );
} }
prop_assert_eq!(Some((Height(2), block2.hash())), state.best_tip()); prop_assert_eq!(Some((Height(2), block2.hash())), state.best_tip());
@ -560,9 +585,7 @@ proptest! {
// convert the coinbase transaction to a version that the non-finalized state will accept // convert the coinbase transaction to a version that the non-finalized state will accept
block1.transactions[0] = transaction_v4_from_coinbase(&block1.transactions[0]).into(); block1.transactions[0] = transaction_v4_from_coinbase(&block1.transactions[0]).into();
block1 block1.transactions.push(spend_transaction.into());
.transactions
.push(spend_transaction.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();
@ -576,7 +599,8 @@ proptest! {
Err(MissingTransparentOutput { Err(MissingTransparentOutput {
outpoint: expected_outpoint, outpoint: expected_outpoint,
location: "the non-finalized and finalized chain", location: "the non-finalized and finalized chain",
}.into()) }
.into())
); );
prop_assert_eq!(Some((Height(0), genesis.hash)), state.best_tip()); prop_assert_eq!(Some((Height(0), genesis.hash)), state.best_tip());
@ -607,7 +631,10 @@ proptest! {
let output_transaction = transaction_v4_with_transparent_data([], [output.0]); let output_transaction = transaction_v4_with_transparent_data([], [output.0]);
// create a spend // create a spend
let expected_outpoint = transparent::OutPoint { hash: output_transaction.hash(), index: 0 }; let expected_outpoint = transparent::OutPoint {
hash: output_transaction.hash(),
index: 0,
};
prevout_input.set_outpoint(expected_outpoint); prevout_input.set_outpoint(expected_outpoint);
let spend_transaction = transaction_v4_with_transparent_data([prevout_input.0], []); let spend_transaction = transaction_v4_with_transparent_data([prevout_input.0], []);
@ -630,7 +657,8 @@ proptest! {
commit_result, commit_result,
Err(EarlyTransparentSpend { Err(EarlyTransparentSpend {
outpoint: expected_outpoint, outpoint: expected_outpoint,
}.into()) }
.into())
); );
prop_assert_eq!(Some((Height(0), genesis.hash)), state.best_tip()); prop_assert_eq!(Some((Height(0), genesis.hash)), state.best_tip());