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

Commit

Permalink
Companion for Decouple Staking and Election - Part 3: Signed Phase (#…
Browse files Browse the repository at this point in the history
…2793)

* Companion for Decouple Staking and Election - Part 3: Signed Phase

paritytech/substrate#7910

* remove some config types

* allow up to 5 signed submissions on polkadot and kusama

* signed phase is equal induration to unsigned phase

* use chain defaults for base and per-byte deposits; >= 16 SignedMaxSubmissions

* use a small but non-trivial solution reward

* reduce signed deposit per byte fee

* reduce signed reward, adjust polkadot expected soln size

* copy submit benchmark from substrate

* demo calculating an appropriate fee for the signed reward

Unfortunately, this doesn't work: it needs to be a constant function,
and AFAIK there's no way to make a trait method constant.

* SignedRewardBase is 1.5x the fee to submit a signed solution

* all chains use deposit byte of base per 50k

* update Substrate

* cargo update -p pallet-election-provider-multi-phase

Co-authored-by: parity-processbot <>
  • Loading branch information
coriolinus authored Jun 28, 2021
1 parent 2b855f3 commit d5fb327
Show file tree
Hide file tree
Showing 10 changed files with 349 additions and 187 deletions.
311 changes: 156 additions & 155 deletions Cargo.lock

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion runtime/common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ pallet-vesting = { git = "https://github.com/paritytech/substrate", branch = "ma
pallet-offences = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-transaction-payment = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-treasury = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }

pallet-election-provider-multi-phase = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }
pallet-beefy = { git = "https://github.com/paritytech/grandpa-bridge-gadget", branch = "master", default-features = false }
pallet-mmr = { git = "https://github.com/paritytech/substrate", branch = "master", default-features = false }

