Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Transaction Weights #62

Merged
merged 18 commits into from
Nov 2, 2019
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
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
50 changes: 50 additions & 0 deletions kitchen/modules/weights/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
[package]
name = "weights"
version = "0.1.0"
authors = ["Anonymous"]
edition = "2018"

[features]
default = ['std']
std = [
'parity-scale-codec/std',
'support/std',
'system/std',
'balances/std',
'runtime-primitives/std',
]

[dependencies.parity-scale-codec]
default-features = false
features = ['derive']
version = '1.0.6'

[dependencies.support]
default_features = false
git = 'https://github.com/paritytech/substrate.git'
package = 'srml-support'
branch = 'master'

[dependencies.system]
default_features = false
git = 'https://github.com/paritytech/substrate.git'
package = 'srml-system'
branch = 'master'

[dependencies.balances]
default_features = false
git = 'https://github.com/paritytech/substrate.git'
package = 'srml-balances'
branch = 'master'

[dependencies.runtime-primitives]
default_features = false
git = 'https://github.com/paritytech/substrate.git'
package = 'sr-primitives'
branch = 'master'

[dev-dependencies.primitives]
default_features = false
git = 'https://github.com/paritytech/substrate.git'
package = 'substrate-primitives'
branch = 'master'
177 changes: 177 additions & 0 deletions kitchen/modules/weights/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
#![cfg_attr(not(feature = "std"), no_std)]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't we use headers here?

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd like to know more about headers. Do you have a link to read?

I do know if I remove this line, the build fails.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean license headers. Probably @shawntabrizi should decide.


// Transaction Weight Examples
// https://crates.parity.io/sr_primitives/weights/index.html
use support::{ensure, decl_module, decl_storage, dispatch::{Result, WeighData}};
use runtime_primitives::weights::{ DispatchClass, Weight, ClassifyDispatch, SimpleDispatchInfo };

pub trait Trait: system::Trait {}

decl_storage! {
trait Store for Module<T: Trait> as SimpleMap {
StoredValue get(stored_value): u32;
}
}

// A "scale" to weigh transactions. This scale can be used with any transactions that take a
// single argument of type u32. The ultimate weight of the transaction is the / product of the
// transaction parameter and the field of this struct.
pub struct Linear(u32);

// The actual weight calculation happens in the
// impl WeighData block
impl WeighData<(&u32,)> for Linear {
fn weigh_data(&self, (x,): (&u32,)) -> Weight {

// Use saturation so that an extremely large parameter value
// Does not cause overflow.
x.saturating_mul(self.0)
}
}

// Any struct that is used to weigh data must also implement ClassifyDispatchInfo. Here we classify
// the transaction as Normal (as opposed to operational.)
impl<T> ClassifyDispatch<T> for Linear {
fn classify_dispatch(&self, _: T) -> DispatchClass {
// Classify all calls as Normal (which is the default)
Default::default()
}
}

// Another scale to weight transactions. This one is more complex. / It computes weight according
// to the formula a*x^2 + b*y + c where / a, b, and c are fields in the struct, and x and y are
// transaction / parameters.
pub struct Quadratic(u32, u32, u32);

impl WeighData<(&u32, &u32)> for Quadratic {
fn weigh_data(&self, (x, y): (&u32, &u32)) -> Weight {

let ax2 = x.saturating_mul(*x).saturating_mul(self.0);
let by = y.saturating_mul(self.1);
let c = self.2;

ax2.saturating_add(by).saturating_add(c)
}
}

impl<T> ClassifyDispatch<T> for Quadratic {
fn classify_dispatch(&self, _: T) -> DispatchClass {
// Classify all calls as Normal (which is the default)
Default::default()
}
}

// A final scale to weight transactions. This one weighs / transactions where the first parameter
// is bool. If / the bool is true, then the weight is linear in the / second parameter. Otherwise
// the weight is constant.
pub struct Conditional(u32);

impl WeighData<(&bool, &u32)> for Conditional {
fn weigh_data(&self, (switch, val): (&bool, &u32)) -> Weight {

if *switch {
val.saturating_mul(self.0)
}
else {
self.0
}
}
}

