polkadot_runtime_common/claims/
benchmarking.rs1#[cfg(feature = "runtime-benchmarks")]
20use super::*;
21use crate::claims::Call;
22use frame_benchmarking::v2::*;
23use frame_support::{
24 dispatch::{DispatchInfo, GetDispatchInfo},
25 traits::{Currency, UnfilteredDispatchable},
26};
27use frame_system::RawOrigin;
28use secp_utils::*;
29use sp_runtime::{traits::DispatchTransaction, DispatchResult};
30
31const SEED: u32 = 0;
32
33const MAX_CLAIMS: u32 = 10_000;
34const MIN_VALUE: u32 = 1_000_000;
35
36fn bench_claim_value<T: Config>() -> BalanceOf<T> {
42 CurrencyOf::<T>::minimum_balance().max(MIN_VALUE.into())
43}
44
45fn create_claim<T: Config>(input: u32) -> DispatchResult {
46 let secret_key = libsecp256k1::SecretKey::parse(&keccak_256(&input.encode())).unwrap();
47 let eth_address = eth(&secret_key);
48 let vesting = Some((100_000u32.into(), 1_000u32.into(), 100u32.into()));
49 super::Pallet::<T>::mint_claim(
50 RawOrigin::Root.into(),
51 eth_address,
52 bench_claim_value::<T>(),
53 vesting,
54 None,
55 )?;
56 Ok(())
57}
58
59fn create_claim_attest<T: Config>(input: u32) -> DispatchResult {
60 let secret_key = libsecp256k1::SecretKey::parse(&keccak_256(&input.encode())).unwrap();
61 let eth_address = eth(&secret_key);
62 let vesting = Some((100_000u32.into(), 1_000u32.into(), 100u32.into()));
63 super::Pallet::<T>::mint_claim(
64 RawOrigin::Root.into(),
65 eth_address,
66 bench_claim_value::<T>(),
67 vesting,
68 Some(Default::default()),
69 )?;
70 Ok(())
71}
72
73#[benchmarks(
74 where
75 <T as frame_system::Config>::RuntimeCall: IsSubType<Call<T>> + From<Call<T>>,
76 <T as frame_system::Config>::RuntimeCall: Dispatchable<Info = DispatchInfo> + GetDispatchInfo,
77 <<T as frame_system::Config>::RuntimeCall as Dispatchable>::RuntimeOrigin: AsSystemOriginSigner<T::AccountId> + AsTransactionAuthorizedOrigin + Clone,
78 <<T as frame_system::Config>::RuntimeCall as Dispatchable>::PostInfo: Default,
79 )]
80mod benchmarks {
81 use super::*;
82
83 #[allow(deprecated)]
84 use sp_runtime::traits::ValidateUnsigned;
85
86 #[benchmark]
88 fn claim() -> Result<(), BenchmarkError> {
89 let c = MAX_CLAIMS;
90 for _ in 0..c / 2 {
91 create_claim::<T>(c)?;
92 create_claim_attest::<T>(u32::MAX - c)?;
93 }
94 let secret_key = libsecp256k1::SecretKey::parse(&keccak_256(&c.encode())).unwrap();
95 let eth_address = eth(&secret_key);
96 let account: T::AccountId = account("user", c, SEED);
97 let vesting = Some((100_000u32.into(), 1_000u32.into(), 100u32.into()));
98 let signature = sig::<T>(&secret_key, &account.encode(), &[][..]);
99 super::Pallet::<T>::mint_claim(
100 RawOrigin::Root.into(),
101 eth_address,
102 bench_claim_value::<T>(),
103 vesting,
104 None,
105 )?;
106 assert_eq!(Claims::<T>::get(eth_address), Some(bench_claim_value::<T>()));
107 let source = sp_runtime::transaction_validity::TransactionSource::External;
108 let call_enc =
109 Call::<T>::claim { dest: account.clone(), ethereum_signature: signature.clone() }
110 .encode();
111
112 #[block]
113 {
114 let call = <Call<T> as Decode>::decode(&mut &*call_enc)
115 .expect("call is encoded above, encoding must be correct");
116 #[allow(deprecated)]
117 super::Pallet::<T>::validate_unsigned(source, &call)
118 .map_err(|e| -> &'static str { e.into() })?;
119 call.dispatch_bypass_filter(RawOrigin::None.into())?;
120 }
121
122 assert_eq!(Claims::<T>::get(eth_address), None);
123 Ok(())
124 }
125
126 #[benchmark]
128 fn mint_claim() -> Result<(), BenchmarkError> {
129 let c = MAX_CLAIMS;
130 for _ in 0..c / 2 {
131 create_claim::<T>(c)?;
132 create_claim_attest::<T>(u32::MAX - c)?;
133 }
134 let eth_address = account("eth_address", 0, SEED);
135 let vesting = Some((100_000u32.into(), 1_000u32.into(), 100u32.into()));
136 let statement = StatementKind::Regular;
137
138 #[extrinsic_call]
139 _(RawOrigin::Root, eth_address, bench_claim_value::<T>(), vesting, Some(statement));
140
141 assert_eq!(Claims::<T>::get(eth_address), Some(bench_claim_value::<T>()));
142 Ok(())
143 }
144
145 #[benchmark]
147 fn claim_attest() -> Result<(), BenchmarkError> {
148 let c = MAX_CLAIMS;
149 for _ in 0..c / 2 {
150 create_claim::<T>(c)?;
151 create_claim_attest::<T>(u32::MAX - c)?;
152 }
153 let attest_c = u32::MAX - c;
155 let secret_key = libsecp256k1::SecretKey::parse(&keccak_256(&attest_c.encode())).unwrap();
156 let eth_address = eth(&secret_key);
157 let account: T::AccountId = account("user", c, SEED);
158 let vesting = Some((100_000u32.into(), 1_000u32.into(), 100u32.into()));
159 let statement = StatementKind::Regular;
160 let signature = sig::<T>(&secret_key, &account.encode(), statement.to_text());
161 super::Pallet::<T>::mint_claim(
162 RawOrigin::Root.into(),
163 eth_address,
164 bench_claim_value::<T>(),
165 vesting,
166 Some(statement),
167 )?;
168 assert_eq!(Claims::<T>::get(eth_address), Some(bench_claim_value::<T>()));
169 let call_enc = Call::<T>::claim_attest {
170 dest: account.clone(),
171 ethereum_signature: signature.clone(),
172 statement: StatementKind::Regular.to_text().to_vec(),
173 }
174 .encode();
175 let source = sp_runtime::transaction_validity::TransactionSource::External;
176
177 #[block]
178 {
179 let call = <Call<T> as Decode>::decode(&mut &*call_enc)
180 .expect("call is encoded above, encoding must be correct");
181 #[allow(deprecated)]
182 super::Pallet::<T>::validate_unsigned(source, &call)
183 .map_err(|e| -> &'static str { e.into() })?;
184 call.dispatch_bypass_filter(RawOrigin::None.into())?;
185 }
186
187 assert_eq!(Claims::<T>::get(eth_address), None);
188 Ok(())
189 }
190
191 #[benchmark]
193 fn attest() -> Result<(), BenchmarkError> {
194 let c = MAX_CLAIMS;
195 for _ in 0..c / 2 {
196 create_claim::<T>(c)?;
197 create_claim_attest::<T>(u32::MAX - c)?;
198 }
199 let attest_c = u32::MAX - c;
200 let secret_key = libsecp256k1::SecretKey::parse(&keccak_256(&attest_c.encode())).unwrap();
201 let eth_address = eth(&secret_key);
202 let account: T::AccountId = account("user", c, SEED);
203 let vesting = Some((100_000u32.into(), 1_000u32.into(), 100u32.into()));
204 let statement = StatementKind::Regular;
205 super::Pallet::<T>::mint_claim(
206 RawOrigin::Root.into(),
207 eth_address,
208 bench_claim_value::<T>(),
209 vesting,
210 Some(statement),
211 )?;
212 Preclaims::<T>::insert(&account, eth_address);
213 assert_eq!(Claims::<T>::get(eth_address), Some(bench_claim_value::<T>()));
214
215 let stmt = StatementKind::Regular.to_text().to_vec();
216
217 #[extrinsic_call]
218 _(RawOrigin::Signed(account), stmt);
219
220 assert_eq!(Claims::<T>::get(eth_address), None);
221 Ok(())
222 }
223
224 #[benchmark]
225 fn move_claim() -> Result<(), BenchmarkError> {
226 let c = MAX_CLAIMS;
227 for _ in 0..c / 2 {
228 create_claim::<T>(c)?;
229 create_claim_attest::<T>(u32::MAX - c)?;
230 }
231 let attest_c = u32::MAX - c;
232 let secret_key = libsecp256k1::SecretKey::parse(&keccak_256(&attest_c.encode())).unwrap();
233 let eth_address = eth(&secret_key);
234
235 let new_secret_key =
236 libsecp256k1::SecretKey::parse(&keccak_256(&(u32::MAX / 2).encode())).unwrap();
237 let new_eth_address = eth(&new_secret_key);
238
239 let account: T::AccountId = account("user", c, SEED);
240 Preclaims::<T>::insert(&account, eth_address);
241
242 assert!(Claims::<T>::contains_key(eth_address));
243 assert!(!Claims::<T>::contains_key(new_eth_address));
244
245 #[extrinsic_call]
246 _(RawOrigin::Root, eth_address, new_eth_address, Some(account));
247
248 assert!(!Claims::<T>::contains_key(eth_address));
249 assert!(Claims::<T>::contains_key(new_eth_address));
250 Ok(())
251 }
252
253 #[benchmark(extra)]
255 fn keccak256(i: Linear<0, 10_000>) {
256 let bytes = (i).encode();
257
258 #[block]
259 {
260 for _ in 0..i {
261 let _hash = keccak_256(&bytes);
262 }
263 }
264 }
265
266 #[benchmark(extra)]
268 fn eth_recover(i: Linear<0, 1_000>) {
269 let secret_key = libsecp256k1::SecretKey::parse(&keccak_256(&i.encode())).unwrap();
271 let account: T::AccountId = account("user", i, SEED);
272 let signature = sig::<T>(&secret_key, &account.encode(), &[][..]);
273 let data = account.using_encoded(to_ascii_hex);
274 let extra = StatementKind::default().to_text();
275
276 #[block]
277 {
278 for _ in 0..i {
279 assert!(super::Pallet::<T>::eth_recover(&signature, &data, extra).is_some());
280 }
281 }
282 }
283
284 #[benchmark]
285 fn prevalidate_attests() -> Result<(), BenchmarkError> {
286 let c = MAX_CLAIMS;
287 for _ in 0..c / 2 {
288 create_claim::<T>(c)?;
289 create_claim_attest::<T>(u32::MAX - c)?;
290 }
291 let ext = PrevalidateAttests::<T>::new();
292 let call = super::Call::attest { statement: StatementKind::Regular.to_text().to_vec() };
293 let call: <T as frame_system::Config>::RuntimeCall = call.into();
294 let info = call.get_dispatch_info();
295 let attest_c = u32::MAX - c;
296 let secret_key = libsecp256k1::SecretKey::parse(&keccak_256(&attest_c.encode())).unwrap();
297 let eth_address = eth(&secret_key);
298 let account: T::AccountId = account("user", c, SEED);
299 let vesting = Some((100_000u32.into(), 1_000u32.into(), 100u32.into()));
300 let statement = StatementKind::Regular;
301 super::Pallet::<T>::mint_claim(
302 RawOrigin::Root.into(),
303 eth_address,
304 bench_claim_value::<T>(),
305 vesting,
306 Some(statement),
307 )?;
308 Preclaims::<T>::insert(&account, eth_address);
309 assert_eq!(Claims::<T>::get(eth_address), Some(bench_claim_value::<T>()));
310
311 #[block]
312 {
313 assert!(ext
314 .test_run(RawOrigin::Signed(account).into(), &call, &info, 0, 0, |_| {
315 Ok(Default::default())
316 })
317 .unwrap()
318 .is_ok());
319 }
320
321 Ok(())
322 }
323
324 impl_benchmark_test_suite!(
325 Pallet,
326 crate::claims::mock::new_test_ext(),
327 crate::claims::mock::Test,
328 );
329}