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

            
17
//! Crate containing various traits used by moondance crates allowing to connect pallet
18
//! with each other or with mocks.
19

            
20
#![cfg_attr(not(feature = "std"), no_std)]
21

            
22
extern crate alloc;
23

            
24
pub mod alias;
25
pub mod prod_or_fast;
26

            
27
pub use {
28
    alias::*,
29
    cumulus_primitives_core::{
30
        relay_chain::{BlockNumber, HeadData, Slot, ValidationCode},
31
        ParaId,
32
    },
33
    dp_chain_state_snapshot::{GenericStateProof, ReadEntryErr},
34
    dp_container_chain_genesis_data::ContainerChainGenesisDataItem,
35
};
36

            
37
use {
38
    alloc::{
39
        collections::{btree_map::BTreeMap, btree_set::BTreeSet},
40
        vec,
41
        vec::Vec,
42
    },
43
    core::marker::PhantomData,
44
    frame_support::{
45
        dispatch::DispatchErrorWithPostInfo,
46
        pallet_prelude::{
47
            Decode, DecodeWithMemTracking, DispatchResultWithPostInfo, Encode, Get, MaxEncodedLen,
48
            Weight,
49
        },
50
        BoundedVec,
51
    },
52
    scale_info::TypeInfo,
53
    serde::{Deserialize, Serialize},
54
    sp_core::H256,
55
    sp_runtime::{
56
        app_crypto::sp_core,
57
        traits::{CheckedAdd, CheckedMul},
58
        ArithmeticError, DispatchResult, Perbill, RuntimeDebug,
59
    },
60
};
61

            
62
/// The collator-assignment hook to react to collators being assigned to container chains.
63
pub trait CollatorAssignmentHook<Balance> {
64
    /// This hook is called when collators are assigned to a container
65
    ///
66
    /// The hook should never panic and is required to return the weight consumed.
67
    fn on_collators_assigned(
68
        para_id: ParaId,
69
        maybe_tip: Option<&Balance>,
70
        is_parathread: bool,
71
    ) -> Result<Weight, sp_runtime::DispatchError>;
72
}
73

            
74
#[impl_trait_for_tuples::impl_for_tuples(5)]
75
impl<Balance> CollatorAssignmentHook<Balance> for Tuple {
76
    fn on_collators_assigned(
77
        p: ParaId,
78
        t: Option<&Balance>,
79
        ip: bool,
80
    ) -> Result<Weight, sp_runtime::DispatchError> {
81
        let mut weight: Weight = Default::default();
82
        for_tuples!( #( weight.saturating_accrue(Tuple::on_collators_assigned(p, t, ip)?); )* );
83
        Ok(weight)
84
    }
85
}
86

            
87
/// Container chains collator assignment tip prioritization on congestion.
88
/// Tips paras are willing to pay for collator assignment in case of collators demand
89
/// surpasses the offer.
90
pub trait CollatorAssignmentTip<Balance> {
91
    /// Return the amount this para is willing to tip to be included.
92
    fn get_para_max_tip(a: ParaId) -> Option<Balance>;
93
}
94

            
95
impl<Balance> CollatorAssignmentTip<Balance> for () {
96
    fn get_para_max_tip(_: ParaId) -> Option<Balance> {
97
        None
98
    }
99
}
100

            
101
pub struct AuthorNotingInfo<AccountId> {
102
    pub author: AccountId,
103
    pub block_number: BlockNumber,
104
    pub para_id: ParaId,
105
}
106

            
107
/// The author-noting hook to react to container chains authoring.
108
pub trait AuthorNotingHook<AccountId> {
109
    /// This hook is called partway through the `set_latest_author_data` inherent in author-noting.
110
    ///
111
    /// The hook should never panic and is required to return the weight consumed.
112
    fn on_container_authors_noted(info: &[AuthorNotingInfo<AccountId>]) -> Weight;
113

            
114
    #[cfg(feature = "runtime-benchmarks")]
115
    fn prepare_worst_case_for_bench(author: &AccountId, block_number: BlockNumber, para_id: ParaId);
116
}
117

            
118
#[impl_trait_for_tuples::impl_for_tuples(5)]
119
impl<AccountId> AuthorNotingHook<AccountId> for Tuple {
120
136
    fn on_container_authors_noted(info: &[AuthorNotingInfo<AccountId>]) -> Weight {
121
136
        let mut weight: Weight = Default::default();
122
125
        for_tuples!( #( weight.saturating_accrue(Tuple::on_container_authors_noted(info)); )* );
123
136
        weight
124
136
    }
125

            
126
    #[cfg(feature = "runtime-benchmarks")]
127
    fn prepare_worst_case_for_bench(a: &AccountId, b: BlockNumber, p: ParaId) {
128
        for_tuples!( #( Tuple::prepare_worst_case_for_bench(a, b, p); )* );
129
    }
130
}
131

            
132
pub trait DistributeRewards<AccountId, Imbalance> {
133
    fn distribute_rewards(rewarded: AccountId, amount: Imbalance) -> DispatchResultWithPostInfo;
134
}
135

            
136
impl<AccountId, Imbalance> DistributeRewards<AccountId, Imbalance> for () {
137
26
    fn distribute_rewards(_rewarded: AccountId, _amount: Imbalance) -> DispatchResultWithPostInfo {
138
26
        Ok(().into())
139
26
    }
140
}
141

            
142
/// Get the current list of container chains parachain ids.
143
pub trait GetCurrentContainerChains {
144
    type MaxContainerChains: Get<u32>;
145

            
146
    fn current_container_chains() -> BoundedVec<ParaId, Self::MaxContainerChains>;
147

            
148
    #[cfg(feature = "runtime-benchmarks")]
149
    fn set_current_container_chains(container_chains: &[ParaId]);
150
}
151

            
152
#[derive(Copy, Clone, PartialEq, Eq)]
153
pub enum ForSession {
154
    Current,
155
    Next,
156
}
157

            
158
/// Get the current list of container chains parachain ids with its assigned collators.
159
/// It can return a para id with an empty list of collators.
160
pub trait GetContainerChainsWithCollators<AccountId> {
161
    fn container_chains_with_collators(for_session: ForSession) -> Vec<(ParaId, Vec<AccountId>)>;
162

            
163
    fn get_all_collators_assigned_to_chains(for_session: ForSession) -> BTreeSet<AccountId>;
164

            
165
    #[cfg(feature = "runtime-benchmarks")]
166
    fn set_container_chains_with_collators(
167
        for_session: ForSession,
168
        container_chains: &[(ParaId, Vec<AccountId>)],
169
    );
170
}
171

            
172
/// How often should a parathread collator propose blocks. The units are "1 out of n slots", where the slot time is the
173
/// tanssi slot time, 6 seconds.
174
// TODO: this is currently ignored
175
#[derive(
176
    Clone,
177
    Debug,
178
    Encode,
179
    Decode,
180
    DecodeWithMemTracking,
181
    scale_info::TypeInfo,
182
    PartialEq,
183
    Eq,
184
    Serialize,
185
    Deserialize,
186
    MaxEncodedLen,
187
)]
188
pub struct SlotFrequency {
189
    /// The parathread will produce at most 1 block every x slots. min=10 means that collators can produce 1 block
190
    /// every `x >= 10` slots, but they are not enforced to. If collators produce a block after less than 10
191
    /// slots, they will not be rewarded by tanssi.
192
    pub min: u32,
193
    /// The parathread will produce at least 1 block every x slots. max=10 means that collators are forced to
194
    /// produce 1 block every `x <= 10` slots. Collators can produce a block sooner than that if the `min` allows it, but
195
    /// waiting more than 10 slots will make them lose the block reward.
196
    pub max: u32,
197
}
198

            
199
impl SlotFrequency {
200
1134
    pub fn should_parathread_buy_core(
201
1134
        &self,
202
1134
        current_slot: Slot,
203
1134
        max_slot_required_to_complete_purchase: Slot,
204
1134
        last_block_slot: Slot,
205
1134
    ) -> bool {
206
1134
        current_slot
207
1134
            >= last_block_slot
208
1134
                .saturating_add(Slot::from(u64::from(self.min)))
209
1134
                .saturating_sub(max_slot_required_to_complete_purchase)
210
1134
    }
211

            
212
    pub fn should_parathread_author_block(
213
        &self,
214
        current_slot: Slot,
215
        last_block_slot: Slot,
216
    ) -> bool {
217
        current_slot >= last_block_slot.saturating_add(Slot::from(u64::from(self.min)))
218
    }
219
}
220

            
221
impl Default for SlotFrequency {
222
605
    fn default() -> Self {
223
605
        Self { min: 1, max: 1 }
224
605
    }
225
}
226

            
227
#[derive(
228
    Clone,
229
    Debug,
230
    Encode,
231
    Decode,
232
    DecodeWithMemTracking,
233
    scale_info::TypeInfo,
234
    PartialEq,
235
    Eq,
236
    Serialize,
237
    Deserialize,
238
    MaxEncodedLen,
239
)]
240
pub struct ParathreadParams {
241
    pub slot_frequency: SlotFrequency,
242
}
243

            
244
#[derive(Clone, Debug, Encode, Decode, scale_info::TypeInfo, PartialEq, Eq)]
245
pub struct SessionContainerChains {
246
    pub parachains: Vec<ParaId>,
247
    pub parathreads: Vec<(ParaId, ParathreadParams)>,
248
}
249

            
250
/// Get the list of container chains parachain ids at given
251
/// session index.
252
pub trait GetSessionContainerChains<SessionIndex> {
253
    fn session_container_chains(session_index: SessionIndex) -> SessionContainerChains;
254
    #[cfg(feature = "runtime-benchmarks")]
255
    fn set_session_container_chains(session_index: SessionIndex, container_chains: &[ParaId]);
256
}
257

            
258
/// Returns author for a parachain id for the given slot.
259
pub trait GetContainerChainAuthor<AccountId> {
260
    fn author_for_slot(slot: Slot, para_id: ParaId) -> Option<AccountId>;
261
    #[cfg(feature = "runtime-benchmarks")]
262
    fn set_authors_for_para_id(para_id: ParaId, authors: Vec<AccountId>);
263
}
264

            
265
/// Returns the host configuration composed of the amount of collators assigned
266
/// to the orchestrator chain, and how many collators are assigned per container chain.
267
pub trait GetHostConfiguration<SessionIndex> {
268
    fn max_collators(session_index: SessionIndex) -> u32;
269
    fn min_collators_for_orchestrator(session_index: SessionIndex) -> u32;
270
    fn max_collators_for_orchestrator(session_index: SessionIndex) -> u32;
271
    fn collators_per_container(session_index: SessionIndex) -> u32;
272
    fn collators_per_parathread(session_index: SessionIndex) -> u32;
273
    fn target_container_chain_fullness(session_index: SessionIndex) -> Perbill;
274
    fn max_parachain_cores_percentage(session_index: SessionIndex) -> Option<Perbill>;
275
    fn full_rotation_mode(session_index: SessionIndex) -> FullRotationModes;
276
    #[cfg(feature = "runtime-benchmarks")]
277
    fn set_host_configuration(_session_index: SessionIndex) {}
278
}
279

            
280
/// Returns current session index.
281
pub trait GetSessionIndex<SessionIndex> {
282
    fn session_index() -> SessionIndex;
283

            
284
    #[cfg(feature = "runtime-benchmarks")]
285
    fn skip_to_session(session_index: SessionIndex);
286
}
287

            
288
/// Should pallet_collator_assignment trigger a full rotation on this session?
289
pub trait ShouldRotateAllCollators<SessionIndex> {
290
    fn should_rotate_all_collators(session_index: SessionIndex) -> bool;
291
}
292

            
293
impl<SessionIndex> ShouldRotateAllCollators<SessionIndex> for () {
294
    fn should_rotate_all_collators(_session_index: SessionIndex) -> bool {
295
        false
296
    }
297
}
298

            
299
/// Helper trait for pallet_collator_assignment to be able to give priority to invulnerables
300
pub trait RemoveInvulnerables<AccountId> {
301
    /// Remove the first n invulnerables from the list of collators. The order should be respected.
302
    fn remove_invulnerables(
303
        collators: &mut Vec<AccountId>,
304
        num_invulnerables: usize,
305
    ) -> Vec<AccountId>;
306
}
307

            
308
impl<AccountId: Clone> RemoveInvulnerables<AccountId> for () {
309
1732
    fn remove_invulnerables(
310
1732
        _collators: &mut Vec<AccountId>,
311
1732
        _num_invulnerables: usize,
312
1732
    ) -> Vec<AccountId> {
313
        // Default impl: no collators are invulnerables
314
1732
        vec![]
315
1732
    }
316
}
317

            
318
/// Helper trait for pallet_collator_assignment to be able to not assign collators to container chains with no credits
319
/// in pallet_services_payment
320
pub trait ParaIdAssignmentHooks<B, AC> {
321
    /// Remove para ids with not enough credits. The resulting order will affect priority: the first para id in the list
322
    /// will be the first one to get collators.
323
    fn pre_assignment(para_ids: &mut Vec<ParaId>, old_assigned: &BTreeSet<ParaId>);
324
    fn post_assignment(
325
        current_assigned: &BTreeSet<ParaId>,
326
        new_assigned: &mut BTreeMap<ParaId, Vec<AC>>,
327
        maybe_tip: &Option<B>,
328
    ) -> Weight;
329

            
330
    /// Make those para ids valid by giving them enough credits, for benchmarking.
331
    #[cfg(feature = "runtime-benchmarks")]
332
    fn make_valid_para_ids(para_ids: &[ParaId]);
333
}
334

            
335
impl<B, AC> ParaIdAssignmentHooks<B, AC> for () {
336
    fn pre_assignment(_para_ids: &mut Vec<ParaId>, _currently_assigned: &BTreeSet<ParaId>) {}
337

            
338
    fn post_assignment(
339
        _current_assigned: &BTreeSet<ParaId>,
340
        _new_assigned: &mut BTreeMap<ParaId, Vec<AC>>,
341
        _maybe_tip: &Option<B>,
342
    ) -> Weight {
343
        Default::default()
344
    }
345

            
346
    #[cfg(feature = "runtime-benchmarks")]
347
    fn make_valid_para_ids(_para_ids: &[ParaId]) {}
348
}
349

            
350
pub trait RelayStorageRootProvider {
351
    fn get_relay_storage_root(relay_block_number: u32) -> Option<H256>;
352

            
353
    #[cfg(feature = "runtime-benchmarks")]
354
    fn set_relay_storage_root(relay_block_number: u32, storage_root: Option<H256>);
355
}
356

            
357
impl RelayStorageRootProvider for () {
358
    fn get_relay_storage_root(_relay_block_number: u32) -> Option<H256> {
359
        None
360
    }
361

            
362
    #[cfg(feature = "runtime-benchmarks")]
363
    fn set_relay_storage_root(_relay_block_number: u32, _storage_root: Option<H256>) {}
364
}
365

            
366
/// Information extracted from the latest container chain header
367
#[derive(
368
    Default,