impl<T> ClassifyDispatch<T> for Conditional {
fn classify_dispatch(&self, _: T) -> DispatchClass {
// Classify all calls as Normal (which is the default)
Default::default()
}
}

decl_module! {
pub struct Module<T: Trait> for enum Call where origin: T::Origin {

// Store value does not loop at all so a fixed weight is appropriate. Fixed weights can
// be assigned using types available in the Substrate framework. No custom coding is
// necessary.
#[weight = SimpleDispatchInfo::FixedNormal(100)]
fn store_value(_origin, entry: u32) -> Result {

StoredValue::put(entry);

Ok(())
}

// add_n sets the storage value n times, so it should cost n times as much as
// store_value. Because it performs both a read and a write, the multiplier is set to 200
// instead of 100 as before.
#[weight = Linear(200)]
fn add_n(_origin, n: u32) -> Result {

let mut old : u32;
for _i in 1..=n {
old = StoredValue::get();
StoredValue::put(old + 1);
}
Ok(())
}

// The actual expense of `double` is proportional to a storage value. Dispatch
// weightings can't use storage values directly, because the weight should be computable
// ahead of time. Instead we have the caller pass in the expected storage value and we
// ensure it is correct.
#[weight = Linear(200)]
fn double(_origin, initial_value: u32) -> Result {

// Ensure the value passed by the caller actually matches storage If this condition
// were not true, the caller would be able to avoid paying appropriate fees.
let initial = StoredValue::get();
ensure!(initial == initial_value, "Storage value did not match parameter");

for _i in 1..=initial {
let old = StoredValue::get();
StoredValue::put(old + 1);
}
Ok(())
}

// This one is quadratic in the first argument plus linear in the second plus a constant.
// This calculation is not meant to do something really useful or common other than
// demonstrate that weights should grow by the same order as the compute required by the
// transaction.
#[weight = Quadratic(200, 30, 100)]
fn complex_calculations(_origin, x: u32, y: u32) -> Result {
// This first part performs a relatively cheap (hence 30)
// in-memory calculations.
let mut part1 = 0;
for _i in 1..=y {
part1 += 2
}

// The second part performs x^2 storage read-writes (hence 200)
for _j in 1..=x {
for _k in 1..=x {
StoredValue::put(StoredValue::get() + 1);
}
}

// One final storage write (hence 100)
StoredValue::put(part1);

Ok(())
}

// Here the first parameter, a boolean has a significant effect on the computational
// intensity of the call.
#[weight = Conditional(200)]
fn add_or_set(_origin, add_flag: bool, val: u32) -> Result {
if add_flag {
StoredValue::put(&val);
}
else {
for _i in 1..=val {
StoredValue::put(StoredValue::get());
}
}

Ok(())
}
}
}
2 changes: 2 additions & 0 deletions kitchen/node/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ basic-authorship = { package = "substrate-basic-authorship", git = 'https://gith
# Your runtime must have the necessary runtime modules to support consensus (Babe, Grandpa, etc)
runtime = { package = "super-runtime", path = "../runtimes/super-runtime" }
runtime-genesis = { package = "super-genesis", path = "../runtimes/super-genesis" }
# runtime = { package = "weight-fee-runtime", path = "../runtimes/weight-fee-runtime"}
# runtime-genesis = { package = "weight-fee-genesis", path = "../runtimes/weight-fee-genesis"}

[build-dependencies]
vergen = "3.0.4"
2 changes: 1 addition & 1 deletion kitchen/runtimes/super-genesis/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ version = "2.0.0"
authors = ["Anonymous"]
edition = "2018"

[dependencies.super-runtime]
[dependencies.runtime]
package = 'super-runtime'
path = '../super-runtime'

Expand Down
2 changes: 1 addition & 1 deletion kitchen/runtimes/super-genesis/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use super_runtime::{
use runtime::{
AccountId, BabeConfig, BalancesConfig, GenesisConfig, GrandpaConfig,
SudoConfig, IndicesConfig, SystemConfig, WASM_BINARY,
};
Expand Down
2 changes: 1 addition & 1 deletion kitchen/runtimes/super-runtime/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ schedule-on-finalize = { package = "schedule-on-finalize", path = "../../modules
[dependencies.parity-scale-codec]
default-features = false
features = ['derive']
version = '1.0.6' # v1.0.0 indevhub/node-template
version = '1.0.6'

[dependencies.rstd]
default-features = false
Expand Down
28 changes: 14 additions & 14 deletions kitchen/runtimes/super-runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -258,6 +258,20 @@ impl sudo::Trait for Runtime {
type Proposal = Call;
}

parameter_types! {
pub const TransactionBaseFee: u128 = 0;
pub const TransactionByteFee: u128 = 1;
}

impl transaction_payment::Trait for Runtime {
type Currency = balances::Module<Runtime>;
type OnTransactionPayment = ();
type TransactionBaseFee = TransactionBaseFee;
type TransactionByteFee = TransactionByteFee;
type WeightToFee = ConvertInto;
type FeeMultiplierUpdate = ();
}

// ---------------------- Recipe Runtime Configurations ----------------------
impl simple_event::Trait for Runtime {
type Event = Event;
Expand Down Expand Up @@ -321,20 +335,6 @@ impl schedule_on_finalize::Trait for Runtime {
type ExecutionFrequency = ClearFrequency; // for convenience (can use a different constant)
}

parameter_types! {
pub const TransactionBaseFee: u128 = 0;
pub const TransactionByteFee: u128 = 1;
}

impl transaction_payment::Trait for Runtime {
type Currency = balances::Module<Runtime>;
type OnTransactionPayment = ();
type TransactionBaseFee = TransactionBaseFee;
type TransactionByteFee = TransactionByteFee;
type WeightToFee = ConvertInto;
type FeeMultiplierUpdate = ();
}

construct_runtime!(
pub enum Runtime where
Block = Block,
Expand Down
13 changes: 13 additions & 0 deletions kitchen/runtimes/weight-fee-genesis/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[package]
name = 'weight-fee-genesis'
version = "2.0.0"
authors = ["Anonymous"]
edition = "2018"

[dependencies.runtime]
package = 'weight-fee-runtime'
path = '../weight-fee-runtime'

[dependencies]
babe-primitives = { package = "substrate-consensus-babe-primitives", git = "https://github.com/paritytech/substrate", branch = "master" }
grandpa-primitives = { package = "substrate-finality-grandpa-primitives", git = "https://github.com/paritytech/substrate", branch = "master" }
34 changes: 34 additions & 0 deletions kitchen/runtimes/weight-fee-genesis/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
use runtime::{
AccountId, BabeConfig, BalancesConfig, GenesisConfig, GrandpaConfig,
SudoConfig, IndicesConfig, SystemConfig, WASM_BINARY,
};
use babe_primitives::{AuthorityId as BabeId};
use grandpa_primitives::{AuthorityId as GrandpaId};

pub fn testnet_genesis(initial_authorities: Vec<(AccountId, AccountId, GrandpaId, BabeId)>,
root_key: AccountId,
endowed_accounts: Vec<AccountId>,
_enable_println: bool) -> GenesisConfig {
GenesisConfig {
system: Some(SystemConfig {
code: WASM_BINARY.to_vec(),
changes_trie_config: Default::default(),
}),
indices: Some(IndicesConfig {
ids: endowed_accounts.clone(),
}),
balances: Some(BalancesConfig {
balances: endowed_accounts.iter().cloned().map(|k|(k, 1 << 60)).collect(),
vesting: vec![],
}),
sudo: Some(SudoConfig {
key: root_key,
}),
babe: Some(BabeConfig {
authorities: initial_authorities.iter().map(|x| (x.3.clone(), 1)).collect(),
}),
grandpa: Some(GrandpaConfig {
authorities: initial_authorities.iter().map(|x| (x.2.clone(), 1)).collect(),
}),
}
}
Loading