@@ -25,39 +25,32 @@ mod mock;
2525use sp_std:: { prelude:: * , vec} ;
2626
2727use frame_benchmarking:: v1:: { account, benchmarks} ;
28- use frame_support:: traits:: { Currency , Get , ValidatorSet , ValidatorSetWithIdentification } ;
28+ use frame_support:: traits:: { Currency , Get } ;
2929use frame_system:: { Config as SystemConfig , Pallet as System , RawOrigin } ;
3030
31- #[ cfg( test) ]
32- use sp_runtime:: traits:: UniqueSaturatedInto ;
3331use sp_runtime:: {
3432 traits:: { Convert , Saturating , StaticLookup } ,
3533 Perbill ,
3634} ;
37- use sp_staking:: offence:: { Offence , ReportOffence } ;
35+ use sp_staking:: offence:: ReportOffence ;
3836
3937use pallet_babe:: EquivocationOffence as BabeEquivocationOffence ;
4038use pallet_balances:: Config as BalancesConfig ;
4139use pallet_grandpa:: {
4240 EquivocationOffence as GrandpaEquivocationOffence , TimeSlot as GrandpaTimeSlot ,
4341} ;
44- use pallet_im_online:: { Config as ImOnlineConfig , Pallet as ImOnline , UnresponsivenessOffence } ;
4542use pallet_offences:: { Config as OffencesConfig , Pallet as Offences } ;
4643use pallet_session:: {
4744 historical:: { Config as HistoricalConfig , IdentificationTuple } ,
48- Config as SessionConfig , SessionManager ,
45+ Config as SessionConfig , Pallet as Session , SessionManager ,
4946} ;
50- #[ cfg( test) ]
51- use pallet_staking:: Event as StakingEvent ;
5247use pallet_staking:: {
5348 Config as StakingConfig , Exposure , IndividualExposure , MaxNominationsOf , Pallet as Staking ,
5449 RewardDestination , ValidatorPrefs ,
5550} ;
5651
5752const SEED : u32 = 0 ;
5853
59- const MAX_REPORTERS : u32 = 100 ;
60- const MAX_OFFENDERS : u32 = 100 ;
6154const MAX_NOMINATORS : u32 = 100 ;
6255
6356pub struct Pallet < T : Config > ( Offences < T > ) ;
@@ -66,7 +59,6 @@ pub trait Config:
6659 SessionConfig
6760 + StakingConfig
6861 + OffencesConfig
69- + ImOnlineConfig
7062 + HistoricalConfig
7163 + BalancesConfig
7264 + IdTupleConvert < Self >
@@ -184,220 +176,7 @@ fn make_offenders<T: Config>(
184176 Ok ( ( id_tuples, offenders) )
185177}
186178
187- fn make_offenders_im_online < T : Config > (
188- num_offenders : u32 ,
189- num_nominators : u32 ,
190- ) -> Result < ( Vec < pallet_im_online:: IdentificationTuple < T > > , Vec < Offender < T > > ) , & ' static str > {
191- Staking :: < T > :: new_session ( 0 ) ;
192-
193- let mut offenders = vec ! [ ] ;
194- for i in 0 ..num_offenders {
195- let offender = create_offender :: < T > ( i + 1 , num_nominators) ?;
196- offenders. push ( offender) ;
197- }
198-
199- Staking :: < T > :: start_session ( 0 ) ;
200-
201- let id_tuples = offenders
202- . iter ( )
203- . map ( |offender| {
204- <
205- <T as ImOnlineConfig >:: ValidatorSet as ValidatorSet < T :: AccountId >
206- >:: ValidatorIdOf :: convert ( offender. controller . clone ( ) )
207- . expect ( "failed to get validator id from account id" )
208- } )
209- . map ( |validator_id| {
210- <
211- <T as ImOnlineConfig >:: ValidatorSet as ValidatorSetWithIdentification < T :: AccountId >
212- >:: IdentificationOf :: convert ( validator_id. clone ( ) )
213- . map ( |full_id| ( validator_id, full_id) )
214- . expect ( "failed to convert validator id to full identification" )
215- } )
216- . collect :: < Vec < pallet_im_online:: IdentificationTuple < T > > > ( ) ;
217- Ok ( ( id_tuples, offenders) )
218- }
219-
220- #[ cfg( test) ]
221- fn check_events <
222- T : Config ,
223- I : Iterator < Item = Item > ,
224- Item : sp_std:: borrow:: Borrow < <T as SystemConfig >:: RuntimeEvent > + sp_std:: fmt:: Debug ,
225- > (
226- expected : I ,
227- ) {
228- let events = System :: < T > :: events ( )
229- . into_iter ( )
230- . map ( |frame_system:: EventRecord { event, .. } | event)
231- . collect :: < Vec < _ > > ( ) ;
232- let expected = expected. collect :: < Vec < _ > > ( ) ;
233-
234- fn pretty < D : sp_std:: fmt:: Debug > ( header : & str , ev : & [ D ] , offset : usize ) {
235- log:: info!( "{}" , header) ;
236- for ( idx, ev) in ev. iter ( ) . enumerate ( ) {
237- log:: info!( "\t [{:04}] {:?}" , idx + offset, ev) ;
238- }
239- }
240- fn print_events < D : sp_std:: fmt:: Debug , E : sp_std:: fmt:: Debug > (
241- idx : usize ,
242- events : & [ D ] ,
243- expected : & [ E ] ,
244- ) {
245- let window = 10 ;
246- let start = idx. saturating_sub ( window / 2 ) ;
247- let end_got = ( idx + window / 2 ) . min ( events. len ( ) ) ;
248- pretty ( "Got(window):" , & events[ start..end_got] , start) ;
249- let end_expected = ( idx + window / 2 ) . min ( expected. len ( ) ) ;
250- pretty ( "Expected(window):" , & expected[ start..end_expected] , start) ;
251- log:: info!( "---------------" ) ;
252- let start_got = events. len ( ) . saturating_sub ( window) ;
253- pretty ( "Got(end):" , & events[ start_got..] , start_got) ;
254- let start_expected = expected. len ( ) . saturating_sub ( window) ;
255- pretty ( "Expected(end):" , & expected[ start_expected..] , start_expected) ;
256- }
257-
258- for ( idx, ( a, b) ) in events. iter ( ) . zip ( expected. iter ( ) ) . enumerate ( ) {
259- if a != sp_std:: borrow:: Borrow :: borrow ( b) {
260- print_events ( idx, & events, & expected) ;
261- log:: info!( "Mismatch at: {}" , idx) ;
262- log:: info!( " Got: {:?}" , b) ;
263- log:: info!( "Expected: {:?}" , a) ;
264- if events. len ( ) != expected. len ( ) {
265- log:: info!(
266- "Mismatching lengths. Got: {}, Expected: {}" ,
267- events. len( ) ,
268- expected. len( )
269- )
270- }
271- panic ! ( "Mismatching events." ) ;
272- }
273- }
274-
275- if events. len ( ) != expected. len ( ) {
276- print_events ( 0 , & events, & expected) ;
277- panic ! ( "Mismatching lengths. Got: {}, Expected: {}" , events. len( ) , expected. len( ) , )
278- }
279- }
280-
281179benchmarks ! {
282- report_offence_im_online {
283- let r in 1 .. MAX_REPORTERS ;
284- // we skip 1 offender, because in such case there is no slashing
285- let o in 2 .. MAX_OFFENDERS ;
286- let n in 0 .. MAX_NOMINATORS . min( MaxNominationsOf :: <T >:: get( ) ) ;
287-
288- // Make r reporters
289- let mut reporters = vec![ ] ;
290- for i in 0 .. r {
291- let reporter = account( "reporter" , i, SEED ) ;
292- reporters. push( reporter) ;
293- }
294-
295- // make sure reporters actually get rewarded
296- Staking :: <T >:: set_slash_reward_fraction( Perbill :: one( ) ) ;
297-
298- let ( offenders, raw_offenders) = make_offenders_im_online:: <T >( o, n) ?;
299- let keys = ImOnline :: <T >:: keys( ) ;
300- let validator_set_count = keys. len( ) as u32 ;
301- let offenders_count = offenders. len( ) as u32 ;
302- let offence = UnresponsivenessOffence {
303- session_index: 0 ,
304- validator_set_count,
305- offenders,
306- } ;
307- let slash_fraction = offence. slash_fraction( offenders_count) ;
308- assert_eq!( System :: <T >:: event_count( ) , 0 ) ;
309- } : {
310- let _ = <T as ImOnlineConfig >:: ReportUnresponsiveness :: report_offence(
311- reporters. clone( ) ,
312- offence
313- ) ;
314- }
315- verify {
316- #[ cfg( test) ]
317- {
318- let bond_amount: u32 = UniqueSaturatedInto :: <u32 >:: unique_saturated_into( bond_amount:: <T >( ) ) ;
319- let slash_amount = slash_fraction * bond_amount;
320- let reward_amount = slash_amount. saturating_mul( 1 + n) / 2 ;
321- let reward = reward_amount / r;
322- let slash_report = |id| core:: iter:: once(
323- <T as StakingConfig >:: RuntimeEvent :: from( StakingEvent :: <T >:: SlashReported { validator: id, fraction: slash_fraction, slash_era: 0 } )
324- ) ;
325- let slash = |id| core:: iter:: once(
326- <T as StakingConfig >:: RuntimeEvent :: from( StakingEvent :: <T >:: Slashed { staker: id, amount: BalanceOf :: <T >:: from( slash_amount) } )
327- ) ;
328- let balance_slash = |id| core:: iter:: once(
329- <T as BalancesConfig >:: RuntimeEvent :: from( pallet_balances:: Event :: <T >:: Slashed { who: id, amount: slash_amount. into( ) } )
330- ) ;
331- let balance_locked = |id| core:: iter:: once(
332- <T as BalancesConfig >:: RuntimeEvent :: from( pallet_balances:: Event :: <T >:: Locked { who: id, amount: slash_amount. into( ) } )
333- ) ;
334- let balance_unlocked = |id| core:: iter:: once(
335- <T as BalancesConfig >:: RuntimeEvent :: from( pallet_balances:: Event :: <T >:: Unlocked { who: id, amount: slash_amount. into( ) } )
336- ) ;
337- let chill = |id| core:: iter:: once(
338- <T as StakingConfig >:: RuntimeEvent :: from( StakingEvent :: <T >:: Chilled { stash: id } )
339- ) ;
340- let balance_deposit = |id, amount: u32 |
341- <T as BalancesConfig >:: RuntimeEvent :: from( pallet_balances:: Event :: <T >:: Deposit { who: id, amount: amount. into( ) } ) ;
342- let mut first = true ;
343-
344- // We need to box all events to prevent running into too big allocations in wasm.
345- // The event in FRAME is represented as an enum and the size of the enum depends on the biggest variant.
346- // So, instead of requiring `size_of<Event>() * expected_events` we only need to
347- // allocate `size_of<Box<Event>>() * expected_events`.
348- let slash_events = raw_offenders. into_iter( )
349- . flat_map( |offender| {
350- let nom_slashes = offender. nominator_stashes. into_iter( ) . flat_map( |nom| {
351- balance_slash( nom. clone( ) ) . map( Into :: into)
352- . chain( balance_unlocked( nom. clone( ) ) . map( Into :: into) )
353- . chain( slash( nom) . map( Into :: into) ) . map( Box :: new)
354- } ) ;
355-
356- let events = chill( offender. stash. clone( ) ) . map( Into :: into) . map( Box :: new)
357- . chain( slash_report( offender. stash. clone( ) ) . map( Into :: into) . map( Box :: new) )
358- . chain( balance_slash( offender. stash. clone( ) ) . map( Into :: into) . map( Box :: new) )
359- . chain( balance_unlocked( offender. stash. clone( ) ) . map( Into :: into) . map( Box :: new) )
360- . chain( slash( offender. stash) . map( Into :: into) . map( Box :: new) )
361- . chain( nom_slashes)
362- . collect:: <Vec <_>>( ) ;
363-
364- // the first deposit creates endowed events, see `endowed_reward_events`
365- if first {
366- first = false ;
367- let reward_events = reporters. iter( )
368- . flat_map( |reporter| vec![
369- Box :: new( balance_deposit( reporter. clone( ) , reward) . into( ) ) ,
370- Box :: new( frame_system:: Event :: <T >:: NewAccount { account: reporter. clone( ) } . into( ) ) ,
371- Box :: new( <T as BalancesConfig >:: RuntimeEvent :: from(
372- pallet_balances:: Event :: <T >:: Endowed { account: reporter. clone( ) , free_balance: reward. into( ) }
373- ) . into( ) ) ,
374- ] )
375- . collect:: <Vec <_>>( ) ;
376- events. into_iter( ) . chain( reward_events)
377- } else {
378- let reward_events = reporters. iter( )
379- . map( |reporter| Box :: new( balance_deposit( reporter. clone( ) , reward) . into( ) ) )
380- . collect:: <Vec <_>>( ) ;
381- events. into_iter( ) . chain( reward_events)
382- }
383- } ) ;
384-
385- // In case of error it's useful to see the inputs
386- log:: info!( "Inputs: r: {}, o: {}, n: {}" , r, o, n) ;
387- // make sure that all slashes have been applied
388- check_events:: <T , _, _>(
389- sp_std:: iter:: empty( )
390- . chain( slash_events)
391- . chain( sp_std:: iter:: once( Box :: new( <T as OffencesConfig >:: RuntimeEvent :: from(
392- pallet_offences:: Event :: Offence {
393- kind: UnresponsivenessOffence :: <T >:: ID ,
394- timeslot: 0_u32 . to_le_bytes( ) . to_vec( ) ,
395- }
396- ) . into( ) ) ) )
397- ) ;
398- }
399- }
400-
401180 report_offence_grandpa {
402181 let n in 0 .. MAX_NOMINATORS . min( MaxNominationsOf :: <T >:: get( ) ) ;
403182
@@ -409,12 +188,12 @@ benchmarks! {
409188 Staking :: <T >:: set_slash_reward_fraction( Perbill :: one( ) ) ;
410189
411190 let ( mut offenders, raw_offenders) = make_offenders:: <T >( 1 , n) ?;
412- let keys = ImOnline :: <T >:: keys ( ) ;
191+ let validator_set_count = Session :: <T >:: validators ( ) . len ( ) as u32 ;
413192
414193 let offence = GrandpaEquivocationOffence {
415194 time_slot: GrandpaTimeSlot { set_id: 0 , round: 0 } ,
416195 session_index: 0 ,
417- validator_set_count: keys . len ( ) as u32 ,
196+ validator_set_count,
418197 offender: T :: convert( offenders. pop( ) . unwrap( ) ) ,
419198 } ;
420199 assert_eq!( System :: <T >:: event_count( ) , 0 ) ;
@@ -446,12 +225,12 @@ benchmarks! {
446225 Staking :: <T >:: set_slash_reward_fraction( Perbill :: one( ) ) ;
447226
448227 let ( mut offenders, raw_offenders) = make_offenders:: <T >( 1 , n) ?;
449- let keys = ImOnline :: <T >:: keys ( ) ;
228+ let validator_set_count = Session :: <T >:: validators ( ) . len ( ) as u32 ;
450229
451230 let offence = BabeEquivocationOffence {
452231 slot: 0u64 . into( ) ,
453232 session_index: 0 ,
454- validator_set_count: keys . len ( ) as u32 ,
233+ validator_set_count,
455234 offender: T :: convert( offenders. pop( ) . unwrap( ) ) ,
456235 } ;
457236 assert_eq!( System :: <T >:: event_count( ) , 0 ) ;
0 commit comments