Expand Down Expand Up @@ -91,6 +91,7 @@ std = [
"pallet-vesting/std",
"pallet-transaction-payment/std",
"pallet-treasury/std",
"pallet-election-provider-multi-phase/std",
"slot-range-helper/std",
"sp-runtime/std",
"sp-session/std",
Expand Down
61 changes: 61 additions & 0 deletions runtime/common/src/elections.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// Copyright 2021 Parity Technologies (UK) Ltd.
// This file is part of Polkadot.

// Polkadot is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// Polkadot is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with Polkadot. If not, see <http://www.gnu.org/licenses/>.

//! Code for elections.
use frame_support::{
parameter_types,
traits::Get,
weights::{DispatchClass, Weight, WeightToFeePolynomial},
};
use sp_runtime::Perbill;
use super::{BlockExecutionWeight, BlockLength, BlockWeights};

parameter_types! {
/// A limit for off-chain phragmen unsigned solution submission.
///
/// We want to keep it as high as possible, but can't risk having it reject,
/// so we always subtract the base block execution weight.
pub OffchainSolutionWeightLimit: Weight = BlockWeights::get()
.get(DispatchClass::Normal)
.max_extrinsic
.expect("Normal extrinsics have weight limit configured by default; qed")
.saturating_sub(BlockExecutionWeight::get());

/// A limit for off-chain phragmen unsigned solution length.
///
/// We allow up to 90% of the block's size to be consumed by the solution.
pub OffchainSolutionLengthLimit: u32 = Perbill::from_rational(90_u32, 100) *
*BlockLength::get()
.max
.get(DispatchClass::Normal);
}

/// Compute the expected fee for submitting an election solution.
///
/// This is `multiplier` multiplied by the fee for the expected submission weight according to the
/// weight info.
///
/// Assumes that the signed submission queue is full.
pub fn fee_for_submit_call<T, WeightToFee, WeightInfo>(multiplier: Perbill) -> WeightToFee::Balance
where
T: pallet_election_provider_multi_phase::Config,
WeightToFee: WeightToFeePolynomial,
WeightInfo: pallet_election_provider_multi_phase::WeightInfo,
{
let expected_weight = WeightInfo::submit(T::SignedMaxSubmissions::get());
multiplier * WeightToFee::calc(&expected_weight)
}
24 changes: 3 additions & 21 deletions runtime/common/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright 2019-2020 Parity Technologies (UK) Ltd.
// Copyright 2019-2021 Parity Technologies (UK) Ltd.
// This file is part of Polkadot.

// Polkadot is free software: you can redistribute it and/or modify
Expand Down Expand Up @@ -30,6 +30,7 @@ pub mod paras_registrar;
pub mod slot_range;
pub mod traits;
pub mod xcm_sender;
pub mod elections;

#[cfg(test)]
mod mock;
Expand All @@ -54,6 +55,7 @@ pub use pallet_staking::StakerStatus;
pub use sp_runtime::BuildStorage;
pub use pallet_timestamp::Call as TimestampCall;
pub use pallet_balances::Call as BalancesCall;
pub use elections::{OffchainSolutionLengthLimit, OffchainSolutionWeightLimit};

/// Implementations of some helper traits passed into runtime modules as associated types.
pub use impls::ToAuthor;
Expand Down Expand Up @@ -108,26 +110,6 @@ parameter_types! {
.build_or_panic();
}

parameter_types! {
/// A limit for off-chain phragmen unsigned solution submission.
///
/// We want to keep it as high as possible, but can't risk having it reject,
/// so we always subtract the base block execution weight.
pub OffchainSolutionWeightLimit: Weight = BlockWeights::get()
.get(DispatchClass::Normal)
.max_extrinsic
.expect("Normal extrinsics have weight limit configured by default; qed")
.saturating_sub(BlockExecutionWeight::get());

/// A limit for off-chain phragmen unsigned solution length.
///
/// We allow up to 90% of the block's size to be consumed by the solution.
pub OffchainSolutionLengthLimit: u32 = Perbill::from_rational(90_u32, 100) *
*BlockLength::get()
.max
.get(DispatchClass::Normal);
}

/// Parameterized slow adjusting fee updated based on
/// https://w3f-research.readthedocs.io/en/latest/polkadot/Token%20Economics.html#-2.-slow-adjusting-mechanism
pub type SlowAdjustingFeeUpdate<R> = TargetedFeeAdjustment<
Expand Down
30 changes: 26 additions & 4 deletions runtime/kusama/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ use primitives::v1::{
use runtime_common::{
claims, paras_registrar, xcm_sender, slots, auctions, crowdloan,
SlowAdjustingFeeUpdate, CurrencyToVote, impls::DealWithFees,
BlockHashCount, RocksDbWeight, BlockWeights, BlockLength, OffchainSolutionWeightLimit, OffchainSolutionLengthLimit,
BlockHashCount, RocksDbWeight, BlockWeights, BlockLength,
OffchainSolutionWeightLimit, OffchainSolutionLengthLimit, elections::fee_for_submit_call,
ToAuthor,
};

Expand Down Expand Up @@ -348,11 +349,24 @@ impl pallet_session::historical::Config for Runtime {
}

parameter_types! {
// no signed phase for now, just unsigned.
pub const SignedPhase: u32 = 0;
// phase durations. 1/4 of the last session for each.
pub const SignedPhase: u32 = EPOCH_DURATION_IN_SLOTS / 4;
pub const UnsignedPhase: u32 = EPOCH_DURATION_IN_SLOTS / 4;

// fallback: run election on-chain.
// signed config
pub const SignedMaxSubmissions: u32 = 16;
pub const SignedDepositBase: Balance = deposit(1, 0);
// A typical solution occupies within an order of magnitude of 50kb.
// This formula is currently adjusted such that a typical solution will spend an amount equal
// to the base deposit for every 50 kb.
pub const SignedDepositByte: Balance = deposit(1, 0) / (50 * 1024);
pub SignedRewardBase: Balance = fee_for_submit_call::<
Runtime,
crate::constants::fee::WeightToFee,
crate::weights::pallet_election_provider_multi_phase::WeightInfo<Runtime>,
>(Perbill::from_perthousand(1500));

// fallback: emergency phase.
pub const Fallback: pallet_election_provider_multi_phase::FallbackStrategy =
pallet_election_provider_multi_phase::FallbackStrategy::Nothing;
pub SolutionImprovementThreshold: Perbill = Perbill::from_rational(5u32, 10_000);
Expand All @@ -375,6 +389,14 @@ impl pallet_election_provider_multi_phase::Config for Runtime {
type Event = Event;
type Currency = Balances;
type UnsignedPhase = UnsignedPhase;
type SignedMaxSubmissions = SignedMaxSubmissions;
type SignedRewardBase = SignedRewardBase;
type SignedDepositBase = SignedDepositBase;
type SignedDepositByte = SignedDepositByte;
type SignedDepositWeight = ();
type SignedMaxWeight = Self::MinerMaxWeight;
type SlashHandler = (); // burn slashes
type RewardHandler = (); // nothing to do upon rewards
type SignedPhase = SignedPhase;
type SolutionImprovementThreshold = SolutionImprovementThreshold;
type MinerMaxIterations = MinerMaxIterations;
Expand Down
17 changes: 17 additions & 0 deletions runtime/kusama/src/weights/pallet_election_provider_multi_phase.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,13 @@ impl<T: frame_system::Config> pallet_election_provider_multi_phase::WeightInfo f
.saturating_add(T::DbWeight::get().reads(2 as Weight))
.saturating_add(T::DbWeight::get().writes(6 as Weight))
}
fn submit(c: u32, ) -> Weight {
(84_430_000 as Weight)
// Standard Error: 146_000
.saturating_add((2_758_000 as Weight).saturating_mul(c as Weight))
.saturating_add(T::DbWeight::get().reads(3 as Weight))
.saturating_add(T::DbWeight::get().writes(1 as Weight))
}
fn submit_unsigned(v: u32, t: u32, a: u32, d: u32, ) -> Weight {
(0 as Weight)
// Standard Error: 13_000
Expand All @@ -92,4 +99,14 @@ impl<T: frame_system::Config> pallet_election_provider_multi_phase::WeightInfo f
.saturating_add((4_469_000 as Weight).saturating_mul(d as Weight))
.saturating_add(T::DbWeight::get().reads(4 as Weight))
}
fn finalize_signed_phase_accept_solution() -> Weight {
(47_783_000 as Weight)
.saturating_add(T::DbWeight::get().reads(1 as Weight))
.saturating_add(T::DbWeight::get().writes(2 as Weight))
}
fn finalize_signed_phase_reject_solution() -> Weight {
(21_277_000 as Weight)
.saturating_add(T::DbWeight::get().reads(1 as Weight))
.saturating_add(T::DbWeight::get().writes(1 as Weight))
}
}
28 changes: 25 additions & 3 deletions runtime/polkadot/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ use runtime_common::{
impls::DealWithFees,
BlockHashCount, RocksDbWeight, BlockWeights, BlockLength,
OffchainSolutionWeightLimit, OffchainSolutionLengthLimit,
elections::fee_for_submit_call,
ParachainSessionKeyPlaceholder, AssignmentSessionKeyPlaceholder,
};

Expand Down Expand Up @@ -328,11 +329,24 @@ impl pallet_session::historical::Config for Runtime {
}

parameter_types! {
// no signed phase for now, just unsigned.
pub const SignedPhase: u32 = 0;
// phase durations. 1/4 of the last session for each.
pub const SignedPhase: u32 = EPOCH_DURATION_IN_SLOTS / 4;
pub const UnsignedPhase: u32 = EPOCH_DURATION_IN_SLOTS / 4;

// fallback: run election on-chain.
// signed config
pub const SignedMaxSubmissions: u32 = 16;
pub const SignedDepositBase: Balance = deposit(1, 0);
// A typical solution occupies within an order of magnitude of 50kb.
// This formula is currently adjusted such that a typical solution will spend an amount equal
// to the base deposit for every 50 kb.
pub const SignedDepositByte: Balance = deposit(1, 0) / (50 * 1024);
pub SignedRewardBase: Balance = fee_for_submit_call::<
Runtime,
crate::constants::fee::WeightToFee,
crate::weights::pallet_election_provider_multi_phase::WeightInfo<Runtime>,
>(Perbill::from_perthousand(1500));

// fallback: emergency phase.
pub const Fallback: pallet_election_provider_multi_phase::FallbackStrategy =
pallet_election_provider_multi_phase::FallbackStrategy::Nothing;
pub SolutionImprovementThreshold: Perbill = Perbill::from_rational(5u32, 10_000);
Expand All @@ -356,6 +370,14 @@ impl pallet_election_provider_multi_phase::Config for Runtime {
type Currency = Balances;
type SignedPhase = SignedPhase;
type UnsignedPhase = UnsignedPhase;
type SignedMaxSubmissions = SignedMaxSubmissions;
type SignedRewardBase = SignedRewardBase;
type SignedDepositBase = SignedDepositBase;
type SignedDepositByte = SignedDepositByte;
type SignedDepositWeight = ();
type SignedMaxWeight = Self::MinerMaxWeight;
type SlashHandler = (); // burn slashes
type RewardHandler = (); // nothing to do upon rewards
type SolutionImprovementThreshold = SolutionImprovementThreshold;
type MinerMaxIterations = MinerMaxIterations;
type MinerMaxWeight = OffchainSolutionWeightLimit; // For now use the one from staking.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,4 +92,21 @@ impl<T: frame_system::Config> pallet_election_provider_multi_phase::WeightInfo f
.saturating_add((3_606_000 as Weight).saturating_mul(d as Weight))
.saturating_add(T::DbWeight::get().reads(4 as Weight))
}
fn finalize_signed_phase_accept_solution() -> Weight {
(47_783_000 as Weight)
.saturating_add(T::DbWeight::get().reads(1 as Weight))
.saturating_add(T::DbWeight::get().writes(2 as Weight))
}
fn finalize_signed_phase_reject_solution() -> Weight {
(21_277_000 as Weight)
.saturating_add(T::DbWeight::get().reads(1 as Weight))
.saturating_add(T::DbWeight::get().writes(1 as Weight))
}
fn submit(c: u32) -> Weight {
(78_972_000 as Weight)
// Standard Error: 16_000
.saturating_add((308_000 as Weight).saturating_mul(c as Weight))
.saturating_add(T::DbWeight::get().reads(4 as Weight))
.saturating_add(T::DbWeight::get().writes(3 as Weight))
}
}
28 changes: 25 additions & 3 deletions runtime/westend/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ use runtime_common::{
impls::ToAuthor,
BlockHashCount, BlockWeights, BlockLength, RocksDbWeight,
OffchainSolutionWeightLimit, OffchainSolutionLengthLimit,
elections::fee_for_submit_call,
};

use runtime_parachains::origin as parachains_origin;
Expand Down Expand Up @@ -333,11 +334,24 @@ impl pallet_session::historical::Config for Runtime {
}

parameter_types! {
// no signed phase for now, just unsigned.
pub const SignedPhase: u32 = 0;
// phase durations. 1/4 of the last session for each.
pub const SignedPhase: u32 = EPOCH_DURATION_IN_SLOTS / 4;
pub const UnsignedPhase: u32 = EPOCH_DURATION_IN_SLOTS / 4;

// fallback: run election on-chain.
// signed config
pub const SignedMaxSubmissions: u32 = 128;
pub const SignedDepositBase: Balance = deposit(1, 0);
// A typical solution occupies within an order of magnitude of 50kb.
// This formula is currently adjusted such that a typical solution will spend an amount equal
// to the base deposit for every 50 kb.
pub const SignedDepositByte: Balance = deposit(1, 0) / (50 * 1024);
pub SignedRewardBase: Balance = fee_for_submit_call::<
Runtime,
crate::constants::fee::WeightToFee,
crate::weights::pallet_election_provider_multi_phase::WeightInfo<Runtime>,
>(Perbill::from_perthousand(1500));

// fallback: emergency phase.
pub const Fallback: pallet_election_provider_multi_phase::FallbackStrategy =
pallet_election_provider_multi_phase::FallbackStrategy::Nothing;

Expand All @@ -362,6 +376,14 @@ impl pallet_election_provider_multi_phase::Config for Runtime {
type Currency = Balances;
type SignedPhase = SignedPhase;
type UnsignedPhase = UnsignedPhase;
type SignedMaxSubmissions = SignedMaxSubmissions;
type SignedRewardBase = SignedRewardBase;
type SignedDepositBase = SignedDepositBase;
type SignedDepositByte = SignedDepositByte;
type SignedDepositWeight = ();
type SignedMaxWeight = Self::MinerMaxWeight;
type SlashHandler = (); // burn slashes
type RewardHandler = (); // nothing to do upon rewards
type SolutionImprovementThreshold = SolutionImprovementThreshold;
type MinerMaxIterations = MinerMaxIterations;
type MinerMaxWeight = OffchainSolutionWeightLimit; // For now use the one from staking.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,4 +92,21 @@ impl<T: frame_system::Config> pallet_election_provider_multi_phase::WeightInfo f
.saturating_add((3_731_000 as Weight).saturating_mul(d as Weight))
.saturating_add(T::DbWeight::get().reads(4 as Weight))
}
fn finalize_signed_phase_accept_solution() -> Weight {
(47_783_000 as Weight)
.saturating_add(T::DbWeight::get().reads(1 as Weight))
.saturating_add(T::DbWeight::get().writes(2 as Weight))
}
fn finalize_signed_phase_reject_solution() -> Weight {
(21_277_000 as Weight)
.saturating_add(T::DbWeight::get().reads(1 as Weight))
.saturating_add(T::DbWeight::get().writes(1 as Weight))
}
fn submit(c: u32) -> Weight {
(78_972_000 as Weight)
// Standard Error: 16_000
.saturating_add((308_000 as Weight).saturating_mul(c as Weight))
.saturating_add(T::DbWeight::get().reads(4 as Weight))
.saturating_add(T::DbWeight::get().writes(3 as Weight))
}
}

0 comments on commit d5fb327

Please sign in to comment.