Skip to content

Commit

Permalink
Merge pull request #3006 from autonomys/history-seeding
Browse files Browse the repository at this point in the history
Add history seeding pallet
  • Loading branch information
dastansam authored Sep 16, 2024
2 parents 70c266b + 17c23ba commit 62a015d
Show file tree
Hide file tree
Showing 11 changed files with 406 additions and 7 deletions.
17 changes: 17 additions & 0 deletions Cargo.lock

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

46 changes: 46 additions & 0 deletions crates/pallet-history-seeding/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
[package]
name = "pallet-history-seeding"
version = "0.1.0"
edition = "2021"
description = "A pallet for seeding history of the network"
authors = ["Dariia Porechna <[email protected]>"]
repository = "https://github.com/autonomys/subspace"
license = "Apache-2.0"
readme = "README.md"
include = [
"/src",
"/Cargo.toml",
"/README.md",
]

[dependencies]
codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] }
frame-benchmarking = { default-features = false, git = "https://github.com/subspace/polkadot-sdk", rev = "5626154d0781ac9a6ffd5a6207ed237f425ae631", optional = true }
frame-support = { default-features = false, git = "https://github.com/subspace/polkadot-sdk", rev = "5626154d0781ac9a6ffd5a6207ed237f425ae631" }
frame-system = { default-features = false, git = "https://github.com/subspace/polkadot-sdk", rev = "5626154d0781ac9a6ffd5a6207ed237f425ae631" }
scale-info = { version = "2.11.2", default-features = false, features = ["derive"] }
sp-std = { default-features = false, git = "https://github.com/subspace/polkadot-sdk", rev = "5626154d0781ac9a6ffd5a6207ed237f425ae631" }

[dev-dependencies]
pallet-sudo = { default-features = false, git = "https://github.com/subspace/polkadot-sdk", rev = "5626154d0781ac9a6ffd5a6207ed237f425ae631", features = ["std"] }
sp-core = { default-features = false, git = "https://github.com/subspace/polkadot-sdk", rev = "5626154d0781ac9a6ffd5a6207ed237f425ae631" }
sp-io = { default-features = false, git = "https://github.com/subspace/polkadot-sdk", rev = "5626154d0781ac9a6ffd5a6207ed237f425ae631" }
sp-runtime = { default-features = false, git = "https://github.com/subspace/polkadot-sdk", rev = "5626154d0781ac9a6ffd5a6207ed237f425ae631" }

[features]
default = ["std"]
std = [
"codec/std",
"frame-benchmarking?/std",
"frame-support/std",
"frame-system/std",
"scale-info/std",
"sp-std/std",
]
try-runtime = ["frame-support/try-runtime"]
runtime-benchmarks = [
"frame-benchmarking",
"frame-benchmarking/runtime-benchmarks",
"frame-support/runtime-benchmarks",
"frame-system/runtime-benchmarks",
]
5 changes: 5 additions & 0 deletions crates/pallet-history-seeding/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Pallet History Seeding

The history seeding pallet allows an authorized account to add remarks to the blockchain, which can be used to seed historical data or important information into the chain's history. The authorized account for seeding can be set by root.

License: Apache-2.0
37 changes: 37 additions & 0 deletions crates/pallet-history-seeding/src/benchmarking.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
//! Benchmarking for the pallet-history-seeding

use super::*;
use frame_benchmarking::v2::*;

#[benchmarks]
mod benchmarks {
use super::*;
use crate::Pallet;
use frame_support::pallet_prelude::*;
use frame_system::RawOrigin;
use sp_std::vec;

#[benchmark]
fn seed_history(
b: Linear<0, { *T::BlockLength::get().max.get(DispatchClass::Normal) }>,
) -> Result<(), BenchmarkError> {
let remark_message = vec![1; b as usize];
let seeder: T::AccountId = account("HistorySeeder", 1, 0);

Pallet::<T>::set_history_seeder(RawOrigin::Root.into(), seeder.clone()).unwrap();

#[extrinsic_call]
_(RawOrigin::Signed(seeder), remark_message);

Ok(())
}

#[benchmark]
fn set_history_seeder() {
let seeder = account("HistorySeeder", 1, 0);
#[extrinsic_call]
_(RawOrigin::Root, seeder);
}

impl_benchmark_test_suite!(Pallet, crate::tests::new_test_ext(), crate::tests::Test);
}
82 changes: 82 additions & 0 deletions crates/pallet-history-seeding/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
#![cfg_attr(not(feature = "std"), no_std)]

