1234567891011121314151617#![cfg_attr(not(feature = "std"), no_std)]1819use core::marker::PhantomData;2021use frame_support::{22 pallet,23 traits::Get,24 weights::{Weight, WeightToFeeCoefficient, WeightToFeeCoefficients, WeightToFeePolynomial},25};26pub use pallet::*;27use parity_scale_codec::{Decode, Encode, MaxEncodedLen};28use scale_info::TypeInfo;29use smallvec::smallvec;30use sp_arithmetic::{31 per_things::{PerThing, Perbill},32 traits::{BaseArithmetic, Unsigned},33};34use sp_core::U256;3536#[cfg(feature = "runtime-benchmarks")]37mod benchmarking;38pub mod weights;3940#[pallet]41mod pallet {42 use core::fmt::Debug;4344 use frame_support::{pallet_prelude::*, traits::Get};45 use frame_system::{ensure_root, pallet_prelude::*};46 use parity_scale_codec::Codec;47 use sp_arithmetic::{traits::AtLeast32BitUnsigned, FixedPointOperand, Permill};4849 use super::*;50 pub use crate::weights::WeightInfo;5152 #[pallet::config]53 pub trait Config: frame_system::Config {54 55 type RuntimeEvent: From<Event<Self>> + IsType<<Self as frame_system::Config>::RuntimeEvent>;5657 type Balance: Parameter58 + Member59 + AtLeast32BitUnsigned60 + From<up_common::types::Balance>61 + Codec62 + Default63 + Copy64 + MaybeSerializeDeserialize65 + Debug66 + MaxEncodedLen67 + TypeInfo68 + FixedPointOperand;6970 #[pallet::constant]71 type DefaultWeightToFeeCoefficient: Get<u64>;72 #[pallet::constant]73 type DefaultMinGasPrice: Get<u64>;7475 #[pallet::constant]76 type MaxXcmAllowedLocations: Get<u32>;77 #[pallet::constant]78 type AppPromotionDailyRate: Get<Perbill>;79 #[pallet::constant]80 type DayRelayBlocks: Get<BlockNumberFor<Self>>;8182 #[pallet::constant]83 type DefaultCollatorSelectionMaxCollators: Get<u32>;84 #[pallet::constant]85 type DefaultCollatorSelectionLicenseBond: Get<Self::Balance>;86 #[pallet::constant]87 type DefaultCollatorSelectionKickThreshold: Get<BlockNumberFor<Self>>;8889 90 type WeightInfo: WeightInfo;91 }9293 #[pallet::event]94 #[pallet::generate_deposit(pub(super) fn deposit_event)]95 pub enum Event<T: Config> {96 NewDesiredCollators {97 desired_collators: Option<u32>,98 },99 NewCollatorLicenseBond {100 bond_cost: Option<T::Balance>,101 },102 NewCollatorKickThreshold {103 length_in_blocks: Option<BlockNumberFor<T>>,104 },105 }106107 fn update_base_fee<T: Config>() {108 let base_fee_per_gas: U256 = <MinGasPriceOverride<T>>::get().into();109 let elasticity: Permill = Permill::zero();110 111 sp_io::storage::set(112 &hex_literal::hex!("c1fef3b7207c11a52df13c12884e77263864ade243c642793ebcfe9e16f454ca"),113 &base_fee_per_gas.encode(),114 );115 116 sp_io::storage::set(117 &hex_literal::hex!("c1fef3b7207c11a52df13c12884e772609bc3a1e532c9cb85d57feed02cbff8e"),118 &elasticity.encode(),119 );120 }121122 123 #[pallet::hooks]124 impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {125 fn on_runtime_upgrade() -> Weight {126 update_base_fee::<T>();127 T::DbWeight::get().reads_writes(1, 2)128 }129 }130131 #[pallet::genesis_config]132 pub struct GenesisConfig<T>(PhantomData<T>);133134 impl<T: Config> Default for GenesisConfig<T> {135 fn default() -> Self {136 Self(Default::default())137 }138 }139140 #[pallet::genesis_build]141 impl<T: Config> BuildGenesisConfig for GenesisConfig<T> {142 fn build(&self) {143 update_base_fee::<T>();144 }145 }146147 #[pallet::error]148 pub enum Error<T> {149 InconsistentConfiguration,150 }151152 #[pallet::storage]153 pub type WeightToFeeCoefficientOverride<T: Config> = StorageValue<154 Value = u64,155 QueryKind = ValueQuery,156 OnEmpty = T::DefaultWeightToFeeCoefficient,157 >;158159 #[pallet::storage]160 pub type MinGasPriceOverride<T: Config> =161 StorageValue<Value = u64, QueryKind = ValueQuery, OnEmpty = T::DefaultMinGasPrice>;162163 #[pallet::storage]164 pub type AppPromomotionConfigurationOverride<T: Config> =165 StorageValue<Value = AppPromotionConfiguration<BlockNumberFor<T>>, QueryKind = ValueQuery>;166167 #[pallet::storage]168 pub type CollatorSelectionDesiredCollatorsOverride<T: Config> = StorageValue<169 Value = u32,170 QueryKind = ValueQuery,171 OnEmpty = T::DefaultCollatorSelectionMaxCollators,172 >;173174 #[pallet::storage]175 pub type CollatorSelectionLicenseBondOverride<T: Config> = StorageValue<176 Value = T::Balance,177 QueryKind = ValueQuery,178 OnEmpty = T::DefaultCollatorSelectionLicenseBond,179 >;180181 #[pallet::storage]182 pub type CollatorSelectionKickThresholdOverride<T: Config> = StorageValue<183 Value = BlockNumberFor<T>,184 QueryKind = ValueQuery,185 OnEmpty = T::DefaultCollatorSelectionKickThreshold,186 >;187188 #[pallet::call]189 impl<T: Config> Pallet<T> {190 #[pallet::call_index(0)]191 #[pallet::weight(T::WeightInfo::set_weight_to_fee_coefficient_override())]192 pub fn set_weight_to_fee_coefficient_override(193 origin: OriginFor<T>,194 coeff: Option<u64>,195 ) -> DispatchResult {196 ensure_root(origin)?;197 if let Some(coeff) = coeff {198 <WeightToFeeCoefficientOverride<T>>::set(coeff);199 } else {200 <WeightToFeeCoefficientOverride<T>>::kill();201 }202 Ok(())203 }204205 #[pallet::call_index(1)]206 #[pallet::weight(T::WeightInfo::set_min_gas_price_override())]207 pub fn set_min_gas_price_override(208 origin: OriginFor<T>,209 coeff: Option<u64>,210 ) -> DispatchResult {211 ensure_root(origin)?;212 if let Some(coeff) = coeff {213 <MinGasPriceOverride<T>>::set(coeff);214 } else {215 <MinGasPriceOverride<T>>::kill();216 }217 218 219 update_base_fee::<T>();220 Ok(())221 }222223 #[pallet::call_index(3)]224 #[pallet::weight(T::WeightInfo::set_app_promotion_configuration_override())]225 pub fn set_app_promotion_configuration_override(226 origin: OriginFor<T>,227 mut configuration: AppPromotionConfiguration<BlockNumberFor<T>>,228 ) -> DispatchResult {229 ensure_root(origin)?;230 if configuration.interval_income.is_some() {231 return Err(<Error<T>>::InconsistentConfiguration.into());232 }233234 configuration.interval_income = configuration.recalculation_interval.map(|b| {235 Perbill::from_rational(b, T::DayRelayBlocks::get())236 * T::AppPromotionDailyRate::get()237 });238239 <AppPromomotionConfigurationOverride<T>>::set(configuration);240241 Ok(())242 }243244 #[pallet::call_index(4)]245 #[pallet::weight(T::WeightInfo::set_collator_selection_desired_collators())]246 pub fn set_collator_selection_desired_collators(247 origin: OriginFor<T>,248 max: Option<u32>,249 ) -> DispatchResult {250 ensure_root(origin)?;251 if let Some(max) = max {252 253 if max > T::DefaultCollatorSelectionMaxCollators::get() {254 log::warn!("max > T::DefaultCollatorSelectionMaxCollators; you might need to run benchmarks again");255 }256 <CollatorSelectionDesiredCollatorsOverride<T>>::set(max);257 } else {258 <CollatorSelectionDesiredCollatorsOverride<T>>::kill();259 }260 Self::deposit_event(Event::NewDesiredCollators {261 desired_collators: max,262 });263 Ok(())264 }265266 #[pallet::call_index(5)]267 #[pallet::weight(T::WeightInfo::set_collator_selection_license_bond())]268 pub fn set_collator_selection_license_bond(269 origin: OriginFor<T>,270 amount: Option<<T as Config>::Balance>,271 ) -> DispatchResult {272 ensure_root(origin)?;273 if let Some(amount) = amount {274 <CollatorSelectionLicenseBondOverride<T>>::set(amount);275 } else {276 <CollatorSelectionLicenseBondOverride<T>>::kill();277 }278 Self::deposit_event(Event::NewCollatorLicenseBond { bond_cost: amount });279 Ok(())280 }281282 #[pallet::call_index(6)]283 #[pallet::weight(T::WeightInfo::set_collator_selection_kick_threshold())]284 pub fn set_collator_selection_kick_threshold(285 origin: OriginFor<T>,286 threshold: Option<BlockNumberFor<T>>,287 ) -> DispatchResult {288 ensure_root(origin)?;289 if let Some(threshold) = threshold {290 <CollatorSelectionKickThresholdOverride<T>>::set(threshold);291 } else {292 <CollatorSelectionKickThresholdOverride<T>>::kill();293 }294 Self::deposit_event(Event::NewCollatorKickThreshold {295 length_in_blocks: threshold,296 });297 Ok(())298 }299 }300301 #[pallet::pallet]302 pub struct Pallet<T>(_);303}304305pub struct WeightToFee<T, B>(PhantomData<(T, B)>);306307impl<T, B> WeightToFeePolynomial for WeightToFee<T, B>308where309 T: Config,310 B: BaseArithmetic + From<u32> + From<u64> + Copy + Unsigned,311{312 type Balance = B;313314 fn polynomial() -> WeightToFeeCoefficients<Self::Balance> {315 smallvec!(WeightToFeeCoefficient {316 coeff_integer: (<WeightToFeeCoefficientOverride<T>>::get() / Perbill::ACCURACY as u64)317 .into(),318 coeff_frac: Perbill::from_parts(319 (<WeightToFeeCoefficientOverride<T>>::get() % Perbill::ACCURACY as u64) as u32320 ),321 negative: false,322 degree: 1,323 })324 }325}326327pub struct FeeCalculator<T>(PhantomData<T>);328impl<T: Config> fp_evm::FeeCalculator for FeeCalculator<T> {329 fn min_gas_price() -> (U256, Weight) {330 (331 <MinGasPriceOverride<T>>::get().into(),332 T::DbWeight::get().reads(1),333 )334 }335}336337#[derive(Encode, Decode, Clone, Debug, Default, TypeInfo, MaxEncodedLen, PartialEq, PartialOrd)]338pub struct AppPromotionConfiguration<BlockNumber> {339 340 pub recalculation_interval: Option<BlockNumber>,341 342 pub pending_interval: Option<BlockNumber>,343 344 pub interval_income: Option<Perbill>,345 346 pub max_stakers_per_calculation: Option<u8>,347}