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
pub mod alias;
23
pub mod prod_or_fast;
24

            
25
pub use {
26
    alias::*,
27
    cumulus_primitives_core::{
28
        relay_chain::{BlockNumber, HeadData, Slot, ValidationCode},
29
        ParaId,
30
    },
31
    dp_chain_state_snapshot::{GenericStateProof, ReadEntryErr},
32
    dp_container_chain_genesis_data::ContainerChainGenesisDataItem,
33
};
34
use {
35
    core::marker::PhantomData,
36
    frame_support::{
37
        dispatch::DispatchErrorWithPostInfo,
38
        pallet_prelude::{Decode, DispatchResultWithPostInfo, Encode, Get, MaxEncodedLen, Weight},
39
        BoundedVec,
40
    },
41
    scale_info::TypeInfo,
42
    serde::{Deserialize, Serialize},
43
    sp_core::H256,
44
    sp_runtime::{
45
        app_crypto::sp_core,
46
        traits::{CheckedAdd, CheckedMul},
47
        ArithmeticError, DispatchResult, Perbill, RuntimeDebug,
48
    },
49
    sp_std::{
50
        collections::{btree_map::BTreeMap, btree_set::BTreeSet},
51
        vec::Vec,
52
    },
53
};
54

            
55
// Separate import as rustfmt wrongly change it to `sp_std::vec::self`, which is the module instead
56
// of the macro.
57
use sp_std::vec;
58

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

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

            
84
/// Container chains collator assignment tip prioritization on congestion.
85
/// Tips paras are willing to pay for collator assignment in case of collators demand
86
/// surpasses the offer.
87
pub trait CollatorAssignmentTip<Balance> {
88
    fn get_para_tip(a: ParaId) -> Option<Balance>;
89
}
90

            
91
impl<Balance> CollatorAssignmentTip<Balance> for () {
92
    fn get_para_tip(_: ParaId) -> Option<Balance> {
93
        None
94
    }
95
}
96

            
97
pub struct AuthorNotingInfo<AccountId> {
98
    pub author: AccountId,
99
    pub block_number: BlockNumber,
100
    pub para_id: ParaId,
101
}
102

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

            
110
    #[cfg(feature = "runtime-benchmarks")]
111
    fn prepare_worst_case_for_bench(author: &AccountId, block_number: BlockNumber, para_id: ParaId);
112
}
113

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

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

            
128
pub trait DistributeRewards<AccountId, Imbalance> {
129
    fn distribute_rewards(rewarded: AccountId, amount: Imbalance) -> DispatchResultWithPostInfo;
130
}
131

            
132
impl<AccountId, Imbalance> DistributeRewards<AccountId, Imbalance> for () {
133
26
    fn distribute_rewards(_rewarded: AccountId, _amount: Imbalance) -> DispatchResultWithPostInfo {
134
26
        Ok(().into())
135
26
    }
136
}
137

            
138
/// Get the current list of container chains parachain ids.
139
pub trait GetCurrentContainerChains {
140
    type MaxContainerChains: Get<u32>;
141

            
142
    fn current_container_chains() -> BoundedVec<ParaId, Self::MaxContainerChains>;
143

            
144
    #[cfg(feature = "runtime-benchmarks")]
145
    fn set_current_container_chains(container_chains: &[ParaId]);
146
}
147

            
148
#[derive(Copy, Clone, PartialEq, Eq)]
149
pub enum ForSession {
150
    Current,
151
    Next,
152
}
153

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

            
159
    fn get_all_collators_assigned_to_chains(for_session: ForSession) -> BTreeSet<AccountId>;
160

            
161
    #[cfg(feature = "runtime-benchmarks")]
162
    fn set_container_chains_with_collators(
163
        for_session: ForSession,
164
        container_chains: &[(ParaId, Vec<AccountId>)],
165
    );
