1#![cfg_attr(not(feature = "std"), no_std)]
19
20#[cfg(not(feature = "std"))]
21extern crate alloc;
22
23pub mod fees;
24
25pub use pallet::*;
26
27#[frame_support::pallet]
28mod pallet {
29 #[cfg(not(feature = "std"))]
30 use alloc::vec::Vec;
31 use frame_support::pallet_prelude::*;
32 use frame_support::storage::generator::StorageValue as _;
33 use frame_system::pallet_prelude::*;
34 use parity_scale_codec::{Codec, MaxEncodedLen};
35 use scale_info::TypeInfo;
36 use sp_block_fees::{INHERENT_IDENTIFIER, InherentError, InherentType};
37 use sp_domains::{BlockFees, ChainId};
38 use sp_runtime::traits::{AtLeast32BitUnsigned, MaybeSerializeDeserialize, Saturating};
39 use sp_runtime::{FixedPointOperand, SaturatedConversion};
40 use sp_std::fmt::Debug;
41 use sp_std::result;
42
43 #[pallet::config]
44 pub trait Config: frame_system::Config {
45 type Balance: Parameter
47 + Member
48 + AtLeast32BitUnsigned
49 + Codec
50 + Default
51 + Copy
52 + MaybeSerializeDeserialize
53 + Debug
54 + MaxEncodedLen
55 + TypeInfo
56 + FixedPointOperand;
57
58 type DomainChainByteFee: Get<Self::Balance>;
60 }
61
62 #[pallet::storage]
67 #[pallet::getter(fn collected_block_fees)]
68 pub(super) type CollectedBlockFees<T: Config> =
69 StorageValue<_, BlockFees<T::Balance>, ValueQuery>;
70
71 #[pallet::storage]
76 #[pallet::getter(fn consensus_chain_byte_fee)]
77 pub(super) type ConsensusChainByteFee<T: Config> = StorageValue<_, T::Balance, ValueQuery>;
78
79 #[pallet::storage]
83 pub(super) type NextConsensusChainByteFee<T: Config> = StorageValue<_, T::Balance, ValueQuery>;
84
85 #[pallet::pallet]
87 #[pallet::without_storage_info]
88 pub struct Pallet<T>(_);
89
90 #[pallet::hooks]
91 impl<T: Config> Hooks<BlockNumberFor<T>> for Pallet<T> {
92 fn on_initialize(_now: BlockNumberFor<T>) -> Weight {
93 CollectedBlockFees::<T>::set(BlockFees::<T::Balance>::default());
97 T::DbWeight::get().writes(1)
98 }
99
100 fn on_finalize(_now: BlockNumberFor<T>) {
101 let transaction_byte_fee = NextConsensusChainByteFee::<T>::take();
102 ConsensusChainByteFee::<T>::put(transaction_byte_fee);
103 }
104 }
105
106 #[pallet::call]
107 impl<T: Config> Pallet<T> {
108 #[pallet::call_index(0)]
109 #[pallet::weight((
110 Weight::from_all(10_000).saturating_add(
116 T::DbWeight::get().writes(1)
117 ),
118 DispatchClass::Mandatory
119 ))]
120 pub fn set_next_consensus_chain_byte_fee(
121 origin: OriginFor<T>,
122 #[pallet::compact] transaction_byte_fee: T::Balance,
123 ) -> DispatchResult {
124 ensure_none(origin)?;
125 NextConsensusChainByteFee::<T>::put(transaction_byte_fee);
126 Ok(())
127 }
128 }
129
130 #[pallet::inherent]
131 impl<T: Config> ProvideInherent for Pallet<T> {
132 type Call = Call<T>;
133 type Error = InherentError;
134 const INHERENT_IDENTIFIER: InherentIdentifier = INHERENT_IDENTIFIER;
135
136 fn create_inherent(data: &InherentData) -> Option<Self::Call> {
137 let inherent_data = data
138 .get_data::<InherentType>(&INHERENT_IDENTIFIER)
139 .expect("Domain block fees inherent data not correctly encoded")
140 .expect("Domain block fees inherent data must be provided");
141
142 let transaction_byte_fee = inherent_data.saturated_into::<T::Balance>();
143
144 Some(Call::set_next_consensus_chain_byte_fee {
145 transaction_byte_fee,
146 })
147 }
148
149 fn check_inherent(
150 call: &Self::Call,
151 data: &InherentData,
152 ) -> result::Result<(), Self::Error> {
153 let inherent_data = data
154 .get_data::<InherentType>(&INHERENT_IDENTIFIER)
155 .expect("Domain block fees inherent data not correctly encoded")
156 .expect("Domain block fees inherent data must be provided");
157
158 let provided_transaction_byte_fee = inherent_data.saturated_into::<T::Balance>();
159
160 if let Call::set_next_consensus_chain_byte_fee {
161 transaction_byte_fee,
162 } = call
163 && transaction_byte_fee != &provided_transaction_byte_fee
164 {
165 return Err(InherentError::IncorrectConsensusChainByteFee);
166 }
167
168 Ok(())
169 }
170
171 fn is_inherent(call: &Self::Call) -> bool {
172 matches!(call, Call::set_next_consensus_chain_byte_fee { .. })
173 }
174 }
175
176 impl<T: Config> Pallet<T> {
177 pub fn note_domain_execution_fee(rewards: T::Balance) {
180 CollectedBlockFees::<T>::mutate(|block_fees| {
181 block_fees.domain_execution_fee =
182 block_fees.domain_execution_fee.saturating_add(rewards);
183 });
184 }
185
186 pub fn note_consensus_storage_fee(storage_fee: T::Balance) {
188 CollectedBlockFees::<T>::mutate(|block_fees| {
189 block_fees.consensus_storage_fee =
190 block_fees.consensus_storage_fee.saturating_add(storage_fee);
191 });
192 }
193
194 pub fn note_burned_balance(burned_balance: T::Balance) {
196 CollectedBlockFees::<T>::mutate(|block_fees| {
197 block_fees.burned_balance =
198 block_fees.burned_balance.saturating_add(burned_balance);
199 });
200 }
201
202 pub fn note_chain_rewards(chain_id: ChainId, balance: T::Balance) {
204 CollectedBlockFees::<T>::mutate(|block_fees| {
205 let total_balance = match block_fees.chain_rewards.get(&chain_id) {
206 None => balance,
207 Some(prev_balance) => prev_balance.saturating_add(balance),
208 };
209 block_fees.chain_rewards.insert(chain_id, total_balance)
210 });
211 }
212
213 pub fn final_domain_transaction_byte_fee() -> T::Balance {
219 ConsensusChainByteFee::<T>::get().saturating_add(T::DomainChainByteFee::get())
220 }
221
222 pub fn block_fees_storage_key() -> Vec<u8> {
223 CollectedBlockFees::<T>::storage_value_final_key().to_vec()
224 }
225 }
226}