20
20
use super :: * ;
21
21
use crate :: { Pallet as MultiPhase , unsigned:: IndexAssignmentOf } ;
22
22
use frame_benchmarking:: { account, impl_benchmark_test_suite} ;
23
- use frame_support:: { assert_ok, traits:: OnInitialize } ;
23
+ use frame_support:: { assert_ok, traits:: Hooks } ;
24
24
use frame_system:: RawOrigin ;
25
25
use rand:: { prelude:: SliceRandom , rngs:: SmallRng , SeedableRng } ;
26
- use frame_election_provider_support:: Assignment ;
27
26
use sp_arithmetic:: { per_things:: Percent , traits:: One } ;
28
27
use sp_npos_elections:: IndexAssignment ;
29
28
use sp_runtime:: InnerOf ;
@@ -38,14 +37,14 @@ fn solution_with_size<T: Config>(
38
37
size : SolutionOrSnapshotSize ,
39
38
active_voters_count : u32 ,
40
39
desired_targets : u32 ,
41
- ) -> RawSolution < CompactOf < T > > {
42
- assert ! ( size. targets >= desired_targets, "must have enough targets" ) ;
43
- assert ! (
40
+ ) -> Result < RawSolution < CompactOf < T > > , & ' static str > {
41
+ ensure ! ( size. targets >= desired_targets, "must have enough targets" ) ;
42
+ ensure ! (
44
43
size. targets >= ( <CompactOf <T >>:: LIMIT * 2 ) as u32 ,
45
44
"must have enough targets for unique votes."
46
45
) ;
47
- assert ! ( size. voters >= active_voters_count, "must have enough voters" ) ;
48
- assert ! (
46
+ ensure ! ( size. voters >= active_voters_count, "must have enough voters" ) ;
47
+ ensure ! (
49
48
( <CompactOf <T >>:: LIMIT as u32 ) < desired_targets,
50
49
"must have enough winners to give them votes."
51
50
) ;
@@ -125,7 +124,7 @@ fn solution_with_size<T: Config>(
125
124
. map ( |( voter, _stake, votes) | {
126
125
let percent_per_edge: InnerOf < CompactAccuracyOf < T > > =
127
126
( 100 / votes. len ( ) ) . try_into ( ) . unwrap_or_else ( |_| panic ! ( "failed to convert" ) ) ;
128
- Assignment {
127
+ crate :: unsigned :: Assignment :: < T > {
129
128
who : voter. clone ( ) ,
130
129
distribution : votes
131
130
. iter ( )
@@ -141,7 +140,31 @@ fn solution_with_size<T: Config>(
141
140
let round = <MultiPhase < T > >:: round ( ) ;
142
141
143
142
assert ! ( score[ 0 ] > 0 , "score is zero, this probably means that the stakes are not set." ) ;
144
- RawSolution { compact, score, round }
143
+ Ok ( RawSolution { compact, score, round } )
144
+ }
145
+
146
+ fn set_up_data_provider < T : Config > ( v : u32 , t : u32 ) {
147
+ // number of votes in snapshot.
148
+
149
+ T :: DataProvider :: clear ( ) ;
150
+ log ! ( info, "setting up with voters = {} [degree = {}], targets = {}" , v, T :: DataProvider :: MAXIMUM_VOTES_PER_VOTER , t) ;
151
+
152
+ // fill targets.
153
+ let mut targets = ( 0 ..t) . map ( |i| {
154
+ let target = frame_benchmarking:: account :: < T :: AccountId > ( "Target" , i, SEED ) ;
155
+ T :: DataProvider :: add_target ( target. clone ( ) ) ;
156
+ target
157
+ } ) . collect :: < Vec < _ > > ( ) ;
158
+ // we should always have enough voters to fill.
159
+ assert ! ( targets. len( ) > T :: DataProvider :: MAXIMUM_VOTES_PER_VOTER as usize ) ;
160
+ targets. truncate ( T :: DataProvider :: MAXIMUM_VOTES_PER_VOTER as usize ) ;
161
+
162
+ // fill voters.
163
+ ( 0 ..v) . for_each ( |i| {
164
+ let voter = frame_benchmarking:: account :: < T :: AccountId > ( "Voter" , i, SEED ) ;
165
+ let weight = T :: Currency :: minimum_balance ( ) . saturated_into :: < u64 > ( ) * 1000 ;
166
+ T :: DataProvider :: add_voter ( voter, weight, targets. clone ( ) ) ;
167
+ } ) ;
145
168
}
146
169
147
170
frame_benchmarking:: benchmarks! {
@@ -223,14 +246,18 @@ frame_benchmarking::benchmarks! {
223
246
224
247
// a call to `<Pallet as ElectionProvider>::elect` where we only return the queued solution.
225
248
elect_queued {
226
- // assume largest values for the election status. These will merely affect the decoding.
227
- let v = T :: BenchmarkingConfig :: VOTERS [ 1 ] ;
228
- let t = T :: BenchmarkingConfig :: TARGETS [ 1 ] ;
229
- let a = T :: BenchmarkingConfig :: ACTIVE_VOTERS [ 1 ] ;
230
- let d = T :: BenchmarkingConfig :: DESIRED_TARGETS [ 1 ] ;
249
+ // number of votes in snapshot.
250
+ let v in ( T :: BenchmarkingConfig :: VOTERS [ 0 ] ) .. T :: BenchmarkingConfig :: VOTERS [ 1 ] ;
251
+ // number of targets in snapshot.
252
+ let t in ( T :: BenchmarkingConfig :: TARGETS [ 0 ] ) .. T :: BenchmarkingConfig :: TARGETS [ 1 ] ;
253
+ // number of assignments, i.e. compact.len(). This means the active nominators, thus must be
254
+ // a subset of `v` component.
255
+ let a in ( T :: BenchmarkingConfig :: ACTIVE_VOTERS [ 0 ] ) .. T :: BenchmarkingConfig :: ACTIVE_VOTERS [ 1 ] ;
256
+ // number of desired targets. Must be a subset of `t` component.
257
+ let d in ( T :: BenchmarkingConfig :: DESIRED_TARGETS [ 0 ] ) .. T :: BenchmarkingConfig :: DESIRED_TARGETS [ 1 ] ;
231
258
232
259
let witness = SolutionOrSnapshotSize { voters: v, targets: t } ;
233
- let raw_solution = solution_with_size:: <T >( witness, a, d) ;
260
+ let raw_solution = solution_with_size:: <T >( witness, a, d) ? ;
234
261
let ready_solution =
235
262
<MultiPhase <T >>:: feasibility_check( raw_solution, ElectionCompute :: Signed ) . unwrap( ) ;
236
263
@@ -251,15 +278,6 @@ frame_benchmarking::benchmarks! {
251
278
assert_eq!( <CurrentPhase <T >>:: get( ) , <Phase <T :: BlockNumber >>:: Off ) ;
252
279
}
253
280
254
- #[ extra]
255
- create_snapshot {
256
- assert!( <MultiPhase <T >>:: snapshot( ) . is_none( ) ) ;
257
- } : {
258
- <MultiPhase :: <T >>:: create_snapshot( ) . unwrap( )
259
- } verify {
260
- assert!( <MultiPhase <T >>:: snapshot( ) . is_some( ) ) ;
261
- }
262
-
263
281
submit {
264
282
let c in 1 .. ( T :: SignedMaxSubmissions :: get( ) - 1 ) ;
265
283
@@ -307,7 +325,7 @@ frame_benchmarking::benchmarks! {
307
325
T :: BenchmarkingConfig :: DESIRED_TARGETS [ 1 ] ;
308
326
309
327
let witness = SolutionOrSnapshotSize { voters: v, targets: t } ;
310
- let raw_solution = solution_with_size:: <T >( witness, a, d) ;
328
+ let raw_solution = solution_with_size:: <T >( witness, a, d) ? ;
311
329
312
330
assert!( <MultiPhase <T >>:: queued_solution( ) . is_none( ) ) ;
313
331
<CurrentPhase <T >>:: put( Phase :: Unsigned ( ( true , 1u32 . into( ) ) ) ) ;
@@ -324,6 +342,84 @@ frame_benchmarking::benchmarks! {
324
342
assert!( <MultiPhase <T >>:: queued_solution( ) . is_some( ) ) ;
325
343
}
326
344
345
+ // This is checking a valid solution. The worse case is indeed a valid solution.
346
+ feasibility_check {
347
+ // number of votes in snapshot.
348
+ let v in ( T :: BenchmarkingConfig :: VOTERS [ 0 ] ) .. T :: BenchmarkingConfig :: VOTERS [ 1 ] ;
349
+ // number of targets in snapshot.
350
+ let t in ( T :: BenchmarkingConfig :: TARGETS [ 0 ] ) .. T :: BenchmarkingConfig :: TARGETS [ 1 ] ;
351
+ // number of assignments, i.e. compact.len(). This means the active nominators, thus must be
352
+ // a subset of `v` component.
353
+ let a in ( T :: BenchmarkingConfig :: ACTIVE_VOTERS [ 0 ] ) .. T :: BenchmarkingConfig :: ACTIVE_VOTERS [ 1 ] ;
354
+ // number of desired targets. Must be a subset of `t` component.
355
+ let d in ( T :: BenchmarkingConfig :: DESIRED_TARGETS [ 0 ] ) .. T :: BenchmarkingConfig :: DESIRED_TARGETS [ 1 ] ;
356
+
357
+ let size = SolutionOrSnapshotSize { voters: v, targets: t } ;
358
+ let raw_solution = solution_with_size:: <T >( size, a, d) ?;
359
+
360
+ assert_eq!( raw_solution. compact. voter_count( ) as u32 , a) ;
361
+ assert_eq!( raw_solution. compact. unique_targets( ) . len( ) as u32 , d) ;
362
+
363
+ // encode the most significant storage item that needs to be decoded in the dispatch.
364
+ let encoded_snapshot = <MultiPhase <T >>:: snapshot( ) . unwrap( ) . encode( ) ;
365
+ } : {
366
+ assert_ok!( <MultiPhase <T >>:: feasibility_check( raw_solution, ElectionCompute :: Unsigned ) ) ;
367
+ let _decoded_snap = <RoundSnapshot <T :: AccountId > as Decode >:: decode( & mut & * encoded_snapshot) . unwrap( ) ;
368
+ }
369
+
370
+ // NOTE: this weight is not used anywhere, but the fact that it should succeed when execution in
371
+ // isolation is vital to ensure memory-safety. For the same reason, we don't care about the
372
+ // components iterating, we merely check that this operation will work with the "maximum"
373
+ // numbers.
374
+ //
375
+ // ONLY run this benchmark in isolation, and pass the `--extra` flag to enable it.
376
+ //
377
+ // NOTE: If this benchmark does not run out of memory with a given heap pages, it means that the
378
+ // OCW process can SURELY succeed with the given configuration, but the opposite is not true.
379
+ // This benchmark is doing more work than a raw call to `OffchainWorker_offchain_worker` runtime
380
+ // api call, since it is also setting up some mock data, which will itself exhaust the heap to
381
+ // some extent.
382
+ #[ extra]
383
+ mine_solution_offchain_memory {
384
+ // number of votes in snapshot. Fixed to maximum.
385
+ let v = T :: BenchmarkingConfig :: MINER_MAXIMUM_VOTERS ;
386
+ // number of targets in snapshot. Fixed to maximum.
387
+ let t = T :: BenchmarkingConfig :: MAXIMUM_TARGETS ;
388
+
389
+ T :: DataProvider :: clear( ) ;
390
+ set_up_data_provider:: <T >( v, t) ;
391
+ let now = frame_system:: Pallet :: <T >:: block_number( ) ;
392
+ <CurrentPhase <T >>:: put( Phase :: Unsigned ( ( true , now) ) ) ;
393
+ <MultiPhase :: <T >>:: create_snapshot( ) . unwrap( ) ;
394
+ } : {
395
+ // we can't really verify this as it won't write anything to state, check logs.
396
+ <MultiPhase :: <T >>:: offchain_worker( now)
397
+ }
398
+
399
+ // NOTE: this weight is not used anywhere, but the fact that it should succeed when execution in
400
+ // isolation is vital to ensure memory-safety. For the same reason, we don't care about the
401
+ // components iterating, we merely check that this operation will work with the "maximum"
402
+ // numbers.
403
+ //
404
+ // ONLY run this benchmark in isolation, and pass the `--extra` flag to enable it.
405
+ #[ extra]
406
+ create_snapshot_memory {
407
+ // number of votes in snapshot. Fixed to maximum.
408
+ let v = T :: BenchmarkingConfig :: SNAPSHOT_MAXIMUM_VOTERS ;
409
+ // number of targets in snapshot. Fixed to maximum.
410
+ let t = T :: BenchmarkingConfig :: MAXIMUM_TARGETS ;
411
+
412
+ T :: DataProvider :: clear( ) ;
413
+ set_up_data_provider:: <T >( v, t) ;
414
+ assert!( <MultiPhase <T >>:: snapshot( ) . is_none( ) ) ;
415
+ } : {
416
+ <MultiPhase :: <T >>:: create_snapshot( ) . unwrap( )
417
+ } verify {
418
+ assert!( <MultiPhase <T >>:: snapshot( ) . is_some( ) ) ;
419
+ assert_eq!( <MultiPhase <T >>:: snapshot_metadata( ) . unwrap( ) . voters, v + t) ;
420
+ assert_eq!( <MultiPhase <T >>:: snapshot_metadata( ) . unwrap( ) . targets, t) ;
421
+ }
422
+
327
423
#[ extra]
328
424
trim_assignments_length {
329
425
// number of votes in snapshot.
@@ -344,7 +440,7 @@ frame_benchmarking::benchmarks! {
344
440
// Compute a random solution, then work backwards to get the lists of voters, targets, and
345
441
// assignments
346
442
let witness = SolutionOrSnapshotSize { voters: v, targets: t } ;
347
- let RawSolution { compact, .. } = solution_with_size:: <T >( witness, a, d) ;
443
+ let RawSolution { compact, .. } = solution_with_size:: <T >( witness, a, d) ? ;
348
444
let RoundSnapshot { voters, targets } = MultiPhase :: <T >:: snapshot( ) . unwrap( ) ;
349
445
let voter_at = helpers:: voter_at_fn:: <T >( & voters) ;
350
446
let target_at = helpers:: target_at_fn:: <T >( & targets) ;
@@ -394,39 +490,10 @@ frame_benchmarking::benchmarks! {
394
490
log!( trace, "actual encoded size = {}" , encoding. len( ) ) ;
395
491
assert!( encoding. len( ) <= desired_size) ;
396
492
}
397
-
398
- // This is checking a valid solution. The worse case is indeed a valid solution.
399
- feasibility_check {
400
- // number of votes in snapshot.
401
- let v in ( T :: BenchmarkingConfig :: VOTERS [ 0 ] ) .. T :: BenchmarkingConfig :: VOTERS [ 1 ] ;
402
- // number of targets in snapshot.
403
- let t in ( T :: BenchmarkingConfig :: TARGETS [ 0 ] ) .. T :: BenchmarkingConfig :: TARGETS [ 1 ] ;
404
- // number of assignments, i.e. compact.len(). This means the active nominators, thus must be
405
- // a subset of `v` component.
406
- let a in
407
- ( T :: BenchmarkingConfig :: ACTIVE_VOTERS [ 0 ] ) .. T :: BenchmarkingConfig :: ACTIVE_VOTERS [ 1 ] ;
408
- // number of desired targets. Must be a subset of `t` component.
409
- let d in
410
- ( T :: BenchmarkingConfig :: DESIRED_TARGETS [ 0 ] ) ..
411
- T :: BenchmarkingConfig :: DESIRED_TARGETS [ 1 ] ;
412
-
413
- let size = SolutionOrSnapshotSize { voters: v, targets: t } ;
414
- let raw_solution = solution_with_size:: <T >( size, a, d) ;
415
-
416
- assert_eq!( raw_solution. compact. voter_count( ) as u32 , a) ;
417
- assert_eq!( raw_solution. compact. unique_targets( ) . len( ) as u32 , d) ;
418
-
419
- // encode the most significant storage item that needs to be decoded in the dispatch.
420
- let encoded_snapshot = <MultiPhase <T >>:: snapshot( ) . unwrap( ) . encode( ) ;
421
- } : {
422
- assert_ok!( <MultiPhase <T >>:: feasibility_check( raw_solution, ElectionCompute :: Unsigned ) ) ;
423
- let _decoded_snap = <RoundSnapshot <T :: AccountId > as Decode >:: decode( & mut & * encoded_snapshot)
424
- . unwrap( ) ;
425
- }
426
493
}
427
494
428
495
impl_benchmark_test_suite ! (
429
496
MultiPhase ,
430
- crate :: mock:: ExtBuilder :: default ( ) . build ( ) ,
497
+ crate :: mock:: ExtBuilder :: default ( ) . build_offchainify ( 10 ) . 0 ,
431
498
crate :: mock:: Runtime ,
432
499
) ;
0 commit comments