166
}
167

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

            
194
impl SlotFrequency {
195
1074
    pub fn should_parathread_buy_core(
196
1074
        &self,
197
1074
        current_slot: Slot,
198
1074
        max_slot_required_to_complete_purchase: Slot,
199
1074
        last_block_slot: Slot,
200
1074
    ) -> bool {
201
1074
        current_slot
202
1074
            >= last_block_slot
203
1074
                .saturating_add(Slot::from(u64::from(self.min)))
204
1074
                .saturating_sub(max_slot_required_to_complete_purchase)
205
1074
    }
206

            
207
    pub fn should_parathread_author_block(
208
        &self,
209
        current_slot: Slot,
210
        last_block_slot: Slot,
211
    ) -> bool {
212
        current_slot >= last_block_slot.saturating_add(Slot::from(u64::from(self.min)))
213
    }
214
}
215

            
216
impl Default for SlotFrequency {
217
675
    fn default() -> Self {
218
675
        Self { min: 1, max: 1 }
219
675
    }
220
}
221

            
222
#[derive(
223
    Clone,
224
    Debug,
225
    Encode,
226
    Decode,
227
1236
    scale_info::TypeInfo,
228
    PartialEq,
229
    Eq,
230
    Serialize,
231
    Deserialize,
232
    MaxEncodedLen,
233
)]
234
pub struct ParathreadParams {
235
    pub slot_frequency: SlotFrequency,
236
}
237

            
238
#[derive(Clone, Debug, Encode, Decode, scale_info::TypeInfo, PartialEq, Eq)]
239
pub struct SessionContainerChains {
240
    pub parachains: Vec<ParaId>,
241
    pub parathreads: Vec<(ParaId, ParathreadParams)>,
242
}
243

            
244
/// Get the list of container chains parachain ids at given
245
/// session index.
246
pub trait GetSessionContainerChains<SessionIndex> {
247
    fn session_container_chains(session_index: SessionIndex) -> SessionContainerChains;
248
    #[cfg(feature = "runtime-benchmarks")]
249
    fn set_session_container_chains(session_index: SessionIndex, container_chains: &[ParaId]);
250
}
251

            
252
/// Returns author for a parachain id for the given slot.
253
pub trait GetContainerChainAuthor<AccountId> {
254
    fn author_for_slot(slot: Slot, para_id: ParaId) -> Option<AccountId>;
255
    #[cfg(feature = "runtime-benchmarks")]
256
    fn set_authors_for_para_id(para_id: ParaId, authors: Vec<AccountId>);
257
}
258

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

            
274
/// Returns current session index.
275
pub trait GetSessionIndex<SessionIndex> {
276
    fn session_index() -> SessionIndex;
277

            
278
    #[cfg(feature = "runtime-benchmarks")]
279
    fn skip_to_session(session_index: SessionIndex);
280
}
281

            
282
/// Should pallet_collator_assignment trigger a full rotation on this session?
283
pub trait ShouldRotateAllCollators<SessionIndex> {
284
    fn should_rotate_all_collators(session_index: SessionIndex) -> bool;
285
}
286

            
287
impl<SessionIndex> ShouldRotateAllCollators<SessionIndex> for () {
288
    fn should_rotate_all_collators(_session_index: SessionIndex) -> bool {
289
        false
290
    }
291
}
292

            
293
/// Helper trait for pallet_collator_assignment to be able to give priority to invulnerables
294
pub trait RemoveInvulnerables<AccountId> {
295
    /// Remove the first n invulnerables from the list of collators. The order should be respected.
296
    fn remove_invulnerables(
297
        collators: &mut Vec<AccountId>,
298
        num_invulnerables: usize,
299
    ) -> Vec<AccountId>;
300
}
301

            
302
impl<AccountId: Clone> RemoveInvulnerables<AccountId> for () {
303
1193
    fn remove_invulnerables(
304
1193
        _collators: &mut Vec<AccountId>,
305
1193
        _num_invulnerables: usize,
306
1193
    ) -> Vec<AccountId> {
307
1193
        // Default impl: no collators are invulnerables
308
1193
        vec![]
309
1193
    }
310
}
311

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

            
324
    /// Make those para ids valid by giving them enough credits, for benchmarking.
325
    #[cfg(feature = "runtime-benchmarks")]
326
    fn make_valid_para_ids(para_ids: &[ParaId]);
