1#![cfg(feature = "runtime-benchmarks")]
21
22use super::*;
23use crate::Pallet as Balances;
24
25use frame_benchmarking::v2::*;
26use frame_system::RawOrigin;
27use sp_runtime::traits::Bounded;
28use types::ExtraFlags;
29
30const SEED: u32 = 0;
31const ED_MULTIPLIER: u32 = 10;
33
34fn minimum_balance<T: Config<I>, I: 'static>() -> T::Balance {
35 if cfg!(feature = "insecure_zero_ed") {
36 100u32.into()
37 } else {
38 T::ExistentialDeposit::get()
39 }
40}
41
42#[instance_benchmarks]
43mod benchmarks {
44 use super::*;
45
46 #[benchmark]
50 fn transfer_allow_death() {
51 let existential_deposit: T::Balance = minimum_balance::<T, I>();
52 let caller = whitelisted_caller();
53
54 let balance = existential_deposit.saturating_mul(ED_MULTIPLIER.into()).max(1u32.into());
56 let _ = <Balances<T, I> as Currency<_>>::make_free_balance_be(&caller, balance);
57
58 let recipient: T::AccountId = account("recipient", 0, SEED);
61 let recipient_lookup = T::Lookup::unlookup(recipient.clone());
62 let transfer_amount =
63 existential_deposit.saturating_mul((ED_MULTIPLIER - 1).into()) + 1u32.into();
64
65 #[extrinsic_call]
66 _(RawOrigin::Signed(caller.clone()), recipient_lookup, transfer_amount);
67
68 if cfg!(feature = "insecure_zero_ed") {
69 assert_eq!(Balances::<T, I>::free_balance(&caller), balance - transfer_amount);
70 } else {
71 assert_eq!(Balances::<T, I>::free_balance(&caller), Zero::zero());
72 }
73
74 assert_eq!(Balances::<T, I>::free_balance(&recipient), transfer_amount);
75 }
76
77 #[benchmark(extra)]
80 fn transfer_best_case() {
81 let caller = whitelisted_caller();
82 let recipient: T::AccountId = account("recipient", 0, SEED);
83 let recipient_lookup = T::Lookup::unlookup(recipient.clone());
84
85 let _ =
88 <Balances<T, I> as Currency<_>>::make_free_balance_be(&caller, T::Balance::max_value());
89
90 let existential_deposit: T::Balance = minimum_balance::<T, I>();
92 let _ =
93 <Balances<T, I> as Currency<_>>::make_free_balance_be(&recipient, existential_deposit);
94 let transfer_amount = existential_deposit.saturating_mul(ED_MULTIPLIER.into());
95
96 #[extrinsic_call]
97 transfer_allow_death(RawOrigin::Signed(caller.clone()), recipient_lookup, transfer_amount);
98
99 assert!(!Balances::<T, I>::free_balance(&caller).is_zero());
100 assert!(!Balances::<T, I>::free_balance(&recipient).is_zero());
101 }
102
103 #[benchmark]
106 fn transfer_keep_alive() {
107 let caller = whitelisted_caller();
108 let recipient: T::AccountId = account("recipient", 0, SEED);
109 let recipient_lookup = T::Lookup::unlookup(recipient.clone());
110
111 let _ =
113 <Balances<T, I> as Currency<_>>::make_free_balance_be(&caller, T::Balance::max_value());
114 let existential_deposit: T::Balance = minimum_balance::<T, I>();
115 let transfer_amount = existential_deposit.saturating_mul(ED_MULTIPLIER.into());
116
117 #[extrinsic_call]
118 _(RawOrigin::Signed(caller.clone()), recipient_lookup, transfer_amount);
119
120 assert!(!Balances::<T, I>::free_balance(&caller).is_zero());
121 assert_eq!(Balances::<T, I>::free_balance(&recipient), transfer_amount);
122 }
123
124 #[benchmark]
126 fn force_set_balance_creating() {
127 let user: T::AccountId = account("user", 0, SEED);
128 let user_lookup = T::Lookup::unlookup(user.clone());
129
130 let existential_deposit: T::Balance = minimum_balance::<T, I>();
131 let balance_amount = existential_deposit.saturating_mul(ED_MULTIPLIER.into());
132
133 #[extrinsic_call]
134 force_set_balance(RawOrigin::Root, user_lookup, balance_amount);
135
136 assert_eq!(Balances::<T, I>::free_balance(&user), balance_amount);
137 }
138
139 #[benchmark]
141 fn force_set_balance_killing() {
142 let user: T::AccountId = account("user", 0, SEED);
143 let user_lookup = T::Lookup::unlookup(user.clone());
144
145 let existential_deposit: T::Balance = minimum_balance::<T, I>();
147 let balance_amount = existential_deposit.saturating_mul(ED_MULTIPLIER.into());
148 let _ = <Balances<T, I> as Currency<_>>::make_free_balance_be(&user, balance_amount);
149
150 #[extrinsic_call]
151 force_set_balance(RawOrigin::Root, user_lookup, Zero::zero());
152
153 assert!(Balances::<T, I>::free_balance(&user).is_zero());
154 }
155
156 #[benchmark]
160 fn force_transfer() {
161 let existential_deposit: T::Balance = minimum_balance::<T, I>();
162 let source: T::AccountId = account("source", 0, SEED);
163 let source_lookup = T::Lookup::unlookup(source.clone());
164
165 let balance = existential_deposit.saturating_mul(ED_MULTIPLIER.into());
167 let _ = <Balances<T, I> as Currency<_>>::make_free_balance_be(&source, balance);
168
169 let recipient: T::AccountId = account("recipient", 0, SEED);
172 let recipient_lookup = T::Lookup::unlookup(recipient.clone());
173 let transfer_amount =
174 existential_deposit.saturating_mul((ED_MULTIPLIER - 1).into()) + 1u32.into();
175
176 #[extrinsic_call]
177 _(RawOrigin::Root, source_lookup, recipient_lookup, transfer_amount);
178
179 if cfg!(feature = "insecure_zero_ed") {
180 assert_eq!(Balances::<T, I>::free_balance(&source), balance - transfer_amount);
181 } else {
182 assert_eq!(Balances::<T, I>::free_balance(&source), Zero::zero());
183 }
184
185 assert_eq!(Balances::<T, I>::free_balance(&recipient), transfer_amount);
186 }
187
188 #[benchmark(extra)]
192 fn transfer_increasing_users(u: Linear<0, 1_000>) {
193 let existential_deposit: T::Balance = minimum_balance::<T, I>();
195 let caller = whitelisted_caller();
196
197 let balance = existential_deposit.saturating_mul(ED_MULTIPLIER.into());
199 let _ = <Balances<T, I> as Currency<_>>::make_free_balance_be(&caller, balance);
200
201 let recipient: T::AccountId = account("recipient", 0, SEED);
204 let recipient_lookup = T::Lookup::unlookup(recipient.clone());
205 let transfer_amount =
206 existential_deposit.saturating_mul((ED_MULTIPLIER - 1).into()) + 1u32.into();
207
208 for i in 0..u {
210 let new_user: T::AccountId = account("new_user", i, SEED);
213 let _ = <Balances<T, I> as Currency<_>>::make_free_balance_be(&new_user, balance);
214 }
215
216 #[extrinsic_call]
217 transfer_allow_death(RawOrigin::Signed(caller.clone()), recipient_lookup, transfer_amount);
218
219 if cfg!(feature = "insecure_zero_ed") {
220 assert_eq!(Balances::<T, I>::free_balance(&caller), balance - transfer_amount);
221 } else {
222 assert_eq!(Balances::<T, I>::free_balance(&caller), Zero::zero());
223 }
224
225 assert_eq!(Balances::<T, I>::free_balance(&recipient), transfer_amount);
226 }
227
228 #[benchmark]
232 fn transfer_all() {
233 let caller = whitelisted_caller();
234 let recipient: T::AccountId = account("recipient", 0, SEED);
235 let recipient_lookup = T::Lookup::unlookup(recipient.clone());
236
237 let existential_deposit: T::Balance = minimum_balance::<T, I>();
239 let balance = existential_deposit.saturating_mul(ED_MULTIPLIER.into());
240 let _ = <Balances<T, I> as Currency<_>>::make_free_balance_be(&caller, balance);
241
242 #[extrinsic_call]
243 _(RawOrigin::Signed(caller.clone()), recipient_lookup, false);
244
245 assert!(Balances::<T, I>::free_balance(&caller).is_zero());
246 assert_eq!(Balances::<T, I>::free_balance(&recipient), balance);
247 }
248
249 #[benchmark]
250 fn force_unreserve() -> Result<(), BenchmarkError> {
251 let user: T::AccountId = account("user", 0, SEED);
252 let user_lookup = T::Lookup::unlookup(user.clone());
253
254 let ed = minimum_balance::<T, I>();
256 let balance = ed + ed;
257 let _ = <Balances<T, I> as Currency<_>>::make_free_balance_be(&user, balance);
258
259 <Balances<T, I> as ReservableCurrency<_>>::reserve(&user, ed)?;
261 assert_eq!(Balances::<T, I>::reserved_balance(&user), ed);
262 assert_eq!(Balances::<T, I>::free_balance(&user), ed);
263
264 #[extrinsic_call]
265 _(RawOrigin::Root, user_lookup, balance);
266
267 assert!(Balances::<T, I>::reserved_balance(&user).is_zero());
268 assert_eq!(Balances::<T, I>::free_balance(&user), ed + ed);
269
270 Ok(())
271 }
272
273 #[benchmark]
274 fn upgrade_accounts(u: Linear<1, 1_000>) {
275 let caller: T::AccountId = whitelisted_caller();
276 let who = (0..u)
277 .into_iter()
278 .map(|i| -> T::AccountId {
279 let user = account("old_user", i, SEED);
280 let account = AccountData {
281 free: minimum_balance::<T, I>(),
282 reserved: minimum_balance::<T, I>(),
283 frozen: Zero::zero(),
284 flags: ExtraFlags::old_logic(),
285 };
286 frame_system::Pallet::<T>::inc_providers(&user);
287 assert!(T::AccountStore::try_mutate_exists(&user, |a| -> DispatchResult {
288 *a = Some(account);
289 Ok(())
290 })
291 .is_ok());
292 assert!(!Balances::<T, I>::account(&user).flags.is_new_logic());
293 assert_eq!(frame_system::Pallet::<T>::providers(&user), 1);
294 assert_eq!(frame_system::Pallet::<T>::consumers(&user), 0);
295 user
296 })
297 .collect();
298
299 #[extrinsic_call]
300 _(RawOrigin::Signed(caller.clone()), who);
301
302 for i in 0..u {
303 let user: T::AccountId = account("old_user", i, SEED);
304 assert!(Balances::<T, I>::account(&user).flags.is_new_logic());
305 assert_eq!(frame_system::Pallet::<T>::providers(&user), 1);
306 assert_eq!(frame_system::Pallet::<T>::consumers(&user), 1);
307 }
308 }
309
310 #[benchmark]
311 fn force_adjust_total_issuance() {
312 let ti = TotalIssuance::<T, I>::get();
313 let delta = 123u32.into();
314
315 #[extrinsic_call]
316 _(RawOrigin::Root, AdjustmentDirection::Increase, delta);
317
318 assert_eq!(TotalIssuance::<T, I>::get(), ti + delta);
319 }
320
321 #[benchmark]
323 fn burn_allow_death() {
324 let existential_deposit: T::Balance = minimum_balance::<T, I>();
325 let caller = whitelisted_caller();
326
327 let balance = existential_deposit.saturating_mul(ED_MULTIPLIER.into());
329 let _ = <Balances<T, I> as Currency<_>>::make_free_balance_be(&caller, balance);
330
331 let burn_amount = balance - existential_deposit + 1u32.into();
333
334 #[extrinsic_call]
335 burn(RawOrigin::Signed(caller.clone()), burn_amount, false);
336
337 if cfg!(feature = "insecure_zero_ed") {
338 assert_eq!(Balances::<T, I>::free_balance(&caller), balance - burn_amount);
339 } else {
340 assert_eq!(Balances::<T, I>::free_balance(&caller), Zero::zero());
341 }
342 }
343
344 #[benchmark]
346 fn burn_keep_alive() {
347 let existential_deposit: T::Balance = minimum_balance::<T, I>();
348 let caller = whitelisted_caller();
349
350 let balance = existential_deposit.saturating_mul(ED_MULTIPLIER.into());
352 let _ = <Balances<T, I> as Currency<_>>::make_free_balance_be(&caller, balance);
353
354 let burn_amount = 1u32.into();
356
357 #[extrinsic_call]
358 burn(RawOrigin::Signed(caller.clone()), burn_amount, true);
359
360 assert_eq!(Balances::<T, I>::free_balance(&caller), balance - burn_amount);
361 }
362
363 impl_benchmark_test_suite! {
364 Balances,
365 crate::tests::ExtBuilder::default().build(),
366 crate::tests::Test,
367 }
368}