#[cfg(feature = "runtime-benchmarks")]
mod benchmarking;

#[cfg(test)]
mod tests;
pub mod weights;

pub use pallet::*;

#[frame_support::pallet]
pub mod pallet {
use crate::weights::WeightInfo;
use frame_support::pallet_prelude::*;
use frame_support::traits::BuildGenesisConfig;
use frame_system::pallet_prelude::*;
use scale_info::prelude::vec::Vec;

#[pallet::config]
pub trait Config: frame_system::Config {
type WeightInfo: WeightInfo;
}

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

#[pallet::error]
pub enum Error<T> {
/// The sender is not authorized to seed history
NotAuthorized,
}

#[pallet::storage]
#[pallet::getter(fn history_seeder)]
pub(super) type HistorySeeder<T: Config> = StorageValue<_, T::AccountId, OptionQuery>;

#[pallet::call]
impl<T: Config> Pallet<T> {
/// Seed history with a remark
#[pallet::call_index(0)]
#[pallet::weight((T::WeightInfo::seed_history(remark.len() as u32), Pays::No))]
pub fn seed_history(origin: OriginFor<T>, remark: Vec<u8>) -> DispatchResult {
let who = ensure_signed(origin.clone())?;

ensure!(
Some(who.clone()) == Self::history_seeder(),
Error::<T>::NotAuthorized
);

let _ = remark;

Ok(())
}

#[pallet::call_index(1)]
#[pallet::weight(T::WeightInfo::set_history_seeder())]
pub fn set_history_seeder(
origin: OriginFor<T>,
new_seeder: T::AccountId,
) -> DispatchResult {
ensure_root(origin)?;
HistorySeeder::<T>::put(new_seeder);
Ok(())
}
}

#[derive(frame_support::DefaultNoBound)]
#[pallet::genesis_config]
pub struct GenesisConfig<T: Config> {
pub history_seeder: Option<T::AccountId>,
}

#[pallet::genesis_build]
impl<T: Config> BuildGenesisConfig for GenesisConfig<T> {
fn build(&self) {
if let Some(seeder) = &self.history_seeder {
HistorySeeder::<T>::put(seeder);
}
}
}
}
93 changes: 93 additions & 0 deletions crates/pallet-history-seeding/src/tests.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
use crate::{self as pallet_history_seeding, Error};
use frame_support::traits::BuildGenesisConfig;
use frame_support::{assert_noop, assert_ok, construct_runtime, derive_impl};
use frame_system as system;
use sp_runtime::BuildStorage;

type Block = frame_system::mocking::MockBlock<Test>;

construct_runtime!(
pub struct Test {
System: frame_system,
HistorySeeding: pallet_history_seeding,
}
);

#[derive_impl(frame_system::config_preludes::TestDefaultConfig)]
impl frame_system::Config for Test {
type Block = Block;
}

impl pallet_history_seeding::Config for Test {
type WeightInfo = ();
}

pub fn new_test_ext() -> sp_io::TestExternalities {
let t = system::GenesisConfig::<Test>::default()
.build_storage()
.unwrap();
t.into()
}

#[test]
fn genesis_config_works() {
new_test_ext().execute_with(|| {
let genesis_config = pallet_history_seeding::GenesisConfig::<Test> {
history_seeder: Some(1),
};
genesis_config.build();
assert_eq!(HistorySeeding::history_seeder(), Some(1));
});
}

#[test]
fn set_history_seeder_works() {
new_test_ext().execute_with(|| {
assert_ok!(HistorySeeding::set_history_seeder(RuntimeOrigin::root(), 1));
assert_eq!(HistorySeeding::history_seeder(), Some(1));

// Ensure only root can set the history seeder
assert_noop!(
HistorySeeding::set_history_seeder(RuntimeOrigin::signed(1), 2),
sp_runtime::DispatchError::BadOrigin
);
});
}

#[test]
fn seed_history_works() {
new_test_ext().execute_with(|| {
System::set_block_number(1);

// Set the history seeder
assert_ok!(HistorySeeding::set_history_seeder(RuntimeOrigin::root(), 1));

// Seed history
let remark = vec![1, 2, 3];
assert_ok!(HistorySeeding::seed_history(
RuntimeOrigin::signed(1),
remark.clone()
));

// Ensure unauthorized account cannot seed history
assert_noop!(
HistorySeeding::seed_history(RuntimeOrigin::signed(2), remark),
Error::<Test>::NotAuthorized
);
});
}

