Skip to content

Commit

Permalink
[FRAME] Parameters pallet (paritytech#2061)
Browse files Browse the repository at this point in the history
Closes paritytech#169  

Fork of the `orml-parameters-pallet` as introduced by
open-web3-stack/open-runtime-module-library#927
(cc @xlc)
It greatly changes how the macros work, but keeps the pallet the same.
The downside of my code is now that it does only support constant keys
in the form of types, not value-bearing keys.
I think this is an acceptable trade off, give that it can be used by
*any* pallet without any changes.

The pallet allows to dynamically set parameters that can be used in
pallet configs while also restricting the updating on a per-key basis.
The rust-docs contains a complete example.

Changes:
- Add `parameters-pallet`
- Use in the kitchensink as demonstration
- Add experimental attribute to define dynamic params in the runtime.
- Adding a bunch of traits to `frame_support::traits::dynamic_params`
that can be re-used by the ORML macros

## Example

First to define the parameters in the runtime file. The syntax is very
explicit about the codec index and errors if there is no.
```rust
#[dynamic_params(RuntimeParameters, pallet_parameters::Parameters::<Runtime>))]
pub mod dynamic_params {
	use super::*;

	#[dynamic_pallet_params]
	#[codec(index = 0)]
	pub mod storage {
		/// Configures the base deposit of storing some data.
		#[codec(index = 0)]
		pub static BaseDeposit: Balance = 1 * DOLLARS;

		/// Configures the per-byte deposit of storing some data.
		#[codec(index = 1)]
		pub static ByteDeposit: Balance = 1 * CENTS;
	}

	#[dynamic_pallet_params]
	#[codec(index = 1)]
	pub mod contracts {
		#[codec(index = 0)]
		pub static DepositPerItem: Balance = deposit(1, 0);

		#[codec(index = 1)]
		pub static DepositPerByte: Balance = deposit(0, 1);
	}
}
```

Then the pallet is configured with the aggregate:  
```rust
impl pallet_parameters::Config for Runtime {
	type AggregratedKeyValue = RuntimeParameters;
	type AdminOrigin = EnsureRootWithSuccess<AccountId, ConstBool<true>>;
	...
}
```

And then the parameters can be used in a pallet config:
```rust
impl pallet_preimage::Config for Runtime {
	type DepositBase = dynamic_params::storage::DepositBase;
}
```

A custom origin an be defined like this:  
```rust
pub struct DynamicParametersManagerOrigin;

impl EnsureOriginWithArg<RuntimeOrigin, RuntimeParametersKey> for DynamicParametersManagerOrigin {
	type Success = ();

	fn try_origin(
		origin: RuntimeOrigin,
		key: &RuntimeParametersKey,
	) -> Result<Self::Success, RuntimeOrigin> {
		match key {
			RuntimeParametersKey::Storage(_) => {
				frame_system::ensure_root(origin.clone()).map_err(|_| origin)?;
				return Ok(())
			},
			RuntimeParametersKey::Contract(_) => {
				frame_system::ensure_root(origin.clone()).map_err(|_| origin)?;
				return Ok(())
			},
		}
	}

	#[cfg(feature = "runtime-benchmarks")]
	fn try_successful_origin(_key: &RuntimeParametersKey) -> Result<RuntimeOrigin, ()> {
		Ok(RuntimeOrigin::Root)
	}
}
```

---------

Signed-off-by: Oliver Tale-Yazdi <oliver.tale-yazdi@parity.io>
Co-authored-by: Nikhil Gupta <17176722+gupnik@users.noreply.github.com>
Co-authored-by: Kian Paimani <5588131+kianenigma@users.noreply.github.com>
Co-authored-by: command-bot <>
  • Loading branch information
3 people authored Feb 8, 2024
1 parent 62e553e commit fc75e97
Show file tree
Hide file tree
Showing 18 changed files with 1,981 additions and 18 deletions.
4 changes: 4 additions & 0 deletions substrate/bin/node/runtime/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ pallet-vesting = { path = "../../../frame/vesting", default-features = false }
pallet-whitelist = { path = "../../../frame/whitelist", default-features = false }
pallet-tx-pause = { path = "../../../frame/tx-pause", default-features = false }
pallet-safe-mode = { path = "../../../frame/safe-mode", default-features = false }
pallet-parameters = { path = "../../../frame/parameters", default-features = false }

[build-dependencies]
substrate-wasm-builder = { path = "../../../utils/wasm-builder", optional = true }
Expand Down Expand Up @@ -209,6 +210,7 @@ std = [
"pallet-nomination-pools/std",
"pallet-offences-benchmarking?/std",
"pallet-offences/std",
"pallet-parameters/std",
"pallet-preimage/std",
"pallet-proxy/std",
"pallet-ranked-collective/std",
Expand Down Expand Up @@ -310,6 +312,7 @@ runtime-benchmarks = [
"pallet-nomination-pools/runtime-benchmarks",
"pallet-offences-benchmarking/runtime-benchmarks",
"pallet-offences/runtime-benchmarks",
"pallet-parameters/runtime-benchmarks",
"pallet-preimage/runtime-benchmarks",
"pallet-proxy/runtime-benchmarks",
"pallet-ranked-collective/runtime-benchmarks",
Expand Down Expand Up @@ -386,6 +389,7 @@ try-runtime = [
"pallet-nis/try-runtime",
"pallet-nomination-pools/try-runtime",
"pallet-offences/try-runtime",
"pallet-parameters/try-runtime",
"pallet-preimage/try-runtime",
"pallet-proxy/try-runtime",
"pallet-ranked-collective/try-runtime",
Expand Down
102 changes: 89 additions & 13 deletions substrate/bin/node/runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ use frame_election_provider_support::{
use frame_support::{
construct_runtime, derive_impl,
dispatch::DispatchClass,
dynamic_params::{dynamic_pallet_params, dynamic_params},
genesis_builder_helper::{build_config, create_default_config},
instances::{Instance1, Instance2},
ord_parameter_types,
Expand All @@ -44,9 +45,9 @@ use frame_support::{
GetSalary, PayFromAccount,
},
AsEnsureOriginWithArg, ConstBool, ConstU128, ConstU16, ConstU32, Contains, Currency,
EitherOfDiverse, EqualPrivilegeOnly, Imbalance, InsideBoth, InstanceFilter,
KeyOwnerProofSystem, LinearStoragePrice, LockIdentifier, Nothing, OnUnbalanced,
WithdrawReasons,
EitherOfDiverse, EnsureOriginWithArg, EqualPrivilegeOnly, Imbalance, InsideBoth,
InstanceFilter, KeyOwnerProofSystem, LinearStoragePrice, LockIdentifier, Nothing,
OnUnbalanced, WithdrawReasons,
},
weights::{
constants::{
Expand Down Expand Up @@ -457,9 +458,6 @@ impl pallet_glutton::Config for Runtime {
}

parameter_types! {
pub const PreimageBaseDeposit: Balance = 1 * DOLLARS;
// One cent: $10,000 / MB
pub const PreimageByteDeposit: Balance = 1 * CENTS;
pub const PreimageHoldReason: RuntimeHoldReason = RuntimeHoldReason::Preimage(pallet_preimage::HoldReason::Preimage);
}

Expand All @@ -472,7 +470,11 @@ impl pallet_preimage::Config for Runtime {
AccountId,
Balances,
PreimageHoldReason,
LinearStoragePrice<PreimageBaseDeposit, PreimageByteDeposit, Balance>,
LinearStoragePrice<
dynamic_params::storage::BaseDeposit,
dynamic_params::storage::ByteDeposit,
Balance,
>,
>;
}

Expand Down Expand Up @@ -1326,9 +1328,6 @@ impl pallet_tips::Config for Runtime {
}

parameter_types! {
pub const DepositPerItem: Balance = deposit(1, 0);
pub const DepositPerByte: Balance = deposit(0, 1);
pub const DefaultDepositLimit: Balance = deposit(1024, 1024 * 1024);
pub Schedule: pallet_contracts::Schedule<Runtime> = Default::default();
pub CodeHashLockupDepositPercent: Perbill = Perbill::from_percent(30);
}
Expand All @@ -1346,9 +1345,9 @@ impl pallet_contracts::Config for Runtime {
/// change because that would break already deployed contracts. The `Call` structure itself
/// is not allowed to change the indices of existing pallets, too.
type CallFilter = Nothing;
type DepositPerItem = DepositPerItem;
type DepositPerByte = DepositPerByte;
type DefaultDepositLimit = DefaultDepositLimit;
type DepositPerItem = dynamic_params::contracts::DepositPerItem;
type DepositPerByte = dynamic_params::contracts::DepositPerByte;
type DefaultDepositLimit = dynamic_params::contracts::DefaultDepositLimit;
type CallStack = [pallet_contracts::Frame<Self>; 5];
type WeightPrice = pallet_transaction_payment::Pallet<Self>;
type WeightInfo = pallet_contracts::weights::SubstrateWeight<Self>;
Expand Down Expand Up @@ -2088,6 +2087,81 @@ impl pallet_mixnet::Config for Runtime {
type MinMixnodes = ConstU32<7>; // Low to allow small testing networks
}

/// Dynamic parameters that can be changed at runtime through the
/// `pallet_parameters::set_parameter`.
#[dynamic_params(RuntimeParameters, pallet_parameters::Parameters::<Runtime>)]
pub mod dynamic_params {
use super::*;

#[dynamic_pallet_params]
#[codec(index = 0)]
pub mod storage {
/// Configures the base deposit of storing some data.
#[codec(index = 0)]
pub static BaseDeposit: Balance = 1 * DOLLARS;

/// Configures the per-byte deposit of storing some data.
#[codec(index = 1)]
pub static ByteDeposit: Balance = 1 * CENTS;
}

#[dynamic_pallet_params]
#[codec(index = 1)]
pub mod contracts {
#[codec(index = 0)]
pub static DepositPerItem: Balance = deposit(1, 0);

#[codec(index = 1)]
pub static DepositPerByte: Balance = deposit(0, 1);

#[codec(index = 2)]
pub static DefaultDepositLimit: Balance = deposit(1024, 1024 * 1024);
}
}

#[cfg(feature = "runtime-benchmarks")]
impl Default for RuntimeParameters {
fn default() -> Self {
RuntimeParameters::Storage(dynamic_params::storage::Parameters::BaseDeposit(
dynamic_params::storage::BaseDeposit,
Some(1 * DOLLARS),
))
}
}

pub struct DynamicParametersManagerOrigin;
impl EnsureOriginWithArg<RuntimeOrigin, RuntimeParametersKey> for DynamicParametersManagerOrigin {
type Success = ();

fn try_origin(
origin: RuntimeOrigin,
key: &RuntimeParametersKey,
) -> Result<Self::Success, RuntimeOrigin> {
match key {
RuntimeParametersKey::Storage(_) => {
frame_system::ensure_root(origin.clone()).map_err(|_| origin)?;
return Ok(())
},
RuntimeParametersKey::Contract(_) => {
frame_system::ensure_root(origin.clone()).map_err(|_| origin)?;
return Ok(())
},
}
}

#[cfg(feature = "runtime-benchmarks")]
fn try_successful_origin(_key: &RuntimeParametersKey) -> Result<RuntimeOrigin, ()> {
Ok(RuntimeOrigin::root())
}
}

impl pallet_parameters::Config for Runtime {
type RuntimeParameters = RuntimeParameters;
type RuntimeEvent = RuntimeEvent;
type AdminOrigin = DynamicParametersManagerOrigin;
type WeightInfo = ();
}

construct_runtime!(
pub enum Runtime {
System: frame_system,
Expand Down Expand Up @@ -2169,6 +2243,7 @@ construct_runtime!(
Broker: pallet_broker,
TasksExample: pallet_example_tasks,
Mixnet: pallet_mixnet,
Parameters: pallet_parameters,
SkipFeelessPayment: pallet_skip_feeless_payment,
}
);
Expand Down Expand Up @@ -2288,6 +2363,7 @@ mod benches {
[pallet_elections_phragmen, Elections]
[pallet_fast_unstake, FastUnstake]
[pallet_nis, Nis]
[pallet_parameters, Parameters]
[pallet_grandpa, Grandpa]
[pallet_identity, Identity]
[pallet_im_online, ImOnline]
Expand Down
2 changes: 1 addition & 1 deletion substrate/frame/examples/kitchensink/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ codec = { package = "parity-scale-codec", version = "3.6.1", default-features =
log = { version = "0.4.17", default-features = false }
scale-info = { version = "2.10.0", default-features = false, features = ["derive"] }

frame-support = { path = "../../support", default-features = false }
frame-support = { path = "../../support", default-features = false, features = ["experimental"] }
frame-system = { path = "../../system", default-features = false }

sp-io = { path = "../../../primitives/io", default-features = false }
Expand Down
57 changes: 57 additions & 0 deletions substrate/frame/parameters/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
[package]
name = "pallet-parameters"
description = "Pallet to store and configure parameters."
repository.workspace = true
license = "Apache-2.0"
version = "0.0.1"
authors = ["Acala Developers", "Parity Technologies <admin@parity.io>"]
edition.workspace = true

[dependencies]
codec = { package = "parity-scale-codec", version = "3.0.0", default-features = false, features = ["max-encoded-len"] }
scale-info = { version = "2.1.2", default-features = false, features = ["derive"] }
paste = { version = "1.0.14", default-features = false }
serde = { version = "1.0.188", features = ["derive"], optional = true }
docify = "0.2.5"

frame-support = { path = "../support", default-features = false, features = ["experimental"] }
frame-system = { path = "../system", default-features = false }
sp-core = { path = "../../primitives/core", default-features = false }
sp-runtime = { path = "../../primitives/runtime", default-features = false }
sp-std = { path = "../../primitives/std", default-features = false }
frame-benchmarking = { path = "../benchmarking", default-features = false, optional = true }

[dev-dependencies]
sp-core = { path = "../../primitives/core", features = ["std"] }
sp-io = { path = "../../primitives/io", features = ["std"] }
pallet-example-basic = { path = "../examples/basic", features = ["std"] }
pallet-balances = { path = "../balances", features = ["std"] }

[features]
default = ["std"]
std = [
"codec/std",
"frame-benchmarking?/std",
"frame-support/std",
"frame-system/std",
"scale-info/std",
"serde",
"sp-core/std",
"sp-runtime/std",
"sp-std/std",
]
runtime-benchmarks = [
"frame-benchmarking/runtime-benchmarks",
"frame-support/runtime-benchmarks",
"frame-system/runtime-benchmarks",
"pallet-balances/runtime-benchmarks",
"pallet-example-basic/runtime-benchmarks",
"sp-runtime/runtime-benchmarks",
]
try-runtime = [
"frame-support/try-runtime",
"frame-system/try-runtime",
"pallet-balances/try-runtime",
"pallet-example-basic/try-runtime",
"sp-runtime/try-runtime",
]
51 changes: 51 additions & 0 deletions substrate/frame/parameters/src/benchmarking.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
// 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.

//! Parameters pallet benchmarking.
#![cfg(feature = "runtime-benchmarks")]

use super::*;
#[cfg(test)]
use crate::Pallet as Parameters;

use frame_benchmarking::v2::*;

#[benchmarks(where T::RuntimeParameters: Default)]
mod benchmarks {
use super::*;

#[benchmark]
fn set_parameter() -> Result<(), BenchmarkError> {
let kv = T::RuntimeParameters::default();
let k = kv.clone().into_parts().0;

let origin =
T::AdminOrigin::try_successful_origin(&k).map_err(|_| BenchmarkError::Weightless)?;

#[extrinsic_call]
_(origin as T::RuntimeOrigin, kv);

Ok(())
}

impl_benchmark_test_suite! {
Parameters,
crate::tests::mock::new_test_ext(),
crate::tests::mock::Runtime,
}
}
Loading

0 comments on commit fc75e97

Please sign in to comment.