Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ parameter_types! {
pub static MinerTxPriority: u64 = 100;
pub static SolutionImprovementThreshold: Perbill = Perbill::zero();
pub static OffchainRepeat: BlockNumber = 5;
pub static OffchainStorage: bool = true;
pub static MinerMaxLength: u32 = 256;
pub static MinerPages: u32 = 1;
pub static MaxVotesPerVoter: u32 = <TestNposSolution as NposSolution>::LIMIT as u32;
Expand Down Expand Up @@ -193,6 +194,7 @@ impl crate::verifier::Config for Runtime {
impl crate::unsigned::Config for Runtime {
type MinerPages = MinerPages;
type OffchainRepeat = OffchainRepeat;
type OffchainStorage = OffchainStorage;
type MinerTxPriority = MinerTxPriority;
type OffchainSolver = SequentialPhragmen<Self::AccountId, Perbill>;
type WeightInfo = ();
Expand Down Expand Up @@ -354,6 +356,10 @@ impl ExtBuilder {
MaxBackersPerWinnerFinal::set(c);
self
}
pub(crate) fn offchain_storage(self, s: bool) -> Self {
OffchainStorage::set(s);
self
}
pub(crate) fn miner_tx_priority(self, p: u64) -> Self {
MinerTxPriority::set(p);
self
Expand Down Expand Up @@ -431,6 +437,7 @@ impl ExtBuilder {
(95, 100),
(96, 100),
(97, 100),
(98, 100),
(99, 100),
(999, 100),
(9999, 100),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ impl EstimateCallFee<signed_pallet::Call<Runtime>, Balance> for FixedCallFee {
parameter_types! {
pub static SignedDepositBase: Balance = 5;
pub static SignedDepositPerPage: Balance = 1;
pub static InvulnerableDeposit: Balance = 7;
pub static SignedMaxSubmissions: u32 = 3;
pub static SignedRewardBase: Balance = 3;
pub static SignedPhaseSwitch: SignedSwitch = SignedSwitch::Real;
Expand All @@ -76,10 +77,10 @@ parameter_types! {
}

impl crate::signed::Config for Runtime {
type RuntimeHoldReason = RuntimeHoldReason;
type Currency = Balances;
type DepositBase = SignedDepositBase;
type DepositPerPage = SignedDepositPerPage;
type InvulnerableDeposit = InvulnerableDeposit;
type EstimateCallFee = FixedCallFee;
type MaxSubmissions = SignedMaxSubmissions;
type RewardBase = SignedRewardBase;
Expand Down
84 changes: 65 additions & 19 deletions substrate/frame/election-provider-multi-block/src/signed/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,6 @@
//! for more or less free by the submitter itself, and by anyone else as well, in which case they
//! get a share of the the sum deposit. The share increases as times goes on.
//! **Metadata update**: imagine you mis-computed your score.
//! **whitelisted accounts**: who will not pay deposits are needed. They can still be ejected, but
//! for free.
//! **Permissionless `clear_old_round_data`**: Anyone can clean anyone else's data, and get a part
//! of their deposit.

Expand Down Expand Up @@ -236,14 +234,17 @@ pub mod pallet {
/// Handler to the currency.
type Currency: Inspect<Self::AccountId>
+ Mutate<Self::AccountId>
+ MutateHold<Self::AccountId, Reason = Self::RuntimeHoldReason>;
+ MutateHold<Self::AccountId, Reason: From<HoldReason>>;

/// Base deposit amount for a submission.
type DepositBase: CalculateBaseDeposit<BalanceOf<Self>>;

/// Extra deposit per-page.
type DepositPerPage: CalculatePageDeposit<BalanceOf<Self>>;

/// The fixed deposit charged upon [`Pallet::register`] from [`Invulnerables`].
type InvulnerableDeposit: Get<BalanceOf<Self>>;

/// Base reward that is given to the winner.
type RewardBase: Get<BalanceOf<Self>>;

Expand All @@ -268,9 +269,6 @@ pub mod pallet {
/// submitter for the winner.
type EstimateCallFee: EstimateCallFee<Call<Self>, BalanceOf<Self>>;

/// Overarching hold reason.
type RuntimeHoldReason: From<HoldReason>;

/// Provided weights of this pallet.
type WeightInfo: WeightInfo;
}
Expand All @@ -283,6 +281,19 @@ pub mod pallet {
SignedSubmission,
}

/// Accounts whitelisted by governance to always submit their solutions.
///
/// They are different in that:
///
/// * They always pay a fixed deposit for submission, specified by
/// [`Config::InvulnerableDeposit`]. They pay no page deposit.
/// * If _ejected_ by better solution from [`SortedScores`], they will get their full deposit
/// back.
/// * They always get their tx-fee back even if they are _discarded_.
#[pallet::storage]
pub type Invulnerables<T: Config> =
StorageValue<_, BoundedVec<T::AccountId, ConstU32<16>>, ValueQuery>;

/// Wrapper type for signed submissions.
///
/// It handles 3 storage items:
Expand Down Expand Up @@ -478,7 +489,11 @@ pub mod pallet {
Pallet::<T>::settle_deposit(
&discarded,
metadata.deposit,
T::EjectGraceRatio::get(),
if Pallet::<T>::is_invulnerable(&discarded) {
One::one()
} else {
T::EjectGraceRatio::get()
},
);
}

Expand Down Expand Up @@ -513,12 +528,16 @@ pub mod pallet {
}

/// Get the deposit of a registration with the given number of pages.
fn deposit_for(pages: usize) -> BalanceOf<T> {
let round = Pallet::<T>::current_round();
let queue_size = Self::submitters_count(round);
let base = T::DepositBase::calculate_base_deposit(queue_size);
let pages = T::DepositPerPage::calculate_page_deposit(queue_size, pages);
base.saturating_add(pages)
fn deposit_for(who: &T::AccountId, pages: usize) -> BalanceOf<T> {
if Pallet::<T>::is_invulnerable(who) {
T::InvulnerableDeposit::get()
} else {
let round = Pallet::<T>::current_round();
let queue_size = Self::submitters_count(round);
let base = T::DepositBase::calculate_base_deposit(queue_size);
let pages = T::DepositPerPage::calculate_page_deposit(queue_size, pages);
base.saturating_add(pages)
}
}

fn try_mutate_page_inner(
Expand All @@ -539,7 +558,7 @@ pub mod pallet {

// update deposit.
let new_pages = metadata.pages.iter().filter(|x| **x).count();
let new_deposit = Self::deposit_for(new_pages);
let new_deposit = Self::deposit_for(&who, new_pages);
let old_deposit = metadata.deposit;
if new_deposit > old_deposit {
let to_reserve = new_deposit - old_deposit;
Expand Down Expand Up @@ -748,6 +767,8 @@ pub mod pallet {
RoundNotOver,
/// Bad witness data provided.
BadWitnessData,
/// Too many invulnerable accounts are provided,
TooManyInvulnerables,
}

#[pallet::call]
Expand All @@ -765,7 +786,7 @@ pub mod pallet {
// note: we could already check if this is a duplicate here, but prefer keeping the code
// simple for now.

let deposit = Submissions::<T>::deposit_for(0);
let deposit = Submissions::<T>::deposit_for(&who, 0);
let reward = T::RewardBase::get();
let fee = T::EstimateCallFee::estimate_call_fee(
&Call::register { claimed_score },
Expand Down Expand Up @@ -875,21 +896,42 @@ pub mod pallet {
Precision::BestEffort,
);
debug_assert_eq!(_res, Ok(metadata.deposit));
Self::deposit_event(Event::<T>::Discarded(current_round, discarded));

// maybe give back their fees
if Self::is_invulnerable(&discarded) {
let _r = T::Currency::mint_into(&discarded, metadata.fee);
debug_assert!(_r.is_ok());
}

Self::deposit_event(Event::<T>::Discarded(round, discarded));

// IFF all good, this is free of charge.
Ok(None.into())
}

/// Set the invulnerable list.
///
/// Dispatch origin must the the same as [`crate::Config::AdminOrigin`].
#[pallet::call_index(4)]
#[pallet::weight(T::DbWeight::get().writes(1))]
pub fn set_invulnerables(origin: OriginFor<T>, inv: Vec<T::AccountId>) -> DispatchResult {
<T as crate::Config>::AdminOrigin::ensure_origin(origin)?;
let bounded: BoundedVec<_, ConstU32<16>> =
inv.try_into().map_err(|_| Error::<T>::TooManyInvulnerables)?;
Invulnerables::<T>::set(bounded);
Ok(())
}
}

#[pallet::view_functions]
impl<T: Config> Pallet<T> {
/// Get the deposit amount that will be held for a solution of `pages`.
///
/// This allows an offchain application to know what [`Config::DepositPerPage`] and
/// [`Config::DepositBase`] are doing under the hood.
pub fn deposit_for(pages: u32) -> BalanceOf<T> {
Submissions::<T>::deposit_for(pages as usize)
/// [`Config::DepositBase`] are doing under the hood. It also takes into account if `who` is
/// [`Invulnerables`] or not.
pub fn deposit_for(who: T::AccountId, pages: u32) -> BalanceOf<T> {
Submissions::<T>::deposit_for(&who, pages as usize)
}
}

Expand Down Expand Up @@ -937,6 +979,10 @@ impl<T: Config> Pallet<T> {
crate::Pallet::<T>::round()
}

fn is_invulnerable(who: &T::AccountId) -> bool {
Invulnerables::<T>::get().contains(who)
}

fn settle_deposit(who: &T::AccountId, deposit: BalanceOf<T>, grace: Perbill) {
let to_refund = grace * deposit;
let to_slash = deposit.defensive_saturating_sub(to_refund);
Expand Down
Loading