1
// Copyright (C) Moondance Labs Ltd.
2
// This file is part of Tanssi.
3

            
4
// Tanssi is free software: you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation, either version 3 of the License, or
7
// (at your option) any later version.
8

            
9
// Tanssi is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
// GNU General Public License for more details.
13

            
14
// You should have received a copy of the GNU General Public License
15
// along with Tanssi.  If not, see <http://www.gnu.org/licenses/>
16
use super::*;
17
12
fn get_active_collators(block: u32) -> AuthorNotingInfo<AccountId> {
18
12
    AuthorNotingInfo {
19
12
        block_number: block,
20
12
        author: COLLATOR_1,
21
12
        para_id: CONTAINER_CHAIN_ID_1,
22
12
    }
23
12
}
24

            
25
1
fn get_max_active_collators_vec(block: u32) -> Vec<AuthorNotingInfo<AccountId>> {
26
1
    let total_collators: u32 = <Test as Config>::MaxCollatorsPerSession::get();
27
1
    let mut active_collators: Vec<AuthorNotingInfo<AccountId>> = Vec::new();
28
5
    for i in 0u32..total_collators {
29
5
        active_collators.push(AuthorNotingInfo {
30
5
            block_number: block + i,
31
5
            author: (i + 3).into(),
32
5
            para_id: 3002.into(),
33
5
        });
34
5
    }
35
1
    active_collators
36
1
}
37

            
38
1
fn get_overflowing_active_collators_vec(block: u32) -> Vec<AuthorNotingInfo<AccountId>> {
39
1
    let total_collators = <Test as Config>::MaxCollatorsPerSession::get();
40
1
    let mut overflowing_active_collators: Vec<AuthorNotingInfo<AccountId>> = Vec::new();
41
6
    for i in 0u32..=total_collators {
42
6
        overflowing_active_collators.push(AuthorNotingInfo {
43
6
            block_number: block + i,
44
6
            author: (i + 1).into(),
45
6
            para_id: 2000.into(),
46
6
        });
47
6
    }
48
1
    overflowing_active_collators
49
1
}
50

            
51
1
fn get_overflowing_active_chains_vec(block: u32) -> Vec<AuthorNotingInfo<AccountId>> {
52
1
    let total_chains = <Test as Config>::MaxContainerChains::get();
53
1
    let mut overflowing_active_chains: Vec<AuthorNotingInfo<AccountId>> = Vec::new();
54
4
    for i in 0u32..=total_chains {
55
4
        overflowing_active_chains.push(AuthorNotingInfo {
56
4
            block_number: block,
57
4
            author: COLLATOR_1,
58
4
            para_id: (i + 2000).into(),
59
4
        });
60
4
    }
61
1
    overflowing_active_chains
62
1
}
63

            
64
9
fn get_active_chains_set(
65
9
    chains: Vec<tp_traits::ParaId>,
66
9
) -> BoundedBTreeSet<tp_traits::ParaId, <Test as Config>::MaxContainerChains> {
67
9
    let mut chain_set = BoundedBTreeSet::new();
68
18
    for chain in chains {
69
9
        let _ = chain_set.try_insert(chain);
70
9
    }
71
9
    chain_set
72
9
}
73

            
74
#[test]
75
1
fn enabling_and_disabling_inactivity_tracking_works() {
76
1
    ExtBuilder.build().execute_with(|| {
77
1
        assert_eq!(
78
1
            CurrentActivityTrackingStatus::<Test>::get(),
79
            ActivityTrackingStatus::Enabled { start: 0, end: 0 }
80
        );
81

            
82
1
        run_to_block(SESSION_BLOCK_LENGTH);
83
1
        assert_ok!(Pallet::<Test>::set_inactivity_tracking_status(
84
1
            RuntimeOrigin::root(),
85
            false
86
        ));
87

            
88
1
        let suspension_period: u32 = get_max_inactive_sessions() + 1u32;
89
1
        assert_eq!(
90
1
            CurrentActivityTrackingStatus::<Test>::get(),
91
1
            ActivityTrackingStatus::Disabled {
92
1
                end: suspension_period
93
1
            }
94
        );
95

            
96
1
        run_to_block(SESSION_BLOCK_LENGTH * (u64::from(suspension_period) + 1));
97

            
98
1
        assert_ok!(Pallet::<Test>::set_inactivity_tracking_status(
99
1
            RuntimeOrigin::root(),
100
            true
101
        ));
102

            
103
1
        assert_eq!(
104
1
            CurrentActivityTrackingStatus::<Test>::get(),
105
1
            ActivityTrackingStatus::Enabled {
106
1
                start: suspension_period + 2,
107
1
                end: 2 * suspension_period
108
1
            }
109
        );
110
1
        run_to_block(SESSION_BLOCK_LENGTH * (2 * u64::from(suspension_period) + 1));
111

            
112
1
        assert_ok!(Pallet::<Test>::set_inactivity_tracking_status(
113
1
            RuntimeOrigin::root(),
114
            false
115
        ));
116

            
117
1
        assert_eq!(
118
1
            CurrentActivityTrackingStatus::<Test>::get(),
119
1
            ActivityTrackingStatus::Disabled {
120
1
                end: 3 * suspension_period
121
1
            }
122
        );
123
1
    });
124
1
}
125

            
126
#[test]
127
1
fn enabling_and_disabling_inactivity_tracking_fails_for_non_root() {
128
1
    ExtBuilder.build().execute_with(|| {
129
1
        assert_noop!(
130
1
            Pallet::<Test>::set_inactivity_tracking_status(
131
1
                RuntimeOrigin::signed(COLLATOR_1),
132
                false
133
            ),
134
1
            BadOrigin
135
        );
136
1
    });
137
1
}
138

            
139
#[test]
140
1
fn setting_the_same_inactivity_tracking_status_fails() {
141
1
    ExtBuilder.build().execute_with(|| {
142
1
        assert_noop!(
143
1
            Pallet::<Test>::set_inactivity_tracking_status(RuntimeOrigin::root(), true),
144
1
            Error::<Test>::ActivityTrackingStatusAlreadyEnabled
145
        );
146
1
        run_to_block(SESSION_BLOCK_LENGTH);
147
1
        assert_ok!(Pallet::<Test>::set_inactivity_tracking_status(
148
1
            RuntimeOrigin::root(),
149
            false
150
        ));
151
1
        assert_noop!(
152
1
            Pallet::<Test>::set_inactivity_tracking_status(RuntimeOrigin::root(), false),
153
1
            Error::<Test>::ActivityTrackingStatusAlreadyDisabled
154
        );
155
1
    });
156
1
}
157

            
158
#[test]
159
1
fn enabling_and_disabling_inactivity_tracking_fails_if_called_before_end_of_suspension_period() {
160
1
    ExtBuilder.build().execute_with(|| {
161
1
        assert_eq!(
162
1
            CurrentActivityTrackingStatus::<Test>::get(),
163
            ActivityTrackingStatus::Enabled { start: 0, end: 0 }
164
        );
165
1
        assert_noop!(
166
1
            Pallet::<Test>::set_inactivity_tracking_status(RuntimeOrigin::root(), false),
167
1
            Error::<Test>::ActivityTrackingStatusUpdateSuspended
168
        );
169
1
    });
170
1
}
171

            
172
#[test]
173
1
fn inactivity_tracking_handler_with_enabled_and_disabled_tracking_works() {
174
1
    ExtBuilder.build().execute_with(|| {
175
1
        assert!(
176
1
            !<Pallet::<Test> as NodeActivityTrackingHelper<AccountId>>::is_node_inactive(
177
1
                &COLLATOR_1
178
1
            )
179
        );
180
1
        assert!(
181
1
            !<Pallet::<Test> as NodeActivityTrackingHelper<AccountId>>::is_node_inactive(
182
1
                &COLLATOR_2
183
1
            )
184
        );
185

            
186
1
        run_to_block(u64::from(get_max_inactive_sessions()) * SESSION_BLOCK_LENGTH + 1);
187
1
        assert_eq!(
188
1
            <Test as Config>::CurrentSessionIndex::session_index(),
189
1
            get_max_inactive_sessions()
190
        );
191

            
192
1
        let inactive_collator = get_collator_set(vec![COLLATOR_1]);
193
2
        for session_id in 0..get_max_inactive_sessions() {
194
2
            InactiveCollators::<Test>::insert(session_id, inactive_collator.clone());
195
2
            assert_eq!(
196
2
                InactiveCollators::<Test>::get(session_id),
197
                inactive_collator
198
            );
199
        }
200

            
201
1
        assert!(
202
1
            <Pallet::<Test> as NodeActivityTrackingHelper<AccountId>>::is_node_inactive(
203
1
                &COLLATOR_1
204
            )
205
        );
206
1
        assert!(
207
1
            !<Pallet::<Test> as NodeActivityTrackingHelper<AccountId>>::is_node_inactive(
208
1
                &COLLATOR_2
209
1
            )
210
        );
211

            
212
1
        assert_ok!(Pallet::<Test>::set_inactivity_tracking_status(
213
1
            RuntimeOrigin::root(),
214
            false
215
        ));
216

            
217
1
        assert!(
218
1
            !<Pallet::<Test> as NodeActivityTrackingHelper<AccountId>>::is_node_inactive(
219
1
                &COLLATOR_1
220
1
            )
221
        );
222
1
        assert!(
223
1
            !<Pallet::<Test> as NodeActivityTrackingHelper<AccountId>>::is_node_inactive(
224
1
                &COLLATOR_2
225
1
            )
226
        );
227
1
    });
228
1
}
229

            
230
#[test]
231
1
fn inactivity_tracking_handler_with_one_active_session_works() {
232
1
    ExtBuilder.build().execute_with(|| {
233
1
        run_to_block(u64::from(get_max_inactive_sessions()) * SESSION_BLOCK_LENGTH + 1);
234

            
235
1
        let inactive_collator_1 = get_collator_set(vec![COLLATOR_1]);
236
1
        let inactive_collator_2 = get_collator_set(vec![COLLATOR_2]);
237
1
        InactiveCollators::<Test>::insert(0, inactive_collator_1.clone());
238
1
        InactiveCollators::<Test>::insert(1, inactive_collator_2.clone());
239
1
        assert!(
240
1
            !<Pallet::<Test> as NodeActivityTrackingHelper<AccountId>>::is_node_inactive(
241
1
                &COLLATOR_2
242
1
            )
243
        );
244
1
        assert!(
245
1
            !<Pallet::<Test> as NodeActivityTrackingHelper<AccountId>>::is_node_inactive(
246
1
                &COLLATOR_1
247
1
            )
248
        );
249
1
    });
250
1
}
251

            
252
#[test]
253
1
fn inactivity_tracking_handler_works_as_expected_with_no_activity_during_initial_sessions() {
254
1
    ExtBuilder.build().execute_with(|| {
255
1
        run_to_block(SESSION_BLOCK_LENGTH + 1);
256

            
257
1
        assert!(
258
1
            !<Pallet::<Test> as NodeActivityTrackingHelper<AccountId>>::is_node_inactive(
259
1
                &COLLATOR_1
260
1
            )
261
        );
262
1
        assert!(
263
1
            !<Pallet::<Test> as NodeActivityTrackingHelper<AccountId>>::is_node_inactive(
264
1
                &COLLATOR_2
265
1
            )
266
        );
267
1
    });
268
1
}
269

            
270
#[test]
271
1
fn inactivity_tracking_handler_with_enabled_tracking_after_disabling_it_works() {
272
1
    ExtBuilder.build().execute_with(|| {
273
1
        run_to_block(SESSION_BLOCK_LENGTH);
274
1
        assert_ok!(Pallet::<Test>::set_inactivity_tracking_status(
275
1
            RuntimeOrigin::root(),
276
            false
277
        ));
278

            
279
1
        let suspension_period: u32 = get_max_inactive_sessions() + 1u32;
280
1
        assert_eq!(
281
1
            CurrentActivityTrackingStatus::<Test>::get(),
282
1
            ActivityTrackingStatus::Disabled {
283
1
                end: suspension_period
284
1
            }
285
        );
286

            
287
1
        run_to_block(SESSION_BLOCK_LENGTH * (u64::from(suspension_period) + 1));
288

            
289
1
        assert_ok!(Pallet::<Test>::set_inactivity_tracking_status(
290
1
            RuntimeOrigin::root(),
291
            true
292
        ));
293
1
        assert_eq!(
294
1
            CurrentActivityTrackingStatus::<Test>::get(),
295
1
            ActivityTrackingStatus::Enabled {
296
1
                start: suspension_period + 2,
297
1
                end: 2 * suspension_period
298
1
            }
299
        );
300
1
        assert_eq!(
301
1
            <Test as Config>::CurrentSessionIndex::session_index(),
302
1
            suspension_period + 1
303
        );
304
1
        let inactive_collators = get_collator_set(vec![COLLATOR_1, COLLATOR_2]);
305

            
306
        // Since we do not introduce any activity record, but the enabled tracking status
307
        // start = suspension_period + 2 < CurrentSessionIndex + MaxInactiveStatus = suspension_period + 1 + 2
308
        // so the collators should be considered active
309
1
        assert!(
310
1
            !<Pallet::<Test> as NodeActivityTrackingHelper<AccountId>>::is_node_inactive(
311
1
                &COLLATOR_1
312
1
            )
313
        );
314
1
        assert!(
315
1
            !<Pallet::<Test> as NodeActivityTrackingHelper<AccountId>>::is_node_inactive(
316
1
                &COLLATOR_2
317
1
            )
318
        );
319
        // Now start = CurrentSessionIndex so the collators should be considered active
320
1
        run_to_block(SESSION_BLOCK_LENGTH * (u64::from(suspension_period) + 2));
321
        // Manually re-insert the collators to inactive collators storage after a session is processed
322
        // to simulate the case when the collators are inactive
323
1
        InactiveCollators::<Test>::insert(suspension_period + 1, inactive_collators.clone());
324
1
        assert_eq!(
325
1
            <Test as Config>::CurrentSessionIndex::session_index(),
326
1
            suspension_period + 2
327
        );
328
1
        assert!(
329
1
            !<Pallet::<Test> as NodeActivityTrackingHelper<AccountId>>::is_node_inactive(
330
1
                &COLLATOR_1
331
1
            )
332
        );
333
1
        assert!(
334
1
            !<Pallet::<Test> as NodeActivityTrackingHelper<AccountId>>::is_node_inactive(
335
1
                &COLLATOR_2
336
1
            )
337
        );
338
1
        run_to_block(SESSION_BLOCK_LENGTH * (u64::from(suspension_period) + 3));
339
1
        InactiveCollators::<Test>::insert(suspension_period + 2, inactive_collators.clone());
340
        // Once CurrentSessionIndex >= start + MaxInactiveSessions collators will be considered inactive
341
        // since there are inactivity records for it
342
1
        run_to_block(
343
1
            SESSION_BLOCK_LENGTH
344
1
                * (u64::from(suspension_period) + 2 + u64::from(get_max_inactive_sessions())),
345
        );
346
1
        InactiveCollators::<Test>::insert(suspension_period + 3, inactive_collators);
347
1
        assert_eq!(
348
1
            <Test as Config>::CurrentSessionIndex::session_index(),
349
1
            suspension_period + 2 + get_max_inactive_sessions()
350
        );
351
1
        assert!(
352
1
            <Pallet::<Test> as NodeActivityTrackingHelper<AccountId>>::is_node_inactive(
353
1
                &COLLATOR_1
354
            )
355
        );
356
1
        assert!(
357
1
            <Pallet::<Test> as NodeActivityTrackingHelper<AccountId>>::is_node_inactive(
358
1
                &COLLATOR_2
359
            )
360
        );
361
1
    });
362
1
}
363

            
364
#[test]
365
1
fn processing_ended_session_correctly_updates_current_session_collators_and_active_collators_records(
366
1
) {
367
1
    ExtBuilder.build().execute_with(|| {
368
1
        let current_session_active_collator_record: BoundedBTreeSet<AccountId, ConstU32<5>> =
369
1
            get_collator_set(vec![COLLATOR_1]);
370
1
        let inactive_collators_record: BoundedBTreeSet<AccountId, ConstU32<5>> =
371
1
            get_collator_set(vec![COLLATOR_2]);
372
1
        let current_session_active_chain_record = get_active_chains_set(vec![CONTAINER_CHAIN_ID_1]);
373
1
        let empty_set: BoundedBTreeSet<AccountId, ConstU32<5>> = BoundedBTreeSet::new();
374

            
375
1
        ActiveCollatorsForCurrentSession::<Test>::put(
376
1
            current_session_active_collator_record.clone(),
377
        );
378
1
        ActiveContainerChainsForCurrentSession::<Test>::put(
379
1
            current_session_active_chain_record.clone(),
380
        );
381

            
382
1
        assert_eq!(
383
1
            ActiveCollatorsForCurrentSession::<Test>::get(),
384
            current_session_active_collator_record
385
        );
386
1
        assert_eq!(
387
1
            ActiveContainerChainsForCurrentSession::<Test>::get(),
388
            current_session_active_chain_record
389
        );
390

            
391
1
        assert_eq!(InactiveCollators::<Test>::get(0), empty_set);
392

            
393
1
        run_to_block(SESSION_BLOCK_LENGTH + 1);
394

            
395
1
        assert_eq!(ActiveCollatorsForCurrentSession::<Test>::get(), empty_set);
396
1
        assert_eq!(InactiveCollators::<Test>::get(0), inactive_collators_record);
397
1
    });
398
1
}
399

            
400
#[test]
401
1
fn processing_ended_session_correctly_cleans_outdated_collator_records() {
402
1
    ExtBuilder.build().execute_with(|| {
403
1
        assert_eq!(<Test as Config>::CurrentSessionIndex::session_index(), 0);
404

            
405
1
        let current_session_active_collator_record: BoundedBTreeSet<AccountId, ConstU32<5>> =
406
1
            get_collator_set(vec![COLLATOR_1]);
407
1
        let inactive_collators_record: BoundedBTreeSet<AccountId, ConstU32<5>> =
408
1
            get_collator_set(vec![COLLATOR_2]);
409
1
        let current_session_active_chain_record = get_active_chains_set(vec![CONTAINER_CHAIN_ID_1]);
410
1
        let empty_set: BoundedBTreeSet<AccountId, ConstU32<5>> = BoundedBTreeSet::new();
411

            
412
1
        ActiveCollatorsForCurrentSession::<Test>::put(
413
1
            current_session_active_collator_record.clone(),
414
        );
415
1
        ActiveContainerChainsForCurrentSession::<Test>::put(
416
1
            current_session_active_chain_record.clone(),
417
        );
418

            
419
1
        assert_eq!(
420
1
            ActiveCollatorsForCurrentSession::<Test>::get(),
421
            current_session_active_collator_record
422
        );
423
1
        assert_eq!(
424
1
            ActiveContainerChainsForCurrentSession::<Test>::get(),
425
            current_session_active_chain_record
426
        );
427
1
        assert_eq!(InactiveCollators::<Test>::get(0), empty_set);
428

            
429
1
        run_to_block(SESSION_BLOCK_LENGTH);
430

            
431
1
        assert_eq!(ActiveCollatorsForCurrentSession::<Test>::get(), empty_set);
432
1
        assert_eq!(InactiveCollators::<Test>::get(0), inactive_collators_record);
433

            
434
1
        run_to_block(u64::from(get_max_inactive_sessions()) * SESSION_BLOCK_LENGTH + 1);
435
1
        assert_eq!(
436
1
            <Test as Config>::CurrentSessionIndex::session_index(),
437
1
            get_max_inactive_sessions()
438
        );
439

            
440
1
        assert_eq!(ActiveCollatorsForCurrentSession::<Test>::get(), empty_set);
441
1
        assert_eq!(InactiveCollators::<Test>::get(0), inactive_collators_record);
442

            
443
1
        run_to_block((u64::from(get_max_inactive_sessions()) + 1) * SESSION_BLOCK_LENGTH + 1);
444
1
        assert_eq!(
445
1
            <Test as Config>::CurrentSessionIndex::session_index(),
446
1
            get_max_inactive_sessions() + 1
447
        );
448

            
449
1
        assert_eq!(ActiveCollatorsForCurrentSession::<Test>::get(), empty_set);
450
1
        assert_eq!(InactiveCollators::<Test>::get(0), empty_set);
451
1
    });
452
1
}
453

            
454
#[test]
455
1
fn active_collators_noting_for_current_session_works_when_activity_tracking_is_enabled() {
456
1
    ExtBuilder.build().execute_with(|| {
457
1
        let current_session_active_collator_record: BoundedBTreeSet<AccountId, ConstU32<5>> =
458
1
            get_collator_set(vec![COLLATOR_1]);
459
1
        assert_eq!(ActiveCollatorsForCurrentSession::<Test>::get().len(), 0);
460
1
        run_to_block(2);
461
1
        <Pallet<Test> as AuthorNotingHook<AccountId>>::on_container_authors_noted(&[
462
1
            get_active_collators(2),
463
1
        ]);
464
1
        assert_eq!(
465
1
            ActiveCollatorsForCurrentSession::<Test>::get(),
466
            current_session_active_collator_record
467
        );
468
1
        run_to_block(3);
469
1
        <Pallet<Test> as AuthorNotingHook<AccountId>>::on_container_authors_noted(&[
470
1
            get_active_collators(3),
471
1
        ]);
472
1
        assert_eq!(
473
1
            ActiveCollatorsForCurrentSession::<Test>::get(),
474
            current_session_active_collator_record
475
        );
476
1
    });
477
1
}
478

            
479
#[test]
480
1
fn active_collators_noting_for_current_session_works_when_activity_tracking_is_disabled_then_enabled(
481
1
) {
482
1
    ExtBuilder.build().execute_with(|| {
483
1
        assert_eq!(ActiveCollatorsForCurrentSession::<Test>::get().len(), 0);
484

            
485
1
        run_to_block(SESSION_BLOCK_LENGTH);
486
1
        assert_ok!(Pallet::<Test>::set_inactivity_tracking_status(
487
1
            RuntimeOrigin::root(),
488
            false
489
        ));
490
        // Since the activity tracking is disabled, the active collators noting
491
        // should not update ActiveCollatorsForCurrentSession
492
1
        <Pallet<Test> as AuthorNotingHook<AccountId>>::on_container_authors_noted(&[
493
1
            get_active_collators(SESSION_BLOCK_LENGTH as u32),
494
1
        ]);
495
1
        assert_eq!(ActiveCollatorsForCurrentSession::<Test>::get().len(), 0);
496
1
        let suspension_period: u32 = get_max_inactive_sessions() + 1u32;
497
1
        run_to_block(SESSION_BLOCK_LENGTH * (u64::from(suspension_period) + 1));
498
1
        assert_ok!(Pallet::<Test>::set_inactivity_tracking_status(
499
1
            RuntimeOrigin::root(),
500
            true
501
        ));
502
1
        assert_eq!(
503
1
            CurrentActivityTrackingStatus::<Test>::get(),
504
1
            ActivityTrackingStatus::Enabled {
505
1
                start: suspension_period + 2,
506
1
                end: 2 * suspension_period
507
1
            }
508
        );
509
        // Since the activity tracking is enabled,
510
        // start = suspension_period + 2 and current session = suspension_period + 1 so
511
        // the active collators noting should not update ActiveCollatorsForCurrentSession
512
1
        <Pallet<Test> as AuthorNotingHook<AccountId>>::on_container_authors_noted(&[
513
1
            get_active_collators(SESSION_BLOCK_LENGTH as u32),
514
1
        ]);
515
1
        assert_eq!(ActiveCollatorsForCurrentSession::<Test>::get().len(), 0);
516

            
517
1
        run_to_block(SESSION_BLOCK_LENGTH * (2 * u64::from(suspension_period) + 1));
518
1
        <Pallet<Test> as AuthorNotingHook<AccountId>>::on_container_authors_noted(&[
519
1
            get_active_collators(SESSION_BLOCK_LENGTH as u32),
520
1
        ]);
521
1
        let current_session_active_collator_record: BoundedBTreeSet<AccountId, ConstU32<5>> =
522
1
            get_collator_set(vec![COLLATOR_1]);
523
1
        assert_eq!(
524
1
            ActiveCollatorsForCurrentSession::<Test>::get(),
525
            current_session_active_collator_record
526
        );
527
1
    });
528
1
}
529

            
530
#[test]
531
1
fn disabling_inactivity_tracking_clears_the_current_active_collators_storage() {
532
1
    ExtBuilder.build().execute_with(|| {
533
1
        assert_eq!(
534
1
            CurrentActivityTrackingStatus::<Test>::get(),
535
            ActivityTrackingStatus::Enabled { start: 0, end: 0 }
536
        );
537

            
538
1
        run_to_block(SESSION_BLOCK_LENGTH);
539
1
        <Pallet<Test> as AuthorNotingHook<AccountId>>::on_container_authors_noted(&[
540
1
            get_active_collators(SESSION_BLOCK_LENGTH as u32),
541
1
        ]);
542
1
        assert_eq!(ActiveCollatorsForCurrentSession::<Test>::get().len(), 1);
543

            
544
1
        run_to_block(SESSION_BLOCK_LENGTH);
545
1
        assert_ok!(Pallet::<Test>::set_inactivity_tracking_status(
546
1
            RuntimeOrigin::root(),
547
            false
548
        ));
549
1
        assert_eq!(
550
1
            CurrentActivityTrackingStatus::<Test>::get(),
551
1
            ActivityTrackingStatus::Disabled {
552
1
                end: get_max_inactive_sessions() + 1
553
1
            }
554
        );
555
1
        assert_eq!(ActiveCollatorsForCurrentSession::<Test>::get().len(), 0);
556
1
    });
557
1
}
558

            
559
#[test]
560
1
fn inactivity_tracking_is_disabled_if_current_active_collators_storage_overflows() {
561
1
    ExtBuilder.build().execute_with(|| {
562
1
        assert_eq!(
563
1
            CurrentActivityTrackingStatus::<Test>::get(),
564
            ActivityTrackingStatus::Enabled { start: 0, end: 0 }
565
        );
566
1
        run_to_block(1);
567
1
        <Pallet<Test> as AuthorNotingHook<AccountId>>::on_container_authors_noted(
568
1
            get_overflowing_active_collators_vec(1).as_slice(),
569
        );
570
1
        assert_eq!(
571
1
            CurrentActivityTrackingStatus::<Test>::get(),
572
            ActivityTrackingStatus::Disabled { end: 2 }
573
        );
574
1
    });
575
1
}
576

            
577
#[test]
578
1
fn inactivity_tracking_is_disabled_if_active_chains_storage_overflows() {
579
1
    ExtBuilder.build().execute_with(|| {
580
1
        assert_eq!(
581
1
            CurrentActivityTrackingStatus::<Test>::get(),
582
            ActivityTrackingStatus::Enabled { start: 0, end: 0 }
583
        );
584
1
        run_to_block(1);
585
1
        <Pallet<Test> as AuthorNotingHook<AccountId>>::on_container_authors_noted(
586
1
            get_overflowing_active_chains_vec(1).as_slice(),
587
        );
588
1
        assert_eq!(
589
1
            CurrentActivityTrackingStatus::<Test>::get(),
590
            ActivityTrackingStatus::Disabled { end: 2 }
591
        );
592
1
    });
593
1
}
594

            
595
#[test]
596
1
fn inactivity_tracking_is_disabled_if_current_active_collators_storage_overflows_while_processing_inactive_chains_in_the_end_of_a_session(
597
1
) {
598
1
    ExtBuilder.build().execute_with(|| {
599
1
        assert_eq!(
600
1
            CurrentActivityTrackingStatus::<Test>::get(),
601
            ActivityTrackingStatus::Enabled { start: 0, end: 0 }
602
        );
603
1
        run_to_block(1);
604
        // We note the max active collators for the session which are not COLLATOR_1 and COLLATOR_2
605
        // for chains that are not CONTAINER_CHAIN_ID_1 and CONTAINER_CHAIN_ID_2
606
1
        <Pallet<Test> as AuthorNotingHook<AccountId>>::on_container_authors_noted(
607
1
            &get_max_active_collators_vec(1),
608
        );
609
        // Since the active collators storage is not overflowing,
610
        // we will not disable the activity tracking
611
1
        assert_eq!(
612
1
            CurrentActivityTrackingStatus::<Test>::get(),
613
            ActivityTrackingStatus::Enabled { start: 0, end: 0 }
614
        );
615
        // Since chain with id CONTAINER_CHAIN_ID_1 is inactive COLLATOR_1 and COLLATOR_2
616
        // will be added to the active collators storage for current session and it will overflow
617
1
        run_to_block(SESSION_BLOCK_LENGTH + 1);
618
1
        assert_eq!(
619
1
            CurrentActivityTrackingStatus::<Test>::get(),
620
            ActivityTrackingStatus::Disabled { end: 2 }
621
        );
622
1
        assert_eq!(InactiveCollators::<Test>::get(0).len(), 0);
623
1
    });
624
1
}
625

            
626
#[test]
627
1
fn active_chains_noting_for_current_session_works_when_activity_tracking_is_enabled() {
628
1
    ExtBuilder.build().execute_with(|| {
629
1
        let current_session_active_chain_record = get_active_chains_set(vec![CONTAINER_CHAIN_ID_1]);
630
1
        assert_eq!(
631
1
            ActiveContainerChainsForCurrentSession::<Test>::get().len(),
632
            0
633
        );
634
1
        run_to_block(2);
635
1
        <Pallet<Test> as AuthorNotingHook<AccountId>>::on_container_authors_noted(&[
636
1
            get_active_collators(2),
637
1
        ]);
638
1
        assert_eq!(
639
1
            ActiveContainerChainsForCurrentSession::<Test>::get(),
640
            current_session_active_chain_record
641
        );
642
1
        run_to_block(3);
643
1
        <Pallet<Test> as AuthorNotingHook<AccountId>>::on_container_authors_noted(&[
644
1
            get_active_collators(3),
645
1
        ]);
646
1
        assert_eq!(
647
1
            ActiveContainerChainsForCurrentSession::<Test>::get(),
648
            current_session_active_chain_record
649
        );
650
1
    });
651
1
}
652
#[test]
653
1
fn active_chains_noting_for_current_session_works_when_activity_tracking_is_disabled_than_enabled()
654
{
655
1
    ExtBuilder.build().execute_with(|| {
656
1
        let current_session_active_chain_record = get_active_chains_set(vec![CONTAINER_CHAIN_ID_1]);
657
1
        assert_eq!(
658
1
            ActiveContainerChainsForCurrentSession::<Test>::get().len(),
659
            0
660
        );
661
1
        run_to_block(SESSION_BLOCK_LENGTH);
662
1
        assert_ok!(Pallet::<Test>::set_inactivity_tracking_status(
663
1
            RuntimeOrigin::root(),
664
            false
665
        ));
666
1
        <Pallet<Test> as AuthorNotingHook<AccountId>>::on_container_authors_noted(&[
667
1
            get_active_collators(SESSION_BLOCK_LENGTH as u32),
668
1
        ]);
669
1
        assert_eq!(
670
1
            ActiveContainerChainsForCurrentSession::<Test>::get().len(),
671
            0
672
        );
673
1
        let disabled_tracking_status_end_block: u32 =
674
1
            (get_max_inactive_sessions() + 2u32) * SESSION_BLOCK_LENGTH as u32;
675
1
        run_to_block(u64::from(disabled_tracking_status_end_block));
676
1
        assert_ok!(Pallet::<Test>::set_inactivity_tracking_status(
677
1
            RuntimeOrigin::root(),
678
            true
679
        ));
680
        // Since the activity tracking is enabled we will need to wait until the start of
681
        // the next session before we are able to updating ActiveContainerChainsForCurrentSession
682
1
        <Pallet<Test> as AuthorNotingHook<AccountId>>::on_container_authors_noted(&[
683
1
            get_active_collators(disabled_tracking_status_end_block),
684
1
        ]);
685
1
        assert_eq!(
686
1
            ActiveContainerChainsForCurrentSession::<Test>::get().len(),
687
            0
688
        );
689
1
        run_to_block(u64::from(disabled_tracking_status_end_block) + SESSION_BLOCK_LENGTH);
690
1
        <Pallet<Test> as AuthorNotingHook<AccountId>>::on_container_authors_noted(&[
691
1
            get_active_collators(disabled_tracking_status_end_block + SESSION_BLOCK_LENGTH as u32),
692
1
        ]);
693
1
        assert_eq!(
694
1
            ActiveContainerChainsForCurrentSession::<Test>::get(),
695
            current_session_active_chain_record
696
        );
697
1
    });
698
1
}
699

            
700
#[test]
701
1
fn inactive_chain_collators_are_correctly_processed_when_activity_tracking_is_enabled() {
702
1
    ExtBuilder.build().execute_with(|| {
703
1
        assert!(ActiveContainerChainsForCurrentSession::<Test>::get().is_empty());
704
1
        assert!(ActiveCollatorsForCurrentSession::<Test>::get().is_empty());
705
1
        run_to_block(SESSION_BLOCK_LENGTH - 1);
706
1
        assert!(ActiveContainerChainsForCurrentSession::<Test>::get().is_empty());
707
1
        assert!(ActiveCollatorsForCurrentSession::<Test>::get().is_empty());
708
1
        run_to_block(SESSION_BLOCK_LENGTH);
709
1
        assert!(InactiveCollators::<Test>::get(0).is_empty());
710
1
    });
711
1
}
712

            
713
#[test]
714
1
fn inactive_collator_for_active_chain_is_correctly_processed_when_activity_tracking_is_enabled() {
715
1
    ExtBuilder.build().execute_with(|| {
716
1
        let current_session_active_collator_record = get_collator_set(vec![COLLATOR_1]);
717
1
        let current_session_active_chain_record = get_active_chains_set(vec![CONTAINER_CHAIN_ID_1]);
718
1
        assert_eq!(
719
1
            ActiveContainerChainsForCurrentSession::<Test>::get().len(),
720
            0
721
        );
722
1
        assert_eq!(ActiveCollatorsForCurrentSession::<Test>::get().len(), 0);
723
1
        run_to_block(2);
724
1
        <Pallet<Test> as AuthorNotingHook<AccountId>>::on_container_authors_noted(&[
725
1
            get_active_collators(2),
726
1
        ]);
727
1
        run_to_block(SESSION_BLOCK_LENGTH - 1);
728
1
        assert_eq!(
729
1
            ActiveContainerChainsForCurrentSession::<Test>::get(),
730
            current_session_active_chain_record
731
        );
732
1
        assert_eq!(
733
1
            ActiveCollatorsForCurrentSession::<Test>::get(),
734
            current_session_active_collator_record
735
        );
736
1
        run_to_block(SESSION_BLOCK_LENGTH);
737
1
        assert_eq!(
738
1
            InactiveCollators::<Test>::get(0),
739
1
            get_collator_set(vec![COLLATOR_2])
740
        );
741
1
    });
742
1
}
743

            
744
#[test]
745
1
fn inactive_chain_collators_are_processed_correctly_when_activity_tracking_is_disabled_than_enabled(
746
1
) {
747
1
    ExtBuilder.build().execute_with(|| {
748
1
        let last_disabled_session_id = get_max_inactive_sessions() + 2u32;
749
1
        assert_eq!(
750
1
            ActiveContainerChainsForCurrentSession::<Test>::get().len(),
751
            0
752
        );
753
1
        run_to_block(SESSION_BLOCK_LENGTH);
754
1
        assert_ok!(Pallet::<Test>::set_inactivity_tracking_status(
755
1
            RuntimeOrigin::root(),
756
            false
757
        ));
758

            
759
1
        run_to_block(2 * SESSION_BLOCK_LENGTH - 1);
760
1
        ActiveContainerChainsForCurrentSession::<Test>::put(get_active_chains_set(vec![
761
            CONTAINER_CHAIN_ID_1,
762
        ]));
763
1
        ActiveCollatorsForCurrentSession::<Test>::put(get_collator_set(vec![COLLATOR_1]));
764

            
765
1
        run_to_block(2 * SESSION_BLOCK_LENGTH);
766
1
        assert_eq!(
767
1
            ActiveContainerChainsForCurrentSession::<Test>::get().len(),
768
            0
769
        );
770
1
        assert_eq!(
771
1
            ActiveContainerChainsForCurrentSession::<Test>::get().len(),
772
            0
773
        );
774
1
        assert_eq!(InactiveCollators::<Test>::get(1).len(), 0);
775

            
776
1
        let disabled_tracking_status_end_block: u32 =
777
1
            last_disabled_session_id * SESSION_BLOCK_LENGTH as u32;
778
1
        run_to_block(u64::from(disabled_tracking_status_end_block));
779
1
        assert_ok!(Pallet::<Test>::set_inactivity_tracking_status(
780
1
            RuntimeOrigin::root(),
781
            true
782
        ));
783

            
784
        // Since the activity tracking is enabled we will need to wait until the start of
785
        // the next session before process_inactive_chains_for_session() is enabled
786
1
        run_to_block(u64::from(disabled_tracking_status_end_block) + SESSION_BLOCK_LENGTH - 1);
787
1
        ActiveContainerChainsForCurrentSession::<Test>::put(get_active_chains_set(vec![
788
            CONTAINER_CHAIN_ID_1,
789
        ]));
790
1
        ActiveCollatorsForCurrentSession::<Test>::put(get_collator_set(vec![COLLATOR_1]));
791

            
792
1
        run_to_block(u64::from(disabled_tracking_status_end_block) + SESSION_BLOCK_LENGTH);
793
1
        assert_eq!(
794
1
            ActiveContainerChainsForCurrentSession::<Test>::get().len(),
795
            0
796
        );
797
1
        assert_eq!(
798
1
            ActiveContainerChainsForCurrentSession::<Test>::get().len(),
799
            0
800
        );
801
1
        assert_eq!(
802
1
            InactiveCollators::<Test>::get(last_disabled_session_id).len(),
803
            0
804
        );
805

            
806
1
        run_to_block(u64::from(disabled_tracking_status_end_block) + 2 * SESSION_BLOCK_LENGTH - 1);
807
1
        ActiveContainerChainsForCurrentSession::<Test>::put(get_active_chains_set(vec![
808
            CONTAINER_CHAIN_ID_1,
809
        ]));
810
1
        ActiveCollatorsForCurrentSession::<Test>::put(get_collator_set(vec![COLLATOR_1]));
811

            
812
1
        run_to_block(u64::from(disabled_tracking_status_end_block) + 2 * SESSION_BLOCK_LENGTH);
813
1
        assert_eq!(
814
1
            ActiveContainerChainsForCurrentSession::<Test>::get().len(),
815
            0
816
        );
817
1
        assert_eq!(
818
1
            ActiveContainerChainsForCurrentSession::<Test>::get().len(),
819
            0
820
        );
821
1
        assert_eq!(
822
1
            InactiveCollators::<Test>::get(last_disabled_session_id + 1),
823
1
            get_collator_set(vec![COLLATOR_2])
824
        );
825
1
    });
826
1
}
827

            
828
#[test]
829
1
fn chain_inactivity_tracking_correctly_processes_parathreads() {
830
1
    ExtBuilder.build().execute_with(|| {
831
        // We will insert CONTAINER_CHAIN_ID_3 as an active chain but not add the collator assigned
832
        // to it (COLLATOR_3) to the list of active collators. Since all parathreads are considered
833
        // inactive, we should not see the collator in inactive collators storage after the session
834
        // is processed
835
1
        let current_session_active_chain_record = get_active_chains_set(vec![CONTAINER_CHAIN_ID_3]);
836
1
        <ActiveContainerChainsForCurrentSession<Test>>::put(
837
1
            current_session_active_chain_record.clone(),
838
        );
839
1
        assert_eq!(ActiveCollatorsForCurrentSession::<Test>::get().len(), 0);
840
1
        run_to_block(SESSION_BLOCK_LENGTH - 1);
841
1
        assert_eq!(
842
1
            ActiveContainerChainsForCurrentSession::<Test>::get(),
843
            current_session_active_chain_record
844
        );
845
1
        assert!(ActiveCollatorsForCurrentSession::<Test>::get().is_empty());
846
1
        run_to_block(SESSION_BLOCK_LENGTH);
847
1
        assert!(InactiveCollators::<Test>::get(0).is_empty());
848
1
    });
849
1
}