Skip to content

Commit 62a015d

Browse files
authored
Merge pull request #3006 from autonomys/history-seeding
Add history seeding pallet
2 parents 70c266b + 17c23ba commit 62a015d

File tree

11 files changed

+406
-7
lines changed

11 files changed

+406
-7
lines changed

Cargo.lock

Lines changed: 17 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
[package]
2+
name = "pallet-history-seeding"
3+
version = "0.1.0"
4+
edition = "2021"
5+
description = "A pallet for seeding history of the network"
6+
authors = ["Dariia Porechna <dariia@subspace.foundation>"]
7+
repository = "https://github.com/autonomys/subspace"
8+
license = "Apache-2.0"
9+
readme = "README.md"
10+
include = [
11+
"/src",
12+
"/Cargo.toml",
13+
"/README.md",
14+
]
15+
16+
[dependencies]
17+
codec = { package = "parity-scale-codec", version = "3.6.12", default-features = false, features = ["derive"] }
18+
frame-benchmarking = { default-features = false, git = "https://github.com/subspace/polkadot-sdk", rev = "5626154d0781ac9a6ffd5a6207ed237f425ae631", optional = true }
19+
frame-support = { default-features = false, git = "https://github.com/subspace/polkadot-sdk", rev = "5626154d0781ac9a6ffd5a6207ed237f425ae631" }
20+
frame-system = { default-features = false, git = "https://github.com/subspace/polkadot-sdk", rev = "5626154d0781ac9a6ffd5a6207ed237f425ae631" }
21+
scale-info = { version = "2.11.2", default-features = false, features = ["derive"] }
22+
sp-std = { default-features = false, git = "https://github.com/subspace/polkadot-sdk", rev = "5626154d0781ac9a6ffd5a6207ed237f425ae631" }
23+
24+
[dev-dependencies]
25+
pallet-sudo = { default-features = false, git = "https://github.com/subspace/polkadot-sdk", rev = "5626154d0781ac9a6ffd5a6207ed237f425ae631", features = ["std"] }
26+
sp-core = { default-features = false, git = "https://github.com/subspace/polkadot-sdk", rev = "5626154d0781ac9a6ffd5a6207ed237f425ae631" }
27+
sp-io = { default-features = false, git = "https://github.com/subspace/polkadot-sdk", rev = "5626154d0781ac9a6ffd5a6207ed237f425ae631" }
28+
sp-runtime = { default-features = false, git = "https://github.com/subspace/polkadot-sdk", rev = "5626154d0781ac9a6ffd5a6207ed237f425ae631" }
29+
30+
[features]
31+
default = ["std"]
32+
std = [
33+
"codec/std",
34+
"frame-benchmarking?/std",
35+
"frame-support/std",
36+
"frame-system/std",
37+
"scale-info/std",
38+
"sp-std/std",
39+
]
40+
try-runtime = ["frame-support/try-runtime"]
41+
runtime-benchmarks = [
42+
"frame-benchmarking",
43+
"frame-benchmarking/runtime-benchmarks",
44+
"frame-support/runtime-benchmarks",
45+
"frame-system/runtime-benchmarks",
46+
]
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Pallet History Seeding
2+
3+
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.
4+
5+
License: Apache-2.0
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
//! Benchmarking for the pallet-history-seeding
2+
3+
use super::*;
4+
use frame_benchmarking::v2::*;
5+
6+
#[benchmarks]
7+
mod benchmarks {
8+
use super::*;
9+
use crate::Pallet;
10+
use frame_support::pallet_prelude::*;
11+
use frame_system::RawOrigin;
12+
use sp_std::vec;
13+
14+
#[benchmark]
15+
fn seed_history(
16+
b: Linear<0, { *T::BlockLength::get().max.get(DispatchClass::Normal) }>,
17+
) -> Result<(), BenchmarkError> {
18+
let remark_message = vec![1; b as usize];
19+
let seeder: T::AccountId = account("HistorySeeder", 1, 0);
20+
21+
Pallet::<T>::set_history_seeder(RawOrigin::Root.into(), seeder.clone()).unwrap();
22+
23+
#[extrinsic_call]
24+
_(RawOrigin::Signed(seeder), remark_message);
25+
26+
Ok(())
27+
}
28+
29+
#[benchmark]
30+
fn set_history_seeder() {
31+
let seeder = account("HistorySeeder", 1, 0);
32+
#[extrinsic_call]
33+
_(RawOrigin::Root, seeder);
34+
}
35+
36+
impl_benchmark_test_suite!(Pallet, crate::tests::new_test_ext(), crate::tests::Test);
37+
}
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
#![cfg_attr(not(feature = "std"), no_std)]
2+
3+
#[cfg(feature = "runtime-benchmarks")]
4+
mod benchmarking;
5+
6+
#[cfg(test)]
7+
mod tests;
8+
pub mod weights;
9+
10+
pub use pallet::*;
11+
12+
#[frame_support::pallet]
13+
pub mod pallet {
14+
use crate::weights::WeightInfo;
15+
use frame_support::pallet_prelude::*;
16+
use frame_support::traits::BuildGenesisConfig;
17+
use frame_system::pallet_prelude::*;
18+
use scale_info::prelude::vec::Vec;
19+
20+
#[pallet::config]
21+
pub trait Config: frame_system::Config {
22+
type WeightInfo: WeightInfo;
23+
}
24+
25+
#[pallet::pallet]
26+
pub struct Pallet<T>(_);
27+
28+
#[pallet::error]
29+
pub enum Error<T> {
30+
/// The sender is not authorized to seed history
31+
NotAuthorized,
32+
}
33+
34+
#[pallet::storage]
35+
#[pallet::getter(fn history_seeder)]
36+
pub(super) type HistorySeeder<T: Config> = StorageValue<_, T::AccountId, OptionQuery>;
37+
38+
#[pallet::call]
39+
impl<T: Config> Pallet<T> {
40+
/// Seed history with a remark
41+
#[pallet::call_index(0)]
42+
#[pallet::weight((T::WeightInfo::seed_history(remark.len() as u32), Pays::No))]
43+
pub fn seed_history(origin: OriginFor<T>, remark: Vec<u8>) -> DispatchResult {
44+
let who = ensure_signed(origin.clone())?;
45+
46+
ensure!(
47+
Some(who.clone()) == Self::history_seeder(),
48+
Error::<T>::NotAuthorized
49+
);
50+
51+
let _ = remark;
52+
53+
Ok(())
54+
}
55+
56+
#[pallet::call_index(1)]
57+
#[pallet::weight(T::WeightInfo::set_history_seeder())]
58+
pub fn set_history_seeder(
59+
origin: OriginFor<T>,
60+
new_seeder: T::AccountId,
61+
) -> DispatchResult {
62+
ensure_root(origin)?;
63+
HistorySeeder::<T>::put(new_seeder);
64+
Ok(())
65+
}
66+
}
67+
68+
#[derive(frame_support::DefaultNoBound)]
69+
#[pallet::genesis_config]
70+
pub struct GenesisConfig<T: Config> {
71+
pub history_seeder: Option<T::AccountId>,
72+
}
73+
74+
#[pallet::genesis_build]
75+
impl<T: Config> BuildGenesisConfig for GenesisConfig<T> {
76+
fn build(&self) {
77+
if let Some(seeder) = &self.history_seeder {
78+
HistorySeeder::<T>::put(seeder);
79+
}
80+
}
81+
}
82+
}
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
use crate::{self as pallet_history_seeding, Error};
2+
use frame_support::traits::BuildGenesisConfig;
3+
use frame_support::{assert_noop, assert_ok, construct_runtime, derive_impl};
4+
use frame_system as system;
5+
use sp_runtime::BuildStorage;
6+
7+
type Block = frame_system::mocking::MockBlock<Test>;
8+
9+
construct_runtime!(
10+
pub struct Test {
11+
System: frame_system,
12+
HistorySeeding: pallet_history_seeding,
13+
}
14+
);
15+
16+
#[derive_impl(frame_system::config_preludes::TestDefaultConfig)]
17+
impl frame_system::Config for Test {
18+
type Block = Block;
19+
}
20+
21+
impl pallet_history_seeding::Config for Test {
22+
type WeightInfo = ();
23+
}
24+
25+
pub fn new_test_ext() -> sp_io::TestExternalities {
26+
let t = system::GenesisConfig::<Test>::default()
27+
.build_storage()
28+
.unwrap();
29+
t.into()
30+
}
31+
32+
#[test]
33+
fn genesis_config_works() {
34+
new_test_ext().execute_with(|| {
35+
let genesis_config = pallet_history_seeding::GenesisConfig::<Test> {
36+
history_seeder: Some(1),
37+
};
38+
genesis_config.build();
39+
assert_eq!(HistorySeeding::history_seeder(), Some(1));
40+
});
41+
}
42+
43+
#[test]
44+
fn set_history_seeder_works() {
45+
new_test_ext().execute_with(|| {
46+
assert_ok!(HistorySeeding::set_history_seeder(RuntimeOrigin::root(), 1));
47+
assert_eq!(HistorySeeding::history_seeder(), Some(1));
48+
49+
// Ensure only root can set the history seeder
50+
assert_noop!(
51+
HistorySeeding::set_history_seeder(RuntimeOrigin::signed(1), 2),
52+
sp_runtime::DispatchError::BadOrigin
53+
);
54+
});
55+
}
56+
57+
#[test]
58+
fn seed_history_works() {
59+
new_test_ext().execute_with(|| {
60+
System::set_block_number(1);
61+
62+
// Set the history seeder
63+
assert_ok!(HistorySeeding::set_history_seeder(RuntimeOrigin::root(), 1));
64+
65+
// Seed history
66+
let remark = vec![1, 2, 3];
67+
assert_ok!(HistorySeeding::seed_history(
68+
RuntimeOrigin::signed(1),
69+
remark.clone()
70+
));
71+
72+
// Ensure unauthorized account cannot seed history
73+
assert_noop!(
74+
HistorySeeding::seed_history(RuntimeOrigin::signed(2), remark),
75+
Error::<Test>::NotAuthorized
76+
);
77+
});
78+
}
79+
80+
#[test]
81+
fn seed_history_fails_when_no_seeder_set() {
82+
new_test_ext().execute_with(|| {
83+
let remark = vec![1, 2, 3];
84+
assert_noop!(
85+
HistorySeeding::seed_history(RuntimeOrigin::signed(1), remark.clone()),
86+
Error::<Test>::NotAuthorized
87+
);
88+
assert_noop!(
89+
HistorySeeding::seed_history(RuntimeOrigin::root(), remark),
90+
sp_runtime::DispatchError::BadOrigin
91+
);
92+
});
93+
}
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
2+
//! Autogenerated weights for pallet_history_seeding
3+
//!
4+
//! THIS FILE WAS AUTO-GENERATED USING THE SUBSTRATE BENCHMARK CLI VERSION 42.0.0
5+
//! DATE: 2024-09-12, STEPS: `50`, REPEAT: `20`, LOW RANGE: `[]`, HIGH RANGE: `[]`
6+
//! WORST CASE MAP SIZE: `1000000`
7+
//! HOSTNAME: `MacBook-Pro.local`, CPU: `<UNKNOWN>`
8+
//! EXECUTION: , WASM-EXECUTION: Compiled, CHAIN: None, DB CACHE: 1024
9+
10+
// Executed Command:
11+
// /Users/dastansamat/.cargo/target/release/subspace-node
12+
// benchmark
13+
// pallet
14+
// --runtime
15+
// /Users/dastansamat/.cargo/target/release/wbuild/subspace-runtime/subspace_runtime.compact.compressed.wasm
16+
// --steps=50
17+
// --repeat=20
18+
// --pallet=pallet_history_seeding
19+
// --extrinsic
20+
// *
21+
// --wasm-execution=compiled
22+
// --heap-pages=4096
23+
// --output=./crates/pallet-history-seeding/src/weights.rs
24+
// --template
25+
// ./frame-weight-template.hbs
26+
27+
#![cfg_attr(rustfmt, rustfmt_skip)]
28+
#![allow(unused_parens)]
29+
#![allow(unused_imports)]
30+
31+
use frame_support::{traits::Get, weights::{Weight, constants::ParityDbWeight}};
32+
use core::marker::PhantomData;
33+
34+
/// Weight functions needed for pallet_history_seeding.
35+
pub trait WeightInfo {
36+
fn seed_history(b: u32, ) -> Weight;
37+
fn set_history_seeder() -> Weight;
38+
}
39+
40+
/// Weights for pallet_history_seeding using the Substrate node and recommended hardware.
41+
pub struct SubstrateWeight<T>(PhantomData<T>);
42+
impl<T: frame_system::Config> WeightInfo for SubstrateWeight<T> {
43+
/// Storage: `HistorySeeding::HistorySeeder` (r:1 w:0)
44+
/// Proof: `HistorySeeding::HistorySeeder` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`)
45+
/// The range of component `b` is `[0, 3932160]`.
46+
fn seed_history(b: u32, ) -> Weight {
47+
// Proof Size summary in bytes:
48+
// Measured: `37`
49+
// Estimated: `1517`
50+
// Minimum execution time: 2_000_000 picoseconds.
51+
Weight::from_parts(2_000_000, 1517)
52+
// Standard Error: 0
53+
.saturating_add(Weight::from_parts(211, 0).saturating_mul(b.into()))
54+
.saturating_add(T::DbWeight::get().reads(1_u64))
55+
}
56+
/// Storage: `HistorySeeding::HistorySeeder` (r:0 w:1)
57+
/// Proof: `HistorySeeding::HistorySeeder` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`)
58+
fn set_history_seeder() -> Weight {
59+
// Proof Size summary in bytes:
60+
// Measured: `0`
61+
// Estimated: `0`
62+
// Minimum execution time: 1_000_000 picoseconds.
63+
Weight::from_parts(2_000_000, 0)
64+
.saturating_add(T::DbWeight::get().writes(1_u64))
65+
}
66+
}
67+
68+
// For backwards compatibility and tests
69+
impl WeightInfo for () {
70+
/// Storage: `HistorySeeding::HistorySeeder` (r:1 w:0)
71+
/// Proof: `HistorySeeding::HistorySeeder` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`)
72+
/// The range of component `b` is `[0, 3932160]`.
73+
fn seed_history(b: u32, ) -> Weight {
74+
// Proof Size summary in bytes:
75+
// Measured: `37`
76+
// Estimated: `1517`
77+
// Minimum execution time: 2_000_000 picoseconds.
78+
Weight::from_parts(2_000_000, 1517)
79+
// Standard Error: 0
80+
.saturating_add(Weight::from_parts(211, 0).saturating_mul(b.into()))
81+
.saturating_add(ParityDbWeight::get().reads(1_u64))
82+
}
83+
/// Storage: `HistorySeeding::HistorySeeder` (r:0 w:1)
84+
/// Proof: `HistorySeeding::HistorySeeder` (`max_values`: Some(1), `max_size`: Some(32), added: 527, mode: `MaxEncodedLen`)
85+
fn set_history_seeder() -> Weight {
86+
// Proof Size summary in bytes:
87+
// Measured: `0`
88+
// Estimated: `0`
89+
// Minimum execution time: 1_000_000 picoseconds.
90+
Weight::from_parts(2_000_000, 0)
91+
.saturating_add(ParityDbWeight::get().writes(1_u64))
92+
}
93+
}

0 commit comments

Comments
 (0)