1234567891011121314151617#![cfg_attr(not(feature = "std"), no_std)]1819use core::marker::PhantomData;2021use frame_support::{22 pallet,23 weights::{WeightToFeePolynomial, WeightToFeeCoefficients, WeightToFeeCoefficient, Weight},24 traits::Get,25 Parameter,26};27use codec::{Decode, Encode, MaxEncodedLen};28use scale_info::TypeInfo;29use sp_arithmetic::{30 per_things::{Perbill, PerThing},31 traits::{BaseArithmetic, Unsigned},32};33use smallvec::smallvec;3435pub use pallet::*;36use sp_core::U256;3738#[cfg(feature = "runtime-benchmarks")]39mod benchmarking;40pub mod weights;4142#[pallet]43mod pallet {44 use super::*;45 use frame_support::{46 traits::{Get},47 pallet_prelude::{48 StorageValue, ValueQuery, DispatchResult, IsType, Member, MaybeSerializeDeserialize,49 },50 log,51 dispatch::{Codec, fmt::Debug},52 };53 use frame_system::{pallet_prelude::OriginFor, ensure_root};54 use sp_arithmetic::{FixedPointOperand, traits::AtLeast32BitUnsigned};55 pub use crate::weights::WeightInfo;5657 #[pallet::config]58 pub trait Config: frame_system::Config {59 60 type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;6162 type Balance: Parameter63 + Member64 + AtLeast32BitUnsigned65 + Codec66 + Default67 + Copy68 + MaybeSerializeDeserialize69 + Debug70 + MaxEncodedLen71 + TypeInfo72 + FixedPointOperand;7374 #[pallet::constant]75 type DefaultWeightToFeeCoefficient: Get<u64>;76 #[pallet::constant]77 type DefaultMinGasPrice: Get<u64>;7879 #[pallet::constant]80 type MaxXcmAllowedLocations: Get<u32>;81 #[pallet::constant]82 type AppPromotionDailyRate: Get<Perbill>;83 #[pallet::constant]84 type DayRelayBlocks: Get<Self::BlockNumber>;8586 #[pallet::constant]87 type DefaultCollatorSelectionMaxCollators: Get<u32>;88 #[pallet::constant]89 type DefaultCollatorSelectionLicenseBond: Get<Self::Balance>;90 #[pallet::constant]91 type DefaultCollatorSelectionKickThreshold: Get<Self::BlockNumber>;9293 94 type WeightInfo: WeightInfo;95 }9697 #[pallet::event]98 #[pallet::generate_deposit(pub(super) fn deposit_event)]99 pub enum Event<T: Config> {100 NewDesiredCollators {101 desired_collators: Option<u32>,102 },103 NewCollatorLicenseBond {104 bond_cost: Option<T::Balance>,105 },106 NewCollatorKickThreshold {107 length_in_blocks: Option<T::BlockNumber>,108 },109 }110111 #[pallet::error]112 pub enum Error<T> {113 InconsistentConfiguration,114 }115116 #[pallet::storage]117 pub type WeightToFeeCoefficientOverride<T: Config> = StorageValue<118 Value = u64,119 QueryKind = ValueQuery,120 OnEmpty = T::DefaultWeightToFeeCoefficient,121 >;122123 #[pallet::storage]124 pub type MinGasPriceOverride<T: Config> =125 StorageValue<Value = u64, QueryKind = ValueQuery, OnEmpty = T::DefaultMinGasPrice>;126127 #[pallet::storage]128 pub type AppPromomotionConfigurationOverride<T: Config> =129 StorageValue<Value = AppPromotionConfiguration<T::BlockNumber>, QueryKind = ValueQuery>;130131 #[pallet::storage]132 pub type CollatorSelectionDesiredCollatorsOverride<T: Config> = StorageValue<133 Value = u32,134 QueryKind = ValueQuery,135 OnEmpty = T::DefaultCollatorSelectionMaxCollators,136 >;137138 #[pallet::storage]139 pub type CollatorSelectionLicenseBondOverride<T: Config> = StorageValue<140 Value = T::Balance,141 QueryKind = ValueQuery,142 OnEmpty = T::DefaultCollatorSelectionLicenseBond,143 >;144145 #[pallet::storage]146 pub type CollatorSelectionKickThresholdOverride<T: Config> = StorageValue<147 Value = T::BlockNumber,148 QueryKind = ValueQuery,149 OnEmpty = T::DefaultCollatorSelectionKickThreshold,150 >;151152 #[pallet::call]153 impl<T: Config> Pallet<T> {154 #[pallet::call_index(0)]155 #[pallet::weight(T::WeightInfo::set_weight_to_fee_coefficient_override())]156 pub fn set_weight_to_fee_coefficient_override(157 origin: OriginFor<T>,158 coeff: Option<u64>,159 ) -> DispatchResult {160 ensure_root(origin)?;161 if let Some(coeff) = coeff {162 <WeightToFeeCoefficientOverride<T>>::set(coeff);163 } else {164 <WeightToFeeCoefficientOverride<T>>::kill();165 }166 Ok(())167 }168169 #[pallet::call_index(1)]170 #[pallet::weight(T::WeightInfo::set_min_gas_price_override())]171 pub fn set_min_gas_price_override(172 origin: OriginFor<T>,173 coeff: Option<u64>,174 ) -> DispatchResult {175 ensure_root(origin)?;176 if let Some(coeff) = coeff {177 <MinGasPriceOverride<T>>::set(coeff);178 } else {179 <MinGasPriceOverride<T>>::kill();180 }181 Ok(())182 }183184 #[pallet::call_index(3)]185 #[pallet::weight(T::WeightInfo::set_app_promotion_configuration_override())]186 pub fn set_app_promotion_configuration_override(187 origin: OriginFor<T>,188 mut configuration: AppPromotionConfiguration<T::BlockNumber>,189 ) -> DispatchResult {190 ensure_root(origin)?;191 if configuration.interval_income.is_some() {192 return Err(<Error<T>>::InconsistentConfiguration.into());193 }194195 configuration.interval_income = configuration.recalculation_interval.map(|b| {196 Perbill::from_rational(b, T::DayRelayBlocks::get())197 * T::AppPromotionDailyRate::get()198 });199200 <AppPromomotionConfigurationOverride<T>>::set(configuration);201202 Ok(())203 }204205 #[pallet::call_index(4)]206 #[pallet::weight(T::WeightInfo::set_collator_selection_desired_collators())]207 pub fn set_collator_selection_desired_collators(208 origin: OriginFor<T>,209 max: Option<u32>,210 ) -> DispatchResult {211 ensure_root(origin)?;212 if let Some(max) = max {213 214 if max > T::DefaultCollatorSelectionMaxCollators::get() {215 log::warn!("max > T::DefaultCollatorSelectionMaxCollators; you might need to run benchmarks again");216 }217 <CollatorSelectionDesiredCollatorsOverride<T>>::set(max);218 } else {219 <CollatorSelectionDesiredCollatorsOverride<T>>::kill();220 }221 Self::deposit_event(Event::NewDesiredCollators {222 desired_collators: max,223 });224 Ok(())225 }226227 #[pallet::call_index(5)]228 #[pallet::weight(T::WeightInfo::set_collator_selection_license_bond())]229 pub fn set_collator_selection_license_bond(230 origin: OriginFor<T>,231 amount: Option<<T as Config>::Balance>,232 ) -> DispatchResult {233 ensure_root(origin)?;234 if let Some(amount) = amount {235 <CollatorSelectionLicenseBondOverride<T>>::set(amount);236 } else {237 <CollatorSelectionLicenseBondOverride<T>>::kill();238 }239 Self::deposit_event(Event::NewCollatorLicenseBond { bond_cost: amount });240 Ok(())241 }242243 #[pallet::call_index(6)]244 #[pallet::weight(T::WeightInfo::set_collator_selection_kick_threshold())]245 pub fn set_collator_selection_kick_threshold(246 origin: OriginFor<T>,247 threshold: Option<T::BlockNumber>,248 ) -> DispatchResult {249 ensure_root(origin)?;250 if let Some(threshold) = threshold {251 <CollatorSelectionKickThresholdOverride<T>>::set(threshold);252 } else {253 <CollatorSelectionKickThresholdOverride<T>>::kill();254 }255 Self::deposit_event(Event::NewCollatorKickThreshold {256 length_in_blocks: threshold,257 });258 Ok(())259 }260 }261262 #[pallet::pallet]263 pub struct Pallet<T>(_);264}265266pub struct WeightToFee<T, B>(PhantomData<(T, B)>);267268impl<T, B> WeightToFeePolynomial for WeightToFee<T, B>269where270 T: Config,271 B: BaseArithmetic + From<u32> + From<u64> + Copy + Unsigned,272{273 type Balance = B;274275 fn polynomial() -> WeightToFeeCoefficients<Self::Balance> {276 smallvec!(WeightToFeeCoefficient {277 coeff_integer: (<WeightToFeeCoefficientOverride<T>>::get() / Perbill::ACCURACY as u64)278 .into(),279 coeff_frac: Perbill::from_parts(280 (<WeightToFeeCoefficientOverride<T>>::get() % Perbill::ACCURACY as u64) as u32281 ),282 negative: false,283 degree: 1,284 })285 }286}287288pub struct FeeCalculator<T>(PhantomData<T>);289impl<T: Config> fp_evm::FeeCalculator for FeeCalculator<T> {290 fn min_gas_price() -> (U256, Weight) {291 (292 <MinGasPriceOverride<T>>::get().into(),293 T::DbWeight::get().reads(1),294 )295 }296}297298#[derive(Encode, Decode, Clone, Debug, Default, TypeInfo, MaxEncodedLen, PartialEq, PartialOrd)]299pub struct AppPromotionConfiguration<BlockNumber> {300 301 pub recalculation_interval: Option<BlockNumber>,302 303 pub pending_interval: Option<BlockNumber>,304 305 pub interval_income: Option<Perbill>,306 307 pub max_stakers_per_calculation: Option<u8>,308}