1use crate::blockdata::transaction::{ExtraField, KeyImage, RawExtraField, SubField, TxOutTarget};
17use crate::consensus::encode::Encodable;
18use crate::consensus::{deserialize, serialize};
19use crate::cryptonote::hash::Hashable;
20use crate::util::key::H;
21use crate::util::ringct::{CtKey, EcdhInfo, Key, RctSig, RctSigBase, RctSigPrunable, RctType};
22use crate::{
23 Amount, Block, BlockHeader, Hash, PrivateKey, PublicKey, Transaction, TransactionPrefix, TxIn,
24 TxOut, VarInt, ViewPair,
25};
26use hex::{FromHex, ToHex};
27use std::io;
28use std::str::FromStr;
29
30pub fn fuzz_block_deserialize(fuzz_data: &[u8]) -> bool {
32 let fuzz_bytes = fuzz_data.to_vec();
33
34 if let Ok(val) = deserialize::<Block>(&fuzz_bytes[..]) {
36 assert_eq!(fuzz_bytes, serialize(&val), "\nfuzz_data: {:?}", fuzz_data);
37 }
38
39 true
40}
41
42pub fn fuzz_block_header_deserialize(fuzz_data: &[u8]) -> bool {
44 let fuzz_bytes = fuzz_data.to_vec();
45
46 if let Ok(val) = deserialize::<BlockHeader>(&fuzz_bytes[..]) {
48 assert_eq!(fuzz_bytes, serialize(&val), "\nfuzz_data: {:?}", fuzz_data);
49 }
50
51 true
52}
53
54pub fn fuzz_transaction_prefix_deserialize(fuzz_data: &[u8]) -> bool {
56 let fuzz_bytes = fuzz_data.to_vec();
57
58 if let Ok(val) = deserialize::<TransactionPrefix>(&fuzz_bytes[..]) {
60 assert_eq!(fuzz_bytes, serialize(&val), "\nfuzz_data: {:?}", fuzz_data);
61 }
62
63 true
64}
65
66#[derive(Clone, Copy, PartialEq, Eq)]
68pub enum AddPadding {
69 ToFront,
71 ToMiddle,
73 ToRear,
75}
76
77fn u64_val_from_fuzz_data(fuzz_data: &[u8]) -> u64 {
78 if fuzz_data.is_empty() {
79 0
80 } else {
81 let mut vec = fuzz_data.to_vec().clone();
82 vec.resize(8, 0);
83 let mut bytes = [0u8; 8];
84 bytes.copy_from_slice(vec.as_slice());
85 u64::from_le_bytes(bytes)
86 }
87}
88
89pub fn fuzz_create_extra_field(fuzz_data: &[u8], add_padding: AddPadding) -> ExtraField {
91 let fuzz_bytes = fuzz_data.to_vec();
92 let hash = Hash::new(fuzz_data);
93
94 let tx_pub_key_field = SubField::TxPublicKey(match PublicKey::from_slice(fuzz_data) {
96 Ok(val) => val,
97 Err(_) => H,
98 });
99 let nonce_field = SubField::Nonce(fuzz_bytes.clone());
100
101 let padding_field = SubField::Padding(fuzz_bytes.first().copied().unwrap_or_default());
103
104 let u64_val = u64_val_from_fuzz_data(fuzz_data);
106 let merge_mining_field = SubField::MergeMining(VarInt(u64_val), hash);
107
108 let additional_public_key_field =
110 SubField::AdditionalPublickKey(match PublicKey::from_slice(fuzz_data) {
111 Ok(val) => {
112 if fuzz_bytes.is_empty() {
113 vec![]
114 } else {
115 vec![val; (fuzz_bytes[0] % 10 + 1) as usize]
116 }
117 }
118 Err(_) => vec![H],
119 });
120
121 let mysterious_miner_gate_field = SubField::MysteriousMinerGate(fuzz_bytes);
123
124 let sub_fields = match add_padding {
125 AddPadding::ToFront => vec![
126 padding_field, tx_pub_key_field,
128 nonce_field,
129 merge_mining_field,
130 additional_public_key_field,
131 mysterious_miner_gate_field,
132 ],
133 AddPadding::ToMiddle => vec![
134 tx_pub_key_field,
135 nonce_field,
136 merge_mining_field,
137 padding_field, additional_public_key_field,
139 mysterious_miner_gate_field,
140 ],
141 AddPadding::ToRear => vec![
142 tx_pub_key_field,
143 nonce_field,
144 merge_mining_field,
145 additional_public_key_field,
146 mysterious_miner_gate_field,
147 padding_field,
148 ],
149 };
150
151 ExtraField(sub_fields)
153}
154
155pub fn fuzz_extra_field_parse_sub_fields(extra_field: &ExtraField) -> bool {
157 for sub_field in &extra_field.0 {
158 let ser_sub_field = serialize(sub_field);
159 match deserialize::<SubField>(&ser_sub_field) {
160 Ok(des_sub_field) => {
161 assert_eq!(sub_field, &des_sub_field, "\nsub field: {}", sub_field)
162 }
163 Err(err) => {
164 panic!(
165 "Deserializing a serialized SubField may not fail\n({})\nsub field: {:?}",
166 err, sub_field
167 )
168 }
169 }
170 }
171
172 true
173}
174
175pub fn fuzz_extra_field_try_parse(
177 extra_field: &ExtraField,
178 add_padding: AddPadding,
179 fuzz_data: &[u8],
180) -> bool {
181 let raw_extra_field = RawExtraField::from(extra_field.clone());
182 match ExtraField::try_parse(&raw_extra_field) {
183 Ok(parsed_extra_field) => {
184 assert_eq!(
185 extra_field, &parsed_extra_field,
186 "\nOn 'Ok(_)\noriginal: {:?}\nparsed: {:?}\n'fuzz_data: {:?}",
187 extra_field, parsed_extra_field, fuzz_data
188 )
189 }
190 Err(parsed_extra_field) => {
191 if parsed_extra_field.0.len() > extra_field.0.len() {
192 panic!(
193 "On 'Err(_)', parsed extra field has to many sub fields\noriginal: {:?}\nparsed: {:?}\nfuzz_data: {:?}",
194 extra_field,
195 parsed_extra_field,
196 fuzz_data,
197 );
198 }
199 for parsed_sub_field in parsed_extra_field.0.iter() {
200 match parsed_sub_field {
201 SubField::Padding(_) => {
202 }
204 _ => {
205 extra_field.0.iter().find(|&x| x == parsed_sub_field).unwrap_or_else(|| {
207 panic!(
208 "On 'Err(_)', parsed sub field '{}' is not in original extra field\noriginal: {:?}\nparsed: {:?}\nfuzz_data: {:?}",
209 parsed_sub_field,
210 extra_field,
211 parsed_extra_field,
212 fuzz_data,
213 )
214 });
215 }
216 }
217 }
218 if add_padding == AddPadding::ToRear {
219 panic!(
220 "\nOn 'Err(_)', parsing a serialized ExtraField with padding at the rear may not fail\n({:?})\n({:?})\nfuzz_data: {:?}",
221 extra_field,
222 parsed_extra_field,
223 fuzz_data,
224 );
225 }
226 }
227 };
228
229 true
230}
231
232pub fn fuzz_create_raw_extra_field(fuzz_data: &[u8]) -> RawExtraField {
234 let add_padding = if fuzz_data.is_empty() {
235 AddPadding::ToMiddle
236 } else {
237 match fuzz_data.len() % 3 {
238 0 => AddPadding::ToFront,
239 1 => AddPadding::ToMiddle,
240 _ => AddPadding::ToRear,
241 }
242 };
243 RawExtraField::from(fuzz_create_extra_field(fuzz_data, add_padding))
244}
245
246pub fn fuzz_transaction_deserialize(fuzz_data: &[u8]) -> bool {
248 let fuzz_bytes = fuzz_data.to_vec();
249
250 if let Ok(val) = deserialize::<Transaction>(&fuzz_bytes[..]) {
252 assert_eq!(fuzz_bytes, serialize(&val));
253 }
254
255 let raw_extra_field = fuzz_create_raw_extra_field(fuzz_data);
256
257 let transaction = fuzz_create_transaction_alternative_1(fuzz_data, &raw_extra_field);
258 let serialized_tx = serialize(&transaction);
259 let _ = deserialize::<Transaction>(&serialized_tx[..]);
260
261 let transaction = fuzz_create_transaction_alternative_2(fuzz_data, &raw_extra_field);
262 let serialized_tx = serialize(&transaction);
263 let _ = deserialize::<Transaction>(&serialized_tx[..]);
264
265 true
266}
267
268pub fn fuzz_transaction_components(fuzz_data: &[u8]) -> bool {
270 let fuzz_bytes = fuzz_data.to_vec().clone();
271 let (rct_type, inputs, outputs, mixin) = if fuzz_bytes.is_empty() {
272 (RctType::Null, 0, 0, 0)
273 } else {
274 (
275 match fuzz_bytes[0] % 8 {
276 0 => RctType::Null,
277 1 => RctType::Full,
278 3 => RctType::Clsag,
279 4 => RctType::Simple,
280 5 => RctType::Bulletproof,
281 6 => RctType::Bulletproof2,
282 7 => RctType::BulletproofPlus,
283 _ => RctType::Null,
284 },
285 fuzz_bytes[0] % 5,
286 fuzz_bytes[0] % 7,
287 fuzz_bytes[0] % 3,
288 )
289 };
290
291 if let Ok(val) = deserialize::<TransactionPrefix>(&fuzz_bytes[..]) {
293 assert_eq!(fuzz_bytes, serialize(&val));
294 }
295
296 let fuzz_bytes = fuzz_data.to_vec().clone();
298 let mut decoder = io::Cursor::new(&fuzz_bytes);
299 if let Ok(Some(rct_sig)) =
300 RctSigBase::consensus_decode(&mut decoder, inputs as usize, outputs as usize)
301 {
302 let mut encoder = Vec::new();
303 if rct_sig.consensus_encode(&mut encoder).is_ok() {
304 }
307 }
308
309 let fuzz_bytes = fuzz_data.to_vec().clone();
311 let mut decoder = io::Cursor::new(&fuzz_bytes);
312 if let Ok(Some(rct_sig)) = RctSigPrunable::consensus_decode(
313 &mut decoder,
314 rct_type,
315 inputs as usize,
316 outputs as usize,
317 mixin as usize,
318 ) {
319 let mut encoder = Vec::new();
320 if rct_sig.consensus_encode(&mut encoder, rct_type).is_ok() {
321 }
324 }
325
326 true
327}
328
329pub fn fuzz_create_transaction_alternative_1(
331 fuzz_data: &[u8],
332 raw_extra_field: &RawExtraField,
333) -> Transaction {
334 let hash_1 = Hash::new(fuzz_data);
335 let hash_2 = Hash::new(hash_1.0);
336 let hash_3 = Hash::new(hash_2.0);
337 let hash_4 = Hash::new(hash_3.0);
338 let hash_5 = Hash::new(hash_4.0);
339 let hash_6 = Hash::new(hash_5.0);
340 let hash_7 = Hash::new(hash_6.0);
341 let hash_8 = Hash::new(hash_7.0);
342 let u64_val = u64_val_from_fuzz_data(fuzz_data);
343
344 let prefix = TransactionPrefix {
345 version: VarInt(u64_val),
346 unlock_time: VarInt(u64_val),
347 inputs: vec![
348 TxIn::ToKey {
349 amount: VarInt(u64_val),
350 key_offsets: vec![],
351 k_image: KeyImage { image: hash_1 },
352 },
353 TxIn::Gen {
354 height: VarInt(u64_val),
355 },
356 ],
357 outputs: vec![
358 TxOut {
359 amount: VarInt(u64_val),
360 target: TxOutTarget::ToKey { key: hash_2.0 },
361 },
362 TxOut {
363 amount: VarInt(u64_val),
364 target: TxOutTarget::ToTaggedKey {
365 key: hash_3.0,
366 view_tag: hash_1.0[0],
367 },
368 },
369 ],
370 extra: raw_extra_field.clone(),
371 };
372
373 let rct_signatures = RctSig {
374 sig: Option::from(RctSigBase {
375 rct_type: RctType::Full,
376 txn_fee: Amount::from_pico(u64_val),
377 pseudo_outs: vec![
378 Key { key: hash_4.0 },
379 Key { key: hash_8.0 },
380 Key { key: hash_7.0 },
381 ],
382 ecdh_info: vec![
383 EcdhInfo::Standard {
384 mask: Key { key: hash_5.0 },
385 amount: Key { key: hash_6.0 },
386 },
387 EcdhInfo::Standard {
388 mask: Key { key: hash_5.0 },
389 amount: Key { key: hash_6.0 },
390 },
391 ],
392 out_pk: vec![CtKey {
393 mask: Key { key: hash_7.0 },
394 }],
395 }),
396 p: None,
397 };
398
399 Transaction {
400 prefix,
401 signatures: vec![],
402 rct_signatures,
403 }
404}
405
406pub fn fuzz_create_transaction_alternative_2(
408 fuzz_data: &[u8],
409 raw_extra_field: &RawExtraField,
410) -> Transaction {
411 let hash_1 = Hash::new(fuzz_data);
412 let hash_2 = Hash::new(hash_1.0);
413 let hash_3 = Hash::new(hash_2.0);
414 let hash_4 = Hash::new(hash_3.0);
415 let hash_5 = Hash::new(hash_4.0);
416 let hash_6 = Hash::new(hash_5.0);
417 let hash_7 = Hash::new(hash_6.0);
418 let hash_8 = Hash::new(hash_7.0);
419 let u64_val = u64_val_from_fuzz_data(fuzz_data);
420
421 let prefix = TransactionPrefix {
422 version: VarInt(u64_val),
423 unlock_time: VarInt(u64_val),
424 inputs: vec![
425 TxIn::ToKey {
427 amount: VarInt(u64_val),
428 key_offsets: vec![],
429 k_image: KeyImage { image: hash_1 },
430 },
431 TxIn::Gen {
432 height: VarInt(u64_val),
433 },
434 TxIn::ToKey {
435 amount: VarInt(u64_val),
436 key_offsets: vec![VarInt(u64_val)],
437 k_image: KeyImage { image: hash_1 },
438 },
439 ],
440 outputs: vec![
441 TxOut {
442 amount: VarInt(u64_val),
443 target: TxOutTarget::ToKey { key: hash_2.0 },
444 },
445 TxOut {
446 amount: VarInt(u64_val),
447 target: TxOutTarget::ToTaggedKey {
448 key: hash_3.0,
449 view_tag: hash_1.0[0],
450 },
451 },
452 ],
453 extra: raw_extra_field.clone(),
454 };
455
456 let rct_signatures = RctSig {
457 sig: Option::from(RctSigBase {
458 rct_type: RctType::Full,
459 txn_fee: Amount::from_pico(u64_val),
460 pseudo_outs: vec![Key { key: hash_4.0 }, Key { key: hash_8.0 }],
461 ecdh_info: vec![
462 EcdhInfo::Standard {
463 mask: Key { key: hash_5.0 },
464 amount: Key { key: hash_6.0 },
465 },
466 EcdhInfo::Standard {
467 mask: Key { key: hash_5.0 },
468 amount: Key { key: hash_6.0 },
469 },
470 ],
471 out_pk: vec![
472 CtKey {
473 mask: Key { key: hash_7.0 },
474 },
475 CtKey {
476 mask: Key { key: hash_8.0 },
477 },
478 ],
479 }),
480 p: Option::from(RctSigPrunable {
481 range_sigs: vec![],
482 bulletproofs: vec![],
483 bulletproofplus: vec![],
484 MGs: vec![],
485 Clsags: vec![],
486 pseudo_outs: vec![],
487 }),
488 };
489
490 Transaction {
491 prefix,
492 signatures: vec![],
493 rct_signatures,
494 }
495}
496
497pub fn fuzz_hash_convert(fuzz_data: &[u8]) -> bool {
499 let hash = Hash::new(fuzz_data);
501
502 let hash_str: String = hash.encode_hex();
503 if let Ok(hash2) = Hash::from_hex(hash_str.clone()) {
504 assert_eq!(hash, hash2);
505 }
506
507 let hash_str_with_0x = format!("0x{hash_str}");
508 if let Ok(hash2) = Hash::from_hex(hash_str_with_0x) {
509 assert_eq!(hash, hash2);
510 }
511
512 assert_eq!(hash.as_scalar(), Hash::hash_to_scalar(fuzz_data));
513
514 true
515}
516
517pub fn fuzz_raw_extra_field_deserialize(raw_extra_field: &RawExtraField) -> bool {
519 let raw_extra_field_bytes = serialize(raw_extra_field);
520 if let Ok(raw_extra_field_2) = deserialize::<RawExtraField>(&raw_extra_field_bytes) {
521 assert_eq!(raw_extra_field, &raw_extra_field_2);
522 }
523
524 true
525}
526
527pub fn fuzz_raw_extra_field_from(fuzz_data: &[u8]) -> bool {
529 let extra_field = fuzz_create_extra_field(fuzz_data, AddPadding::ToRear);
530 let _ = RawExtraField::from(extra_field.clone());
531 let _ = fuzz_create_raw_extra_field(fuzz_data);
532
533 true
534}
535
536pub fn fuzz_transaction_hash(transaction: &Transaction) -> bool {
538 let _hash = transaction.hash();
539 true
540}
541
542pub fn fuzz_transaction_check_outputs(transaction: &Transaction) -> bool {
544 let secret_view = match PrivateKey::from_str(
545 "bcfdda53205318e1c14fa0ddca1a45df363bb427972981d0249d0f4652a7df07",
546 ) {
547 Ok(val) => val,
548 Err(_) => {
549 return true;
551 }
552 };
553 let secret_spend = match PrivateKey::from_str(
554 "e5f4301d32f3bdaef814a835a18aaaa24b13cc76cf01a832a7852faf9322e907",
555 ) {
556 Ok(val) => val,
557 Err(_) => {
558 return true;
560 }
561 };
562 let public_spend = PublicKey::from_private_key(&secret_spend);
563 let viewpair = ViewPair {
564 view: secret_view,
565 spend: public_spend,
566 };
567
568 let _ = transaction.check_outputs(&viewpair, 0..3, 0..3);
569 true
570}
571
572#[cfg(test)]
573mod tests {
574 use crate::{Address, AddressType, Network};
575 use quickcheck::QuickCheck;
576
577 use crate::util::fuzz_utils::{
578 fuzz_block_deserialize, fuzz_block_header_deserialize, fuzz_create_extra_field,
579 fuzz_create_raw_extra_field, fuzz_create_transaction_alternative_1,
580 fuzz_create_transaction_alternative_2, fuzz_extra_field_parse_sub_fields,
581 fuzz_extra_field_try_parse, fuzz_hash_convert, fuzz_raw_extra_field_deserialize,
582 fuzz_raw_extra_field_from, fuzz_transaction_check_outputs, fuzz_transaction_components,
583 fuzz_transaction_deserialize, fuzz_transaction_hash, fuzz_transaction_prefix_deserialize,
584 AddPadding,
585 };
586
587 #[test]
588 fn test_fuzz_block_deserialize() {
589 fn internal(data: Vec<u8>) -> bool {
590 fuzz_block_deserialize(&data)
591 }
592
593 const TESTS: u64 = 10_000;
594
595 QuickCheck::new()
596 .min_tests_passed(TESTS)
597 .tests(TESTS)
598 .max_tests(TESTS)
599 .quickcheck(internal as fn(Vec<u8>) -> bool);
600 }
601
602 #[test]
603 fn test_fuzz_block_header_deserialize() {
604 fn internal(data: Vec<u8>) -> bool {
605 fuzz_block_header_deserialize(&data)
606 }
607
608 const TESTS: u64 = 10_000;
609
610 QuickCheck::new()
611 .min_tests_passed(TESTS)
612 .tests(TESTS)
613 .max_tests(TESTS)
614 .quickcheck(internal as fn(Vec<u8>) -> bool);
615 }
616
617 #[test]
618 fn test_fuzz_transaction_prefix_deserialize() {
619 fn internal(data: Vec<u8>) -> bool {
620 fuzz_transaction_prefix_deserialize(&data)
621 }
622
623 const TESTS: u64 = 10_000;
624
625 QuickCheck::new()
626 .min_tests_passed(TESTS)
627 .tests(TESTS)
628 .max_tests(TESTS)
629 .quickcheck(internal as fn(Vec<u8>) -> bool);
630 }
631
632 #[test]
633 fn test_fuzz_transaction_deserialize() {
634 fn internal(data: Vec<u8>) -> bool {
635 fuzz_transaction_deserialize(&data)
636 }
637
638 const TESTS: u64 = 10_000;
639
640 QuickCheck::new()
641 .min_tests_passed(TESTS)
642 .tests(TESTS)
643 .max_tests(TESTS)
644 .quickcheck(internal as fn(Vec<u8>) -> bool);
645 }
646
647 #[test]
648 fn test_fuzz_transaction_components() {
649 fn internal(data: Vec<u8>) -> bool {
650 fuzz_transaction_components(&data)
651 }
652
653 const TESTS: u64 = 1_000;
654
655 QuickCheck::new()
656 .min_tests_passed(TESTS)
657 .tests(TESTS)
658 .max_tests(TESTS)
659 .quickcheck(internal as fn(Vec<u8>) -> bool);
660 }
661
662 #[test]
663 fn test_fuzz_hash_convert() {
664 fn internal(data: Vec<u8>) -> bool {
665 fuzz_hash_convert(&data)
666 }
667
668 const TESTS: u64 = 10_000;
669
670 QuickCheck::new()
671 .min_tests_passed(TESTS)
672 .tests(TESTS)
673 .max_tests(TESTS)
674 .quickcheck(internal as fn(Vec<u8>) -> bool);
675 }
676
677 #[test]
678 fn test_fuzz_raw_extra_field_from() {
679 fn internal(data: Vec<u8>) -> bool {
680 fuzz_raw_extra_field_from(&data)
681 }
682
683 const TESTS: u64 = 10_000;
684
685 QuickCheck::new()
686 .min_tests_passed(TESTS)
687 .tests(TESTS)
688 .max_tests(TESTS)
689 .quickcheck(internal as fn(Vec<u8>) -> bool);
690 }
691
692 #[test]
693 fn test_fuzz_raw_extra_field_deserialize() {
694 fn internal(data: Vec<u8>) -> bool {
695 let raw_extra_field = fuzz_create_raw_extra_field(&data);
696 fuzz_raw_extra_field_deserialize(&raw_extra_field)
697 }
698
699 const TESTS: u64 = 10_000;
700
701 QuickCheck::new()
702 .min_tests_passed(TESTS)
703 .tests(TESTS)
704 .max_tests(TESTS)
705 .quickcheck(internal as fn(Vec<u8>) -> bool);
706 }
707
708 #[test]
709 fn test_fuzz_extra_field_parse_sub_fields() {
710 fn internal(data: Vec<u8>) -> bool {
711 let add_padding = if data.is_empty() {
712 AddPadding::ToMiddle
713 } else {
714 match data.len() % 3 {
715 0 => AddPadding::ToFront,
716 1 => AddPadding::ToMiddle,
717 _ => AddPadding::ToRear,
718 }
719 };
720 let extra_field = fuzz_create_extra_field(&data, add_padding);
721 fuzz_extra_field_parse_sub_fields(&extra_field)
722 }
723
724 const TESTS: u64 = 10_000;
725
726 QuickCheck::new()
727 .min_tests_passed(TESTS)
728 .tests(TESTS)
729 .max_tests(TESTS)
730 .quickcheck(internal as fn(Vec<u8>) -> bool);
731 }
732
733 #[test]
734 fn test_fuzz_extra_field_try_parse() {
735 fn internal(data: Vec<u8>) -> bool {
736 let add_padding = if data.is_empty() {
737 AddPadding::ToMiddle
738 } else {
739 match data.len() % 3 {
740 0 => AddPadding::ToFront,
741 1 => AddPadding::ToMiddle,
742 _ => AddPadding::ToRear,
743 }
744 };
745 let extra_field = fuzz_create_extra_field(&data, add_padding);
746 fuzz_extra_field_try_parse(&extra_field, add_padding, &data)
747 }
748
749 const TESTS: u64 = 10_000;
750
751 QuickCheck::new()
752 .min_tests_passed(TESTS)
753 .tests(TESTS)
754 .max_tests(TESTS)
755 .quickcheck(internal as fn(Vec<u8>) -> bool);
756 }
757
758 #[test]
759 fn test_fuzz_transaction_hash() {
760 fn internal(data: Vec<u8>) -> bool {
761 let raw_extra_field = fuzz_create_raw_extra_field(&data);
762 let transaction = fuzz_create_transaction_alternative_1(&data, &raw_extra_field);
763 let _ = fuzz_transaction_hash(&transaction);
764 let transaction = fuzz_create_transaction_alternative_2(&data, &raw_extra_field);
765 fuzz_transaction_hash(&transaction)
766 }
767
768 const TESTS: u64 = 10_000;
769
770 QuickCheck::new()
771 .min_tests_passed(TESTS)
772 .tests(TESTS)
773 .max_tests(TESTS)
774 .quickcheck(internal as fn(Vec<u8>) -> bool);
775 }
776
777 #[test]
778 fn test_fuzz_transaction_check_outputs() {
779 fn internal(data: Vec<u8>) -> bool {
780 let raw_extra_field = fuzz_create_raw_extra_field(&data);
781 let transaction = fuzz_create_transaction_alternative_1(&data, &raw_extra_field);
782 let _ = fuzz_transaction_check_outputs(&transaction);
783 let transaction = fuzz_create_transaction_alternative_2(&data, &raw_extra_field);
784 let _ = fuzz_transaction_check_outputs(&transaction);
785 true
786 }
787
788 const TESTS: u64 = 1_000;
789
790 QuickCheck::new()
791 .min_tests_passed(TESTS)
792 .tests(TESTS)
793 .max_tests(TESTS)
794 .quickcheck(internal as fn(Vec<u8>) -> bool);
795 }
796
797 #[test]
798 fn test_fuzz_address_from_bytes() {
799 fn internal(data: Vec<u8>) -> bool {
800 let _ = Address::from_bytes(&data);
801 true
802 }
803
804 const TESTS: u64 = 10_000;
805
806 QuickCheck::new()
807 .min_tests_passed(TESTS)
808 .tests(TESTS)
809 .max_tests(TESTS)
810 .quickcheck(internal as fn(Vec<u8>) -> bool);
811 }
812
813 #[test]
814 fn test_fuzz_address_type_from_slice() {
815 fn internal(data: Vec<u8>) -> bool {
816 let network = if data.is_empty() {
817 Network::Mainnet
818 } else {
819 match data.len() % 3 {
820 0 => Network::Mainnet,
821 1 => Network::Testnet,
822 _ => Network::Stagenet,
823 }
824 };
825 let _ = AddressType::from_slice(&data, network);
826 true
827 }
828
829 const TESTS: u64 = 10_000;
830
831 QuickCheck::new()
832 .min_tests_passed(TESTS)
833 .tests(TESTS)
834 .max_tests(TESTS)
835 .quickcheck(internal as fn(Vec<u8>) -> bool);
836 }
837
838 #[test]
842 fn test_fuzz_block_deserialize_coverage() {
843 let data = [
844 12, 12, 148, 222, 186, 248, 5, 190, 179, 72, 156, 114, 42, 40, 92, 9, 42, 50, 231, 198,
845 137, 58, 191, 199, 208, 105, 105, 156, 131, 38, 252, 52, 69, 167, 73, 197, 39, 107, 98,
846 0, 0, 0, 0, 2, 155, 137, 34, 1, 255, 223, 136, 34, 1, 182, 153, 212, 200, 177, 236, 2,
847 2, 35, 223, 82, 74, 242, 162, 239, 95, 135, 10, 219, 110, 28, 235, 3, 164, 117, 195,
848 159, 139, 158, 247, 106, 165, 11, 70, 221, 210, 161, 131, 73, 64, 43, 1, 40, 57, 191,
849 161, 155, 117, 36, 236, 116, 136, 145, 119, 20, 194, 22, 202, 37, 75, 56, 237, 4, 36,
850 202, 101, 174, 130, 138, 124, 0, 106, 234, 241, 2, 8, 245, 49, 106, 127, 107, 153, 204,
851 166, 0, 0,
852 ];
853 fuzz_block_deserialize(&data);
854 }
855
856 #[test]
857 fn test_fuzz_block_header_deserialize_coverage() {
858 let data = [
859 12, 12, 148, 222, 186, 248, 5, 190, 179, 72, 156, 114, 42, 40, 92, 9, 42, 50, 231, 198,
860 137, 58, 191, 199, 208, 105, 105, 156, 131, 38, 252, 52, 69, 167, 73, 197, 39, 107, 98,
861 0, 0, 0, 0,
862 ];
863 fuzz_block_header_deserialize(&data);
864 }
865
866 #[test]
867 fn test_fuzz_transaction_prefix_deserialize_coverage() {
868 let data = [
869 2, 155, 137, 34, 1, 255, 223, 136, 34, 1, 182, 153, 212, 200, 177, 236, 2, 2, 35, 223,
870 82, 74, 242, 162, 239, 95, 135, 10, 219, 110, 28, 235, 3, 164, 117, 195, 159, 139, 158,
871 247, 106, 165, 11, 70, 221, 210, 161, 131, 73, 64, 43, 1, 40, 57, 191, 161, 155, 117,
872 36, 236, 116, 136, 145, 119, 20, 194, 22, 202, 37, 75, 56, 237, 4, 36, 202, 101, 174,
873 130, 138, 124, 0, 106, 234, 241, 2, 8, 245, 49, 106, 127, 107, 153, 204, 166,
874 ];
875 fuzz_transaction_prefix_deserialize(&data);
876 }
877
878 #[test]
879 fn test_fuzz_extra_field_parse_sub_fields_coverage() {
880 let extra_field_1 = fuzz_create_extra_field(&[0, 1, 2], AddPadding::ToFront);
881 let extra_field_2 = fuzz_create_extra_field(&[0, 1, 2], AddPadding::ToMiddle);
882 assert_ne!(extra_field_1, extra_field_2);
883
884 let mut extra_field = fuzz_create_extra_field(&[], AddPadding::ToRear);
885 extra_field.0.pop();
886 extra_field.0.pop();
887 fuzz_extra_field_parse_sub_fields(&extra_field);
888 }
889
890 #[test]
891 fn test_fuzz_extra_field_try_parse_coverage() {
892 let extra_field = fuzz_create_extra_field(&[], AddPadding::ToRear);
893 fuzz_extra_field_try_parse(&extra_field, AddPadding::ToRear, &[]);
894 let data = [
895 230, 196, 73, 143, 43, 56, 217, 81, 1, 244, 76, 0, 106, 157, 99, 164, 0, 128, 107, 252,
896 189, 156, 211, 217, 79, 231, 213, 136, 104, 65, 213, 255, 90, 255, 15, 64, 244, 201,
897 135, 97, 135, 0, 21, 174, 185, 65, 184, 27, 229, 84, 182, 255, 236, 217, 32, 1, 63,
898 ];
899 let mut extra_field = fuzz_create_extra_field(&data, AddPadding::ToMiddle);
900 extra_field.0.pop();
901 fuzz_extra_field_try_parse(&extra_field, AddPadding::ToMiddle, &[]);
902 }
903
904 #[test]
905 fn test_fuzz_transaction_deserialize_coverage() {
906 use std::panic;
907 let _result = panic::catch_unwind(|| {
908 let data = [1];
909 fuzz_transaction_deserialize(&data);
910 });
911 }
912
913 #[test]
914 fn test_fuzz_remaining_coverage() {
915 let data = [1];
916 fuzz_transaction_components(&data);
917 fuzz_hash_convert(&data);
918 let raw_extra_field = fuzz_create_raw_extra_field(&data);
919 fuzz_raw_extra_field_deserialize(&raw_extra_field);
920 fuzz_raw_extra_field_from(&data);
921 fuzz_transaction_hash(&fuzz_create_transaction_alternative_2(
922 &data,
923 &raw_extra_field,
924 ));
925 fuzz_transaction_check_outputs(&fuzz_create_transaction_alternative_2(
926 &data,
927 &raw_extra_field,
928 ));
929 }
930}