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
use {
18
    core::{fmt::Debug, marker::PhantomData},
19
    frame_system::pallet_prelude::BlockNumberFor,
20
    parity_scale_codec::{FullCodec, MaxEncodedLen},
21
    scale_info::TypeInfo,
22
    sp_runtime::traits::{CheckedAdd, Get},
23
};
24

            
25
/// Allows to get the current instant and check if some duration is elapsed.
26
pub trait Timer {
27
    /// Type for the instant. Must implement some traits to be used easily with
28
    /// the Pooled Staking pallet.
29
    type Instant: FullCodec + TypeInfo + Clone + Debug + Eq + MaxEncodedLen;
30

            
31
    /// Get the current instant.
32
    fn now() -> Self::Instant;
33

            
34
    /// Check if the timer started at `started` is elapsed.
35
    fn is_elapsed(start: &Self::Instant) -> bool;
36

            
37
    /// Returns an instant that will make `is_elapsed` true.
38
    #[cfg(feature = "runtime-benchmarks")]
39
    fn elapsed_instant() -> Self::Instant;
40

            
41
    /// Skip to a state where `now` will make `is_elapsed` true.
42
    #[cfg(feature = "runtime-benchmarks")]
43
    fn skip_to_elapsed();
44
}
45

            
46
/// A timer using block numbers.
47
/// `T` is the Runtime type while `G` is a getter for the delay.
48
pub struct BlockNumberTimer<T, G>(PhantomData<(T, G)>);
49

            
50
impl<T, G> Timer for BlockNumberTimer<T, G>
51
where
52
    T: frame_system::Config,
53
    G: Get<BlockNumberFor<T>>,
54
{
55
    type Instant = BlockNumberFor<T>;
56

            
57
159
    fn now() -> Self::Instant {
58
159
        frame_system::Pallet::<T>::block_number()
59
159
    }
60

            
61
70
    fn is_elapsed(start: &Self::Instant) -> bool {
62
70
        let delay = G::get();
63
70
        let Some(end) = start.checked_add(&delay) else {
64
            return false;
65
        };
66
70
        end <= Self::now()
67
70
    }
68

            
69
    #[cfg(feature = "runtime-benchmarks")]
70
    fn elapsed_instant() -> Self::Instant {
71
        let delay = G::get();
72
        Self::now()
73
            .checked_add(&delay)
74
            .expect("overflow when computing valid elapsed instant")
75
    }
76

            
77
    #[cfg(feature = "runtime-benchmarks")]
78
    fn skip_to_elapsed() {
79
        frame_system::Pallet::<T>::set_block_number(Self::elapsed_instant());
80
    }
81
}
82

            
83
/// Allows knowing if some account is eligible to be a candidate.
84
pub trait IsCandidateEligible<AccountId> {
85
    /// Is the provided account id eligible?
86
    fn is_candidate_eligible(a: &AccountId) -> bool;
87

            
88
    /// Make the provided account id eligible if `eligible` is true, and not
89
    /// eligible if false.
90
    #[cfg(feature = "runtime-benchmarks")]
91
    fn make_candidate_eligible(a: &AccountId, eligible: bool);
92
}
93

            
94
impl<AccountId> IsCandidateEligible<AccountId> for () {
95
29
    fn is_candidate_eligible(_: &AccountId) -> bool {
96
29
        true
97
29
    }
98

            
99
    #[cfg(feature = "runtime-benchmarks")]
100
    fn make_candidate_eligible(_: &AccountId, _: bool) {}
101
}