diff --git a/Cargo.toml b/Cargo.toml index a7b75c657..572b45bf3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -63,7 +63,7 @@ tokio-console = ["dep:console-subscriber"] aead = { version = "0.5", features = ["std"] } aes-gcm = "0.10" anyhow = { version = "1.0", features = ["backtrace"] } -arbitrary = { version = "1.3", features = ["derive"], optional = true } +arbitrary = { version = "1.4.1", features = ["derive"], optional = true } arraystring = { version = "0.3.0", features = ["serde-traits"] } bech32 = "0.9" bincode = "1.3" @@ -137,7 +137,7 @@ deranged = "=0.4.0" # because they are optional deps but required for unit tests. # please ensure versions match in both sections. -arbitrary = { version = "1.3", features = ["derive"] } +arbitrary = { version = "1.4.1", features = ["derive"] } assert2 = "0.3" blake3 = "1.5.4" clienter = "0.1.1" diff --git a/proptest-regressions/models/blockchain/type_scripts/native_currency_amount.txt b/proptest-regressions/models/blockchain/type_scripts/native_currency_amount.txt new file mode 100644 index 000000000..c12c2e2b3 --- /dev/null +++ b/proptest-regressions/models/blockchain/type_scripts/native_currency_amount.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. +cc 3f3ee95b494c869c3181f96fd00474e6ba18527614a5ed78ea1971ce87755583 # shrinks to a = 182, b = 23598722 diff --git a/proptest-regressions/models/state/wallet/secret_key_material.txt b/proptest-regressions/models/state/wallet/secret_key_material.txt new file mode 100644 index 000000000..720f9d63d --- /dev/null +++ b/proptest-regressions/models/state/wallet/secret_key_material.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. +cc 277a15bc6084663c6a6ca5ccb79ff247ac2ceb1c9df9190e297a5407d9790cdb # shrinks to input = _CatchInconsistentSharesArgs { n: 3, t: 2, s: XFieldElement { coefficients: [BFieldElement(0), BFieldElement(0), BFieldElement(0)] }, seed_a: [0, 0, 244, 79, 87, 114, 45, 179, 177, 244, 48, 86, 13, 124, 232, 44, 114, 56, 37, 104, 131, 49, 17, 176, 238, 9, 36, 2, 255, 172, 170, 164], seed_b: [105, 12, 160, 18, 138, 166, 133, 34, 94, 44, 149, 193, 199, 222, 211, 45, 27, 217, 192, 16, 2, 208, 146, 151, 249, 142, 227, 112, 135, 211, 186, 210], indices: {0: false, 1: false} } +cc 13273dd6ad615cc44297e5514ef8109f23b9e2b39f4cc7055e0bd6970b8f9a7c # shrinks to input = _CatchTooFewSharesToRecombineArgs { n: 5, t: 2, fromindices_remove_num: 1, s: XFieldElement { coefficients: [BFieldElement(15230334930374689589), BFieldElement(13245717797154725729), BFieldElement(16740857572578077618)] }, seed: [130, 153, 93, 131, 38, 88, 103, 106, 175, 19, 242, 51, 163, 35, 186, 36, 186, 163, 207, 131, 104, 241, 159, 14, 87, 231, 150, 32, 77, 98, 183, 235] } +cc 4adcbb9c7a069d655d530e7e2be1501814339a40f70302335c3bc3bc02f5bfbf # shrinks to input = _CatchTooFewSharesToRecombineArgs { n: 13, t: 4, fromindices_take: 3, s: XFieldElement { coefficients: [BFieldElement(2157574511224767603), BFieldElement(3141929367015615680), BFieldElement(12387067636899090808)] }, seed: [158, 233, 166, 68, 118, 192, 184, 5, 160, 160, 32, 2, 49, 118, 161, 53, 13, 117, 40, 21, 10, 226, 142, 231, 56, 29, 166, 205, 41, 60, 14, 209] } diff --git a/proptest-regressions/models/state/wallet/wallet_state.txt b/proptest-regressions/models/state/wallet/wallet_state.txt new file mode 100644 index 000000000..249cf6c7b --- /dev/null +++ b/proptest-regressions/models/state/wallet/wallet_state.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. +cc 402ca26d27a47a5128fd3d326233d47257f118af81a0e3c117ab822482040557 # shrinks to input = _ScanForUtxosAnnouncedToFutureKeysBehavesArgs { kernel: TransactionKernel { inputs: [RemovalRecord { absolute_indices: AbsoluteIndexSet([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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), target_chunks: ChunkDictionary { dictionary: [] } }, RemovalRecord { absolute_indices: AbsoluteIndexSet([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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), target_chunks: ChunkDictionary { dictionary: [] } }, RemovalRecord { absolute_indices: AbsoluteIndexSet([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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), target_chunks: ChunkDictionary { dictionary: [] } }, RemovalRecord { absolute_indices: AbsoluteIndexSet([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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]), target_chunks: ChunkDictionary { dictionary: [] } }, RemovalRecord { absolute_indices: AbsoluteIndexSet([187838372309726231235571735806345927522, 9226786220334241846252289635884635269, 242909590200352974128804381616738152211, 23240027162088295129899252107638977006, 40577974254821571078807612542258114576, 193450773245347110721206293952255357460, 5962001276738947830688190761425465026, 107085777230260037223063748057535750720, 19889412013629443299476738198488709496, 64891266399186012611855783018123387376, 279045832839256296288406995106441046063, 260157076865946884493602271411767820411, 211156026909476312878583743726409612012, 310712666337501391909396197137144162570, 275481586581042193992451908447591801901, 142762771078392141949196074825761410224, 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]), target_chunks: ChunkDictionary { dictionary: [] } }, RemovalRecord { absolute_indices: AbsoluteIndexSet([175418469100345133404740350575071802070, 272769910107593928735555522617862251426, 257950563793706309679217286762672943891, 306950359859040261930928002307912479012, 109232001378306006484387519566305844686, 74077376507589803873145190047741994190, 31857834342535822019947366683323146890, 34045537513010044579786272626200051642, 95655399947054492797781555089411996187, 302808578093559783340984122086787477127, 66236417123645915679239211607669846225, 165001954369676865554101820407805763064, 187594443698106687137408933501175246362, 141102460335779455484983755090504859613, 184105712321826099094193154649796416308, 201652713951815944195541546172031768617, 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]), target_chunks: ChunkDictionary { dictionary: [] } }, RemovalRecord { absolute_indices: AbsoluteIndexSet([241168209829397251931607614465046289271, 110719593706548595226315948201478293706, 271812631793773757242789067198007865012, 116765686220114695055018595024850577257, 114683115280831300051309479761470046770, 255765348109622021159846121295758447941, 76597694249858168520157018613193423646, 286623732834788307737542624350502951854, 230033193962499204261272282310509345143, 279681388558724897232104754997981267712, 68598095929873544901053948914327041150, 67308113298490426337212947678150634762, 156753846948645828932466369401983708202, 258200684535601361052714521856644188812, 142015821703537991858758341143036753194, 287949052080720873923159973568533139023, 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]), target_chunks: ChunkDictionary { dictionary: [] } }, RemovalRecord { absolute_indices: AbsoluteIndexSet([129441033891045505652786488852200865808, 234191578266027970854276568021192978146, 315250261591409015490195154291149818725, 121086034076401468660977837028847617506, 166956423383391314160018293378819172816, 262581991337607049346969142147952379404, 44629695941271100035114316580232453715, 212623159231432590656991869377257210688, 233516393875167957333822190942646222795, 234800566469879276916276767558199815235, 260159297581454686902594913093491718483, 193734306993820971610904414986332765679, 254874230414641052961487812378552257244, 118709581317465554708790149398484054422, 242583260110553004936668586626494092245, 40424310994436305032303378449244077664, 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]), target_chunks: ChunkDictionary { dictionary: [] } }, RemovalRecord { absolute_indices: AbsoluteIndexSet([183090574447426579724462192330993850371, 169542790999861409594673773310759908276, 315934926793961295253404112270994176258, 308828064645528659238268837888615123215, 117222903045028622082386533710574713731, 243510711857579278979361121030702965500, 60806427209762134221138780533478989022, 268677985231353816969047675610050903110, 262805398690549631886742490634362117976, 339850523556943307550265003096035274445, 94573025932686169958595301562059413103, 300028291413977622308902438868984828516, 335721113187447026266052744910439207741, 30031017050094833247947064902099072875, 126500621540309265948394449538783678218, 83200499835080743661474662427553924450, 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]), target_chunks: ChunkDictionary { dictionary: [] } }, RemovalRecord { absolute_indices: AbsoluteIndexSet([111162884348225908818806979888369512547, 122429371577231928707158809536950112212, 155091183694270381314914806582529482211, 111254702168195367096559447918279687406, 258858349904665610573616538543742832213, 25859737672211534955080933026602058854, 222957848010981752218560365198014870000, 253845577511973494993925806283902013474, 88407759222609603987304743323335356071, 57618790152813339292015517318505074412, 295782171393873199192558175956279294769, 199157342447496254479433572689108080006, 205376347357580043561744292827835759419, 316781345433981735308955893435920565604, 96220251277151488926544703968909802995, 96968385780824608423277489024991756118, 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]), target_chunks: ChunkDictionary { dictionary: [] } }], outputs: [AdditionRecord { canonical_commitment: Digest([BFieldElement(15138393705905965074), BFieldElement(5715321146917141858), BFieldElement(2025553880093465485), BFieldElement(16049790255538782644), BFieldElement(13277881995534108432)]) }, AdditionRecord { canonical_commitment: Digest([BFieldElement(13721970016016628679), BFieldElement(10732713227752091409), BFieldElement(13088704052830076240), BFieldElement(241130917557690218), BFieldElement(4663975473028924244)]) }, AdditionRecord { canonical_commitment: Digest([BFieldElement(18195755897583172097), BFieldElement(11759850735424564942), BFieldElement(9269921484503573456), BFieldElement(4070660067091640837), BFieldElement(13801891659688581799)]) }, AdditionRecord { canonical_commitment: Digest([BFieldElement(2997523546133789555), BFieldElement(1027473522163877101), BFieldElement(179684890016590226), BFieldElement(7542938529723859870), BFieldElement(304787421468639630)]) }, AdditionRecord { canonical_commitment: Digest([BFieldElement(4352065421592124754), BFieldElement(2244528857665255421), BFieldElement(2337596514492246790), BFieldElement(11923923154971343092), BFieldElement(4673510892572251134)]) }, AdditionRecord { canonical_commitment: Digest([BFieldElement(6476218278423820985), BFieldElement(11893880339976042844), BFieldElement(14547121449388345308), BFieldElement(6061510556200277294), BFieldElement(16057247281978448546)]) }, AdditionRecord { canonical_commitment: Digest([BFieldElement(11369724667593118055), BFieldElement(15467512033793886483), BFieldElement(10313919546334782116), BFieldElement(14161608839853784995), BFieldElement(3400425475727973453)]) }, AdditionRecord { canonical_commitment: Digest([BFieldElement(11401873493971582711), BFieldElement(8951197665733601418), BFieldElement(15250424005110854153), BFieldElement(16527533783549753988), BFieldElement(15082888871674409439)]) }, AdditionRecord { canonical_commitment: Digest([BFieldElement(10509654249492789565), BFieldElement(720716616330957637), BFieldElement(16544603559993889158), BFieldElement(1662057123039726810), BFieldElement(3167550471252314058)]) }, AdditionRecord { canonical_commitment: Digest([BFieldElement(5210347958558312609), BFieldElement(2306488311175920262), BFieldElement(12869835730636181982), BFieldElement(2428889240933533537), BFieldElement(12755014124847902917)]) }], public_announcements: [PublicAnnouncement { message: [BFieldElement(15884481429022564768)] }, PublicAnnouncement { message: [BFieldElement(14530646945330919691)] }, PublicAnnouncement { message: [BFieldElement(17959760730545003381), BFieldElement(8409104519645579564), BFieldElement(1586358888024711263)] }, PublicAnnouncement { message: [BFieldElement(12095069714697206986), BFieldElement(2031500355379357816), BFieldElement(14640793394426729553), BFieldElement(13522871257528388665), BFieldElement(2570314984734164838)] }, PublicAnnouncement { message: [BFieldElement(8699100688241764292)] }, PublicAnnouncement { message: [BFieldElement(14692730965107593451), BFieldElement(7426871737695424812)] }, PublicAnnouncement { message: [] }, PublicAnnouncement { message: [BFieldElement(17965519443884779700)] }, PublicAnnouncement { message: [] }, PublicAnnouncement { message: [BFieldElement(5103898807170197346)] }], fee: NativeCurrencyAmount(-93307920320214216526854826832718109), coinbase: None, timestamp: Timestamp(BFieldElement(2191574252729573049)), mutator_set_hash: Digest([BFieldElement(5415148282019439692), BFieldElement(7439707642813495188), BFieldElement(9579878639018222932), BFieldElement(3089809536731588947), BFieldElement(3742802823922246365)]), merge_bit: true, mast_sequences: OnceLock() }, seed: [69, 73, 151, 239, 250, 245, 72, 118, 42, 146, 98, 160, 168, 234, 170, 188, 32, 76, 0, 1, 146, 5, 143, 90, 82, 66, 106, 197, 121, 6, 118, 57], wallet_secret: WalletEntropy { secret_seed: SecretKeyMaterial(XFieldElement { coefficients: [BFieldElement(16890398611283121490), BFieldElement(9571449853494202541), BFieldElement(13617511223615987342)] }) }, future_generation_relative_indices: [37, 50, 36, 57, 64, 73, 75, 27, 7, 92, 10, 57, 99, 24, 98, 40, 59, 18, 7, 71], future_symmetric_relative_indices: [38, 16, 75, 50, 5, 95, 89, 63, 84, 72, 20, 58, 19, 18, 97, 88, 51, 87, 14, 79], utxo_vec: [Utxo { lock_script_hash: Digest([BFieldElement(11734473545476664005), BFieldElement(7677170266584541097), BFieldElement(12455566286960229714), BFieldElement(7079023132890078553), BFieldElement(9591878480570904449)]), coins: [Coin { type_script_hash: Digest([BFieldElement(9389679697988060533), BFieldElement(2575304485465387192), BFieldElement(11728035277246680350), BFieldElement(16299950903823737320), BFieldElement(18416311382244266086)]), state: [BFieldElement(5897767532360035245), BFieldElement(13297150867656869820), BFieldElement(9929354350360254675), BFieldElement(322427489802945)] }] }, Utxo { lock_script_hash: Digest([BFieldElement(7119962650343461743), BFieldElement(14566213138128677918), BFieldElement(11754996783891718406), BFieldElement(10848119504848176651), BFieldElement(5291475450388746636)]), coins: [Coin { type_script_hash: Digest([BFieldElement(9389679697988060533), BFieldElement(2575304485465387192), BFieldElement(11728035277246680350), BFieldElement(16299950903823737320), BFieldElement(18416311382244266086)]), state: [BFieldElement(13218597685357845360), BFieldElement(9817536800980277835), BFieldElement(8803532848407744900), BFieldElement(4371885864286155)] }] }, Utxo { lock_script_hash: Digest([BFieldElement(2477930120691769750), BFieldElement(17452891400806100410), BFieldElement(2835871318768418853), BFieldElement(2882557900583871475), BFieldElement(14098627000087751054)]), coins: [Coin { type_script_hash: Digest([BFieldElement(9389679697988060533), BFieldElement(2575304485465387192), BFieldElement(11728035277246680350), BFieldElement(16299950903823737320), BFieldElement(18416311382244266086)]), state: [BFieldElement(16057326159727749870), BFieldElement(16469801774923874955), BFieldElement(8043648804871682055), BFieldElement(1252837664984205)] }] }, Utxo { lock_script_hash: Digest([BFieldElement(11935864088402191293), BFieldElement(10291871606440905097), BFieldElement(11386593850616703524), BFieldElement(13267467131466977163), BFieldElement(14995931812139147046)]), coins: [Coin { type_script_hash: Digest([BFieldElement(9389679697988060533), BFieldElement(2575304485465387192), BFieldElement(11728035277246680350), BFieldElement(16299950903823737320), BFieldElement(18416311382244266086)]), state: [BFieldElement(10969134858391375350), BFieldElement(17330947661078731500), BFieldElement(10075908916617358905), BFieldElement(4990064802022800)] }] }, Utxo { lock_script_hash: Digest([BFieldElement(17811038290460779910), BFieldElement(779494290056410373), BFieldElement(6900300415515338902), BFieldElement(13221596072730154461), BFieldElement(8735279329923530068)]), coins: [Coin { type_script_hash: Digest([BFieldElement(9389679697988060533), BFieldElement(2575304485465387192), BFieldElement(11728035277246680350), BFieldElement(16299950903823737320), BFieldElement(18416311382244266086)]), state: [BFieldElement(3074961266256874245), BFieldElement(6970931167612782345), BFieldElement(11278508499475804230), BFieldElement(1489391578690920)] }] }, Utxo { lock_script_hash: Digest([BFieldElement(17692820064384144335), BFieldElement(15506870095291674475), BFieldElement(18092228782047710295), BFieldElement(8384719699605228129), BFieldElement(5597393581490539449)]), coins: [Coin { type_script_hash: Digest([BFieldElement(9389679697988060533), BFieldElement(2575304485465387192), BFieldElement(11728035277246680350), BFieldElement(16299950903823737320), BFieldElement(18416311382244266086)]), state: [BFieldElement(15636938192572018575), BFieldElement(12496820661837258705), BFieldElement(11973054292179757710), BFieldElement(1722002712420825)] }] }, Utxo { lock_script_hash: Digest([BFieldElement(10819311696754037997), BFieldElement(3929405742030108580), BFieldElement(15791952798763932974), BFieldElement(10373132254748355400), BFieldElement(10120840268595749413)]), coins: [Coin { type_script_hash: Digest([BFieldElement(9389679697988060533), BFieldElement(2575304485465387192), BFieldElement(11728035277246680350), BFieldElement(16299950903823737320), BFieldElement(18416311382244266086)]), state: [BFieldElement(9848327752230614550), BFieldElement(2013038702876442615), BFieldElement(5314191179024184135), BFieldElement(3348996453308955)] }] }, Utxo { lock_script_hash: Digest([BFieldElement(13709285127375675221), BFieldElement(16586374932282083899), BFieldElement(19595851335093008), BFieldElement(9595385629298709339), BFieldElement(16473262284419624496)]), coins: [Coin { type_script_hash: Digest([BFieldElement(9389679697988060533), BFieldElement(2575304485465387192), BFieldElement(11728035277246680350), BFieldElement(16299950903823737320), BFieldElement(18416311382244266086)]), state: [BFieldElement(15493874597207126820), BFieldElement(7752822915626201250), BFieldElement(2945117700485076750), BFieldElement(6275965125243915)] }] }, Utxo { lock_script_hash: Digest([BFieldElement(245301963386940214), BFieldElement(18325413118328715587), BFieldElement(16376641205036471123), BFieldElement(3114083242640856999), BFieldElement(18439398116819779589)]), coins: [Coin { type_script_hash: Digest([BFieldElement(9389679697988060533), BFieldElement(2575304485465387192), BFieldElement(11728035277246680350), BFieldElement(16299950903823737320), BFieldElement(18416311382244266086)]), state: [BFieldElement(1853575994666305140), BFieldElement(16405468228611215760), BFieldElement(15236337569241081780), BFieldElement(3127144212653025)] }] }, Utxo { lock_script_hash: Digest([BFieldElement(11841036193258422933), BFieldElement(11173034642244287704), BFieldElement(1023966289358512928), BFieldElement(13111104056011581754), BFieldElement(4168273693718245693)]), coins: [Coin { type_script_hash: Digest([BFieldElement(9389679697988060533), BFieldElement(2575304485465387192), BFieldElement(11728035277246680350), BFieldElement(16299950903823737320), BFieldElement(18416311382244266086)]), state: [BFieldElement(1391617713372134160), BFieldElement(6472631179465758780), BFieldElement(17620171093731480510), BFieldElement(5841473348779830)] }] }, Utxo { lock_script_hash: Digest([BFieldElement(15167345063029471594), BFieldElement(12742663598087759439), BFieldElement(17163921982923874449), BFieldElement(9727494029413890691), BFieldElement(17625776690114093107)]), coins: [Coin { type_script_hash: Digest([BFieldElement(9389679697988060533), BFieldElement(2575304485465387192), BFieldElement(11728035277246680350), BFieldElement(16299950903823737320), BFieldElement(18416311382244266086)]), state: [BFieldElement(11160089181636486660), BFieldElement(12195224966005906305), BFieldElement(17625404519970372600), BFieldElement(3392556011614845)] }] }, Utxo { lock_script_hash: Digest([BFieldElement(8746357738781804940), BFieldElement(4698206243774298054), BFieldElement(3263591750634794095), BFieldElement(12790817552505221021), BFieldElement(1254114419665860488)]), coins: [Coin { type_script_hash: Digest([BFieldElement(9389679697988060533), BFieldElement(2575304485465387192), BFieldElement(11728035277246680350), BFieldElement(16299950903823737320), BFieldElement(18416311382244266086)]), state: [BFieldElement(4354410883608348255), BFieldElement(10210996886564454510), BFieldElement(6055706523612860160), BFieldElement(3915906366445185)] }] }, Utxo { lock_script_hash: Digest([BFieldElement(17723751257837291665), BFieldElement(1118285294277815055), BFieldElement(8729479629901297304), BFieldElement(13759893068744706797), BFieldElement(185425075377040905)]), coins: [Coin { type_script_hash: Digest([BFieldElement(9389679697988060533), BFieldElement(2575304485465387192), BFieldElement(11728035277246680350), BFieldElement(16299950903823737320), BFieldElement(18416311382244266086)]), state: [BFieldElement(5374218616896680100), BFieldElement(2857744433478582420), BFieldElement(17962002030297491025), BFieldElement(1044201038694990)] }] }, Utxo { lock_script_hash: Digest([BFieldElement(4567596872650868959), BFieldElement(9915530694671305503), BFieldElement(6389617024850346600), BFieldElement(17511509514400840329), BFieldElement(13932111122009741574)]), coins: [Coin { type_script_hash: Digest([BFieldElement(9389679697988060533), BFieldElement(2575304485465387192), BFieldElement(11728035277246680350), BFieldElement(16299950903823737320), BFieldElement(18416311382244266086)]), state: [BFieldElement(2032077760319233035), BFieldElement(1734328929255058695), BFieldElement(14939346301688268720), BFieldElement(1071388181672340)] }] }, Utxo { lock_script_hash: Digest([BFieldElement(12371829086087757802), BFieldElement(462242815113600662), BFieldElement(4536612891079198267), BFieldElement(16399911546340092512), BFieldElement(15670602439261237996)]), coins: [Coin { type_script_hash: Digest([BFieldElement(9389679697988060533), BFieldElement(2575304485465387192), BFieldElement(11728035277246680350), BFieldElement(16299950903823737320), BFieldElement(18416311382244266086)]), state: [BFieldElement(10978452991801340715), BFieldElement(2717763791407845435), BFieldElement(7463703163483953540), BFieldElement(1065306507982620)] }] }, Utxo { lock_script_hash: Digest([BFieldElement(7283589231369400523), BFieldElement(5863920823854357007), BFieldElement(15864981781066739855), BFieldElement(12595592930720887495), BFieldElement(5911269572300400318)]), coins: [Coin { type_script_hash: Digest([BFieldElement(9389679697988060533), BFieldElement(2575304485465387192), BFieldElement(11728035277246680350), BFieldElement(16299950903823737320), BFieldElement(18416311382244266086)]), state: [BFieldElement(17587103895714139695), BFieldElement(16564385480269855530), BFieldElement(13171269112861966470), BFieldElement(901986081622950)] }] }, Utxo { lock_script_hash: Digest([BFieldElement(9568393369862402448), BFieldElement(11607320111817529014), BFieldElement(5215795800631223210), BFieldElement(8968887591096857579), BFieldElement(15117534428142646287)]), coins: [Coin { type_script_hash: Digest([BFieldElement(9389679697988060533), BFieldElement(2575304485465387192), BFieldElement(11728035277246680350), BFieldElement(16299950903823737320), BFieldElement(18416311382244266086)]), state: [BFieldElement(12331686934645378065), BFieldElement(10895062692780635700), BFieldElement(17262290968190649810), BFieldElement(4389709978560405)] }] }, Utxo { lock_script_hash: Digest([BFieldElement(15976124532632988373), BFieldElement(5687745959464227142), BFieldElement(14456278147456037710), BFieldElement(1531310930972148408), BFieldElement(3052958342681777759)]), coins: [Coin { type_script_hash: Digest([BFieldElement(9389679697988060533), BFieldElement(2575304485465387192), BFieldElement(11728035277246680350), BFieldElement(16299950903823737320), BFieldElement(18416311382244266086)]), state: [BFieldElement(4712639189262882720), BFieldElement(5343579986661460560), BFieldElement(10069341366162457440), BFieldElement(5113493572146510)] }] }, Utxo { lock_script_hash: Digest([BFieldElement(13911616883398034605), BFieldElement(3984697902022180803), BFieldElement(17901719722460382830), BFieldElement(823670782254500416), BFieldElement(17574864989999429791)]), coins: [Coin { type_script_hash: Digest([BFieldElement(9389679697988060533), BFieldElement(2575304485465387192), BFieldElement(11728035277246680350), BFieldElement(16299950903823737320), BFieldElement(18416311382244266086)]), state: [BFieldElement(1669209030265259835), BFieldElement(4839129390599632245), BFieldElement(5895368458118328735), BFieldElement(8251542706761540)] }] }, Utxo { lock_script_hash: Digest([BFieldElement(363888290493451795), BFieldElement(9115867029071007844), BFieldElement(2852013117172031762), BFieldElement(18115823597811017002), BFieldElement(16920360529545888455)]), coins: [Coin { type_script_hash: Digest([BFieldElement(9389679697988060533), BFieldElement(2575304485465387192), BFieldElement(11728035277246680350), BFieldElement(16299950903823737320), BFieldElement(18416311382244266086)]), state: [BFieldElement(13852457265220693890), BFieldElement(5055087076405983510), BFieldElement(7471460926685710815), BFieldElement(2706314727154335)] }] }], sender_randomness_vec: [Digest([BFieldElement(5747088673301216186), BFieldElement(7977124451401782407), BFieldElement(12425069662800007599), BFieldElement(6121625294358946499), BFieldElement(5477320185323967101)]), Digest([BFieldElement(1925077999830021366), BFieldElement(3572598872997198046), BFieldElement(1062369364184447771), BFieldElement(2624065246285650475), BFieldElement(419920320083311207)]), Digest([BFieldElement(808275572345802395), BFieldElement(6898629439172047241), BFieldElement(8354826649539910770), BFieldElement(2205439478736587548), BFieldElement(6748981776329378901)]), Digest([BFieldElement(9966160607560851334), BFieldElement(1309151645912403190), BFieldElement(8335373411816875410), BFieldElement(4292223795756972686), BFieldElement(1492321666954243262)]), Digest([BFieldElement(7838805749636362117), BFieldElement(4653937131634109957), BFieldElement(17233998096205515112), BFieldElement(18251662178563028011), BFieldElement(11661543842446541711)]), Digest([BFieldElement(17414742708430093292), BFieldElement(11816091043148264046), BFieldElement(15166931317683292668), BFieldElement(7108116136623633235), BFieldElement(6735567016855495337)]), Digest([BFieldElement(8642910076157803741), BFieldElement(1875525860871731278), BFieldElement(1162692585963605943), BFieldElement(440110694427328648), BFieldElement(8529918667945540508)]), Digest([BFieldElement(9209397049507079480), BFieldElement(7378832539145507279), BFieldElement(3279206518674012882), BFieldElement(9993146145482047117), BFieldElement(12729204313108320580)]), Digest([BFieldElement(17517977570843957872), BFieldElement(8420680942085863224), BFieldElement(4741247189359113897), BFieldElement(5146811484050370056), BFieldElement(6719559202806769433)]), Digest([BFieldElement(6535751324896135176), BFieldElement(8726359489233160885), BFieldElement(7640113069829722593), BFieldElement(4562310003713972996), BFieldElement(16598144122201055832)]), Digest([BFieldElement(6427735710700277247), BFieldElement(856519272226235404), BFieldElement(18267488601518833913), BFieldElement(938006444291125934), BFieldElement(2498139440143212629)]), Digest([BFieldElement(16937340131562112380), BFieldElement(5386502772550088066), BFieldElement(2835483515799109264), BFieldElement(15858612749312694266), BFieldElement(4169512735355753812)]), Digest([BFieldElement(10128910114555968873), BFieldElement(16505174014348653269), BFieldElement(9358828218035675507), BFieldElement(4354008187519117651), BFieldElement(14512348877499117929)]), Digest([BFieldElement(6990579304681817945), BFieldElement(16016819117726508447), BFieldElement(10661214258393202001), BFieldElement(12241211707341822922), BFieldElement(5898476166672869980)]), Digest([BFieldElement(11831276057043488560), BFieldElement(8758742214565918736), BFieldElement(1662566778540774205), BFieldElement(29407807284821101), BFieldElement(16019148757976447913)]), Digest([BFieldElement(9719360883831230484), BFieldElement(16426633543929286588), BFieldElement(3111699313826798668), BFieldElement(7248160669051780205), BFieldElement(397874815626414586)]), Digest([BFieldElement(1948296933211069916), BFieldElement(16407226024735237131), BFieldElement(262061898754450642), BFieldElement(14294241742153658928), BFieldElement(10699896366419796152)]), Digest([BFieldElement(6763801540818757270), BFieldElement(2124111077709407906), BFieldElement(16991237853108216072), BFieldElement(9944839863551780313), BFieldElement(3654458104542604145)]), Digest([BFieldElement(17320828767316352408), BFieldElement(12618763962435341019), BFieldElement(6343796670928240675), BFieldElement(5213108852818203113), BFieldElement(2389012384420863286)]), Digest([BFieldElement(3868230134277491786), BFieldElement(18196693393072206809), BFieldElement(2096361811796605292), BFieldElement(7169143980154516466), BFieldElement(1236814746982532873)])], select_vec: [true, true, true, false, true, false, false, true, false, true, true, true, true, true, false, false, true, true, false, false] } diff --git a/proptest-regressions/rpc_server.txt b/proptest-regressions/rpc_server.txt new file mode 100644 index 000000000..e17385246 --- /dev/null +++ b/proptest-regressions/rpc_server.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. +cc 9a1b149fba15483e9f31a7852760ce8d5df51e9d38b2126f1ddaec0825d1384d # shrinks to input = _PublicAnnouncementsInBlockTestArgs { tx_block1: TransactionKernel { inputs: [], outputs: [AdditionRecord { canonical_commitment: Digest([BFieldElement(0), BFieldElement(0), BFieldElement(0), BFieldElement(0), BFieldElement(0)]) }, AdditionRecord { canonical_commitment: Digest([BFieldElement(0), BFieldElement(0), BFieldElement(0), BFieldElement(0), BFieldElement(0)]) }], public_announcements: [PublicAnnouncement { message: [] }, PublicAnnouncement { message: [] }, PublicAnnouncement { message: [] }, PublicAnnouncement { message: [] }, PublicAnnouncement { message: [] }, PublicAnnouncement { message: [BFieldElement(67425554709697360)] }, PublicAnnouncement { message: [] }], fee: NativeCurrencyAmount(-70685956793913118433183217491150354), coinbase: Some(NativeCurrencyAmount(-7927620070728119810108028777943770)), timestamp: Timestamp(BFieldElement(4891014318722709738)), mutator_set_hash: Digest([BFieldElement(11934671718491951346), BFieldElement(11281373832596201266), BFieldElement(11355207949940880926), BFieldElement(3448036920268554380), BFieldElement(18323932419006503564)]), merge_bit: false, mast_sequences: OnceLock() } } +cc a41693db527e06e59a7f2be3b95304c4cef3e750a99a405319ee6554c48d297b # shrinks to input = _PublicAnnouncementsInBlockTestArgs { tx_block1: TransactionKernel { inputs: [], outputs: [AdditionRecord { canonical_commitment: Digest([BFieldElement(0), BFieldElement(0), BFieldElement(0), BFieldElement(0), BFieldElement(0)]) }, AdditionRecord { canonical_commitment: Digest([BFieldElement(0), BFieldElement(0), BFieldElement(0), BFieldElement(0), BFieldElement(0)]) }], public_announcements: [PublicAnnouncement { message: [BFieldElement(0), BFieldElement(9321591543486476998), BFieldElement(14573288706066622957), BFieldElement(9270886323901199519), BFieldElement(6734302117330064099), BFieldElement(16315627936601254197), BFieldElement(1178352053662224171), BFieldElement(8562213646120173239), BFieldElement(14793640925920860846), BFieldElement(7689510137104745238)] }, PublicAnnouncement { message: [BFieldElement(5850826884696472421), BFieldElement(10698350416477277912), BFieldElement(13415571233392094868), BFieldElement(9369934884966037034), BFieldElement(1662925058444927082), BFieldElement(7719516251173924890), BFieldElement(5373964820120010726), BFieldElement(10610712547096075267), BFieldElement(11399396361836030022), BFieldElement(13510348934276136326), BFieldElement(9085767833742476303), BFieldElement(5723913007932892529), BFieldElement(14231465034676843008), BFieldElement(6743161496293035502), BFieldElement(2749227069055044627), BFieldElement(18036348259610191480), BFieldElement(5492289514897661826), BFieldElement(1816896152465294170), BFieldElement(11544661119781190865), BFieldElement(12871712508422676972), BFieldElement(5126909686560286199), BFieldElement(4106022111572319076), BFieldElement(4065245845049566976), BFieldElement(8435945931257478577), BFieldElement(581043917489909685), BFieldElement(15460116745659416903), BFieldElement(11595981507090494167), BFieldElement(10449461704944053966), BFieldElement(2348631313570448087), BFieldElement(9927913115758177289), BFieldElement(2633819268146899658), BFieldElement(10669540681299957084), BFieldElement(5013673220773961496), BFieldElement(3948526355233602916), BFieldElement(998937149810993859), BFieldElement(3130813340322589295), BFieldElement(16942730675331240903), BFieldElement(6739880786431782644), BFieldElement(1658810169485282839), BFieldElement(4680543269938070822), BFieldElement(4635403039071193656), BFieldElement(9284534826280127145), BFieldElement(9668509141778854314), BFieldElement(18154100913628760140), BFieldElement(6790729872447145021), BFieldElement(11405845389050366412), BFieldElement(2148834898663828983), BFieldElement(10394265723755212783), BFieldElement(6493915292875594243), BFieldElement(12365884486086245291), BFieldElement(17067169933775367752), BFieldElement(5940587059403139278), BFieldElement(5126795535245805706), BFieldElement(968779048322462424), BFieldElement(16406133146074705194), BFieldElement(12848833384879852395), BFieldElement(17404328651326943881)] }, PublicAnnouncement { message: [BFieldElement(7594660911295056224), BFieldElement(9005093803197862104), BFieldElement(15025730599736576353), BFieldElement(7914242664642492317), BFieldElement(12018369970623897564), BFieldElement(9872731862978059190), BFieldElement(13894353222482954917), BFieldElement(5477190326445056532), BFieldElement(15805830104178530499), BFieldElement(18290222969886878371), BFieldElement(5809929793795126022), BFieldElement(14375298667674961713), BFieldElement(4708049240228224037), BFieldElement(7418504464344747364), BFieldElement(3933733290989638003), BFieldElement(481998146018717127), BFieldElement(12284253152957971365), BFieldElement(15386012654265221971), BFieldElement(13095150001978380178), BFieldElement(295382796281590133), BFieldElement(8620366749541598725), BFieldElement(1304791959912836792), BFieldElement(15032448768365563164), BFieldElement(5739589016008141687), BFieldElement(13327138790541052286), BFieldElement(15815768633216926923), BFieldElement(6870536856369804543), BFieldElement(13847281322079990768), BFieldElement(17867324372895401144), BFieldElement(7460365984828993082), BFieldElement(12571143625909199848), BFieldElement(3658343088136045555), BFieldElement(8268888862926619393), BFieldElement(14224805658164422154), BFieldElement(16285394648147870757)] }, PublicAnnouncement { message: [BFieldElement(7439523716026445599), BFieldElement(16506073198336684448), BFieldElement(8705287737056517607), BFieldElement(8231651265310199470), BFieldElement(8882080563348816394), BFieldElement(10981566394564037466), BFieldElement(9944193038408968910), BFieldElement(2673945369351400012), BFieldElement(18410912251055652393), BFieldElement(13529496378182984936), BFieldElement(17507505312805448836), BFieldElement(17093662154025067297), BFieldElement(13577695661611463010), BFieldElement(14027539052546300427), BFieldElement(14320401750441668324), BFieldElement(4642063197896523367), BFieldElement(11435512758271904425), BFieldElement(3594000353401027283), BFieldElement(12948518030387709580), BFieldElement(13872249565484404042), BFieldElement(13711630440439798972), BFieldElement(3055460397186942638), BFieldElement(4471839359132047087), BFieldElement(7252155648573431983), BFieldElement(15488590433812695552), BFieldElement(3073337756105039874), BFieldElement(17524778332946899191), BFieldElement(2992524196386455437), BFieldElement(2680138085677036979), BFieldElement(4833235556042958219), BFieldElement(12699725177376044034), BFieldElement(10023777893194050836), BFieldElement(15269608515504270087), BFieldElement(1068170828386830562), BFieldElement(4028999331936546181), BFieldElement(5058503403519597591), BFieldElement(18155019592594960458), BFieldElement(4673416853673096741), BFieldElement(18193416338625244637), BFieldElement(15033419402450607093), BFieldElement(2820245543402743989), BFieldElement(1287191723978980010), BFieldElement(3163286325826709282), BFieldElement(12820804990350095894), BFieldElement(5974568893285562216), BFieldElement(5229511236206493934), BFieldElement(7531764728822743164), BFieldElement(13540153938888160563), BFieldElement(16591155923905484307), BFieldElement(15548338335182666774), BFieldElement(2907711232935622352), BFieldElement(13364481892358474264), BFieldElement(3324677873674596074), BFieldElement(7924880984895465917), BFieldElement(15828564237640882969)] }, PublicAnnouncement { message: [BFieldElement(3165922451199185807), BFieldElement(9189718261240953031), BFieldElement(17776659556933552908), BFieldElement(1311034704645877024), BFieldElement(5202296038206071929), BFieldElement(7411088882245642516), BFieldElement(14558620641619267447), BFieldElement(10675027321315435128), BFieldElement(598665310789595969), BFieldElement(7819087183872051628), BFieldElement(12056578678418623332), BFieldElement(6486259572712224753), BFieldElement(826095746329047719)] }, PublicAnnouncement { message: [BFieldElement(10724539382916705974), BFieldElement(1303220643318753185), BFieldElement(9473115488117201169), BFieldElement(18414856417842107025), BFieldElement(13025091628248206563), BFieldElement(17528284268534257198), BFieldElement(5429883350585155873), BFieldElement(556130114172974692), BFieldElement(961897794049784841), BFieldElement(8967399253274453237), BFieldElement(8717640694119776425), BFieldElement(3407239960751345411), BFieldElement(11910891741869293262), BFieldElement(3089303601062184614), BFieldElement(6412325466307238772), BFieldElement(13520523155363096809), BFieldElement(13210311521673699752), BFieldElement(14313262878921039267), BFieldElement(16375763654579367188), BFieldElement(10723868226945010993), BFieldElement(17899760067805144176), BFieldElement(6796570027146899127), BFieldElement(9843358327620200645), BFieldElement(10878971082324431167), BFieldElement(17633750723062498615), BFieldElement(5423225153423790055)] }, PublicAnnouncement { message: [BFieldElement(15063874826012908280), BFieldElement(11794845301655914544), BFieldElement(68103292217826961), BFieldElement(7664254457830799794), BFieldElement(9752717190870353867), BFieldElement(7707108688065508978), BFieldElement(11616340567884692049), BFieldElement(8311508965875839190), BFieldElement(4761161030291574899), BFieldElement(1008348757178514264), BFieldElement(9372206087471090780), BFieldElement(2077983553569022931), BFieldElement(7138630344912605983), BFieldElement(8851221038629380645), BFieldElement(13851104793546852152), BFieldElement(12508746294651885015), BFieldElement(3522013474798245655), BFieldElement(12931322237949325250), BFieldElement(10615197952485630066), BFieldElement(14073208853836752003), BFieldElement(17723075682634902071), BFieldElement(5864566181164094734)] }], fee: NativeCurrencyAmount(-80189601208177427720452833441052689), coinbase: None, timestamp: Timestamp(BFieldElement(81953083721190621)), mutator_set_hash: Digest([BFieldElement(1209579961828006965), BFieldElement(17845347245891483320), BFieldElement(8689404300665274380), BFieldElement(12557353202409237661), BFieldElement(10895426204171946523)]), merge_bit: true, mast_sequences: OnceLock() } } diff --git a/proptest-regressions/util_types/mutator_set/removal_record.txt b/proptest-regressions/util_types/mutator_set/removal_record.txt new file mode 100644 index 000000000..7f11ee5f5 --- /dev/null +++ b/proptest-regressions/util_types/mutator_set/removal_record.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. +cc beb87393cd159b94e90456b0d4ed98d512823341049f1e2470baf26dc6444b05 # shrinks to input = _RemovalRecordMissingChunkElementIsInvalidPbtArgs { initial_additions: 33, index_to_drop: 14, to_remove_rand: 94615430264692362 } +cc 188cbdc2fcf5f21fdde330e2184199074a1488a21447491a0a2a6659913eda64 # shrinks to input = _RemovalRecordMissingChunkElementIsInvalidPbtArgs { initial_additions: 38, index_to_drop: 2, to_remove_rand: 792244780276861568 } +cc 43e028e16e3a6e23838fdb9ab81b37b5e6b06979332cd7661363e7f42bfa4e00 # shrinks to input = _RemovalRecordMissingChunkElementIsInvalidPbtArgs { initial_additions: 68, index_to_drop: 4, to_remove_rand: 22 } diff --git a/src/api/api_impl.rs b/src/api/api_impl.rs index 465235729..b29307039 100644 --- a/src/api/api_impl.rs +++ b/src/api/api_impl.rs @@ -58,12 +58,12 @@ impl Api { } /// retrieve a transaction recipient in mutable context. - pub fn wallet_mut(&mut self) -> api::wallet::Wallet { + pub fn wallet_mut(&mut self) -> api::wallet::Wallet<'_> { self.global_state_lock.clone().into() } /// retrieve a transaction recipient in immutable context. - pub fn wallet(&self) -> api::wallet::Wallet { + pub fn wallet(&self) -> api::wallet::Wallet<'_> { self.global_state_lock.clone().into() } } diff --git a/src/bin/dashboard_src/dashboard_app.rs b/src/bin/dashboard_src/dashboard_app.rs index 3d134fa50..576f36fb5 100644 --- a/src/bin/dashboard_src/dashboard_app.rs +++ b/src/bin/dashboard_src/dashboard_app.rs @@ -287,7 +287,7 @@ impl DashboardApp { Ok(()) } - pub fn current_screen(&mut self) -> RefMut { + pub fn current_screen(&mut self) -> RefMut<'_, dyn Screen> { self.screens .get(&self.current_menu_item) .unwrap() diff --git a/src/database/leveldb.rs b/src/database/leveldb.rs index 7bf60faa7..c74cb1d38 100644 --- a/src/database/leveldb.rs +++ b/src/database/leveldb.rs @@ -327,7 +327,7 @@ impl<'a> Iterable<'a> for DbIntMut { } impl Snapshots for DbIntMut { - fn snapshot(&self) -> Snapshot { + fn snapshot(&self) -> Snapshot<'_> { self.db.as_ref().unwrap().snapshot() } } @@ -567,7 +567,7 @@ impl<'a> Iterable<'a> for DB { } impl Snapshots for DB { - fn snapshot(&self) -> Snapshot { + fn snapshot(&self) -> Snapshot<'_> { self.0.snapshot() } } diff --git a/src/locks/std/atomic_mutex.rs b/src/locks/std/atomic_mutex.rs index b5529487a..f59964bef 100644 --- a/src/locks/std/atomic_mutex.rs +++ b/src/locks/std/atomic_mutex.rs @@ -225,7 +225,7 @@ impl AtomicMutex { /// let atomic_car = AtomicMutex::from(Car{year: 2016}); /// let year = atomic_car.lock_guard().year; /// ``` - pub fn lock_guard(&self) -> AtomicMutexGuard { + pub fn lock_guard(&self) -> AtomicMutexGuard<'_, T> { self.try_acquire_read_cb(); let guard = self.inner.lock().expect("Read lock should succeed"); AtomicMutexGuard::new(guard, &self.lock_callback_info, LockAcquisition::Read) @@ -242,7 +242,7 @@ impl AtomicMutex { /// let mut atomic_car = AtomicMutex::from(Car{year: 2016}); /// atomic_car.lock_guard_mut().year = 2022; /// ``` - pub fn lock_guard_mut(&mut self) -> AtomicMutexGuard { + pub fn lock_guard_mut(&mut self) -> AtomicMutexGuard<'_, T> { self.try_acquire_write_cb(); let guard = self.inner.lock().expect("Write lock should succeed"); AtomicMutexGuard::new(guard, &self.lock_callback_info, LockAcquisition::Write) diff --git a/src/locks/std/atomic_rw.rs b/src/locks/std/atomic_rw.rs index e8d1be349..b57f5bcea 100644 --- a/src/locks/std/atomic_rw.rs +++ b/src/locks/std/atomic_rw.rs @@ -209,7 +209,7 @@ impl AtomicRw { /// let atomic_car = AtomicRw::from(Car{year: 2016}); /// let year = atomic_car.lock_guard().year; /// ``` - pub fn lock_guard(&self) -> AtomicRwReadGuard { + pub fn lock_guard(&self) -> AtomicRwReadGuard<'_, T> { self.try_acquire_read_cb(); let guard = self.inner.read().expect("Read lock should succeed"); AtomicRwReadGuard::new(guard, &self.lock_callback_info) @@ -226,7 +226,7 @@ impl AtomicRw { /// let mut atomic_car = AtomicRw::from(Car{year: 2016}); /// atomic_car.lock_guard_mut().year = 2022; /// ``` - pub fn lock_guard_mut(&mut self) -> AtomicRwWriteGuard { + pub fn lock_guard_mut(&mut self) -> AtomicRwWriteGuard<'_, T> { self.try_acquire_write_cb(); let guard = self.inner.write().expect("Write lock should succeed"); AtomicRwWriteGuard::new(guard, &self.lock_callback_info) diff --git a/src/locks/tokio/atomic_mutex.rs b/src/locks/tokio/atomic_mutex.rs index ab41d5c76..6e956a1d2 100644 --- a/src/locks/tokio/atomic_mutex.rs +++ b/src/locks/tokio/atomic_mutex.rs @@ -217,7 +217,7 @@ impl AtomicMutex { /// # }) /// ``` #[cfg_attr(feature = "track-lock-location", track_caller)] - pub async fn lock_guard(&self) -> AtomicMutexGuard { + pub async fn lock_guard(&self) -> AtomicMutexGuard<'_, T> { self.try_acquire_read_cb(); let try_acquire_at = now(); @@ -233,7 +233,7 @@ impl AtomicMutex { /// Attempt to return a read lock and return an `AtomicMutextGuard`. Returns /// an error if the lock is already held, otherwise returns Ok(lock). #[cfg_attr(feature = "track-lock-location", track_caller)] - pub fn try_lock_guard(&self) -> Result, tokio::sync::TryLockError> { + pub fn try_lock_guard(&self) -> Result, tokio::sync::TryLockError> { self.try_acquire_try_acquire(); let try_acquire_at = now(); @@ -260,7 +260,7 @@ impl AtomicMutex { /// # }) /// ``` #[cfg_attr(feature = "track-lock-location", track_caller)] - pub async fn lock_guard_mut(&mut self) -> AtomicMutexGuard { + pub async fn lock_guard_mut(&mut self) -> AtomicMutexGuard<'_, T> { self.try_acquire_write_cb(); let try_acquire_at = now(); diff --git a/src/locks/tokio/atomic_rw.rs b/src/locks/tokio/atomic_rw.rs index 8207d97ba..022a4fc97 100644 --- a/src/locks/tokio/atomic_rw.rs +++ b/src/locks/tokio/atomic_rw.rs @@ -226,7 +226,7 @@ impl AtomicRw { /// # }) ///``` #[cfg_attr(feature = "track-lock-location", track_caller)] - pub async fn lock_guard(&self) -> AtomicRwReadGuard { + pub async fn lock_guard(&self) -> AtomicRwReadGuard<'_, T> { self.try_acquire_read_cb(); let try_acquire_at = now(); @@ -248,7 +248,7 @@ impl AtomicRw { /// # }) /// ``` #[cfg_attr(feature = "track-lock-location", track_caller)] - pub async fn lock_guard_mut(&mut self) -> AtomicRwWriteGuard { + pub async fn lock_guard_mut(&mut self) -> AtomicRwWriteGuard<'_, T> { self.try_acquire_write_cb(); let try_acquire_at = now(); @@ -260,7 +260,7 @@ impl AtomicRw { /// /// If the lock cannot be acquired without waiting, an error is returned. #[cfg_attr(feature = "track-lock-location", track_caller)] - pub fn try_lock_guard_mut(&mut self) -> Result, TryLockError> { + pub fn try_lock_guard_mut(&mut self) -> Result, TryLockError> { self.try_acquire_write_cb(); let try_acquire_at = now(); diff --git a/src/main_loop/proof_upgrader.rs b/src/main_loop/proof_upgrader.rs index 58f353a07..1c701d634 100644 --- a/src/main_loop/proof_upgrader.rs +++ b/src/main_loop/proof_upgrader.rs @@ -1141,7 +1141,8 @@ mod tests { tx_proving_capability: Some(TxProvingCapability::SingleProof), ..Default::default() }; - let mut alice = state_with_premine_and_self_mined_blocks(cli_args, &mut rng, 1).await; + let mut alice = + state_with_premine_and_self_mined_blocks(cli_args, rng.random::<[Digest; 1]>()).await; let mut transactions = vec![]; for _ in 0..=1 { @@ -1193,9 +1194,9 @@ mod tests { let block2 = fake_block_successor_with_merged_tx( &block1, now, - rng.random(), false, vec![mined_tx.into()], + rng.random(), network, ) .await; diff --git a/src/mine_loop.rs b/src/mine_loop.rs index d0d466680..c8f682701 100644 --- a/src/mine_loop.rs +++ b/src/mine_loop.rs @@ -1061,6 +1061,7 @@ pub(crate) async fn mine( pub(crate) mod tests { use std::hint::black_box; + use arbitrary::Arbitrary; use block_appendix::BlockAppendix; use block_body::BlockBody; use block_header::tests::random_block_header; @@ -1071,6 +1072,7 @@ pub(crate) mod tests { use num_traits::One; use num_traits::Pow; use num_traits::Zero; + use rand::RngCore; use tracing_test::traced_test; use super::*; @@ -1080,6 +1082,7 @@ pub(crate) mod tests { use crate::job_queue::errors::JobHandleError; use crate::models::blockchain::block::mock_block_generator::MockBlockGenerator; use crate::models::blockchain::block::validity::block_primitive_witness::tests::deterministic_block_primitive_witness; + use crate::models::blockchain::transaction::transaction_kernel::TransactionKernelProxy; use crate::models::blockchain::transaction::validity::single_proof::SingleProof; use crate::models::blockchain::type_scripts::native_currency_amount::NativeCurrencyAmount; use crate::models::proof_abstractions::mast_hash::MastHash; @@ -1095,7 +1098,6 @@ pub(crate) mod tests { use crate::tests::shared::invalid_empty_block; use crate::tests::shared::make_mock_transaction_with_mutator_set_hash; use crate::tests::shared::mock_genesis_global_state; - use crate::tests::shared::random_transaction_kernel; use crate::tests::shared::wait_until; use crate::tests::shared_tokio_runtime; use crate::triton_vm_job_queue::TritonVmJobQueue; @@ -1143,8 +1145,7 @@ pub(crate) mod tests { /// update the difficulty field, as this applies to the next block and only /// changes as a result of the timestamp of this block. pub(crate) fn mine_iteration_for_tests(block: &mut Block, rng: &mut StdRng) { - let nonce = rng.random(); - block.set_header_nonce(nonce); + block.set_header_nonce(rng.random()); } /// Estimates the hash rate in number of hashes per milliseconds @@ -2089,10 +2090,17 @@ pub(crate) mod tests { let cofactor = (1.0 - (1.0 / f64::from(difficulty))).log10(); let k = (-4.0 / cofactor).ceil() as usize; + let mut rng = rand::rng(); + let mut unstructured_source = vec![0u8; TransactionKernelProxy::size_hint(2).0]; + rng.fill_bytes(&mut unstructured_source); + let mut unstructured = arbitrary::Unstructured::new(&unstructured_source); + let mut predecessor_header = random_block_header(); predecessor_header.difficulty = Difficulty::from(difficulty); let predecessor_body = BlockBody::new( - random_transaction_kernel(), + TransactionKernelProxy::arbitrary(&mut unstructured) + .unwrap() + .into_kernel(), random_mutator_set_accumulator(), random_mmra(), random_mmra(), @@ -2109,13 +2117,14 @@ pub(crate) mod tests { successor_header.prev_block_digest = predecessor_block.hash(); // note that successor's difficulty is random let successor_body = BlockBody::new( - random_transaction_kernel(), + TransactionKernelProxy::arbitrary(&mut unstructured) + .unwrap() + .into_kernel(), random_mutator_set_accumulator(), random_mmra(), random_mmra(), ); - let mut rng = rand::rng(); let mut counter = 0; let mut successor_block = Block::new( successor_header, diff --git a/src/models/blockchain/block/block_header.rs b/src/models/blockchain/block/block_header.rs index 3920ebc85..0b4abbbc8 100644 --- a/src/models/blockchain/block/block_header.rs +++ b/src/models/blockchain/block/block_header.rs @@ -274,12 +274,14 @@ pub(crate) mod tests { guesser_digest: rng.random(), } } - #[test] - pub fn test_block_header_decode() { - let block_header = random_block_header(); - let encoded = block_header.encode(); - let decoded = *BlockHeader::decode(&encoded).unwrap(); - assert_eq!(block_header, decoded); + + proptest::proptest! { + #[test] + fn test_block_header_decode(block_header in proptest_arbitrary_interop::arb::()) { + let encoded = block_header.encode(); + let decoded = *BlockHeader::decode(&encoded).unwrap(); + assert_eq!(block_header, decoded); + } } #[test] diff --git a/src/models/blockchain/block/mod.rs b/src/models/blockchain/block/mod.rs index 32cf73077..b23effaf3 100644 --- a/src/models/blockchain/block/mod.rs +++ b/src/models/blockchain/block/mod.rs @@ -1100,11 +1100,14 @@ impl Block { #[cfg_attr(coverage_nightly, coverage(off))] pub(crate) mod tests { use macro_rules_attr::apply; + use proptest::collection; + use proptest_arbitrary_interop::arb; use rand::random; use rand::rngs::StdRng; use rand::Rng; use rand::SeedableRng; use strum::IntoEnumIterator; + use test_strategy::proptest; use tracing_test::traced_test; use twenty_first::util_types::mmr::mmr_trait::LeafMutation; @@ -1183,12 +1186,13 @@ pub(crate) mod tests { ); } - #[test] - fn block_subsidy_calculation_terminates() { - Block::block_subsidy(BFieldElement::MAX.into()); + proptest::proptest! { + #[test] + fn block_subsidy_calculation_terminates(height_arb in arb::()) { + Block::block_subsidy(BFieldElement::MAX.into()); - let random_height: BFieldElement = random(); - Block::block_subsidy(random_height.into()); + Block::block_subsidy(height_arb.into()); + } } #[test] @@ -1380,9 +1384,14 @@ pub(crate) mod tests { } } - #[apply(shared_tokio_runtime)] - async fn can_prove_block_ancestry() { - let mut rng = rand::rng(); + #[proptest(async = "tokio")] + async fn can_prove_block_ancestry( + #[strategy(collection::vec(arb::(), 55))] mut sender_randomness_vec: Vec, + #[strategy(0..54usize)] index: usize, + #[strategy(collection::vec(arb::(), 55))] mut wallet_secret_vec: Vec< + WalletEntropy, + >, + ) { let network = Network::RegTest; let genesis_block = Block::genesis(network); let mut blocks = vec![]; @@ -1397,10 +1406,18 @@ pub(crate) mod tests { let mut mmra = MmrAccumulator::new_from_leafs(vec![genesis_block.hash()]); for i in 0..55 { - let wallet_secret = WalletEntropy::new_random(); - let key = wallet_secret.nth_generation_spending_key_for_tests(0); - let (new_block, _) = - make_mock_block(network, blocks.last().unwrap(), None, key, rng.random()).await; + let key = wallet_secret_vec + .pop() + .unwrap() + .nth_generation_spending_key_for_tests(0); + let (new_block, _) = make_mock_block( + network, + blocks.last().unwrap(), + None, + key, + sender_randomness_vec.pop().unwrap(), + ) + .await; if i != 54 { ammr.append(new_block.hash()).await; mmra.append(new_block.hash()); @@ -1415,7 +1432,6 @@ pub(crate) mod tests { let last_block_mmra = blocks.last().unwrap().body().block_mmr_accumulator.clone(); assert_eq!(mmra, last_block_mmra); - let index = rand::rng().random_range(0..blocks.len() - 1); let block_digest = blocks[index].hash(); let leaf_index = index as u64; diff --git a/src/models/blockchain/transaction/transaction_kernel.rs b/src/models/blockchain/transaction/transaction_kernel.rs index 07f80b3ca..c68ba14aa 100644 --- a/src/models/blockchain/transaction/transaction_kernel.rs +++ b/src/models/blockchain/transaction/transaction_kernel.rs @@ -260,6 +260,7 @@ pub mod neptune_arbitrary { /// /// It is also useful for destructuring kernel fields without cloning. #[derive(Debug, Clone)] +#[cfg_attr(any(test, feature = "arbitrary-impls"), derive(arbitrary::Arbitrary))] pub struct TransactionKernelProxy { /// contains the transaction inputs. pub inputs: Vec, @@ -415,52 +416,58 @@ impl TransactionKernelModifier { #[cfg_attr(coverage_nightly, coverage(off))] pub mod tests { use itertools::Itertools; + use proptest::collection; + use proptest::prelude::any; use proptest::prelude::Strategy; + use proptest::strategy::ValueTree; use proptest::test_runner::TestRunner; - use rand::random; - use rand::rngs::StdRng; - use rand::Rng; - use rand::RngCore; - use rand::SeedableRng; + use proptest_arbitrary_interop::arb; + use test_strategy::proptest; use super::*; use crate::models::blockchain::block::mutator_set_update::MutatorSetUpdate; use crate::models::blockchain::transaction::Transaction; use crate::models::blockchain::transaction::TransactionProof; - use crate::tests::shared::pseudorandom_amount; - use crate::tests::shared::pseudorandom_option; - use crate::tests::shared::pseudorandom_public_announcement; - use crate::tests::shared::random_public_announcement; - use crate::tests::shared::random_transaction_kernel; - use crate::util_types::mutator_set::removal_record::AbsoluteIndexSet; - use crate::util_types::mutator_set::shared::NUM_TRIALS; - use crate::util_types::test_shared::mutator_set::pseudorandom_addition_record; - use crate::util_types::test_shared::mutator_set::pseudorandom_removal_record; - - pub fn pseudorandom_transaction_kernel( - seed: [u8; 32], - num_inputs: usize, - num_outputs: usize, - num_public_announcements: usize, - ) -> TransactionKernel { - let mut rng: StdRng = SeedableRng::from_seed(seed); - let inputs = (0..num_inputs) - .map(|_| pseudorandom_removal_record(rng.random::<[u8; 32]>())) - .collect_vec(); - let outputs = (0..num_outputs) - .map(|_| pseudorandom_addition_record(rng.random::<[u8; 32]>())) - .collect_vec(); - let public_announcements = (0..num_public_announcements) - .map(|_| pseudorandom_public_announcement(rng.random::<[u8; 32]>())) - .collect_vec(); - let fee = pseudorandom_amount(rng.random::<[u8; 32]>()); - let coinbase = - pseudorandom_option(rng.random(), pseudorandom_amount(rng.random::<[u8; 32]>())); - let timestamp: Timestamp = rng.random(); - let mutator_set_hash: Digest = rng.random(); - let merge_bit: bool = rng.random(); - - TransactionKernelProxy { + use crate::tests::shared::propcompose_txkernel; + + proptest::prop_compose! { + pub fn propcompose_txkernel_with_usualtxdata( + inputs: Vec, + outputs: Vec, + fee: NativeCurrencyAmount, + timestamp: Timestamp, + ) (mutator_set_hash in arb::()) -> TransactionKernel { + TransactionKernelProxy { + inputs: inputs.clone(), + outputs: outputs.clone(), + public_announcements: vec![], + fee, + timestamp, + coinbase: None, + mutator_set_hash, + merge_bit: false, + } + .into_kernel() + } + } + + proptest::prop_compose! { + pub fn propcompose_txkernel_with_lengths( + num_inputs: usize, + num_outputs: usize, + num_public_announcements: usize, + ) ( + inputs in collection::vec(crate::util_types::test_shared::mutator_set::propcompose_rr_with_independent_absindset_chunkdict(), num_inputs), + outputs in collection::vec(arb::(), num_outputs), + public_announcements in collection::vec(collection::vec(arb::(), 10..59), num_public_announcements).prop_map( + |vecvec| vecvec.into_iter().map(|message| PublicAnnouncement { message }).collect_vec() + ), + fee in arb::(), + coinbase in arb::>(), + timestamp in arb::(), + mutator_set_hash in arb::(), + merge_bit in any::(), + ) -> TransactionKernel {TransactionKernelProxy { inputs, outputs, public_announcements, @@ -470,7 +477,7 @@ pub mod tests { mutator_set_hash, merge_bit, } - .into_kernel() + .into_kernel()} } #[test] @@ -543,63 +550,65 @@ pub mod tests { ); } - #[test] - pub fn decode_public_announcement() { - let pubscript = random_public_announcement(); + #[proptest] + fn decode_public_announcement( + #[strategy(arb::())] pubscript: PublicAnnouncement, + ) { let encoded = pubscript.encode(); let decoded = *PublicAnnouncement::decode(&encoded).unwrap(); assert_eq!(pubscript, decoded); } - #[test] - pub fn decode_public_announcements() { - let pubscripts = vec![random_public_announcement(), random_public_announcement()]; + #[proptest] + fn decode_public_announcements( + #[strategy([arb(), arb()])] pubscripts: [PublicAnnouncement; 2], + ) { + let pubscripts = pubscripts.to_vec(); let encoded = pubscripts.encode(); let decoded = *Vec::::decode(&encoded).unwrap(); assert_eq!(pubscripts, decoded); } - #[test] - pub fn test_decode_transaction_kernel() { - let kernel = random_transaction_kernel(); + #[proptest] + fn test_decode_transaction_kernel( + #[strategy(propcompose_txkernel())] kernel: TransactionKernel, + ) { let encoded = kernel.encode(); let decoded = *TransactionKernel::decode(&encoded).unwrap(); assert_eq!(kernel, decoded); } - #[test] - pub fn test_decode_transaction_kernel_small() { - let mut rng = rand::rng(); - let absolute_indices = AbsoluteIndexSet::new( - &(0..NUM_TRIALS as usize) - .map(|_| (u128::from(rng.next_u64()) << 64) ^ u128::from(rng.next_u64())) - .collect_vec() - .try_into() - .unwrap(), - ); - let removal_record = RemovalRecord { - absolute_indices, - target_chunks: Default::default(), - }; - let kernel = TransactionKernelProxy { - inputs: vec![removal_record], - outputs: vec![AdditionRecord { - canonical_commitment: random(), - }], - public_announcements: Default::default(), - fee: NativeCurrencyAmount::one(), - coinbase: None, - timestamp: Default::default(), - mutator_set_hash: rng.random::(), - merge_bit: true, + proptest::proptest! { + #[test] + fn test_decode_transaction_kernel_small( + absolute_indices in crate::util_types::mutator_set::removal_record::propcompose_absindset(), + canonical_commitment in arb::(), + mutator_set_hash in arb::(), + ) { + let removal_record = RemovalRecord { + absolute_indices, + target_chunks: Default::default(), + }; + let kernel = TransactionKernelProxy { + inputs: vec![removal_record], + outputs: vec![AdditionRecord { + canonical_commitment + }], + public_announcements: Default::default(), + fee: NativeCurrencyAmount::one(), + coinbase: None, + timestamp: Default::default(), + mutator_set_hash, + merge_bit: true, + } + .into_kernel(); + let encoded = kernel.encode(); + println!( + "encoded: {}", + encoded.iter().map(|x| x.to_string()).join(", ") + ); + let decoded = *TransactionKernel::decode(&encoded).unwrap(); + assert_eq!(kernel, decoded); } - .into_kernel(); - let encoded = kernel.encode(); - println!( - "encoded: {}", - encoded.iter().map(|x| x.to_string()).join(", ") - ); - let decoded = *TransactionKernel::decode(&encoded).unwrap(); - assert_eq!(kernel, decoded); } } diff --git a/src/models/blockchain/transaction/utxo.rs b/src/models/blockchain/transaction/utxo.rs index 8cf4809ea..dab041aea 100644 --- a/src/models/blockchain/transaction/utxo.rs +++ b/src/models/blockchain/transaction/utxo.rs @@ -279,29 +279,13 @@ pub mod neptune_arbitrary { #[cfg_attr(coverage_nightly, coverage(off))] mod tests { use proptest::prelude::*; - use rand::Rng; + use proptest_arbitrary_interop::arb; use test_strategy::proptest; use tracing_test::traced_test; use super::*; use crate::triton_vm::prelude::*; - fn make_random_utxo() -> Utxo { - let mut rng = rand::rng(); - let lock_script = LockScript::anyone_can_spend(); - let lock_script_hash = lock_script.hash(); - let num_coins = rng.random_range(0..10); - let mut coins = vec![]; - for _i in 0..num_coins { - let amount = NativeCurrencyAmount::from_raw_i128( - rng.random_range(0i128..=NativeCurrencyAmount::MAX_NAU), - ); - coins.push(Coin::new_native_currency(amount)); - } - - (lock_script_hash, coins).into() - } - impl Utxo { pub(crate) fn with_coin(mut self, coin: Coin) -> Self { self.coins.push(coin); @@ -318,16 +302,16 @@ mod tests { } } - #[test] - fn hash_utxo_test() { - let output = make_random_utxo(); - let _digest = crate::Hash::hash(&output); + proptest::proptest! { + #[test] + fn hash_utxo_test(output in arb::()) { + let _digest = crate::Hash::hash(&output); + } } #[traced_test] - #[test] - fn serialization_test() { - let utxo = make_random_utxo(); + #[proptest] + fn serialization_test(#[strategy(arb::())] utxo: Utxo) { let serialized: String = serde_json::to_string(&utxo).unwrap(); let utxo_again: Utxo = serde_json::from_str(&serialized).unwrap(); assert_eq!(utxo, utxo_again); diff --git a/src/models/blockchain/transaction/validity/single_proof.rs b/src/models/blockchain/transaction/validity/single_proof.rs index b227f519a..61e4ee4c4 100644 --- a/src/models/blockchain/transaction/validity/single_proof.rs +++ b/src/models/blockchain/transaction/validity/single_proof.rs @@ -1004,15 +1004,12 @@ mod tests { mod update_tests { use rand::random; - use rand::rngs::StdRng; - use rand::Rng; - use rand::SeedableRng; use tasm_lib::hashing::merkle_verify::MerkleVerify; use twenty_first::prelude::Mmr; use crate::models::blockchain::transaction::transaction_kernel::TransactionKernelModifier; use crate::models::blockchain::transaction::validity::tasm::single_proof::update_branch::tests::deterministic_update_witness_additions_and_removals; - use crate::util_types::test_shared::mutator_set::pseudorandom_removal_record; + use crate::util_types::mutator_set::removal_record::RemovalRecord; use super::*; @@ -1184,12 +1181,11 @@ mod tests { test_result.unwrap(); } - fn bad_absolute_index_set_length_too_long(good_witness: &UpdateWitness) { - let mut rng = StdRng::seed_from_u64(0); + fn bad_absolute_index_set_length_too_long(good_witness: &UpdateWitness, rr: RemovalRecord) { let mut bad_witness = good_witness.clone(); let mut new_inputs = bad_witness.new_kernel.inputs.clone(); - new_inputs.push(pseudorandom_removal_record(rng.random())); + new_inputs.push(rr); bad_witness.new_kernel = TransactionKernelModifier::default() .inputs(new_inputs) @@ -1220,7 +1216,7 @@ mod tests { bad_old_aocl(&good_witness); bad_absolute_index_set_value(&good_witness); bad_absolute_index_set_length_too_short(&good_witness); - bad_absolute_index_set_length_too_long(&good_witness); + proptest::proptest!(|(rr in arb::())| bad_absolute_index_set_length_too_long(&good_witness, rr)); } #[apply(shared_tokio_runtime)] diff --git a/src/models/blockchain/type_scripts/native_currency_amount.rs b/src/models/blockchain/type_scripts/native_currency_amount.rs index 7706085f7..fce315580 100644 --- a/src/models/blockchain/type_scripts/native_currency_amount.rs +++ b/src/models/blockchain/type_scripts/native_currency_amount.rs @@ -548,20 +548,19 @@ pub mod neptune_arbitrary { #[cfg_attr(coverage_nightly, coverage(off))] pub(crate) mod tests { use std::cmp::max; + use std::panic::catch_unwind; - use arbitrary::Arbitrary; - use arbitrary::Unstructured; use get_size2::GetSize; use itertools::Itertools; use num_bigint::BigInt; use num_traits::FromPrimitive; use proptest::prelude::BoxedStrategy; use proptest::prelude::Strategy; + use proptest::prelude::*; use proptest::prop_assert; use proptest::prop_assert_eq; use proptest::prop_assume; use proptest_arbitrary_interop::arb; - use rand::Rng; use test_strategy::proptest; use super::*; @@ -579,12 +578,14 @@ pub(crate) mod tests { .boxed() } - #[test] - fn test_string_conversion() { - let mut rng = rand::rng(); - - for _ in 0..100 { - let number = rng.random_range(0..42000000); + proptest::proptest! { + #![proptest_config(ProptestConfig { + cases: 100, .. ProptestConfig::default() + })] + #[test] + fn test_string_conversion( + number in 0..42000000u32 + ) { let amount = NativeCurrencyAmount::coins(number); let string = amount.to_string(); let reconstructed_amount = NativeCurrencyAmount::coins_from_str(&string) @@ -594,14 +595,12 @@ pub(crate) mod tests { } } - #[test] - fn test_bfe_conversion() { - let mut rng = rand::rng(); - - for _ in 0..5 { - let amount = - NativeCurrencyAmount::arbitrary(&mut Unstructured::new(&rng.random::<[u8; 32]>())) - .unwrap(); + proptest::proptest! { + #![proptest_config(ProptestConfig { + cases: 5, .. ProptestConfig::default() + })] + #[test] + fn test_bfe_conversion(amount in arb::()) { let bfes = amount.encode(); let reconstructed_amount = *NativeCurrencyAmount::decode(&bfes).unwrap(); @@ -611,17 +610,12 @@ pub(crate) mod tests { #[test] fn test_bfe_conversion_with_option_amount() { - let mut rng = rand::rng(); - - for _ in 0..10 { - let amount = - NativeCurrencyAmount::arbitrary(&mut Unstructured::new(&rng.random::<[u8; 32]>())) - .unwrap(); + proptest::proptest!(ProptestConfig::with_cases(10), |(amount in arb::())| { let bfes = Some(amount).encode(); let reconstructed_amount = *Option::::decode(&bfes).unwrap(); assert_eq!(Some(amount), reconstructed_amount); - } + }); let amount: Option = None; let bfes = amount.encode(); @@ -638,17 +632,32 @@ pub(crate) mod tests { assert_eq!(a_amount + b_amount, NativeCurrencyAmount::coins(a + b)); } - #[test] - fn from_nau_conversion_pbt() { - let mut rng = rand::rng(); - let a: u64 = rng.random_range(0..(1 << 63)); - let b: u64 = rng.random_range(0..(1 << 63)); - let a_amount: NativeCurrencyAmount = NativeCurrencyAmount::from_nau(a.into()); - let b_amount: NativeCurrencyAmount = NativeCurrencyAmount::from_nau(b.into()); - assert_eq!( - a_amount + b_amount, - NativeCurrencyAmount::from_nau((a + b).into()) - ); + proptest::proptest! { + #[test] + fn from_nau_conversion_pbt( + a in (0u64..(1 << 63)), + b in (0u64..(1 << 63)), + ) { + let a_amount: NativeCurrencyAmount = NativeCurrencyAmount::from_nau(a.into()); + let b_amount: NativeCurrencyAmount = NativeCurrencyAmount::from_nau(b.into()); + assert_eq!( + a_amount + b_amount, + NativeCurrencyAmount::from_nau((a + b).into()) + ); + } + + #[test] + fn amount_scalar_mul_pbt( + a in 0..42000000u32, + b in 0..42000000u32 + ) { + if u64::from(a) * u64::from(b) <= 42000000 { + let prod_checked: NativeCurrencyAmount = NativeCurrencyAmount::coins(a * b); + let mut prod_calculated: NativeCurrencyAmount = NativeCurrencyAmount::coins(a); + prod_calculated = prod_calculated.scalar_mul(b); + assert_eq!(prod_checked, prod_calculated); + } else {assert![catch_unwind(|| NativeCurrencyAmount::coins(a).scalar_mul(b)).is_err()]} + } } #[test] @@ -685,22 +694,6 @@ pub(crate) mod tests { assert_eq!(one_hundred, one_hundred.lossy_f64_fraction_mul(1f64)); } - #[test] - fn amount_scalar_mul_pbt() { - let mut rng = rand::rng(); - let mut a = 6481; - let mut b = 6481; - while u64::from(a) * u64::from(b) > 42000000 { - a = rng.random_range(0..42000000); - b = rng.random_range(0..42000000); - } - - let prod_checked: NativeCurrencyAmount = NativeCurrencyAmount::coins(a * b); - let mut prod_calculated: NativeCurrencyAmount = NativeCurrencyAmount::coins(a); - prod_calculated = prod_calculated.scalar_mul(b); - assert_eq!(prod_checked, prod_calculated); - } - #[test] fn get_size_test() { let fourteen: NativeCurrencyAmount = NativeCurrencyAmount::coins(14); diff --git a/src/models/state/archival_state.rs b/src/models/state/archival_state.rs index dcfce0c99..78f5e3820 100644 --- a/src/models/state/archival_state.rs +++ b/src/models/state/archival_state.rs @@ -1198,7 +1198,6 @@ pub(super) mod tests { use crate::tests::shared_tokio_runtime; use crate::triton_vm_job_queue::TritonVmJobPriority; use crate::triton_vm_job_queue::TritonVmJobQueue; - use crate::util_types::test_shared::mutator_set::random_removal_record; pub(super) async fn make_test_archival_state(network: Network) -> ArchivalState { let data_dir: DataDirectory = unit_test_data_directory(network).unwrap(); @@ -2630,11 +2629,13 @@ pub(super) mod tests { } #[traced_test] - #[apply(shared_tokio_runtime)] - async fn find_canonical_block_with_input_genesis_block_test() { + #[test_strategy::proptest(async = "tokio")] + async fn find_canonical_block_with_input_genesis_block_test( + #[strategy(crate::util_types::mutator_set::removal_record::propcompose_absindset())] + random_index_set: AbsoluteIndexSet, + ) { let network = Network::Main; let archival_state = make_test_archival_state(network).await; - let random_index_set: AbsoluteIndexSet = random_removal_record().absolute_indices; assert!(archival_state .find_canonical_block_with_input(random_index_set, None) diff --git a/src/models/state/mod.rs b/src/models/state/mod.rs index 62e8b6795..51221d74c 100644 --- a/src/models/state/mod.rs +++ b/src/models/state/mod.rs @@ -2140,9 +2140,9 @@ mod tests { // Verify that duplicated entries in `incoming_randomness.dat` are // handled correctly. let network = Network::Main; - let mut rng = rand::rng(); let cli_args = cli_args::Args::default_with_network(network); - let mut state = state_with_premine_and_self_mined_blocks(cli_args, &mut rng, 1).await; + let mut state = + state_with_premine_and_self_mined_blocks(cli_args, [rand::rng().random()]).await; let mut state = state.lock_guard_mut().await; let orignal_mutxos = state .wallet_state @@ -2235,10 +2235,9 @@ mod tests { #[apply(shared_tokio_runtime)] async fn restore_monitored_utxos_from_recovery_data_test() { let network = Network::Main; - let mut rng = rand::rng(); let cli_args = cli_args::Args::default_with_network(network); let mut global_state_lock = - state_with_premine_and_self_mined_blocks(cli_args, &mut rng, 1).await; + state_with_premine_and_self_mined_blocks(cli_args, [rand::rng().random()]).await; // Delete everything from monitored UTXO and from raw-hash keys. let mut global_state = global_state_lock.lock_guard_mut().await; diff --git a/src/models/state/transaction_kernel_id.rs b/src/models/state/transaction_kernel_id.rs index 4de332f32..1f0544e38 100644 --- a/src/models/state/transaction_kernel_id.rs +++ b/src/models/state/transaction_kernel_id.rs @@ -13,6 +13,7 @@ use crate::models::blockchain::transaction::transaction_kernel::TransactionKerne /// A unique identifier of a transaction whose value is unaffected by a /// transaction update. #[derive(Debug, Clone, Copy, PartialEq, Eq, GetSize, Hash, Serialize, Deserialize)] +#[cfg_attr(test, derive(Default))] pub struct TransactionKernelId(Digest); impl Display for TransactionKernelId { diff --git a/src/models/state/wallet/mod.rs b/src/models/state/wallet/mod.rs index 4a0f4162d..dfaccdb78 100644 --- a/src/models/state/wallet/mod.rs +++ b/src/models/state/wallet/mod.rs @@ -1099,23 +1099,26 @@ mod tests { .generate_sender_randomness(BFieldElement::new(10).into(), random()); } - #[test] - fn master_seed_is_not_sender_randomness() { - let secret = rand::rng().random::(); - let secret_as_digest = Digest::new( - [ - secret.coefficients.to_vec(), - vec![BFieldElement::new(0); Digest::LEN - EXTENSION_DEGREE], - ] - .concat() - .try_into() - .unwrap(), - ); - let wallet = WalletEntropy::new(SecretKeyMaterial(secret)); - assert_ne!( - wallet.generate_sender_randomness(BlockHeight::genesis(), random()), - secret_as_digest - ); + proptest::proptest! { + #[test] + fn master_seed_is_not_sender_randomness( + secret in proptest_arbitrary_interop::arb::() + ) { + let secret_as_digest = Digest::new( + [ + secret.coefficients.to_vec(), + vec![BFieldElement::new(0); Digest::LEN - EXTENSION_DEGREE], + ] + .concat() + .try_into() + .unwrap(), + ); + let wallet = WalletEntropy::new(SecretKeyMaterial(secret)); + assert_ne!( + wallet.generate_sender_randomness(BlockHeight::genesis(), random()), + secret_as_digest + ); + } } #[test] diff --git a/src/models/state/wallet/secret_key_material.rs b/src/models/state/wallet/secret_key_material.rs index 449f8c2d9..3c52d5a62 100644 --- a/src/models/state/wallet/secret_key_material.rs +++ b/src/models/state/wallet/secret_key_material.rs @@ -198,15 +198,19 @@ mod tests { use super::*; - #[test] - fn phrase_conversion_works() { - let wallet_secret = SecretKeyMaterial(rng().random()); - let phrase = wallet_secret.to_phrase(); - let wallet_again = SecretKeyMaterial::from_phrase(&phrase).unwrap(); - let phrase_again = wallet_again.to_phrase(); - - assert_eq!(wallet_secret, wallet_again); - assert_eq!(phrase, phrase_again); + proptest::proptest! { + #[test] + fn phrase_conversion_works( + secret in proptest_arbitrary_interop::arb::() + ) { + let wallet_secret = SecretKeyMaterial(secret); + let phrase = wallet_secret.to_phrase(); + let wallet_again = SecretKeyMaterial::from_phrase(&phrase).unwrap(); + let phrase_again = wallet_again.to_phrase(); + + assert_eq!(wallet_secret, wallet_again); + assert_eq!(phrase, phrase_again); + } } #[test] @@ -224,6 +228,8 @@ mod tests { mod shamir { use proptest::prelude::Just; use proptest::prop_assert_eq; + use proptest::prop_assume; + use proptest::sample; use proptest_arbitrary_interop::arb; use test_strategy::proptest; @@ -252,15 +258,13 @@ mod tests { #[strategy(2usize..=#n)] t: usize, #[strategy(arb())] s: XFieldElement, #[strategy([arb(); 32])] seed: [u8; 32], + #[strategy(sample::subsequence((0..#n).collect_vec(), #t))] indices: Vec, ) { - let mut rng = StdRng::from_seed(seed); let secret_key = SecretKeyMaterial(s); - let mut shares = secret_key - .share_shamir(t, n, rng.random()) + let shares = secret_key + .share_shamir(t, n, seed) .expect("sharing on happy path should succeed"); - let selected_shares = (0..t) - .map(|_| shares.swap_remove(rng.random_range(0..shares.len()))) - .collect_vec(); + let selected_shares = indices.into_iter().map(|i| shares[i]).collect_vec(); // #arbitraryHashSetIterator let recombination = SecretKeyMaterial::combine_shamir(t, selected_shares) .expect("recombining on happy path should succeed"); @@ -313,17 +317,15 @@ mod tests { fn catch_too_few_shares_to_recombine( #[strategy(2usize..20)] n: usize, #[strategy(2usize..=#n)] t: usize, + #[strategy(sample::subsequence((0..#n).collect_vec(), #t - 1))] indices: Vec, #[strategy(arb())] s: XFieldElement, #[strategy([arb(); 32])] seed: [u8; 32], ) { - let mut rng = StdRng::from_seed(seed); let secret_key = SecretKeyMaterial(s); - let mut shares = secret_key - .share_shamir(t, n, rng.random()) + let shares = secret_key + .share_shamir(t, n, seed) .expect("sharing on happy path should succeed"); - let selected_shares = (0..t - 1) - .map(|_| shares.swap_remove(rng.random_range(0..shares.len()))) - .collect_vec(); + let selected_shares = indices.into_iter().map(|i| shares[i]).collect_vec(); prop_assert_eq!( SecretKeyMaterial::combine_shamir(t, selected_shares), Err(ShamirSecretSharingError::TooFewSharesToRecombine) @@ -336,15 +338,13 @@ mod tests { #[strategy(2usize..=#n)] t: usize, #[strategy(arb())] s: XFieldElement, #[strategy([arb(); 32])] seed: [u8; 32], + #[strategy(sample::subsequence((0..#n).collect_vec(), #t - 1))] indices: Vec, ) { - let mut rng = StdRng::from_seed(seed); let secret_key = SecretKeyMaterial(s); - let mut shares = secret_key - .share_shamir(t, n, rng.random()) + let shares = secret_key + .share_shamir(t, n, seed) .expect("sharing on happy path should succeed"); - let mut selected_shares = (0..t - 1) - .map(|_| shares.swap_remove(rng.random_range(0..shares.len()))) - .collect_vec(); + let mut selected_shares = indices.into_iter().map(|i| shares[i]).collect_vec(); let invalid_share = (0, secret_key); selected_shares.push(invalid_share); prop_assert_eq!( @@ -357,18 +357,17 @@ mod tests { fn catch_duplicate_index( #[strategy(2usize..20)] n: usize, #[strategy(2usize..=#n)] t: usize, + #[strategy(0usize..#t - 1)] dup_ind: usize, #[strategy(arb())] s: XFieldElement, #[strategy([arb(); 32])] seed: [u8; 32], + #[strategy(sample::subsequence((0..#t).collect_vec(), #t - 1))] indices: Vec, ) { - let mut rng = StdRng::from_seed(seed); let secret_key = SecretKeyMaterial(s); - let mut shares = secret_key - .share_shamir(t, n, rng.random()) + let shares = secret_key + .share_shamir(t, n, seed) .expect("sharing on happy path should succeed"); - let mut selected_shares = (0..t - 1) - .map(|_| shares.swap_remove(rng.random_range(0..shares.len()))) - .collect_vec(); - let duplicate_share = selected_shares[rng.random_range(0..selected_shares.len())]; + let mut selected_shares = indices.into_iter().map(|i| shares[i]).collect_vec(); + let duplicate_share = selected_shares[dup_ind]; selected_shares.push(duplicate_share); println!("selected shares: {:?}", selected_shares); prop_assert_eq!( @@ -382,56 +381,32 @@ mod tests { #[strategy(3usize..20)] n: usize, #[strategy(2usize..#n)] t: usize, #[strategy(arb())] s: XFieldElement, - #[strategy([arb(); 32])] seed: [u8; 32], + #[strategy([arb(); 32])] seed_a: [u8; 32], + #[strategy([arb(); 32])] seed_b: [u8; 32], + #[strategy(sample::subsequence((0..#n).collect_vec(), #t + 1))] indices: Vec, + #[strategy(proptest::collection::vec(proptest::prelude::any::(), #t + 1))] + choices: Vec, ) { - let mut rng = StdRng::from_seed(seed); + // Make a random selection of t+1 shares such that both sharings are represented. There can be no duplicate indices. + prop_assume!(choices.iter().any(|x| x != &choices[0])); + // nothing to test here if the sharings are identical + prop_assume!(seed_a != seed_b); + let secret_key = SecretKeyMaterial(s); - let mut shares_a = secret_key - .share_shamir(t, n, rng.random()) + let shares_a = secret_key + .share_shamir(t, n, seed_a) .expect("sharing on happy path should succeed"); - let mut shares_b = secret_key - .share_shamir(t, n, rng.random()) + let shares_b = secret_key + .share_shamir(t, n, seed_b) .expect("sharing on happy path should succeed"); - // Make a random selection of t+1 shares such that both sharings are - // represented. There can be no duplicate indices so n > t. - let insert_unique_index = |collection: &mut Vec<_>, share: (_, _)| { - let is_share_in_collection = collection.iter().any(|(i, _)| *i == share.0); - if !is_share_in_collection { - collection.push(share); - } - is_share_in_collection - }; - - // add one share a, randomly selected - let mut selected_shares = vec![]; - insert_unique_index( - &mut selected_shares, - shares_a.swap_remove(rng.random_range(0..shares_a.len())), - ); - - // add one from b, randomly selected, and make sure it gets added - // even if we get an index collision on the first guess - while insert_unique_index( - &mut selected_shares, - shares_b.swap_remove(rng.random_range(0..shares_b.len())), - ) {} - - // complete the collection by drawing randomly from a or b when - // possible - while selected_shares.len() < t + 1 { - let next_share = if shares_a.is_empty() && shares_b.is_empty() { - panic!("cannot happen: both were populated with more than 2 elements"); - } else if !shares_a.is_empty() && shares_b.is_empty() { - shares_a.swap_remove(rng.random_range(0..shares_a.len())) - } else if shares_a.is_empty() && !shares_b.is_empty() { - shares_b.swap_remove(rng.random_range(0..shares_b.len())) - } else if rng.random() { - shares_a.swap_remove(rng.random_range(0..shares_a.len())) + let mut selected_shares = Vec::with_capacity(t + 1); + for (index, choice) in std::iter::zip(indices, choices) { + if choice { + selected_shares.push(shares_b[index]); } else { - shares_b.swap_remove(rng.random_range(0..shares_b.len())) - }; - insert_unique_index(&mut selected_shares, next_share); + selected_shares.push(shares_a[index]); + } } prop_assert_eq!( diff --git a/src/models/state/wallet/transaction_input.rs b/src/models/state/wallet/transaction_input.rs index 08b86dfb2..cf4530540 100644 --- a/src/models/state/wallet/transaction_input.rs +++ b/src/models/state/wallet/transaction_input.rs @@ -44,22 +44,6 @@ impl TxInput { pub fn native_currency_amount(&self) -> NativeCurrencyAmount { self.utxo.get_native_currency_amount() } - - #[cfg(test)] - pub fn new_random(amount: NativeCurrencyAmount) -> Self { - use crate::models::blockchain::transaction::lock_script::LockScript; - use crate::models::state::wallet::address::generation_address::GenerationSpendingKey; - use crate::models::state::wallet::address::SpendingKey; - use crate::util_types::mutator_set::ms_membership_proof::pseudorandom_mutator_set_membership_proof; - - let lock_script = LockScript::anyone_can_spend(); - let key: SpendingKey = GenerationSpendingKey::derive_from_seed(rand::random()).into(); - Self(UnlockedUtxo::unlock( - Utxo::new_native_currency(lock_script.clone(), amount), - key.lock_script_and_witness(), - pseudorandom_mutator_set_membership_proof(rand::random()), - )) - } } /// Represents a list of [TxInput] diff --git a/src/models/state/wallet/wallet_state.rs b/src/models/state/wallet/wallet_state.rs index bf7325673..a41ef37b4 100644 --- a/src/models/state/wallet/wallet_state.rs +++ b/src/models/state/wallet/wallet_state.rs @@ -2557,7 +2557,6 @@ pub(crate) mod tests { .await; let genesis_block = Block::genesis(network); - let guesser_preimage_1a: Digest = bob_wallet_secret.guesser_preimage(genesis_block.hash()); let mock_block_seed = rng.random(); let guesser_fraction = 0.5f64; @@ -2571,7 +2570,10 @@ pub(crate) mod tests { None, bob_key, mock_block_seed, - (guesser_fraction, guesser_preimage_1a), + ( + guesser_fraction, + bob_wallet_secret.guesser_preimage(genesis_block.hash()), + ), ) .await; @@ -2597,7 +2599,6 @@ pub(crate) mod tests { // Add a new block to state as tip, which *only* differs in its PoW // solution. `bob` did *not* find the PoW-solution for this block. - let guesser_preimage_1b: Digest = rng.random(); let (block_1b, expected_utxos_block_1b) = make_mock_block_with_puts_and_guesser_preimage_and_guesser_fraction( network, @@ -2607,7 +2608,7 @@ pub(crate) mod tests { None, bob_key, mock_block_seed, - (guesser_fraction, guesser_preimage_1b), + (guesser_fraction, rng.random()), ) .await; @@ -4171,16 +4172,21 @@ pub(crate) mod tests { } pub(crate) mod scan_mode { + use proptest::collection; + use proptest::prelude::any; + use proptest_arbitrary_interop::arb; use std::hint::black_box; use super::*; use crate::config_models::fee_notification_policy::FeeNotificationPolicy; use crate::mine_loop::make_coinbase_transaction_stateless; use crate::models::blockchain::block::block_height::BlockHeight; - use crate::models::blockchain::transaction::transaction_kernel::tests::pseudorandom_transaction_kernel; + use crate::models::blockchain::transaction::transaction_kernel::tests::propcompose_txkernel_with_lengths; use crate::models::state::wallet::utxo_notification::UtxoNotificationPayload; use crate::tests::shared::unit_test_data_directory; + const NUM_FUTURE_KEYS: usize = 20; + /// Test scan mode. /// /// In rough terms, this test verifies that importing a wallet followed @@ -4369,13 +4375,29 @@ pub(crate) mod tests { /// b) the relative index is smaller than num_future_keys. /// #[traced_test] - #[apply(shared_tokio_runtime)] - async fn scan_for_utxos_announced_to_future_keys_behaves() { + #[test_strategy::proptest(async = "tokio")] + async fn scan_for_utxos_announced_to_future_keys_behaves( + #[strategy(propcompose_txkernel_with_lengths(10, 10, 10))] kernel: TransactionKernel, + #[strategy(arb())] wallet_secret: WalletEntropy, + #[strategy(collection::vec( + 0_usize..100, + NUM_FUTURE_KEYS, + ))] + mut future_generation_relative_indices: Vec, + #[strategy(collection::vec( + 0_usize..100, + NUM_FUTURE_KEYS, + ))] + mut future_symmetric_relative_indices: Vec, + #[strategy(collection::vec(arb(), 2 * NUM_FUTURE_KEYS))] mut utxo_vec: Vec, + #[strategy(collection::vec(arb(), 2 * NUM_FUTURE_KEYS))] mut sender_randomness_vec: Vec< + Digest, + >, + #[strategy(collection::vec(any::(), 2 * NUM_FUTURE_KEYS))] mut select_vec: Vec< + bool, + >, + ) { let network = Network::Main; - let seed: [u8; 32] = random(); - dbg!(seed); - let mut rng = StdRng::from_seed(seed); - let wallet_secret = WalletEntropy::new_pseudorandom(rng.random()); let data_dir = unit_test_data_directory(network).unwrap(); let wallet_state = WalletState::new_from_wallet_entropy( &data_dir, @@ -4388,10 +4410,6 @@ pub(crate) mod tests { let generation_counter = wallet_state.wallet_db.get_generation_key_counter(); let symmetric_counter = wallet_state.wallet_db.get_symmetric_key_counter(); - let num_future_keys = 20; - let mut future_generation_relative_indices = (0..num_future_keys) - .map(|_| rng.random_range(0_usize..100)) - .collect_vec(); future_generation_relative_indices.sort(); let future_generation_keys = future_generation_relative_indices .into_iter() @@ -4407,9 +4425,6 @@ pub(crate) mod tests { ) }) .collect_vec(); - let mut future_symmetric_relative_indices = (0..num_future_keys) - .map(|_| rng.random_range(0_usize..100)) - .collect_vec(); future_symmetric_relative_indices.sort(); let future_symmetric_keys = future_symmetric_relative_indices .into_iter() @@ -4424,8 +4439,6 @@ pub(crate) mod tests { }) .collect_vec(); - let kernel = pseudorandom_transaction_kernel(rng.random(), 10, 10, 10); - // create master list of UTXOs with context struct UtxoContext { select: bool, @@ -4441,11 +4454,8 @@ pub(crate) mod tests { .into_iter() .chain(future_symmetric_keys) { - let coin = Coin::new_native_currency(NativeCurrencyAmount::coins( - rng.random::() >> 15, - )); - let utxo = Utxo::from((rng.random::(), vec![coin])); - let sender_randomness = rng.random::(); + let utxo = utxo_vec.pop().unwrap(); + let sender_randomness = sender_randomness_vec.pop().unwrap(); let receiver_preimage = key.privacy_preimage(); let utxo_notification_payload = @@ -4462,7 +4472,7 @@ pub(crate) mod tests { }; let addition_record = incoming_utxo.addition_record(); - let select = rng.random::(); + let select = select_vec.pop().unwrap(); if select { addition_records.push(addition_record); } @@ -4485,7 +4495,7 @@ pub(crate) mod tests { // scan let caught_utxos = wallet_state - .scan_for_utxos_announced_to_future_keys(num_future_keys, &new_kernel) + .scan_for_utxos_announced_to_future_keys(NUM_FUTURE_KEYS, &new_kernel) .collect_vec(); // filter master list according to expectation @@ -4496,11 +4506,11 @@ pub(crate) mod tests { continue; } - let index_in_range = uc.relative_index < num_future_keys; + let index_in_range = uc.relative_index < NUM_FUTURE_KEYS; if !index_in_range { println!( "rejecting UTXO because index {} >= {}", - uc.relative_index, num_future_keys + uc.relative_index, NUM_FUTURE_KEYS ); continue; } diff --git a/src/peer_loop.rs b/src/peer_loop.rs index 12b06cbd2..fcfd05b32 100644 --- a/src/peer_loop.rs +++ b/src/peer_loop.rs @@ -3874,7 +3874,7 @@ mod tests { let blocks: [Block; 11] = fake_valid_sequence_of_blocks_for_tests( &genesis_block, Timestamp::hours(1), - [0u8; 32], + Default::default(), network, ) .await; @@ -4036,9 +4036,10 @@ mod tests { let blocks = fake_valid_sequence_of_blocks_for_tests_dyn( &block_1, network.target_block_interval(), - rng.random(), + (0..rng.random_range(ALICE_SYNC_MODE_THRESHOLD + 1..20)) + .map(|_| rng.random()) + .collect_vec(), network, - rng.random_range(ALICE_SYNC_MODE_THRESHOLD + 1..20), ) .await; for block in &blocks { diff --git a/src/rpc_server.rs b/src/rpc_server.rs index b76310f3e..bdf7891cc 100644 --- a/src/rpc_server.rs +++ b/src/rpc_server.rs @@ -3724,7 +3724,7 @@ mod tests { use crate::config_models::cli_args; use crate::config_models::network::Network; use crate::database::storage::storage_vec::traits::*; - use crate::models::blockchain::transaction::transaction_kernel::tests::pseudorandom_transaction_kernel; + use crate::models::blockchain::transaction::transaction_kernel::tests::propcompose_txkernel_with_lengths; use crate::models::peer::NegativePeerSanction; use crate::models::peer::PeerSanction; use crate::models::state::wallet::address::generation_address::GenerationSpendingKey; @@ -3734,11 +3734,12 @@ mod tests { use crate::tests::shared::invalid_block_with_transaction; use crate::tests::shared::make_mock_block; use crate::tests::shared::mock_genesis_global_state; - use crate::tests::shared::random_transaction_kernel; use crate::tests::shared::unit_test_data_directory; use crate::tests::shared_tokio_runtime; use crate::Block; + const NUM_PUBLIC_ANNOUNCEMENTS_BLOCK1: usize = 7; + async fn test_rpc_server( wallet_entropy: WalletEntropy, peer_count: u8, @@ -3889,7 +3890,7 @@ mod tests { let _ = rpc_server.clone().mempool_overview(ctx, token, 0, 20).await; let _ = rpc_server .clone() - .mempool_tx_kernel(ctx, token, random_transaction_kernel().txid()) + .mempool_tx_kernel(ctx, token, Default::default()) .await; let _ = rpc_server.clone().clear_all_standings(ctx, token).await; let _ = rpc_server @@ -4436,8 +4437,11 @@ mod tests { } #[traced_test] - #[apply(shared_tokio_runtime)] - async fn public_announcements_in_block_test() { + #[test_strategy::proptest(async = "tokio")] #[ignore = "TODO remove this when handled separately"] + async fn public_announcements_in_block_test( + #[strategy(propcompose_txkernel_with_lengths(0usize, 2usize, NUM_PUBLIC_ANNOUNCEMENTS_BLOCK1))] + tx_block1: crate::models::blockchain::transaction::transaction_kernel::TransactionKernel, + ) { let network = Network::Main; let mut rpc_server = test_rpc_server( WalletEntropy::new_random(), @@ -4445,16 +4449,6 @@ mod tests { cli_args::Args::default_with_network(network), ) .await; - let mut rng = rand::rng(); - let num_public_announcements_block1 = 7; - let num_inputs = 0; - let num_outputs = 2; - let tx_block1 = pseudorandom_transaction_kernel( - rng.random(), - num_inputs, - num_outputs, - num_public_announcements_block1, - ); let tx_block1 = Transaction { kernel: tx_block1, proof: TransactionProof::invalid(), @@ -4476,7 +4470,7 @@ mod tests { "Must return expected public announcements" ); assert_eq!( - num_public_announcements_block1, + NUM_PUBLIC_ANNOUNCEMENTS_BLOCK1, block1_public_announcements.len(), "Must return expected number of public announcements" ); diff --git a/src/tests/shared.rs b/src/tests/shared.rs index e68786c37..3252f1401 100644 --- a/src/tests/shared.rs +++ b/src/tests/shared.rs @@ -23,18 +23,15 @@ use itertools::Itertools; use num_traits::Zero; use pin_project_lite::pin_project; use proptest::collection::vec; +use proptest::prelude::BoxedStrategy; use proptest::prelude::Strategy; use proptest::strategy::ValueTree; use proptest::test_runner::TestRunner; use proptest_arbitrary_interop::arb; use rand::distr::Alphanumeric; use rand::distr::SampleString; -use rand::random; -use rand::rngs::StdRng; use rand::seq::SliceRandom; use rand::Rng; -use rand::RngCore; -use rand::SeedableRng; use tasm_lib::prelude::Tip5; use tasm_lib::twenty_first::bfe; use tasm_lib::twenty_first::util_types::mmr::mmr_accumulator::MmrAccumulator; @@ -71,7 +68,8 @@ use crate::models::blockchain::block::Block; use crate::models::blockchain::block::BlockProof; use crate::models::blockchain::transaction::lock_script::LockScript; use crate::models::blockchain::transaction::primitive_witness::PrimitiveWitness; -use crate::models::blockchain::transaction::transaction_kernel::tests::pseudorandom_transaction_kernel; +use crate::models::blockchain::transaction::transaction_kernel; +use crate::models::blockchain::transaction::transaction_kernel::tests::propcompose_txkernel_with_lengths; use crate::models::blockchain::transaction::transaction_kernel::TransactionKernel; use crate::models::blockchain::transaction::transaction_kernel::TransactionKernelModifier; use crate::models::blockchain::transaction::transaction_kernel::TransactionKernelProxy; @@ -79,7 +77,6 @@ use crate::models::blockchain::transaction::utxo::Utxo; use crate::models::blockchain::transaction::validity::neptune_proof::Proof; use crate::models::blockchain::transaction::validity::single_proof::SingleProof; use crate::models::blockchain::transaction::validity::tasm::single_proof::merge_branch::MergeWitness; -use crate::models::blockchain::transaction::PublicAnnouncement; use crate::models::blockchain::transaction::Transaction; use crate::models::blockchain::transaction::TransactionProof; use crate::models::blockchain::type_scripts::native_currency_amount::NativeCurrencyAmount; @@ -121,6 +118,37 @@ use crate::RPCServerToMain; use crate::PEER_CHANNEL_CAPACITY; use crate::VERSION; +/// Ubiquitous container holding any combination of randomness used in the test helpers; implements both +/// random and `proptest` generation. Useful when helper needs few random values and a call to it becomes +/// cluttered. +#[derive(arbitrary::Arbitrary, Debug, Clone, PartialEq, Eq)] +pub struct Randomness { + pub bytes_arr: [[u8; 32]; BA], + pub digests: [Digest; D], +} +impl rand::distr::Distribution> + for rand::distr::StandardUniform +{ + fn sample(&self, rng: &mut R) -> Randomness { + let mut bytes = [[Default::default(); 32]; BA]; + let mut digests = [Default::default(); D]; + bytes.iter_mut().for_each(|b| rng.fill_bytes(b)); + digests.iter_mut().for_each(|d| *d = rng.random()); + Randomness { + bytes_arr: bytes, + digests, + } + } +} +impl Default for Randomness { + fn default() -> Self { + Self { + bytes_arr: [[Default::default(); 32]; BA], + digests: [Default::default(); D], + } + } +} + /// Return an empty peer map pub fn get_peer_map() -> HashMap { HashMap::new() @@ -262,10 +290,9 @@ pub(crate) async fn mock_genesis_global_state( /// A state with a premine UTXO and self-mined blocks. Both composing and /// guessing was done by the returned entity. Tip has height of /// `num_blocks_mined`. -pub(crate) async fn state_with_premine_and_self_mined_blocks( +pub(crate) async fn state_with_premine_and_self_mined_blocks( cli_args: cli_args::Args, - rng: &mut T, - num_blocks_mined: usize, + coinbase_sender_randomness_coll: [Digest; NUM_BLOCKS_MINED], ) -> GlobalStateLock { let network = cli_args.network; let wallet = WalletEntropy::devnet_wallet(); @@ -274,8 +301,7 @@ pub(crate) async fn state_with_premine_and_self_mined_blocks( mock_genesis_global_state(2, wallet.clone(), cli_args.clone()).await; let mut previous_block = Block::genesis(network); - for _ in 0..num_blocks_mined { - let guesser_preimage = wallet.guesser_preimage(previous_block.hash()); + for coinbase_sender_randomness in coinbase_sender_randomness_coll { let (next_block, composer_utxos) = make_mock_block_with_puts_and_guesser_preimage_and_guesser_fraction( network, @@ -284,8 +310,8 @@ pub(crate) async fn state_with_premine_and_self_mined_blocks( vec![], None, own_key, - rng.random(), - (0.5, guesser_preimage), + coinbase_sender_randomness, + (0.5, wallet.guesser_preimage(previous_block.hash())), ) .await; @@ -453,6 +479,14 @@ impl stream::Stream for Mock { } } +// TODO ditch this by rewriting the underlying `Strategy` with `IntoRange` +proptest::prop_compose! { + pub fn propcompose_txkernel() (num_inputs in 1usize..=5, num_outputs in 1usize..=6, num_public_announcements in 0usize..5) + (r in propcompose_txkernel_with_lengths(num_inputs, num_outputs, num_public_announcements)) -> TransactionKernel { + r + } +} + /// Return path for the directory containing test data, like proofs and block /// data. pub(crate) fn test_helper_data_dir() -> PathBuf { @@ -607,65 +641,6 @@ pub(crate) fn try_fetch_file_from_server(filename: String) -> Option<(Vec, S None } -pub fn pseudorandom_option(seed: [u8; 32], thing: T) -> Option { - let mut rng: StdRng = SeedableRng::from_seed(seed); - if rng.next_u32() % 2 == 0 { - None - } else { - Some(thing) - } -} - -pub fn pseudorandom_amount(seed: [u8; 32]) -> NativeCurrencyAmount { - let mut rng: StdRng = SeedableRng::from_seed(seed); - let number: u128 = rng.random::() >> 10; - NativeCurrencyAmount::from_nau(number.try_into().unwrap()) -} - -pub fn pseudorandom_utxo(seed: [u8; 32]) -> Utxo { - let mut rng: StdRng = SeedableRng::from_seed(seed); - ( - rng.random(), - NativeCurrencyAmount::coins(rng.random_range(0..42000000)).to_native_coins(), - ) - .into() -} - -pub fn random_transaction_kernel() -> TransactionKernel { - let mut rng = rand::rng(); - let num_inputs = 1 + (rng.next_u32() % 5) as usize; - let num_outputs = 1 + (rng.next_u32() % 6) as usize; - let num_public_announcements = (rng.next_u32() % 5) as usize; - pseudorandom_transaction_kernel( - rng.random(), - num_inputs, - num_outputs, - num_public_announcements, - ) -} - -pub fn pseudorandom_public_announcement(seed: [u8; 32]) -> PublicAnnouncement { - let mut rng: StdRng = SeedableRng::from_seed(seed); - let len = 10 + (rng.next_u32() % 50) as usize; - let message = (0..len).map(|_| rng.random()).collect_vec(); - PublicAnnouncement { message } -} - -pub fn random_public_announcement() -> PublicAnnouncement { - let mut rng = rand::rng(); - pseudorandom_public_announcement(rng.random::<[u8; 32]>()) -} - -pub fn random_amount() -> NativeCurrencyAmount { - let mut rng = rand::rng(); - pseudorandom_amount(rng.random::<[u8; 32]>()) -} - -pub fn random_option(thing: T) -> Option { - let mut rng = rand::rng(); - pseudorandom_option(rng.random::<[u8; 32]>(), thing) -} - pub(crate) fn make_mock_txs_with_primitive_witness_with_timestamp( count: usize, timestamp: Timestamp, @@ -791,14 +766,6 @@ pub(crate) fn dummy_expected_utxo() -> ExpectedUtxo { } } -pub(crate) fn mock_item_and_randomnesses() -> (Digest, Digest, Digest) { - let mut rng = rand::rng(); - let item: Digest = rng.random(); - let sender_randomness: Digest = rng.random(); - let receiver_preimage: Digest = rng.random(); - (item, sender_randomness, receiver_preimage) -} - // TODO: Change this function into something more meaningful! pub fn make_mock_transaction_with_wallet( inputs: Vec, @@ -806,27 +773,21 @@ pub fn make_mock_transaction_with_wallet( fee: NativeCurrencyAmount, _wallet_state: &WalletState, timestamp: Option, -) -> Transaction { - let timestamp = match timestamp { - Some(ts) => ts, - None => Timestamp::now(), - }; - let kernel = TransactionKernelProxy { +) -> BoxedStrategy { + transaction_kernel::tests::propcompose_txkernel_with_usualtxdata( inputs, outputs, - public_announcements: vec![], fee, - timestamp, - coinbase: None, - mutator_set_hash: random(), - merge_bit: false, - } - .into_kernel(); - - Transaction { + match timestamp { + Some(ts) => ts, + None => Timestamp::now(), + }, + ) + .prop_map(|kernel| Transaction { kernel, proof: TransactionProof::invalid(), - } + }) + .boxed() } /// Create a block containing the supplied transaction kernel, starting from @@ -918,20 +879,17 @@ pub(crate) async fn make_mock_block_with_puts_and_guesser_preimage_and_guesser_f outputs: Vec, block_timestamp: Option, composer_key: generation_address::GenerationSpendingKey, - seed: [u8; 32], + coinbase_sender_randomness: Digest, guesser_parameters: (f64, Digest), ) -> (Block, Vec) { let (guesser_fraction, guesser_preimage) = guesser_parameters; - let mut rng: StdRng = SeedableRng::from_seed(seed); - // Build coinbase UTXO and associated data let block_timestamp = match block_timestamp { Some(ts) => ts, None => previous_block.kernel.header.timestamp + network.target_block_interval(), }; - let coinbase_sender_randomness: Digest = rng.random(); let composer_parameters = ComposerParameters::new( composer_key.to_address().into(), coinbase_sender_randomness, @@ -997,7 +955,7 @@ pub(crate) async fn make_mock_block( previous_block: &Block, block_timestamp: Option, composer_key: generation_address::GenerationSpendingKey, - seed: [u8; 32], + coinbase_sender_randomness: Digest, ) -> (Block, Vec) { make_mock_block_with_inputs_and_outputs( network, @@ -1006,7 +964,7 @@ pub(crate) async fn make_mock_block( vec![], block_timestamp, composer_key, - seed, + coinbase_sender_randomness, ) .await } @@ -1022,7 +980,7 @@ pub(crate) async fn make_mock_block_with_inputs_and_outputs( outputs: Vec, block_timestamp: Option, composer_key: generation_address::GenerationSpendingKey, - seed: [u8; 32], + coinbase_sender_randomness: Digest, ) -> (Block, Vec) { make_mock_block_with_puts_and_guesser_preimage_and_guesser_fraction( network, @@ -1031,7 +989,7 @@ pub(crate) async fn make_mock_block_with_inputs_and_outputs( outputs, block_timestamp, composer_key, - seed, + coinbase_sender_randomness, (0f64, Digest::default()), ) .await @@ -1178,7 +1136,7 @@ pub(crate) async fn fake_valid_block_from_tx_for_tests( ) -> Block { let mut block = fake_valid_block_proposal_from_tx(network, predecessor, tx).await; - let mut rng = StdRng::from_seed(seed); + let mut rng = ::from_seed(seed); while !block.has_proof_of_work(network, predecessor.header()) { mine_iteration_for_tests(&mut block, &mut rng); } @@ -1263,10 +1221,9 @@ pub(crate) async fn fake_create_block_transaction_for_tests( selected_mempool_txs = vec![nop_transaction]; } - let mut rng = StdRng::from_seed(shuffle_seed); for tx_to_include in selected_mempool_txs { block_transaction = - fake_merge_transactions_for_tests(block_transaction, tx_to_include, rng.random()) + fake_merge_transactions_for_tests(block_transaction, tx_to_include, shuffle_seed) .await .expect("Must be able to merge transactions in mining context"); } @@ -1277,16 +1234,16 @@ pub(crate) async fn fake_create_block_transaction_for_tests( async fn fake_block_successor( predecessor: &Block, timestamp: Timestamp, - seed: [u8; 32], with_valid_pow: bool, + rness: Randomness<2, 2>, network: Network, ) -> Block { fake_block_successor_with_merged_tx( predecessor, timestamp, - seed, with_valid_pow, vec![], + rness, network, ) .await @@ -1295,16 +1252,15 @@ async fn fake_block_successor( pub async fn fake_block_successor_with_merged_tx( predecessor: &Block, timestamp: Timestamp, - seed: [u8; 32], with_valid_pow: bool, txs: Vec, + rness: Randomness<2, 2>, network: Network, ) -> Block { - let mut rng = StdRng::from_seed(seed); - + let (mut seed_bytes, mut seed_digests) = (rness.bytes_arr.to_vec(), rness.digests.to_vec()); let composer_parameters = ComposerParameters::new( - GenerationReceivingAddress::derive_from_seed(rng.random()).into(), - rng.random(), + GenerationReceivingAddress::derive_from_seed(seed_digests.pop().unwrap()).into(), + seed_digests.pop().unwrap(), None, 0.5f64, FeeNotificationPolicy::OffChain, @@ -1313,7 +1269,7 @@ pub async fn fake_block_successor_with_merged_tx( predecessor, composer_parameters, timestamp, - rng.random(), + seed_bytes.pop().unwrap(), txs, network, ) @@ -1321,7 +1277,13 @@ pub async fn fake_block_successor_with_merged_tx( .unwrap(); if with_valid_pow { - fake_valid_block_from_tx_for_tests(network, predecessor, block_tx, rng.random()).await + fake_valid_block_from_tx_for_tests( + network, + predecessor, + block_tx, + seed_bytes.pop().unwrap(), + ) + .await } else { fake_valid_block_proposal_from_tx(network, predecessor, block_tx).await } @@ -1330,19 +1292,19 @@ pub async fn fake_block_successor_with_merged_tx( pub(crate) async fn fake_valid_block_proposal_successor_for_test( predecessor: &Block, timestamp: Timestamp, - seed: [u8; 32], + rness: Randomness<2, 2>, network: Network, ) -> Block { - fake_block_successor(predecessor, timestamp, seed, false, network).await + fake_block_successor(predecessor, timestamp, false, rness, network).await } pub(crate) async fn fake_valid_successor_for_tests( predecessor: &Block, timestamp: Timestamp, - seed: [u8; 32], + rness: Randomness<2, 2>, network: Network, ) -> Block { - fake_block_successor(predecessor, timestamp, seed, true, network).await + fake_block_successor(predecessor, timestamp, true, rness, network).await } /// Create a block with coinbase going to self. For testing purposes. @@ -1352,13 +1314,13 @@ pub(crate) async fn fake_valid_successor_for_tests( /// will not pass `triton_vm::verify`, as its validity is only mocked. pub(crate) async fn fake_valid_block_for_tests( state_lock: &GlobalStateLock, - seed: [u8; 32], + rness: Randomness<2, 2>, ) -> Block { let current_tip = state_lock.lock_guard().await.chain.light_state().clone(); fake_valid_successor_for_tests( ¤t_tip, current_tip.header().timestamp + Timestamp::hours(1), - seed, + rness, state_lock.cli().network, ) .await @@ -1373,13 +1335,18 @@ pub(crate) async fn fake_valid_block_for_tests( pub(crate) async fn fake_valid_sequence_of_blocks_for_tests( predecessor: &Block, block_interval: Timestamp, - seed: [u8; 32], + rness: [Randomness<2, 2>; N], network: Network, ) -> [Block; N] { - fake_valid_sequence_of_blocks_for_tests_dyn(predecessor, block_interval, seed, network, N) - .await - .try_into() - .unwrap() + fake_valid_sequence_of_blocks_for_tests_dyn( + predecessor, + block_interval, + rness.to_vec(), + network, + ) + .await + .try_into() + .unwrap() } /// Create a deterministic sequence of valid blocks. @@ -1391,17 +1358,15 @@ pub(crate) async fn fake_valid_sequence_of_blocks_for_tests( pub(crate) async fn fake_valid_sequence_of_blocks_for_tests_dyn( mut predecessor: &Block, block_interval: Timestamp, - seed: [u8; 32], + mut rness_vec: Vec>, network: Network, - n: usize, ) -> Vec { let mut blocks = vec![]; - let mut rng: StdRng = SeedableRng::from_seed(seed); - for _ in 0..n { + while let Some(rness) = rness_vec.pop() { let block = fake_valid_successor_for_tests( predecessor, predecessor.header().timestamp + block_interval, - rng.random(), + rness, network, ) .await; @@ -1481,6 +1446,24 @@ where Ok(()) } +// recursively copy source dir to destination +pub fn copy_dir_recursive(source: &PathBuf, destination: &PathBuf) -> std::io::Result<()> { + if !source.is_dir() { + return Err(std::io::Error::other("Source is not a directory")); + } + std::fs::create_dir_all(destination)?; + for entry in std::fs::read_dir(source)? { + let entry = entry?; + let dest_path = &destination.join(entry.file_name()); + if entry.path().is_dir() { + copy_dir_recursive(&entry.path(), dest_path)?; + } else { + std::fs::copy(entry.path(), dest_path)?; + } + } + Ok(()) +} + mod tests { use super::*; diff --git a/src/util_types/mutator_set.rs b/src/util_types/mutator_set.rs index 9e45fd176..9f02191a8 100644 --- a/src/util_types/mutator_set.rs +++ b/src/util_types/mutator_set.rs @@ -94,7 +94,6 @@ mod tests { use tests::removal_record::RemovalRecord; use super::*; - use crate::tests::shared::mock_item_and_randomnesses; use crate::tests::shared_tokio_runtime; use crate::util_types::mutator_set::mutator_set_accumulator::MutatorSetAccumulator; use crate::util_types::test_shared::mutator_set::*; diff --git a/src/util_types/mutator_set/chunk.rs b/src/util_types/mutator_set/chunk.rs index 21f9000ef..e4b962cb0 100644 --- a/src/util_types/mutator_set/chunk.rs +++ b/src/util_types/mutator_set/chunk.rs @@ -286,37 +286,32 @@ mod tests { assert!(s_back.relative_indices.is_empty()); } - #[test] - fn test_indices() { - let mut chunk = Chunk::empty_chunk(); - let mut rng = rand::rng(); - let num_insertions = 100; - for _ in 0..num_insertions { - let index = rng.next_u32() % (CHUNK_SIZE); - chunk.insert(index); - } - - let indices = chunk.to_indices(); - - let reconstructed_chunk = Chunk::from_indices(&indices); + proptest::proptest! { + #[test] + fn test_indices(indices in proptest::collection::vec(0u32..CHUNK_SIZE, 100)) { + let mut chunk = Chunk::empty_chunk(); + for index in indices { + chunk.insert(index); + } - assert_eq!(chunk, reconstructed_chunk); - } + let chunk_indices = chunk.to_indices(); + let reconstructed_chunk = Chunk::from_indices(&chunk_indices); - #[test] - fn test_chunk_decode() { - let mut chunk = Chunk::empty_chunk(); - let mut rng = rand::rng(); - let num_insertions = 100; - for _ in 0..num_insertions { - let index = rng.next_u32() % (CHUNK_SIZE); - chunk.insert(index); + proptest::prop_assert_eq!(chunk, reconstructed_chunk); } - let encoded = chunk.encode(); - let decoded = *Chunk::decode(&encoded).unwrap(); + #[test] + fn test_chunk_decode(indices in proptest::collection::vec(0u32..CHUNK_SIZE, 100)) { + let mut chunk = Chunk::empty_chunk(); + for index in indices { + chunk.insert(index); + } + + let encoded = chunk.encode(); + let decoded = *Chunk::decode(&encoded).unwrap(); - assert_eq!(chunk, decoded); + proptest::prop_assert_eq!(chunk, decoded); + } } /// Collect statistics about the typical number of elements in a `Chunk`. diff --git a/src/util_types/mutator_set/chunk_dictionary.rs b/src/util_types/mutator_set/chunk_dictionary.rs index c1681cf84..fd578a142 100644 --- a/src/util_types/mutator_set/chunk_dictionary.rs +++ b/src/util_types/mutator_set/chunk_dictionary.rs @@ -6,10 +6,6 @@ use std::vec::IntoIter; use arbitrary::Arbitrary; use get_size2::GetSize; use itertools::Itertools; -use rand::rngs::StdRng; -use rand::Rng; -use rand::RngCore; -use rand::SeedableRng; use serde::Deserialize; use serde::Serialize; use tasm_lib::prelude::TasmObject; @@ -109,7 +105,7 @@ impl ChunkDictionary { self.dictionary.is_empty() } - pub fn iter(&self) -> Iter<(ChunkIndex, AuthenticatedChunk)> { + pub fn iter(&self) -> Iter<'_, (ChunkIndex, AuthenticatedChunk)> { self.dictionary.iter() } @@ -117,7 +113,7 @@ impl ChunkDictionary { self.dictionary.len() } - pub fn iter_mut(&mut self) -> IterMut<(ChunkIndex, AuthenticatedChunk)> { + pub fn iter_mut(&mut self) -> IterMut<'_, (ChunkIndex, AuthenticatedChunk)> { self.dictionary.iter_mut() } @@ -179,37 +175,13 @@ impl IntoIterator for ChunkDictionary { } } -/// Generate pseudorandom chunk dictionary from the given seed, for testing purposes. -pub fn pseudorandom_chunk_dictionary(seed: [u8; 32]) -> ChunkDictionary { - let mut rng: StdRng = SeedableRng::from_seed(seed); - - let mut dictionary = vec![]; - for _ in 0..37 { - let key = rng.next_u64(); - let authpath: Vec = (0..rng.random_range(0..6)) - .map(|_| rng.random()) - .collect_vec(); - let chunk: Vec = (0..rng.random_range(0..17)) - .map(|_| rng.random()) - .collect_vec(); - - dictionary.push(( - key, - ( - MmrMembershipProof::new(authpath), - Chunk { - relative_indices: chunk, - }, - ), - )); - } - ChunkDictionary::new(dictionary) -} - #[cfg(test)] #[cfg_attr(coverage_nightly, coverage(off))] -mod tests { +pub mod tests { use macro_rules_attr::apply; + use proptest::collection; + use proptest::prelude::any; + use proptest::prop_compose; use twenty_first::math::other::random_elements; use twenty_first::math::tip5::Digest; use twenty_first::util_types::mmr::mmr_membership_proof::MmrMembershipProof; @@ -218,7 +190,22 @@ mod tests { use crate::tests::shared_tokio_runtime; use crate::util_types::archival_mmr::tests::mock; use crate::util_types::mutator_set::shared::CHUNK_SIZE; - use crate::util_types::test_shared::mutator_set::random_chunk_dictionary; + + prop_compose! { + pub fn propcompose_chunkdict() (dictionary in collection::vec(( + any::(), collection::vec(proptest_arbitrary_interop::arb::(), 0..6), collection::vec(any::(), 0..17), + ), 37)) -> ChunkDictionary { + ChunkDictionary::new(dictionary.into_iter().map(|(key, authpath, chunk)| ( + key, + ( + MmrMembershipProof::new(authpath), + Chunk { + relative_indices: chunk, + }, + ) + )).collect_vec()) + } + } #[apply(shared_tokio_runtime)] async fn hash_test() { @@ -311,10 +298,11 @@ mod tests { assert_eq!((mp, chunk), s_back_non_empty.get(&key).unwrap().clone()); } - #[test] - fn test_chunk_dictionary_decode() { - let chunk_dictionary = random_chunk_dictionary(); - + #[test_strategy::proptest] + fn test_chunk_dictionary_decode( + #[strategy(proptest_arbitrary_interop::arb::())] + chunk_dictionary: ChunkDictionary, + ) { let encoded = chunk_dictionary.encode(); let decoded = *ChunkDictionary::decode(&encoded).unwrap(); diff --git a/src/util_types/mutator_set/ms_membership_proof.rs b/src/util_types/mutator_set/ms_membership_proof.rs index c4777c34e..56af6ff05 100644 --- a/src/util_types/mutator_set/ms_membership_proof.rs +++ b/src/util_types/mutator_set/ms_membership_proof.rs @@ -8,9 +8,6 @@ use std::ops::IndexMut; use arbitrary::Arbitrary; use get_size2::GetSize; use itertools::Itertools; -use rand::rngs::StdRng; -use rand::Rng; -use rand::SeedableRng; use serde::Deserialize; use serde::Serialize; use tasm_lib::structure::tasm_object::TasmObject; @@ -23,7 +20,6 @@ use twenty_first::util_types::mmr::mmr_membership_proof::MmrMembershipProof; use twenty_first::util_types::mmr::mmr_trait::Mmr; use super::addition_record::AdditionRecord; -use super::chunk_dictionary::pseudorandom_chunk_dictionary; use super::chunk_dictionary::ChunkDictionary; use super::commit; use super::get_swbf_indices; @@ -556,46 +552,17 @@ impl MsMembershipProof { } } -/// Generate a pseudorandom mutator set membership proof from the given seed, for testing -/// purposes. -pub fn pseudorandom_mutator_set_membership_proof(seed: [u8; 32]) -> MsMembershipProof { - let mut rng: StdRng = SeedableRng::from_seed(seed); - let sender_randomness: Digest = rng.random(); - let receiver_preimage: Digest = rng.random(); - let (auth_path_aocl, aocl_leaf_index) = - pseudorandom_mmr_membership_proof_with_index(rng.random()); - let target_chunks: ChunkDictionary = pseudorandom_chunk_dictionary(rng.random()); - MsMembershipProof { - sender_randomness, - receiver_preimage, - aocl_leaf_index, - auth_path_aocl, - target_chunks, - } -} - -/// Generate a pseudorandom Merkle mountain range membership proof from the given seed, -/// for testing purposes. -pub fn pseudorandom_mmr_membership_proof_with_index(seed: [u8; 32]) -> (MmrMembershipProof, u64) { - let mut rng: StdRng = SeedableRng::from_seed(seed); - let leaf_index: u64 = rng.random(); - let authentication_path: Vec = (0..rng.random_range(0..15)) - .map(|_| rng.random()) - .collect_vec(); - ( - MmrMembershipProof { - authentication_path, - }, - leaf_index, - ) -} - #[cfg(test)] #[cfg_attr(coverage_nightly, coverage(off))] -mod tests { +pub mod tests { use itertools::Either; use itertools::Itertools; use macro_rules_attr::apply; + use proptest::collection; + use proptest::prelude::any; + use proptest::prelude::*; + use proptest::prop_compose; + use proptest_arbitrary_interop::arb; use rand::random; use rand::rngs::StdRng; use rand::Rng; @@ -611,7 +578,37 @@ mod tests { use crate::util_types::mutator_set::commit; use crate::util_types::test_shared::mutator_set::empty_rusty_mutator_set; use crate::util_types::test_shared::mutator_set::mock_item_and_randomnesses; - use crate::util_types::test_shared::mutator_set::random_mutator_set_membership_proof; + + const N: usize = 100; + + prop_compose! { + /// Generate a pseudorandom mutator set membership proof from the given seed, for testing purposes. + pub fn propcompose_msmembershipproof() ( + sender_randomness in arb::(), + receiver_preimage in arb::(), + (auth_path_aocl, aocl_leaf_index) in propcompose_mmrmembershipproof_with_index(), + target_chunks in crate::util_types::mutator_set::chunk_dictionary::tests::propcompose_chunkdict(), + ) -> MsMembershipProof { + MsMembershipProof { + sender_randomness, + receiver_preimage, + aocl_leaf_index, + auth_path_aocl, + target_chunks, + } + } + } + + prop_compose! { + /// Generate a pseudorandom Merkle mountain range membership proof from the given seed, + /// for testing purposes. + pub fn propcompose_mmrmembershipproof_with_index() (len in 0..15usize) ( + authentication_path in collection::vec(arb::(), len), + leaf_index in any::() + ) -> (MmrMembershipProof, u64) { + (MmrMembershipProof {authentication_path}, leaf_index) + } + } #[test] fn mp_equality_test() { @@ -699,12 +696,15 @@ mod tests { } } - #[apply(shared_tokio_runtime)] - async fn revert_update_from_remove_test() { - let n = 100; - let mut rng = rand::rng(); - - let own_index = rng.next_u32() as usize % n; + #[test_strategy::proptest(async = "tokio")] + async fn revert_update_from_remove_test( + #[strategy(0..N)] own_index: usize, + #[strategy(collection::vec(arb::(), N))] mut item_vec: Vec, + #[strategy(collection::vec(arb::(), N))] mut sender_randomness_vec: Vec, + #[strategy(collection::vec(arb::(), N))] mut receiver_preimage_vec: Vec, + #[strategy(collection::vec(any::(), N))] mut condition: Vec, + #[any] cutoff_rand: usize, + ) { let mut own_membership_proof = None; let mut own_item = None; @@ -714,10 +714,10 @@ mod tests { let mut membership_proofs: Vec<(Digest, MsMembershipProof)> = vec![]; // add items - for i in 0..n { - let item: Digest = random(); - let sender_randomness: Digest = random(); - let receiver_preimage: Digest = random(); + for i in 0..N { + let item: Digest = item_vec.pop().unwrap(); + let sender_randomness: Digest = sender_randomness_vec.pop().unwrap(); + let receiver_preimage: Digest = receiver_preimage_vec.pop().unwrap(); let addition_record = commit(item, sender_randomness, receiver_preimage.hash()); for (oi, mp) in &mut membership_proofs { @@ -768,12 +768,12 @@ mod tests { // generate some removal records let mut removal_records = vec![]; for (item, membership_proof) in membership_proofs { - if rng.next_u32() % 2 == 1 { + if condition.pop().unwrap() { let removal_record = archival_mutator_set.drop(item, &membership_proof).await; removal_records.push(removal_record); } } - let cutoff_point = 1 + (rng.next_u32() as usize % (removal_records.len() - 1)); + let cutoff_point = 1 + (cutoff_rand % (removal_records.len() - 1)); let mut membership_proof_snapshot = None; // apply removal records @@ -1394,10 +1394,12 @@ mod tests { } } - #[test] - fn test_decode_mutator_set_membership_proof() { - for _ in 0..100 { - let msmp = random_mutator_set_membership_proof(); + proptest::proptest! { + #![proptest_config(ProptestConfig { + cases: 100, .. ProptestConfig::default() + })] + #[test] + fn test_decode_mutator_set_membership_proof(msmp in propcompose_msmembershipproof()) { let encoded = msmp.encode(); let decoded: MsMembershipProof = *MsMembershipProof::decode(&encoded).unwrap(); assert_eq!(msmp, decoded); diff --git a/src/util_types/mutator_set/msa_and_records.rs b/src/util_types/mutator_set/msa_and_records.rs index 81c4a800a..84911ebc0 100644 --- a/src/util_types/mutator_set/msa_and_records.rs +++ b/src/util_types/mutator_set/msa_and_records.rs @@ -289,11 +289,12 @@ mod tests { use proptest::prop_assert; use proptest_arbitrary_interop::arb; use tasm_lib::prelude::Digest; - use test_strategy::proptest; use super::MsaAndRecords; - use crate::util_types::test_shared::mutator_set::random_mutator_set_membership_proof; - use crate::util_types::test_shared::mutator_set::random_removal_record; + use crate::util_types::mutator_set::ms_membership_proof::tests::propcompose_msmembershipproof; + use crate::util_types::mutator_set::ms_membership_proof::MsMembershipProof; + use crate::util_types::mutator_set::removal_record::RemovalRecord; + use crate::util_types::test_shared::mutator_set::propcompose_rr_with_independent_absindset_chunkdict; impl MsaAndRecords { /// Split an [MsaAndRecords] into multiple instances of the same type. @@ -329,7 +330,7 @@ mod tests { } } - #[proptest(cases = 1)] + #[test_strategy::proptest(cases = 1)] fn msa_and_records_is_valid( #[strategy(0usize..10)] _num_removals: usize, #[strategy(0u64..=u64::MAX)] _aocl_size: u64, @@ -348,21 +349,23 @@ mod tests { #[test] fn split_msa_and_records() { - split_prop([1]); - split_prop([0]); - split_prop([0, 5]); - split_prop([3, 4]); - split_prop([12, 2, 5]); + proptest::proptest!(|(data in vec((propcompose_rr_with_independent_absindset_chunkdict(), propcompose_msmembershipproof()), 1))| split_prop([1], data)); + proptest::proptest!(|(data in vec((propcompose_rr_with_independent_absindset_chunkdict(), propcompose_msmembershipproof()), 0))| split_prop([0], data)); + proptest::proptest!(|(data in vec((propcompose_rr_with_independent_absindset_chunkdict(), propcompose_msmembershipproof()), 5))| split_prop([0, 5], data)); + proptest::proptest!(|(data in vec((propcompose_rr_with_independent_absindset_chunkdict(), propcompose_msmembershipproof()), 7))| split_prop([3, 4], data)); + proptest::proptest!(|(data in vec((propcompose_rr_with_independent_absindset_chunkdict(), propcompose_msmembershipproof()), 19))| split_prop([12, 2, 5], data)); } - fn split_prop(split: [usize; N]) { + fn split_prop( + split: [usize; N], + mut data: Vec<(RemovalRecord, MsMembershipProof)>, + ) { let mut original = MsaAndRecords::default(); let total = split.into_iter().sum::(); for _ in 0..total { - original.removal_records.push(random_removal_record()); - original - .membership_proofs - .push(random_mutator_set_membership_proof()); + let datum = data.pop().unwrap(); + original.removal_records.push(datum.0); + original.membership_proofs.push(datum.1); } let split_msa_and_records = original.split_by(split); diff --git a/src/util_types/mutator_set/mutator_set_accumulator.rs b/src/util_types/mutator_set/mutator_set_accumulator.rs index 21305fca9..679b8655b 100644 --- a/src/util_types/mutator_set/mutator_set_accumulator.rs +++ b/src/util_types/mutator_set/mutator_set_accumulator.rs @@ -506,6 +506,7 @@ mod tests { use itertools::izip; use itertools::Itertools; use macro_rules_attr::apply; + use proptest::prelude::*; use proptest::prop_assert_eq; use rand::Rng; use test_strategy::proptest; @@ -864,13 +865,17 @@ mod tests { } } - #[test] - fn test_mutator_set_accumulator_decode() { - for _ in 0..100 { - let msa = random_mutator_set_accumulator(); + proptest::proptest! { + #![proptest_config(ProptestConfig { + cases: 100, .. ProptestConfig::default() + })] + #[test] + fn test_mutator_set_accumulator_decode( + msa in proptest_arbitrary_interop::arb::() + ) { let encoded = msa.encode(); let decoded: MutatorSetAccumulator = *MutatorSetAccumulator::decode(&encoded).unwrap(); - assert_eq!(msa, decoded); + prop_assert_eq!(msa, decoded); } } diff --git a/src/util_types/mutator_set/removal_record.rs b/src/util_types/mutator_set/removal_record.rs index 4988d44ed..4809d58c2 100644 --- a/src/util_types/mutator_set/removal_record.rs +++ b/src/util_types/mutator_set/removal_record.rs @@ -30,6 +30,8 @@ use super::shared::NUM_TRIALS; use super::MutatorSetError; use crate::models::blockchain::shared::Hash; use crate::prelude::twenty_first; +#[cfg(test)] +pub use tests::propcompose_absindset; #[derive(Debug, Clone, Copy, PartialEq, Eq, BFieldCodec, TasmObject, Hash)] #[cfg_attr(any(test, feature = "arbitrary-impls"), derive(Arbitrary))] @@ -379,10 +381,11 @@ pub(crate) enum RemovalRecordValidityError { #[cfg_attr(coverage_nightly, coverage(off))] mod tests { use itertools::Itertools; + use proptest::prelude::*; + use proptest::prop_compose; + use proptest_arbitrary_interop::arb; use rand::prelude::IndexedRandom; use rand::Rng; - use rand::RngCore; - use test_strategy::proptest; use super::*; use crate::util_types::mutator_set::addition_record::AdditionRecord; @@ -405,6 +408,12 @@ mod tests { } } + prop_compose! { + pub fn propcompose_absindset() (inner in [proptest::prelude::any::(); NUM_TRIALS as usize]) -> AbsoluteIndexSet { + AbsoluteIndexSet::new(&inner) + } + } + #[test] fn increment_bloom_filter_index_behaves_as_expected() { let (_item, _mp, removal_record) = mock_item_mp_rr_for_init_msa(); @@ -584,7 +593,8 @@ mod tests { assert!(!rr_for_aocl0.validate(&MutatorSetAccumulator::default())); } - #[proptest(cases = 10)] + /// non-deterministic; a correction was shelved at + #[test_strategy::proptest(cases = 10)] fn removal_record_missing_chunk_element_is_invalid_pbt( #[strategy(1u64..20*u64::from(BATCH_SIZE))] initial_additions: u64, #[strategy(0u64..(#initial_additions as u64))] index_to_drop: u64, @@ -806,52 +816,50 @@ mod tests { } } - #[test] - fn test_index_set_serialization() { - let mut rng = rand::rng(); - let original_indexset = AbsoluteIndexSet::new( - &(0..NUM_TRIALS) - .map(|_| (u128::from(rng.next_u64()) << 64) | u128::from(rng.next_u64())) - .collect_vec() - .try_into() - .unwrap(), - ); - let serialized_indexset = serde_json::to_string(&original_indexset).unwrap(); - let reconstructed_indexset: AbsoluteIndexSet = - serde_json::from_str(&serialized_indexset).unwrap(); + proptest::proptest! { + #[test] + fn test_index_set_serialization( + original_indexset in propcompose_absindset() + ) { + let serialized_indexset = serde_json::to_string(&original_indexset).unwrap(); + let reconstructed_indexset: AbsoluteIndexSet = + serde_json::from_str(&serialized_indexset).unwrap(); - assert_eq!(original_indexset, reconstructed_indexset); + assert_eq!(original_indexset, reconstructed_indexset); + } } - #[test] - fn test_removal_record_decode() { - for _ in 0..10 { - let removal_record = random_removal_record(); - let encoded = removal_record.encode(); - let decoded = *RemovalRecord::decode(&encoded).unwrap(); - assert_eq!(removal_record, decoded); + proptest::proptest! { + #![proptest_config(ProptestConfig { + cases: 10, .. ProptestConfig::default() + })] + #[test] + fn test_removal_record_decode(removal_record in arb::()) { + let encoded = &removal_record.encode(); + let decoded = *RemovalRecord::decode(encoded).unwrap(); + assert_eq!(removal_record, decoded); } - } - #[test] - fn test_removal_record_vec_decode() { - let mut rng = rand::rng(); - for _ in 0..10 { - let length = rng.random_range(0..10); - let removal_records = vec![random_removal_record(); length]; - let encoded = removal_records.encode(); - let decoded = *Vec::::decode(&encoded).unwrap(); - assert_eq!(removal_records, decoded); + #[test] + fn test_removal_record_vec_decode(removal_records in proptest::collection::vec(arb::(), 0..10)) { + let encoded = removal_records.encode(); + let decoded = *Vec::::decode(&encoded).unwrap(); + assert_eq!(removal_records, decoded); } } - #[test] - fn test_absindexset_record_decode() { - for _ in 0..100 { - let removal_record = random_removal_record(); - let encoded_absindexset = removal_record.absolute_indices.encode(); - let decoded_absindexset = *AbsoluteIndexSet::decode(&encoded_absindexset).unwrap(); - assert_eq!(removal_record.absolute_indices, decoded_absindexset); + proptest::proptest! { + #![proptest_config(ProptestConfig { + cases: 100, .. ProptestConfig::default() + })] + #[test] + fn test_absindexset_record_decode(removal_record in arb::()) { + let encoded_absindexset = removal_record.absolute_indices.encode(); + let decoded_absindexset = *AbsoluteIndexSet::decode(&encoded_absindexset).unwrap(); + assert_eq!( + removal_record.absolute_indices, + decoded_absindexset + ); } } } diff --git a/src/util_types/test_shared/mutator_set.rs b/src/util_types/test_shared/mutator_set.rs index 35c9278a9..ca6dd24e7 100644 --- a/src/util_types/test_shared/mutator_set.rs +++ b/src/util_types/test_shared/mutator_set.rs @@ -19,24 +19,14 @@ use crate::util_types::mutator_set::active_window::ActiveWindow; use crate::util_types::mutator_set::addition_record::AdditionRecord; use crate::util_types::mutator_set::archival_mutator_set::ArchivalMutatorSet; use crate::util_types::mutator_set::chunk::Chunk; -use crate::util_types::mutator_set::chunk_dictionary::pseudorandom_chunk_dictionary; -use crate::util_types::mutator_set::chunk_dictionary::ChunkDictionary; use crate::util_types::mutator_set::commit; -use crate::util_types::mutator_set::ms_membership_proof::pseudorandom_mutator_set_membership_proof; use crate::util_types::mutator_set::ms_membership_proof::MsMembershipProof; use crate::util_types::mutator_set::mutator_set_accumulator::MutatorSetAccumulator; -use crate::util_types::mutator_set::removal_record::AbsoluteIndexSet; use crate::util_types::mutator_set::removal_record::RemovalRecord; use crate::util_types::mutator_set::rusty_archival_mutator_set::RustyArchivalMutatorSet; use crate::util_types::mutator_set::shared::CHUNK_SIZE; -use crate::util_types::mutator_set::shared::NUM_TRIALS; use crate::util_types::mutator_set::shared::WINDOW_SIZE; -pub fn random_chunk_dictionary() -> ChunkDictionary { - let mut rng = rand::rng(); - pseudorandom_chunk_dictionary(rng.random::<[u8; 32]>()) -} - pub async fn get_all_indices_with_duplicates< MmrStorage: StorageVec + Send + Sync, ChunkStorage: StorageVec + Send + Sync, @@ -120,22 +110,11 @@ pub fn random_mmra() -> MmrAccumulator { pseudorandom_mmra(rand::rng().random()) } -/// Generate a pseudorandom removal record from the given seed, for testing purposes. -pub(crate) fn pseudorandom_removal_record(seed: [u8; 32]) -> RemovalRecord { - let mut rng: StdRng = SeedableRng::from_seed(seed); - let absolute_indices = AbsoluteIndexSet::new( - &(0..NUM_TRIALS as usize) - .map(|_| (u128::from(rng.next_u64()) << 64) ^ u128::from(rng.next_u64())) - .collect_vec() - .try_into() - .unwrap(), - ); - let target_chunks = pseudorandom_chunk_dictionary(rng.random::<[u8; 32]>()); - - RemovalRecord { - absolute_indices, - target_chunks, - } +proptest::prop_compose! { + pub fn propcompose_rr_with_independent_absindset_chunkdict() ( + absolute_indices in crate::util_types::mutator_set::removal_record::propcompose_absindset(), + target_chunks in crate::util_types::mutator_set::chunk_dictionary::tests::propcompose_chunkdict() + ) -> RemovalRecord {RemovalRecord {absolute_indices, target_chunks}} } pub fn pseudorandom_addition_record(seed: [u8; 32]) -> AdditionRecord { @@ -146,11 +125,6 @@ pub fn pseudorandom_addition_record(seed: [u8; 32]) -> AdditionRecord { } } -pub fn random_addition_record() -> AdditionRecord { - let mut rng = rand::rng(); - pseudorandom_addition_record(rng.random::<[u8; 32]>()) -} - pub fn pseudorandom_mmra(seed: [u8; 32]) -> MmrAccumulator { let mut rng: StdRng = SeedableRng::from_seed(seed); let leaf_count = u64::from(rng.next_u32()); @@ -391,16 +365,6 @@ pub fn random_swbf_active() -> ActiveWindow { aw } -/// Generate a random MsMembershipProof. For serialization testing. Might not be a consistent or valid object. -pub fn random_mutator_set_membership_proof() -> MsMembershipProof { - pseudorandom_mutator_set_membership_proof(rand::rng().random()) -} - -pub fn random_removal_record() -> RemovalRecord { - let mut rng = rand::rng(); - pseudorandom_removal_record(rng.random::<[u8; 32]>()) -} - fn merkle_verify_tester_helper(root: Digest, index: u64, path: &[Digest], leaf: Digest) -> bool { let mut acc = leaf; for (shift, &p) in path.iter().enumerate() { @@ -423,9 +387,6 @@ mod tests { #[apply(shared_tokio_runtime)] async fn can_call() { - let rcd = random_chunk_dictionary(); - assert!(!rcd.is_empty()); - let _ = random_removal_record(); let mut rms = empty_rusty_mutator_set().await; let ams = rms.ams_mut(); let _ = get_all_indices_with_duplicates(ams).await;