369
    Clone,
370
    Encode,
371
    Decode,
372
    PartialEq,
373
    sp_core::RuntimeDebug,
374
    scale_info::TypeInfo,
375
    MaxEncodedLen,
376
    Serialize,
377
    Deserialize,
378
)]
379
pub struct ContainerChainBlockInfo<AccountId> {
380
    pub block_number: BlockNumber,
381
    pub author: AccountId,
382
    pub latest_slot_number: Slot,
383
}
384

            
385
pub trait LatestAuthorInfoFetcher<AccountId> {
386
    fn get_latest_author_info(para_id: ParaId) -> Option<ContainerChainBlockInfo<AccountId>>;
387
}
388

            
389
pub trait StorageDeposit<Data, Balance> {
390
    fn compute_deposit(data: &Data) -> Result<Balance, DispatchErrorWithPostInfo>;
391
}
392

            
393
pub struct BytesDeposit<BaseCost, ByteCost>(PhantomData<(BaseCost, ByteCost)>);
394
impl<Data, Balance, BaseCost, ByteCost> StorageDeposit<Data, Balance>
395
    for BytesDeposit<BaseCost, ByteCost>
396
where
397
    Data: Encode,
398
    Balance: TryFrom<usize> + CheckedAdd + CheckedMul,
399
    BaseCost: Get<Balance>,
