Skip to content
This repository has been archived by the owner on Nov 15, 2023. It is now read-only.

Introduce Pallet paged-list #14120

Merged
merged 44 commits into from
Jul 19, 2023
Merged
Show file tree
Hide file tree
Changes from 17 commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
2604a36
Prototype StoragePagedList
ggwpez May 10, 2023
5b16ac7
Add drain
ggwpez May 10, 2023
6ece860
Remove stale docs
ggwpez May 10, 2023
c9f8a5c
Add fuzzer tests
ggwpez May 11, 2023
da9deb3
Update
ggwpez May 11, 2023
8a8acaa
Review
ggwpez May 11, 2023
caff2a2
fmt
ggwpez May 11, 2023
630784d
Docs and clippy
ggwpez May 11, 2023
7760e97
Sum docs
ggwpez May 11, 2023
42a0e48
Cleanup
ggwpez May 11, 2023
560d88c
Merge remote-tracking branch 'origin/master' into oty-paginated-list
ggwpez May 11, 2023
38c0ca1
Undo WIP
ggwpez May 12, 2023
1a6d383
Add pallet-paged-list
ggwpez May 12, 2023
1d82f6f
Move code to pallet
ggwpez May 13, 2023
2d6d7e3
Move fuzzer
ggwpez May 13, 2023
fd7f1a5
Cleanup
ggwpez May 13, 2023
6d3acec
fmt
ggwpez May 13, 2023
a3c82f3
docs
ggwpez May 30, 2023
e518331
Rename Appendix -> Appender
ggwpez May 30, 2023
314e4c0
Rename clear -> delete
ggwpez May 30, 2023
d2aa1b6
Feature gate testing stuff
ggwpez May 30, 2023
f0d4133
Docs review
ggwpez May 30, 2023
9a7afbb
Cleanup
ggwpez May 30, 2023
ac3c0db
doc review
ggwpez May 30, 2023
df2a610
Review renames
ggwpez May 30, 2023
c1f2e6e
Merge remote-tracking branch 'origin/master' into oty-paginated-list
ggwpez May 30, 2023
c3d78db
Add docs
ggwpez May 30, 2023
fbfe452
Fix fuzzer
ggwpez May 30, 2023
5e18eed
Docs + examples
ggwpez May 30, 2023
7315a3b
Remove hasher
ggwpez May 30, 2023
4958b10
Remove empty Event and Call
ggwpez May 30, 2023
a13223b
Remove MaxPages
ggwpez May 30, 2023
4d3ad58
Fix docs
ggwpez May 30, 2023
79cdffa
Test eager page removal
ggwpez May 30, 2023
ff3638c
Cleanup
ggwpez May 30, 2023
351678c
Update frame/paged-list/src/paged_list.rs
ggwpez May 31, 2023
a36a923
Fix docs
ggwpez May 31, 2023
715fc97
Remove as_*_vec
ggwpez May 31, 2023
98bbf9f
Merge remote-tracking branch 'origin/master' into oty-paginated-list
ggwpez May 31, 2023
8683686
Update versions
ggwpez May 31, 2023
19bdd0e
Rename ValuesPerPage -> ValuesPerNewPage
ggwpez May 31, 2023
dbceffa
Merge remote-tracking branch 'origin/master' into oty-paginated-list
Jul 19, 2023
551ad22
Update lockfile
ggwpez Jul 19, 2023
2cbaa8a
Fix mock
ggwpez Jul 19, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,8 @@ members = [
"frame/nomination-pools/benchmarking",
"frame/nomination-pools/test-staking",
"frame/nomination-pools/runtime-api",
"frame/paged-list",
"frame/paged-list/fuzzer",
"frame/insecure-randomness-collective-flip",
"frame/ranked-collective",
"frame/recovery",
Expand Down
51 changes: 51 additions & 0 deletions frame/paged-list/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
[package]
name = "pallet-paged-list"
version = "0.1.0"
description = "FRAME pallet that provides a paged list data structure."
authors = ["Parity Technologies <admin@parity.io>"]
homepage = "https://substrate.io"
edition = "2021"
license = "Apache-2.0"
repository = "https://github.com/paritytech/substrate"

[package.metadata.docs.rs]
targets = ["x86_64-unknown-linux-gnu"]

[dependencies]
codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = [ "derive"] }
scale-info = { version = "2.0.0", default-features = false, features = ["derive"] }

