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