pallet_block_producer_fees/
lib.rs1#![cfg_attr(not(feature = "std"), no_std)]
15#![deny(missing_docs)]
16
17pub mod benchmarking;
18
19#[cfg(test)]
20mod mock;
21#[cfg(test)]
22mod tests;
23pub mod weights;
24
25pub use pallet::*;
26pub use weights::WeightInfo;
27
28#[frame_support::pallet]
29pub mod pallet {
30 use super::*;
31 use frame_support::pallet_prelude::*;
32 use frame_system::pallet_prelude::*;
33 use sp_block_producer_fees::PerTenThousands;
34 use sp_consensus_slots::Slot;
35 use sp_std::collections::vec_deque::VecDeque;
36
37 pub const PALLET_VERSION: u32 = 1;
39
40 #[pallet::pallet]
41 pub struct Pallet<T>(_);
42
43 #[pallet::config]
44 pub trait Config: frame_system::Config {
45 #[pallet::constant]
47 type HistoricalChangesPerProducer: Get<u16>;
48
49 type WeightInfo: WeightInfo;
51
52 fn current_slot() -> Slot;
54
55 #[cfg(feature = "runtime-benchmarks")]
56 type BenchmarkHelper: benchmarking::BenchmarkHelper<Self::AccountId>;
58 }
59
60 type FeeChange = (Slot, PerTenThousands);
61
62 #[pallet::storage]
64 #[pallet::unbounded]
65 pub type FeesChanges<T: Config> = StorageMap<
66 Hasher = Twox64Concat,
67 Key = T::AccountId,
68 Value = VecDeque<FeeChange>,
69 QueryKind = ValueQuery,
70 >;
71
72 #[pallet::call]
73 impl<T: Config> Pallet<T> {
74 #[pallet::call_index(0)]
76 #[pallet::weight((T::WeightInfo::set_fee(), DispatchClass::Normal))]
77 pub fn set_fee(origin: OriginFor<T>, fee_numerator: PerTenThousands) -> DispatchResult {
78 let account_id = ensure_signed(origin)?;
79 if fee_numerator > 10000 {
80 return Err(DispatchError::Other("fee numerator must be in range from 0 to 10000"));
81 }
82 FeesChanges::<T>::mutate(account_id, |fees_log| {
83 if fees_log.len() > T::HistoricalChangesPerProducer::get().into() {
84 let _ = fees_log.pop_back();
85 }
86 fees_log.push_front((T::current_slot(), fee_numerator));
87 });
88 Ok(())
89 }
90 }
91
92 impl<T: Config> Pallet<T> {
93 pub fn get_version() -> u32 {
95 PALLET_VERSION
96 }
97
98 pub fn get_all() -> impl Iterator<Item = (T::AccountId, VecDeque<FeeChange>)> {
100 FeesChanges::<T>::iter()
101 }
102
103 pub fn get_all_latest() -> impl Iterator<Item = (T::AccountId, FeeChange)> {
105 Self::get_all().map(|(account_id, changes)| {
106 (account_id, *changes.front().expect("There are no empty collections in storage"))
107 })
108 }
109
110 pub fn get(id: T::AccountId) -> VecDeque<FeeChange> {
113 FeesChanges::<T>::get(id)
114 }
115
116 pub fn get_latest(id: T::AccountId) -> Option<FeeChange> {
118 FeesChanges::<T>::get(id).front().cloned()
119 }
120 }
121}