400
    ByteCost: Get<Balance>,
401
{
402
103
    fn compute_deposit(data: &Data) -> Result<Balance, DispatchErrorWithPostInfo> {
403
103
        let base = BaseCost::get();
404
103
        let byte = ByteCost::get();
405
103
        let size: Balance = data
406
103
            .encoded_size()
407
103
            .try_into()
408
103
            .map_err(|_| ArithmeticError::Overflow)?;
409

            
410
103
        let deposit = byte
411
103
            .checked_mul(&size)
412
103
            .ok_or(ArithmeticError::Overflow)?
413
103
            .checked_add(&base)
414
103
            .ok_or(ArithmeticError::Overflow)?;
415

            
416
103
        Ok(deposit)
417
103
    }
418
}
419

            
420
/// Trait to abstract away relay storage proofs, and allow the same logic to work on both parachains and solochains.
421
/// Parachains should use relay storage proofs, while solochains should read from storage directly.
422
pub trait GenericStorageReader {
423
    fn read_entry<T: Decode>(&self, key: &[u8], fallback: Option<T>) -> Result<T, ReadEntryErr>;
424
}
425

            
426
impl GenericStorageReader for GenericStateProof<cumulus_primitives_core::relay_chain::Block> {
427
142
    fn read_entry<T: Decode>(&self, key: &[u8], fallback: Option<T>) -> Result<T, ReadEntryErr> {
428
142
        GenericStateProof::read_entry(self, key, fallback)
429
142
    }
430
}
431

            
432
/// Solo chain impl, read directly from storage
433
pub struct NativeStorageReader;
434
impl GenericStorageReader for NativeStorageReader {
435
24
    fn read_entry<T: Decode>(&self, key: &[u8], fallback: Option<T>) -> Result<T, ReadEntryErr> {
436
24
        match frame_support::storage::unhashed::get(key).or(fallback) {
437
24
            Some(x) => Ok(x),
438
            None => Err(ReadEntryErr::Absent),
439
        }
440
24
    }
441
}
442

            
443
/// Trait to handle registrar-related operations in a relay-chain context.
444
/// Mostly used to wire Tanssi's and Polkadot's registrars, for them to
445
/// work together in a solo-chain environment.
446
pub trait RegistrarHandler<AccountId> {
447
    fn register(
448
        who: AccountId,
449
        id: ParaId,
450
        genesis_storage: &[ContainerChainGenesisDataItem],
451
        head_data: Option<HeadData>,
452
    ) -> DispatchResult;
453

            
454
    fn schedule_para_upgrade(id: ParaId) -> DispatchResult;
455
    fn schedule_para_downgrade(id: ParaId) -> DispatchResult;
456
    fn deregister(id: ParaId);
457
    fn deregister_weight() -> Weight;
458

            
459
    #[cfg(feature = "runtime-benchmarks")]
460
    fn bench_head_data() -> Option<HeadData> {
461
        None
462
    }
463
    #[cfg(feature = "runtime-benchmarks")]
464
    fn add_trusted_validation_code(_code: Vec<u8>) {}
465
    #[cfg(feature = "runtime-benchmarks")]
466
    fn registrar_new_session(_session: u32) {}
467
    #[cfg(feature = "runtime-benchmarks")]
468
    fn prepare_chain_registration(_id: ParaId, _who: AccountId) {}
469
}
470

            
471
impl<AccountId> RegistrarHandler<AccountId> for () {
472
63
    fn register(
473
63
        _who: AccountId,
474
63
        _id: ParaId,
475
63
        _genesis_storage: &[ContainerChainGenesisDataItem],
476
63
        _head_data: Option<HeadData>,
477
63
    ) -> DispatchResult {
478
63
        Ok(())
479
63
    }
480

            
481
40
    fn schedule_para_upgrade(_id: ParaId) -> DispatchResult {
482
40
        Ok(())
483
40
    }
484

            
485
10
    fn schedule_para_downgrade(_id: ParaId) -> DispatchResult {
486
10
        Ok(())
487
10
    }
488

            
489
    fn deregister(_id: ParaId) {}
490

            
491
    fn deregister_weight() -> Weight {
492
        Weight::default()
493
    }
494
}
495

            
496
/// Trait to retrieve the orchestrator block author (if any).
497
/// In a relay-chain context we will return None.
498
pub trait MaybeSelfChainBlockAuthor<AccountId> {
499
    fn get_block_author() -> Option<AccountId>;
500
}
501

            
502
impl<AccountId> MaybeSelfChainBlockAuthor<AccountId> for () {
503
15548
    fn get_block_author() -> Option<AccountId> {
504
15548
        None
505
15548
    }
506
}
507

            
508
/// Information regarding the active era (era in used in session).
509
#[derive(Clone, Encode, Decode, RuntimeDebug, TypeInfo, MaxEncodedLen)]
510
pub struct ActiveEraInfo {
511
    /// Index of era.
512
    pub index: EraIndex,
513
    /// Moment of start expressed as millisecond from `$UNIX_EPOCH`.
514
    ///
515
    /// Start can be none if start hasn't been set for the era yet,
516
    /// Start is set on the first on_finalize of the era to guarantee usage of `Time`.
517
    pub start: Option<u64>,
518
}
519

            
520
/// Counter for the number of eras that have passed.
521
pub type EraIndex = u32;
522

            
523
pub trait EraIndexProvider {
524
    fn active_era() -> ActiveEraInfo;
525
    fn era_to_session_start(era_index: EraIndex) -> Option<u32>;
526
}
527

            
528
pub trait ValidatorProvider<ValidatorId> {
529
    fn validators() -> Vec<ValidatorId>;
530
}
531

            
532
pub trait InvulnerablesProvider<ValidatorId> {
533
    fn invulnerables() -> Vec<ValidatorId>;
534
}
535

            
536
pub trait OnEraStart {
537
    fn on_era_start(_era_index: EraIndex, _session_start: u32, _external_idx: u64) {}
538
}
539

            
540
#[impl_trait_for_tuples::impl_for_tuples(5)]
541
impl OnEraStart for Tuple {
542
1183
    fn on_era_start(era_index: EraIndex, session_start: u32, external_idx: u64) {
543
1183
        for_tuples!( #( Tuple::on_era_start(era_index, session_start, external_idx); )* );
544
1183
    }
545
}
546

            
547
pub trait OnEraEnd {
548
    fn on_era_end(_era_index: EraIndex) {}
549
}
550

            
551
#[impl_trait_for_tuples::impl_for_tuples(5)]
552
impl OnEraEnd for Tuple {
553
    fn on_era_end(era_index: EraIndex) {
554
        for_tuples!( #( Tuple::on_era_end(era_index); )* );
555
    }
556
}
557

            
558
/// Strategy to use when rotating collators. Default: rotate all of them. Allows to rotate only a random subset.
559
#[derive(
560
    Clone,
561
    Debug,
562
    Default,
563
    Encode,
564
    Decode,
565
    DecodeWithMemTracking,
566
    scale_info::TypeInfo,
567
    PartialEq,
568
    Eq,
569
    Serialize,
570
    Deserialize,
571
    MaxEncodedLen,
572
)]
573
pub enum FullRotationMode {
574
    #[default]
575
    RotateAll,
576
    KeepAll,
577
    /// Keep this many collators
578
    KeepCollators {
579
        keep: u32,
580
    },
581
    /// Keep a ratio of collators wrt to max collators.
582
    /// If max collators changes, the number of collators kept also changes.
583
    KeepPerbill {
584
        percentage: Perbill,
585
    },
586
}
587

            
588
/// Allow to set a different [FullRotationMode] for each kind of chain. Default: rotate all.
589
#[derive(
590
    Clone,
