pallet_feeless/
extensions.rs1use crate::types::RateLimiter;
27use codec::{Decode, DecodeWithMemTracking, Encode};
28use core::marker::PhantomData;
29use frame_support::pallet_prelude::InvalidTransaction::ExhaustsResources;
30use scale_info::TypeInfo;
31use sp_runtime::{
32 impl_tx_ext_default,
33 traits::{DispatchInfoOf, Dispatchable, PostDispatchInfoOf, TransactionExtension},
34 transaction_validity::{TransactionSource, TransactionValidityError, ValidTransaction},
35 DispatchResult, Weight,
36};
37
38#[derive(Encode, Decode, DecodeWithMemTracking, Clone, Eq, PartialEq, TypeInfo)]
40#[scale_info(skip_type_params(T))]
41pub struct CheckRate<T: frame_system::Config + Send + Sync>(PhantomData<T>);
42
43impl<T: frame_system::Config + Send + Sync> core::fmt::Debug for CheckRate<T> {
44 #[cfg(feature = "std")]
45 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
46 write!(f, "CheckRate")
47 }
48
49 #[cfg(not(feature = "std"))]
50 fn fmt(&self, _: &mut core::fmt::Formatter) -> core::fmt::Result {
51 Ok(())
52 }
53}
54
55pub struct Pre<T: frame_system::Config> {
56 who: Option<T::AccountId>,
57}
58
59impl<T: frame_system::Config> core::fmt::Debug for Pre<T> {
60 #[cfg(feature = "std")]
61 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
62 write!(f, "who: {:?}", self.who)
63 }
64
65 #[cfg(not(feature = "std"))]
66 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
67 f.write_str("<wasm:stripped>")
68 }
69}
70
71impl<T: frame_system::Config + Send + Sync> Default for CheckRate<T> {
72 fn default() -> Self {
73 Self::new()
74 }
75}
76
77impl<T: frame_system::Config + Send + Sync> CheckRate<T> {
78 pub fn new() -> Self {
79 Self(PhantomData)
80 }
81}
82
83impl<T> TransactionExtension<T::RuntimeCall> for CheckRate<T>
84where
85 T: frame_system::Config + Send + Sync,
86 T::AccountData: RateLimiter<T>,
87{
88 type Implicit = ();
89 type Pre = Pre<T>;
90 type Val = Pre<T>;
91
92 const IDENTIFIER: &'static str = "CheckRate";
93
94 impl_tx_ext_default!(T::RuntimeCall; weight);
95
96 fn validate(
98 &self,
99 origin: <T::RuntimeCall as Dispatchable>::RuntimeOrigin,
100 _call: &T::RuntimeCall,
101 _info: &DispatchInfoOf<T::RuntimeCall>,
102 len: usize,
103 _: (),
104 _implication: &impl Encode,
105 _source: TransactionSource,
106 ) -> Result<
107 (
108 ValidTransaction,
109 Self::Val,
110 <T::RuntimeCall as Dispatchable>::RuntimeOrigin,
111 ),
112 TransactionValidityError,
113 > {
114 let Ok(who) = frame_system::ensure_signed(origin.clone()) else {
115 return Ok((Default::default(), Pre { who: None }, origin));
116 };
117
118 let account_data = frame_system::Account::<T>::get(who.clone()).data;
119 let block = frame_system::Pallet::<T>::block_number();
120 if account_data.is_allowed(block, len as u32) {
121 Ok((
122 Default::default(),
123 Pre {
124 who: Some(who.clone()),
125 },
126 origin,
127 ))
128 } else {
129 Err(TransactionValidityError::Invalid(ExhaustsResources))
130 }
131 }
132
133 fn prepare(
135 self,
136 val: Self::Val,
137 _origin: &<T::RuntimeCall as Dispatchable>::RuntimeOrigin,
138 _call: &T::RuntimeCall,
139 _info: &DispatchInfoOf<T::RuntimeCall>,
140 _len: usize,
141 ) -> Result<Self::Pre, TransactionValidityError> {
142 Ok(val)
143 }
144
145 fn post_dispatch_details(
147 pre: Self::Pre,
148 _info: &DispatchInfoOf<T::RuntimeCall>,
149 _post_info: &PostDispatchInfoOf<T::RuntimeCall>,
150 len: usize,
151 _result: &DispatchResult,
152 ) -> Result<Weight, TransactionValidityError> {
153 if let Some(who) = pre.who {
154 let mut account_data = frame_system::Account::<T>::get(who.clone()).data;
155 let block = frame_system::Pallet::<T>::block_number();
156 account_data.update_rate(block, len as u32);
157 frame_system::Account::<T>::mutate(who, |account| account.data = account_data);
158 }
159 Ok(Weight::zero())
160 }
161}