327
}
328

            
329
impl<B, AC> ParaIdAssignmentHooks<B, AC> for () {
330
    fn pre_assignment(_para_ids: &mut Vec<ParaId>, _currently_assigned: &BTreeSet<ParaId>) {}
331

            
332
    fn post_assignment(
333
        _current_assigned: &BTreeSet<ParaId>,
334
        _new_assigned: &mut BTreeMap<ParaId, Vec<AC>>,
335
        _maybe_tip: &Option<B>,
336
    ) -> Weight {
337
        Default::default()
338
    }
339

            
340
    #[cfg(feature = "runtime-benchmarks")]
341
    fn make_valid_para_ids(_para_ids: &[ParaId]) {}
342
}
343

            
344
pub trait RelayStorageRootProvider {
345
    fn get_relay_storage_root(relay_block_number: u32) -> Option<H256>;
346

            
347
    #[cfg(feature = "runtime-benchmarks")]
348
    fn set_relay_storage_root(relay_block_number: u32, storage_root: Option<H256>);
349
}
350

            
351
impl RelayStorageRootProvider for () {
352
    fn get_relay_storage_root(_relay_block_number: u32) -> Option<H256> {
353
        None
354
    }
355

            
356
    #[cfg(feature = "runtime-benchmarks")]
357
    fn set_relay_storage_root(_relay_block_number: u32, _storage_root: Option<H256>) {}
358
}
359

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

            
379
pub trait LatestAuthorInfoFetcher<AccountId> {
380
    fn get_latest_author_info(para_id: ParaId) -> Option<ContainerChainBlockInfo<AccountId>>;
381
}
382

            
383
pub trait StorageDeposit<Data, Balance> {
384
    fn compute_deposit(data: &Data) -> Result<Balance, DispatchErrorWithPostInfo>;
385
}
386

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

            
404
194
        let deposit = byte
405
194
            .checked_mul(&size)
406
194
            .ok_or(ArithmeticError::Overflow)?
407
194
            .checked_add(&base)
408
194
            .ok_or(ArithmeticError::Overflow)?;
409

            
410
194
        Ok(deposit)
411
194
    }
412
}
413

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

            
420
impl GenericStorageReader for GenericStateProof<cumulus_primitives_core::relay_chain::Block> {
421
23482
    fn read_entry<T: Decode>(&self, key: &[u8], fallback: Option<T>) -> Result<T, ReadEntryErr> {
422
23482
        GenericStateProof::read_entry(self, key, fallback)
423
23482
    }
424
}
425

            
426
/// Solo chain impl, read directly from storage
427
pub struct NativeStorageReader;
428
impl GenericStorageReader for NativeStorageReader {
429
22
    fn read_entry<T: Decode>(&self, key: &[u8], fallback: Option<T>) -> Result<T, ReadEntryErr> {
430
22
        match frame_support::storage::unhashed::get(key).or(fallback) {
431
22
            Some(x) => Ok(x),
432
            None => Err(ReadEntryErr::Absent),
433
        }
434
22
    }
435
}
436

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

            
448
    fn schedule_para_upgrade(id: ParaId) -> DispatchResult;
449
    fn schedule_para_downgrade(id: ParaId) -> DispatchResult;
450
    fn deregister(id: ParaId);
451
    fn deregister_weight() -> Weight;
452

            
453
    #[cfg(feature = "runtime-benchmarks")]
454
    fn bench_head_data() -> Option<HeadData> {
455
        None
456
    }
457
    #[cfg(feature = "runtime-benchmarks")]
458
    fn add_trusted_validation_code(_code: Vec<u8>) {}
459
    #[cfg(feature = "runtime-benchmarks")]
460
    fn registrar_new_session(_session: u32) {}
461
    #[cfg(feature = "runtime-benchmarks")]
462
    fn prepare_chain_registration(_id: ParaId, _who: AccountId) {}