frame-benchmarking = { version = "4.0.0-dev", default-features = false, optional = true, path = "../benchmarking" }
frame-support = { version = "4.0.0-dev", default-features = false, path = "../support" }
frame-system = { version = "4.0.0-dev", default-features = false, path = "../system" }
sp-runtime = { version = "7.0.0", default-features = false, path = "../../primitives/runtime" }
sp-std = { version = "5.0.0", default-features = false, path = "../../primitives/std" }

sp-core = { version = "7.0.0", path = "../../primitives/core", default-features = false, optional = true }
sp-io = { version = "7.0.0", path = "../../primitives/io", default-features = false, optional = true }

[features]
default = ["std"]

std = [
"codec/std",
"frame-benchmarking?/std",
"frame-support/std",
"frame-system/std",
"scale-info/std",
"sp-core/std",
"sp-io/std",
"sp-runtime/std",
"sp-std/std",
]

runtime-benchmarks = [
"frame-benchmarking/runtime-benchmarks",
"frame-support/runtime-benchmarks",
"frame-system/runtime-benchmarks",
"sp-runtime/runtime-benchmarks",
]

try-runtime = [
"frame-support/try-runtime"
]
30 changes: 30 additions & 0 deletions frame/paged-list/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# Pallet PagedList

FRAME pallet that provides a paged list data structure.
(TODO add more).

# Design Goals

1. TODO

# Design

TODO

# Examples

```rust
use pallet_paged_list::Pallet as PagedList;

fn main() {

}
```

# License

Apache-2.0

# References
This crate was auto generated by FRAMY CLI <https://crates.io/crates/framy>.
Please report bugs and build failures at <https://github.com/ggwpez/framy/issues>.
22 changes: 22 additions & 0 deletions frame/paged-list/fuzzer/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
[package]
name = "pallet-paged-list-fuzzer"
version = "0.1.0"
authors = ["Parity Technologies <admin@parity.io>"]
edition = "2021"
license = "Apache-2.0"
homepage = "https://substrate.io"
repository = "https://github.com/paritytech/substrate/"
description = "Fuzz storage types of pallet-paged-list"
publish = false

[[bin]]
name = "pallet-paged-list"
path = "src/paged_list.rs"

[dependencies]
arbitrary = "1.3.0"
honggfuzz = "0.5.49"

frame-support = { version = "4.0.0-dev", default-features = false, features = [ "std" ], path = "../../support" }
sp-io = { path = "../../../primitives/io", default-features = false, features = [ "std" ] }
pallet-paged-list = { path = "../", default-features = false, features = [ "std" ] }
101 changes: 101 additions & 0 deletions frame/paged-list/fuzzer/src/paged_list.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
// This file is part of Substrate.

// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! # Running
//! Running this fuzzer can be done with `cargo hfuzz run pallet-paged-list`. `honggfuzz` CLI
//! options can be used by setting `HFUZZ_RUN_ARGS`, such as `-n 4` to use 4 threads.
//!
//! # Debugging a panic
//! Once a panic is found, it can be debugged with
//! `cargo hfuzz run-debug pallet-paged-list hfuzz_workspace/pallet-paged-list/*.fuzz`.
//!
//! # More information
//! More information about `honggfuzz` can be found
//! [here](https://docs.rs/honggfuzz/).

use arbitrary::Arbitrary;
use honggfuzz::fuzz;

use frame_support::{storage::StorageList, StorageNoopGuard};
use pallet_paged_list::mock::{PagedList1 as List, *};
use sp_io::TestExternalities;
type Meta = MetaOf<Test, ()>;

fn main() {
loop {
fuzz!(|data: (Vec<Op>, u8)| {
drain_append_work(data.0, data.1);
});
}
}