591
    Debug,
592
    Default,
593
    Encode,
594
    DecodeWithMemTracking,
595
    Decode,
596
    scale_info::TypeInfo,
597
    PartialEq,
598
    Eq,
599
    Serialize,
600
    Deserialize,
601
    MaxEncodedLen,
602
)]
603
pub struct FullRotationModes {
604
    pub orchestrator: FullRotationMode,
605
    pub parachain: FullRotationMode,
606
    pub parathread: FullRotationMode,
607
}
608

            
609
impl FullRotationModes {
610
    /// Keep all collators assigned to their current chain if possible. This is equivalent to disabling rotation.
611
56927
    pub fn keep_all() -> Self {
612
56927
        Self {
613
56927
            orchestrator: FullRotationMode::KeepAll,
614
56927
            parachain: FullRotationMode::KeepAll,
615
56927
            parathread: FullRotationMode::KeepAll,
616
56927
        }
617
56927
    }
618
}
619

            
620
// A trait to retrieve the external index provider identifying some set of data
621
// In starlight, used to retrieve the external index associated to validators
622
pub trait ExternalIndexProvider {
623
    fn get_external_index() -> u64;
624
}
625

            
626
// A trait to check invulnerables
627
pub trait InvulnerablesHelper<AccountId> {
628
    /// Checks if the given `AccountId` is invulnerable.
629
    fn is_invulnerable(account_id: &AccountId) -> bool;
630
}
631

            
632
// A trait to verify the inactivity status of nodes
633
// and handle the offline status of nodes
634
pub trait NodeActivityTrackingHelper<AccountId> {
635
    /// Check if a node is inactive.
636
    fn is_node_inactive(node: &AccountId) -> bool;
637
    /// Check if a node is offline.
638
    fn is_node_offline(node: &AccountId) -> bool;
639
    #[cfg(feature = "runtime-benchmarks")]
640
    /// Marks online node as online
641
    fn make_node_online(node: &AccountId);
642
    /// Marks node as inactive for the current activity window so it could be notified as inactive
643
    #[cfg(feature = "runtime-benchmarks")]
644
    fn make_node_inactive(node: &AccountId);
645
}
646

            
647
// A trait to help verify if a ParaId is a chain or parathread
648
pub trait ParathreadHelper {
649
    fn get_parathreads_for_session() -> BTreeSet<ParaId>;
650
}
651

            
652
// A trait to help updating the collators rewards when a collator's online status changes.
653
pub trait StakingCandidateHelper<AccountId> {
654
    /// Check if the candidate is in SortedEligibleCandidates list.
655
    fn is_candidate_selected(candidate: &AccountId) -> bool;
656
    /// Updates stake when candidate's online status change.
657
    fn on_online_status_change(
658
        candidate: &AccountId,
659
        is_online: bool,
660
    ) -> DispatchResultWithPostInfo;
661
    /// Benchmarking helper function that makes collator part of the SortedEligibleCollators list.
662
    #[cfg(feature = "runtime-benchmarks")]
663
    fn make_collator_eligible_candidate(collator: &AccountId);
664
}