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
#![cfg(test)]
17

            
18
use {
19
    crate::{
20
        tests::common::*, InactivityTracking, MinimumSelfDelegation, PooledStaking,
21
        TanssiCollatorAssignment, TanssiInvulnerables,
22
    },
23
    frame_support::assert_ok,
24
    pallet_pooled_staking::{ActivePoolKind, SortedEligibleCandidates},
25
    tp_traits::NodeActivityTrackingHelper,
26
};
27

            
28
2
fn init_test_setup() {
29
    // Ensure that BOB is not an invulnerable collator and is part of the sorted eligible candidates list.
30
2
    assert_ok!(TanssiInvulnerables::remove_invulnerable(
31
2
        root_origin(),
32
2
        BOB.into()
33
    ));
34
2
    assert_ok!(TanssiInvulnerables::remove_invulnerable(
35
2
        root_origin(),
36
2
        CHARLIE.into()
37
    ));
38
2
    let stake = MinimumSelfDelegation::get() * 10;
39
2
    assert_ok!(PooledStaking::request_delegate(
40
2
        origin_of(BOB.into()),
41
2
        BOB.into(),
42
2
        ActivePoolKind::AutoCompounding,
43
2
        stake
44
    ));
45
2
    assert_ok!(PooledStaking::request_delegate(
46
2
        origin_of(CHARLIE.into()),
47
2
        CHARLIE.into(),
48
2
        ActivePoolKind::AutoCompounding,
49
2
        stake
50
    ));
51
    // Verify that BOB is
52
    //- a non-invulnerable collator
53
    //- assigned to a container chain
54
    //- part of the sorted eligible candidates list.
55
2
    assert!(!TanssiInvulnerables::invulnerables().contains(&BOB.into()));
56
2
    assert!(TanssiCollatorAssignment::collator_container_chain()
57
2
        .container_chains
58
2
        .iter()
59
2
        .any(|(_, collators)| collators.contains(&BOB.into())));
60
2
    assert!(<SortedEligibleCandidates<Runtime>>::get()
61
2
        .iter()
62
2
        .any(|c| c.candidate == BOB.into()));
63
    // Enable offline marking.
64
2
    assert_ok!(InactivityTracking::enable_offline_marking(
65
2
        root_origin(),
66
        true
67
    ));
68
2
}
69

            
70
#[test]
71
1
fn set_collator_offline_using_set_offline_removes_it_from_assigned_collators_and_sorted_eligible_candidates(
72
1
) {
73
1
    ExtBuilder::default()
74
1
        .with_config(pallet_configuration::HostConfiguration {
75
1
            max_collators: 100,
76
1
            min_orchestrator_collators: 0,
77
1
            max_orchestrator_collators: 0,
78
1
            collators_per_container: 2,
79
1
            ..Default::default()
80
1
        })
81
1
        .with_balances(vec![
82
1
            // BOB gets 10k extra tokens for his mapping deposit
83
1
            (AccountId::from(ALICE), 100_000 * UNIT),
84
1
            (AccountId::from(BOB), 210_000 * UNIT),
85
1
            (AccountId::from(CHARLIE), 210_000 * UNIT),
86
1
            (AccountId::from(DAVE), 100_000 * UNIT),
87
1
        ])
88
1
        .with_collators(vec![
89
1
            (AccountId::from(ALICE), 100 * UNIT),
90
1
            (AccountId::from(BOB), 210 * UNIT),
91
1
            (AccountId::from(CHARLIE), 210 * UNIT),
92
1
            (AccountId::from(DAVE), 100 * UNIT),
93
1
        ])
94
1
        .with_empty_parachains(vec![3001u32, 3002u32])
95
1
        .build()
96
1
        .execute_with(|| {
97
1
            init_test_setup();
98
1
            let pending_assignment_before_offline_marking =
99
1
                TanssiCollatorAssignment::pending_collator_container_chain();
100
1
            assert!(pending_assignment_before_offline_marking.is_some());
101
1
            assert!(pending_assignment_before_offline_marking
102
1
                .unwrap()
103
1
                .container_chains
104
1
                .iter()
105
1
                .any(|(_, collators)| collators.contains(&BOB.into())));
106
1
            assert!(!InactivityTracking::is_node_offline(&BOB.into()));
107
1
            assert_ok!(InactivityTracking::set_offline(origin_of(BOB.into())));
108
1
            assert!(InactivityTracking::is_node_offline(&BOB.into()));
109
            // Since, BOB is in the current pending assignment, we need to wait uintil session 2
110
            // before it can be removed from the container chain assignment.
111
1
            run_to_session(2);
112
1
            run_block();
113
            // Verify that after being set offline, BOB is no longer:
114
            // - assigned to any container chain
115
            // - in the sorted eligible candidates list
116
1
            assert!(!TanssiCollatorAssignment::collator_container_chain()
117
1
                .container_chains
118
1
                .iter()
119
2
                .any(|(_, collators)| collators.contains(&BOB.into())));
120
1
            assert!(!<SortedEligibleCandidates<Runtime>>::get()
121
1
                .iter()
122
1
                .any(|c| c.candidate == BOB.into()));
123
1
        });
124
1
}
125

            
126
#[test]
127
1
fn set_collator_online_adds_it_to_assigned_collators_and_sorted_eligible_candidates() {
128
1
    ExtBuilder::default()
129
1
        .with_config(pallet_configuration::HostConfiguration {
130
1
            max_collators: 100,
131
1
            min_orchestrator_collators: 0,
132
1
            max_orchestrator_collators: 0,
133
1
            collators_per_container: 2,
134
1
            ..Default::default()
135
1
        })
136
1
        .with_balances(vec![
137
1
            // BOB gets 10k extra tokens for his mapping deposit
138
1
            (AccountId::from(ALICE), 100_000 * UNIT),
139
1
            (AccountId::from(BOB), 210_000 * UNIT),
140
1
            (AccountId::from(CHARLIE), 210_000 * UNIT),
141
1
            (AccountId::from(DAVE), 100_000 * UNIT),
142
1
        ])
143
1
        .with_collators(vec![
144
1
            (AccountId::from(ALICE), 100 * UNIT),
145
1
            (AccountId::from(BOB), 210 * UNIT),
146
1
            (AccountId::from(CHARLIE), 210 * UNIT),
147
1
            (AccountId::from(DAVE), 100 * UNIT),
148
1
        ])
149
1
        .with_empty_parachains(vec![3001u32, 3002u32])
150
1
        .build()
151
1
        .execute_with(|| {
152
1
            init_test_setup();
153
1
            assert!(!InactivityTracking::is_node_offline(&BOB.into()));
154
1
            assert_ok!(InactivityTracking::set_offline(origin_of(BOB.into())));
155
            // Since, BOB is in the current pending assignment, we need to wait uintil session 2
156
            // before it can be removed from the container chain assignment.
157
1
            run_to_session(2);
158
1
            run_block();
159
1
            assert!(InactivityTracking::is_node_offline(&BOB.into()));
160
1
            assert_ok!(InactivityTracking::set_online(origin_of(BOB.into())));
161
1
            assert!(!InactivityTracking::is_node_offline(&BOB.into()));
162
            // Since BOB is set online but not included in the current pending assignment,
163
            // we need to wait at least 2 session before it can be assigned to a container chain.
164
1
            let initial_pending_assignment_after_online_marking =
165
1
                TanssiCollatorAssignment::pending_collator_container_chain();
166
1
            assert!(initial_pending_assignment_after_online_marking.is_none());
167
1
            run_to_session(3);
168
1
            run_block();
169
1
            let pending_assignment_after_online_marking =
170
1
                TanssiCollatorAssignment::pending_collator_container_chain();
171
1
            assert!(pending_assignment_after_online_marking.is_some());
172
1
            assert!(pending_assignment_after_online_marking
173
1
                .unwrap()
174
1
                .container_chains
175
1
                .iter()
176
2
                .any(|(_, collators)| collators.contains(&BOB.into())));
177
1
            run_to_session(4);
178
1
            run_block();
179
            // Verify that after being set online, BOB is:
180
            // - assigned to any container chain
181
            // - in the sorted eligible candidates list
182
1
            assert!(TanssiCollatorAssignment::collator_container_chain()
183
1
                .container_chains
184
1
                .iter()
185
2
                .any(|(_, collators)| collators.contains(&BOB.into())));
186
1
            assert!(<SortedEligibleCandidates<Runtime>>::get()
187
1
                .iter()
188
1
                .any(|c| c.candidate == BOB.into()));
189
1
        });
190
1
}