From 59cb2b963fa3fc0ee7a22d460a5a28d005fdab34 Mon Sep 17 00:00:00 2001 From: Yevhenii Babichenko Date: Mon, 4 Oct 2021 09:48:05 +0300 Subject: [PATCH 1/2] WIP chain-impl-mockchain proptest --- cardano-legacy-address/Cargo.toml | 4 + cardano-legacy-address/src/address.rs | 6 +- chain-addr/src/lib.rs | 4 + chain-crypto/src/key.rs | 11 + chain-crypto/src/testing.rs | 41 +++ chain-impl-mockchain/Cargo.toml | 12 +- .../accounting/account/account_state.txt | 8 + .../proptest-regressions/block/test.txt | 7 + .../proptest-regressions/fee.txt | 7 + .../proptest-regressions/fragment/test.txt | 9 + .../proptest-regressions/ledger/ledger.txt | 7 + .../proptest-regressions/ledger/pots.txt | 7 + .../ledger/tests/discrimination_tests.txt | 8 + .../ledger/tests/update_tests.txt | 7 + .../proptest-regressions/rewards.txt | 7 + .../proptest-regressions/stake/controlled.txt | 7 + .../stake/distribution.txt | 7 + .../proptest-regressions/transaction/test.txt | 7 + .../proptest-regressions/update.txt | 7 + .../proptest-regressions/utxo.txt | 7 + chain-impl-mockchain/src/account.rs | 9 +- .../src/accounting/account/account_state.rs | 192 +++++++----- .../src/accounting/account/last_rewards.rs | 4 + .../src/accounting/account/mod.rs | 269 ++++++++--------- chain-impl-mockchain/src/block/headerraw.rs | 9 +- chain-impl-mockchain/src/block/mod.rs | 14 + chain-impl-mockchain/src/block/test.rs | 94 +++--- .../src/certificate/delegation.rs | 8 + .../src/certificate/encrypted_vote_tally.rs | 8 + chain-impl-mockchain/src/certificate/mod.rs | 13 +- chain-impl-mockchain/src/certificate/pool.rs | 57 ++++ chain-impl-mockchain/src/certificate/test.rs | 20 +- .../src/certificate/vote_cast.rs | 4 + .../src/certificate/vote_plan.rs | 62 +++- .../src/certificate/vote_tally.rs | 12 + chain-impl-mockchain/src/chaineval.rs | 12 + chain-impl-mockchain/src/chaintypes.rs | 8 + chain-impl-mockchain/src/config.rs | 19 +- chain-impl-mockchain/src/date.rs | 4 + chain-impl-mockchain/src/fee.rs | 71 +++-- chain-impl-mockchain/src/fragment/config.rs | 9 +- chain-impl-mockchain/src/fragment/content.rs | 12 +- chain-impl-mockchain/src/fragment/mod.rs | 4 + chain-impl-mockchain/src/fragment/test.rs | 22 +- .../src/header/deconstruct.rs | 4 + chain-impl-mockchain/src/header/test.rs | 131 ++++++++- chain-impl-mockchain/src/header/version.rs | 23 +- chain-impl-mockchain/src/key.rs | 36 ++- chain-impl-mockchain/src/ledger/check.rs | 53 ++-- .../src/ledger/governance/parameters.rs | 21 +- .../src/ledger/governance/treasury.rs | 15 +- chain-impl-mockchain/src/ledger/ledger.rs | 174 ++++++----- chain-impl-mockchain/src/ledger/pots.rs | 87 +++--- .../src/ledger/tests/discrimination_tests.rs | 47 ++- .../src/ledger/tests/initial_funds_tests.rs | 22 +- .../src/ledger/tests/ledger_tests.rs | 94 +++--- .../src/ledger/tests/update_tests.rs | 29 +- chain-impl-mockchain/src/legacy.rs | 5 + chain-impl-mockchain/src/milli.rs | 4 + chain-impl-mockchain/src/rewards.rs | 47 ++- chain-impl-mockchain/src/setting.rs | 10 + chain-impl-mockchain/src/stake/controlled.rs | 37 ++- chain-impl-mockchain/src/stake/delegation.rs | 122 ++++---- .../src/stake/distribution.rs | 277 +++++++++--------- chain-impl-mockchain/src/stake/stake.rs | 4 + .../src/testing/arbitrary/transaction.rs | 18 +- .../src/testing/arbitrary/update_proposal.rs | 96 ++++++ .../src/testing/data/address.rs | 12 +- chain-impl-mockchain/src/testing/e2e/fees.rs | 5 +- chain-impl-mockchain/src/testing/mod.rs | 1 + .../src/testing/scenario/template/builders.rs | 4 +- .../src/testing/serialization.rs | 35 +-- chain-impl-mockchain/src/testing/strategy.rs | 43 +++ .../src/transaction/element.rs | 9 + chain-impl-mockchain/src/transaction/input.rs | 4 + .../src/transaction/payload.rs | 4 + chain-impl-mockchain/src/transaction/test.rs | 96 ++++-- .../src/transaction/transfer.rs | 4 + chain-impl-mockchain/src/transaction/utxo.rs | 4 + .../src/transaction/witness.rs | 11 +- chain-impl-mockchain/src/treasury.rs | 4 + chain-impl-mockchain/src/txbuilder.rs | 9 +- chain-impl-mockchain/src/update.rs | 44 ++- chain-impl-mockchain/src/utxo.rs | 83 ++++-- chain-impl-mockchain/src/value.rs | 4 + chain-impl-mockchain/src/vote/choice.rs | 23 +- chain-impl-mockchain/src/vote/committee.rs | 25 +- chain-impl-mockchain/src/vote/manager.rs | 46 +-- chain-impl-mockchain/src/vote/payload.rs | 47 +++ chain-impl-mockchain/src/vote/tally.rs | 17 +- chain-time/src/timeline.rs | 4 + chain-time/src/units.rs | 4 + 92 files changed, 2034 insertions(+), 980 deletions(-) create mode 100644 chain-impl-mockchain/proptest-regressions/accounting/account/account_state.txt create mode 100644 chain-impl-mockchain/proptest-regressions/block/test.txt create mode 100644 chain-impl-mockchain/proptest-regressions/fee.txt create mode 100644 chain-impl-mockchain/proptest-regressions/fragment/test.txt create mode 100644 chain-impl-mockchain/proptest-regressions/ledger/ledger.txt create mode 100644 chain-impl-mockchain/proptest-regressions/ledger/pots.txt create mode 100644 chain-impl-mockchain/proptest-regressions/ledger/tests/discrimination_tests.txt create mode 100644 chain-impl-mockchain/proptest-regressions/ledger/tests/update_tests.txt create mode 100644 chain-impl-mockchain/proptest-regressions/rewards.txt create mode 100644 chain-impl-mockchain/proptest-regressions/stake/controlled.txt create mode 100644 chain-impl-mockchain/proptest-regressions/stake/distribution.txt create mode 100644 chain-impl-mockchain/proptest-regressions/transaction/test.txt create mode 100644 chain-impl-mockchain/proptest-regressions/update.txt create mode 100644 chain-impl-mockchain/proptest-regressions/utxo.txt create mode 100644 chain-impl-mockchain/src/testing/strategy.rs diff --git a/cardano-legacy-address/Cargo.toml b/cardano-legacy-address/Cargo.toml index 3e711f659..56fbfafc6 100644 --- a/cardano-legacy-address/Cargo.toml +++ b/cardano-legacy-address/Cargo.toml @@ -22,9 +22,13 @@ chain-ser = {path = "../chain-ser"} criterion = { version = "0.3.0", optional = true } +proptest = { git = "https://github.com/input-output-hk/proptest.git", optional = true } +test-strategy = { version = "0.1", optional = true } + [features] default = [] with-bench = ["criterion"] +property-test-api = ["proptest", "test-strategy"] [[bench]] harness = false diff --git a/cardano-legacy-address/src/address.rs b/cardano-legacy-address/src/address.rs index 5f5629ea6..296537e5a 100644 --- a/cardano-legacy-address/src/address.rs +++ b/cardano-legacy-address/src/address.rs @@ -162,7 +162,11 @@ fn hash_spending_data(xpub: &XPub, attrs: &Attributes) -> [u8; 28] { /// A valid cardano Address that is displayed in base58 #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Hash)] -pub struct Addr(Vec); +#[cfg_attr( + any(test, feature = "property-test-api"), + derive(test_strategy::Arbitrary) +)] +pub struct Addr(#[cfg_attr(any(test, feature = "property-test-api"), any(proptest::collection::size_range(ed25519_bip32::XPUB_SIZE).lift()))] Vec); #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum AddressMatchXPub { diff --git a/chain-addr/src/lib.rs b/chain-addr/src/lib.rs index 8866966ca..399fcdaab 100644 --- a/chain-addr/src/lib.rs +++ b/chain-addr/src/lib.rs @@ -88,6 +88,10 @@ pub enum Kind { /// Kind Type of an address #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[cfg_attr( + any(test, feature = "property-test-api"), + derive(test_strategy::Arbitrary) +)] pub enum KindType { Single, Group, diff --git a/chain-crypto/src/key.rs b/chain-crypto/src/key.rs index 55c6d5338..4aea21ae8 100644 --- a/chain-crypto/src/key.rs +++ b/chain-crypto/src/key.rs @@ -288,4 +288,15 @@ mod test { .boxed() } } + + impl Arbitrary for SecretKey { + type Parameters = (); + type Strategy = BoxedStrategy>; + + fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { + any::<(TestCryptoGen, u32)>() + .prop_map(|(gen, idx)| SecretKey::generate(gen.get_rng(idx))) + .boxed() + } + } } diff --git a/chain-crypto/src/testing.rs b/chain-crypto/src/testing.rs index 8070d9284..c5bc1f24f 100644 --- a/chain-crypto/src/testing.rs +++ b/chain-crypto/src/testing.rs @@ -163,3 +163,44 @@ pub fn public_key_strategy() -> impl Strategy() .prop_map(|(gen, idx)| SecretKey::::generate(gen.get_rng(idx)).to_public()) } + +impl proptest::arbitrary::Arbitrary for digest::DigestOf { + type Strategy = BoxedStrategy>; + type Parameters = (); + + fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { + any::>() + .prop_map(|bytes| digest::DigestOf::>::digest(&bytes).coerce()) + .boxed() + } +} + +impl proptest::arbitrary::Arbitrary for Blake2b256 { + type Strategy = BoxedStrategy; + type Parameters = (); + + fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { + any::<[u8; Self::HASH_SIZE]>() + .prop_map(|bytes| Self::try_from_slice(&bytes).unwrap()) + .boxed() + } +} + +impl proptest::arbitrary::Arbitrary for Signature +where + A: VerificationAlgorithm + 'static, + A::Signature: Send, + T: Send + 'static, +{ + type Strategy = BoxedStrategy; + type Parameters = (); + + fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { + use proptest::collection::vec; + // generic parameters may not be used in const operations + // type parameters may not be used in const expressions + vec(any::(), A::SIGNATURE_SIZE) + .prop_map(|bytes| Self::from_binary(&bytes).unwrap()) + .boxed() + } +} diff --git a/chain-impl-mockchain/Cargo.toml b/chain-impl-mockchain/Cargo.toml index 36ba487fd..8329bed56 100644 --- a/chain-impl-mockchain/Cargo.toml +++ b/chain-impl-mockchain/Cargo.toml @@ -21,7 +21,6 @@ strum = "0.21.0" strum_macros = "0.21.0" hex = { version = "0.4.2", default-features = false, features = [ "std" ] } quickcheck = { version = "0.9", optional = true } -quickcheck_macros = { version = "0.9", optional = true } ed25519-bip32 = { version = "0.4", optional = true } thiserror = "1.0" lazy_static = { version = "1.3.0", optional = true } @@ -30,6 +29,8 @@ rand_chacha = { version = "0.3", optional = true } rayon = "1.5.0" criterion = { version = "0.3.0", optional = true } rand = "0.8" +proptest = { git = "https://github.com/input-output-hk/proptest.git", optional = true } +test-strategy = { version = "0.1", optional = true } [features] property-test-api = [ @@ -37,20 +38,23 @@ property-test-api = [ "chain-time/property-test-api", "chain-addr/property-test-api", "quickcheck", - "quickcheck_macros", "lazy_static", "rand_chacha", - "ed25519-bip32"] + "ed25519-bip32", + "proptest", + "test-strategy"] with-bench = ["criterion","property-test-api"] evm = ["chain-evm"] [dev-dependencies] quickcheck = "0.9" -quickcheck_macros = "0.9" +proptest = { git = "https://github.com/input-output-hk/proptest.git" } +test-strategy = "0.1" chain-core = { path = "../chain-core"} chain-crypto = { path = "../chain-crypto", features=["property-test-api"]} chain-time = { path = "../chain-time", features=["property-test-api"]} chain-addr = { path = "../chain-addr", features=["property-test-api"]} +cardano-legacy-address = { path = "../cardano-legacy-address", features = ["property-test-api"] } ed25519-bip32 = "0.4" rand_chacha = "0.3" lazy_static = "1.3.0" diff --git a/chain-impl-mockchain/proptest-regressions/accounting/account/account_state.txt b/chain-impl-mockchain/proptest-regressions/accounting/account/account_state.txt new file mode 100644 index 000000000..4d85772bb --- /dev/null +++ b/chain-impl-mockchain/proptest-regressions/accounting/account/account_state.txt @@ -0,0 +1,8 @@ +# Seeds for failure cases proptest has generated in the past. It is +# automatically read and these particular cases re-run before any +# novel cases are generated. +# +# It is recommended to check this file in to source control so that +# everyone who runs the test benefits from these saved cases. +xx e09a705689b01a3d9614cffcb42fa70a56c61c1b3386beebc1c7c54edefffab8 # shrinks to input = _AddRewardsArgs { account_state_no_reward: AccountState { counter: SpendingCounter(0), delegation: NonDelegated, value: Value(0), last_rewards: LastRewards { epoch: 1, reward: Value(1) }, extra: () }, value: Value(0) } +xx 447db2634032facedd7577335b8c534572638ee886279f92103b000438b56f3d # shrinks to input = _AccountStateIsConsistentArgs { account_state: AccountState { counter: SpendingCounter(0), delegation: NonDelegated, value: Value(0), last_rewards: LastRewards { epoch: 0, reward: Value(1) }, extra: () }, operations: ArbitraryOperationChain([]) } diff --git a/chain-impl-mockchain/proptest-regressions/block/test.txt b/chain-impl-mockchain/proptest-regressions/block/test.txt new file mode 100644 index 000000000..1888b1123 --- /dev/null +++ b/chain-impl-mockchain/proptest-regressions/block/test.txt @@ -0,0 +1,7 @@ +# Seeds for failure cases proptest has generated in the past. It is +# automatically read and these particular cases re-run before any +# novel cases are generated. +# +# It is recommended to check this file in to source control so that +# everyone who runs the test benefits from these saved cases. +xx 06ff120a1a57076ff1b140e1d21aa68c83e6f8fc9db72a270033b824f60665fe # shrinks to input = _BlockSerializationBijectionArgs { b: Block { header: Header { version: 0, content_size: 6620, date: BlockDate { epoch: 0, slot_id: 7 }, height: ChainLength(0), content_hash: [158, 109, 166, 250, 220, 36, 55, 159, 240, 86, 159, 131, 20, 40, 218, 123, 47, 10, 230, 58, 175, 7, 121, 63, 158, 100, 247, 249, 215, 231, 101, 99], parent_hash: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], self_hash: Hash(Blake2b256(0xd6eda981734efe98fcb557b9dde4560d0a4094595025d33bbf8a6426b0531c36)) }, contents: Contents([Transaction(Transaction { payload: [0, 0, 0, 1, 0, 0, 0, 0, 6, 4], nb_inputs: 6, nb_outputs: 4, valid_until: BlockDate { epoch: 1, slot_id: 0 }, nb_witnesses: 6, total_input_value: Err(Overflow), total_output_value: Err(Overflow) }), UpdateProposal(SignedUpdateProposal { proposal: UpdateProposalWithProposer { proposal: UpdateProposal { changes: ConfigParams([LinearFee(LinearFee { constant: 8509399299441267046, coefficient: 4162527309543075811, certificate: 1376841379703122195, per_certificate_fees: PerCertificateFee { certificate_pool_registration: None, certificate_stake_delegation: None, certificate_owner_stake_delegation: None }, per_vote_certificate_fees: PerVoteCertificateFee { certificate_vote_plan: Some(11637295236967284070), certificate_vote_cast: Some(15563684843509304925) } }), AddBftLeader(BftLeaderId(a3f8297598485c4d634ef0cca690b9228173a083a03069400f19b203a9f88bbf)), AddBftLeader(BftLeaderId(27e13e53affab664e2474a4bd4666ebcaa1cf3803d5fa6b63224da544039d307)), ConsensusGenesisPraosActiveSlotsCoeff(Milli(1753248081875394678)), PerCertificateFees(PerCertificateFee { certificate_pool_registration: Some(15112963417939073120), certificate_stake_delegation: None, certificate_owner_stake_delegation: None }), RemoveCommitteeId(CommitteeId("7c908bdf17cb3cd99826d3187bbdc8393af9642bd6c7f1791e1c7a31397c61a4")), PerVoteCertificateFees(PerVoteCertificateFee { certificate_vote_plan: Some(10042472229943517727), certificate_vote_cast: Some(15988995554858536140) }), BlockContentMaxSize(1383655495), RemoveBftLeader(BftLeaderId(4be5ddb92be1b10e9b8b03630a3f728a41bdb71682e4a97ad972d2fcf0de4ec4)), ConsensusVersion(GenesisPraos), LinearFee(LinearFee { constant: 12685328204969149040, coefficient: 6047227482761131339, certificate: 17625091382419611533, per_certificate_fees: PerCertificateFee { certificate_pool_registration: Some(4183897682099873428), certificate_stake_delegation: Some(15951037307123862837), certificate_owner_stake_delegation: Some(2720580246103682069) }, per_vote_certificate_fees: PerVoteCertificateFee { certificate_vote_plan: None, certificate_vote_cast: None } }), FeesInTreasury(true), ConsensusGenesisPraosActiveSlotsCoeff(Milli(4089406697155118316)), RemoveCommitteeId(CommitteeId("d87e46473f0658717374d1a26bdb1c91b4a29cf58bc49dd86e80fa0a40c6994d")), Discrimination(Production), TreasuryParams(TaxType { fixed: Value(9752118325682132766), ratio: Ratio { numerator: 2147106296916723114, denominator: 14895443424137118286 }, max_limit: Some(14158442014589073431) }), RemoveCommitteeId(CommitteeId("d6112629d363c95a34fd0df84a4dd3fdc82483c78ee330a7e916137edf30c1a6")), SlotDuration(184), Block0Date(Block0Date(776734601602711230)), ConsensusGenesisPraosActiveSlotsCoeff(Milli(17552911462722443627)), RemoveCommitteeId(CommitteeId("1252d4af1d1f58591a8c47ff32498ec04852ad0f36849182c67f0044e61bbf4f")), TreasuryAdd(Value(13280972954631018568)), RewardParams(Halving { constant: 7641435406615480257, ratio: Ratio { numerator: 16052536367381467884, denominator: 15293487790592492254 }, epoch_start: 4146907072, epoch_rate: 20 }), KesUpdateSpeed(2018134660), FeesInTreasury(true), ConsensusGenesisPraosActiveSlotsCoeff(Milli(14754923675532597586)), ConsensusVersion(Bft), RewardLimitNone, RewardPot(Value(18201246796688381987)), FeesInTreasury(false), RewardLimitByAbsoluteStake(Ratio { numerator: 1920053628280424939, denominator: 2879590716663920872 }), SlotsPerEpoch(1638145906), AddCommitteeId(CommitteeId("900539e800f236e1059d78cebd6f92698b67cf46ce28bc078dbbfb30e5a0c67a")), RewardLimitByAbsoluteStake(Ratio { numerator: 14303576630718179672, denominator: 2768559410632812736 }), Block0Date(Block0Date(17137352480141707314)), ConsensusGenesisPraosActiveSlotsCoeff(Milli(16481992922188455173)), ConsensusVersion(GenesisPraos), TreasuryParams(TaxType { fixed: Value(17958928178354457662), ratio: Ratio { numerator: 17492428562062473438, denominator: 11654201308158575328 }, max_limit: None }), EpochStabilityDepth(1221703950), ConsensusVersion(GenesisPraos), ProposalExpiration(3292203897), RewardLimitByAbsoluteStake(Ratio { numerator: 10541314208717098443, denominator: 5291277299498639771 }), SlotDuration(130), AddCommitteeId(CommitteeId("42913ef55d34e1139ffc8bc4a8a4870207206f569466ea2f1b5d3f992dd85039")), SlotsPerEpoch(24576303), Block0Date(Block0Date(3312505813340692318)), RewardLimitNone, SlotsPerEpoch(1323213596), AddBftLeader(BftLeaderId(cb8c20cb519c8c7ac3e0b295dff56c527e8d83a81a81a57e750b9a1217c13b19)), RewardLimitNone, Block0Date(Block0Date(8661437214991811294)), TreasuryParams(TaxType { fixed: Value(11689078349602552178), ratio: Ratio { numerator: 11823605079467177377, denominator: 16672305785547812404 }, max_limit: Some(2255781282143724533) }), RewardPot(Value(4632541792027475905)), ConsensusVersion(GenesisPraos), PoolRewardParticipationCapping((3074745667, 402711014)), ConsensusVersion(GenesisPraos), LinearFee(LinearFee { constant: 7140495616130150370, coefficient: 4032484440910129126, certificate: 11031336438978447627, per_certificate_fees: PerCertificateFee { certificate_pool_registration: Some(7718577589809081764), certificate_stake_delegation: None, certificate_owner_stake_delegation: Some(4123973342910201799) }, per_vote_certificate_fees: PerVoteCertificateFee { certificate_vote_plan: None, certificate_vote_cast: None } }), KesUpdateSpeed(237631447), AddCommitteeId(CommitteeId("3252830e3520f5dd5288c1d979b24a32012a25b7cd9413352444e3fc2f848d67")), RewardPot(Value(16384077696085144004)), RewardLimitByAbsoluteStake(Ratio { numerator: 10543051459603846454, denominator: 887552115360397344 }), RewardLimitNone, SlotsPerEpoch(1661214717), LinearFee(LinearFee { constant: 8059984570402647134, coefficient: 39049127300531479, certificate: 3948226027407986296, per_certificate_fees: PerCertificateFee { certificate_pool_registration: Some(15503156861130657588), certificate_stake_delegation: None, certificate_owner_stake_delegation: Some(1481967454901772040) }, per_vote_certificate_fees: PerVoteCertificateFee { certificate_vote_plan: None, certificate_vote_cast: Some(1328295448404180709) } }), AddBftLeader(BftLeaderId(7f2de359cd4c2ebf1b1d715bca6be4bfc7009bfe5c8b738b822b749cdea619ee)), SlotsPerEpoch(956090884), RewardLimitNone, RewardLimitNone, PerCertificateFees(PerCertificateFee { certificate_pool_registration: None, certificate_stake_delegation: Some(9739438636893886841), certificate_owner_stake_delegation: None }), AddCommitteeId(CommitteeId("560e4ecd8d4a698921ed5f5963dbb40830ae60250e077366d25c5ac7afda8b7d")), AddBftLeader(BftLeaderId(8352f2a608ca5349daa884adfd8ee7806e0ebca996f0821022eff08a5e6b42b8)), RewardLimitByAbsoluteStake(Ratio { numerator: 6584734116125462550, denominator: 12036253990287158649 }), ConsensusVersion(Bft), ProposalExpiration(2604201073), EpochStabilityDepth(1379077722), Discrimination(Test), LinearFee(LinearFee { constant: 13621583522028544318, coefficient: 17138979099487665452, certificate: 350684778578231540, per_certificate_fees: PerCertificateFee { certificate_pool_registration: Some(15665770151993010896), certificate_stake_delegation: None, certificate_owner_stake_delegation: None }, per_vote_certificate_fees: PerVoteCertificateFee { certificate_vote_plan: None, certificate_vote_cast: Some(10856295391898531934) } }), TreasuryAdd(Value(9765393528995792869)), PoolRewardParticipationCapping((948592783, 2349626577)), BlockContentMaxSize(2397117411), PerVoteCertificateFees(PerVoteCertificateFee { certificate_vote_plan: None, certificate_vote_cast: Some(3915559811430673703) }), AddCommitteeId(CommitteeId("99b0c6fb442afd9d9ed4c4caf839bcff34bc4725b5e78be6955521a4c06c2dff")), PoolRewardParticipationCapping((1178352620, 170337293)), RemoveBftLeader(BftLeaderId(24dc9a9f4c50ab1e738671c691310f383193c8487aa91706feab225f6c9b668c)), LinearFee(LinearFee { constant: 11277379489007461814, coefficient: 2979136073432554889, certificate: 17760756573326054725, per_certificate_fees: PerCertificateFee { certificate_pool_registration: Some(14824415556857542251), certificate_stake_delegation: Some(6288366692921389342), certificate_owner_stake_delegation: Some(11575744902719702944) }, per_vote_certificate_fees: PerVoteCertificateFee { certificate_vote_plan: Some(2225486405004065824), certificate_vote_cast: None } }), EpochStabilityDepth(837873635), Discrimination(Production), LinearFee(LinearFee { constant: 2453711968824352096, coefficient: 10952079859916492613, certificate: 1886187040621393249, per_certificate_fees: PerCertificateFee { certificate_pool_registration: None, certificate_stake_delegation: Some(16588748574885645602), certificate_owner_stake_delegation: Some(803654925890254406) }, per_vote_certificate_fees: PerVoteCertificateFee { certificate_vote_plan: None, certificate_vote_cast: Some(5226955558182299319) } }), Discrimination(Production), KesUpdateSpeed(2235734966), AddCommitteeId(CommitteeId("93284c7941ea1d7c016d68c3b6bec2abdb9797f2bc145249ea4629afdc230519")), BlockContentMaxSize(2010270593), RemoveBftLeader(BftLeaderId(410e46b45e0c21797110a1e809532067e08b3c85c3ca5952d1d63d5ff46b3f0f)), SlotDuration(8), ConsensusVersion(Bft), LinearFee(LinearFee { constant: 7098106361210054322, coefficient: 3991694362271223024, certificate: 7615598627963544943, per_certificate_fees: PerCertificateFee { certificate_pool_registration: None, certificate_stake_delegation: None, certificate_owner_stake_delegation: None }, per_vote_certificate_fees: PerVoteCertificateFee { certificate_vote_plan: None, certificate_vote_cast: Some(3949427096556186610) } }), RemoveBftLeader(BftLeaderId(a52618ff2044275fc41cc87fd6951917376c9433df2e40bb7fca7f6a097b7751)), TransactionMaxExpiryEpochs(126), BlockContentMaxSize(151450091), EpochStabilityDepth(67400952), TransactionMaxExpiryEpochs(99), LinearFee(LinearFee { constant: 15906912287688485838, coefficient: 11127116947801765015, certificate: 3490182911664789683, per_certificate_fees: PerCertificateFee { certificate_pool_registration: None, certificate_stake_delegation: Some(16380914555116579068), certificate_owner_stake_delegation: Some(14318800970937704367) }, per_vote_certificate_fees: PerVoteCertificateFee { certificate_vote_plan: None, certificate_vote_cast: Some(14552639958008214308) } }), RewardParams(Linear { constant: 9840803333844330212, ratio: Ratio { numerator: 10687979700188028632, denominator: 17292757975470323083 }, epoch_start: 3963359960, epoch_rate: 20 }), Discrimination(Production), TreasuryParams(TaxType { fixed: Value(8919949325672032480), ratio: Ratio { numerator: 13944088885356503677, denominator: 6552948056200122869 }, max_limit: Some(18273212044482099582) }), RemoveBftLeader(BftLeaderId(102c1eaec161f384989c61852d420fb55758bdb6d008407e80662fe2d9e62c91)), RewardPot(Value(3910160094569979999)), PerCertificateFees(PerCertificateFee { certificate_pool_registration: Some(16605280914607612999), certificate_stake_delegation: Some(7556551262097191967), certificate_owner_stake_delegation: None }), SlotDuration(127), PoolRewardParticipationCapping((102339824, 2165917817)), ConsensusGenesisPraosActiveSlotsCoeff(Milli(8437096392002565201)), TreasuryParams(TaxType { fixed: Value(5963045330779827947), ratio: Ratio { numerator: 17331075463580215462, denominator: 15592587501008951897 }, max_limit: Some(16909099279085185329) }), AddBftLeader(BftLeaderId(f81af028abc95edbea9387fe53cc4f32a5c57b5e47a295282d9a0a702edd3303)), ConsensusGenesisPraosActiveSlotsCoeff(Milli(3062346545910876903)), PerVoteCertificateFees(PerVoteCertificateFee { certificate_vote_plan: None, certificate_vote_cast: Some(5257650612084608167) }), LinearFee(LinearFee { constant: 3168665155199702088, coefficient: 17096717614894695336, certificate: 997061910474436857, per_certificate_fees: PerCertificateFee { certificate_pool_registration: None, certificate_stake_delegation: Some(14360839254652874541), certificate_owner_stake_delegation: None }, per_vote_certificate_fees: PerVoteCertificateFee { certificate_vote_plan: None, certificate_vote_cast: None } }), SlotDuration(105), Discrimination(Production), AddCommitteeId(CommitteeId("b21af0891db6ceb368573b7b928dd89013a3db6cac28ed761fd9564249db2739")), AddBftLeader(BftLeaderId(d0a2e87157c2a8af4722ced8363dc5ac208cf6ddab4bff5995a932e114f893bd)), RewardLimitNone, PerCertificateFees(PerCertificateFee { certificate_pool_registration: None, certificate_stake_delegation: Some(10725056449801933076), certificate_owner_stake_delegation: Some(12135198107892145521) }), EpochStabilityDepth(99330217), TreasuryParams(TaxType { fixed: Value(10099110182910098406), ratio: Ratio { numerator: 10229303018669426667, denominator: 5763454671461927242 }, max_limit: Some(2200289636210435033) }), TransactionMaxExpiryEpochs(130), PerCertificateFees(PerCertificateFee { certificate_pool_registration: Some(6232528293311572565), certificate_stake_delegation: None, certificate_owner_stake_delegation: None }), RewardLimitByAbsoluteStake(Ratio { numerator: 5983721778805656590, denominator: 13444132933502506694 }), ProposalExpiration(939468434), PerVoteCertificateFees(PerVoteCertificateFee { certificate_vote_plan: Some(12785862314194087409), certificate_vote_cast: None }), SlotDuration(140), LinearFee(LinearFee { constant: 18412152269980751538, coefficient: 9424852116725366251, certificate: 12765498844711618291, per_certificate_fees: PerCertificateFee { certificate_pool_registration: Some(14634791451222528837), certificate_stake_delegation: Some(7941668239369524402), certificate_owner_stake_delegation: Some(9841535889817461312) }, per_vote_certificate_fees: PerVoteCertificateFee { certificate_vote_plan: Some(15588331692655144606), certificate_vote_cast: None } }), TreasuryParams(TaxType { fixed: Value(14088748694136233438), ratio: Ratio { numerator: 15861081268486263731, denominator: 1988011914228303193 }, max_limit: Some(10441641556771275199) }), TreasuryAdd(Value(840322869061474556)), ConsensusGenesisPraosActiveSlotsCoeff(Milli(14900589618452861588)), LinearFee(LinearFee { constant: 10235015336775753781, coefficient: 15513896336687688475, certificate: 2854903378768193579, per_certificate_fees: PerCertificateFee { certificate_pool_registration: Some(9722420659591098642), certificate_stake_delegation: Some(13294792656793059341), certificate_owner_stake_delegation: None }, per_vote_certificate_fees: PerVoteCertificateFee { certificate_vote_plan: None, certificate_vote_cast: None } }), SlotDuration(229), TransactionMaxExpiryEpochs(148), RewardLimitByAbsoluteStake(Ratio { numerator: 1530801082489626184, denominator: 15416813818236756980 }), BlockContentMaxSize(641403494), AddCommitteeId(CommitteeId("0e6b1500f8f415e3f4071895ba5c89cc95ef4c22882cd7640aa9d1a579003674")), PoolRewardParticipationCapping((313593248, 1956028381)), RewardPot(Value(18284042251530822067)), TreasuryAdd(Value(3075583086304607056)), RewardPot(Value(15303516292179526701)), PerCertificateFees(PerCertificateFee { certificate_pool_registration: Some(10318471443382004797), certificate_stake_delegation: None, certificate_owner_stake_delegation: None }), AddBftLeader(BftLeaderId(9527f06df2b8e286b121c16519e3f07acd00037ddf23daf81a14c5827349123f)), ConsensusGenesisPraosActiveSlotsCoeff(Milli(1964876398486642206)), PerCertificateFees(PerCertificateFee { certificate_pool_registration: None, certificate_stake_delegation: Some(1452820359417148638), certificate_owner_stake_delegation: None }), RewardParams(Halving { constant: 2840663237314060024, ratio: Ratio { numerator: 17489398464493780743, denominator: 6906978071775227515 }, epoch_start: 4108996337, epoch_rate: 20 }), AddCommitteeId(CommitteeId("34c2c4d76ad843acaa927081e45cab9799ae5cd26af30c2949404da62e9c9969")), TreasuryAdd(Value(10256688033776831171)), RemoveBftLeader(BftLeaderId(481d425224ed18b183921b6b8584a407ecdc19263024cd1f8bac0023bfd048e9)), SlotDuration(33), AddBftLeader(BftLeaderId(377f0b17897302c9b9a2c127cda6e293d0b7e0a83d53a0d2a287dce68cf9e37c)), TransactionMaxExpiryEpochs(178), LinearFee(LinearFee { constant: 3978873879144725379, coefficient: 16540973950505804681, certificate: 16696346287438882983, per_certificate_fees: PerCertificateFee { certificate_pool_registration: Some(6061853725428924605), certificate_stake_delegation: Some(10586384229788908587), certificate_owner_stake_delegation: None }, per_vote_certificate_fees: PerVoteCertificateFee { certificate_vote_plan: None, certificate_vote_cast: None } }), EpochStabilityDepth(618432770), Discrimination(Production), SlotsPerEpoch(2128469058), RewardLimitNone, TreasuryParams(TaxType { fixed: Value(17072583796743481868), ratio: Ratio { numerator: 16262485811609083673, denominator: 6592617852650112211 }, max_limit: Some(3765954707714674295) }), RewardParams(Linear { constant: 861379852554654890, ratio: Ratio { numerator: 4415184242839363312, denominator: 7280128366854248684 }, epoch_start: 3760510918, epoch_rate: 20 }), TreasuryParams(TaxType { fixed: Value(13739153869771598700), ratio: Ratio { numerator: 3162960939031674534, denominator: 271141988726497761 }, max_limit: Some(4963134197815501365) }), BlockContentMaxSize(207411362), TreasuryAdd(Value(4054375135467990673)), RewardLimitByAbsoluteStake(Ratio { numerator: 8308895656337615487, denominator: 8983039807833092726 }), TreasuryAdd(Value(6026808084490958607)), SlotDuration(24), PoolRewardParticipationCapping((2122539623, 2622503456)), TreasuryAdd(Value(16222190083152669326)), SlotsPerEpoch(2399767084), AddBftLeader(BftLeaderId(f2e7a9b405ae87baca161f352a3c6468af5c95f301cdc6f2ec678c96b83bb59f)), KesUpdateSpeed(779802962), ConsensusGenesisPraosActiveSlotsCoeff(Milli(17325280563223443653)), SlotDuration(110), SlotsPerEpoch(81892958), Discrimination(Test), Discrimination(Production), ProposalExpiration(3367199283), PoolRewardParticipationCapping((695119476, 1531729580)), Block0Date(Block0Date(14554264792701531159)), RewardLimitByAbsoluteStake(Ratio { numerator: 14191689689372188131, denominator: 10993314962760120443 }), RewardPot(Value(8050550661329038965)), RewardLimitNone, SlotDuration(224), SlotDuration(173), PerCertificateFees(PerCertificateFee { certificate_pool_registration: None, certificate_stake_delegation: None, certificate_owner_stake_delegation: Some(2203101908808842527) }), AddBftLeader(BftLeaderId(1c4249df52708f09d30e0ec58a7b9b52393e431be049bd7dadec82a6c7768004)), RemoveBftLeader(BftLeaderId(9fabd9ce6798073a2bb28f094c01a57f3c1a8e83721396230a2a2bc96ac194e7)), SlotsPerEpoch(240553275), KesUpdateSpeed(2612543631), FeesInTreasury(false), Discrimination(Test), ProposalExpiration(3965792493), FeesInTreasury(true), SlotDuration(235), BlockContentMaxSize(2642368057), ProposalExpiration(4221859726), TreasuryParams(TaxType { fixed: Value(11154917975237732907), ratio: Ratio { numerator: 17865953634000831994, denominator: 10344664431237028729 }, max_limit: None }), PerCertificateFees(PerCertificateFee { certificate_pool_registration: Some(5761416865706133925), certificate_stake_delegation: None, certificate_owner_stake_delegation: None }), RewardPot(Value(8937186963044202742)), Discrimination(Test), Block0Date(Block0Date(5897101387390362014)), FeesInTreasury(true), TransactionMaxExpiryEpochs(31), FeesInTreasury(true), PerVoteCertificateFees(PerVoteCertificateFee { certificate_vote_plan: None, certificate_vote_cast: None }), SlotDuration(169), ConsensusGenesisPraosActiveSlotsCoeff(Milli(16460772210511487833)), BlockContentMaxSize(2761992079), TransactionMaxExpiryEpochs(237), RemoveCommitteeId(CommitteeId("cf886218900a57e787d04ff9ac21fa0acffc346c9940c7f7f2389ba4e14ee570")), PoolRewardParticipationCapping((1149436775, 69933951)), Discrimination(Test), TreasuryParams(TaxType { fixed: Value(927008255650824390), ratio: Ratio { numerator: 6955226401000245528, denominator: 4246591198647825001 }, max_limit: None }), Discrimination(Production), KesUpdateSpeed(1335919740), TreasuryAdd(Value(2919714459120548942)), PoolRewardParticipationCapping((1698061894, 3763841791)), TransactionMaxExpiryEpochs(79), RewardPot(Value(10431784303320504412)), RewardLimitByAbsoluteStake(Ratio { numerator: 16923994109212027408, denominator: 51924134095075530 }), ConsensusVersion(Bft), RemoveBftLeader(BftLeaderId(110556cd20518467e4e421a164faef421a4754c98f9f992bb582d931c37290fa)), PerCertificateFees(PerCertificateFee { certificate_pool_registration: Some(15573118951795449492), certificate_stake_delegation: Some(115411988395073004), certificate_owner_stake_delegation: None }), RewardPot(Value(1956946844664658750)), PoolRewardParticipationCapping((4009277573, 1752041216)), RemoveCommitteeId(CommitteeId("312918242580edfc0a50faa5f0d21685a5fec88c16a44150891a8b8a157efe2d")), RewardLimitNone, TreasuryParams(TaxType { fixed: Value(9817673064944884965), ratio: Ratio { numerator: 16755618815441263981, denominator: 16389447190034974052 }, max_limit: Some(12948142504440865760) }), BlockContentMaxSize(1580824279), RewardParams(Linear { constant: 8259454474807573813, ratio: Ratio { numerator: 11337254777662321394, denominator: 15974794474546166300 }, epoch_start: 2337725805, epoch_rate: 20 }), SlotsPerEpoch(4101362461), Discrimination(Test), RewardLimitNone, RewardPot(Value(6200601442349531090)), TreasuryAdd(Value(15535340948037631672)), RewardLimitByAbsoluteStake(Ratio { numerator: 3077629408339332945, denominator: 16169508396136970302 }), Block0Date(Block0Date(16181543897800330905)), RewardLimitByAbsoluteStake(Ratio { numerator: 6651747119529980409, denominator: 15944070830632150707 }), Block0Date(Block0Date(15362704349675298720)), TreasuryAdd(Value(15974334764067139595)), ConsensusVersion(GenesisPraos), TreasuryAdd(Value(9271455581264697499)), RewardPot(Value(612191669595382488)), TreasuryAdd(Value(598170329675191741)), ConsensusVersion(Bft), RewardLimitNone, AddCommitteeId(CommitteeId("c171fde8d1f1a657618c9dece27fc850aeaf984985272832476910ff76284a79")), EpochStabilityDepth(3381974364), AddCommitteeId(CommitteeId("20274436bde2bca7f830adcf2a66b52747d74bcf0652a5b8d964106dd345c863")), Block0Date(Block0Date(6608380110239032403)), TransactionMaxExpiryEpochs(132), SlotDuration(12)]) }, proposer_id: BftLeaderId(fde5e4e2f927740c4aad669505886e63e23e5959ca55b00c596349329e9111f0) } }), StakeDelegation(Transaction { payload: [197, 82, 144, 187, 105, 109, 73, 83, 141, 132, 166, 120, 29, 18, 194, 49, 251, 74, 148, 60, 221, 116, 38, 182, 145, 151, 95, 182, 236, 182, 58, 250, 0, 0, 0, 0, 1, 0, 0, 0, 0, 13, 4], nb_inputs: 13, nb_outputs: 4, valid_until: BlockDate { epoch: 1, slot_id: 0 }, nb_witnesses: 13, total_input_value: Err(Overflow), total_output_value: Err(Overflow) })]) } } diff --git a/chain-impl-mockchain/proptest-regressions/fee.txt b/chain-impl-mockchain/proptest-regressions/fee.txt new file mode 100644 index 000000000..6dc6c22b3 --- /dev/null +++ b/chain-impl-mockchain/proptest-regressions/fee.txt @@ -0,0 +1,7 @@ +# Seeds for failure cases proptest has generated in the past. It is +# automatically read and these particular cases re-run before any +# novel cases are generated. +# +# It is recommended to check this file in to source control so that +# everyone who runs the test benefits from these saved cases. +xx 3dc719c99d00969fd03e8e1d1f8d247bb5454706b24c88a7fa30c3afd0d3f412 # shrinks to input = _LinearFeeCertificateCalculationArgs { certificate: PoolRetirement(PoolRetirement { pool_id: $hash_ty(0x8257a87f25ab75cb5f6ba506adb59cf1764365e93f5e7400c3ed1fe3496f1e2f), retirement_time: TimeOffsetSeconds(DurationSeconds(7448678820576350356)) }), inputs: 141, outputs: 204, fee: LinearFee { constant: 84037131145763882, coefficient: 4127535450679263578, certificate: 16808812788604336532, per_certificate_fees: PerCertificateFee { certificate_pool_registration: Some(8974887929408341596), certificate_stake_delegation: None, certificate_owner_stake_delegation: None }, per_vote_certificate_fees: PerVoteCertificateFee { certificate_vote_plan: Some(8783595777020599411), certificate_vote_cast: None } }, per_certificate_fees: PerCertificateFee { certificate_pool_registration: Some(13700089163430403858), certificate_stake_delegation: Some(2491635649483717791), certificate_owner_stake_delegation: Some(6568572915426812252) }, per_vote_certificate_fees: PerVoteCertificateFee { certificate_vote_plan: Some(8482191035474706181), certificate_vote_cast: Some(8792449183706279014) } } diff --git a/chain-impl-mockchain/proptest-regressions/fragment/test.txt b/chain-impl-mockchain/proptest-regressions/fragment/test.txt new file mode 100644 index 000000000..757e01533 --- /dev/null +++ b/chain-impl-mockchain/proptest-regressions/fragment/test.txt @@ -0,0 +1,9 @@ +# Seeds for failure cases proptest has generated in the past. It is +# automatically read and these particular cases re-run before any +# novel cases are generated. +# +# It is recommended to check this file in to source control so that +# everyone who runs the test benefits from these saved cases. +xx f779cfcda49afe7b4e8a1522ddc9df2b628f8287d27619f92082ed7bf07e872a # shrinks to input = _InitialEntsSerializationBijectionArgs { config_params: ConfigParams([LinearFee(LinearFee { constant: 0, coefficient: 0, certificate: 0, per_certificate_fees: PerCertificateFee { certificate_pool_registration: None, certificate_stake_delegation: None, certificate_owner_stake_delegation: None }, per_vote_certificate_fees: PerVoteCertificateFee { certificate_vote_plan: None, certificate_vote_cast: Some(1) } })]) } +xx 584bc2dc033882ab5b88a47af5bf2159deb77e6cc2e017069b5d34a343430f81 # shrinks to input = _FragmentRawBijectionArgs { b: OwnerStakeDelegation(Transaction { payload: [8, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0], nb_inputs: 0, nb_outputs: 0, valid_until: BlockDate { epoch: 1, slot_id: 0 }, nb_witnesses: 0, total_input_value: Ok(Value(0)), total_output_value: Ok(Value(0)) }) } +xx 0ca2daad13262f5e0a8786a0365cf319b8cf645828481f44dc1898c5e43df8e5 # shrinks to input = _FragmentSerializationBijectionArgs { b: StakeDelegation(Transaction { payload: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0], nb_inputs: 0, nb_outputs: 0, valid_until: BlockDate { epoch: 1, slot_id: 0 }, nb_witnesses: 0, total_input_value: Ok(Value(0)), total_output_value: Ok(Value(0)) }) } diff --git a/chain-impl-mockchain/proptest-regressions/ledger/ledger.txt b/chain-impl-mockchain/proptest-regressions/ledger/ledger.txt new file mode 100644 index 000000000..18c0b0ae8 --- /dev/null +++ b/chain-impl-mockchain/proptest-regressions/ledger/ledger.txt @@ -0,0 +1,7 @@ +# Seeds for failure cases proptest has generated in the past. It is +# automatically read and these particular cases re-run before any +# novel cases are generated. +# +# It is recommended to check this file in to source control so that +# everyone who runs the test benefits from these saved cases. +xx d60c59631a4d512ed4aead7831583a4f1a6729ee20e7f4fa13b98c0d442d6615 # shrinks to input = _TestInternalApplyTransactionFundsWereTransferedArgs { sender_address: AddressData { public_key: ec612c23485d5afa5a9cd700416e1d09f12747dcf970812c47de8befb2c256b8, spending_counter: None, address: Address(Test, Single(ec612c23485d5afa5a9cd700416e1d09f12747dcf970812c47de8befb2c256b8)) }, reciever_address: AddressData { public_key: ec612c23485d5afa5a9cd700416e1d09f12747dcf970812c47de8befb2c256b8, spending_counter: None, address: Address(Test, Single(ec612c23485d5afa5a9cd700416e1d09f12747dcf970812c47de8befb2c256b8)) } } diff --git a/chain-impl-mockchain/proptest-regressions/ledger/pots.txt b/chain-impl-mockchain/proptest-regressions/ledger/pots.txt new file mode 100644 index 000000000..b073a68d9 --- /dev/null +++ b/chain-impl-mockchain/proptest-regressions/ledger/pots.txt @@ -0,0 +1,7 @@ +# Seeds for failure cases proptest has generated in the past. It is +# automatically read and these particular cases re-run before any +# novel cases are generated. +# +# It is recommended to check this file in to source control so that +# everyone who runs the test benefits from these saved cases. +xx 24cfaf93ff3cb9cbfd3da49403bce08b74535932f91dc059c2121f2f380c8d0f # shrinks to input = _TreasuryAddArgs { pots: Pots { fees: Value(0), treasury: Treasury(Value(13107457562879298199)), rewards: Value(0) }, value: Value(5339286510830253417) } diff --git a/chain-impl-mockchain/proptest-regressions/ledger/tests/discrimination_tests.txt b/chain-impl-mockchain/proptest-regressions/ledger/tests/discrimination_tests.txt new file mode 100644 index 000000000..08c26b7cd --- /dev/null +++ b/chain-impl-mockchain/proptest-regressions/ledger/tests/discrimination_tests.txt @@ -0,0 +1,8 @@ +# Seeds for failure cases proptest has generated in the past. It is +# automatically read and these particular cases re-run before any +# novel cases are generated. +# +# It is recommended to check this file in to source control so that +# everyone who runs the test benefits from these saved cases. +xx df8b322ea4a7e4ccf2bcf7660d070a40b57bd7305d30ac987c586bb539feeba2 # shrinks to input = _LedgerVerifiesFaucetDiscriminationArgs { arbitrary_faucet_disc: Production, arbitrary_faucet_address_kind: Script, arbitrary_ledger_disc: Production } +xx d44a0cf703cc32fdd0c0980c964286088e936d6e8bbc811330a8222dc6f0faa8 # shrinks to input = _LedgerVerifiesTransactionDiscriminationArgs { arbitrary_input_disc: Production, arbitrary_output_disc: Production, arbitrary_input_address_kind: Single, arbitrary_output_address_kind: Script } diff --git a/chain-impl-mockchain/proptest-regressions/ledger/tests/update_tests.txt b/chain-impl-mockchain/proptest-regressions/ledger/tests/update_tests.txt new file mode 100644 index 000000000..13d6be625 --- /dev/null +++ b/chain-impl-mockchain/proptest-regressions/ledger/tests/update_tests.txt @@ -0,0 +1,7 @@ +# Seeds for failure cases proptest has generated in the past. It is +# automatically read and these particular cases re-run before any +# novel cases are generated. +# +# It is recommended to check this file in to source control so that +# everyone who runs the test benefits from these saved cases. +xx 282ba5a0bd548585b46e68632d5ca4dbc017bf3ddf5508f7de77c50e9a4c5431 # shrinks to input = _LedgerAdoptSettingsFromUpdateProposalArgs { update_proposal_data: UpdateProposalData { leaders: [BftLeaderId(2e5d30506528a9d2499eec72f80c52f29683d952ebda0b37124b1706344b0a73)], proposal: SignedUpdateProposal { proposal: UpdateProposalWithProposer { proposal: UpdateProposal { changes: ConfigParams([]) }, proposer_id: BftLeaderId(2e5d30506528a9d2499eec72f80c52f29683d952ebda0b37124b1706344b0a73) } }, proposal_id: Hash(Blake2b256(0xd85f698bb43038619b209676144afd82675fae79a64af03b80eb9719c02c70ec)), votes: [] } } diff --git a/chain-impl-mockchain/proptest-regressions/rewards.txt b/chain-impl-mockchain/proptest-regressions/rewards.txt new file mode 100644 index 000000000..d699fe358 --- /dev/null +++ b/chain-impl-mockchain/proptest-regressions/rewards.txt @@ -0,0 +1,7 @@ +# Seeds for failure cases proptest has generated in the past. It is +# automatically read and these particular cases re-run before any +# novel cases are generated. +# +# It is recommended to check this file in to source control so that +# everyone who runs the test benefits from these saved cases. +xx 45efc80baa8a4a5447f550e41d50602f84c6229beff60279451470e07a8a2ada # shrinks to input = _TaxCutFullyAccountedArgs { v: Value(6644475504521289437), treasury_tax: TaxType { fixed: Value(0), ratio: Ratio { numerator: 51212825857, denominator: 1 }, max_limit: None } } diff --git a/chain-impl-mockchain/proptest-regressions/stake/controlled.txt b/chain-impl-mockchain/proptest-regressions/stake/controlled.txt new file mode 100644 index 000000000..59a350385 --- /dev/null +++ b/chain-impl-mockchain/proptest-regressions/stake/controlled.txt @@ -0,0 +1,7 @@ +# Seeds for failure cases proptest has generated in the past. It is +# automatically read and these particular cases re-run before any +# novel cases are generated. +# +# It is recommended to check this file in to source control so that +# everyone who runs the test benefits from these saved cases. +xx ec315982c34c2629ae0688eba526095487ae16b077462e99a677d8b2c7e13965 # shrinks to input = _StakeControlFromLedgerArgs { accounts: [(Identifier(f8b65c90de7ff37aff43813733594c4dd55c8b4eeaa396aa7b3a41a017ac43b0), AccountState { counter: SpendingCounter(0), delegation: NonDelegated, value: Value(13328654530110817621), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(fe58c4767cc340a71c07af82f12fb3662f266df1e2189f022a4d6d36b9d49774), AccountState { counter: SpendingCounter(0), delegation: Full($hash_ty(0xe04cdfb0c96f7f84e35574da24ed42a342a706570ca32bf19d7b60e8b2361fba)), value: Value(326104323273759881), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(a680ff38fe471266e52a1c3247f7d10ecba3cb38239d95dba2bf842b5da5d29e), AccountState { counter: SpendingCounter(0), delegation: Full($hash_ty(0xcec32d8bbf26ad74822a99efc0c3f4cf4a019ba66ef936e29806a096b0782790)), value: Value(8072321678300584646), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(dfde123e71c3857797db2658f6bd4def65a47d638cc21a6b86958f9b201dda3a), AccountState { counter: SpendingCounter(0), delegation: Full($hash_ty(0xe04cdfb0c96f7f84e35574da24ed42a342a706570ca32bf19d7b60e8b2361fba)), value: Value(14250634732752524471), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(a0d1eca32f78aaa46e09ce132d73dc42ddbb1382221185ccda8915f5bac5d80f), AccountState { counter: SpendingCounter(0), delegation: NonDelegated, value: Value(10482060103363346697), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(0a5f0f80e6d65de9cbedd81968717cfe1da529d269a1eab77e0d15c65739a363), AccountState { counter: SpendingCounter(0), delegation: NonDelegated, value: Value(13543343767653592497), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(a1ddc0091df0ffb1177d538aa4086b555216ae92b157de4aa405d5a561ffecdf), AccountState { counter: SpendingCounter(0), delegation: Full($hash_ty(0xcec32d8bbf26ad74822a99efc0c3f4cf4a019ba66ef936e29806a096b0782790)), value: Value(4688518905522364622), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(ee6c03d25b21b2a61f6c73feaf3874600cb19c245c5f7574ad05fd5e8c27ce2c), AccountState { counter: SpendingCounter(0), delegation: Full($hash_ty(0xa7267f9051f209500c01bf670313e9a3e77a397b893d1e6cc5958c5e48d457b2)), value: Value(221591265123300060), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(ef1b9eee211664c086b7a0b0fa84874f972d58074a5a34722c80dca21ca9c265), AccountState { counter: SpendingCounter(0), delegation: Full($hash_ty(0xcec32d8bbf26ad74822a99efc0c3f4cf4a019ba66ef936e29806a096b0782790)), value: Value(14296802355296427470), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(494a0afc15ede2495527714d3131553ac132235e54e7899e58ce59ab085ca549), AccountState { counter: SpendingCounter(0), delegation: Full($hash_ty(0xe04cdfb0c96f7f84e35574da24ed42a342a706570ca32bf19d7b60e8b2361fba)), value: Value(8929415438454279253), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(7eec8998572e0dad3f63f4785373c290cca07ae25d08372e3a7d6486da7ec9e0), AccountState { counter: SpendingCounter(0), delegation: NonDelegated, value: Value(8333762354021836587), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(b4ed7426366d2e050bfe5662fbef67fae8057a01d00085e8676aecc3d26c42d3), AccountState { counter: SpendingCounter(0), delegation: NonDelegated, value: Value(8853164764655482624), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(f76b6d5529e51e8fa0d9612e88917afacd2d26bdf4a793492980faf3017596ac), AccountState { counter: SpendingCounter(0), delegation: Full($hash_ty(0xe04cdfb0c96f7f84e35574da24ed42a342a706570ca32bf19d7b60e8b2361fba)), value: Value(16684687164810514811), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(31bef4e27abbf576c69961a0756a10ec8ff15897d5fe36047713ceb0151dc7d4), AccountState { counter: SpendingCounter(0), delegation: Full($hash_ty(0xcec32d8bbf26ad74822a99efc0c3f4cf4a019ba66ef936e29806a096b0782790)), value: Value(10436700135461090499), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(bd44d294a4853f79fcca36ac297397b53e1f0492862a2a98d3088d79f056ef58), AccountState { counter: SpendingCounter(0), delegation: Full($hash_ty(0xe04cdfb0c96f7f84e35574da24ed42a342a706570ca32bf19d7b60e8b2361fba)), value: Value(11066579792607851568), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(4e70a4c19c6fd30d81bb2a3142f26c2721af8336f4823d2b5b3bcc91d6ea083f), AccountState { counter: SpendingCounter(0), delegation: Full($hash_ty(0xa7267f9051f209500c01bf670313e9a3e77a397b893d1e6cc5958c5e48d457b2)), value: Value(12918658212734058192), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(a899fed1e713e1ed340fe6060e6292d820d7b87a740ec009fde3161c8d65c479), AccountState { counter: SpendingCounter(0), delegation: NonDelegated, value: Value(14176864159121770338), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(00b40201ad87aca82945a2f8b6e1516b2a5c68570f75920de793a174400b2558), AccountState { counter: SpendingCounter(0), delegation: NonDelegated, value: Value(12820458654749738484), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(ec51daca9ff3b3bdd6c088de46c8cad5cf2ac0ef2a1fe43efafda6c47a469697), AccountState { counter: SpendingCounter(0), delegation: NonDelegated, value: Value(5305128136735168051), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(60c91f3314c4fb42a12a196bf898bc28548395467ba469c49509ba6dc9a91894), AccountState { counter: SpendingCounter(0), delegation: NonDelegated, value: Value(1411502834151038650), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(11e39c093896e7b71d6a98dcbbde31e63d688ef947764bedead55206fa677b02), AccountState { counter: SpendingCounter(0), delegation: Full($hash_ty(0xcec32d8bbf26ad74822a99efc0c3f4cf4a019ba66ef936e29806a096b0782790)), value: Value(15184178846572986553), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(a9b2de48c6dcb9e8be16b7995b99041a3e3b322c0bf87ae7e827cabee5b0b9cc), AccountState { counter: SpendingCounter(0), delegation: Full($hash_ty(0xcec32d8bbf26ad74822a99efc0c3f4cf4a019ba66ef936e29806a096b0782790)), value: Value(15328543421051712430), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(d27dc17432c3ad0bedc8289bb31f9d4603c220a3792ebe26c186cc5a451ca932), AccountState { counter: SpendingCounter(0), delegation: NonDelegated, value: Value(18195112272845173085), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(1373f1397248be06f4fa7cf3bb5803d61e3445cd1025afbe66bb1b9841fbba7b), AccountState { counter: SpendingCounter(0), delegation: Full($hash_ty(0xcec32d8bbf26ad74822a99efc0c3f4cf4a019ba66ef936e29806a096b0782790)), value: Value(9698796445743119053), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(fff5ddcfb18b61da575c0a14831658f46dddd8c2cc55f8f822aa7d621b028895), AccountState { counter: SpendingCounter(0), delegation: Full($hash_ty(0xa7267f9051f209500c01bf670313e9a3e77a397b893d1e6cc5958c5e48d457b2)), value: Value(16315428491636714069), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(e18ea6fa6f0534990888342289287b0ea0c67962d4383d1d19a4da7015ac3b96), AccountState { counter: SpendingCounter(0), delegation: NonDelegated, value: Value(2897366822760731799), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(a19ad800181edf8a719ac4b3fee91391b22bd99264af610e81f40289cdd63626), AccountState { counter: SpendingCounter(0), delegation: Full($hash_ty(0xa7267f9051f209500c01bf670313e9a3e77a397b893d1e6cc5958c5e48d457b2)), value: Value(3112131229966781601), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(7f8b1ade8e34f92de3eddde8223b8a0758b2b4986f708a43922415307184a638), AccountState { counter: SpendingCounter(0), delegation: NonDelegated, value: Value(2146909507721683072), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(5ee23afda340753ff8cdce3627270e7c76df03de2793f2f42831797dc1841105), AccountState { counter: SpendingCounter(0), delegation: NonDelegated, value: Value(13025022395765281385), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(3492f25eea4be8ee089afd41660a1ae5b5bab972abdba309330ede8b98533bbb), AccountState { counter: SpendingCounter(0), delegation: NonDelegated, value: Value(18300573998966213758), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(319cb630165dac4e4e6484104665839800fd29eeac4ff0e2ed369ebd698ad1be), AccountState { counter: SpendingCounter(0), delegation: Full($hash_ty(0xe04cdfb0c96f7f84e35574da24ed42a342a706570ca32bf19d7b60e8b2361fba)), value: Value(13392535376061485176), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(6b44c2b571fd2dace1b82b33020e8c20aab7af22a85caecac70135b4cc1f90ee), AccountState { counter: SpendingCounter(0), delegation: NonDelegated, value: Value(6339662737903756818), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(8c953ab60eb598cc6690d7a03d1ee55598508cd7d5bc7d143a4fd460a91fade8), AccountState { counter: SpendingCounter(0), delegation: Full($hash_ty(0xcec32d8bbf26ad74822a99efc0c3f4cf4a019ba66ef936e29806a096b0782790)), value: Value(2771169920554459656), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(acfc1992e0cc5b3980b16bff953a441691366d18549df57dd8e519d31bc380ae), AccountState { counter: SpendingCounter(0), delegation: NonDelegated, value: Value(5753359958916310696), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(8b75c144be635eb5593e6a8ade13f70f9c76012abcd7dc41011cb1b0b09674b6), AccountState { counter: SpendingCounter(0), delegation: NonDelegated, value: Value(14453347606340215617), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(6f73c0ebabef593414610a287109fb966f6b461db25c42aba1104b8f2637cb90), AccountState { counter: SpendingCounter(0), delegation: NonDelegated, value: Value(7859716673743989124), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(06d91b3810abfd77c1bb8a1f282b21a7a39b16fe72cbfd15bebeef46f16be483), AccountState { counter: SpendingCounter(0), delegation: NonDelegated, value: Value(18074491515998634443), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(7e9d01539c0baf8e8d625cf366d9f239fd9fa60677c6b5b93bccd106e105444d), AccountState { counter: SpendingCounter(0), delegation: Full($hash_ty(0xa7267f9051f209500c01bf670313e9a3e77a397b893d1e6cc5958c5e48d457b2)), value: Value(16868072193664060601), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(36ec7ef879d28103811aa94001929748bb88ed7a62dead7ce31e59a901cb8d06), AccountState { counter: SpendingCounter(0), delegation: Full($hash_ty(0xe04cdfb0c96f7f84e35574da24ed42a342a706570ca32bf19d7b60e8b2361fba)), value: Value(11186058897919316830), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(a160401b199235ab153d8e7698529a4f3687f613b509d6ec77948d953d915735), AccountState { counter: SpendingCounter(0), delegation: NonDelegated, value: Value(6311881872648591894), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(2ae4bc6d4c1afaf309a8dbfb6c446bc2c2d5d2f2d589ab46aeaa8621c343a4da), AccountState { counter: SpendingCounter(0), delegation: NonDelegated, value: Value(16521109814073484210), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(4a2b70bfeb5648e158bdc5f6e90c3185c31ddc430d46f0fa74cc9b4facce269c), AccountState { counter: SpendingCounter(0), delegation: NonDelegated, value: Value(13315546727768913490), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(12a79ed42e601177352a1b76c83c7eb05af83a7b15de5481dc6037d7fff68358), AccountState { counter: SpendingCounter(0), delegation: Full($hash_ty(0xa7267f9051f209500c01bf670313e9a3e77a397b893d1e6cc5958c5e48d457b2)), value: Value(13269633751129488231), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(f488eb6d33342c5dca7d3d750ae3c834b2564815e47a3b31f2595d1d330977fd), AccountState { counter: SpendingCounter(0), delegation: Full($hash_ty(0xe04cdfb0c96f7f84e35574da24ed42a342a706570ca32bf19d7b60e8b2361fba)), value: Value(17541006608899999964), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(95fb3c12de62e908a690a9b01acca1b273ee4ecbecfcbc1067b88111fec6107b), AccountState { counter: SpendingCounter(0), delegation: NonDelegated, value: Value(11941568264450053816), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(12185ec173939d0089f5cdc14a50970ed354926f22a09b711bdb9ae2e95f00c8), AccountState { counter: SpendingCounter(0), delegation: NonDelegated, value: Value(303393846160463446), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(664da81fa0b6114b1142cf4ae791b8bc90f92b03a3146b14327fc90c92f29901), AccountState { counter: SpendingCounter(0), delegation: NonDelegated, value: Value(13448519422570635814), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(da737bcdac93417869ea899b2017e5cfcb71665407a07a3370d87dcd0fd53b79), AccountState { counter: SpendingCounter(0), delegation: NonDelegated, value: Value(7564900691917806396), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(5b3796a430f20f1439039e160d784eea3a50d834b8758e19eabe5a5fc8aad73c), AccountState { counter: SpendingCounter(0), delegation: Full($hash_ty(0xcec32d8bbf26ad74822a99efc0c3f4cf4a019ba66ef936e29806a096b0782790)), value: Value(12088987562725611444), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(9e9d40325490b207f52003e7c35fe811da2ec4ca41e110cdcb0547fa7a96048f), AccountState { counter: SpendingCounter(0), delegation: Full($hash_ty(0xe04cdfb0c96f7f84e35574da24ed42a342a706570ca32bf19d7b60e8b2361fba)), value: Value(5458623465161915902), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(fd2e6491ab5d1c3ddfa0ce5287a2c30434b11b7016bf528a15218d1a4c074083), AccountState { counter: SpendingCounter(0), delegation: Full($hash_ty(0xcec32d8bbf26ad74822a99efc0c3f4cf4a019ba66ef936e29806a096b0782790)), value: Value(11732089751418107928), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(5d7ae5254b65b017e70f5d87c1566138de1f184eee679fb3217997812e5c4286), AccountState { counter: SpendingCounter(0), delegation: NonDelegated, value: Value(15839898716885623236), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(b54b4f5e8cf67c0f086bc54689baae056b82dfebdd7096db92f2b0a1d37d38cf), AccountState { counter: SpendingCounter(0), delegation: Full($hash_ty(0xe04cdfb0c96f7f84e35574da24ed42a342a706570ca32bf19d7b60e8b2361fba)), value: Value(17423160925489289579), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(e25e3ee5249f2722cae65a4f31234173b38278894223af53531ea4c9c9f1c905), AccountState { counter: SpendingCounter(0), delegation: Full($hash_ty(0xe04cdfb0c96f7f84e35574da24ed42a342a706570ca32bf19d7b60e8b2361fba)), value: Value(11318783443039896357), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(f7e60b01e3208a00b64d79ef76def274a4a276355784280494702869a03d5555), AccountState { counter: SpendingCounter(0), delegation: NonDelegated, value: Value(15504230309245364124), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(b7ba97d0bf5cbcd6d3f0e214d2c9d2e642f05f2a28e6856519a6e694bfc34f3a), AccountState { counter: SpendingCounter(0), delegation: NonDelegated, value: Value(12635336544999046615), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(7778dc2d00a362a4ce6f32d69d35166b286d24b8627ea23773364bcabfd19283), AccountState { counter: SpendingCounter(0), delegation: NonDelegated, value: Value(5596369875862109064), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(7a7eedd958a396a0c6bbe4b8845b17fff19cd0e450f8789ff6e4a52d97ef2173), AccountState { counter: SpendingCounter(0), delegation: NonDelegated, value: Value(12296830467003560183), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(434bdd758d509561d2356f1b6689b8e39e15d44040b31d78a4609a4a10743b9d), AccountState { counter: SpendingCounter(0), delegation: Full($hash_ty(0xa7267f9051f209500c01bf670313e9a3e77a397b893d1e6cc5958c5e48d457b2)), value: Value(6733804863276046642), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(25fd9b764a0e22fbe9e4d8588de56c0db422dbc2d6726ee0dfff78dc74c695d9), AccountState { counter: SpendingCounter(0), delegation: NonDelegated, value: Value(13929389588396707025), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(d6f8dec6ecdc1f3f73f6ae55d96e03e1f3a167bf4f3f041325a7d60a1315e1ce), AccountState { counter: SpendingCounter(0), delegation: Full($hash_ty(0xcec32d8bbf26ad74822a99efc0c3f4cf4a019ba66ef936e29806a096b0782790)), value: Value(9594245418958465196), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(83656cc01bfb724510531bbdb9be057af488339900d8bedcd39ba67a560b879a), AccountState { counter: SpendingCounter(0), delegation: NonDelegated, value: Value(8539165580568966797), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(8cbfbe69bc53c883c93a5b71c9b76b699437e8b873210ea6ad9673e2050ca566), AccountState { counter: SpendingCounter(0), delegation: NonDelegated, value: Value(17529331380090329143), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(0a4b32d137638f867a61232f86ff52e53c61ea93565e21a802fb9e2657c1a90d), AccountState { counter: SpendingCounter(0), delegation: NonDelegated, value: Value(14039004082620397247), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(e4b377ddb53519e1630c1b3bf7d197e87272453cd996bc930a3a8606d565ff7e), AccountState { counter: SpendingCounter(0), delegation: Full($hash_ty(0xa7267f9051f209500c01bf670313e9a3e77a397b893d1e6cc5958c5e48d457b2)), value: Value(11876874812238184876), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(1715c06b9c25d2d5c2fbb2e0f6a28b47b48c706db7476ed255bc4f057ad5591a), AccountState { counter: SpendingCounter(0), delegation: NonDelegated, value: Value(15122376435605343214), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(6d44383c09945c9779f1b830d0114a6d38f01e07a1389d9d8f7e655245b6cad1), AccountState { counter: SpendingCounter(0), delegation: NonDelegated, value: Value(8782588903710978677), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(89200c363a101b63014b8c2246ae6fb0b3160ffb8144861ecd7cb4b12146f86f), AccountState { counter: SpendingCounter(0), delegation: NonDelegated, value: Value(1497571291898268137), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(ff94320196495e01466ee17054cf1aba729183f7298432e8bb1c01e5d61cebdc), AccountState { counter: SpendingCounter(0), delegation: Full($hash_ty(0xcec32d8bbf26ad74822a99efc0c3f4cf4a019ba66ef936e29806a096b0782790)), value: Value(10707929288407124026), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(181d74e625bf57a097e8a8b7e501cd6796cb790420a9ef3382e37d568a23a89a), AccountState { counter: SpendingCounter(0), delegation: Full($hash_ty(0xa7267f9051f209500c01bf670313e9a3e77a397b893d1e6cc5958c5e48d457b2)), value: Value(16472299535992037882), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(450705a2a3b323823a62a63972b5ce61cff7af011293cc3bc1469be80712dfe5), AccountState { counter: SpendingCounter(0), delegation: Full($hash_ty(0xa7267f9051f209500c01bf670313e9a3e77a397b893d1e6cc5958c5e48d457b2)), value: Value(6922820215782967761), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(efffaa9ca0bf39538dc1f7038df0d86c77c55187286a683ada2b6743b72cae57), AccountState { counter: SpendingCounter(0), delegation: Full($hash_ty(0xe04cdfb0c96f7f84e35574da24ed42a342a706570ca32bf19d7b60e8b2361fba)), value: Value(724099679952681722), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(69223fd6e0b2b39e42ff3eb677b13e4ff0a68e4c56ee068667d5d9fde40afe47), AccountState { counter: SpendingCounter(0), delegation: Full($hash_ty(0xe04cdfb0c96f7f84e35574da24ed42a342a706570ca32bf19d7b60e8b2361fba)), value: Value(11564903706495080227), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(c7e2de8fa15325bbe578bbc1b5c557620d69f104e81028dfbcc258b9ce083f77), AccountState { counter: SpendingCounter(0), delegation: Full($hash_ty(0xa7267f9051f209500c01bf670313e9a3e77a397b893d1e6cc5958c5e48d457b2)), value: Value(12295050726943209074), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(a672142e39045f7b4807a54e8cb3b15ab0c6a9bdc7c433ef785166669df634d1), AccountState { counter: SpendingCounter(0), delegation: Full($hash_ty(0xa7267f9051f209500c01bf670313e9a3e77a397b893d1e6cc5958c5e48d457b2)), value: Value(5859700786047177781), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(fd3fc98c4cd414f73ae63875a623e659a0d6536b2b962a4ab7eb2b9d386806ef), AccountState { counter: SpendingCounter(0), delegation: Full($hash_ty(0xa7267f9051f209500c01bf670313e9a3e77a397b893d1e6cc5958c5e48d457b2)), value: Value(711719531526926945), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(9ac2c5fd1f79b2250401959cd747fe790de63b1c9c449b85abcfeb6ac91b16a2), AccountState { counter: SpendingCounter(0), delegation: Full($hash_ty(0xcec32d8bbf26ad74822a99efc0c3f4cf4a019ba66ef936e29806a096b0782790)), value: Value(10963258468588135356), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(f66994647e88851b25c82de4a85c6f3678ec06c716095146cf8ae7d5c224dc45), AccountState { counter: SpendingCounter(0), delegation: Full($hash_ty(0xe04cdfb0c96f7f84e35574da24ed42a342a706570ca32bf19d7b60e8b2361fba)), value: Value(10572185756239748799), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(ad67623bd0d79ba6db9b64e955dea59761a46f35e872f0d5f8ea68eb09a69685), AccountState { counter: SpendingCounter(0), delegation: Full($hash_ty(0xe04cdfb0c96f7f84e35574da24ed42a342a706570ca32bf19d7b60e8b2361fba)), value: Value(286207819398940603), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(b519e72b22d66a8e358c37fd408f9229819d9a24e88ed09816e8f20db2718aa9), AccountState { counter: SpendingCounter(0), delegation: NonDelegated, value: Value(1239342842218348081), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(f469fd6d2cc87feb18af8e0ec7fab2d55c912e29923ff63ee81d7fdaef050770), AccountState { counter: SpendingCounter(0), delegation: NonDelegated, value: Value(18272130205898822554), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(79ff05a827d21fe1dcb0e07629d3b58181fa5fc29c67d220e77b45cf923bbf72), AccountState { counter: SpendingCounter(0), delegation: NonDelegated, value: Value(14672486030059388975), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(63a200b074aca3c33c5d5b5a3f941be1cd8fb0cd2c324e0f7ab4e8bedf7a1852), AccountState { counter: SpendingCounter(0), delegation: NonDelegated, value: Value(6563875979810160604), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(b788e32e1f9ad1ed8827e67483135e47d4057869e69421350ea82e60fb1a6cba), AccountState { counter: SpendingCounter(0), delegation: Full($hash_ty(0xcec32d8bbf26ad74822a99efc0c3f4cf4a019ba66ef936e29806a096b0782790)), value: Value(15856850457685464544), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(2ba32e4a8e3e1712dc19b7763d6b34fb9a9a726c5f82888cb570d60598ec2593), AccountState { counter: SpendingCounter(0), delegation: Full($hash_ty(0xcec32d8bbf26ad74822a99efc0c3f4cf4a019ba66ef936e29806a096b0782790)), value: Value(8396865097169978698), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(2de7cdb7a9fa361616b999a712558091a3bfee1e76b79025ec10c7b7938578ab), AccountState { counter: SpendingCounter(0), delegation: Full($hash_ty(0xa7267f9051f209500c01bf670313e9a3e77a397b893d1e6cc5958c5e48d457b2)), value: Value(9172956036313755518), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(7d222bc25a9c3ac4e4a821daa2f9bc2ba88dc43e9399d47b23b6200fb8fc10cc), AccountState { counter: SpendingCounter(0), delegation: Full($hash_ty(0xa7267f9051f209500c01bf670313e9a3e77a397b893d1e6cc5958c5e48d457b2)), value: Value(18129924985756816310), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(b9e064a203746540b772a48445ac8503991f2b935b996f9492442a31f59a5e77), AccountState { counter: SpendingCounter(0), delegation: NonDelegated, value: Value(938006162802451533), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(367a11eb6c81ad99e48edcd628bb465a022de1466e0d023f9ce2777500e28e0f), AccountState { counter: SpendingCounter(0), delegation: NonDelegated, value: Value(6379496131051591161), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(9512a6dbe029d585fd43caf29ab5f279426857562f4c8cbafef46e6d19f117a9), AccountState { counter: SpendingCounter(0), delegation: Full($hash_ty(0xa7267f9051f209500c01bf670313e9a3e77a397b893d1e6cc5958c5e48d457b2)), value: Value(3232451467730892537), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(28efd23b0476b32a9230d5be57c3d06d7be851e08d1df425c200987668072d72), AccountState { counter: SpendingCounter(0), delegation: Full($hash_ty(0xa7267f9051f209500c01bf670313e9a3e77a397b893d1e6cc5958c5e48d457b2)), value: Value(15787949861588357836), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(aa4bd5ac1c2c632b0a399af49521ae203386f83351922f207b847869f3fd4151), AccountState { counter: SpendingCounter(0), delegation: Full($hash_ty(0xe04cdfb0c96f7f84e35574da24ed42a342a706570ca32bf19d7b60e8b2361fba)), value: Value(3994936671726645574), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(29c565b7c8850bd7e3d7d6384d73991717f5ca308489ebd30e5db293c720409d), AccountState { counter: SpendingCounter(0), delegation: NonDelegated, value: Value(8165198498456152020), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(6448de8d41f35d13d485cc2b8f527dfc210285fb0d7ae98c788e72b11757cdae), AccountState { counter: SpendingCounter(0), delegation: Full($hash_ty(0xe04cdfb0c96f7f84e35574da24ed42a342a706570ca32bf19d7b60e8b2361fba)), value: Value(12726214309768212582), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(34a87b8107076dcbcc85646a6aa6120a585cad1d6c50116c6e1d8ddc5f9b4e42), AccountState { counter: SpendingCounter(0), delegation: NonDelegated, value: Value(9286505767193289799), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(293ebd9197ecedeffa7d0da503c1b5d30ac74cf4d88bd094fa53dfa02fbc1096), AccountState { counter: SpendingCounter(0), delegation: Full($hash_ty(0xcec32d8bbf26ad74822a99efc0c3f4cf4a019ba66ef936e29806a096b0782790)), value: Value(14212284737670131602), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(f8a0de7d7349ac57ff7cd4b949cf06c33c807bec82553ace943b3d8d32af7364), AccountState { counter: SpendingCounter(0), delegation: Full($hash_ty(0xa7267f9051f209500c01bf670313e9a3e77a397b893d1e6cc5958c5e48d457b2)), value: Value(17238386465455226647), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(f598f7307c0bbf16aa7d173400e8c1af077bcaa4483eaa0c45972fb37675789a), AccountState { counter: SpendingCounter(0), delegation: NonDelegated, value: Value(6503119119793644382), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(34fef17bcd52195770cd13db5f97de52a26c108f0a24ec5e1dc00f9782080c5c), AccountState { counter: SpendingCounter(0), delegation: Full($hash_ty(0xa7267f9051f209500c01bf670313e9a3e77a397b893d1e6cc5958c5e48d457b2)), value: Value(2430578763869146263), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(21ec37d487fe6091daf289e3d957b710d54f6e9cc2c14d23b69ee57964a51a7d), AccountState { counter: SpendingCounter(0), delegation: NonDelegated, value: Value(9705470705205923644), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(f206061ec19242f1d4e65fc5ed49a843f4c770aa0be08112d21e827f4acff182), AccountState { counter: SpendingCounter(0), delegation: Full($hash_ty(0xcec32d8bbf26ad74822a99efc0c3f4cf4a019ba66ef936e29806a096b0782790)), value: Value(13919899657012270214), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(a9f65d5d7de6fe02cb30377a338052ecdbcdee16b3b715a57f1f53c3d1ae0af4), AccountState { counter: SpendingCounter(0), delegation: NonDelegated, value: Value(147543426278737821), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(64723ff0b7cd145b9c210d0d81e5c517e7dd47dec7d9e7acac4bfda8a62f6a1c), AccountState { counter: SpendingCounter(0), delegation: NonDelegated, value: Value(15072480498004328471), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(d39d85ee292cefe2eff2297e72cba74cd14c3b698c22174abe74a8eb580236c2), AccountState { counter: SpendingCounter(0), delegation: NonDelegated, value: Value(10079733662221797362), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(cc26d92cf7ef1d31517cc23b8d5a52ba299050ff0be834bd605472176dea1625), AccountState { counter: SpendingCounter(0), delegation: NonDelegated, value: Value(9183008027799372612), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(ae36377c04173940347dba0d761a7f6429f6cf6d9da5d817bc29b90adddefe96), AccountState { counter: SpendingCounter(0), delegation: Full($hash_ty(0xe04cdfb0c96f7f84e35574da24ed42a342a706570ca32bf19d7b60e8b2361fba)), value: Value(2604454598788780106), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(d0daf24640a94e87f1e822bf30f4d0926f0f5fc42d3828bd44b9f1cb26fe85bf), AccountState { counter: SpendingCounter(0), delegation: Full($hash_ty(0xcec32d8bbf26ad74822a99efc0c3f4cf4a019ba66ef936e29806a096b0782790)), value: Value(1156766375441581184), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(320429d9025f67ef4511fe66a7da315e6b50109fa15889471e6e9167838828a0), AccountState { counter: SpendingCounter(0), delegation: Full($hash_ty(0xe04cdfb0c96f7f84e35574da24ed42a342a706570ca32bf19d7b60e8b2361fba)), value: Value(16911909704478577768), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(34935ee547d2d60a9f8b7be99c17ac83916e365e6996d9e252eb5113d8bc285f), AccountState { counter: SpendingCounter(0), delegation: NonDelegated, value: Value(10480430743765349199), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(bfc458d0b9e96d85b422db9003273cfb92c13a7419bd7bf350633677ae3413aa), AccountState { counter: SpendingCounter(0), delegation: Full($hash_ty(0xcec32d8bbf26ad74822a99efc0c3f4cf4a019ba66ef936e29806a096b0782790)), value: Value(3325812843873769578), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () }), (Identifier(a4df0b8949c65366ba87edcf1ca498fdc8a0f5828ae7ad64c7ee780328b4c140), AccountState { counter: SpendingCounter(0), delegation: Full($hash_ty(0xcec32d8bbf26ad74822a99efc0c3f4cf4a019ba66ef936e29806a096b0782790)), value: Value(14930453682610895366), last_rewards: LastRewards { epoch: 0, reward: Value(0) }, extra: () })], utxos: [Entry { fragment_id: Hash(Blake2b256(0x66df2b1c5390908db714a32ede62a69005a645013b4c8156c5b1afbb4bcb2e89)), output_index: 0, output: Output { address: Address(Test, Single(4362e55b35cffb441700de8c99970473aee2c4adc2394778e056a93e938a55e5)), value: Value(11325694568008021017) } }, Entry { fragment_id: Hash(Blake2b256(0x36b76f1cbaa316439592ddf34180d91b13c33ab21d8a03e96611e4cd58404fab)), output_index: 0, output: Output { address: Address(Test, Single(b29c981bbc07b218313480394631f0a3887de669f7e67cdac1defdd33c83f4c1)), value: Value(1693126563686560329) } }, Entry { fragment_id: Hash(Blake2b256(0xa6805d653db54a28d1cd92b206e4e092f12e852b1025c19dc4fefc9c468f2d5e)), output_index: 0, output: Output { address: Address(Test, Single(5d4e556143f89317d1e4441ee907323850a70c59a2974330fac14c0faa7677d9)), value: Value(7506940517557718995) } }, Entry { fragment_id: Hash(Blake2b256(0x3c0b97107d7727216aee98f758338a267e8c902e27b2ef2450d267fcb048a09e)), output_index: 0, output: Output { address: Address(Test, Single(b3c8eb2ef9396777e2634eb825036a3fec56733ee28a16a4befe7536deb32e61)), value: Value(1725762896729240768) } }, Entry { fragment_id: Hash(Blake2b256(0x0a205f62edeb9f6e037e60ae53be0174b281878ab67858e85b9ffa6aa85951a2)), output_index: 0, output: Output { address: Address(Test, Single(bcf56189dc0fe5386baa227ffe5640f650c08b7b52c4efaa20240effcf5a89d0)), value: Value(12555388810111770817) } }, Entry { fragment_id: Hash(Blake2b256(0x77324a6e8a36420a650bc46a26e57d9d4a71dc30a3434443909d76c4445d78f6)), output_index: 0, output: Output { address: Address(Test, Single(1b48c975a5acd12e8ea2e67c6e57b082d21501aca340e1805c794cf3933a68e1)), value: Value(16622940976180300470) } }, Entry { fragment_id: Hash(Blake2b256(0x28f1cff8a599e18f5720b68e2b2061ac1157242162f02742fd17b7dd051de8d2)), output_index: 0, output: Output { address: Address(Test, Single(ea52dad6857a6240490b218cf06a0054a4ebded7daf5947ffbebf7b1ff52ab10)), value: Value(11398452071780097539) } }, Entry { fragment_id: Hash(Blake2b256(0x581f1a25c094805f74b3312446387d89b174f9103363d57331a4ca6a9011334a)), output_index: 0, output: Output { address: Address(Test, Single(16751ab165a8984e69bfe617d48ee4d660cf33dde931980f628bbe2b743cbb1d)), value: Value(3417177827575338138) } }, Entry { fragment_id: Hash(Blake2b256(0x9dc95c8cb54e84e1cc0aa5a3cb0e6d3ec8f2943901d1e315e64122529e96ba93)), output_index: 0, output: Output { address: Address(Test, Single(43a39c3897373d31af59656d5fac8ebd501e9b46b561492e4f72a74e351c43c5)), value: Value(2637652157451221154) } }, Entry { fragment_id: Hash(Blake2b256(0x413ef05f1c824603c1a91a414134dd9a1ff420a1d176ae1b6d26b7826bec480c)), output_index: 0, output: Output { address: Address(Test, Single(0f69ddef9df0e25ff3e1203ccb3d8095761e04dc0c4adba981ba568cdcb8d8bc)), value: Value(1399969259995052126) } }, Entry { fragment_id: Hash(Blake2b256(0x5e53767d074a6547893d55509765478a73f4fe59c1ca6afff026b0a54b9c5345)), output_index: 0, output: Output { address: Address(Test, Single(ed7ba857e546f3634f8ae62f5cdfaa72f0c4bc4dba002c4053db3f4b3bc97471)), value: Value(16992387099644903426) } }, Entry { fragment_id: Hash(Blake2b256(0xa6e28f8a303cd677d87c5a1608133e00a377708e8a38191f0f4a2bef04e3a360)), output_index: 0, output: Output { address: Address(Test, Single(d25a5731c1b327955a1da4f117e717e7d1f570da38a31035930d553d85aefa2c)), value: Value(10584448969995328372) } }, Entry { fragment_id: Hash(Blake2b256(0x2321c84b26858067ffd4aeba3b332c2fb7c71badcc71ff0a84408315e4bb1356)), output_index: 0, output: Output { address: Address(Test, Single(54a8da5570ebf461941a9339baa4f7cac59b2d587855dae6e8faadb2b9c52d53)), value: Value(11761925177200302816) } }, Entry { fragment_id: Hash(Blake2b256(0xad83e4782c4da5a15fcb1f0db38c7b17bcb38358c7cdff1d41c0250ec195a959)), output_index: 0, output: Output { address: Address(Test, Single(3f39dc9e2ef55cf536316322cb82fbf963f978ee65852d0e1f485a3909f5f7f9)), value: Value(9339725284854740648) } }, Entry { fragment_id: Hash(Blake2b256(0x1e625ac3f339ae6a9e066ec168418a3f0f6600524046a0f0a81a6c22341a6228)), output_index: 0, output: Output { address: Address(Test, Single(f3e826a35d425183324ff7649e612e6c0c093554ccfd57c334081e582065c70f)), value: Value(11949713391260280475) } }, Entry { fragment_id: Hash(Blake2b256(0x4dbff3ef7ab01c47be8495f6f0819395137f28ef8098661ee4a365cdfe8ecc54)), output_index: 0, output: Output { address: Address(Test, Single(9d62ea00ef5d6b8f84428530cbd7b7d602280f0775528fbe3e1cbfab7fee57fb)), value: Value(15604571787575459777) } }, Entry { fragment_id: Hash(Blake2b256(0xac6532263b8666706ea19d440187ff31b888444457c3e305d0da47f63c54814b)), output_index: 0, output: Output { address: Address(Test, Single(6723244f16ea1d04d2bc74fb71efb296af04a4fdfeac334204d3c225df1d8607)), value: Value(16763259372658348308) } }, Entry { fragment_id: Hash(Blake2b256(0xcf769726170d7d206b41f577d00535867c36982e7dc67c4112b52882f2f429e9)), output_index: 0, output: Output { address: Address(Test, Single(29700f2ba6dc3b4e835dcdaf9725d6a7bda33f25a99527491c42c6ed3f74d207)), value: Value(5603040391375124164) } }, Entry { fragment_id: Hash(Blake2b256(0xa8da4cb2851a4a1a45765f7153fd3667412f8e12da28c1074e7fa30a642c667f)), output_index: 0, output: Output { address: Address(Test, Single(605ff36e8669a7eebcee65d7e0e697d183868913d52d23aa8a45fdd00d1484ff)), value: Value(8802005490670208502) } }, Entry { fragment_id: Hash(Blake2b256(0x699189f6b717dd04ae3fdc91ce39faeb456091f8bee0320c0218304a8bee6bdb)), output_index: 0, output: Output { address: Address(Test, Single(cd538f5f3a023484d2d07fc6e755d937a435211fae1087c3133f4510c8e06a8f)), value: Value(12736933345789602875) } }, Entry { fragment_id: Hash(Blake2b256(0x45f1111cc4cbc8520bebe09c4ebca77db09f558de21cf4e20da59044b315cc18)), output_index: 0, output: Output { address: Address(Test, Single(4af49fb0d1f7e33aeb9dd632178e78700ec1c3993f932045ddc29bf3940561ff)), value: Value(4119325638855272640) } }, Entry { fragment_id: Hash(Blake2b256(0xb49aadfbbce8fa956ee455ea40e3b25bece21dee93bafce7724b6edb4f604911)), output_index: 0, output: Output { address: Address(Test, Single(f049eb35682066cb374f66a4b6a33e7caa5472897dc29e8099b7d1d70ddcefa2)), value: Value(11557774311356197734) } }, Entry { fragment_id: Hash(Blake2b256(0x1bf8df4cd27bca0a1e7a31c5c731c538eab088ab1acf2cee79ea0ef6caad1e3d)), output_index: 0, output: Output { address: Address(Test, Single(8d2b885f8a3392c545c2e6b677effedb4e948181f8fa2183228dd76c6ae457fc)), value: Value(2205300899318175856) } }, Entry { fragment_id: Hash(Blake2b256(0x06d05e4ed7e91ec733934cce62a5e168666fba73ffbe46315da791b64959f33b)), output_index: 0, output: Output { address: Address(Test, Single(fed4496a9634e7508f6054249ebe219ea986defb3cdf2a3ee032d67d79f8cf61)), value: Value(8449543002666349014) } }, Entry { fragment_id: Hash(Blake2b256(0x0e81af1e05ad33d0db96a6db5b13cc945c166b56192266ea738441f46c010c69)), output_index: 0, output: Output { address: Address(Test, Single(41fae0e171494af20754a5d98bf39ad1684610d02bf5c04d25d2952f150ef0b1)), value: Value(1446374969818905811) } }, Entry { fragment_id: Hash(Blake2b256(0x58c2e33cf17cc04a80db341121c54751e2eef4eae1a3cbf1f750c13b67ec35cf)), output_index: 0, output: Output { address: Address(Test, Single(76913b4580343c7c50a97e3cbc9d583a03faa50e781266cb873f466ab464a73f)), value: Value(3356226614546417869) } }, Entry { fragment_id: Hash(Blake2b256(0xd7ed1e926fa993a573296de9ab48ef8eff31974ad438eaf867cd6be1129010e9)), output_index: 0, output: Output { address: Address(Test, Single(15803d1936207d764fa1bf78d5fef0c530915462ea426509f15d73b2ba9888eb)), value: Value(3909151459722175021) } }, Entry { fragment_id: Hash(Blake2b256(0x22a4ac884ef25818b187f19d6ace3d397a0b22af925eb113f32ca427ef05d15f)), output_index: 0, output: Output { address: Address(Test, Single(d25507b0319bf39c314dadedb2e4434b2e286eb5a1cff034f2e68a93a8387b9b)), value: Value(4083294737655158002) } }, Entry { fragment_id: Hash(Blake2b256(0x759fef48df7036518316526a6ed3cbf50ca275920d1b179ad817433467a9022d)), output_index: 0, output: Output { address: Address(Test, Single(58e8dd8a13311fe6a469f18edac5c21e389635e220d9cfdebd1bbc72684ecc0d)), value: Value(9487833983224549150) } }, Entry { fragment_id: Hash(Blake2b256(0xdd8cfd2c231f942e939ce4a4e73aca339c97ad9be51746735b75dcf6905379c6)), output_index: 0, output: Output { address: Address(Test, Single(f50662ecbbf97c0d566a47405af47723b7885c672fdb6e78d497c263c81d9a58)), value: Value(8886794605173975483) } }, Entry { fragment_id: Hash(Blake2b256(0xcf5b678a422711fa354717b25228afd0dbb0304d64d10053d103c320acdbe04e)), output_index: 0, output: Output { address: Address(Test, Single(0803f29b0accb6260c8e91afd69d5d048121a4994f307794b77212973503293d)), value: Value(6351903197340804020) } }, Entry { fragment_id: Hash(Blake2b256(0x02f49f18ef87a9357d206369db958a2155df215dd691436cc4aafe7e82ff6e1e)), output_index: 0, output: Output { address: Address(Test, Single(709b700987c5136d489c84088a22eba677c8b994db0d139338b9606100fb9be9)), value: Value(16900469182158655427) } }, Entry { fragment_id: Hash(Blake2b256(0xfbd8a60d591ba0235f6a427358c7d0d6e606f1c4987cb04671a97716267e9e7e)), output_index: 0, output: Output { address: Address(Test, Single(09a66bdde89b0d104957faf399b168c5d3b0b9e94ab515e909c673dddf0cf691)), value: Value(16925271292463805538) } }, Entry { fragment_id: Hash(Blake2b256(0x96bb7a9af9b399cda4174546bec0527908733ae4fbcb927cf2182912cf3b7a55)), output_index: 0, output: Output { address: Address(Test, Single(9ff8577bf95e741fd789836ab579cc3ded71a20698cf7cf18db1ef964a37a656)), value: Value(14167590609777030870) } }, Entry { fragment_id: Hash(Blake2b256(0xa5cec0c9bf370f04ad842c1f5c641f903a655aa9afa4541eeba62516b4440158)), output_index: 0, output: Output { address: Address(Test, Single(870ef5cc2df400cd96dc1bbb44ca5aecf650366a1727859f339d7166ee1fe4aa)), value: Value(1578957236963252217) } }, Entry { fragment_id: Hash(Blake2b256(0x90064cfe0e78e4445ba7db283f7edd38d63790a30375a453028b0a3645446c62)), output_index: 0, output: Output { address: Address(Test, Single(c0057d47c6b437e5c4b249b228805265c82007856c01d8b6c3a5e237c5866201)), value: Value(1079200001960504775) } }, Entry { fragment_id: Hash(Blake2b256(0x141190da6021f2cdd5c34f6ae30b8c7215eb64652300ef250def2171abd16909)), output_index: 0, output: Output { address: Address(Test, Single(149132252679999fd8ebe0569dec21cce41633d1da35d601c1ee4671c89100de)), value: Value(13237022044382986807) } }, Entry { fragment_id: Hash(Blake2b256(0x74b685d1d19dd6db1d21e6ebc8aefff918e5d582d340127ff96efce2805e67ba)), output_index: 0, output: Output { address: Address(Test, Single(e34575a9428ec9dd7f2ef8466044f7dc0175c3ec4bc71b4a1108e1efa3c63362)), value: Value(6492151683959734430) } }] } diff --git a/chain-impl-mockchain/proptest-regressions/stake/distribution.txt b/chain-impl-mockchain/proptest-regressions/stake/distribution.txt new file mode 100644 index 000000000..7b4fdfc2f --- /dev/null +++ b/chain-impl-mockchain/proptest-regressions/stake/distribution.txt @@ -0,0 +1,7 @@ +# Seeds for failure cases proptest has generated in the past. It is +# automatically read and these particular cases re-run before any +# novel cases are generated. +# +# It is recommended to check this file in to source control so that +# everyone who runs the test benefits from these saved cases. +xx 08e03ada52d9d3683cc429541c2d8b1c8750903779325aa4b559777a4abb8f8e # shrinks to input = _AssignAccountValueIsConsitentWithStakeDistributionArgs { account_identifier: Identifier(ec612c23485d5afa5a9cd700416e1d09f12747dcf970812c47de8befb2c256b8), delegation_type: Ratio(DelegationRatio { parts: 8, pools: [] }), value: Stake(1) } diff --git a/chain-impl-mockchain/proptest-regressions/transaction/test.txt b/chain-impl-mockchain/proptest-regressions/transaction/test.txt new file mode 100644 index 000000000..71e1619c5 --- /dev/null +++ b/chain-impl-mockchain/proptest-regressions/transaction/test.txt @@ -0,0 +1,7 @@ +# Seeds for failure cases proptest has generated in the past. It is +# automatically read and these particular cases re-run before any +# novel cases are generated. +# +# It is recommended to check this file in to source control so that +# everyone who runs the test benefits from these saved cases. +xx 22277a863c8ded231683e5858674bc85f6670fa064c33c59a6cf0d47d80d7cee # shrinks to input = _StakeOwnerDelegationTxEncodeDecodeArgs { transaction: Transaction { payload: [8, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0], nb_inputs: 0, nb_outputs: 0, valid_until: BlockDate { epoch: 1, slot_id: 0 }, nb_witnesses: 0, total_input_value: Ok(Value(0)), total_output_value: Ok(Value(0)) } } diff --git a/chain-impl-mockchain/proptest-regressions/update.txt b/chain-impl-mockchain/proptest-regressions/update.txt new file mode 100644 index 000000000..0cf933e11 --- /dev/null +++ b/chain-impl-mockchain/proptest-regressions/update.txt @@ -0,0 +1,7 @@ +# Seeds for failure cases proptest has generated in the past. It is +# automatically read and these particular cases re-run before any +# novel cases are generated. +# +# It is recommended to check this file in to source control so that +# everyone who runs the test benefits from these saved cases. +xx 4642d80469dec0525b5af24e14ada6222305a2ae797c3127bfa04a810a2ca1c6 # shrinks to input = _UpdateProposalSerializeDeserializeBijectionArgs { update_proposal: UpdateProposal { changes: ConfigParams([LinearFee(LinearFee { constant: 0, coefficient: 0, certificate: 0, per_certificate_fees: PerCertificateFee { certificate_pool_registration: None, certificate_stake_delegation: None, certificate_owner_stake_delegation: None }, per_vote_certificate_fees: PerVoteCertificateFee { certificate_vote_plan: None, certificate_vote_cast: Some(1) } })]) } } diff --git a/chain-impl-mockchain/proptest-regressions/utxo.txt b/chain-impl-mockchain/proptest-regressions/utxo.txt new file mode 100644 index 000000000..3fccf1a9a --- /dev/null +++ b/chain-impl-mockchain/proptest-regressions/utxo.txt @@ -0,0 +1,7 @@ +# Seeds for failure cases proptest has generated in the past. It is +# automatically read and these particular cases re-run before any +# novel cases are generated. +# +# It is recommended to check this file in to source control so that +# everyone who runs the test benefits from these saved cases. +xx 19270d1f1aee9a25c6507114a1ecca479baf33abdaeeb9304a55ad1048e2010a # shrinks to input = _TransactionUnspentRemoveArgs { outputs: ArbitraryTransactionOutputs { utxos: {0: Output { address: Address(Test, Single(b1d12215b806dce8f7d9bf818bcd6f4bfbbbc1f1c2a0987bb75f5f2624ad1f61)), value: Value(6105) }}, idx_to_remove: 255 } } diff --git a/chain-impl-mockchain/src/account.rs b/chain-impl-mockchain/src/account.rs index 29ee3db59..e1e8f1bb8 100644 --- a/chain-impl-mockchain/src/account.rs +++ b/chain-impl-mockchain/src/account.rs @@ -15,7 +15,14 @@ pub type Witness = Signature; /// Account Identifier (also used as Public Key) #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct Identifier(PublicKey); +#[cfg_attr( + any(test, feature = "property-test-api"), + derive(test_strategy::Arbitrary) +)] +pub struct Identifier( + #[cfg_attr(any(test, feature = "property-test-api"), strategy(chain_crypto::testing::public_key_strategy::()))] + PublicKey, +); impl From> for Identifier { fn from(pk: PublicKey) -> Self { diff --git a/chain-impl-mockchain/src/accounting/account/account_state.rs b/chain-impl-mockchain/src/accounting/account/account_state.rs index dbcf95fce..0c617d4b9 100644 --- a/chain-impl-mockchain/src/accounting/account/account_state.rs +++ b/chain-impl-mockchain/src/accounting/account/account_state.rs @@ -5,12 +5,19 @@ use imhamt::HamtIter; use super::{LastRewards, LedgerError}; +#[cfg(any(test, feature = "property-test-api"))] +use proptest::prelude::*; + /// Set the choice of delegation: /// /// * No delegation /// * Full delegation of this account to a specific pool /// * Ratio of stake to multiple pools #[derive(Clone, PartialEq, Eq, Debug)] +#[cfg_attr( + any(test, feature = "property-test-api"), + derive(test_strategy::Arbitrary) +)] pub enum DelegationType { NonDelegated, Full(PoolId), @@ -28,11 +35,22 @@ pub enum DelegationType { /// and by extension parts need to be equal to the sum of individual /// pools parts. #[derive(Clone, PartialEq, Eq, Debug)] +#[cfg_attr( + any(test, feature = "property-test-api"), + derive(test_strategy::Arbitrary) +)] pub struct DelegationRatio { + #[cfg_attr(any(test, feature = "property-test-api"), strategy(Just(8u8)))] pub(crate) parts: u8, + #[cfg_attr(any(test, feature = "property-test-api"), strategy(delegation_ratio_strategy(#parts)))] pub(crate) pools: Box<[(PoolId, u8)]>, } +#[cfg(any(test, feature = "property-test-api"))] +fn delegation_ratio_strategy(parts: u8) -> impl Strategy> { + Just(Vec::new().into_boxed_slice()) // TODO proptest +} + /// The maximum number of pools pub const DELEGATION_RATIO_MAX_DECLS: usize = 8; @@ -76,6 +94,10 @@ impl DelegationRatio { } #[derive(Clone, PartialEq, Eq, Debug)] +#[cfg_attr( + any(test, feature = "property-test-api"), + derive(test_strategy::Arbitrary) +)] pub struct AccountState { pub counter: SpendingCounter, pub delegation: DelegationType, @@ -190,6 +212,10 @@ impl AccountState { /// needs to be used in the spending phase to make /// sure we have non-replayability of a transaction. #[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[cfg_attr( + any(test, feature = "property-test-api"), + derive(test_strategy::Arbitrary) +)] pub struct SpendingCounter(pub(crate) u32); impl SpendingCounter { @@ -240,21 +266,19 @@ mod tests { value::Value, }; use quickcheck::{Arbitrary, Gen, TestResult}; - use quickcheck_macros::quickcheck; use std::iter; - #[quickcheck] - pub fn account_sub_is_consistent( - init_value: Value, - sub_value: Value, - counter: u32, - ) -> TestResult { + use proptest::prelude::*; + use test_strategy::proptest; + + #[proptest] + fn account_sub_is_consistent(init_value: Value, sub_value: Value, counter: u32) { let mut account_state = AccountState::new(init_value, ()); account_state.counter = counter.into(); - TestResult::from_bool( - should_sub_fail(account_state.clone(), sub_value) - == account_state.sub(sub_value).is_err(), - ) + prop_assert_eq!( + should_sub_fail(account_state.clone(), sub_value), + account_state.sub(sub_value).is_err() + ); } #[test] @@ -269,22 +293,26 @@ mod tests { ); } - #[quickcheck] - pub fn add_value(init_value: Value, value_to_add: Value) -> TestResult { + #[proptest] + fn add_value(init_value: Value, value_to_add: Value) { let account_state = AccountState::new(init_value, ()); let left = account_state.add_value(value_to_add); let right = account_state.add(value_to_add); match (left, right) { - (Err(_), Err(_)) => TestResult::passed(), + (Err(_), Err(_)) => {} (Ok(next_left), Ok(next_right)) => { - TestResult::from_bool(next_left.value() == next_right.value()) + prop_assert_eq!(next_left.value(), next_right.value()) } - (Ok(_), Err(_)) => TestResult::error("add_value() success while add() failed"), - (Err(_), Ok(_)) => TestResult::error("add() success while add_value() failed"), + (Ok(_), Err(_)) => panic!("add_value() success while add() failed"), + (Err(_), Ok(_)) => panic!("add() success while add_value() failed"), } } #[derive(Clone, Debug)] + #[cfg_attr( + any(test, feature = "property-test-api"), + derive(test_strategy::Arbitrary) + )] pub enum ArbitraryAccountStateOp { Add(Value), Sub(Value), @@ -305,7 +333,11 @@ mod tests { } } - #[derive(Clone, Debug)] + #[derive(Debug, Clone)] + #[cfg_attr( + any(test, feature = "property-test-api"), + derive(test_strategy::Arbitrary) + )] pub struct ArbitraryOperationChain(pub Vec); impl Arbitrary for ArbitraryOperationChain { @@ -390,14 +422,18 @@ mod tests { } } - #[quickcheck] - pub fn account_state_is_consistent( - mut account_state: AccountState<()>, + #[proptest] + fn account_state_is_consistent( + account_state: AccountState<()>, operations: ArbitraryOperationChain, - ) -> TestResult { + ) { + // TODO test-strategy needs to be fixed, it removes mut modifier from argument bindings + let mut account_state = account_state; // to count spending counter let mut successful_subs = 0; + let mut should_exit = false; + let initial_account_state = account_state.clone(); for (counter, operation) in operations.clone().into_iter().enumerate() { account_state = match operation { @@ -406,8 +442,8 @@ mod tests { match (should_fail, account_state.add(value)) { (false, Ok(account_state)) => account_state, (true, Err(_)) => account_state, - (false, Err(err)) => return TestResult::error(format!("Operation {}: unexpected add operation failure. Expected success but got: {:?}",counter,err)), - (true, Ok(account_state)) => return TestResult::error(format!("Operation {}: unexpected add operation success. Expected failure but got: success. AccountState: {:?}",counter, &account_state)), + (false, Err(err)) => panic!(format!("Operation {}: unexpected add operation failure. Expected success but got: {:?}",counter,err)), + (true, Ok(account_state)) => panic!(format!("Operation {}: unexpected add operation success. Expected failure but got: success. AccountState: {:?}",counter, &account_state)), } } ArbitraryAccountStateOp::Sub(value) => { @@ -418,12 +454,17 @@ mod tests { // check if account has any funds left match account_state { Some(account_state) => account_state, - None => return verify_account_lost_all_funds(initial_account_state,operations,counter,successful_subs,account_state.unwrap()) + None => { + let expected_account = operations.get_account_state_after_n_ops(initial_account_state.clone(), counter, successful_subs); + prop_assert_eq!(expected_account.value, Value::zero(),"Account is dry out from funds after {} operations, while expectation was different. Expected: {:?}, Actual {:?}",counter,expected_account,account_state.unwrap()); + should_exit = true; + break; + }, } } (true, Err(_)) => account_state, - (false, Err(err)) => return TestResult::error(format!("Operation {}: unexpected sub operation failure. Expected success but got: {:?}",counter,err)), - (true, Ok(account_state)) => return TestResult::error(format!("Operation {}: unexpected sub operation success. Expected failure but got: success. AccountState: {:?}",counter, &account_state)), + (false, Err(err)) => panic!(format!("Operation {}: unexpected sub operation failure. Expected success but got: {:?}",counter,err)), + (true, Ok(account_state)) => panic!(format!("Operation {}: unexpected sub operation success. Expected failure but got: success. AccountState: {:?}",counter, &account_state)), } } ArbitraryAccountStateOp::Delegate(stake_pool_id) => { @@ -434,31 +475,12 @@ mod tests { } }; } - let expected_account_state = - operations.get_account_state(initial_account_state, successful_subs); - if expected_account_state == account_state { - TestResult::passed() - } else { - TestResult::error(format!( - "Actual AccountState is not equal to expected one. Expected {:?}, but got {:?}", - expected_account_state, account_state - )) - } - } - fn verify_account_lost_all_funds( - initial_account_state: AccountState<()>, - operations: ArbitraryOperationChain, - counter: usize, - subs: u32, - actual_account_state: AccountState<()>, - ) -> TestResult { - let expected_account = - operations.get_account_state_after_n_ops(initial_account_state, counter, subs); - if expected_account.value == Value::zero() { - TestResult::passed() - } else { - TestResult::error(format!("Account is dry out from funds after {} operations, while expectation was different. Expected: {:?}, Actual {:?}",counter,expected_account,actual_account_state)) + if !should_exit { + let expected_account_state = + operations.get_account_state(initial_account_state, successful_subs); + + prop_assert_eq!(expected_account_state, account_state); } } @@ -539,8 +561,8 @@ mod tests { assert!(DelegationRatio::new(parts, pools).is_none()); } - #[quickcheck] - pub fn add_rewards(account_state_no_reward: AccountState<()>, value: Value) -> TestResult { + #[proptest] + fn add_rewards(account_state_no_reward: AccountState<()>, value: Value) { let initial_value = account_state_no_reward.value(); let account_state_reward = account_state_no_reward.clone(); @@ -551,38 +573,48 @@ mod tests { .add_rewards(1, value) .expect("cannot add reward"); - accounts_are_the_same(account_state_no_reward, account_state_reward, initial_value) + prop_assert_eq!( + account_state_no_reward.value(), + account_state_reward.value(), + "value should be the same {} vs {}", + account_state_no_reward.value(), + account_state_reward.value() + ); + + let expected_reward_account_state = + (account_state_reward.last_rewards.reward + initial_value).unwrap(); + + prop_assert_eq!( + account_state_no_reward.value(), + expected_reward_account_state, + "reward should be the same {} vs {}", + account_state_no_reward.value(), + expected_reward_account_state + ); } - #[quickcheck] - pub fn new_account_rewards(value: Value) -> TestResult { + #[proptest] + fn new_account_rewards(value: Value) { let account_state = AccountState::new(value, ()); let account_with_reward = AccountState::new_reward(1, value, ()); - accounts_are_the_same(account_state, account_with_reward, Value::zero()) - } - - fn accounts_are_the_same( - account_without_reward: AccountState<()>, - account_with_reward: AccountState<()>, - initial_value: Value, - ) -> TestResult { - if account_without_reward.value() != account_with_reward.value() { - return TestResult::error(format!( - "value should be the same {} vs {}", - account_without_reward.value(), - account_with_reward.value() - )); - } + + prop_assert_eq!( + account_state.value(), + account_with_reward.value(), + "value should be the same {} vs {}", + account_state.value(), + account_with_reward.value() + ); let expected_reward_account_state = - (account_with_reward.last_rewards.reward + initial_value).unwrap(); - if account_without_reward.value() != expected_reward_account_state { - return TestResult::error(format!( - "reward should be the same {} vs {}", - account_without_reward.value(), - expected_reward_account_state - )); - } - TestResult::passed() + (account_with_reward.last_rewards.reward + Value::zero()).unwrap(); + + prop_assert_eq!( + account_state.value(), + expected_reward_account_state, + "reward should be the same {} vs {}", + account_state.value(), + expected_reward_account_state + ); } } diff --git a/chain-impl-mockchain/src/accounting/account/last_rewards.rs b/chain-impl-mockchain/src/accounting/account/last_rewards.rs index cfe32feda..23af346f2 100644 --- a/chain-impl-mockchain/src/accounting/account/last_rewards.rs +++ b/chain-impl-mockchain/src/accounting/account/last_rewards.rs @@ -6,6 +6,10 @@ use crate::value::Value; /// It tracks the epoch where the rewards has been received, /// and the total amount of reward for such an epoch #[derive(Debug, Clone, PartialEq, Eq)] +#[cfg_attr( + any(test, feature = "property-test-api"), + derive(test_strategy::Arbitrary) +)] pub struct LastRewards { pub epoch: Epoch, pub reward: Value, diff --git a/chain-impl-mockchain/src/accounting/account/mod.rs b/chain-impl-mockchain/src/accounting/account/mod.rs index cbe44d6d1..fc7615888 100644 --- a/chain-impl-mockchain/src/accounting/account/mod.rs +++ b/chain-impl-mockchain/src/accounting/account/mod.rs @@ -233,100 +233,108 @@ mod tests { value::Value, }; - use quickcheck::{Arbitrary, Gen, TestResult}; - use quickcheck_macros::quickcheck; + use proptest::{ + collection::{hash_map, vec}, + prelude::*, + sample::select, + }; use std::collections::HashSet; use std::iter; - - impl Arbitrary for Ledger { - fn arbitrary(gen: &mut G) -> Self { - let account_size = std::cmp::max(usize::arbitrary(gen), 1); - let stake_pool_size = - std::cmp::min(account_size, usize::arbitrary(gen) % account_size + 1); - let arbitrary_accounts_ids = iter::from_fn(|| Some(Identifier::arbitrary(gen))) - .take(account_size) - .collect::>(); - - let arbitrary_stake_pools = iter::from_fn(|| Some(PoolRegistration::arbitrary(gen))) - .take(stake_pool_size) - .collect::>(); - - let mut ledger = Ledger::new(); - - // Add all arbitrary accounts - for account_id in arbitrary_accounts_ids.iter().cloned() { - ledger = ledger - .add_account(&account_id, AverageValue::arbitrary(gen).into(), ()) - .unwrap(); - } - - // Choose random subset of arbitraty accounts and delegate stake to random stake pools - for account_id in - arbitrary_utils::choose_random_set_subset(&arbitrary_accounts_ids, gen) - { - let random_stake_pool = - arbitrary_utils::choose_random_item(&arbitrary_stake_pools, gen); - ledger = ledger - .set_delegation( - &account_id, - &DelegationType::Full(random_stake_pool.to_id()), + use test_strategy::proptest; + + impl proptest::arbitrary::Arbitrary for Ledger { + type Parameters = (); + type Strategy = proptest::strategy::BoxedStrategy; + + fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { + (1..256usize) + .prop_flat_map(|account_size| { + let arbitrary_accounts = + hash_map(any::(), any::(), account_size); // TODO proptest AverageValue + let arbitrary_stake_pools = vec(any::(), 1..=account_size); + (arbitrary_accounts, arbitrary_stake_pools) + }) + .prop_flat_map(|(arbitrary_accounts, arbitrary_stake_pools)| { + // Choose random subset of arbitraty accounts and delegate stake to random stake pools + let accounts_to_select_from = arbitrary_accounts + .iter() + .map(|(key, _value)| key) + .cloned() + .collect::>(); + let pools_to_select_from = arbitrary_stake_pools + .iter() + .map(|sp| sp.to_id()) + .collect::>(); + let accounts_to_select_from_len = accounts_to_select_from.len(); + let delegations = vec( + ( + select(accounts_to_select_from), + select(pools_to_select_from), + ), + 0..accounts_to_select_from_len, + ); + ( + Just(arbitrary_accounts), + Just(arbitrary_stake_pools), + delegations, ) - .unwrap(); - } - ledger + }) + .prop_map(|(arbitrary_accounts, arbitrary_stake_pools, delegations)| { + // TODO proptest arbitrary_stake_pools -- check the original implementation + let mut ledger = Ledger::new(); + + // Add all arbitrary accounts + for (account_id, value) in arbitrary_accounts { + ledger = ledger.add_account(&account_id, value, ()).unwrap(); + } + + for (delegator, delegatee) in delegations { + ledger = ledger + .set_delegation(&delegator, &DelegationType::Full(delegatee)) + .unwrap(); + } + + ledger + }) + .boxed() } } - #[quickcheck] - pub fn account_ledger_test( + #[proptest] + fn account_ledger_test( mut ledger: Ledger, account_id: Identifier, value: Value, stake_pool_id: PoolId, - ) -> TestResult { - if value == Value::zero() || ledger.exists(&account_id) { - return TestResult::discard(); - } + ) { + // TODO test-strategy needs to be fixed, it removes mut modifier from argument bindings + let mut ledger = ledger; + + prop_assume!(value != Value::zero() && !ledger.exists(&account_id)); let initial_total_value = ledger.get_total_value().unwrap(); // add new account - ledger = match ledger.add_account(&account_id, value, ()) { - Ok(ledger) => ledger, - Err(err) => { - return TestResult::error(format!( - "Add account with id {} should be successful: {:?}", - account_id, err - )) - } - }; + ledger = ledger.add_account(&account_id, value, ()).unwrap(); // add account again should throw an error - if ledger.add_account(&account_id, value, ()).is_ok() { - return TestResult::error(format!( - "Account with id {} again should should", - account_id - )); - } - assert!( + prop_assert!(ledger.add_account(&account_id, value, ()).is_err()); + prop_assert!( ledger.exists(&account_id), "Account with id {} should exist", account_id ); - assert!( + prop_assert!( ledger.iter().any(|(x, _)| *x == account_id), "Account with id {} should be listed amongst other", account_id ); // verify total value was increased - let test_result = test_total_value( + test_total_value( (initial_total_value + value).unwrap(), ledger.get_total_value().unwrap(), ); - if test_result.is_error() { - return test_result; - } // set delegation to stake pool ledger = match ledger @@ -334,60 +342,53 @@ mod tests { { Ok(ledger) => ledger, Err(err) => { - return TestResult::error(format!( + panic!( "Set delegation operation for id {} should be successful: {:?}", account_id, err - )) + ); } }; // verify total value is still the same - assert!(!test_total_value( + test_total_value( (initial_total_value + value).unwrap(), ledger.get_total_value().unwrap(), - ) - .is_failure()); + ); // add value to account ledger = match ledger.add_value(&account_id, value) { Ok(ledger) => ledger, Err(err) => { - return TestResult::error(format!( + panic!( "Add value to account operation for id {} should be successful: {:?}", account_id, err - )) + ) } }; // verify total value was increased - let test_result = test_total_value( + test_total_value( (initial_total_value + (value + value).unwrap()).unwrap(), ledger.get_total_value().unwrap(), ); - if test_result.is_error() { - return test_result; - } //add reward to account ledger = match ledger.add_rewards_to_account(&account_id, 0, value, ()) { Ok(ledger) => ledger, Err(err) => { - return TestResult::error(format!( + panic!( "Add rewards to account operation for id {} should be successful: {:?}", account_id, err - )) + ) } }; let value_after_reward = Value(value.0 * 3); // verify total value was increased - let test_result = test_total_value( + test_total_value( (initial_total_value + value_after_reward).unwrap(), ledger.get_total_value().unwrap(), ); - if test_result.is_error() { - return test_result; - } //verify account state match ledger.get_state(&account_id) { @@ -404,17 +405,17 @@ mod tests { }; if *account_state != expected_account_state { - return TestResult::error(format!( + panic!( "Account state is incorrect expected {:?} but got {:?}", expected_account_state, account_state - )); + ); } } Err(err) => { - return TestResult::error(format!( + panic!( "Get state for id {} should be successful: {:?}", account_id, err - )) + ) } } @@ -422,38 +423,35 @@ mod tests { ledger = match ledger.remove_value(&account_id, value) { Ok((ledger, _spending_counter)) => ledger, Err(err) => { - return TestResult::error(format!( + panic!( "Removew value operation for id {} should be successful: {:?}", account_id, err - )) + ) } }; let value_before_reward = Value(value.0 * 2); // verify total value was decreased - let test_result = test_total_value( + test_total_value( (initial_total_value + value_before_reward).unwrap(), ledger.get_total_value().unwrap(), ); - if test_result.is_error() { - return test_result; - } // verify remove account fails beause account still got some founds if ledger.remove_account(&account_id).is_ok() { - return TestResult::error(format!( + panic!( "Remove account should be unsuccesfull... account for id {} still got funds", account_id - )); + ); } // removes all funds from account ledger = match ledger.remove_value(&account_id, value_before_reward) { Ok((ledger, _spending_counter)) => ledger, Err(err) => { - return TestResult::error(format!( + panic!( "Remove all funds operation for id {} should be successful: {:?}", account_id, err - )) + ) } }; @@ -461,10 +459,10 @@ mod tests { ledger = match ledger.remove_account(&account_id) { Ok(ledger) => ledger, Err(err) => { - return TestResult::error(format!( + panic!( "Remove account operation for id {} should be successful: {:?}", account_id, err - )) + ) } }; @@ -481,26 +479,19 @@ mod tests { ); //Account state is should be none - TestResult::from_bool(ledger.get_state(&account_id).is_err()) + prop_assert!(ledger.get_state(&account_id).is_err()) } - fn test_total_value(expected: Value, actual: Value) -> TestResult { - if actual == expected { - TestResult::passed() - } else { - TestResult::error(format!( - "Wrong total value expected {} but got {}", - expected, actual - )) - } + fn test_total_value(expected: Value, actual: Value) { + assert_eq!(expected, actual, "Wrong total value"); } - #[quickcheck] - pub fn ledger_total_value_is_correct_after_remove_value( + #[proptest] + fn ledger_total_value_is_correct_after_remove_value( id: Identifier, account_state: AccountState<()>, value_to_remove: Value, - ) -> TestResult { + ) { let mut ledger = Ledger::new(); ledger = ledger .add_account(&id, account_state.get_value(), ()) @@ -509,29 +500,18 @@ mod tests { let expected_result = account_state.get_value() - value_to_remove; match (result, expected_result) { (Err(_), Err(_)) => verify_total_value(ledger, account_state.get_value()), - (Ok(_), Err(_)) => TestResult::failed(), - (Err(_), Ok(_)) => TestResult::failed(), + (Ok(_), Err(_)) => panic!(), + (Err(_), Ok(_)) => panic!(), (Ok((ledger, _)), Ok(value)) => verify_total_value(ledger, value), } } - fn verify_total_value(ledger: Ledger, value: Value) -> TestResult { - if ledger.get_total_value().unwrap() == value { - TestResult::passed() - } else { - TestResult::error(format!( - "Wrong total value got {:?}, while expecting {:?}", - ledger.get_total_value(), - value - )) - } + fn verify_total_value(ledger: Ledger, value: Value) { + assert_eq!(ledger.get_total_value().unwrap(), value); } - #[quickcheck] - pub fn ledger_removes_account_only_if_zeroed( - id: Identifier, - account_state: AccountState<()>, - ) -> TestResult { + #[proptest] + fn ledger_removes_account_only_if_zeroed(id: Identifier, account_state: AccountState<()>) { let mut ledger = Ledger::new(); ledger = ledger .add_account(&id, account_state.get_value(), ()) @@ -539,29 +519,18 @@ mod tests { let result = ledger.remove_account(&id); let expected_zero = account_state.get_value() == Value::zero(); match (result, expected_zero) { - (Err(_), false) => verify_account_exists(&ledger, &id), - (Ok(_), false) => TestResult::failed(), - (Err(_), true) => TestResult::failed(), - (Ok(ledger), true) => verify_account_does_not_exist(&ledger, &id), - } - } - - fn verify_account_exists(ledger: &Ledger, id: &Identifier) -> TestResult { - if ledger.exists(&id) { - TestResult::passed() - } else { - TestResult::error(format!( + (Err(_), false) => prop_assert!( + ledger.exists(&id), "Account ({:?}) does not exist, while it should", - &id - )) - } - } - - fn verify_account_does_not_exist(ledger: &Ledger, id: &Identifier) -> TestResult { - if ledger.exists(&id) { - TestResult::error(format!("Account ({:?}) exists, while it should not", &id)) - } else { - TestResult::passed() + id + ), + (Ok(_), false) => panic!(), + (Err(_), true) => panic!(), + (Ok(ledger), true) => prop_assert!( + ledger.exists(&id), + "Account ({:?}) exists, while it should not", + id + ), } } diff --git a/chain-impl-mockchain/src/block/headerraw.rs b/chain-impl-mockchain/src/block/headerraw.rs index 7c287f3da..c54001e45 100644 --- a/chain-impl-mockchain/src/block/headerraw.rs +++ b/chain-impl-mockchain/src/block/headerraw.rs @@ -2,7 +2,14 @@ use chain_core::property; /// Block Header Bytes #[derive(Debug, Clone, PartialEq, Eq)] -pub struct HeaderRaw(pub(super) Vec); +#[cfg_attr( + any(test, feature = "property-test-api"), + derive(test_strategy::Arbitrary) +)] +pub struct HeaderRaw( + #[cfg_attr(any(test, feature = "property-test-api"), any(proptest::collection::size_range(..65536).lift()))] + pub(super) Vec, +); impl AsRef<[u8]> for HeaderRaw { fn as_ref(&self) -> &[u8] { diff --git a/chain-impl-mockchain/src/block/mod.rs b/chain-impl-mockchain/src/block/mod.rs index 46625cf6e..267654c54 100644 --- a/chain-impl-mockchain/src/block/mod.rs +++ b/chain-impl-mockchain/src/block/mod.rs @@ -11,6 +11,8 @@ mod headerraw; #[cfg(any(test, feature = "property-test-api"))] pub mod test; +#[cfg(any(test, feature = "property-test-api"))] +use proptest::prelude::*; //pub use self::builder::BlockBuilder; pub use crate::fragment::{BlockContentHash, BlockContentSize, Contents, ContentsBuilder}; @@ -30,11 +32,23 @@ pub use crate::date::{BlockDate, BlockDateParseError, Epoch, SlotId}; /// transaction and a reference to the parent block. Alongside /// with the position of that block in the chain. #[derive(Debug, Clone)] +#[cfg_attr( + any(test, feature = "property-test-api"), + derive(test_strategy::Arbitrary) +)] pub struct Block { + #[cfg_attr(any(test, feature = "property-test-api"), strategy(header_from_contents_strategy(#contents)))] pub header: Header, + #[cfg_attr(any(test, feature = "property-test-api"), by_ref)] pub contents: Contents, } +#[cfg(any(test, feature = "property-test-api"))] +fn header_from_contents_strategy(contents: &Contents) -> impl Strategy { + let (parent_hash, content_size) = contents.compute_hash_size(); + crate::header::test::header_strategy(parent_hash, content_size) +} + impl PartialEq for Block { fn eq(&self, rhs: &Self) -> bool { self.header.hash() == rhs.header.hash() diff --git a/chain-impl-mockchain/src/block/test.rs b/chain-impl-mockchain/src/block/test.rs index 1f3d2b227..2e81c934c 100644 --- a/chain-impl-mockchain/src/block/test.rs +++ b/chain-impl-mockchain/src/block/test.rs @@ -11,62 +11,70 @@ use crate::{ }; #[cfg(test)] use chain_core::property::{Block as _, Deserialize, HasHeader as _, Serialize}; +use proptest::prelude::*; #[cfg(test)] use quickcheck::TestResult; use quickcheck::{Arbitrary, Gen}; +use test_strategy::proptest; -quickcheck! { - fn headerraw_serialization_bijection(b: HeaderRaw) -> TestResult { - serialization_bijection(b) - } - - fn header_serialization_bijection(b: Header) -> TestResult { - serialization_bijection_r(b) - } +#[proptest] +fn headerraw_serialization_bijection(b: HeaderRaw) { + serialization_bijection(b) +} - fn block_serialization_bijection(b: Block) -> TestResult { - serialization_bijection(b) - } +#[proptest] +fn header_serialization_bijection(b: Header) { + serialization_bijection_r(b) +} - fn block_serialization_bijection_r(b: Block) -> TestResult { - serialization_bijection_r(b) - } +#[proptest] +fn block_serialization_bijection(b: Block) { + serialization_bijection(b) +} - fn block_properties(block: Block) -> TestResult { +#[proptest] +fn block_serialization_bijection_r(b: Block) { + serialization_bijection_r(b) +} - let vec = block.serialize_as_vec().unwrap(); - let new_block = Block::deserialize(&vec[..]).unwrap(); +#[proptest] +fn block_properties(block: Block) { + let vec = block.serialize_as_vec().unwrap(); + let new_block = Block::deserialize(&vec[..]).unwrap(); - assert_eq!(block.is_consistent(),new_block.is_consistent()); - assert!(block.fragments().eq(new_block.fragments())); - assert_eq!(block.header(),new_block.header()); - assert_eq!(block.id(),new_block.id()); - assert_eq!(block.parent_id(),new_block.parent_id()); - assert_eq!(block.date(),new_block.date()); - assert_eq!(block.version(),new_block.version()); + prop_assert_eq!(block.is_consistent(), new_block.is_consistent()); + prop_assert!(block.fragments().eq(new_block.fragments())); + prop_assert_eq!(block.header(), new_block.header()); + prop_assert_eq!(block.id(), new_block.id()); + prop_assert_eq!(block.parent_id(), new_block.parent_id()); + prop_assert_eq!(block.date(), new_block.date()); + prop_assert_eq!(block.version(), new_block.version()); - TestResult::from_bool(block.chain_length() == new_block.chain_length()) - } + prop_assert_eq!(block.chain_length(), new_block.chain_length()); +} - fn header_properties(block: Block) -> TestResult { - use chain_core::property::Header as Prop; - let header = block.header.clone(); - assert_eq!(header.hash(),block.id()); - assert_eq!(header.id(),block.id()); - assert_eq!(header.parent_id(),block.parent_id()); - assert_eq!(header.date(),block.date()); - assert_eq!(header.version(),block.version()); +#[proptest] +fn header_properties(block: Block) { + use chain_core::property::Header as Prop; + let header = block.header.clone(); + prop_assert_eq!(header.hash(), block.id()); + prop_assert_eq!(header.id(), block.id()); + prop_assert_eq!(header.parent_id(), block.parent_id()); + prop_assert_eq!(header.date(), block.date()); + prop_assert_eq!(header.version(), block.version()); - assert_eq!(header.get_bft_leader_id(),block.header.get_bft_leader_id()); - assert_eq!(header.get_stakepool_id(),block.header.get_stakepool_id()); - assert_eq!(header.common(),block.header.common()); - assert_eq!(header.to_raw(),block.header.to_raw()); - assert_eq!(header.as_auth_slice(),block.header.as_auth_slice()); - assert!(are_desc_equal(header.description(),block.header.description())); - assert_eq!(header.size(),block.header.size()); + prop_assert_eq!(header.get_bft_leader_id(), block.header.get_bft_leader_id()); + prop_assert_eq!(header.get_stakepool_id(), block.header.get_stakepool_id()); + prop_assert_eq!(header.common(), block.header.common()); + prop_assert_eq!(header.to_raw(), block.header.to_raw()); + prop_assert_eq!(header.as_auth_slice(), block.header.as_auth_slice()); + prop_assert!(are_desc_equal( + header.description(), + block.header.description() + )); + prop_assert_eq!(header.size(), block.header.size()); - TestResult::from_bool(header.chain_length() == block.chain_length()) - } + prop_assert_eq!(header.chain_length(), block.chain_length()); } #[cfg(test)] diff --git a/chain-impl-mockchain/src/certificate/delegation.rs b/chain-impl-mockchain/src/certificate/delegation.rs index 916c11a0b..59f39f3b4 100644 --- a/chain-impl-mockchain/src/certificate/delegation.rs +++ b/chain-impl-mockchain/src/certificate/delegation.rs @@ -17,6 +17,10 @@ use typed_bytes::{ByteArray, ByteBuilder}; /// This structure is not sufficient to identify the owner, and instead we rely on a special /// authenticated transaction, which has 1 input. #[derive(Debug, Clone, PartialEq, Eq)] +#[cfg_attr( + any(test, feature = "property-test-api"), + derive(test_strategy::Arbitrary) +)] pub struct OwnerStakeDelegation { pub delegation: DelegationType, } @@ -35,6 +39,10 @@ impl OwnerStakeDelegation { } #[derive(Debug, Clone, PartialEq, Eq)] +#[cfg_attr( + any(test, feature = "property-test-api"), + derive(test_strategy::Arbitrary) +)] pub struct StakeDelegation { pub account_id: UnspecifiedAccountIdentifier, pub delegation: DelegationType, diff --git a/chain-impl-mockchain/src/certificate/encrypted_vote_tally.rs b/chain-impl-mockchain/src/certificate/encrypted_vote_tally.rs index de648454a..3a0a8d909 100644 --- a/chain-impl-mockchain/src/certificate/encrypted_vote_tally.rs +++ b/chain-impl-mockchain/src/certificate/encrypted_vote_tally.rs @@ -12,12 +12,20 @@ use chain_crypto::Verification; use typed_bytes::{ByteArray, ByteBuilder}; #[derive(Debug, Clone)] +#[cfg_attr( + any(test, feature = "property-test-api"), + derive(test_strategy::Arbitrary) +)] pub struct EncryptedVoteTallyProof { pub id: CommitteeId, pub signature: SingleAccountBindingSignature, } #[derive(Debug, Eq, PartialEq, Hash, Clone)] +#[cfg_attr( + any(test, feature = "property-test-api"), + derive(test_strategy::Arbitrary) +)] pub struct EncryptedVoteTally { id: VotePlanId, } diff --git a/chain-impl-mockchain/src/certificate/mod.rs b/chain-impl-mockchain/src/certificate/mod.rs index 8156efcf1..346e4a177 100644 --- a/chain-impl-mockchain/src/certificate/mod.rs +++ b/chain-impl-mockchain/src/certificate/mod.rs @@ -174,6 +174,10 @@ impl<'a> From<&'a Certificate> for CertificatePayload { #[allow(clippy::large_enum_variant)] #[derive(Debug, Clone)] +#[cfg_attr( + any(test, feature = "property-test-api"), + derive(test_strategy::Arbitrary) +)] pub enum Certificate { StakeDelegation(StakeDelegation), OwnerStakeDelegation(OwnerStakeDelegation), @@ -275,11 +279,12 @@ pub enum SignedCertificate { #[cfg(test)] mod tests { use super::*; + use proptest::prelude::*; use quickcheck::TestResult; - use quickcheck_macros::quickcheck; + use test_strategy::proptest; - #[quickcheck] - pub fn need_auth(certificate: Certificate) -> TestResult { + #[proptest] + fn need_auth(certificate: Certificate) { let expected_result = match certificate { Certificate::PoolRegistration(_) => true, Certificate::PoolUpdate(_) => true, @@ -291,6 +296,6 @@ mod tests { Certificate::VoteTally(_) => true, Certificate::EncryptedVoteTally(_) => true, }; - TestResult::from_bool(certificate.need_auth() == expected_result) + prop_assert_eq!(certificate.need_auth(), expected_result); } } diff --git a/chain-impl-mockchain/src/certificate/pool.rs b/chain-impl-mockchain/src/certificate/pool.rs index e1b7cce88..3b9eca91f 100644 --- a/chain-impl-mockchain/src/certificate/pool.rs +++ b/chain-impl-mockchain/src/certificate/pool.rs @@ -14,6 +14,11 @@ use chain_time::{DurationSeconds, TimeOffsetSeconds}; use std::marker::PhantomData; use typed_bytes::{ByteArray, ByteBuilder}; +#[cfg(any(test, feature = "property-test-api"))] +use chain_crypto::testing::public_key_strategy; +#[cfg(any(test, feature = "property-test-api"))] +use proptest::prelude::*; + /// Pool ID pub type PoolId = PoolRegistrationHash; @@ -28,6 +33,10 @@ pub type IndexSignatures = Vec<(u8, SingleAccountBindingSignature)>; /// Pool information #[derive(Debug, Clone, PartialEq, Eq)] +#[cfg_attr( + any(test, feature = "property-test-api"), + derive(test_strategy::Arbitrary) +)] pub struct PoolRegistration { /// A random value, for user purpose similar to a UUID. /// it may not be unique over a blockchain, so shouldn't be used a unique identifier @@ -37,14 +46,28 @@ pub struct PoolRegistration { pub start_validity: TimeOffsetSeconds, /// Permission system for this pool /// * Management threshold for owners, this need to be <= #owners and > 0. + #[cfg_attr( + any(test, feature = "property-test-api"), + strategy(proptest::strategy::Just(PoolPermissions::new(1))) + )] pub permissions: PoolPermissions, /// Owners of this pool + #[cfg_attr(any(test, feature = "property-test-api"), strategy(proptest::collection::vec(public_key_strategy::(), 0..32)))] pub owners: Vec>, /// Operators of this pool + #[cfg_attr(any(test, feature = "property-test-api"), strategy(proptest::collection::vec(public_key_strategy::(), 0..4).prop_map(Vec::into_boxed_slice)))] pub operators: Box<[PublicKey]>, /// Rewarding + #[cfg_attr( + any(test, feature = "property-test-api"), + strategy(proptest::strategy::Just(TaxType::zero())) + )] pub rewards: TaxType, /// Reward account + #[cfg_attr( + any(test, feature = "property-test-api"), + strategy(proptest::strategy::Just(None)) + )] pub reward_account: Option, /// Genesis Praos keys pub keys: GenesisPraosLeader, @@ -83,6 +106,10 @@ impl PoolPermissions { /// Updating info for a pool #[derive(Debug, Clone, PartialEq, Eq)] +#[cfg_attr( + any(test, feature = "property-test-api"), + derive(test_strategy::Arbitrary) +)] pub struct PoolUpdate { pub pool_id: PoolId, pub last_pool_reg_hash: PoolRegistrationHash, @@ -91,12 +118,20 @@ pub struct PoolUpdate { /// Retirement info for a pool #[derive(Debug, Clone, PartialEq, Eq)] +#[cfg_attr( + any(test, feature = "property-test-api"), + derive(test_strategy::Arbitrary) +)] pub struct PoolRetirement { pub pool_id: PoolId, pub retirement_time: TimeOffsetSeconds, } #[derive(Debug, Clone)] +#[cfg_attr( + any(test, feature = "property-test-api"), + derive(test_strategy::Arbitrary) +)] pub enum PoolSignature { Operator(SingleAccountBindingSignature), Owners(PoolOwnersSignature), @@ -104,10 +139,32 @@ pub enum PoolSignature { /// Representant of a structure signed by a pool's owners #[derive(Debug, Clone)] +#[cfg_attr( + any(test, feature = "property-test-api"), + derive(test_strategy::Arbitrary) +)] pub struct PoolOwnersSignature { + #[cfg_attr( + any(test, feature = "property-test-api"), + strategy(pool_owners_signatures_strategy()) + )] pub signatures: IndexSignatures, } +#[cfg(any(test, feature = "property-test-api"))] +fn pool_owners_signatures_strategy( +) -> impl Strategy> { + use proptest::collection::vec; + + vec(any::(), 1..=32).prop_map(|signatures| { + signatures + .into_iter() + .enumerate() + .map(|(i, sig)| (i as u8, sig)) + .collect::>() + }) +} + pub type PoolOwnersSigned = PoolOwnersSignature; impl PoolRegistration { diff --git a/chain-impl-mockchain/src/certificate/test.rs b/chain-impl-mockchain/src/certificate/test.rs index 33d6594e7..7c55eb57c 100644 --- a/chain-impl-mockchain/src/certificate/test.rs +++ b/chain-impl-mockchain/src/certificate/test.rs @@ -8,10 +8,11 @@ use crate::vote; use chain_core::mempack::{ReadBuf, Readable}; use chain_crypto::{testing, Ed25519}; use chain_time::DurationSeconds; +use proptest::prelude::*; #[cfg(test)] use quickcheck::TestResult; use quickcheck::{Arbitrary, Gen}; -use quickcheck_macros::quickcheck; +use test_strategy::proptest; impl Arbitrary for PoolRetirement { fn arbitrary(g: &mut G) -> Self { @@ -74,6 +75,17 @@ impl Arbitrary for DelegationType { DelegationType::Full(Arbitrary::arbitrary(g)) } } +// TODO proptest +// impl proptest::arbitrary::Arbitrary for DelegationType { +// type Strategy = proptest::strategy::BoxedStrategy; +// type Parameters = (); + +// fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { +// any::() +// .prop_map(|pool_id| DelegationType::Full(pool_id)) +// .boxed() +// } +// } impl Arbitrary for StakeDelegation { fn arbitrary(g: &mut G) -> Self { @@ -273,13 +285,13 @@ impl Arbitrary for Certificate { } } -#[quickcheck] -fn pool_reg_serialization_bijection(b: PoolRegistration) -> TestResult { +#[proptest] +fn pool_reg_serialization_bijection(b: PoolRegistration) { let b_got = b.serialize(); let mut buf = ReadBuf::from(b_got.as_ref()); let result = PoolRegistration::read(&mut buf); let left = Ok(b); assert_eq!(left, result); assert_eq!(buf.get_slice_end(), &[]); - TestResult::from_bool(left == result) + prop_assert_eq!(left, result); } diff --git a/chain-impl-mockchain/src/certificate/vote_cast.rs b/chain-impl-mockchain/src/certificate/vote_cast.rs index 8377ec4ff..5d3ad3c04 100644 --- a/chain-impl-mockchain/src/certificate/vote_cast.rs +++ b/chain-impl-mockchain/src/certificate/vote_cast.rs @@ -10,6 +10,10 @@ use chain_core::{ use typed_bytes::{ByteArray, ByteBuilder}; #[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[cfg_attr( + any(test, feature = "property-test-api"), + derive(test_strategy::Arbitrary) +)] pub struct VoteCast { vote_plan: VotePlanId, proposal_index: u8, diff --git a/chain-impl-mockchain/src/certificate/vote_plan.rs b/chain-impl-mockchain/src/certificate/vote_plan.rs index 20ec04f42..57a26b6a7 100644 --- a/chain-impl-mockchain/src/certificate/vote_plan.rs +++ b/chain-impl-mockchain/src/certificate/vote_plan.rs @@ -34,6 +34,10 @@ pub type VotePlanId = DigestOf; /// is the committee supposed to reveal the results. /// #[derive(Debug, Clone, PartialEq, Eq)] +#[cfg_attr( + any(test, feature = "property-test-api"), + derive(test_strategy::Arbitrary) +)] pub struct VotePlan { /// the vote start validity vote_start: BlockDate, @@ -48,10 +52,36 @@ pub struct VotePlan { /// vote payload type payload_type: vote::PayloadType, /// encrypting votes public keys + #[cfg_attr( + any(test, feature = "property-test-api"), + strategy(committee_public_keys_strategy()) + )] committee_public_keys: Vec, } +#[cfg(any(test, feature = "property-test-api"))] +fn committee_public_keys_strategy( +) -> impl proptest::strategy::Strategy> { + use chain_crypto::testing::TestCryptoGen; + use proptest::prelude::*; + + let h = chain_vote::Crs::from_hash(&[0u8; 32]); + let threshold = 1; + + let keys = any::<(TestCryptoGen, u32)>().prop_map(move |(gen, idx)| { + let mut rng = gen.get_rng(idx); + let mc = chain_vote::MemberCommunicationKey::new(&mut rng); + let m1 = chain_vote::MemberState::new(&mut rng, threshold, &h, &[mc.to_public()], 0); + m1.public_key() + }); + proptest::collection::vec(keys, 1..16) +} + #[derive(Debug, Clone)] +#[cfg_attr( + any(test, feature = "property-test-api"), + derive(test_strategy::Arbitrary) +)] pub struct VotePlanProof { pub id: vote::CommitteeId, pub signature: SingleAccountBindingSignature, @@ -61,19 +91,27 @@ pub struct VotePlanProof { /// /// #[derive(Debug, Clone, PartialEq, Eq)] +#[cfg_attr( + any(test, feature = "property-test-api"), + derive(test_strategy::Arbitrary) +)] pub enum VoteAction { /// the action if off chain or not relevant to the blockchain OffChain, /// control the treasury Treasury { action: TreasuryGovernanceAction }, /// control the parameters - Parameters { action: ParametersGovernanceAction }, + LedgerParameters { action: ParametersGovernanceAction }, } /// a collection of proposals /// /// there may not be more than 255 proposal #[derive(Debug, Clone, PartialEq, Eq, Default)] +#[cfg_attr( + any(test, feature = "property-test-api"), + derive(test_strategy::Arbitrary) +)] pub struct Proposals { proposals: Vec, } @@ -84,6 +122,10 @@ pub struct Proposals { /// for the proposal to be operated. /// #[derive(Debug, Clone, PartialEq, Eq)] +#[cfg_attr( + any(test, feature = "property-test-api"), + derive(test_strategy::Arbitrary) +)] pub struct Proposal { external_id: ExternalProposalId, options: vote::Options, @@ -116,7 +158,7 @@ impl Proposal { // OffChain passes acceptance as it does not require governance return true; } - VoteAction::Parameters { action } => governance + VoteAction::LedgerParameters { action } => governance .parameters .acceptance_criteria_for(action.to_type()), VoteAction::Treasury { action } => governance @@ -151,7 +193,7 @@ impl VoteAction { match self { Self::OffChain => bb.u8(0), Self::Treasury { action } => bb.u8(1).sub(|bb| action.serialize_in(bb)), - Self::Parameters { action } => bb.u8(2).sub(|bb| action.serialize_in(bb)), + Self::LedgerParameters { action } => bb.u8(2).sub(|bb| action.serialize_in(bb)), } } } @@ -213,7 +255,7 @@ impl VotePlan { .iter() .any(|proposal| match proposal.action() { VoteAction::OffChain => false, - VoteAction::Parameters { .. } | VoteAction::Treasury { .. } => true, + VoteAction::LedgerParameters { .. } | VoteAction::Treasury { .. } => true, }) } @@ -392,7 +434,8 @@ impl Readable for VoteAction { match buf.get_u8()? { 0 => Ok(Self::OffChain), 1 => TreasuryGovernanceAction::read(buf).map(|action| Self::Treasury { action }), - 2 => ParametersGovernanceAction::read(buf).map(|action| Self::Parameters { action }), + 2 => ParametersGovernanceAction::read(buf) + .map(|action| Self::LedgerParameters { action }), t => Err(ReadError::UnknownTag(t as u32)), } } @@ -467,10 +510,11 @@ mod tests { use crate::block::BlockDate; use crate::testing::VoteTestGen; use chain_core::property::BlockDate as BlockDateProp; - use quickcheck_macros::quickcheck; + use proptest::prelude::*; + use test_strategy::proptest; - #[quickcheck] - fn serialize_deserialize(vote_plan: VotePlan) -> bool { + #[proptest] + fn serialize_deserialize(vote_plan: VotePlan) { let serialized = vote_plan.serialize(); let mut buf = ReadBuf::from(serialized.as_ref()); @@ -478,7 +522,7 @@ mod tests { let decoded = result.expect("can decode encoded vote plan"); - decoded == vote_plan + prop_assert_eq!(decoded, vote_plan); } #[test] diff --git a/chain-impl-mockchain/src/certificate/vote_tally.rs b/chain-impl-mockchain/src/certificate/vote_tally.rs index 0e8649a59..d2adf1b25 100644 --- a/chain-impl-mockchain/src/certificate/vote_tally.rs +++ b/chain-impl-mockchain/src/certificate/vote_tally.rs @@ -15,8 +15,16 @@ use chain_vote::TallyDecryptShare; use typed_bytes::{ByteArray, ByteBuilder}; #[derive(Debug, Eq, PartialEq, Hash, Clone)] +#[cfg_attr( + any(test, feature = "property-test-api"), + derive(test_strategy::Arbitrary) +)] pub struct VoteTally { id: VotePlanId, + #[cfg_attr( + any(test, feature = "property-test-api"), + strategy(proptest::strategy::Just(VoteTallyPayload::Public)) + )] payload: VoteTallyPayload, } @@ -27,6 +35,10 @@ pub enum VoteTallyPayload { } #[derive(Debug, Clone)] +#[cfg_attr( + any(test, feature = "property-test-api"), + derive(test_strategy::Arbitrary) +)] pub enum TallyProof { Public { id: CommitteeId, diff --git a/chain-impl-mockchain/src/chaineval.rs b/chain-impl-mockchain/src/chaineval.rs index 0241c9f7d..f35252c95 100644 --- a/chain-impl-mockchain/src/chaineval.rs +++ b/chain-impl-mockchain/src/chaineval.rs @@ -7,6 +7,10 @@ use crate::key::Hash; /// PraosNonce gathered per block #[derive(Debug, Clone, PartialEq, Eq)] +#[cfg_attr( + any(test, feature = "property-test-api"), + derive(test_strategy::Arbitrary) +)] pub struct PraosNonce([u8; 32]); impl PraosNonce { @@ -38,6 +42,10 @@ impl AsRef<[u8]> for PraosNonce { /// Consensus related data extract from the header #[derive(Debug, Clone)] +#[cfg_attr( + any(test, feature = "property-test-api"), + derive(test_strategy::Arbitrary) +)] pub enum ConsensusEvalContext { Genesis, Bft, @@ -49,6 +57,10 @@ pub enum ConsensusEvalContext { /// This is the data extracted from a header related to content evaluation #[derive(Debug, Clone)] +#[cfg_attr( + any(test, feature = "property-test-api"), + derive(test_strategy::Arbitrary) +)] pub struct HeaderContentEvalContext { pub(crate) block_date: BlockDate, pub(crate) chain_length: ChainLength, diff --git a/chain-impl-mockchain/src/chaintypes.rs b/chain-impl-mockchain/src/chaintypes.rs index 38f731577..077bff6e6 100644 --- a/chain-impl-mockchain/src/chaintypes.rs +++ b/chain-impl-mockchain/src/chaintypes.rs @@ -9,6 +9,10 @@ use strum_macros::{Display, EnumString, IntoStaticStr}; pub type HeaderId = Hash; // TODO: change to DigestOf #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[cfg_attr( + any(test, feature = "property-test-api"), + derive(test_strategy::Arbitrary) +)] pub struct ChainLength(pub(crate) u32); impl From for ChainLength { @@ -46,6 +50,10 @@ impl std::fmt::Display for ChainLength { #[derive( Debug, Clone, Copy, Display, EnumString, IntoStaticStr, PartialEq, Eq, PartialOrd, Ord, Hash, )] +#[cfg_attr( + any(test, feature = "property-test-api"), + derive(test_strategy::Arbitrary) +)] pub enum ConsensusType { #[strum(to_string = "bft")] Bft = 1, diff --git a/chain-impl-mockchain/src/config.rs b/chain-impl-mockchain/src/config.rs index c760f173f..d4f7e8c76 100644 --- a/chain-impl-mockchain/src/config.rs +++ b/chain-impl-mockchain/src/config.rs @@ -56,6 +56,10 @@ impl From for ReadError { } #[derive(Clone, Debug, Eq, PartialEq)] +#[cfg_attr( + any(test, feature = "property-test-api"), + derive(test_strategy::Arbitrary) +)] pub enum ConfigParam { Block0Date(Block0Date), Discrimination(Discrimination), @@ -78,7 +82,10 @@ pub enum ConfigParam { FeesInTreasury(bool), RewardLimitNone, RewardLimitByAbsoluteStake(Ratio), - PoolRewardParticipationCapping((NonZeroU32, NonZeroU32)), + PoolRewardParticipationCapping( + #[cfg_attr(any(test, feature = "property-test-api"), strategy((crate::testing::strategy::non_zero_u32(), crate::testing::strategy::non_zero_u32())))] + (NonZeroU32, NonZeroU32), + ), AddCommitteeId(CommitteeId), RemoveCommitteeId(CommitteeId), PerVoteCertificateFees(PerVoteCertificateFee), @@ -86,17 +93,23 @@ pub enum ConfigParam { } #[derive(Clone, Debug, Eq, PartialEq)] +#[cfg_attr( + any(test, feature = "property-test-api"), + derive(test_strategy::Arbitrary) +)] pub enum RewardParams { Linear { constant: u64, ratio: Ratio, epoch_start: Epoch, + #[cfg_attr(any(test, feature = "property-test-api"), strategy(proptest::strategy::Just(NonZeroU32::new(20).unwrap())))] epoch_rate: NonZeroU32, }, Halving { constant: u64, ratio: Ratio, epoch_start: Epoch, + #[cfg_attr(any(test, feature = "property-test-api"), strategy(proptest::strategy::Just(NonZeroU32::new(20).unwrap())))] epoch_rate: NonZeroU32, }, } @@ -390,6 +403,10 @@ trait ConfigParamVariant: Clone + Eq + PartialEq { /// Seconds elapsed since 1-Jan-1970 (unix time) #[derive(Debug, Clone, Copy, Eq, PartialEq)] +#[cfg_attr( + any(test, feature = "property-test-api"), + derive(test_strategy::Arbitrary) +)] pub struct Block0Date(pub u64); impl ConfigParamVariant for Block0Date { diff --git a/chain-impl-mockchain/src/date.rs b/chain-impl-mockchain/src/date.rs index b91e712c2..f1b9a88c6 100644 --- a/chain-impl-mockchain/src/date.rs +++ b/chain-impl-mockchain/src/date.rs @@ -8,6 +8,10 @@ use std::{error, fmt, num::ParseIntError, str}; /// blockchain. There may be many transactions related to the same /// `SlotId`. #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[cfg_attr( + any(test, feature = "property-test-api"), + derive(test_strategy::Arbitrary) +)] pub struct BlockDate { pub epoch: Epoch, pub slot_id: SlotId, diff --git a/chain-impl-mockchain/src/fee.rs b/chain-impl-mockchain/src/fee.rs index 19a388306..5daee30d3 100644 --- a/chain-impl-mockchain/src/fee.rs +++ b/chain-impl-mockchain/src/fee.rs @@ -3,9 +3,16 @@ use crate::transaction as tx; use crate::value::Value; use std::num::NonZeroU64; +#[cfg(any(test, feature = "property-test-api"))] +use crate::testing::strategy::optional_non_zero_u64; + /// Linear fee using the basic affine formula /// `COEFFICIENT * bytes(COUNT(tx.inputs) + COUNT(tx.outputs)) + CONSTANT + CERTIFICATE*COUNT(certificates)`. #[derive(PartialEq, Eq, PartialOrd, Debug, Clone, Copy)] +#[cfg_attr( + any(test, feature = "property-test-api"), + derive(test_strategy::Arbitrary) +)] pub struct LinearFee { pub constant: u64, pub coefficient: u64, @@ -15,15 +22,43 @@ pub struct LinearFee { } #[derive(PartialEq, Eq, PartialOrd, Debug, Clone, Copy, Default)] +#[cfg_attr( + any(test, feature = "property-test-api"), + derive(test_strategy::Arbitrary) +)] pub struct PerCertificateFee { + #[cfg_attr( + any(test, feature = "property-test-api"), + strategy(optional_non_zero_u64()) + )] pub certificate_pool_registration: Option, + #[cfg_attr( + any(test, feature = "property-test-api"), + strategy(optional_non_zero_u64()) + )] pub certificate_stake_delegation: Option, + #[cfg_attr( + any(test, feature = "property-test-api"), + strategy(optional_non_zero_u64()) + )] pub certificate_owner_stake_delegation: Option, } #[derive(PartialEq, Eq, PartialOrd, Debug, Clone, Copy, Default)] +#[cfg_attr( + any(test, feature = "property-test-api"), + derive(test_strategy::Arbitrary) +)] pub struct PerVoteCertificateFee { + #[cfg_attr( + any(test, feature = "property-test-api"), + strategy(optional_non_zero_u64()) + )] pub certificate_vote_plan: Option, + #[cfg_attr( + any(test, feature = "property-test-api"), + strategy(optional_non_zero_u64()) + )] pub certificate_vote_cast: Option, } @@ -142,10 +177,11 @@ mod test { use super::*; #[cfg(test)] use crate::certificate::{Certificate, CertificatePayload}; + use proptest::prelude::*; #[cfg(test)] use quickcheck::TestResult; use quickcheck::{Arbitrary, Gen}; - use quickcheck_macros::quickcheck; + use test_strategy::proptest; impl Arbitrary for PerCertificateFee { fn arbitrary(g: &mut G) -> Self { @@ -178,28 +214,29 @@ mod test { } } - #[quickcheck] - pub fn linear_fee_certificate_calculation( + #[proptest] + fn linear_fee_certificate_calculation( certificate: Certificate, inputs: u8, outputs: u8, mut fee: LinearFee, per_certificate_fees: PerCertificateFee, per_vote_certificate_fees: PerVoteCertificateFee, - ) -> TestResult { + ) { + // TODO test-strategy needs to be fixed, it removes mut modifier from argument bindings + let mut fee = fee; fee.per_certificate_fees(per_certificate_fees); fee.per_vote_certificate_fees(per_vote_certificate_fees); let per_certificate_fees = fee.per_certificate_fees; - if per_certificate_fees.certificate_pool_registration.is_none() - || per_certificate_fees.certificate_stake_delegation.is_none() - || per_certificate_fees - .certificate_owner_stake_delegation - .is_none() - || per_vote_certificate_fees.certificate_vote_plan.is_none() - || per_vote_certificate_fees.certificate_vote_cast.is_none() - { - return TestResult::discard(); - } + prop_assume!( + per_certificate_fees.certificate_pool_registration.is_some() + && per_certificate_fees.certificate_stake_delegation.is_some() + && per_certificate_fees + .certificate_owner_stake_delegation + .is_some() + && per_vote_certificate_fees.certificate_vote_plan.is_some() + && per_vote_certificate_fees.certificate_vote_cast.is_some() + ); let certificate_payload: CertificatePayload = (&certificate).into(); let fee_value = fee.calculate(Some(certificate_payload.as_slice()), inputs, outputs); @@ -210,11 +247,7 @@ mod test { + fee.constant, ); - if fee_value == expected_value { - TestResult::passed() - } else { - TestResult::error(format!("Wrong fee: {} vs {}", fee_value, expected_value)) - } + prop_assert_eq!(fee_value, expected_value); } #[cfg(test)] diff --git a/chain-impl-mockchain/src/fragment/config.rs b/chain-impl-mockchain/src/fragment/config.rs index fb583b37d..bed40d6ef 100644 --- a/chain-impl-mockchain/src/fragment/config.rs +++ b/chain-impl-mockchain/src/fragment/config.rs @@ -3,7 +3,14 @@ use chain_core::mempack::{ReadBuf, ReadError, Readable}; use chain_core::property; #[derive(Debug, Clone, PartialEq, Eq, Default)] -pub struct ConfigParams(pub(crate) Vec); +#[cfg_attr( + any(test, feature = "property-test-api"), + derive(test_strategy::Arbitrary) +)] +pub struct ConfigParams( + #[cfg_attr(any(test, feature = "property-test-api"), any(proptest::collection::size_range(..256).lift()))] + pub(crate) Vec, +); impl ConfigParams { pub fn new() -> Self { diff --git a/chain-impl-mockchain/src/fragment/content.rs b/chain-impl-mockchain/src/fragment/content.rs index 2c2516143..ba04027e4 100644 --- a/chain-impl-mockchain/src/fragment/content.rs +++ b/chain-impl-mockchain/src/fragment/content.rs @@ -6,11 +6,21 @@ use std::slice; pub type BlockContentHash = Hash; pub type BlockContentSize = u32; +#[cfg(any(test, feature = "property-test-api"))] +use proptest::{collection::vec, prelude::*}; + /// Block Contents /// /// To create this structure, make a ContentsBuilder and use into() #[derive(Debug, Clone)] -pub struct Contents(pub(super) Box<[Fragment]>); +#[cfg_attr( + any(test, feature = "property-test-api"), + derive(test_strategy::Arbitrary) +)] +pub struct Contents( + #[cfg_attr(any(test, feature = "property-test-api"), strategy(vec(any::(), ..12).prop_map(|vec| vec.into_boxed_slice())))] + pub(super) Box<[Fragment]>, +); impl PartialEq for Contents { fn eq(&self, rhs: &Self) -> bool { diff --git a/chain-impl-mockchain/src/fragment/mod.rs b/chain-impl-mockchain/src/fragment/mod.rs index af5d442ff..b51151461 100644 --- a/chain-impl-mockchain/src/fragment/mod.rs +++ b/chain-impl-mockchain/src/fragment/mod.rs @@ -28,6 +28,10 @@ pub(super) type MessageTag = FragmentTag; /// All possible messages recordable in the content #[derive(Debug, Clone)] +#[cfg_attr( + any(test, feature = "property-test-api"), + derive(test_strategy::Arbitrary) +)] pub enum Fragment { Initial(ConfigParams), OldUtxoDeclaration(legacy::UtxoDeclaration), diff --git a/chain-impl-mockchain/src/fragment/test.rs b/chain-impl-mockchain/src/fragment/test.rs index 49f5368b6..68a691260 100644 --- a/chain-impl-mockchain/src/fragment/test.rs +++ b/chain-impl-mockchain/src/fragment/test.rs @@ -2,10 +2,11 @@ use super::*; use crate::config::ConfigParam; #[cfg(test)] use crate::testing::serialization::{serialization_bijection, serialization_bijection_r}; +use proptest::prelude::*; #[cfg(test)] use quickcheck::TestResult; use quickcheck::{Arbitrary, Gen}; -use quickcheck_macros::quickcheck; +use test_strategy::proptest; impl Arbitrary for Fragment { fn arbitrary(g: &mut G) -> Self { @@ -29,21 +30,20 @@ impl Arbitrary for Fragment { } } -#[quickcheck] -fn fragment_raw_bijection(b: Fragment) -> TestResult { +#[proptest] +fn fragment_raw_bijection(b: Fragment) { let b_got = Fragment::from_raw(&b.to_raw()).unwrap(); - TestResult::from_bool(b == b_got) + prop_assert_eq!(b, b_got); } -#[quickcheck] -fn fragment_serialization_bijection(b: Fragment) -> TestResult { - serialization_bijection(b) +#[proptest] +fn fragment_serialization_bijection(b: Fragment) { + serialization_bijection(b); } -quickcheck! { - fn initial_ents_serialization_bijection(config_params: ConfigParams) -> TestResult { - serialization_bijection_r(config_params) - } +#[proptest] +fn initial_ents_serialization_bijection(config_params: ConfigParams) { + serialization_bijection_r(config_params) } impl Arbitrary for ConfigParams { diff --git a/chain-impl-mockchain/src/header/deconstruct.rs b/chain-impl-mockchain/src/header/deconstruct.rs index 772a263cd..36f38278b 100644 --- a/chain-impl-mockchain/src/header/deconstruct.rs +++ b/chain-impl-mockchain/src/header/deconstruct.rs @@ -7,6 +7,10 @@ use crate::fragment::{BlockContentHash, BlockContentSize}; use crate::key::BftLeaderId; #[derive(Debug, Clone, PartialEq, Eq)] +#[cfg_attr( + any(test, feature = "property-test-api"), + derive(test_strategy::Arbitrary) +)] pub struct Common { pub block_version: BlockVersion, pub block_date: BlockDate, diff --git a/chain-impl-mockchain/src/header/test.rs b/chain-impl-mockchain/src/header/test.rs index dedb6507b..49169c2fa 100644 --- a/chain-impl-mockchain/src/header/test.rs +++ b/chain-impl-mockchain/src/header/test.rs @@ -1,4 +1,5 @@ use super::*; +use crate::block::BlockContentHash; use crate::chaintypes::ChainLength; use crate::header::{BftProof, BftSignature, Common, GenesisPraosProof, KesSignature}; use crate::key::BftLeaderId; @@ -9,14 +10,15 @@ use chain_crypto::{ VerifiableRandomFunction, }; use lazy_static::lazy_static; +use proptest::prelude::*; #[cfg(test)] use quickcheck::TestResult; use quickcheck::{Arbitrary, Gen}; +use test_strategy::proptest; -quickcheck! { - fn header_serialization_bijection(b: Header) -> TestResult { - serialization_bijection_r(b) - } +#[proptest] +fn header_serialization_bijection(b: Header) { + serialization_bijection_r(b) } impl Arbitrary for BlockVersion { @@ -55,6 +57,25 @@ impl Arbitrary for BftProof { } } } + +impl proptest::arbitrary::Arbitrary for BftProof { + type Parameters = (); + type Strategy = BoxedStrategy; + + fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { + any::>() + .prop_map(|sk| { + let pk = sk.to_public(); + let signature = sk.sign(&[0u8, 1, 2, 3]); + BftProof { + leader_id: BftLeaderId(pk), + signature: BftSignature(signature.coerce()), + } + }) + .boxed() + } +} + impl Arbitrary for GenesisPraosProof { fn arbitrary(g: &mut G) -> Self { use chain_crypto::testing; @@ -83,6 +104,43 @@ impl Arbitrary for GenesisPraosProof { } } +impl proptest::arbitrary::Arbitrary for GenesisPraosProof { + type Parameters = (); + type Strategy = BoxedStrategy; + + fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { + use crate::certificate::PoolId; + + ( + any::(), + any::(), + ) + .prop_map(|(tcg, node_id)| { + let vrf_proof = { + let sk = RistrettoGroup2HashDh::generate(&mut tcg.get_rng(0)); + RistrettoGroup2HashDh::evaluate_and_prove( + &sk, + &[0, 1, 2, 3], + &mut tcg.get_rng(1), + ) + }; + + let kes_proof = { + let sk = SecretKey::::generate(&mut tcg.get_rng(3)); + let signature = sk.sign(&[0u8, 1, 2, 3]); + KesSignature(signature.coerce()) + }; + + Self { + node_id, + vrf_proof: vrf_proof.into(), + kes_proof, + } + }) + .boxed() + } +} + impl Arbitrary for Header { fn arbitrary(g: &mut G) -> Self { let common = Common::arbitrary(g); @@ -116,3 +174,68 @@ impl Arbitrary for Header { } } } + +impl proptest::arbitrary::Arbitrary for Header { + type Parameters = (); + type Strategy = BoxedStrategy; + + fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { + any::<(BlockContentHash, u32)>() + .prop_flat_map(|(content_hash, content_size)| { + header_strategy(content_hash, content_size) + }) + .boxed() + } +} + +pub fn header_strategy( + content_hash: BlockContentHash, + content_size: u32, +) -> impl Strategy { + #[derive(Debug, Clone)] + enum Proof { + Genesis, + Ed25519Signed(BftProof), + KesVrfproof(GenesisPraosProof), + } + + ( + any::(), + any::(), + any::(), + any::(), + ) + .prop_flat_map(move |(ver, parent_hash, chain_length, date)| { + let proof_strategy = match ver { + BlockVersion::Genesis => Just(Proof::Genesis).boxed(), + BlockVersion::Ed25519Signed => { + any::().prop_map(Proof::Ed25519Signed).boxed() + } + BlockVersion::KesVrfproof => any::() + .prop_map(Proof::KesVrfproof) + .boxed(), + }; + + proof_strategy.prop_map(move |proof| { + let hdrbuilder = HeaderBuilderNew::new_raw(ver, &content_hash, content_size) + .set_parent(&parent_hash, chain_length) + .set_date(date); + + match proof { + Proof::Genesis => hdrbuilder.into_unsigned_header().unwrap().generalize(), + Proof::Ed25519Signed(bft_proof) => hdrbuilder + .into_bft_builder() + .unwrap() + .set_consensus_data(&bft_proof.leader_id) + .set_signature(bft_proof.signature) + .generalize(), + Proof::KesVrfproof(gp_proof) => hdrbuilder + .into_genesis_praos_builder() + .unwrap() + .set_consensus_data(&gp_proof.node_id, &gp_proof.vrf_proof) + .set_signature(gp_proof.kes_proof) + .generalize(), + } + }) + }) +} diff --git a/chain-impl-mockchain/src/header/version.rs b/chain-impl-mockchain/src/header/version.rs index 0bcd2701d..0c5610a8e 100644 --- a/chain-impl-mockchain/src/header/version.rs +++ b/chain-impl-mockchain/src/header/version.rs @@ -3,6 +3,10 @@ use crate::chaintypes::ConsensusType; use std::num::NonZeroUsize; #[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[cfg_attr( + any(test, feature = "property-test-api"), + derive(test_strategy::Arbitrary) +)] pub enum AnyBlockVersion { Supported(BlockVersion), Unsupported(u16), @@ -51,6 +55,10 @@ impl From for AnyBlockVersion { } #[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[cfg_attr( + any(test, feature = "property-test-api"), + derive(test_strategy::Arbitrary) +)] pub enum BlockVersion { Genesis, Ed25519Signed, @@ -107,8 +115,9 @@ mod tests { use crate::chaintypes::ConsensusType; use crate::header::{AnyBlockVersion, BlockVersion}; + use proptest::prelude::*; use quickcheck::TestResult; - use quickcheck_macros::quickcheck; + use test_strategy::proptest; #[test] pub fn try_into_block_version() { @@ -149,18 +158,18 @@ mod tests { assert!(AnyBlockVersion::Unsupported(0) != BlockVersion::KesVrfproof); } - #[quickcheck] - pub fn conversion_u16(block_version: AnyBlockVersion) -> TestResult { + #[proptest] + fn conversion_u16(block_version: AnyBlockVersion) { let bytes: u16 = block_version.clone().into(); let new_block_version: AnyBlockVersion = AnyBlockVersion::from(bytes); - TestResult::from_bool(block_version == new_block_version) + prop_assert_eq!(block_version, new_block_version); } - #[quickcheck] - pub fn from_block_version(block_version: BlockVersion) -> TestResult { + #[proptest] + fn from_block_version(block_version: BlockVersion) { let right_version = AnyBlockVersion::Supported(block_version); let left_version: AnyBlockVersion = block_version.into(); - TestResult::from_bool(left_version == right_version) + prop_assert_eq!(left_version, right_version); } #[test] diff --git a/chain-impl-mockchain/src/key.rs b/chain-impl-mockchain/src/key.rs index d4cb2f67a..923a603d6 100644 --- a/chain-impl-mockchain/src/key.rs +++ b/chain-impl-mockchain/src/key.rs @@ -14,7 +14,14 @@ use typed_bytes::ByteBuilder; use chain_core::packer::Codec; use std::str::FromStr; -#[derive(Clone)] +#[cfg(any(test, feature = "property-test-api"))] +use chain_crypto::testing::public_key_strategy; + +#[derive(Debug, Clone)] +#[cfg_attr( + any(test, feature = "property-test-api"), + derive(test_strategy::Arbitrary) +)] pub enum EitherEd25519SecretKey { Extended(crypto::SecretKey), Normal(crypto::SecretKey), @@ -218,6 +225,10 @@ impl Clone for Signed { /// Hash that is used as an address of the various components. #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[cfg_attr( + any(test, feature = "property-test-api"), + derive(test_strategy::Arbitrary) +)] pub struct Hash(crypto::Blake2b256); impl Hash { /// All 0 hash used as a special hash @@ -315,7 +326,14 @@ impl FromStr for Hash { pub type BftVerificationAlg = Ed25519; #[derive(Debug, Clone, PartialEq, Eq, Hash)] -pub struct BftLeaderId(pub(crate) PublicKey); +#[cfg_attr( + any(test, feature = "property-test-api"), + derive(test_strategy::Arbitrary) +)] +pub struct BftLeaderId( + #[cfg_attr(any(test, feature = "property-test-api"), strategy(chain_crypto::testing::public_key_strategy::()))] + pub(crate) PublicKey, +); impl From<[u8; 32]> for BftLeaderId { fn from(v: [u8; 32]) -> BftLeaderId { @@ -373,8 +391,14 @@ impl From> for BftLeaderId { /// Praos Leader consisting of the KES public key and VRF public key #[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[cfg_attr( + any(test, feature = "property-test-api"), + derive(test_strategy::Arbitrary) +)] pub struct GenesisPraosLeader { + #[cfg_attr(any(test, feature = "property-test-api"), strategy(public_key_strategy::()))] pub kes_public_key: PublicKey, + #[cfg_attr(any(test, feature = "property-test-api"), strategy(public_key_strategy::()))] pub vrf_public_key: PublicKey, } @@ -411,6 +435,7 @@ mod tests { #[cfg(test)] use quickcheck::TestResult; use quickcheck::{quickcheck, Arbitrary, Gen}; + use test_strategy::proptest; impl Arbitrary for Hash { fn arbitrary(g: &mut G) -> Self { @@ -443,9 +468,8 @@ mod tests { } } - quickcheck! { - fn leader_id_serialize_deserialize_biyection(leader_id: BftLeaderId) -> TestResult { - serialization_bijection(leader_id) - } + #[proptest] + fn leader_id_serialize_deserialize_biyection(leader_id: BftLeaderId) { + serialization_bijection(leader_id) } } diff --git a/chain-impl-mockchain/src/ledger/check.rs b/chain-impl-mockchain/src/ledger/check.rs index acc960af1..2014e0910 100644 --- a/chain-impl-mockchain/src/ledger/check.rs +++ b/chain-impl-mockchain/src/ledger/check.rs @@ -195,45 +195,38 @@ pub fn valid_transaction_date( #[cfg(test)] mod tests { - use super::*; use quickcheck::TestResult; - use quickcheck_macros::quickcheck; + use test_strategy::proptest; - fn test_valid_block0_transaction_no_inputs_for(tx: Transaction

) -> TestResult { + fn test_valid_block0_transaction_no_inputs_for(tx: Transaction

) { let has_valid_inputs = tx.nb_inputs() == 0 && tx.nb_witnesses() == 0; let result = valid_block0_transaction_no_inputs(&tx.as_slice()); to_quickchek_result(result, has_valid_inputs) } - #[quickcheck] - pub fn test_valid_block0_transaction_no_inputs( - tx: Transaction, - ) -> TestResult { + #[proptest] + fn test_valid_block0_transaction_no_inputs(tx: Transaction) { test_valid_block0_transaction_no_inputs_for(tx) } - #[quickcheck] - pub fn test_valid_block0_transaction_outputs( - tx: Transaction, - ) -> TestResult { + #[proptest] + fn test_valid_block0_transaction_outputs(tx: Transaction) { let has_valid_ios = tx.nb_inputs() == 0 && tx.nb_outputs() == 0; let result = valid_block0_cert_transaction(&tx.as_slice()); to_quickchek_result(result, has_valid_ios) } - #[quickcheck] - pub fn test_valid_output_value(output: Output

) -> TestResult { + #[proptest] + fn test_valid_output_value(output: Output
) { let is_valid_output = output.value != Value::zero(); let result = valid_output_value(&output); to_quickchek_result(result, is_valid_output) } - #[quickcheck] - pub fn test_valid_pool_registration_certificate( - pool_registration: certificate::PoolRegistration, - ) -> TestResult { + #[proptest] + fn test_valid_pool_registration_certificate(pool_registration: certificate::PoolRegistration) { let is_valid = pool_registration.management_threshold() > 0 && (pool_registration.management_threshold() as usize) <= pool_registration.owners.len() @@ -243,26 +236,26 @@ mod tests { to_quickchek_result(result, is_valid) } - #[quickcheck] - pub fn test_valid_stake_owner_delegation_transaction( + #[proptest] + fn test_valid_stake_owner_delegation_transaction( tx: Transaction, - ) -> TestResult { + ) { let is_valid = tx.nb_witnesses() == 1 && tx.nb_inputs() == 1 && tx.nb_outputs() == 0; let result = valid_stake_owner_delegation_transaction(&tx.as_slice()); to_quickchek_result(result, is_valid) } /* - #[quickcheck] - pub fn test_valid_pool_retirement_certificate( + #[proptest] + fn test_valid_pool_retirement_certificate( cert: certificate::PoolOwnersSigned, ) -> TestResult { let is_valid = cert.signatures.len() > 0 && cert.signatures.len() < 256; let result = valid_pool_retirement_certificate(&cert); to_quickchek_result(result, is_valid) } - #[quickcheck] - pub fn test_valid_pool_update_certificate( + #[proptest] + fn test_valid_pool_update_certificate( cert: certificate::PoolOwnersSigned, ) -> TestResult { let is_valid = cert.signatures.len() > 0 && cert.signatures.len() < 256; @@ -271,12 +264,12 @@ mod tests { } */ - fn to_quickchek_result(result: LedgerCheck, should_succeed: bool) -> TestResult { - match (result, should_succeed) { - (Ok(_), true) => TestResult::passed(), - (Ok(_), false) => TestResult::failed(), - (Err(_), true) => TestResult::failed(), - (Err(_), false) => TestResult::passed(), + fn to_quickchek_result(result: LedgerCheck, should_succeed: bool) { + match (&result, should_succeed) { + (Ok(_), true) => {} + (Ok(_), false) => panic!("should fail"), + (Err(_), true) => result.unwrap(), + (Err(_), false) => {} } } } diff --git a/chain-impl-mockchain/src/ledger/governance/parameters.rs b/chain-impl-mockchain/src/ledger/governance/parameters.rs index d1c8ffb4d..7774f2af6 100644 --- a/chain-impl-mockchain/src/ledger/governance/parameters.rs +++ b/chain-impl-mockchain/src/ledger/governance/parameters.rs @@ -5,12 +5,20 @@ use std::collections::hash_map::DefaultHasher; use typed_bytes::ByteBuilder; #[derive(Debug, Clone, Eq, PartialEq)] +#[cfg_attr( + any(test, feature = "property-test-api"), + derive(test_strategy::Arbitrary) +)] pub enum ParametersGovernanceAction { NoOp, RewardAdd { value: Value }, } #[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] +#[cfg_attr( + any(test, feature = "property-test-api"), + derive(test_strategy::Arbitrary) +)] pub enum ParametersGovernanceActionType { NoOp, RewardAdd, @@ -117,11 +125,10 @@ impl Readable for ParametersGovernanceAction { #[cfg(test)] mod tests { - use super::{ParametersGovernance, ParametersGovernanceAction, ParametersGovernanceActionType}; use crate::{ledger::governance::GovernanceAcceptanceCriteria, value::Value, vote::Choice}; use quickcheck::{Arbitrary, Gen}; - use quickcheck_macros::quickcheck; + use test_strategy::proptest; impl Arbitrary for ParametersGovernanceActionType { fn arbitrary(g: &mut G) -> Self { @@ -168,10 +175,8 @@ mod tests { ); } - #[quickcheck] - pub fn parameters_governance_set_acceptance_criteria( - action_type: ParametersGovernanceActionType, - ) { + #[proptest] + fn parameters_governance_set_acceptance_criteria(action_type: ParametersGovernanceActionType) { let mut governance = ParametersGovernance::new(); let new_governance_criteria = some_new_governance_criteria(); governance.set_acceptance_criteria(action_type, new_governance_criteria.clone()); @@ -188,8 +193,8 @@ mod tests { new_governance_criteria } - #[quickcheck] - pub fn parameters_governance_logs(action_type: ParametersGovernanceAction) { + #[proptest] + fn parameters_governance_logs(action_type: ParametersGovernanceAction) { let mut governance = ParametersGovernance::new(); governance.logs_register(action_type.clone()); assert!(governance.logs().any(|x| *x == action_type)); diff --git a/chain-impl-mockchain/src/ledger/governance/treasury.rs b/chain-impl-mockchain/src/ledger/governance/treasury.rs index 4f7cfa718..ee5f874cd 100644 --- a/chain-impl-mockchain/src/ledger/governance/treasury.rs +++ b/chain-impl-mockchain/src/ledger/governance/treasury.rs @@ -5,12 +5,20 @@ use std::collections::hash_map::DefaultHasher; use typed_bytes::ByteBuilder; #[derive(Debug, Clone, Eq, PartialEq)] +#[cfg_attr( + any(test, feature = "property-test-api"), + derive(test_strategy::Arbitrary) +)] pub enum TreasuryGovernanceAction { NoOp, TransferToRewards { value: Value }, } #[derive(Debug, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] +#[cfg_attr( + any(test, feature = "property-test-api"), + derive(test_strategy::Arbitrary) +)] pub enum TreasuryGovernanceActionType { NoOp, TransferToRewards, @@ -102,11 +110,10 @@ impl Readable for TreasuryGovernanceAction { #[cfg(test)] mod tests { - use super::{TreasuryGovernance, TreasuryGovernanceAction, TreasuryGovernanceActionType}; use crate::{ledger::governance::GovernanceAcceptanceCriteria, value::Value, vote::Choice}; use quickcheck::{Arbitrary, Gen}; - use quickcheck_macros::quickcheck; + use test_strategy::proptest; impl Arbitrary for TreasuryGovernanceActionType { fn arbitrary(g: &mut G) -> Self { @@ -142,8 +149,8 @@ mod tests { ); } - #[quickcheck] - pub fn treasury_governance_set_acceptance_criteria(action_type: TreasuryGovernanceActionType) { + #[proptest] + fn treasury_governance_set_acceptance_criteria(action_type: TreasuryGovernanceActionType) { let mut governance = TreasuryGovernance::new(); let new_governance_criteria = some_new_governance_criteria(); governance.set_acceptance_criteria(action_type, new_governance_criteria.clone()); diff --git a/chain-impl-mockchain/src/ledger/ledger.rs b/chain-impl-mockchain/src/ledger/ledger.rs index 11f434599..e21828323 100644 --- a/chain-impl-mockchain/src/ledger/ledger.rs +++ b/chain-impl-mockchain/src/ledger/ledger.rs @@ -41,6 +41,10 @@ use thiserror::Error; // static parameters, effectively this is constant in the parameter of the blockchain #[derive(Debug, Clone, PartialEq, Eq)] +#[cfg_attr( + any(test, feature = "property-test-api"), + derive(test_strategy::Arbitrary) +)] pub struct LedgerStaticParameters { pub block0_initial_hash: HeaderId, pub block0_start_time: config::Block0Date, @@ -1130,7 +1134,7 @@ impl Ledger { let value = self.pots.draw_treasury(value); self.pots.rewards_add(value)?; } - VoteAction::Parameters { action } => { + VoteAction::LedgerParameters { action } => { self.governance.parameters.logs_register(action); } } @@ -1717,9 +1721,10 @@ mod tests { transaction::Witness, }; use chain_addr::Discrimination; + use proptest::prelude::*; use quickcheck::{Arbitrary, Gen, TestResult}; - use quickcheck_macros::quickcheck; use std::{fmt, iter}; + use test_strategy::proptest; impl Arbitrary for LedgerStaticParameters { fn arbitrary(g: &mut G) -> Self { @@ -1765,6 +1770,23 @@ mod tests { } } + fn empty_ledger_strategy() -> impl Strategy { + any::<( + Settings, + LedgerStaticParameters, + TimeEra, + Pots, + BlockDate, + ChainLength, + )>() + .prop_map(|(settings, static_params, era, pots, date, chain_length)| { + let mut ledger = Ledger::empty(settings, static_params, era, pots); + ledger.date = date; + ledger.chain_length = chain_length; + ledger + }) + } + impl fmt::Debug for ArbitraryEmptyLedger { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("Ledger") @@ -1783,12 +1805,13 @@ mod tests { } } - #[quickcheck] - pub fn apply_empty_block_prop_test( + #[proptest] + fn apply_empty_block_prop_test( mut context: HeaderContentEvalContext, - ledger: ArbitraryEmptyLedger, - ) -> TestResult { - let ledger: Ledger = ledger.into(); + #[strategy(empty_ledger_strategy())] ledger: Ledger, + ) { + // TODO test-strategy needs to be fixed, it removes mut modifier from argument bindings + let mut context = context; let should_succeed = context.chain_length == ledger.chain_length.increase() && context.block_date > ledger.date; @@ -1797,10 +1820,10 @@ mod tests { let result = ledger.apply_block(ledger.get_ledger_parameters(), &contents, &context); match (result, should_succeed) { - (Ok(_), true) => TestResult::passed(), - (Ok(_), false) => TestResult::error("should pass"), - (Err(err), true) => TestResult::error(format!("unexpected error: {}", err)), - (Err(_), false) => TestResult::passed(), + (Ok(_), true) => {} + (Ok(_), false) => panic!("should pass"), + (Err(err), true) => panic!("unexpected error: {}", err), + (Err(_), false) => {} } } @@ -1846,32 +1869,29 @@ mod tests { TestTx::new(tx_builder.set_witnesses(&witnesses).set_payload_auth(&())) } - #[quickcheck] - pub fn match_identifier_witness_prop_test( - id: UnspecifiedAccountIdentifier, - witness: Witness, - ) -> TestResult { + #[proptest] + fn match_identifier_witness_prop_test(id: UnspecifiedAccountIdentifier, witness: Witness) { let result = super::match_identifier_witness(&id, &witness); match (witness.clone(), result) { - (Witness::OldUtxo(..), Ok(_)) => TestResult::error("expecting error, but got success"), - (Witness::OldUtxo(..), Err(_)) => TestResult::passed(), - (Witness::Utxo(_), Ok(_)) => TestResult::error("expecting error, but got success"), - (Witness::Utxo(_), Err(_)) => TestResult::passed(), - (Witness::Account(_), Ok(_)) => TestResult::passed(), - (Witness::Account(_), Err(_)) => TestResult::error("unexpected error"), - (Witness::Multisig(_), _) => TestResult::discard(), + (Witness::OldUtxo(..), Ok(_)) => panic!("expecting error, but got success"), + (Witness::OldUtxo(..), Err(_)) => {} + (Witness::Utxo(_), Ok(_)) => panic!("expecting error, but got success"), + (Witness::Utxo(_), Err(_)) => {} + (Witness::Account(_), Ok(_)) => {} + (Witness::Account(_), Err(_)) => panic!("unexpected error"), + (Witness::Multisig(_), _) => {} } } - #[quickcheck] - pub fn input_single_account_verify_negative_prop_test( + #[proptest] + fn input_single_account_verify_negative_prop_test( id: Identifier, account_state: AccountState<()>, value_to_sub: Value, block0_hash: HeaderId, sign_data_hash: TransactionSignDataHash, witness: account::Witness, - ) -> TestResult { + ) { let mut account_ledger = account::Ledger::new(); account_ledger = account_ledger .add_account(&id, account_state.get_value(), ()) @@ -1885,7 +1905,7 @@ mod tests { value_to_sub, ); - TestResult::from_bool(result.is_err()) + prop_assert!(result.is_err()); } #[test] @@ -2015,12 +2035,12 @@ mod tests { assert!(result.is_err()) } - #[quickcheck] - pub fn input_utxo_verify_negative_prop_test( + #[proptest] + fn input_utxo_verify_negative_prop_test( sign_data_hash: TransactionSignDataHash, utxo_pointer: UtxoPointer, witness: Witness, - ) -> TestResult { + ) { let faucet = AddressDataValue::utxo(Discrimination::Test, Value(1000)); let test_ledger = LedgerBuilder::from_config(ConfigBuilder::new()) .faucet(&faucet) @@ -2030,13 +2050,13 @@ mod tests { let inner_ledger: Ledger = test_ledger.into(); let result = inner_ledger.apply_input_to_utxo(&sign_data_hash, &utxo_pointer, &witness); match (witness, result) { - (Witness::OldUtxo(..), Ok(_)) => TestResult::error("expecting error, but got success"), - (Witness::OldUtxo(..), Err(_)) => TestResult::passed(), - (Witness::Utxo(_), Ok(_)) => TestResult::error("expecting error, but got success"), - (Witness::Utxo(_), Err(_)) => TestResult::passed(), - (Witness::Account(_), Ok(_)) => TestResult::error("expecting error, but got success"), - (Witness::Account(_), Err(_)) => TestResult::passed(), - (Witness::Multisig(_), _) => TestResult::discard(), + (Witness::OldUtxo(..), Ok(_)) => panic!("expecting error, but got success"), + (Witness::OldUtxo(..), Err(_)) => {} + (Witness::Utxo(_), Ok(_)) => panic!("expecting error, but got success"), + (Witness::Utxo(_), Err(_)) => {} + (Witness::Account(_), Ok(_)) => panic!("expecting error, but got success"), + (Witness::Account(_), Err(_)) => {} + (Witness::Multisig(_), _) => prop_assume!(false), } } @@ -2089,17 +2109,18 @@ mod tests { assert!(result.is_err()) } - #[quickcheck] - pub fn test_internal_apply_transaction_output_property( + #[proptest] + fn test_internal_apply_transaction_output_property( utxos: utxo::Ledger
, accounts: account::Ledger, static_params: LedgerStaticParameters, transaction_id: FragmentId, - arbitrary_outputs: ArbitraryAddressDataValueVec, - ) -> TestResult { + #[any(proptest::collection::size_range(1..=10).lift())] arbitrary_outputs: Vec< + AddressDataValue, + >, + ) { let multisig_ledger = multisig::Ledger::new(); let outputs: Vec> = arbitrary_outputs - .0 .iter() .map(|x| x.address_data.make_output(x.value)) .collect(); @@ -2112,10 +2133,10 @@ mod tests { should_expect_success(arbitrary_outputs, &static_params), result, ) { - (true, Ok(_)) => TestResult::passed(), - (true, Err(err)) => TestResult::error(format!("Unexpected failure: {:?}", err)), - (false, Ok(_)) => TestResult::error("Expected failure, but got sucess"), - (false, Err(_)) => TestResult::passed(), + (true, Ok(_)) => {} + (true, Err(err)) => panic!("Unexpected failure: {:?}", err), + (false, Ok(_)) => panic!("Expected failure, but got sucess"), + (false, Err(_)) => {} } } @@ -2149,15 +2170,13 @@ mod tests { } fn should_expect_success( - arbitrary_outputs: ArbitraryAddressDataValueVec, + arbitrary_outputs: Vec, static_params: &LedgerStaticParameters, ) -> bool { let is_any_address_different_than_ledger_disc = arbitrary_outputs - .0 .iter() .any(|x| x.address_data.discrimination() != static_params.discrimination); - let is_any_address_zero_output = - arbitrary_outputs.0.iter().any(|x| x.value == Value::zero()); + let is_any_address_zero_output = arbitrary_outputs.iter().any(|x| x.value == Value::zero()); !is_any_address_different_than_ledger_disc && !is_any_address_zero_output } @@ -2533,19 +2552,21 @@ mod tests { .has_fee_equals_to(&Value(12)); } - #[quickcheck] - pub fn test_internal_apply_transaction_is_balanced( - input_addresses: ArbitraryAddressDataValueVec, - output_addresses: ArbitraryAddressDataValueVec, + #[proptest] + fn test_internal_apply_transaction_is_balanced( + #[any(proptest::collection::size_range(1..=10).lift())] input_addresses: Vec< + AddressDataValue, + >, + #[any(proptest::collection::size_range(1..=10).lift())] output_addresses: Vec< + AddressDataValue, + >, fee: Value, - ) -> TestResult { - if input_addresses.is_empty() || output_addresses.is_empty() { - return TestResult::discard(); - } + ) { + prop_assume!(!(input_addresses.is_empty() && output_addresses.is_empty())); let mut test_ledger = LedgerBuilder::from_config(ConfigBuilder::new().with_fee(LinearFee::new(fee.0, 0, 0))) - .faucets(&input_addresses.values()) + .faucets(&input_addresses) .build() .unwrap(); @@ -2554,17 +2575,25 @@ mod tests { .set_payload(&NoExtra) .set_expiry_date(BlockDate::first().next_epoch()) .set_ios( - &input_addresses.make_inputs(&test_ledger), - &output_addresses.make_outputs(), + &input_addresses + .iter() + .map(|x| { + let utxo = test_ledger.find_utxo_for_address(&x.clone().into()); + x.make_input(utxo) + }) + .collect::>(), + &output_addresses + .iter() + .map(|x| x.make_output()) + .collect::>(), ); let witnesses: Vec = input_addresses - .as_addresses() .iter() .map(|x| { make_witness( &block0_hash, - x, + &x.address_data, &tx_builder.get_auth_data_for_witness().hash(), ) }) @@ -2572,19 +2601,20 @@ mod tests { let test_tx = TestTx::new(tx_builder.set_witnesses(&witnesses).set_payload_auth(&())); - let balance_res = (input_addresses.total_value() - output_addresses.total_value()) - .and_then(|balance| balance - fee); + let balance_res = (Value::sum(input_addresses.iter().map(|input| input.value)).unwrap() + - Value::sum(output_addresses.iter().map(|output| output.value)).unwrap()) + .and_then(|balance| balance - fee); match ( balance_res, test_ledger.apply_transaction(test_tx.get_fragment(), BlockDate::first()), ) { - (Ok(balance), Ok(_)) => TestResult::from_bool(balance == Value::zero()), - (Err(err), Ok(_)) => TestResult::error(format!( + (Ok(balance), Ok(_)) => prop_assert_eq!(balance, Value::zero()), + (Err(err), Ok(_)) => panic!( "Expected balance is non zero {:?}, yet transaction is accepted", err - )), - (Ok(balance), Err(_)) => TestResult::from_bool(balance != Value::zero()), - (Err(_), Err(_)) => TestResult::passed(), + ), + (Ok(balance), Err(_)) => prop_assert_ne!(balance, Value::zero()), + (Err(_), Err(_)) => {} } } @@ -2638,8 +2668,8 @@ mod tests { .is_err()); } - #[quickcheck] - pub fn test_internal_apply_transaction_funds_were_transfered( + #[proptest] + fn test_internal_apply_transaction_funds_were_transfered( sender_address: AddressData, reciever_address: AddressData, ) { diff --git a/chain-impl-mockchain/src/ledger/pots.rs b/chain-impl-mockchain/src/ledger/pots.rs index a63bd4cbc..6988104bf 100644 --- a/chain-impl-mockchain/src/ledger/pots.rs +++ b/chain-impl-mockchain/src/ledger/pots.rs @@ -6,6 +6,10 @@ use std::fmt::Debug; /// Special pots of money #[derive(Clone, PartialEq, Eq, Debug)] +#[cfg_attr( + any(test, feature = "property-test-api"), + derive(test_strategy::Arbitrary) +)] pub struct Pots { pub(crate) fees: Value, pub(crate) treasury: Treasury, @@ -179,8 +183,9 @@ impl Pots { mod tests { use super::*; use crate::value::Value; + use proptest::prelude::*; use quickcheck::{Arbitrary, Gen, TestResult}; - use quickcheck_macros::quickcheck; + use test_strategy::proptest; impl Arbitrary for Pots { fn arbitrary(g: &mut G) -> Self { @@ -200,69 +205,75 @@ mod tests { assert_eq!(pots.rewards, Value::zero()); } - #[quickcheck] - pub fn entries(pots: Pots) -> TestResult { + #[proptest] + fn entries(pots: Pots) { for item in pots.entries() { match item { Entry::Fees(fees) => { - assert_eq!(pots.fees, fees); + prop_assert_eq!(pots.fees, fees); } Entry::Treasury(treasury) => { - assert_eq!(pots.treasury.value(), treasury); + prop_assert_eq!(pots.treasury.value(), treasury); } Entry::Rewards(rewards) => { - assert_eq!(pots.rewards, rewards); + prop_assert_eq!(pots.rewards, rewards); } } } - TestResult::passed() } - #[quickcheck] - pub fn append_fees(mut pots: Pots, value: Value) -> TestResult { - if (value + pots.fees).is_err() { - return TestResult::discard(); - } + #[proptest] + fn append_fees(mut pots: Pots, value: Value) { + // TODO test-strategy needs to be fixed, it removes mut modifier from argument bindings + let mut pots = pots; + prop_assume!((value + pots.fees).is_ok()); let before = pots.fees; pots.append_fees(value).unwrap(); - TestResult::from_bool((before + value).unwrap() == pots.fees) + prop_assert_eq!((before + value).unwrap(), pots.fees); } - #[quickcheck] - pub fn siphon_fees(mut pots: Pots) -> TestResult { + #[proptest] + fn siphon_fees(mut pots: Pots) { let before_siphon = pots.fees; + // TODO test-strategy needs to be fixed, it removes mut modifier from argument bindings + let mut pots = pots; let siphoned = pots.siphon_fees(); - if siphoned != before_siphon { - TestResult::error(format!("{} is not equal to {}", siphoned, before_siphon)); - } - TestResult::from_bool(pots.fees == Value::zero()) + prop_assert_eq!( + siphoned, + before_siphon, + "{} is not equal to {}", + siphoned, + before_siphon + ); + prop_assert_eq!(pots.fees, Value::zero()) } - #[quickcheck] - pub fn draw_reward(mut pots: Pots, expected_reward: Value) -> TestResult { - if (expected_reward + pots.rewards).is_err() { - return TestResult::discard(); - } - + #[proptest] + fn draw_reward(mut pots: Pots, expected_reward: Value) { + // TODO test-strategy needs to be fixed, it removes mut modifier from argument bindings + let mut pots = pots; + prop_assume!((expected_reward + pots.rewards).is_ok()); let before_reward = pots.rewards; let to_draw = pots.draw_reward(expected_reward); let draw_reward = cmp::min(before_reward, expected_reward); - if to_draw != draw_reward { - TestResult::error(format!( - "{} is not equal to smallest of pair({},{})", - to_draw, before_reward, expected_reward - )); - } - TestResult::from_bool(pots.rewards == (before_reward - to_draw).unwrap()) + prop_assert_eq!( + to_draw, + draw_reward, + "{} is not equal to smallest of pair({},{})", + to_draw, + before_reward, + expected_reward + ); + prop_assert_eq!(pots.rewards, (before_reward - to_draw).unwrap()) } - #[quickcheck] - pub fn treasury_add(mut pots: Pots, value: Value) -> TestResult { - if (value + pots.rewards).is_err() { - return TestResult::discard(); - } + #[proptest] + fn treasury_add(mut pots: Pots, value: Value) { + // TODO test-strategy needs to be fixed, it removes mut modifier from argument bindings + let mut pots = pots; + prop_assume!((value + pots.rewards).is_ok()); let before_add = pots.treasury.value(); pots.treasury_add(value).unwrap(); - TestResult::from_bool(pots.treasury.value() == (before_add + value).unwrap()) + prop_assert_eq!(pots.treasury.value(), (before_add + value).unwrap()); } } diff --git a/chain-impl-mockchain/src/ledger/tests/discrimination_tests.rs b/chain-impl-mockchain/src/ledger/tests/discrimination_tests.rs index 37bae2c7f..f23ebbdb9 100644 --- a/chain-impl-mockchain/src/ledger/tests/discrimination_tests.rs +++ b/chain-impl-mockchain/src/ledger/tests/discrimination_tests.rs @@ -3,28 +3,27 @@ use crate::{ date::BlockDate, testing::{ - arbitrary::KindTypeWithoutMultisig, builders::TestTxBuilder, data::AddressDataValue, ledger::{ConfigBuilder, LedgerBuilder}, + strategy::kind_type_without_multisig, }, value::Value, }; -use chain_addr::Discrimination; -use quickcheck::TestResult; -use quickcheck_macros::quickcheck; +use chain_addr::{Discrimination, KindType}; +use test_strategy::proptest; -#[quickcheck] -pub fn ledger_verifies_faucet_discrimination( +#[proptest] +fn ledger_verifies_faucet_discrimination( arbitrary_faucet_disc: Discrimination, - arbitrary_faucet_address_kind: KindTypeWithoutMultisig, + #[strategy(kind_type_without_multisig())] arbitrary_faucet_address_kind: KindType, arbitrary_ledger_disc: Discrimination, ) { let config = ConfigBuilder::new().with_discrimination(arbitrary_ledger_disc); let faucet = AddressDataValue::from_discrimination_and_kind_type( arbitrary_faucet_disc, - arbitrary_faucet_address_kind.0, + arbitrary_faucet_address_kind, Value(1000), ); @@ -34,32 +33,32 @@ pub fn ledger_verifies_faucet_discrimination( are_discriminations_unified, LedgerBuilder::from_config(config).faucet(&faucet).build(), ) { - (true, Ok(_)) => TestResult::passed(), + (true, Ok(_)) => {} (false, Ok(_)) => { - TestResult::error("Ledger should reject transaction with mixed discriminations") + panic!("Ledger should reject transaction with mixed discriminations") } (true, Err(_)) => { - TestResult::error("Ledger should accept transaction with unified discriminations") + panic!("Ledger should accept transaction with unified discriminations") } - (false, Err(_)) => TestResult::passed(), + (false, Err(_)) => {} }; } -#[quickcheck] -pub fn ledger_verifies_transaction_discrimination( +#[proptest] +fn ledger_verifies_transaction_discrimination( arbitrary_input_disc: Discrimination, arbitrary_output_disc: Discrimination, - arbitrary_input_address_kind: KindTypeWithoutMultisig, - arbitrary_output_address_kind: KindTypeWithoutMultisig, -) -> TestResult { + #[strategy(kind_type_without_multisig())] arbitrary_input_address_kind: KindType, + #[strategy(kind_type_without_multisig())] arbitrary_output_address_kind: KindType, +) { let faucet = AddressDataValue::from_discrimination_and_kind_type( arbitrary_input_disc, - arbitrary_input_address_kind.kind_type(), + arbitrary_input_address_kind, Value(100), ); let receiver = AddressDataValue::from_discrimination_and_kind_type( arbitrary_output_disc, - arbitrary_output_address_kind.kind_type(), + arbitrary_output_address_kind, Value(100), ); @@ -77,14 +76,14 @@ pub fn ledger_verifies_transaction_discrimination( let actual_result = ledger.apply_transaction(fragment, BlockDate::first()); match (are_discriminations_unified, actual_result) { - (true, Ok(_)) => TestResult::passed(), + (true, Ok(_)) => {} (false, Ok(_)) => { - TestResult::error("Ledger should reject transaction with mixed discriminations") + panic!("Ledger should reject transaction with mixed discriminations") } - (true, Err(err)) => TestResult::error(format!( + (true, Err(err)) => panic!( "Ledger should accept transaction with unified discriminations. Err: {}", err - )), - (false, Err(_)) => TestResult::passed(), + ), + (false, Err(_)) => {} } } diff --git a/chain-impl-mockchain/src/ledger/tests/initial_funds_tests.rs b/chain-impl-mockchain/src/ledger/tests/initial_funds_tests.rs index 909c711f4..1aa057230 100644 --- a/chain-impl-mockchain/src/ledger/tests/initial_funds_tests.rs +++ b/chain-impl-mockchain/src/ledger/tests/initial_funds_tests.rs @@ -6,7 +6,6 @@ use crate::{ accounting::account::DelegationType, ledger::{Block0Error, Error::Block0}, testing::{ - arbitrary::address::ArbitraryAddressDataValueVec, create_initial_stake_pool_owner_delegation, create_initial_transaction, data::AddressDataValue, data::Wallet, @@ -17,21 +16,18 @@ use crate::{ }; use chain_addr::Discrimination; use chain_core::property::Fragment as _; -use quickcheck::TestResult; -use quickcheck_macros::quickcheck; +use test_strategy::proptest; -#[quickcheck] -pub fn ledger_verifies_value_of_initial_funds( - arbitrary_faucets: ArbitraryAddressDataValueVec, -) -> TestResult { +#[proptest] +fn ledger_verifies_value_of_initial_funds( + #[any(proptest::collection::size_range(..10).lift())] arbitrary_faucets: Vec, +) { let config = ConfigBuilder::new().with_discrimination(Discrimination::Test); - TestResult::from_bool( - LedgerBuilder::from_config(config) - .initial_funds(&arbitrary_faucets.values()) - .build() - .is_ok(), - ) + LedgerBuilder::from_config(config) + .initial_funds(&arbitrary_faucets) + .build() + .unwrap(); } #[test] diff --git a/chain-impl-mockchain/src/ledger/tests/ledger_tests.rs b/chain-impl-mockchain/src/ledger/tests/ledger_tests.rs index db419cc79..c0a21ef5d 100644 --- a/chain-impl-mockchain/src/ledger/tests/ledger_tests.rs +++ b/chain-impl-mockchain/src/ledger/tests/ledger_tests.rs @@ -23,14 +23,11 @@ use crate::{ }; use chain_addr::Discrimination; -use quickcheck::TestResult; -use quickcheck_macros::quickcheck; - -#[quickcheck] -pub fn ledger_accepts_correct_transaction( - faucet: AddressDataValue, - receiver: AddressDataValue, -) -> TestResult { +use proptest::prelude::*; +use test_strategy::proptest; + +#[proptest] +fn ledger_accepts_correct_transaction(faucet: AddressDataValue, receiver: AddressDataValue) { let mut ledger = LedgerBuilder::from_config(ConfigBuilder::new()) .initial_fund(&faucet) .build() @@ -39,26 +36,17 @@ pub fn ledger_accepts_correct_transaction( .move_funds(&mut ledger, &faucet, &receiver, faucet.value) .get_fragment(); let total_funds_before = ledger.total_funds(); - let result = ledger.apply_transaction(fragment, BlockDate::first()); - if result.is_err() { - return TestResult::error(format!("Error from ledger: {}", result.err().unwrap())); - } + ledger + .apply_transaction(fragment, BlockDate::first()) + .unwrap(); + let total_funds_after = ledger.total_funds(); - if total_funds_before == total_funds_after { - TestResult::passed() - } else { - TestResult::error(format!( - "Total funds in ledger before and after transaction is not equal {} <> {} ", - total_funds_before, total_funds_after - )) - } + prop_assert_eq!(total_funds_before, total_funds_after); } -#[quickcheck] -pub fn total_funds_are_const_in_ledger( - transaction_data: ArbitraryValidTransactionData, -) -> TestResult { +#[proptest] +fn total_funds_are_const_in_ledger(transaction_data: ArbitraryValidTransactionData) { let config = ConfigBuilder::new() .with_discrimination(Discrimination::Test) .with_fee(transaction_data.fee); @@ -73,36 +61,23 @@ pub fn total_funds_are_const_in_ledger( &transaction_data.output_addresses, ); let total_funds_before = ledger.total_funds(); - let result = ledger.apply_transaction(signed_tx.get_fragment(), BlockDate::first()); - - if result.is_err() { - return TestResult::error(format!("Error from ledger: {:?}", result.err())); - } + ledger + .apply_transaction(signed_tx.get_fragment(), BlockDate::first()) + .unwrap(); let total_funds_after = ledger.total_funds(); - if total_funds_before != total_funds_after { - return TestResult::error(format!( - "Total funds in ledger before and after transaction is not equal {} <> {}", - total_funds_before, total_funds_after - )); - } + prop_assert_eq!( + total_funds_before, + total_funds_after, + "Total funds in ledger before and after transaction is not equal" + ); let utxo_verifier = UtxoVerifier::new(transaction_data.clone()); - let utxo_verification_result = utxo_verifier.verify(&ledger); - if utxo_verification_result.is_err() { - return TestResult::error(format!("{}", utxo_verification_result.err().unwrap())); - } + utxo_verifier.verify(&ledger).unwrap(); let account_state_verifier = AccountStatesVerifier::new(transaction_data); - let account_state_verification_result = account_state_verifier.verify(ledger.accounts()); - if account_state_verification_result.is_err() { - return TestResult::error(format!( - "{}", - account_state_verification_result.err().unwrap() - )); - } - TestResult::passed() + account_state_verifier.verify(ledger.accounts()).unwrap(); } #[test] @@ -366,16 +341,19 @@ pub fn ledger_new_no_bft_leader() { ); } -#[quickcheck] -pub fn wrong_fragment_at_block0(fragment: Fragment) -> TestResult { - match fragment { - Fragment::OldUtxoDeclaration(_) => return TestResult::discard(), - Fragment::Transaction(_) => return TestResult::discard(), - Fragment::StakeDelegation(_) => return TestResult::discard(), - Fragment::PoolRegistration(_) => return TestResult::discard(), - Fragment::VotePlan(_) => return TestResult::discard(), - _ => (), - }; +#[proptest] +fn wrong_fragment_at_block0(fragment: Fragment) { + fn filter_fragments(fragment: &Fragment) -> bool { + match fragment { + Fragment::OldUtxoDeclaration(_) => false, + Fragment::Transaction(_) => false, + Fragment::StakeDelegation(_) => false, + Fragment::PoolRegistration(_) => false, + Fragment::VotePlan(_) => false, + _ => true, + } + } + prop_assume!(filter_fragments(&fragment)); let header_id = TestGen::hash(); let mut ie = ConfigParams::new(); @@ -387,5 +365,5 @@ pub fn wrong_fragment_at_block0(fragment: Fragment) -> TestResult { ie.push(ConfigParam::SlotsPerEpoch(10u32)); ie.push(ConfigParam::KesUpdateSpeed(3600)); - TestResult::from_bool(Ledger::new(header_id, vec![&Fragment::Initial(ie), &fragment]).is_err()) + prop_assert!(Ledger::new(header_id, vec![&Fragment::Initial(ie), &fragment]).is_err()) } diff --git a/chain-impl-mockchain/src/ledger/tests/update_tests.rs b/chain-impl-mockchain/src/ledger/tests/update_tests.rs index 61c21e565..9a39cb883 100644 --- a/chain-impl-mockchain/src/ledger/tests/update_tests.rs +++ b/chain-impl-mockchain/src/ledger/tests/update_tests.rs @@ -9,13 +9,11 @@ use crate::{ testing::{ConfigBuilder, LedgerBuilder}, }; use chain_crypto::{Ed25519, SecretKey}; -use quickcheck::TestResult; -use quickcheck_macros::quickcheck; +use proptest::prelude::*; +use test_strategy::proptest; -#[quickcheck] -pub fn ledger_adopt_settings_from_update_proposal( - update_proposal_data: UpdateProposalData, -) -> TestResult { +#[proptest] +fn ledger_adopt_settings_from_update_proposal(update_proposal_data: UpdateProposalData) { let cb = ConfigBuilder::new().with_leaders(&update_proposal_data.leaders_ids()); let testledger = LedgerBuilder::from_config(cb) @@ -66,19 +64,14 @@ pub fn ledger_adopt_settings_from_update_proposal( } } - if !ledger.updates.proposals.is_empty() { - return TestResult::error(format!( - "Error: proposal collection should be empty but contains:{:?}", - ledger.updates.proposals - )); - } + prop_assert!( + ledger.updates.proposals.is_empty(), + "Error: proposal collection should be empty but contains:{:?}", + ledger.updates.proposals + ); - if all_settings_equal { - TestResult::passed() - } else { - TestResult::error(format!("Error: proposed update reached required votes, but proposal was NOT updated, Expected: {:?} vs Actual: {:?}", - expected_params,actual_params)) - } + prop_assert!(all_settings_equal, "Error: proposed update reached required votes, but proposal was NOT updated, Expected: {:?} vs Actual: {:?}", + expected_params,actual_params); } fn build_block( diff --git a/chain-impl-mockchain/src/legacy.rs b/chain-impl-mockchain/src/legacy.rs index 23cfad7e3..cc16cd076 100644 --- a/chain-impl-mockchain/src/legacy.rs +++ b/chain-impl-mockchain/src/legacy.rs @@ -8,7 +8,12 @@ use chain_core::property; use chain_crypto::{Ed25519, PublicKey}; #[derive(Debug, Clone, PartialEq, Eq)] +#[cfg_attr( + any(test, feature = "property-test-api"), + derive(test_strategy::Arbitrary) +)] pub struct UtxoDeclaration { + #[cfg_attr(any(test, feature = "property-test-api"), any(proptest::collection::size_range(..256).lift()))] pub addrs: Vec<(OldAddress, Value)>, } diff --git a/chain-impl-mockchain/src/milli.rs b/chain-impl-mockchain/src/milli.rs index 423354741..7e9ea8a94 100644 --- a/chain-impl-mockchain/src/milli.rs +++ b/chain-impl-mockchain/src/milli.rs @@ -4,6 +4,10 @@ use std::{fmt, iter}; const MILLI_MULTIPLIER: u64 = 1000; #[derive(Clone, Copy, Debug, Default, Eq, Ord, PartialEq, PartialOrd)] +#[cfg_attr( + any(test, feature = "property-test-api"), + derive(test_strategy::Arbitrary) +)] pub struct Milli(u64); impl Milli { diff --git a/chain-impl-mockchain/src/rewards.rs b/chain-impl-mockchain/src/rewards.rs index bb9071f96..c4a352cad 100644 --- a/chain-impl-mockchain/src/rewards.rs +++ b/chain-impl-mockchain/src/rewards.rs @@ -5,6 +5,9 @@ use chain_core::mempack::{ReadBuf, ReadError}; use std::num::{NonZeroU32, NonZeroU64}; use typed_bytes::ByteBuilder; +#[cfg(any(test, feature = "property-test-api"))] +use crate::testing::strategy; + #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum CompoundingType { Linear, @@ -12,8 +15,16 @@ pub enum CompoundingType { } #[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[cfg_attr( + any(test, feature = "property-test-api"), + derive(test_strategy::Arbitrary) +)] pub struct Ratio { pub numerator: u64, + #[cfg_attr( + any(test, feature = "property-test-api"), + strategy(strategy::non_zero_u64()) + )] pub denominator: NonZeroU64, } @@ -44,12 +55,20 @@ impl Ratio { } #[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[cfg_attr( + any(test, feature = "property-test-api"), + derive(test_strategy::Arbitrary) +)] pub struct TaxType { // what get subtracted as fixed value pub fixed: Value, // Ratio of tax after fixed amout subtracted pub ratio: Ratio, // Max limit of tax + #[cfg_attr( + any(test, feature = "property-test-api"), + strategy(strategy::optional_non_zero_u64()) + )] pub max_limit: Option, } @@ -270,26 +289,28 @@ pub fn tax_cut(v: Value, tax_type: &TaxType) -> Result TestResult { + #[proptest] + fn tax_cut_fully_accounted(v: Value, treasury_tax: TaxType) { match tax_cut(v, &treasury_tax) { Ok(td) => { let sum = (td.taxed + td.after_tax).unwrap(); - if sum == v { - TestResult::passed() - } else { - TestResult::error(format!( - "mismatch taxed={} remaining={} expected={} got={} for {:?}", - td.taxed, td.after_tax, v, sum, treasury_tax - )) - } + prop_assert_eq!( + sum, + v, + "mismatch taxed={} remaining={} expected={} got={} for {:?}", + td.taxed, + td.after_tax, + v, + sum, + treasury_tax + ); } - Err(_) => TestResult::discard(), + Err(_) => prop_assume!(false), } } diff --git a/chain-impl-mockchain/src/setting.rs b/chain-impl-mockchain/src/setting.rs index d50d92f1e..d6b3f58f5 100644 --- a/chain-impl-mockchain/src/setting.rs +++ b/chain-impl-mockchain/src/setting.rs @@ -336,6 +336,7 @@ impl Default for Settings { #[cfg(test)] mod tests { use super::{FeesGoesTo, Settings}; + use proptest::prelude::*; use quickcheck::{Arbitrary, Gen}; impl Arbitrary for FeesGoesTo { @@ -353,4 +354,13 @@ mod tests { Settings::new() } } + + impl proptest::arbitrary::Arbitrary for Settings { + type Parameters = (); + type Strategy = Just; + + fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { + Just(Self::new()) + } + } } diff --git a/chain-impl-mockchain/src/stake/controlled.rs b/chain-impl-mockchain/src/stake/controlled.rs index 33da059a1..1b760ca14 100644 --- a/chain-impl-mockchain/src/stake/controlled.rs +++ b/chain-impl-mockchain/src/stake/controlled.rs @@ -181,12 +181,18 @@ mod tests { use super::StakeControl; use crate::{ account::{self, Identifier}, + fragment::FragmentId, rewards::Ratio, stake::Stake, - testing::{utxo::ArbitaryLedgerUtxo, TestGen}, + testing::{data::AddressData, utxo::ArbitaryLedgerUtxo, TestGen}, + utxo::Ledger, + value::Value, }; - use quickcheck_macros::quickcheck; + use chain_addr::{Address, Discrimination}; + use proptest::prelude::*; + use proptest::{collection::hash_map, strategy::Strategy}; use std::num::NonZeroU64; + use test_strategy::proptest; fn create_stake_control_from( assigned: &[(Identifier, Stake)], @@ -413,12 +419,31 @@ mod tests { assert_eq!(stake_control.ratio_by(&second_identifier), expected_ratio); } - #[quickcheck] - pub fn stake_control_from_ledger(accounts: account::Ledger, utxos: ArbitaryLedgerUtxo) { - let stake_control = StakeControl::new_with(&accounts, &utxos.0); + fn utxo_ledger_strategy() -> impl Strategy> { + let output_strategy = any::().prop_map(|value| { + ( + 0, + AddressData::utxo(Discrimination::Test).make_output(value), + ) + }); // TODO proptest AverageValue + hash_map(any::(), output_strategy, 1..=50).prop_map(|utxos| { + utxos + .into_iter() + .fold(Ledger::new(), |ledger, (key, value)| { + ledger.add(&key, &[value]).unwrap() + }) + }) + } + + #[proptest] + fn stake_control_from_ledger( + accounts: account::Ledger, + #[strategy(utxo_ledger_strategy())] utxos: Ledger
, + ) { + let stake_control = StakeControl::new_with(&accounts, &utxos); //verify sum let accounts = accounts.get_total_value().unwrap(); - let utxo_or_group = utxos.0.values().map(|x| x.value).sum(); + let utxo_or_group = utxos.values().map(|x| x.value).sum(); let expected_sum = accounts .checked_add(utxo_or_group) .expect("cannot calculate expected total"); diff --git a/chain-impl-mockchain/src/stake/delegation.rs b/chain-impl-mockchain/src/stake/delegation.rs index 629f2ab17..b27e5dcde 100644 --- a/chain-impl-mockchain/src/stake/delegation.rs +++ b/chain-impl-mockchain/src/stake/delegation.rs @@ -186,9 +186,10 @@ mod tests { use super::*; use crate::certificate::PoolRegistration; - use quickcheck::{Arbitrary, Gen, TestResult}; - use quickcheck_macros::quickcheck; + use proptest::prelude::*; + use quickcheck::{Arbitrary, Gen}; use std::iter; + use test_strategy::proptest; impl Arbitrary for PoolsState { fn arbitrary(gen: &mut G) -> Self { @@ -205,6 +206,24 @@ mod tests { } } + impl proptest::arbitrary::Arbitrary for PoolsState { + type Parameters = (); + type Strategy = BoxedStrategy; + + fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { + any::>() + .prop_map(|stake_pools| { + stake_pools.into_iter().fold( + PoolsState::new(), + |delegation_state, stake_pool| { + delegation_state.register_stake_pool(stake_pool).unwrap() + }, + ) + }) + .boxed() + } + } + impl Arbitrary for PoolState { fn arbitrary(gen: &mut G) -> Self { let registration = Arc::new(PoolRegistration::arbitrary(gen)); @@ -225,87 +244,60 @@ mod tests { } } - #[quickcheck] - pub fn delegation_state_tests( - delegation_state: PoolsState, - stake_pool: PoolRegistration, - ) -> TestResult { + #[proptest] + fn delegation_state_tests(delegation_state: PoolsState, stake_pool: PoolRegistration) { // register stake pool first time should be ok - let delegation_state = match delegation_state.register_stake_pool(stake_pool.clone()) { - Ok(delegation_state) => delegation_state, - Err(err) => { - return TestResult::error(format!("Cannot register stake pool, due to {:?}", err)) - } - }; + let delegation_state = delegation_state + .register_stake_pool(stake_pool.clone()) + .unwrap(); // register stake pool again should throw error - if delegation_state + prop_assert!(delegation_state .register_stake_pool(stake_pool.clone()) - .is_ok() - { - return TestResult::error( - "Register the same stake pool twice should return error while it didn't", - ); - } + .is_err()); let stake_pool_id = stake_pool.to_id(); // stake pool should be in collection - if !delegation_state - .stake_pool_ids() - .any(|x| x == stake_pool_id) - { - return TestResult::error(format!( - "stake pool with id: {:?} should exist in iterator", - stake_pool_id - )); - }; + prop_assert!( + delegation_state + .stake_pool_ids() + .any(|x| x == stake_pool_id), + "stake pool with id: {:?} should exist in iterator", + stake_pool_id + ); // stake pool should exist in collection - if !delegation_state.stake_pool_exists(&stake_pool_id) { - TestResult::error(format!( - "stake pool with id {:?} should exist in collection", - stake_pool_id - )); - } + prop_assert!( + delegation_state.stake_pool_exists(&stake_pool_id), + "stake pool with id {:?} should exist in collection", + stake_pool_id + ); // deregister stake pool should be ok - let delegation_state = match delegation_state.deregister_stake_pool(&stake_pool_id) { - Ok(delegation_state) => delegation_state, - Err(err) => { - return TestResult::error(format!("Cannot deregister stake pool due to: {:?}", err)) - } - }; + let delegation_state = delegation_state + .deregister_stake_pool(&stake_pool_id) + .unwrap(); // deregister stake pool again should throw error - if delegation_state + prop_assert!(delegation_state .deregister_stake_pool(&stake_pool_id) - .is_ok() - { - return TestResult::error( - "Deregister the same stake pool twice should return error while it didn't", - ); - } + .is_ok()); // stake pool should not exist in collection - if delegation_state.stake_pool_exists(&stake_pool_id) { - return TestResult::error(format!( - "stake pool with id should be removed from collection {:?}", - stake_pool_id - )); - } + prop_assert!( + delegation_state.stake_pool_exists(&stake_pool_id), + "stake pool with id should be removed from collection {:?}", + stake_pool_id + ); // stake pool should not be in collection - if delegation_state - .stake_pool_ids() - .any(|x| x == stake_pool_id) - { - return TestResult::error(format!( - "stake pool with id should be removed from iterator {:?}", - stake_pool_id - )); - } - - TestResult::passed() + prop_assert!( + !delegation_state + .stake_pool_ids() + .any(|x| x == stake_pool_id), + "stake pool with id should be removed from iterator {:?}", + stake_pool_id + ); } } diff --git a/chain-impl-mockchain/src/stake/distribution.rs b/chain-impl-mockchain/src/stake/distribution.rs index 54c94e0ce..690cc448e 100644 --- a/chain-impl-mockchain/src/stake/distribution.rs +++ b/chain-impl-mockchain/src/stake/distribution.rs @@ -246,8 +246,9 @@ mod tests { }; use chain_addr::{Address, Kind}; use chain_crypto::PublicKey; + use proptest::prelude::*; use quickcheck::{Arbitrary, Gen, TestResult}; - use quickcheck_macros::quickcheck; + use test_strategy::proptest; /// Holds all possible cases of distribution source #[derive(Clone, Debug)] @@ -389,119 +390,106 @@ mod tests { } } - #[quickcheck] - pub fn stake_distribution_is_consistent_with_total_value( - stake_distribution_data: StakeDistributionArbitraryData, - ) -> TestResult { - let mut accounts = account::Ledger::new(); - let mut dstate = PoolsState::new(); - let mut utxos = utxo::Ledger::new(); - - // create two stake pools, one active and one inactive - let id_active_pool = stake_distribution_data.active_stake_pool.to_id(); - dstate = dstate - .register_stake_pool(stake_distribution_data.active_stake_pool.clone()) - .unwrap(); - let id_retired_pool = stake_distribution_data.retired_stake_pool.to_id(); - - // add utxos - for (fragment_id, tx_index, output) in stake_distribution_data.utxos.iter().cloned() { - utxos = utxos.add(&fragment_id, &[(tx_index, output)]).unwrap(); - } - - // add delegation addresses with all accounts delegated to active stake pool - for (fragment_id, tx_index, output) in stake_distribution_data.groups.iter().cloned() { - utxos = utxos - .add(&fragment_id, &[(tx_index, output.clone())]) - .unwrap(); - let account_public_key: PublicKey = match output.address.kind() { - Kind::Group(_, delegation_key) => delegation_key.clone(), - _ => panic!("delegation utxo should have Kind::Group type"), - }; - accounts = accounts - .add_account( - &Identifier::from(account_public_key.clone()), - Value::zero(), - (), - ) - .unwrap(); - accounts = accounts - .set_delegation( - &Identifier::from(account_public_key.clone()), - &DelegationType::Full(id_active_pool.clone()), - ) - .unwrap(); - } - - // add delegation addresses which point to single account with delegation - for (fragment_id, tx_index, output) in stake_distribution_data - .groups_single_account - .iter() - .cloned() - { - utxos = utxos.add(&fragment_id, &[(tx_index, output)]).unwrap(); - } - - // add accounts without delegation - for (id, value) in stake_distribution_data.unassigned_accounts.iter().cloned() { - accounts = accounts.add_account(&id, value, ()).unwrap(); - } - - // add accounts with delegation - for (id, value) in stake_distribution_data.assigned_accounts.iter().cloned() { - accounts = accounts.add_account(&id, value, ()).unwrap(); - accounts = accounts - .set_delegation(&id, &DelegationType::Full(id_active_pool.clone())) - .unwrap(); - } - - // add accounts with delegation as a target for delegation addresses - let single_account = stake_distribution_data.single_account.clone(); - accounts = accounts - .add_account(&single_account.0, single_account.1, ()) - .unwrap(); - accounts = accounts - .set_delegation(&single_account.0, &DelegationType::Full(id_active_pool)) - .unwrap(); - - // add accounts with retired stake pool - for (id, value) in stake_distribution_data.dangling_accounts.iter().cloned() { - accounts = accounts.add_account(&id, value, ()).unwrap(); - accounts = accounts - .set_delegation(&id, &DelegationType::Full(id_retired_pool.clone())) - .unwrap(); - } - - // verify - let distribution = super::get_distribution(&accounts, &dstate, &utxos); - - if distribution.unassigned != stake_distribution_data.calculate_unassigned() { - return TestResult::error(format!( - "Wrong Unassigned value. expected: {} but got {}", - stake_distribution_data.calculate_unassigned(), - &distribution.unassigned - )); - } - - if distribution.dangling != stake_distribution_data.calculate_dangling() { - return TestResult::error(format!( - "Wrong Unassigned value. expected: {} but got {}", - stake_distribution_data.calculate_unassigned(), - &distribution.unassigned - )); - } - - let pools_total_stake: Stake = - Stake::sum(distribution.to_pools.values().map(|x| x.stake.total)); - if pools_total_stake != stake_distribution_data.pools_total() { - return TestResult::error(format!( - "Wrong Unassigned value. expected: {} but got {}", - stake_distribution_data.pools_total(), - pools_total_stake - )); - } - TestResult::passed() - } + // TODO proptest + // #[proptest] + // fn stake_distribution_is_consistent_with_total_value( + // stake_distribution_data: StakeDistributionArbitraryData, + // ) { + // let mut accounts = account::Ledger::new(); + // let mut dstate = PoolsState::new(); + // let mut utxos = utxo::Ledger::new(); + + // // create two stake pools, one active and one inactive + // let id_active_pool = stake_distribution_data.active_stake_pool.to_id(); + // dstate = dstate + // .register_stake_pool(stake_distribution_data.active_stake_pool.clone()) + // .unwrap(); + // let id_retired_pool = stake_distribution_data.retired_stake_pool.to_id(); + + // // add utxos + // for (fragment_id, tx_index, output) in stake_distribution_data.utxos.iter().cloned() { + // utxos = utxos.add(&fragment_id, &[(tx_index, output)]).unwrap(); + // } + + // // add delegation addresses with all accounts delegated to active stake pool + // for (fragment_id, tx_index, output) in stake_distribution_data.groups.iter().cloned() { + // utxos = utxos + // .add(&fragment_id, &[(tx_index, output.clone())]) + // .unwrap(); + // let account_public_key: PublicKey = match output.address.kind() { + // Kind::Group(_, delegation_key) => delegation_key.clone(), + // _ => panic!("delegation utxo should have Kind::Group type"), + // }; + // accounts = accounts + // .add_account( + // &Identifier::from(account_public_key.clone()), + // Value::zero(), + // (), + // ) + // .unwrap(); + // accounts = accounts + // .set_delegation( + // &Identifier::from(account_public_key.clone()), + // &DelegationType::Full(id_active_pool.clone()), + // ) + // .unwrap(); + // } + + // // add delegation addresses which point to single account with delegation + // for (fragment_id, tx_index, output) in stake_distribution_data + // .groups_single_account + // .iter() + // .cloned() + // { + // utxos = utxos.add(&fragment_id, &[(tx_index, output)]).unwrap(); + // } + + // // add accounts without delegation + // for (id, value) in stake_distribution_data.unassigned_accounts.iter().cloned() { + // accounts = accounts.add_account(&id, value, ()).unwrap(); + // } + + // // add accounts with delegation + // for (id, value) in stake_distribution_data.assigned_accounts.iter().cloned() { + // accounts = accounts.add_account(&id, value, ()).unwrap(); + // accounts = accounts + // .set_delegation(&id, &DelegationType::Full(id_active_pool.clone())) + // .unwrap(); + // } + + // // add accounts with delegation as a target for delegation addresses + // let single_account = stake_distribution_data.single_account.clone(); + // accounts = accounts + // .add_account(&single_account.0, single_account.1, ()) + // .unwrap(); + // accounts = accounts + // .set_delegation(&single_account.0, &DelegationType::Full(id_active_pool)) + // .unwrap(); + + // // add accounts with retired stake pool + // for (id, value) in stake_distribution_data.dangling_accounts.iter().cloned() { + // accounts = accounts.add_account(&id, value, ()).unwrap(); + // accounts = accounts + // .set_delegation(&id, &DelegationType::Full(id_retired_pool.clone())) + // .unwrap(); + // } + + // // verify + // let distribution = super::get_distribution(&accounts, &dstate, &utxos); + + // prop_assert_eq!( + // stake_distribution_data.calculate_unassigned(), + // distribution.unassigned + // ); + // prop_assert_eq!( + // stake_distribution_data.calculate_dangling(), + // distribution.dangling + // ); + + // let pools_total_stake: Stake = + // Stake::sum(distribution.to_pools.values().map(|x| x.stake.total)); + // prop_assert_eq!(stake_distribution_data.pools_total(), pools_total_stake); + // } #[derive(Clone, Debug)] pub struct CorrectDelegationType(DelegationType); @@ -561,21 +549,43 @@ mod tests { } } - #[quickcheck] - pub fn assign_account_value_is_consitent_with_stake_distribution( + #[proptest] + fn assign_account_value_is_consitent_with_stake_distribution( account_identifier: account::Identifier, - delegation_type: CorrectDelegationType, + delegation_type: DelegationType, value: Stake, - ) -> TestResult { + ) { let mut stake_distribution = StakeDistribution::empty(); - stake_distribution.to_pools = delegation_type.get_pools(); + stake_distribution.to_pools = match &delegation_type { + DelegationType::NonDelegated => HashMap::new(), + DelegationType::Full(pool_id) => { + let mut pools = HashMap::new(); + let information = PoolStakeInformation { + registration: None, + stake: PoolStakeDistribution::new(), + }; + pools.insert(pool_id.clone(), information); + pools + } + DelegationType::Ratio(delegation_ratio) => { + let mut pools = HashMap::new(); + for pool_id in delegation_ratio.pools().iter().cloned().map(|x| x.0) { + let information = PoolStakeInformation { + registration: None, + stake: PoolStakeDistribution::new(), + }; + pools.insert(pool_id.clone(), information); + } + pools + } + }; assign_account_value( &mut stake_distribution, &account_identifier, - &delegation_type.0, + &delegation_type, value, ); - match delegation_type.0 { + match delegation_type { DelegationType::NonDelegated => { assert_distribution(stake_distribution, value, Stake::zero(), Stake::zero()) } @@ -593,27 +603,10 @@ mod tests { unassigned: Stake, dangling: Stake, pools: Stake, - ) -> TestResult { - if stake_distribution.unassigned != unassigned { - return TestResult::error(&format!( - "wrong unassigned {} vs {}", - stake_distribution.unassigned, unassigned - )); - } - if stake_distribution.dangling != dangling { - return TestResult::error(&format!( - "wrong dangling {} vs {}", - stake_distribution.dangling, dangling - )); - } - if stake_distribution.total_stake() != pools { - return TestResult::error(&format!( - "wrong to_pools {} vs {}", - stake_distribution.total_stake(), - pools - )); - } - TestResult::passed() + ) { + assert_eq!(stake_distribution.unassigned, unassigned); + assert_eq!(stake_distribution.dangling, dangling); + assert_eq!(stake_distribution.total_stake(), pools); } #[test] diff --git a/chain-impl-mockchain/src/stake/stake.rs b/chain-impl-mockchain/src/stake/stake.rs index 4c540e89a..d610b2dee 100644 --- a/chain-impl-mockchain/src/stake/stake.rs +++ b/chain-impl-mockchain/src/stake/stake.rs @@ -2,6 +2,10 @@ use crate::value::Value; use std::ops::{Add, AddAssign}; #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] +#[cfg_attr( + any(test, feature = "property-test-api"), + derive(test_strategy::Arbitrary) +)] pub struct Stake(pub u64); #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] diff --git a/chain-impl-mockchain/src/testing/arbitrary/transaction.rs b/chain-impl-mockchain/src/testing/arbitrary/transaction.rs index 1845f0a14..62d072d5c 100644 --- a/chain-impl-mockchain/src/testing/arbitrary/transaction.rs +++ b/chain-impl-mockchain/src/testing/arbitrary/transaction.rs @@ -6,6 +6,7 @@ use crate::{ arbitrary::{utils as arbitrary_utils, AverageValue}, data::{AddressData, AddressDataValue}, ledger::TestLedger, + strategy, }, transaction::{Input, Output}, value::*, @@ -13,17 +14,30 @@ use crate::{ use chain_addr::{Address, Kind}; use chain_crypto::{Ed25519, PublicKey}; use quickcheck::{Arbitrary, Gen}; -use std::iter; +use std::{convert::TryInto, iter}; use thiserror::Error; -#[derive(Clone, Debug)] +#[derive(Clone, Debug, test_strategy::Arbitrary)] pub struct ArbitraryValidTransactionData { + #[any(proptest::collection::size_range(..256).lift())] pub addresses: Vec, + #[strategy(strategy::choose_random_vec_subset(#addresses, None))] pub input_addresses: Vec, + #[strategy(choose_random_output_subset(#addresses, #input_addresses))] pub output_addresses: Vec, pub fee: LinearFee, } +fn choose_random_output_subset( + addreses: Vec, + inputs: Vec, +) -> impl proptest::strategy::Strategy> { + // this way we get at least one coin per output + let inputs_sum: u64 = inputs.into_iter().map(|input| input.value.0).sum(); + let max_outputs_len = std::cmp::min(addreses.len(), inputs_sum.try_into().unwrap()); + strategy::choose_random_vec_subset(addreses, Some(max_outputs_len)) +} + impl Arbitrary for ArbitraryValidTransactionData { fn arbitrary(gen: &mut G) -> Self { use ArbitraryValidTransactionData as tx_data; diff --git a/chain-impl-mockchain/src/testing/arbitrary/update_proposal.rs b/chain-impl-mockchain/src/testing/arbitrary/update_proposal.rs index 3258b590a..39881fb1f 100644 --- a/chain-impl-mockchain/src/testing/arbitrary/update_proposal.rs +++ b/chain-impl-mockchain/src/testing/arbitrary/update_proposal.rs @@ -9,6 +9,8 @@ use crate::{ update::{SignedUpdateProposal, SignedUpdateVote, UpdateVote}, }; use chain_crypto::{Ed25519, Ed25519Extended, SecretKey}; +use proptest::prelude::*; +use proptest::sample::select; use quickcheck::{Arbitrary, Gen}; use std::fmt::{self, Debug}; use std::{collections::HashMap, iter}; @@ -111,3 +113,97 @@ impl Arbitrary for UpdateProposalData { } } } + +impl proptest::arbitrary::Arbitrary for UpdateProposalData { + type Parameters = (); + type Strategy = BoxedStrategy; + + fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { + use proptest::collection::vec; + + let leaders_strategy = vec(any::>(), 1..=20).prop_map(|sks| { + sks.into_iter() + .map(|sk| { + let leader_id = BftLeaderId(sk.to_public()); + (leader_id, sk) + }) + .collect::>() + }); + + let voters_leaders_proposer_strategy = leaders_strategy.prop_flat_map(|leaders| { + let voters = vec(select(leaders.clone()), 0..leaders.len()) + .prop_map(|entries| entries.into_iter().collect::>()); + let leaders = leaders.into_iter().collect::>(); + let leaders_ids = leaders.keys().cloned().collect::>(); + let proposer = select(leaders_ids); + (Just(leaders), voters, proposer) + }); + + let settings_strategy = any::<(u32, u8, u32, u32, LinearFee, u32)>() + .prop_map( + |( + slots_per_epoch, + slot_duration, + epoch_stablility_depth, + block_content_max_size, + linear_fee, + proposal_expiration, + )| { + vec![ + ConfigParam::SlotsPerEpoch(slots_per_epoch), + ConfigParam::SlotDuration(slot_duration), + ConfigParam::EpochStabilityDepth(epoch_stablility_depth), + ConfigParam::BlockContentMaxSize(block_content_max_size), + ConfigParam::LinearFee(linear_fee), + ConfigParam::ProposalExpiration(proposal_expiration), + ] + }, + ) + .prop_flat_map(|settings| { + let settings_len = settings.len(); + vec(select(settings), 0..settings_len) + }); + + let proposal_id_strategy = any::(); + + let sk_strategy = any::>(); + + ( + voters_leaders_proposer_strategy, + settings_strategy, + proposal_id_strategy, + sk_strategy, + ) + .prop_map( + |((leaders, voters, proposer_id), settings, proposal_id, sk)| { + let update_proposal = ProposalBuilder::new() + .with_proposal_changes(settings) + .build(); + let signed_update_proposal = SignedProposalBuilder::new() + .with_proposal_update(update_proposal) + .with_proposer_id(proposer_id) + .build(); + let signed_votes: Vec = voters + .iter() + .map(|(id, _)| { + let update_vote = UpdateVote { + proposal_id, + voter_id: id.clone(), + }; + SignedUpdateVote { vote: update_vote } + }) + .collect(); + let update_successful = signed_votes.len() > (leaders.len() / 2); + UpdateProposalData { + leaders, + proposal: signed_update_proposal, + proposal_id, + votes: signed_votes, + block_signing_key: sk, + update_successful, + } + }, + ) + .boxed() + } +} diff --git a/chain-impl-mockchain/src/testing/data/address.rs b/chain-impl-mockchain/src/testing/data/address.rs index 849f822cb..df8f14212 100644 --- a/chain-impl-mockchain/src/testing/data/address.rs +++ b/chain-impl-mockchain/src/testing/data/address.rs @@ -2,7 +2,7 @@ use crate::{ account::{Identifier, SpendingCounter}, chaintypes::HeaderId, key::EitherEd25519SecretKey, - testing::builders::make_witness, + testing::{builders::make_witness, strategy::address_without_multisig}, transaction::{Input, Output, TransactionAuthData, Witness}, utxo::Entry, value::Value, @@ -18,11 +18,15 @@ use std::fmt::{self, Debug}; /// /// Struct is responsible for adding some code which makes converting into transaction input/output easily. /// Also it held all needed information (private key, public key) which can construct witness for transaction. -/// #[derive(Clone)] +#[cfg_attr( + any(test, feature = "property-test-api"), + derive(test_strategy::Arbitrary) +)] pub struct AddressData { pub private_key: EitherEd25519SecretKey, pub spending_counter: Option, + #[strategy(address_without_multisig())] pub address: Address, } @@ -227,6 +231,10 @@ impl From for Address { } #[derive(Clone, Debug, PartialEq)] +#[cfg_attr( + any(test, feature = "property-test-api"), + derive(test_strategy::Arbitrary) +)] pub struct AddressDataValue { pub address_data: AddressData, pub value: Value, diff --git a/chain-impl-mockchain/src/testing/e2e/fees.rs b/chain-impl-mockchain/src/testing/e2e/fees.rs index 585f77fa2..009444047 100644 --- a/chain-impl-mockchain/src/testing/e2e/fees.rs +++ b/chain-impl-mockchain/src/testing/e2e/fees.rs @@ -9,10 +9,11 @@ use crate::{ value::Value, }; use chain_addr::Discrimination; -use quickcheck_macros::quickcheck; use std::num::NonZeroU64; +use test_strategy::proptest; + const ALICE: &str = "Alice"; const BOB: &str = "Bob"; const STAKE_POOL: &str = "stake_pool"; @@ -197,7 +198,7 @@ fn transaction_without_fees() { /// Verifies that after a transaction in a ledger with fees, the total funds do not change and the /// fee pots contain the fee. -#[quickcheck] +#[proptest] fn transaction_with_fees(fee: u64) { verify_total_funds_after_transaction_with_fee(fee); } diff --git a/chain-impl-mockchain/src/testing/mod.rs b/chain-impl-mockchain/src/testing/mod.rs index ca6d02ce1..72d8a94bd 100644 --- a/chain-impl-mockchain/src/testing/mod.rs +++ b/chain-impl-mockchain/src/testing/mod.rs @@ -13,3 +13,4 @@ pub use data::KeysDb; pub use gen::{TestGen, VoteTestGen}; pub use ledger::{ConfigBuilder, LedgerBuilder, TestLedger, UtxoDb}; pub mod serialization; +pub mod strategy; diff --git a/chain-impl-mockchain/src/testing/scenario/template/builders.rs b/chain-impl-mockchain/src/testing/scenario/template/builders.rs index 965c723a4..4da43418d 100644 --- a/chain-impl-mockchain/src/testing/scenario/template/builders.rs +++ b/chain-impl-mockchain/src/testing/scenario/template/builders.rs @@ -361,7 +361,7 @@ impl ProposalDefBuilder { } pub fn action_transfer_to_rewards(&mut self, value: u64) -> &mut Self { - self.action_type = VoteAction::Parameters { + self.action_type = VoteAction::LedgerParameters { action: ParametersGovernanceAction::RewardAdd { value: Value(value), }, @@ -370,7 +370,7 @@ impl ProposalDefBuilder { } pub fn action_parameters_no_op(&mut self) -> &mut Self { - self.action_type = VoteAction::Parameters { + self.action_type = VoteAction::LedgerParameters { action: ParametersGovernanceAction::NoOp, }; self diff --git a/chain-impl-mockchain/src/testing/serialization.rs b/chain-impl-mockchain/src/testing/serialization.rs index 16c623941..ced05f7f9 100644 --- a/chain-impl-mockchain/src/testing/serialization.rs +++ b/chain-impl-mockchain/src/testing/serialization.rs @@ -1,42 +1,29 @@ use chain_core::mempack::{ReadBuf, Readable}; use chain_core::property::{Deserialize, Serialize}; use quickcheck::{Arbitrary, TestResult}; +use std::fmt::Debug; /// test that any arbitrary given object can serialize and deserialize /// back into itself (i.e. it is a bijection, or a one to one match /// between the serialized bytes and the object) -pub fn serialization_bijection(t: T) -> TestResult +pub fn serialization_bijection(t: T) where - T: Arbitrary + Serialize + Deserialize + Eq, + T: Arbitrary + Serialize + Deserialize + Eq + Debug, { - let vec = match t.serialize_as_vec() { - Err(error) => return TestResult::error(format!("serialization: {}", error)), - Ok(v) => v, - }; - let decoded_t = match T::deserialize(&vec[..]) { - Err(error) => return TestResult::error(format!("deserialization: {}", error)), - Ok(v) => v, - }; - TestResult::from_bool(decoded_t == t) + let vec = t.serialize_as_vec().unwrap(); + let decoded_t = T::deserialize(&vec[..]).unwrap(); + assert_eq!(decoded_t, t); } /// test that any arbitrary given object can serialize and deserialize /// back into itself (i.e. it is a bijection, or a one to one match /// between the serialized bytes and the object) -pub fn serialization_bijection_r(t: T) -> TestResult +pub fn serialization_bijection_r(t: T) where - T: Arbitrary + Serialize + Readable + Eq, + T: Arbitrary + Serialize + Readable + Eq + Debug, { - let vec = match t.serialize_as_vec() { - Err(error) => return TestResult::error(format!("serialization: {}", error)), - Ok(v) => v, - }; + let vec = t.serialize_as_vec().unwrap(); let mut buf = ReadBuf::from(&vec); - let decoded_t = match T::read(&mut buf) { - Err(error) => { - return TestResult::error(format!("deserialization: {:?}\n{}", error, buf.debug())) - } - Ok(v) => v, - }; - TestResult::from_bool(buf.expect_end().is_ok() && decoded_t == t) + let decoded_t = T::read(&mut buf).unwrap(); + assert!(buf.expect_end().is_ok() && decoded_t == t); } diff --git a/chain-impl-mockchain/src/testing/strategy.rs b/chain-impl-mockchain/src/testing/strategy.rs new file mode 100644 index 000000000..740eb8095 --- /dev/null +++ b/chain-impl-mockchain/src/testing/strategy.rs @@ -0,0 +1,43 @@ +use std::{ + collections::HashSet, + convert::TryFrom, + fmt::Debug, + num::{NonZeroU32, NonZeroU64}, +}; + +use proptest::{collection::vec, prelude::*, sample::select}; + +// TODO proptest this should be implemented in proptest itself +pub fn non_zero_u32() -> impl Strategy { + (1..u32::MAX).prop_map(|value| NonZeroU32::try_from(value).unwrap()) +} + +pub fn non_zero_u64() -> impl Strategy { + (1..u64::MAX).prop_map(|value| NonZeroU64::try_from(value).unwrap()) +} + +pub fn optional_non_zero_u64() -> impl Strategy> { + proptest::option::of(non_zero_u64()) +} + +pub fn kind_type_without_multisig() -> impl Strategy { + any::().prop_filter("only non-multisig variants are accepted", |kt| { + kt != &chain_addr::KindType::Multisig + }) +} + +pub fn address_without_multisig() -> impl Strategy { + any::() + .prop_filter("only non-multisig variants are accepted", |k| { + !matches!(k, chain_addr::Kind::Multisig(_)) + }) + .prop_map(|k| chain_addr::Address(chain_addr::Discrimination::Test, k)) +} + +pub fn choose_random_vec_subset( + v: Vec, + max_len: Option, +) -> impl Strategy> { + let max_len = max_len.unwrap_or_else(|| v.len()); + vec(select(v), 0..max_len) +} diff --git a/chain-impl-mockchain/src/transaction/element.rs b/chain-impl-mockchain/src/transaction/element.rs index e299da269..c7fe6562a 100644 --- a/chain-impl-mockchain/src/transaction/element.rs +++ b/chain-impl-mockchain/src/transaction/element.rs @@ -29,6 +29,10 @@ pub type TransactionSignDataHash = DigestOf; pub struct TransactionBindingAuthDataPhantom(); #[derive(Debug, Clone)] +#[cfg_attr( + any(test, feature = "property-test-api"), + derive(test_strategy::Arbitrary) +)] pub struct SingleAccountBindingSignature( pub(crate) Signature, ); @@ -66,8 +70,13 @@ impl Readable for SingleAccountBindingSignature { } #[derive(Debug, Clone)] +#[cfg_attr( + any(test, feature = "property-test-api"), + derive(test_strategy::Arbitrary) +)] pub enum AccountBindingSignature { Single(SingleAccountBindingSignature), + #[cfg_attr(any(test, feature = "property-test-api"), weight(0))] Multi(u32), // TODO } diff --git a/chain-impl-mockchain/src/transaction/input.rs b/chain-impl-mockchain/src/transaction/input.rs index 88c0fcfdf..f5d4a4980 100644 --- a/chain-impl-mockchain/src/transaction/input.rs +++ b/chain-impl-mockchain/src/transaction/input.rs @@ -16,6 +16,10 @@ pub const INPUT_PTR_SIZE: usize = 32; /// This is either an single account or a multisig account depending on the witness type #[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[cfg_attr( + any(test, feature = "property-test-api"), + derive(test_strategy::Arbitrary) +)] pub struct UnspecifiedAccountIdentifier([u8; INPUT_PTR_SIZE]); impl UnspecifiedAccountIdentifier { diff --git a/chain-impl-mockchain/src/transaction/payload.rs b/chain-impl-mockchain/src/transaction/payload.rs index 5be62edd1..1e066e03b 100644 --- a/chain-impl-mockchain/src/transaction/payload.rs +++ b/chain-impl-mockchain/src/transaction/payload.rs @@ -121,6 +121,10 @@ impl<'a, P: ?Sized> PayloadAuthSlice<'a, P> { } #[derive(Debug, Clone, PartialEq, Eq)] +#[cfg_attr( + any(test, feature = "property-test-api"), + derive(test_strategy::Arbitrary) +)] pub struct NoExtra; impl property::Serialize for NoExtra { diff --git a/chain-impl-mockchain/src/transaction/test.rs b/chain-impl-mockchain/src/transaction/test.rs index b941636cf..fe14ef25d 100644 --- a/chain-impl-mockchain/src/transaction/test.rs +++ b/chain-impl-mockchain/src/transaction/test.rs @@ -1,6 +1,7 @@ use super::{ element::SingleAccountBindingSignature, AccountBindingSignature, AccountIdentifier, Input, - NoExtra, Payload, Transaction, TxBuilder, UnspecifiedAccountIdentifier, UtxoPointer, Witness, + NoExtra, Output, Payload, Transaction, TxBuilder, UnspecifiedAccountIdentifier, UtxoPointer, + Witness, }; #[cfg(test)] use crate::certificate::OwnerStakeDelegation; @@ -8,27 +9,33 @@ use crate::date::BlockDate; use crate::key::{EitherEd25519SecretKey, SpendingSignature}; #[cfg(test)] use crate::testing::serialization::serialization_bijection_r; +use chain_addr::Address; use chain_crypto::{testing::arbitrary_secret_key, Ed25519, SecretKey, Signature}; +use proptest::prelude::*; #[cfg(test)] use quickcheck::TestResult; use quickcheck::{Arbitrary, Gen}; -use quickcheck_macros::quickcheck; +use test_strategy::proptest; -quickcheck! { - fn transaction_encode_decode(transaction: Transaction) -> TestResult { - serialization_bijection_r(transaction) - } - fn stake_owner_delegation_tx_encode_decode(transaction: Transaction) -> TestResult { - serialization_bijection_r(transaction) - } - /* - fn certificate_tx_encode_decode(transaction: Transaction) -> TestResult { - chain_core::property::testing::serialization_bijection_r(transaction) - } - */ - fn signed_transaction_encode_decode(transaction: Transaction) -> TestResult { - serialization_bijection_r(transaction) - } +#[proptest] +fn transaction_encode_decode(transaction: Transaction) { + serialization_bijection_r(transaction) +} + +#[proptest] +fn stake_owner_delegation_tx_encode_decode(transaction: Transaction) { + serialization_bijection_r(transaction) +} + +/* +fn certificate_tx_encode_decode(transaction: Transaction) -> TestResult { + chain_core::property::testing::serialization_bijection_r(transaction) +} +*/ + +#[proptest] +fn signed_transaction_encode_decode(transaction: Transaction) { + serialization_bijection_r(transaction) } #[cfg(test)] @@ -46,10 +53,10 @@ where } } -#[quickcheck] -pub fn check_transaction_accessor_consistent(tx: Transaction) -> TestResult { +#[proptest] +fn check_transaction_accessor_consistent(tx: Transaction) { let slice = tx.as_slice(); - let res = check_eq( + check_eq( "tx", tx.nb_inputs(), "tx-slice", @@ -109,11 +116,8 @@ pub fn check_transaction_accessor_consistent(tx: Transaction) -> TestRe slice.witnesses().iter().count(), "witnesses", ) - }); - match res { - Ok(()) => TestResult::passed(), - Err(e) => TestResult::error(e), - } + }) + .unwrap(); } impl Arbitrary for UtxoPointer { @@ -132,12 +136,54 @@ impl Arbitrary for Input { } } +impl proptest::arbitrary::Arbitrary for Input { + type Parameters = (); + type Strategy = proptest::strategy::BoxedStrategy; + + fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { + any::() + .prop_map(|utxo_pointer| Self::from_utxo(utxo_pointer)) + .boxed() + } +} + impl Arbitrary for NoExtra { fn arbitrary(_: &mut G) -> Self { Self } } +impl proptest::arbitrary::Arbitrary for Transaction +where + Extra: proptest::arbitrary::Arbitrary + Payload + 'static, + Extra::Auth: proptest::arbitrary::Arbitrary + 'static, +{ + type Parameters = (); + type Strategy = proptest::strategy::BoxedStrategy; + + fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { + use proptest::collection::vec; + + ( + any::(), + any::(), + vec(any::<(Input, Witness)>(), ..16), + vec(any::>(), ..16), + ) + .prop_map(|(payload, payload_auth, inputs_and_witnesses, outputs)| { + let (inputs, witnesses): (Vec<_>, Vec<_>) = + inputs_and_witnesses.into_iter().unzip(); + TxBuilder::new() + .set_payload(&payload) + .set_expiry_date(BlockDate::first().next_epoch()) + .set_ios(&inputs, &outputs) + .set_witnesses(&witnesses) + .set_payload_auth(&payload_auth) + }) + .boxed() + } +} + impl Arbitrary for Transaction where Extra::Auth: Arbitrary, diff --git a/chain-impl-mockchain/src/transaction/transfer.rs b/chain-impl-mockchain/src/transaction/transfer.rs index 60491ece8..2ec516dc7 100644 --- a/chain-impl-mockchain/src/transaction/transfer.rs +++ b/chain-impl-mockchain/src/transaction/transfer.rs @@ -5,6 +5,10 @@ use chain_core::mempack::{ReadBuf, ReadError, Readable}; /// Information how tokens are spent. /// A value of tokens is sent to the address. #[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[cfg_attr( + any(test, feature = "property-test-api"), + derive(test_strategy::Arbitrary) +)] pub struct Output
{ pub address: Address, pub value: Value, diff --git a/chain-impl-mockchain/src/transaction/utxo.rs b/chain-impl-mockchain/src/transaction/utxo.rs index 6ab91792c..cf0337e8f 100644 --- a/chain-impl-mockchain/src/transaction/utxo.rs +++ b/chain-impl-mockchain/src/transaction/utxo.rs @@ -5,6 +5,10 @@ pub type TransactionIndex = u8; /// Unspent transaction pointer. #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[cfg_attr( + any(test, feature = "property-test-api"), + derive(test_strategy::Arbitrary) +)] pub struct UtxoPointer { /// the transaction identifier where the unspent output is pub transaction_id: FragmentId, diff --git a/chain-impl-mockchain/src/transaction/witness.rs b/chain-impl-mockchain/src/transaction/witness.rs index 0517cc2de..b4241ea63 100644 --- a/chain-impl-mockchain/src/transaction/witness.rs +++ b/chain-impl-mockchain/src/transaction/witness.rs @@ -17,14 +17,21 @@ use chain_crypto::{Ed25519, PublicKey, Signature}; /// It's important that witness works with opaque structures /// and may not know the contents of the internal transaction. #[derive(Debug, Clone)] +#[cfg_attr( + any(test, feature = "property-test-api"), + derive(test_strategy::Arbitrary) +)] pub enum Witness { Utxo(SpendingSignature), Account(account::Witness), OldUtxo( - PublicKey, - [u8; 32], + #[cfg_attr(any(test, feature = "property-test-api"), strategy(chain_crypto::testing::public_key_strategy::()))] + PublicKey, + #[cfg_attr(any(test, feature = "property-test-api"), strategy(proptest::strategy::Just([0u8; 32])))] + [u8; 32], Signature, ), + #[cfg_attr(any(test, feature = "property-test-api"), weight(0))] Multisig(multisig::Witness), } diff --git a/chain-impl-mockchain/src/treasury.rs b/chain-impl-mockchain/src/treasury.rs index 33687bde1..50626ac0a 100644 --- a/chain-impl-mockchain/src/treasury.rs +++ b/chain-impl-mockchain/src/treasury.rs @@ -7,6 +7,10 @@ use crate::value::Value; /// withdraw money from, so it serves just to /// record a monotically increasing special account. #[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[cfg_attr( + any(test, feature = "property-test-api"), + derive(test_strategy::Arbitrary) +)] pub struct Treasury(Value); impl Treasury { diff --git a/chain-impl-mockchain/src/txbuilder.rs b/chain-impl-mockchain/src/txbuilder.rs index 06b39007a..092499697 100644 --- a/chain-impl-mockchain/src/txbuilder.rs +++ b/chain-impl-mockchain/src/txbuilder.rs @@ -323,10 +323,9 @@ mod tests { use crate::transaction::{Input, INPUT_PTR_SIZE}; use chain_addr::Address; use quickcheck::{Arbitrary, Gen, TestResult}; - use quickcheck_macros::quickcheck; use std::iter; - #[quickcheck] + #[proptest] fn tx_builder_never_creates_unbalanced_tx( inputs: ArbitraryInputs, outputs: ArbitraryOutputs, @@ -465,7 +464,7 @@ mod tests { u64::arbitrary(gen) % (range + 1) } - #[quickcheck] + #[proptest] fn split_value_splits_whole_value(split_value: ArbitrarySplitValue) -> () { assert_eq!( split_value.parts, @@ -503,8 +502,8 @@ mod tests { } } - #[quickcheck] - pub fn cert_builder_never_creates_unbalanced_tx( + #[proptest] + fn cert_builder_never_creates_unbalanced_tx( input: Input, fee: LinearFee, certificate: Certificate, diff --git a/chain-impl-mockchain/src/update.rs b/chain-impl-mockchain/src/update.rs index e2230e275..0707bd700 100644 --- a/chain-impl-mockchain/src/update.rs +++ b/chain-impl-mockchain/src/update.rs @@ -236,6 +236,10 @@ pub type UpdateProposalId = crate::fragment::FragmentId; pub type UpdateVoterId = BftLeaderId; #[derive(Clone, Debug, PartialEq, Eq)] +#[cfg_attr( + any(test, feature = "property-test-api"), + derive(test_strategy::Arbitrary) +)] pub struct UpdateProposal { pub changes: ConfigParams, } @@ -280,6 +284,10 @@ impl Readable for UpdateProposal { } #[derive(Clone, Debug)] +#[cfg_attr( + any(test, feature = "property-test-api"), + derive(test_strategy::Arbitrary) +)] pub struct UpdateProposalWithProposer { pub proposal: UpdateProposal, pub proposer_id: UpdateVoterId, @@ -306,6 +314,10 @@ impl Readable for UpdateProposalWithProposer { } #[derive(Clone, Debug)] +#[cfg_attr( + any(test, feature = "property-test-api"), + derive(test_strategy::Arbitrary) +)] pub struct SignedUpdateProposal { pub proposal: UpdateProposalWithProposer, } @@ -336,6 +348,10 @@ impl Readable for SignedUpdateProposal { // A positive vote for a proposal. #[derive(Clone, Debug, PartialEq, Eq)] +#[cfg_attr( + any(test, feature = "property-test-api"), + derive(test_strategy::Arbitrary) +)] pub struct UpdateVote { pub proposal_id: UpdateProposalId, pub voter_id: UpdateVoterId, @@ -364,6 +380,10 @@ impl Readable for UpdateVote { } #[derive(Clone, Debug)] +#[cfg_attr( + any(test, feature = "property-test-api"), + derive(test_strategy::Arbitrary) +)] pub struct SignedUpdateVote { pub vote: UpdateVote, } @@ -415,11 +435,12 @@ mod tests { }; #[cfg(test)] use chain_addr::Discrimination; + use proptest::prelude::*; #[cfg(test)] use quickcheck::TestResult; use quickcheck::{Arbitrary, Gen}; - use quickcheck_macros::quickcheck; use std::iter; + use test_strategy::proptest; impl Arbitrary for UpdateProposal { fn arbitrary(g: &mut G) -> Self { @@ -514,10 +535,9 @@ mod tests { update_state.apply_vote(&signed_update_vote, &settings) } - quickcheck! { - fn update_proposal_serialize_deserialize_bijection(update_proposal: UpdateProposal) -> TestResult { - serialization_bijection(update_proposal) - } + #[proptest] + fn update_proposal_serialize_deserialize_bijection(update_proposal: UpdateProposal) { + serialization_bijection(update_proposal) } #[test] @@ -786,7 +806,7 @@ mod tests { assert_eq!(update_state.proposals.len(), 0); } - #[derive(Debug, Copy, Clone)] + #[derive(Debug, Copy, Clone, test_strategy::Arbitrary)] pub struct ExpiryBlockDate { pub block_date: BlockDate, pub proposal_expiration: u32, @@ -819,10 +839,8 @@ mod tests { } } - #[quickcheck] - pub fn rejected_proposals_are_removed_after_expiration_period( - expiry_block_data: ExpiryBlockDate, - ) -> TestResult { + #[proptest] + fn rejected_proposals_are_removed_after_expiration_period(expiry_block_data: ExpiryBlockDate) { let proposal_date = expiry_block_data.block_date(); let proposal_expiration = expiry_block_data.proposal_expiration(); @@ -861,13 +879,11 @@ mod tests { .expect("error while processing proposal"); if proposal_date.epoch + proposal_expiration <= current_block_date.epoch { - assert_eq!(update_state.proposals.len(), 0); + prop_assert_eq!(update_state.proposals.len(), 0); } else { - assert_eq!(update_state.proposals.len(), 1); + prop_assert_eq!(update_state.proposals.len(), 1); } current_block_date = current_block_date.next_epoch() } - - TestResult::passed() } } diff --git a/chain-impl-mockchain/src/utxo.rs b/chain-impl-mockchain/src/utxo.rs index 380eed119..6662e19aa 100644 --- a/chain-impl-mockchain/src/utxo.rs +++ b/chain-impl-mockchain/src/utxo.rs @@ -285,20 +285,23 @@ impl #[cfg(test)] mod tests { - use super::*; use crate::{ key::Hash, testing::arbitrary::AverageValue, testing::data::AddressData, testing::TestGen, value::Value, }; use chain_addr::{Address, Discrimination}; + use proptest::{collection::hash_map, prelude::*}; use quickcheck::{Arbitrary, Gen, TestResult}; - use quickcheck_macros::quickcheck; use std::collections::HashMap; use std::iter; + use test_strategy::proptest; - #[derive(Clone, Debug)] - pub struct ArbitraryUtxos(HashMap); + #[derive(Clone, Debug, test_strategy::Arbitrary)] + pub struct ArbitraryUtxos( + #[strategy(hash_map(any::(), any::(), 1..=10))] + HashMap, + ); impl Arbitrary for ArbitraryUtxos { fn arbitrary(g: &mut G) -> Self { @@ -327,12 +330,27 @@ mod tests { } } - #[derive(Debug, Clone)] + #[derive(Debug, Clone, test_strategy::Arbitrary)] pub struct ArbitraryTransactionOutputs { + #[strategy(utxos_strategy())] pub utxos: HashMap>, pub idx_to_remove: TransactionIndex, } + fn utxos_strategy() -> impl Strategy>> { + proptest::collection::vec( + any::() + .prop_flat_map(|ad| any::().prop_map(move |value| ad.make_output(value))), // TODO proptest make something similar to AverageValue + 1..=50, + ) + .prop_map(|vec| { + vec.into_iter() + .enumerate() + .map(|(i, item)| (i as u8, item)) + .collect() + }) + } + impl Arbitrary for ArbitraryTransactionOutputs { fn arbitrary(g: &mut G) -> Self { let size = usize::arbitrary(g) % 50 + 1; @@ -379,8 +397,26 @@ mod tests { } } - #[quickcheck] - pub fn transaction_unspent_remove(outputs: ArbitraryTransactionOutputs) -> TestResult { + impl proptest::arbitrary::Arbitrary for Ledger
{ + type Parameters = (); + type Strategy = BoxedStrategy; + + fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { + any::() + .prop_map(|arbitrary_utxos| { + arbitrary_utxos + .0 + .into_iter() + .fold(Ledger::new(), |ledger, (key, value)| { + ledger.add(&key, &value.to_vec().as_slice()).unwrap() + }) + }) + .boxed() + } + } + + #[proptest] + fn transaction_unspent_remove(outputs: ArbitraryTransactionOutputs) { let transaction_unspent = TransactionUnspents::from_outputs(outputs.to_vec().as_slice()); let is_index_correct = transaction_unspent.0.contains_key(outputs.idx_to_remove); match ( @@ -388,25 +424,25 @@ mod tests { is_index_correct, ) { (Ok((transaction_unspent, output)), true) => { - if transaction_unspent.0.contains_key(outputs.idx_to_remove) { - return TestResult::error("Element not removed"); - } + prop_assert!( + !transaction_unspent.0.contains_key(outputs.idx_to_remove), + "Element not removed" + ); - assert_eq!( + prop_assert_eq!( output, outputs.utxos.get(&outputs.idx_to_remove).unwrap().clone(), "Outputs are different" ); - TestResult::passed() } - (Ok(_), false) => TestResult::error("Element removed, while it should not"), - (Err(err), true) => TestResult::error(format!("Unexpected error {}", err)), - (Err(_), false) => TestResult::passed(), + (Ok(_), false) => panic!("Element removed, while it should not"), + (Err(err), true) => panic!(format!("Unexpected error {}", err)), + (Err(_), false) => {} } } - #[quickcheck] - pub fn ledger_iter_values_correctly(initial_utxos: ArbitraryUtxos) -> TestResult { + #[proptest] + fn ledger_iter_values_correctly(initial_utxos: ArbitraryUtxos) { let mut ledger = Ledger::new(); ledger = initial_utxos.fill(ledger); @@ -416,15 +452,14 @@ mod tests { let condition = !ledger.iter().any(|x| { x.fragment_id == key && x.output_index == id && x.output.clone() == output }); - if condition { - return TestResult::error(format!( - "Cannot find item using iter: {:?},{:?}", - key, id - )); - } + prop_assert!( + !condition, + "Cannot find item using iter: {:?},{:?}", + key, + id + ); } } - TestResult::passed() } #[test] diff --git a/chain-impl-mockchain/src/value.rs b/chain-impl-mockchain/src/value.rs index 45032efe8..66919abff 100644 --- a/chain-impl-mockchain/src/value.rs +++ b/chain-impl-mockchain/src/value.rs @@ -7,6 +7,10 @@ use thiserror::Error; /// Unspent transaction value. #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)] +#[cfg_attr( + any(test, feature = "property-test-api"), + derive(test_strategy::Arbitrary) +)] pub struct Value(pub u64); const VALUE_SERIALIZED_SIZE: usize = 8; diff --git a/chain-impl-mockchain/src/vote/choice.rs b/chain-impl-mockchain/src/vote/choice.rs index 23b282d39..74d7a7a0d 100644 --- a/chain-impl-mockchain/src/vote/choice.rs +++ b/chain-impl-mockchain/src/vote/choice.rs @@ -1,4 +1,6 @@ use core::ops::Range; +#[cfg(any(test, feature = "property-test-api"))] +use proptest::prelude::*; use thiserror::Error; /// error that may occur when creating a new `Options` using @@ -17,7 +19,12 @@ pub struct InvalidOptionsLength { /// currently this is a 4bits structure, allowing up to 16 choices /// however we may allow more complex object to be set in #[derive(Debug, Clone, PartialEq, Eq)] +#[cfg_attr( + any(test, feature = "property-test-api"), + derive(test_strategy::Arbitrary) +)] pub struct Options { + #[cfg_attr(any(test, feature = "property-test-api"), strategy((1..=Options::NUM_CHOICES_MAX).prop_map(|choices| 0..choices)))] options_range: Range, } @@ -26,6 +33,10 @@ pub struct Options { /// A `Choice` is a representation of a choice that has been made and must /// be compliant with the `Options`. A way to validate it is with `Options::validate`. #[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)] +#[cfg_attr( + any(test, feature = "property-test-api"), + derive(test_strategy::Arbitrary) +)] pub struct Choice(u8); impl Options { @@ -96,8 +107,8 @@ mod property { #[cfg(test)] mod tests { use super::*; - use quickcheck::TestResult; - use quickcheck_macros::quickcheck; + + use test_strategy::proptest; fn validate_choices(options: &Options, choices: I, expected: bool) where @@ -130,15 +141,15 @@ mod tests { } } - #[quickcheck] - pub fn vote_options_max(num_choices: u8) -> TestResult { + #[proptest] + fn vote_options_max(num_choices: u8) { let options = Options::new_length(num_choices); if num_choices == 0 || num_choices > Options::NUM_CHOICES_MAX { - TestResult::from_bool(options.is_err()) + prop_assert!(options.is_err()); } else { let options = options.expect("non `0` options should always be valid"); - TestResult::from_bool(options.as_byte() == num_choices) + prop_assert_eq!(options.as_byte(), num_choices); } } } diff --git a/chain-impl-mockchain/src/vote/committee.rs b/chain-impl-mockchain/src/vote/committee.rs index 6ce80b74d..321d50507 100644 --- a/chain-impl-mockchain/src/vote/committee.rs +++ b/chain-impl-mockchain/src/vote/committee.rs @@ -16,6 +16,10 @@ use thiserror::Error; /// as well as to use as input for the vote casting payload. /// #[derive(Clone, Copy, PartialEq, Eq, Hash)] +#[cfg_attr( + any(test, feature = "property-test-api"), + derive(test_strategy::Arbitrary) +)] pub struct CommitteeId([u8; CommitteeId::COMMITTEE_ID_SIZE]); impl CommitteeId { @@ -145,8 +149,9 @@ mod tests { use super::*; #[cfg(test)] use chain_core::property::Serialize as _; + use proptest::prelude::*; use quickcheck::{Arbitrary, Gen}; - use quickcheck_macros::quickcheck; + use test_strategy::proptest; impl Arbitrary for CommitteeId { fn arbitrary(g: &mut G) -> Self { @@ -156,27 +161,27 @@ mod tests { } } - #[quickcheck] - fn to_from_hex(committee_id: CommitteeId) -> bool { + #[proptest] + fn to_from_hex(committee_id: CommitteeId) { let s = committee_id.to_hex(); let d = CommitteeId::from_hex(&s).expect("decode hexadecimal committee id"); - committee_id == d + prop_assert_eq!(committee_id, d); } - #[quickcheck] - fn display_parse(committee_id: CommitteeId) -> bool { + #[proptest] + fn display_parse(committee_id: CommitteeId) { let s = committee_id.to_string(); let d = s.parse().expect("decode hexadecimal committee id"); - committee_id == d + prop_assert_eq!(committee_id, d); } - #[quickcheck] - fn serialize_readable(committee_id: CommitteeId) -> bool { + #[proptest] + fn serialize_readable(committee_id: CommitteeId) { let b_got = committee_id.serialize_as_vec().unwrap(); let mut buf = ReadBuf::from(b_got.as_ref()); let result = CommitteeId::read(&mut buf).expect("decode the committee ID"); - committee_id == result + prop_assert_eq!(committee_id, result); } } diff --git a/chain-impl-mockchain/src/vote/manager.rs b/chain-impl-mockchain/src/vote/manager.rs index 0797495f8..06aa15986 100644 --- a/chain-impl-mockchain/src/vote/manager.rs +++ b/chain-impl-mockchain/src/vote/manager.rs @@ -376,7 +376,7 @@ impl ProposalManager { self.check_governance_criteria(total, acceptance, results) } - VoteAction::Parameters { action } => { + VoteAction::LedgerParameters { action } => { let t = action.to_type(); let acceptance = governance.parameters.acceptance_criteria_for(t); @@ -859,13 +859,15 @@ impl VotePlanManager { #[cfg(test)] mod tests { use super::*; + use crate::block::BlockDate; use crate::certificate::TallyProof; - use crate::testing::{TestGen, VoteTestGen}; + use chain_core::property::BlockDate as BlockDateProp; - use quickcheck::TestResult; - use quickcheck_macros::quickcheck; + + use proptest::prelude::*; + use test_strategy::proptest; #[test] pub fn proposal_manager_insert_vote() { @@ -1304,9 +1306,11 @@ mod tests { let _ = proposals.push(VoteTestGen::proposal_with_action(VoteAction::Treasury { action: TreasuryGovernanceAction::TransferToRewards { value: Value(30) }, })); - let _ = proposals.push(VoteTestGen::proposal_with_action(VoteAction::Parameters { - action: ParametersGovernanceAction::RewardAdd { value: Value(30) }, - })); + let _ = proposals.push(VoteTestGen::proposal_with_action( + VoteAction::LedgerParameters { + action: ParametersGovernanceAction::RewardAdd { value: Value(30) }, + }, + )); let vote_plan = VotePlan::new( BlockDate::from_epoch_slot_id(1, 0), @@ -1539,20 +1543,22 @@ mod tests { ); } - #[quickcheck] - pub fn vote_plan_manager_can_vote(vote_plan: VotePlan, date: BlockDate) -> TestResult { + #[proptest] + fn vote_plan_manager_can_vote(vote_plan: VotePlan, date: BlockDate) { let vote_plan_manager = VotePlanManager::new(vote_plan.clone(), HashSet::new()); - TestResult::from_bool( - should_be_in_vote_time(&vote_plan, date) == vote_plan_manager.can_vote(date), - ) + prop_assert_eq!( + should_be_in_vote_time(&vote_plan, date), + vote_plan_manager.can_vote(date) + ); } - #[quickcheck] - pub fn vote_plan_manager_can_committee(vote_plan: VotePlan, date: BlockDate) -> TestResult { + #[proptest] + fn vote_plan_manager_can_committee(vote_plan: VotePlan, date: BlockDate) { let vote_plan_manager = VotePlanManager::new(vote_plan.clone(), HashSet::new()); - TestResult::from_bool( - should_be_in_committee_time(&vote_plan, date) == vote_plan_manager.can_committee(date), - ) + prop_assert_eq!( + should_be_in_committee_time(&vote_plan, date), + vote_plan_manager.can_committee(date) + ); } fn should_be_in_vote_time(vote_plan: &VotePlan, date: BlockDate) -> bool { @@ -1569,13 +1575,13 @@ mod tests { date >= vote_finish_date && date < comittee_end_date } - #[quickcheck] - pub fn vote_plan_manager_plan_elapsed(vote_plan: VotePlan, date: BlockDate) -> TestResult { + #[proptest] + fn vote_plan_manager_plan_elapsed(vote_plan: VotePlan, date: BlockDate) { let vote_plan_manager = VotePlanManager::new(vote_plan.clone(), HashSet::new()); let committee_end_date = vote_plan.committee_end(); let vote_plan_elapsed = committee_end_date < date; - TestResult::from_bool(vote_plan_elapsed == vote_plan_manager.vote_plan_elapsed(date)) + prop_assert_eq!(vote_plan_elapsed, vote_plan_manager.vote_plan_elapsed(date)) } #[test] diff --git a/chain-impl-mockchain/src/vote/payload.rs b/chain-impl-mockchain/src/vote/payload.rs index 967960451..9dbf061af 100644 --- a/chain-impl-mockchain/src/vote/payload.rs +++ b/chain-impl-mockchain/src/vote/payload.rs @@ -17,6 +17,10 @@ use typed_bytes::{ByteArray, ByteBuilder}; /// ``` /// #[derive(Debug, Copy, Clone, PartialEq, Eq, Ord, PartialOrd, Hash)] +#[cfg_attr( + any(test, feature = "property-test-api"), + derive(test_strategy::Arbitrary) +)] #[repr(u8)] pub enum PayloadType { Public = 1, @@ -190,7 +194,9 @@ impl Default for PayloadType { #[cfg(any(test, feature = "property-test-api"))] mod tests { use super::*; + use chain_crypto::testing::TestCryptoGen; use chain_vote::{Crs, ElectionPublicKey}; + use proptest::prelude::*; use quickcheck::{Arbitrary, Gen}; impl Arbitrary for PayloadType { @@ -235,4 +241,45 @@ mod tests { } } } + + pub(crate) fn private_vote_strategy() -> impl Strategy { + any::<(TestCryptoGen, [u8; 32], u32)>().prop_map(|(gen, seed, choice)| { + use chain_vote::{MemberCommunicationKey, MemberState, Vote}; + + let mut gen = gen.get_rng(0); + let mc = MemberCommunicationKey::new(&mut gen); + let threshold = 1; + let h = Crs::from_hash(&seed); + let m = MemberState::new(&mut gen, threshold, &h, &[mc.to_public()], 0); + let participants = vec![m.public_key()]; + let ek = ElectionPublicKey::from_participants(&participants); + let vote_options = 3; + let choice = choice % vote_options; + let (vote, proof) = ek.encrypt_and_prove_vote( + &mut gen, + &h, + Vote::new(vote_options as usize, choice as usize), + ); + Payload::private( + EncryptedVote::from_inner(vote), + ProofOfCorrectVote::from_inner(proof), + ) + }) + } + + impl proptest::arbitrary::Arbitrary for Payload { + type Parameters = (); + type Strategy = BoxedStrategy; + + fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { + any::() + .prop_flat_map(|payload_type| match payload_type { + PayloadType::Public => any::() + .prop_map(|choice| Payload::Public { choice }) + .boxed(), + PayloadType::Private => private_vote_strategy().boxed(), + }) + .boxed() + } + } } diff --git a/chain-impl-mockchain/src/vote/tally.rs b/chain-impl-mockchain/src/vote/tally.rs index e699e29e4..d7888129e 100644 --- a/chain-impl-mockchain/src/vote/tally.rs +++ b/chain-impl-mockchain/src/vote/tally.rs @@ -12,10 +12,18 @@ use thiserror::Error; /// it is often associated to the `stake`. when the tally is counted, /// each vote will have the associated weight encoded in. #[derive(Debug, Default, Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] +#[cfg_attr( + any(test, feature = "property-test-api"), + derive(test_strategy::Arbitrary) +)] pub struct Weight(u64); /// the tally results #[derive(Debug, Clone, PartialEq, Eq)] +#[cfg_attr( + any(test, feature = "property-test-api"), + derive(test_strategy::Arbitrary) +)] pub struct TallyResult { results: Box<[Weight]>, @@ -232,9 +240,10 @@ mod tests { stake::Stake, vote::{Choice, Options}, }; + use proptest::prelude::*; use quickcheck::TestResult; use quickcheck::{Arbitrary, Gen}; - use quickcheck_macros::quickcheck; + use test_strategy::proptest; impl Arbitrary for TallyResult { fn arbitrary(g: &mut G) -> Self { @@ -288,9 +297,9 @@ mod tests { assert_eq!(*tally_result.options(), options); } - #[quickcheck] - pub fn tally(tally_result: TallyResult) -> TestResult { + #[proptest] + fn tally(tally_result: TallyResult) { let tally = Tally::new_public(tally_result.clone()); - TestResult::from_bool(tally.is_public() && (*tally.result().unwrap()) == tally_result) + prop_assert!(tally.is_public() && (*tally.result().unwrap()) == tally_result) } } diff --git a/chain-time/src/timeline.rs b/chain-time/src/timeline.rs index 9a9e59941..64e7f9d63 100644 --- a/chain-time/src/timeline.rs +++ b/chain-time/src/timeline.rs @@ -11,6 +11,10 @@ pub struct TimeOffset(pub(crate) Duration); /// Represent an offset in seconds in the timeline #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[cfg_attr( + any(test, feature = "property-test-api"), + derive(test_strategy::Arbitrary) +)] pub struct TimeOffsetSeconds(pub(crate) DurationSeconds); impl From for Timeline { diff --git a/chain-time/src/units.rs b/chain-time/src/units.rs index ae0eceb86..dcdb7ea3b 100644 --- a/chain-time/src/units.rs +++ b/chain-time/src/units.rs @@ -2,6 +2,10 @@ use std::time::Duration; /// Represent a Duration where the maximum precision is in the second #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[cfg_attr( + any(test, feature = "property-test-api"), + derive(test_strategy::Arbitrary) +)] pub struct DurationSeconds(pub u64); impl From for DurationSeconds { From 03764be89c53e109a19f6c17149e53c2e73dbee8 Mon Sep 17 00:00:00 2001 From: Yevhenii Babichenko Date: Mon, 4 Oct 2021 09:50:03 +0300 Subject: [PATCH 2/2] cargo clippy --fix --- .../src/accounting/account/account_state.rs | 12 +++--- .../src/accounting/account/mod.rs | 41 ++++++++++--------- chain-impl-mockchain/src/block/test.rs | 1 - chain-impl-mockchain/src/certificate/mod.rs | 2 +- chain-impl-mockchain/src/certificate/pool.rs | 2 +- chain-impl-mockchain/src/certificate/test.rs | 1 - chain-impl-mockchain/src/fee.rs | 1 - chain-impl-mockchain/src/fragment/test.rs | 1 - chain-impl-mockchain/src/header/test.rs | 1 - chain-impl-mockchain/src/header/version.rs | 4 +- chain-impl-mockchain/src/key.rs | 3 +- .../src/leadership/genesis/mod.rs | 16 ++++---- chain-impl-mockchain/src/ledger/check.rs | 2 +- chain-impl-mockchain/src/ledger/ledger.rs | 15 ++++--- chain-impl-mockchain/src/ledger/pots.rs | 2 +- chain-impl-mockchain/src/ledger/recovery.rs | 2 +- .../src/ledger/tests/update_tests.rs | 2 +- chain-impl-mockchain/src/multiverse.rs | 2 +- chain-impl-mockchain/src/stake/controlled.rs | 2 +- .../src/stake/distribution.rs | 12 +++--- .../src/testing/serialization.rs | 2 +- chain-impl-mockchain/src/testing/strategy.rs | 1 - chain-impl-mockchain/src/transaction/test.rs | 5 +-- chain-impl-mockchain/src/update.rs | 5 +-- chain-impl-mockchain/src/utxo.rs | 10 ++--- chain-impl-mockchain/src/vote/manager.rs | 29 +++++-------- chain-impl-mockchain/src/vote/tally.rs | 2 +- 27 files changed, 79 insertions(+), 99 deletions(-) diff --git a/chain-impl-mockchain/src/accounting/account/account_state.rs b/chain-impl-mockchain/src/accounting/account/account_state.rs index 0c617d4b9..3e396be5d 100644 --- a/chain-impl-mockchain/src/accounting/account/account_state.rs +++ b/chain-impl-mockchain/src/accounting/account/account_state.rs @@ -47,7 +47,7 @@ pub struct DelegationRatio { } #[cfg(any(test, feature = "property-test-api"))] -fn delegation_ratio_strategy(parts: u8) -> impl Strategy> { +fn delegation_ratio_strategy(_parts: u8) -> impl Strategy> { Just(Vec::new().into_boxed_slice()) // TODO proptest } @@ -265,7 +265,7 @@ mod tests { accounting::account::LedgerError, certificate::PoolId, testing::builders::StakePoolBuilder, value::Value, }; - use quickcheck::{Arbitrary, Gen, TestResult}; + use quickcheck::{Arbitrary, Gen}; use std::iter; use proptest::prelude::*; @@ -442,8 +442,8 @@ mod tests { match (should_fail, account_state.add(value)) { (false, Ok(account_state)) => account_state, (true, Err(_)) => account_state, - (false, Err(err)) => panic!(format!("Operation {}: unexpected add operation failure. Expected success but got: {:?}",counter,err)), - (true, Ok(account_state)) => panic!(format!("Operation {}: unexpected add operation success. Expected failure but got: success. AccountState: {:?}",counter, &account_state)), + (false, Err(err)) => panic!("Operation {}: unexpected add operation failure. Expected success but got: {:?}",counter,err), + (true, Ok(account_state)) => panic!("Operation {}: unexpected add operation success. Expected failure but got: success. AccountState: {:?}",counter, &account_state), } } ArbitraryAccountStateOp::Sub(value) => { @@ -463,8 +463,8 @@ mod tests { } } (true, Err(_)) => account_state, - (false, Err(err)) => panic!(format!("Operation {}: unexpected sub operation failure. Expected success but got: {:?}",counter,err)), - (true, Ok(account_state)) => panic!(format!("Operation {}: unexpected sub operation success. Expected failure but got: success. AccountState: {:?}",counter, &account_state)), + (false, Err(err)) => panic!("Operation {}: unexpected sub operation failure. Expected success but got: {:?}",counter,err), + (true, Ok(account_state)) => panic!("Operation {}: unexpected sub operation success. Expected failure but got: success. AccountState: {:?}",counter, &account_state), } } ArbitraryAccountStateOp::Delegate(stake_pool_id) => { diff --git a/chain-impl-mockchain/src/accounting/account/mod.rs b/chain-impl-mockchain/src/accounting/account/mod.rs index fc7615888..6d91011fc 100644 --- a/chain-impl-mockchain/src/accounting/account/mod.rs +++ b/chain-impl-mockchain/src/accounting/account/mod.rs @@ -229,7 +229,7 @@ mod tests { use crate::{ account::{Identifier, Ledger}, certificate::{PoolId, PoolRegistration}, - testing::{arbitrary::utils as arbitrary_utils, arbitrary::AverageValue, TestGen}, + testing::TestGen, value::Value, }; @@ -238,8 +238,7 @@ mod tests { prelude::*, sample::select, }; - use std::collections::HashSet; - use std::iter; + use test_strategy::proptest; impl proptest::arbitrary::Arbitrary for Ledger { @@ -279,23 +278,25 @@ mod tests { delegations, ) }) - .prop_map(|(arbitrary_accounts, arbitrary_stake_pools, delegations)| { - // TODO proptest arbitrary_stake_pools -- check the original implementation - let mut ledger = Ledger::new(); - - // Add all arbitrary accounts - for (account_id, value) in arbitrary_accounts { - ledger = ledger.add_account(&account_id, value, ()).unwrap(); - } - - for (delegator, delegatee) in delegations { - ledger = ledger - .set_delegation(&delegator, &DelegationType::Full(delegatee)) - .unwrap(); - } - - ledger - }) + .prop_map( + |(arbitrary_accounts, _arbitrary_stake_pools, delegations)| { + // TODO proptest arbitrary_stake_pools -- check the original implementation + let mut ledger = Ledger::new(); + + // Add all arbitrary accounts + for (account_id, value) in arbitrary_accounts { + ledger = ledger.add_account(&account_id, value, ()).unwrap(); + } + + for (delegator, delegatee) in delegations { + ledger = ledger + .set_delegation(&delegator, &DelegationType::Full(delegatee)) + .unwrap(); + } + + ledger + }, + ) .boxed() } } diff --git a/chain-impl-mockchain/src/block/test.rs b/chain-impl-mockchain/src/block/test.rs index 2e81c934c..2699742cc 100644 --- a/chain-impl-mockchain/src/block/test.rs +++ b/chain-impl-mockchain/src/block/test.rs @@ -13,7 +13,6 @@ use crate::{ use chain_core::property::{Block as _, Deserialize, HasHeader as _, Serialize}; use proptest::prelude::*; #[cfg(test)] -use quickcheck::TestResult; use quickcheck::{Arbitrary, Gen}; use test_strategy::proptest; diff --git a/chain-impl-mockchain/src/certificate/mod.rs b/chain-impl-mockchain/src/certificate/mod.rs index 346e4a177..ce79f269b 100644 --- a/chain-impl-mockchain/src/certificate/mod.rs +++ b/chain-impl-mockchain/src/certificate/mod.rs @@ -280,7 +280,7 @@ pub enum SignedCertificate { mod tests { use super::*; use proptest::prelude::*; - use quickcheck::TestResult; + use test_strategy::proptest; #[proptest] diff --git a/chain-impl-mockchain/src/certificate/pool.rs b/chain-impl-mockchain/src/certificate/pool.rs index 3b9eca91f..93f4b1511 100644 --- a/chain-impl-mockchain/src/certificate/pool.rs +++ b/chain-impl-mockchain/src/certificate/pool.rs @@ -806,7 +806,7 @@ mod tests { let auth_data = builder.get_auth_data(); let mut sigs = Vec::new(); for (i, key) in pool_owner_with_sign.indexed_signatories_sks() { - let sig = SingleAccountBindingSignature::new(&auth_data, |d| key.sign_slice(&d.0)); + let sig = SingleAccountBindingSignature::new(&auth_data, |d| key.sign_slice(d.0)); sigs.push((i as u8, sig)) } let pool_owner_signed = PoolOwnersSigned { signatures: sigs }; diff --git a/chain-impl-mockchain/src/certificate/test.rs b/chain-impl-mockchain/src/certificate/test.rs index 7c55eb57c..243be5fc1 100644 --- a/chain-impl-mockchain/src/certificate/test.rs +++ b/chain-impl-mockchain/src/certificate/test.rs @@ -10,7 +10,6 @@ use chain_crypto::{testing, Ed25519}; use chain_time::DurationSeconds; use proptest::prelude::*; #[cfg(test)] -use quickcheck::TestResult; use quickcheck::{Arbitrary, Gen}; use test_strategy::proptest; diff --git a/chain-impl-mockchain/src/fee.rs b/chain-impl-mockchain/src/fee.rs index 5daee30d3..f1ba9d178 100644 --- a/chain-impl-mockchain/src/fee.rs +++ b/chain-impl-mockchain/src/fee.rs @@ -179,7 +179,6 @@ mod test { use crate::certificate::{Certificate, CertificatePayload}; use proptest::prelude::*; #[cfg(test)] - use quickcheck::TestResult; use quickcheck::{Arbitrary, Gen}; use test_strategy::proptest; diff --git a/chain-impl-mockchain/src/fragment/test.rs b/chain-impl-mockchain/src/fragment/test.rs index 68a691260..ddcacdef2 100644 --- a/chain-impl-mockchain/src/fragment/test.rs +++ b/chain-impl-mockchain/src/fragment/test.rs @@ -4,7 +4,6 @@ use crate::config::ConfigParam; use crate::testing::serialization::{serialization_bijection, serialization_bijection_r}; use proptest::prelude::*; #[cfg(test)] -use quickcheck::TestResult; use quickcheck::{Arbitrary, Gen}; use test_strategy::proptest; diff --git a/chain-impl-mockchain/src/header/test.rs b/chain-impl-mockchain/src/header/test.rs index 49169c2fa..23660742a 100644 --- a/chain-impl-mockchain/src/header/test.rs +++ b/chain-impl-mockchain/src/header/test.rs @@ -12,7 +12,6 @@ use chain_crypto::{ use lazy_static::lazy_static; use proptest::prelude::*; #[cfg(test)] -use quickcheck::TestResult; use quickcheck::{Arbitrary, Gen}; use test_strategy::proptest; diff --git a/chain-impl-mockchain/src/header/version.rs b/chain-impl-mockchain/src/header/version.rs index 0c5610a8e..78d611acd 100644 --- a/chain-impl-mockchain/src/header/version.rs +++ b/chain-impl-mockchain/src/header/version.rs @@ -116,7 +116,7 @@ mod tests { use crate::chaintypes::ConsensusType; use crate::header::{AnyBlockVersion, BlockVersion}; use proptest::prelude::*; - use quickcheck::TestResult; + use test_strategy::proptest; #[test] @@ -160,7 +160,7 @@ mod tests { #[proptest] fn conversion_u16(block_version: AnyBlockVersion) { - let bytes: u16 = block_version.clone().into(); + let bytes: u16 = block_version.into(); let new_block_version: AnyBlockVersion = AnyBlockVersion::from(bytes); prop_assert_eq!(block_version, new_block_version); } diff --git a/chain-impl-mockchain/src/key.rs b/chain-impl-mockchain/src/key.rs index 923a603d6..7028cccd9 100644 --- a/chain-impl-mockchain/src/key.rs +++ b/chain-impl-mockchain/src/key.rs @@ -433,8 +433,7 @@ mod tests { use chain_crypto::{testing, PublicKey, RistrettoGroup2HashDh, SecretKey, SumEd25519_12}; use lazy_static::lazy_static; #[cfg(test)] - use quickcheck::TestResult; - use quickcheck::{quickcheck, Arbitrary, Gen}; + use quickcheck::{Arbitrary, Gen}; use test_strategy::proptest; impl Arbitrary for Hash { diff --git a/chain-impl-mockchain/src/leadership/genesis/mod.rs b/chain-impl-mockchain/src/leadership/genesis/mod.rs index c494d97a9..e71660002 100644 --- a/chain-impl-mockchain/src/leadership/genesis/mod.rs +++ b/chain-impl-mockchain/src/leadership/genesis/mod.rs @@ -273,7 +273,7 @@ mod tests { type Pools = HashMap, u64, Stake)>; fn make_leadership_with_pools(ledger: &Ledger, pools: &Pools) -> LeadershipData { - let mut selection = LeadershipData::new(0, &ledger); + let mut selection = LeadershipData::new(0, ledger); for (pool_id, (_, _, value)) in pools { update_stake_pool_total_value(&mut selection, pool_id, *value); @@ -326,7 +326,7 @@ mod tests { let mut any_found = false; for (pool_id, (pool_vrf_private_key, times_selected, _)) in pools.iter_mut() { match selection - .leader(&pool_id, &pool_vrf_private_key, date) + .leader(pool_id, pool_vrf_private_key, date) .unwrap() { None => {} @@ -339,7 +339,7 @@ mod tests { if !any_found { empty_slots += 1; } - date = date.next(&ledger.era()); + date = date.next(ledger.era()); } println!("Calculating percentage of election per pool...."); @@ -420,7 +420,7 @@ mod tests { let mut any_small = false; for (pool_id, (pool_vrf_private_key, times_selected, value)) in pools.iter_mut() { match selection - .leader(&pool_id, &pool_vrf_private_key, date) + .leader(pool_id, pool_vrf_private_key, date) .unwrap() { None => {} @@ -439,7 +439,7 @@ mod tests { if any_small { times_selected_small += 1; } - date = date.next(&ledger.era()); + date = date.next(ledger.era()); } for (pool_id, (_pool_vrf_private_key, times_selected, stake)) in pools.iter_mut() { @@ -488,7 +488,7 @@ mod tests { ); assert!(selection - .leader(&stake_pool.id(), &stake_pool.vrf().private_key(), date) + .leader(&stake_pool.id(), stake_pool.vrf().private_key(), date) .is_err()); } @@ -509,7 +509,7 @@ mod tests { assert_eq!( selection - .leader(&stake_pool.id(), &stake_pool.vrf().private_key(), date) + .leader(&stake_pool.id(), stake_pool.vrf().private_key(), date) .unwrap(), None ); @@ -532,7 +532,7 @@ mod tests { update_stake_pool_total_value(&mut selection, &stake_pool.id(), Stake::zero()); assert!(selection - .leader(&stake_pool.id(), &stake_pool.vrf().private_key(), date) + .leader(&stake_pool.id(), stake_pool.vrf().private_key(), date) .is_err()); } diff --git a/chain-impl-mockchain/src/ledger/check.rs b/chain-impl-mockchain/src/ledger/check.rs index 2014e0910..66bb748d4 100644 --- a/chain-impl-mockchain/src/ledger/check.rs +++ b/chain-impl-mockchain/src/ledger/check.rs @@ -196,7 +196,7 @@ pub fn valid_transaction_date( #[cfg(test)] mod tests { use super::*; - use quickcheck::TestResult; + use test_strategy::proptest; fn test_valid_block0_transaction_no_inputs_for(tx: Transaction

) { diff --git a/chain-impl-mockchain/src/ledger/ledger.rs b/chain-impl-mockchain/src/ledger/ledger.rs index e21828323..92baabe48 100644 --- a/chain-impl-mockchain/src/ledger/ledger.rs +++ b/chain-impl-mockchain/src/ledger/ledger.rs @@ -1708,7 +1708,6 @@ mod tests { //reward::RewardParams, setting::{FeesGoesTo, Settings}, testing::{ - address::ArbitraryAddressDataValueVec, builders::{ witness_builder::{make_witness, make_witnesses}, TestTx, TestTxBuilder, @@ -1860,8 +1859,8 @@ mod tests { .set_ios(&[input], &[]); let witness = make_witness( - &block0_hash, - &address_data, + block0_hash, + address_data, &tx_builder.get_auth_data_for_witness().hash(), ); let witnesses = vec![witness]; @@ -1929,7 +1928,7 @@ mod tests { &block0_hash, &sign_data_hash, &id, - &to_account_witness(&signed_tx.witnesses().iter().next().unwrap()), + to_account_witness(&signed_tx.witnesses().iter().next().unwrap()), value_to_sub, ); assert!(result.is_ok()) @@ -1938,7 +1937,7 @@ mod tests { fn account_ledger_with_initials(initials: &[(Identifier, Value)]) -> account::Ledger { let mut account_ledger = account::Ledger::new(); for (id, initial_value) in initials { - account_ledger = account_ledger.add_account(&id, *initial_value, ()).unwrap(); + account_ledger = account_ledger.add_account(id, *initial_value, ()).unwrap(); } account_ledger } @@ -1965,7 +1964,7 @@ mod tests { &wrong_block0_hash, &sign_data_hash, &id, - &to_account_witness(&signed_tx.witnesses().iter().next().unwrap()), + to_account_witness(&signed_tx.witnesses().iter().next().unwrap()), value_to_sub, ); assert!(result.is_err()) @@ -2000,7 +1999,7 @@ mod tests { &wrong_block0_hash, &sign_data_hash, &id, - &to_account_witness(&signed_tx.witnesses().iter().next().unwrap()), + to_account_witness(&signed_tx.witnesses().iter().next().unwrap()), value_to_sub, ); assert!(result.is_err()) @@ -2029,7 +2028,7 @@ mod tests { &wrong_block0_hash, &sign_data_hash, &non_existing_account.public_key().into(), - &to_account_witness(&signed_tx.witnesses().iter().next().unwrap()), + to_account_witness(&signed_tx.witnesses().iter().next().unwrap()), value_to_sub, ); assert!(result.is_err()) diff --git a/chain-impl-mockchain/src/ledger/pots.rs b/chain-impl-mockchain/src/ledger/pots.rs index 6988104bf..71ad41674 100644 --- a/chain-impl-mockchain/src/ledger/pots.rs +++ b/chain-impl-mockchain/src/ledger/pots.rs @@ -184,7 +184,7 @@ mod tests { use super::*; use crate::value::Value; use proptest::prelude::*; - use quickcheck::{Arbitrary, Gen, TestResult}; + use quickcheck::{Arbitrary, Gen}; use test_strategy::proptest; impl Arbitrary for Pots { diff --git a/chain-impl-mockchain/src/ledger/recovery.rs b/chain-impl-mockchain/src/ledger/recovery.rs index 134719c32..deeeae40a 100644 --- a/chain-impl-mockchain/src/ledger/recovery.rs +++ b/chain-impl-mockchain/src/ledger/recovery.rs @@ -1409,7 +1409,7 @@ pub mod test { { let mut c: Cursor> = Cursor::new(Vec::new()); let mut codec = Codec::new(c); - pack_decl_element(&decl_element, &mut codec)?; + pack_decl_element(decl_element, &mut codec)?; c = codec.into_inner(); c.set_position(0); codec = Codec::new(c); diff --git a/chain-impl-mockchain/src/ledger/tests/update_tests.rs b/chain-impl-mockchain/src/ledger/tests/update_tests.rs index 9a39cb883..62f622f92 100644 --- a/chain-impl-mockchain/src/ledger/tests/update_tests.rs +++ b/chain-impl-mockchain/src/ledger/tests/update_tests.rs @@ -33,7 +33,7 @@ fn ledger_adopt_settings_from_update_proposal(update_proposal_data: UpdatePropos // apply votes for vote in update_proposal_data.votes.iter() { - ledger = ledger.apply_update_vote(&vote).unwrap(); + ledger = ledger.apply_update_vote(vote).unwrap(); } // trigger proposal process (build block) diff --git a/chain-impl-mockchain/src/multiverse.rs b/chain-impl-mockchain/src/multiverse.rs index 83b89d5bd..c2e2372f3 100644 --- a/chain-impl-mockchain/src/multiverse.rs +++ b/chain-impl-mockchain/src/multiverse.rs @@ -326,7 +326,7 @@ mod test { let block_ver = BlockVersion::Ed25519Signed; let contents = Contents::empty(); let header = HeaderBuilderNew::new(block_ver, &contents) - .set_parent(&parent, chain_length) + .set_parent(parent, chain_length) .set_date(date) .into_bft_builder() .unwrap() diff --git a/chain-impl-mockchain/src/stake/controlled.rs b/chain-impl-mockchain/src/stake/controlled.rs index 1b760ca14..f4f0055cc 100644 --- a/chain-impl-mockchain/src/stake/controlled.rs +++ b/chain-impl-mockchain/src/stake/controlled.rs @@ -184,7 +184,7 @@ mod tests { fragment::FragmentId, rewards::Ratio, stake::Stake, - testing::{data::AddressData, utxo::ArbitaryLedgerUtxo, TestGen}, + testing::{data::AddressData, TestGen}, utxo::Ledger, value::Value, }; diff --git a/chain-impl-mockchain/src/stake/distribution.rs b/chain-impl-mockchain/src/stake/distribution.rs index 690cc448e..219958e84 100644 --- a/chain-impl-mockchain/src/stake/distribution.rs +++ b/chain-impl-mockchain/src/stake/distribution.rs @@ -229,9 +229,9 @@ mod tests { use super::*; use crate::account; use crate::accounting::account::DelegationType; - use crate::stake::{delegation::PoolsState, Stake}; + use crate::stake::Stake; use crate::{ - account::{AccountAlg, DelegationRatio, Identifier}, + account::{DelegationRatio, Identifier}, certificate::PoolRegistration, fragment::FragmentId, testing::{ @@ -241,13 +241,11 @@ mod tests { TestGen, }, transaction::{Output, TransactionIndex}, - utxo, value::Value, }; - use chain_addr::{Address, Kind}; - use chain_crypto::PublicKey; - use proptest::prelude::*; - use quickcheck::{Arbitrary, Gen, TestResult}; + use chain_addr::Address; + + use quickcheck::{Arbitrary, Gen}; use test_strategy::proptest; /// Holds all possible cases of distribution source diff --git a/chain-impl-mockchain/src/testing/serialization.rs b/chain-impl-mockchain/src/testing/serialization.rs index ced05f7f9..7f4e89088 100644 --- a/chain-impl-mockchain/src/testing/serialization.rs +++ b/chain-impl-mockchain/src/testing/serialization.rs @@ -1,6 +1,6 @@ use chain_core::mempack::{ReadBuf, Readable}; use chain_core::property::{Deserialize, Serialize}; -use quickcheck::{Arbitrary, TestResult}; +use quickcheck::Arbitrary; use std::fmt::Debug; /// test that any arbitrary given object can serialize and deserialize diff --git a/chain-impl-mockchain/src/testing/strategy.rs b/chain-impl-mockchain/src/testing/strategy.rs index 740eb8095..76de54986 100644 --- a/chain-impl-mockchain/src/testing/strategy.rs +++ b/chain-impl-mockchain/src/testing/strategy.rs @@ -1,5 +1,4 @@ use std::{ - collections::HashSet, convert::TryFrom, fmt::Debug, num::{NonZeroU32, NonZeroU64}, diff --git a/chain-impl-mockchain/src/transaction/test.rs b/chain-impl-mockchain/src/transaction/test.rs index fe14ef25d..4360e9075 100644 --- a/chain-impl-mockchain/src/transaction/test.rs +++ b/chain-impl-mockchain/src/transaction/test.rs @@ -13,7 +13,6 @@ use chain_addr::Address; use chain_crypto::{testing::arbitrary_secret_key, Ed25519, SecretKey, Signature}; use proptest::prelude::*; #[cfg(test)] -use quickcheck::TestResult; use quickcheck::{Arbitrary, Gen}; use test_strategy::proptest; @@ -141,9 +140,7 @@ impl proptest::arbitrary::Arbitrary for Input { type Strategy = proptest::strategy::BoxedStrategy; fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { - any::() - .prop_map(|utxo_pointer| Self::from_utxo(utxo_pointer)) - .boxed() + any::().prop_map(Self::from_utxo).boxed() } } diff --git a/chain-impl-mockchain/src/update.rs b/chain-impl-mockchain/src/update.rs index 0707bd700..0b1be8e1d 100644 --- a/chain-impl-mockchain/src/update.rs +++ b/chain-impl-mockchain/src/update.rs @@ -437,7 +437,6 @@ mod tests { use chain_addr::Discrimination; use proptest::prelude::*; #[cfg(test)] - use quickcheck::TestResult; use quickcheck::{Arbitrary, Gen}; use std::iter; use test_strategy::proptest; @@ -517,7 +516,7 @@ mod tests { .with_proposer_id(proposer.leader_id.clone()) .build(); - update_state.apply_proposal(proposal_id, &signed_update_proposal, &settings, block_date) + update_state.apply_proposal(proposal_id, &signed_update_proposal, settings, block_date) } #[cfg(test)] @@ -532,7 +531,7 @@ mod tests { .with_voter_id(proposer.id()) .build(); - update_state.apply_vote(&signed_update_vote, &settings) + update_state.apply_vote(&signed_update_vote, settings) } #[proptest] diff --git a/chain-impl-mockchain/src/utxo.rs b/chain-impl-mockchain/src/utxo.rs index 6662e19aa..ffd34b73f 100644 --- a/chain-impl-mockchain/src/utxo.rs +++ b/chain-impl-mockchain/src/utxo.rs @@ -292,7 +292,7 @@ mod tests { }; use chain_addr::{Address, Discrimination}; use proptest::{collection::hash_map, prelude::*}; - use quickcheck::{Arbitrary, Gen, TestResult}; + use quickcheck::{Arbitrary, Gen}; use std::collections::HashMap; use std::iter; use test_strategy::proptest; @@ -324,7 +324,7 @@ mod tests { pub fn fill(&self, mut ledger: Ledger

) -> Ledger
{ for (key, value) in self.0.iter() { let utxo = value.to_vec(); - ledger = ledger.add(&key, &utxo.as_slice()).unwrap(); + ledger = ledger.add(key, utxo.as_slice()).unwrap(); } ledger } @@ -391,7 +391,7 @@ mod tests { for (key, value) in arbitrary_utxos.0 { let utxo = value.to_vec(); - ledger = ledger.add(&key, &utxo.as_slice()).unwrap(); + ledger = ledger.add(&key, utxo.as_slice()).unwrap(); } ledger } @@ -408,7 +408,7 @@ mod tests { .0 .into_iter() .fold(Ledger::new(), |ledger, (key, value)| { - ledger.add(&key, &value.to_vec().as_slice()).unwrap() + ledger.add(&key, value.to_vec().as_slice()).unwrap() }) }) .boxed() @@ -436,7 +436,7 @@ mod tests { ); } (Ok(_), false) => panic!("Element removed, while it should not"), - (Err(err), true) => panic!(format!("Unexpected error {}", err)), + (Err(err), true) => panic!("Unexpected error {}", err), (Err(_), false) => {} } } diff --git a/chain-impl-mockchain/src/vote/manager.rs b/chain-impl-mockchain/src/vote/manager.rs index 06aa15986..ee64d1c0b 100644 --- a/chain-impl-mockchain/src/vote/manager.rs +++ b/chain-impl-mockchain/src/vote/manager.rs @@ -874,7 +874,7 @@ mod tests { let vote_plan = VoteTestGen::vote_plan(); let vote_choice = vote::Choice::new(1); let vote_cast_payload = vote::Payload::public(vote_choice); - let vote_cast = VoteCast::new(vote_plan.to_id(), 0, vote_cast_payload.clone()); + let vote_cast = VoteCast::new(vote_plan.to_id(), 0, vote_cast_payload); let mut proposal_manager = ProposalManager::new(vote_plan.proposals().get(0).unwrap()); @@ -909,7 +909,7 @@ mod tests { vote_choice, &mut rng, ); - let vote_cast = VoteCast::new(vote_plan.to_id(), 0, vote_cast_payload.clone()); + let vote_cast = VoteCast::new(vote_plan.to_id(), 0, vote_cast_payload); let identifier = TestGen::unspecified_account_identifier(); @@ -933,7 +933,7 @@ mod tests { let vote_plan = VoteTestGen::private_vote_plan_with_committees_manager(&committee_manager); let vote_choice = vote::Choice::new(1); let vote_cast_payload = vote::Payload::public(vote_choice); - let vote_cast = VoteCast::new(vote_plan.to_id(), 0, vote_cast_payload.clone()); + let vote_cast = VoteCast::new(vote_plan.to_id(), 0, vote_cast_payload); let identifier = TestGen::unspecified_account_identifier(); @@ -1405,7 +1405,7 @@ mod tests { ) { let mut vote_action_hit = false; proposal_managers - .public_tally(&stake_controlled, &governance, |_vote_action| { + .public_tally(stake_controlled, governance, |_vote_action| { vote_action_hit = true; }) .unwrap(); @@ -1418,7 +1418,7 @@ mod tests { ) { let mut vote_action_hit = false; proposal_manager - .public_tally(&stake_controlled, &governance, |_vote_action| { + .public_tally(stake_controlled, governance, |_vote_action| { vote_action_hit = true; }) .unwrap(); @@ -1433,9 +1433,8 @@ mod tests { let first_vote_cast_payload = VoteTestGen::vote_cast_payload_for(&choice); let second_vote_cast_payload = VoteTestGen::vote_cast_payload_for(&choice); - let first_vote_cast = VoteCast::new(vote_plan.to_id(), 0, first_vote_cast_payload.clone()); - let second_vote_cast = - VoteCast::new(vote_plan.to_id(), 1, second_vote_cast_payload.clone()); + let first_vote_cast = VoteCast::new(vote_plan.to_id(), 0, first_vote_cast_payload); + let second_vote_cast = VoteCast::new(vote_plan.to_id(), 1, second_vote_cast_payload); let mut proposal_managers = ProposalManagers::new(&vote_plan); @@ -1445,7 +1444,7 @@ mod tests { .validate_vote(&identifier, first_vote_cast) .unwrap(); let second_vote_cast_validated = proposal_managers - .validate_vote(&identifier, second_vote_cast.clone()) + .validate_vote(&identifier, second_vote_cast) .unwrap(); proposal_managers = proposal_managers @@ -1463,10 +1462,7 @@ mod tests { .iter() .find(|(x, _y)| **x == identifier) .unwrap(); - assert_eq!( - *actual_vote_cast_payload, - ValidatedPayload::Public(choice.clone()) - ); + assert_eq!(*actual_vote_cast_payload, ValidatedPayload::Public(choice)); let (_, actual_vote_cast_payload) = proposal_managers .managers() @@ -1476,10 +1472,7 @@ mod tests { .iter() .find(|(x, _y)| **x == identifier) .unwrap(); - assert_eq!( - *actual_vote_cast_payload, - ValidatedPayload::Public(choice.clone()) - ); + assert_eq!(*actual_vote_cast_payload, ValidatedPayload::Public(choice)); } #[test] @@ -1516,7 +1509,7 @@ mod tests { let second_vote_cast = proposal_managers .validate_vote( &identifier, - VoteCast::new(vote_plan.to_id(), 0, second_vote_cast_payload.clone()), + VoteCast::new(vote_plan.to_id(), 0, second_vote_cast_payload), ) .unwrap(); diff --git a/chain-impl-mockchain/src/vote/tally.rs b/chain-impl-mockchain/src/vote/tally.rs index d7888129e..3e83c59cf 100644 --- a/chain-impl-mockchain/src/vote/tally.rs +++ b/chain-impl-mockchain/src/vote/tally.rs @@ -241,7 +241,7 @@ mod tests { vote::{Choice, Options}, }; use proptest::prelude::*; - use quickcheck::TestResult; + use quickcheck::{Arbitrary, Gen}; use test_strategy::proptest;