Stop using prop_filter_map to produce valid sapling shielded data (#2579)

This improves proptest results in CI and locally.

Proptests should be faster, because they are not discarding 1/16 results.

Failures should be minimised more often, improving failure logs,
and generating proptest seeds locally and in CI.

Co-authored-by: Conrado Gouvea <conrado@zfnd.org>
This commit is contained in:
teor 2021-08-07 03:32:35 +10:00 committed by GitHub
parent 4eb0344f01
commit faae1c08bf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 63 additions and 49 deletions

View File

@ -268,32 +268,39 @@ impl Arbitrary for sapling::TransferData<PerSpendAnchor> {
type Parameters = (); type Parameters = ();
fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
// TODO: add an extra spend or output using Either, and stop using filter_map vec(any::<sapling::Output>(), 0..MAX_ARBITRARY_ITEMS)
( .prop_flat_map(|outputs| {
vec( (
any::<sapling::Spend<PerSpendAnchor>>(), if outputs.is_empty() {
0..MAX_ARBITRARY_ITEMS, // must have at least one spend or output
), vec(
vec(any::<sapling::Output>(), 0..MAX_ARBITRARY_ITEMS), any::<sapling::Spend<PerSpendAnchor>>(),
) 1..MAX_ARBITRARY_ITEMS,
.prop_filter_map( )
"arbitrary v4 transfers with no spends and no outputs",
|(spends, outputs)| {
if !spends.is_empty() {
Some(sapling::TransferData::SpendsAndMaybeOutputs {
shared_anchor: FieldNotPresent,
spends: spends.try_into().unwrap(),
maybe_outputs: outputs,
})
} else if !outputs.is_empty() {
Some(sapling::TransferData::JustOutputs {
outputs: outputs.try_into().unwrap(),
})
} else { } else {
None vec(
any::<sapling::Spend<PerSpendAnchor>>(),
0..MAX_ARBITRARY_ITEMS,
)
},
Just(outputs),
)
})
.prop_map(|(spends, outputs)| {
if !spends.is_empty() {
sapling::TransferData::SpendsAndMaybeOutputs {
shared_anchor: FieldNotPresent,
spends: spends.try_into().unwrap(),
maybe_outputs: outputs,
} }
}, } else if !outputs.is_empty() {
) sapling::TransferData::JustOutputs {
outputs: outputs.try_into().unwrap(),
}
} else {
unreachable!("there must be at least one generated spend or output")
}
})
.boxed() .boxed()
} }
@ -304,33 +311,40 @@ impl Arbitrary for sapling::TransferData<SharedAnchor> {
type Parameters = (); type Parameters = ();
fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
// TODO: add an extra spend or output using Either, and stop using filter_map vec(any::<sapling::Output>(), 0..MAX_ARBITRARY_ITEMS)
( .prop_flat_map(|outputs| {
any::<sapling::tree::Root>(), (
vec( any::<sapling::tree::Root>(),
any::<sapling::Spend<SharedAnchor>>(), if outputs.is_empty() {
0..MAX_ARBITRARY_ITEMS, // must have at least one spend or output
), vec(
vec(any::<sapling::Output>(), 0..MAX_ARBITRARY_ITEMS), any::<sapling::Spend<SharedAnchor>>(),
) 1..MAX_ARBITRARY_ITEMS,
.prop_filter_map( )
"arbitrary v5 transfers with no spends and no outputs",
|(shared_anchor, spends, outputs)| {
if !spends.is_empty() {
Some(sapling::TransferData::SpendsAndMaybeOutputs {
shared_anchor,
spends: spends.try_into().unwrap(),
maybe_outputs: outputs,
})
} else if !outputs.is_empty() {
Some(sapling::TransferData::JustOutputs {
outputs: outputs.try_into().unwrap(),
})
} else { } else {
None vec(
any::<sapling::Spend<SharedAnchor>>(),
0..MAX_ARBITRARY_ITEMS,
)
},
Just(outputs),
)
})
.prop_map(|(shared_anchor, spends, outputs)| {
if !spends.is_empty() {
sapling::TransferData::SpendsAndMaybeOutputs {
shared_anchor,
spends: spends.try_into().unwrap(),
maybe_outputs: outputs,
} }
}, } else if !outputs.is_empty() {
) sapling::TransferData::JustOutputs {
outputs: outputs.try_into().unwrap(),
}
} else {
unreachable!("there must be at least one generated spend or output")
}
})
.boxed() .boxed()
} }