referrerpolicy=no-referrer-when-downgrade

pallet_paged_list_fuzzer/
paged_list.rs

1// This file is part of Substrate.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: Apache-2.0
5
6// Licensed under the Apache License, Version 2.0 (the "License");
7// you may not use this file except in compliance with the License.
8// You may obtain a copy of the License at
9//
10// 	http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17
18//! # Running
19//! Running this fuzzer can be done with `cargo hfuzz run pallet-paged-list`. `honggfuzz` CLI
20//! options can be used by setting `HFUZZ_RUN_ARGS`, such as `-n 4` to use 4 threads.
21//!
22//! # Debugging a panic
23//! Once a panic is found, it can be debugged with
24//! `cargo hfuzz run-debug pallet-paged-list hfuzz_workspace/pallet-paged-list/*.fuzz`.
25//!
26//! # More information
27//! More information about `honggfuzz` can be found
28//! [here](https://docs.rs/honggfuzz/).
29
30use arbitrary::Arbitrary;
31use honggfuzz::fuzz;
32
33use frame::{
34	prelude::*, runtime::prelude::storage::storage_noop_guard::StorageNoopGuard,
35	testing_prelude::TestExternalities,
36};
37
38use pallet_paged_list::mock::{PagedList as List, *};
39type Meta = MetaOf<Test, ()>;
40
41fn main() {
42	loop {
43		fuzz!(|data: (Vec<Op>, u8)| {
44			drain_append_work(data.0, data.1);
45		});
46	}
47}
48
49/// Appends and drains random number of elements in random order and checks storage invariants.
50///
51/// It also changes the maximal number of elements per page dynamically, hence the `page_size`.
52fn drain_append_work(ops: Vec<Op>, page_size: u8) {
53	if page_size == 0 {
54		return
55	}
56
57	TestExternalities::default().execute_with(|| {
58		ValuesPerNewPage::set(&page_size.into());
59		let _g = StorageNoopGuard::default();
60		let mut total: i64 = 0;
61
62		for op in ops.into_iter() {
63			total += op.exec();
64
65			assert!(total >= 0);
66			assert_eq!(List::iter().count(), total as usize);
67
68			// We have the assumption that the queue removes the metadata when empty.
69			if total == 0 {
70				assert_eq!(List::drain().count(), 0);
71				assert_eq!(Meta::from_storage().unwrap_or_default(), Default::default());
72			}
73		}
74
75		assert_eq!(List::drain().count(), total as usize);
76		// `StorageNoopGuard` checks that there is no storage leaked.
77	});
78}
79
80enum Op {
81	Append(Vec<u32>),
82	Drain(u8),
83}
84
85impl Arbitrary<'_> for Op {
86	fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
87		if u.arbitrary::<bool>()? {
88			Ok(Op::Append(Vec::<u32>::arbitrary(u)?))
89		} else {
90			Ok(Op::Drain(u.arbitrary::<u8>()?))
91		}
92	}
93}
94
95impl Op {
96	pub fn exec(self) -> i64 {
97		match self {
98			Op::Append(v) => {
99				let l = v.len();
100				List::append_many(v);
101				l as i64
102			},
103			Op::Drain(v) => -(List::drain().take(v as usize).count() as i64),
104		}
105	}
106}