#[test]
fn seed_history_fails_when_no_seeder_set() {
new_test_ext().execute_with(|| {
let remark = vec![1, 2, 3];
assert_noop!(
HistorySeeding::seed_history(RuntimeOrigin::signed(1), remark.clone()),
Error::<Test>::NotAuthorized
);
assert_noop!(
HistorySeeding::seed_history(RuntimeOrigin::root(), remark),
sp_runtime::DispatchError::BadOrigin
);
});
}
93 changes: 93 additions & 0 deletions crates/pallet-history-seeding/src/weights.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@

//! Autogenerated weights for pallet_history_seeding
//!
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 42.0.0
//! DATE: 2024-09-12, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
//! WORST CASE MAP SIZE: `1000000`
//! HOSTNAME: `MacBook-Pro.local`, CPU: `<UNKNOWN>`
//! EXECUTION: , WASM-EXECUTION: Compiled, CHAIN: None, DB CACHE: 1024

// Executed Command:
// /Users/dastansamat/.cargo/target/release/subspace-node
// benchmark
// pallet
// --runtime
// /Users/dastansamat/.cargo/target/release/wbuild/subspace-runtime/subspace_runtime.compact.compressed.wasm
// --steps=50
// --repeat=20
// --pallet=pallet_history_seeding
// --extrinsic
// *
// --wasm-execution=compiled
// --heap-pages=4096
// --output=./crates/pallet-history-seeding/src/weights.rs
// --template
// ./frame-weight-template.hbs

#![cfg_attr(rustfmt, rustfmt_skip)]
#![allow(unused_parens)]
#![allow(unused_imports)]

use frame_support::{traits::Get, weights::{Weight, constants::ParityDbWeight}};
use core::marker::PhantomData;

/// Weight functions needed for pallet_history_seeding.
pub trait WeightInfo {
fn seed_history(b: u32, ) -> Weight;
fn set_history_seeder() -> Weight;
}

/// Weights for pallet_history_seeding using the Substrate node and recommended hardware.
pub struct SubstrateWeight<T>(PhantomData<T>);
impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
/// Storage: `HistorySeeding::HistorySeeder` (r:1 w:0)
/// Proof: `HistorySeeding::HistorySeeder` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`)
/// The range of component `b` is `[0, 3932160]`.
fn seed_history(b: u32, ) -> Weight {
// Proof Size summary in bytes:
// Measured: `37`
// Estimated: `1517`
// Minimum execution time: 2_000_000 picoseconds.
Weight::from_parts(2_000_000, 1517)
// Standard Error: 0
.saturating_add(Weight::from_parts(211, 0).saturating_mul(b.into()))
.saturating_add(T::DbWeight::get().reads(1_u64))
}
/// Storage: `HistorySeeding::HistorySeeder` (r:0 w:1)
/// Proof: `HistorySeeding::HistorySeeder` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`)
fn set_history_seeder() -> Weight {
// Proof Size summary in bytes:
// Measured: `0`
// Estimated: `0`
// Minimum execution time: 1_000_000 picoseconds.
Weight::from_parts(2_000_000, 0)
.saturating_add(T::DbWeight::get().writes(1_u64))
}
}

// For backwards compatibility and tests
impl WeightInfo for () {
/// Storage: `HistorySeeding::HistorySeeder` (r:1 w:0)
/// Proof: `HistorySeeding::HistorySeeder` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`)
/// The range of component `b` is `[0, 3932160]`.
fn seed_history(b: u32, ) -> Weight {
// Proof Size summary in bytes:
// Measured: `37`
// Estimated: `1517`
// Minimum execution time: 2_000_000 picoseconds.
Weight::from_parts(2_000_000, 1517)
// Standard Error: 0
.saturating_add(Weight::from_parts(211, 0).saturating_mul(b.into()))
.saturating_add(ParityDbWeight::get().reads(1_u64))
}
/// Storage: `HistorySeeding::HistorySeeder` (r:0 w:1)
/// Proof: `HistorySeeding::HistorySeeder` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`)
fn set_history_seeder() -> Weight {
// Proof Size summary in bytes:
// Measured: `0`
// Estimated: `0`
// Minimum execution time: 1_000_000 picoseconds.
Weight::from_parts(2_000_000, 0)
.saturating_add(ParityDbWeight::get().writes(1_u64))
}
}
Loading

0 comments on commit 62a015d

Please sign in to comment.