463
}
464

            
465
impl<AccountId> RegistrarHandler<AccountId> for () {
466
151
    fn register(
467
151
        _who: AccountId,
468
151
        _id: ParaId,
469
151
        _genesis_storage: &[ContainerChainGenesisDataItem],
470
151
        _head_data: Option<HeadData>,
471
151
    ) -> DispatchResult {
472
151
        Ok(())
473
151
    }
474

            
475
64
    fn schedule_para_upgrade(_id: ParaId) -> DispatchResult {
476
64
        Ok(())
477
64
    }
478

            
479
70
    fn schedule_para_downgrade(_id: ParaId) -> DispatchResult {
480
70
        Ok(())
481
70
    }
482

            
483
42
    fn deregister(_id: ParaId) {}
484

            
485
42
    fn deregister_weight() -> Weight {
486
42
        Weight::default()
487
42
    }
488
}
489

            
490
/// Trait to retrieve the orchestrator block author (if any).
491
/// In a relay-chain context we will return None.
492
pub trait MaybeSelfChainBlockAuthor<AccountId> {
493
    fn get_block_author() -> Option<AccountId>;
494
}
495

            
496
impl<AccountId> MaybeSelfChainBlockAuthor<AccountId> for () {
497
14169
    fn get_block_author() -> Option<AccountId> {
498
14169
        None
499
14169
    }
500
}
501

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

            
514
/// Counter for the number of eras that have passed.
515
pub type EraIndex = u32;
516

            
517
pub trait EraIndexProvider {
518
    fn active_era() -> ActiveEraInfo;
519
    fn era_to_session_start(era_index: EraIndex) -> Option<u32>;
520
}
521

            
522
pub trait ValidatorProvider<ValidatorId> {
523
    fn validators() -> Vec<ValidatorId>;
524
}
525

            
526
pub trait InvulnerablesProvider<ValidatorId> {
527
    fn invulnerables() -> Vec<ValidatorId>;
528
}
529

            
530
pub trait OnEraStart {
531
    fn on_era_start(_era_index: EraIndex, _session_start: u32, _external_idx: u64) {}
532
}
533

            
534
#[impl_trait_for_tuples::impl_for_tuples(5)]
535
impl OnEraStart for Tuple {
536
681
    fn on_era_start(era_index: EraIndex, session_start: u32, external_idx: u64) {
537
681
        for_tuples!( #( Tuple::on_era_start(era_index, session_start, external_idx); )* );
538
681
    }
539
}
540

            
541
pub trait OnEraEnd {
542
    fn on_era_end(_era_index: EraIndex) {}
543
}
544

            
545
#[impl_trait_for_tuples::impl_for_tuples(5)]
546
impl OnEraEnd for Tuple {
547
    fn on_era_end(era_index: EraIndex) {
548
        for_tuples!( #( Tuple::on_era_end(era_index); )* );
549
    }
550
}
551

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

            
581
/// Allow to set a different [FullRotationMode] for each kind of chain. Default: rotate all.
582
#[derive(
583
    Clone,
584
    Debug,
585
    Default,
586
    Encode,
587
    Decode,
588
3708
    scale_info::TypeInfo,
589
    PartialEq,
590
    Eq,
591
    Serialize,
592
    Deserialize,
593
    MaxEncodedLen,
594
)]
595
pub struct FullRotationModes {
596
    pub orchestrator: FullRotationMode,
597
    pub parachain: FullRotationMode,
598
    pub parathread: FullRotationMode,
599
}
600

            
601
impl FullRotationModes {
602
    /// Keep all collators assigned to their current chain if possible. This is equivalent to disabling rotation.
603
49856
    pub fn keep_all() -> Self {
604
49856
        Self {
605
49856
            orchestrator: FullRotationMode::KeepAll,
606
49856
            parachain: FullRotationMode::KeepAll,
607
49856
            parathread: FullRotationMode::KeepAll,
608
49856
        }
609
49856
    }
610
}
611

            
612
// A trait to retrieve the external index provider identifying some set of data
613
// In starlight, used to retrieve the external index associated to validators
614
pub trait ExternalIndexProvider {
615
    fn get_external_index() -> u64;
616
}
617

            
618
// A trait to verify if a node has been inactive during the last minimum activity
619
pub trait NodeActivityTrackingHelper<AccountId> {
620
    fn is_node_inactive(node: &AccountId) -> bool;
621
}
622

            
623
// A trait to help verify if a ParaId is a chain or parathread
624
pub trait ParathreadHelper {
625
    fn get_parathreads_for_session() -> BTreeSet<ParaId>;
626
}