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