/// Appends and drains random number of elements in random order and checks storage invariants.
fn drain_append_work(ops: Vec<Op>, page_size: u8) {
if page_size == 0 {
return
}

TestExternalities::default().execute_with(|| {
ValuesPerPage::set(&page_size.into());
let _g = StorageNoopGuard::default();
let mut total: i64 = 0;

for op in ops.into_iter() {
total += op.exec();

assert!(total >= 0);
assert_eq!(List::iter().count(), total as usize);

// We have the assumption that the queue removes the metadata when being empty.
if total == 0 {
assert_eq!(List::drain().count(), 0);
assert_eq!(Meta::from_storage().unwrap_or_default(), Default::default());
}
}

assert_eq!(List::drain().count(), total as usize);
// No storage leaking (checked by `StorageNoopGuard`).
});
}

enum Op {
Append(Vec<u32>),
Drain(u8),
}

impl Arbitrary<'_> for Op {
fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result<Self> {
if u.arbitrary::<bool>()? {
Ok(Op::Append(Vec::<u32>::arbitrary(u)?))
} else {
Ok(Op::Drain(u.arbitrary::<u8>()?))
}
}
}

impl Op {
pub fn exec(self) -> i64 {
match self {
Op::Append(v) => {
let l = v.len();
List::append_many(v);
l as i64
},
Op::Drain(v) => -(List::drain().take(v as usize).count() as i64),
}
}
}
117 changes: 117 additions & 0 deletions frame/paged-list/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
// This file is part of Substrate.

// Copyright (C) Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: Apache-2.0

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! A minimal wrapper around the [`paged_list::StoragePagedList`].

#![cfg_attr(not(feature = "std"), no_std)]
#![doc = include_str!("../README.md")]

pub use pallet::*;

pub mod mock;
mod paged_list;
mod tests;

use codec::FullCodec;
use frame_support::{
pallet_prelude::StorageList,
traits::{PalletInfoAccess, StorageInstance},
};
pub use paged_list::StoragePagedList;

#[frame_support::pallet]
pub mod pallet {
use super::*;
use frame_support::pallet_prelude::*;

#[pallet::pallet]
pub struct Pallet<T, I = ()>(_);

/// This type alias is what FRAME normally get us.
pub type List<T, I> = StoragePagedList<
ListPrefix<T, I>,
Blake2_128Concat,
<T as Config<I>>::Value,
<T as Config<I>>::ValuesPerPage,
<T as Config<I>>::MaxPages,
>;

#[pallet::config]
pub trait Config<I: 'static = ()>: frame_system::Config {
type RuntimeEvent: From<Event<Self, I>>
+ IsType<<Self as frame_system::Config>::RuntimeEvent>;

type Value: FullCodec + Clone + MaxEncodedLen;

#[pallet::constant]
type ValuesPerPage: Get<u32>;

#[pallet::constant]
type MaxPages: Get<Option<u32>>;
}

#[pallet::event]
pub enum Event<T: Config<I>, I: 'static = ()> {}

#[pallet::call]
impl<T: Config<I>, I: 'static> Pallet<T, I> {}
}

// This exposes the list functionality to other pallets.
impl<T: Config<I>, I: 'static> StorageList<T::Value> for Pallet<T, I> {
type Iterator = <List<T, I> as StorageList<T::Value>>::Iterator;
type Appendix = <List<T, I> as StorageList<T::Value>>::Appendix;

fn iter() -> Self::Iterator {
List::<T, I>::iter()
}

fn drain() -> Self::Iterator {
List::<T, I>::drain()
}

fn appendix() -> Self::Appendix {
List::<T, I>::appendix()
}
}

// Helper stuff for tests.
#[cfg(feature = "std")]
impl<T: Config<I>, I: 'static> Pallet<T, I> {
/// Return the elements of the list.
pub fn as_vec() -> Vec<T::Value> {
<Self as frame_support::storage::StorageList<_>>::iter().collect()
}

/// Remove and return all elements of the list.
pub fn as_drained_vec() -> Vec<T::Value> {
<Self as frame_support::storage::StorageList<_>>::drain().collect()
}
}

/// The storage prefix for the list.
///
/// Unique for each instance.
pub struct ListPrefix<T, I>(core::marker::PhantomData<(T, I)>);

impl<T: Config<I>, I: 'static> StorageInstance for ListPrefix<T, I> {
fn pallet_prefix() -> &'static str {
crate::Pallet::<T, I>::name()
}

const STORAGE_PREFIX: &'static str = "paged_list";
}
Loading