1#![cfg_attr(not(feature = "std"), no_std)]
17
18use frame_support::dispatch::{DispatchInfo, PostDispatchInfo};
19use frame_support::traits::Get;
20use frame_system::limits::BlockWeights;
21use frame_system::{Config, ConsumedWeight};
22use parity_scale_codec::{Decode, Encode};
23use scale_info::TypeInfo;
24use sp_runtime::DispatchResult;
25use sp_runtime::traits::{
26 DispatchInfoOf, DispatchOriginOf, Dispatchable, PostDispatchInfoOf, TransactionExtension,
27 ValidateResult,
28};
29use sp_runtime::transaction_validity::{
30 TransactionSource, TransactionValidity, TransactionValidityError,
31};
32use sp_weights::Weight;
33
34#[derive(Encode, Decode, Clone, Eq, PartialEq, Default, TypeInfo)]
40#[scale_info(skip_type_params(T))]
41pub struct CheckWeight<T: Config + Send + Sync>(core::marker::PhantomData<T>);
42
43impl<T: Config + Send + Sync> CheckWeight<T>
44where
45 T::RuntimeCall: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo>,
46{
47 pub fn new() -> Self {
49 Self(Default::default())
50 }
51
52 pub fn do_prepare(
57 info: &DispatchInfoOf<T::RuntimeCall>,
58 len: usize,
59 next_len: u32,
60 ) -> Result<(), TransactionValidityError> {
61 let all_weight = frame_system::Pallet::<T>::block_weight();
62 let maximum_weight = T::BlockWeights::get();
63 let next_weight =
64 calculate_consumed_weight::<T::RuntimeCall>(&maximum_weight, all_weight, info, len);
65
66 frame_system::AllExtrinsicsLen::<T>::put(next_len);
67 frame_system::BlockWeight::<T>::put(next_weight);
68
69 Ok(())
70 }
71}
72
73fn calculate_consumed_weight<Call>(
75 maximum_weight: &BlockWeights,
76 mut all_weight: ConsumedWeight,
77 info: &DispatchInfoOf<Call>,
78 len: usize,
79) -> ConsumedWeight
80where
81 Call: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo>,
82{
83 let extrinsic_weight = info
85 .total_weight()
86 .saturating_add(maximum_weight.get(info.class).base_extrinsic)
87 .saturating_add(Weight::from_parts(0, len as u64));
88
89 all_weight.accrue(extrinsic_weight, info.class);
91
92 all_weight
93}
94
95impl<T: Config + Send + Sync> TransactionExtension<T::RuntimeCall> for CheckWeight<T>
96where
97 T::RuntimeCall: Dispatchable<Info = DispatchInfo, PostInfo = PostDispatchInfo>,
98{
99 type Implicit = ();
100 type Pre = ();
101 type Val = u32;
102 const IDENTIFIER: &'static str = "CheckWeight";
103
104 fn weight(&self, _: &T::RuntimeCall) -> Weight {
105 <T::ExtensionsWeightInfo as frame_system::ExtensionsWeightInfo>::check_weight()
108 }
109
110 fn validate(
111 &self,
112 origin: T::RuntimeOrigin,
113 _call: &T::RuntimeCall,
114 info: &DispatchInfoOf<T::RuntimeCall>,
115 len: usize,
116 _self_implicit: Self::Implicit,
117 _inherited_implication: &impl Encode,
118 _source: TransactionSource,
119 ) -> ValidateResult<Self::Val, T::RuntimeCall> {
120 let (validity, next_len) = frame_system::CheckWeight::<T>::do_validate(info, len)?;
121 Ok((validity, next_len, origin))
122 }
123
124 fn prepare(
125 self,
126 val: Self::Val,
127 _origin: &DispatchOriginOf<T::RuntimeCall>,
128 _call: &T::RuntimeCall,
129 info: &DispatchInfoOf<T::RuntimeCall>,
130 len: usize,
131 ) -> Result<Self::Pre, TransactionValidityError> {
132 Self::do_prepare(info, len, val)
133 }
134
135 fn post_dispatch_details(
136 _pre: Self::Pre,
137 info: &DispatchInfoOf<T::RuntimeCall>,
138 post_info: &PostDispatchInfoOf<T::RuntimeCall>,
139 _len: usize,
140 _result: &DispatchResult,
141 ) -> Result<Weight, TransactionValidityError> {
142 frame_system::CheckWeight::<T>::do_post_dispatch(info, post_info)?;
143 Ok(Weight::zero())
144 }
145
146 fn bare_validate(
147 _call: &T::RuntimeCall,
148 info: &DispatchInfoOf<T::RuntimeCall>,
149 len: usize,
150 ) -> TransactionValidity {
151 Ok(frame_system::CheckWeight::<T>::do_validate(info, len)?.0)
152 }
153
154 fn bare_validate_and_prepare(
155 _call: &T::RuntimeCall,
156 info: &DispatchInfoOf<T::RuntimeCall>,
157 len: usize,
158 ) -> Result<(), TransactionValidityError> {
159 let (_, next_len) = frame_system::CheckWeight::<T>::do_validate(info, len)?;
160 Self::do_prepare(info, len, next_len)
161 }
162
163 fn bare_post_dispatch(
164 info: &DispatchInfoOf<T::RuntimeCall>,
165 post_info: &mut PostDispatchInfoOf<T::RuntimeCall>,
166 _len: usize,
167 _result: &DispatchResult,
168 ) -> Result<(), TransactionValidityError> {
169 frame_system::CheckWeight::<T>::do_post_dispatch(info, post_info)
170 }
171}
172
173impl<T: Config + Send + Sync> core::fmt::Debug for CheckWeight<T> {
174 #[cfg(feature = "std")]
175 fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
176 write!(f, "CheckWeight")
177 }
178
179 #[cfg(not(feature = "std"))]
180 fn fmt(&self, _: &mut core::fmt::Formatter) -> core::fmt::Result {
181 Ok(())
182 }
183}