pallet_transaction_fees/
lib.rs1#![cfg_attr(not(feature = "std"), no_std)]
4#![forbid(unsafe_code)]
5#![warn(rust_2018_idioms, missing_debug_implementations)]
6
7pub mod weights;
8
9use frame_support::sp_runtime::SaturatedConversion;
10use frame_support::sp_runtime::traits::Zero;
11use frame_support::traits::{Currency, Get};
12use frame_support::weights::Weight;
13use frame_system::pallet_prelude::*;
14pub use pallet::*;
15use parity_scale_codec::{Codec, Decode, Encode};
16use scale_info::TypeInfo;
17use subspace_runtime_primitives::FindBlockRewardAddress;
18
19type BalanceOf<T> =
20 <<T as Config>::Currency as Currency<<T as frame_system::Config>::AccountId>>::Balance;
21
22pub trait WeightInfo {
23 fn on_initialize() -> Weight;
24}
25
26#[derive(Encode, Decode, TypeInfo)]
27struct CollectedFees<Balance: Codec> {
28 storage: Balance,
29 compute: Balance,
30 tips: Balance,
31}
32
33#[frame_support::pallet]
34mod pallet {
35 use super::{BalanceOf, CollectedFees, WeightInfo};
36 use frame_support::pallet_prelude::*;
37 use frame_support::traits::Currency;
38 use frame_system::pallet_prelude::*;
39 use subspace_runtime_primitives::{BlockTransactionByteFee, FindBlockRewardAddress};
40
41 #[pallet::config]
42 pub trait Config: frame_system::Config<RuntimeEvent: From<Event<Self>>> {
43 #[pallet::constant]
46 type MinReplicationFactor: Get<u16>;
47
48 #[pallet::constant]
50 type CreditSupply: Get<BalanceOf<Self>>;
51
52 #[pallet::constant]
54 type TotalSpacePledged: Get<u128>;
55
56 #[pallet::constant]
59 type BlockchainHistorySize: Get<u128>;
60
61 type Currency: Currency<Self::AccountId>;
62
63 type FindBlockRewardAddress: FindBlockRewardAddress<Self::AccountId>;
64
65 type DynamicCostOfStorage: Get<bool>;
67
68 type WeightInfo: WeightInfo;
69 }
70
71 #[pallet::storage]
81 pub(super) type TransactionByteFee<T> =
82 StorageValue<_, BlockTransactionByteFee<BalanceOf<T>>, ValueQuery>;
83
84 #[pallet::storage]
87 pub(super) type IsDuringBlockExecution<T: Config> = StorageValue<_, bool, ValueQuery>;
88
89 #[pallet::storage]
92 pub(super) type BlockAuthor<T: Config> = StorageValue<_, T::AccountId>;
93
94 #[pallet::storage]
97 pub(super) type CollectedBlockFees<T: Config> = StorageValue<_, CollectedFees<BalanceOf<T>>>;
98
99 #[pallet::pallet]
101 #[pallet::without_storage_info]
102 pub struct Pallet<T>(_);
103
104 #[pallet::event]
106 #[pallet::generate_deposit(pub(super) fn deposit_event)]
107 pub enum Event<T: Config> {
108 #[codec(index = 0)]
110 BlockFees {
111 who: T::AccountId,
113 storage: BalanceOf<T>,
115 compute: BalanceOf<T>,
117 tips: BalanceOf<T>,
119 },
120 #[codec(index = 1)]
122 BurnedBlockFees {
123 storage: BalanceOf<T>,
125 compute: BalanceOf<T>,
127 tips: BalanceOf<T>,
129 },
130 }
131
132 #[pallet::hooks]
133 impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T>
134 where
135 BalanceOf<T>: From<u8> + From<u64>,
136 {
137 fn on_initialize(now: BlockNumberFor<T>) -> Weight {
138 Self::do_initialize(now);
139 T::WeightInfo::on_initialize()
140 }
141
142 fn on_finalize(now: BlockNumberFor<T>) {
143 Self::do_finalize(now);
144 }
145 }
146}
147
148impl<T: Config> Pallet<T>
149where
150 BalanceOf<T>: From<u64>,
151{
152 fn do_initialize(_n: BlockNumberFor<T>) {
153 if let Some(block_author) = T::FindBlockRewardAddress::find_block_reward_address() {
155 BlockAuthor::<T>::put(block_author);
156 }
157
158 CollectedBlockFees::<T>::put(CollectedFees {
159 storage: BalanceOf::<T>::zero(),
160 compute: BalanceOf::<T>::zero(),
161 tips: BalanceOf::<T>::zero(),
162 });
163
164 TransactionByteFee::<T>::mutate(|transaction_byte_fee| {
166 transaction_byte_fee.current = transaction_byte_fee.next
167 });
168 IsDuringBlockExecution::<T>::set(true);
169 }
170
171 fn do_finalize(_n: BlockNumberFor<T>) {
172 TransactionByteFee::<T>::mutate(|transaction_byte_fee| {
174 transaction_byte_fee.next = Self::calculate_transaction_byte_fee()
175 });
176 IsDuringBlockExecution::<T>::take();
177
178 let collected_fees = CollectedBlockFees::<T>::take()
179 .expect("`CollectedBlockFees` was set in `on_initialize`; qed");
180
181 let total = collected_fees.storage + collected_fees.compute + collected_fees.tips;
182
183 if !total.is_zero() {
184 if let Some(block_author) = BlockAuthor::<T>::take() {
186 let _imbalance = T::Currency::deposit_creating(&block_author, total);
187 Self::deposit_event(Event::<T>::BlockFees {
188 who: block_author.clone(),
189 storage: collected_fees.storage,
190 compute: collected_fees.compute,
191 tips: collected_fees.tips,
192 });
193 } else {
194 let amount = collected_fees.storage + collected_fees.compute + collected_fees.tips;
196 if !amount.is_zero() {
197 Self::deposit_event(Event::<T>::BurnedBlockFees {
198 storage: collected_fees.storage,
199 compute: collected_fees.compute,
200 tips: collected_fees.tips,
201 });
202 }
203 }
204 }
205 }
206
207 pub fn transaction_byte_fee() -> BalanceOf<T> {
211 if !T::DynamicCostOfStorage::get() {
212 return BalanceOf::<T>::from(1);
213 }
214
215 if IsDuringBlockExecution::<T>::get() {
216 TransactionByteFee::<T>::get().current
217 } else {
218 TransactionByteFee::<T>::get().next
219 }
220 }
221
222 pub fn calculate_transaction_byte_fee() -> BalanceOf<T> {
223 let credit_supply = T::CreditSupply::get();
224
225 match (T::TotalSpacePledged::get() / u128::from(T::MinReplicationFactor::get()))
226 .checked_sub(T::BlockchainHistorySize::get())
227 {
228 Some(free_space) if free_space > 0 => {
229 credit_supply / BalanceOf::<T>::saturated_from(free_space)
230 }
231 _ => credit_supply,
232 }
233 }
234
235 pub fn note_transaction_fees(
236 storage_fee: BalanceOf<T>,
237 compute_fee: BalanceOf<T>,
238 tip: BalanceOf<T>,
239 ) {
240 CollectedBlockFees::<T>::mutate(|collected_block_fees| {
241 if let Some(collected_block_fees) = collected_block_fees.as_mut() {
244 collected_block_fees.storage += storage_fee;
245 collected_block_fees.compute += compute_fee;
246 collected_block_fees.tips += tip;
247 }
248 });
249 }
250}
251
252impl<T: Config> subspace_runtime_primitives::StorageFee<BalanceOf<T>> for Pallet<T>
253where
254 BalanceOf<T>: From<u64>,
255{
256 fn transaction_byte_fee() -> BalanceOf<T> {
257 Self::transaction_byte_fee()
258 }
259
260 fn note_storage_fees(storage_fee: BalanceOf<T>) {
261 Self::note_transaction_fees(storage_fee, Zero::zero(), Zero::zero())
262 }
263}