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

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

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