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

            
19
use {
20
    crate::{tests::common::*, ContainerRegistrar, Paras, Registrar, ServicesPayment},
21
    alloc::vec,
22
    cumulus_primitives_core::{relay_chain::HeadData, ParaId},
23
    frame_support::{assert_noop, assert_ok, pallet_prelude::DispatchResultWithPostInfo},
24
    sp_runtime::DispatchError,
25
};
26

            
27
#[test]
28
1
fn test_can_buy_credits_before_registering_para() {
29
1
    ExtBuilder::default()
30
1
        .with_balances(vec![
31
1
            // Alice gets 10k extra tokens for her mapping deposit
32
1
            (AccountId::from(ALICE), 210_000 * UNIT),
33
1
            (AccountId::from(BOB), 100_000 * UNIT),
34
1
            (AccountId::from(CHARLIE), 100_000 * UNIT),
35
1
            (AccountId::from(DAVE), 100_000 * UNIT),
36
1
        ])
37
1
        .with_collators(vec![
38
1
            (AccountId::from(ALICE), 210 * UNIT),
39
1
            (AccountId::from(BOB), 100 * UNIT),
40
1
            (AccountId::from(CHARLIE), 100 * UNIT),
41
1
            (AccountId::from(DAVE), 100 * UNIT),
42
1
        ])
43
1
        .build()
44
1
        .execute_with(|| {
45
1
            run_to_block(2);
46

            
47
1
            let blocks_number = 1_000_000;
48
            // Try to buy the maximum amount of credits
49
1
            let balance_before = System::account(AccountId::from(ALICE)).data.free;
50
1
            assert_ok!(ServicesPayment::purchase_credits(
51
1
                origin_of(ALICE.into()),
52
1
                2000.into(),
53
1
                block_credits_to_required_balance(blocks_number, 2000.into())
54
            ));
55
1
            let balance_after = System::account(AccountId::from(ALICE)).data.free;
56

            
57
            // Now parachain tank should have this amount
58
1
            let balance_tank = System::account(ServicesPayment::parachain_tank(2000.into()))
59
1
                .data
60
1
                .free;
61

            
62
1
            assert_eq!(
63
                balance_tank,
64
1
                block_credits_to_required_balance(blocks_number, 2000.into())
65
            );
66

            
67
1
            let expected_cost = block_credits_to_required_balance(blocks_number, 2000.into());
68
1
            assert_eq!(balance_before - balance_after, expected_cost);
69
1
        });
70
1
}
71

            
72
#[test]
73
1
fn test_can_buy_credits_before_registering_para_and_receive_free_credits() {
74
1
    ExtBuilder::default()
75
1
        .with_balances(vec![
76
1
            // Alice gets 10k extra tokens for her mapping deposit
77
1
            (AccountId::from(ALICE), 210_000 * UNIT),
78
1
            (AccountId::from(BOB), 100_000 * UNIT),
79
1
            (AccountId::from(CHARLIE), 100_000 * UNIT),
80
1
            (AccountId::from(DAVE), 100_000 * UNIT),
81
1
        ])
82
1
        .with_collators(vec![
83
1
            (AccountId::from(ALICE), 210 * UNIT),
84
1
            (AccountId::from(BOB), 100 * UNIT),
85
1
            (AccountId::from(CHARLIE), 100 * UNIT),
86
1
            (AccountId::from(DAVE), 100 * UNIT),
87
1
        ])
88
1
        .build()
89
1
        .execute_with(|| {
90
1
            run_to_block(2);
91

            
92
            // Try to buy (FreeBlockProductionCredits - 1) credits
93
1
            let balance_before = System::account(AccountId::from(ALICE)).data.free;
94
1
            assert_ok!(ServicesPayment::purchase_credits(
95
1
                origin_of(ALICE.into()),
96
1
                2000.into(),
97
1
                block_credits_to_required_balance(
98
1
                    crate::FreeBlockProductionCredits::get() - 1,
99
1
                    2000.into()
100
                )
101
            ));
102
1
            let balance_after = System::account(AccountId::from(ALICE)).data.free;
103

            
104
            // Now parachain tank should have this amount
105
1
            let balance_tank = System::account(ServicesPayment::parachain_tank(2000.into()))
106
1
                .data
107
1
                .free;
108

            
109
1
            assert_eq!(
110
                balance_tank,
111
1
                block_credits_to_required_balance(
112
1
                    crate::FreeBlockProductionCredits::get() - 1,
113
1
                    2000.into()
114
                )
115
            );
116

            
117
1
            let expected_cost = block_credits_to_required_balance(
118
1
                crate::FreeBlockProductionCredits::get() - 1,
119
1
                2000.into(),
120
            );
121
1
            assert_eq!(balance_before - balance_after, expected_cost);
122

            
123
            // Now register para
124
1
            assert_ok!(Registrar::reserve(origin_of(ALICE.into())));
125
1
            assert_ok!(ContainerRegistrar::register(
126
1
                origin_of(ALICE.into()),
127
1
                2000.into(),
128
1
                get_genesis_data_with_validation_code().0,
129
1
                Some(HeadData(vec![1u8, 2u8, 3u8]))
130
            ));
131

            
132
1
            run_to_session(2);
133

            
134
            // We need to accept the validation code, so that the para is onboarded after 2 sessions.
135
1
            assert_ok!(Paras::add_trusted_validation_code(
136
1
                root_origin(),
137
1
                get_genesis_data_with_validation_code().1.into()
138
            ));
139
1
            run_to_session(4);
140

            
141
1
            set_dummy_boot_node(origin_of(ALICE.into()), 2000.into());
142

            
143
1
            assert_ok!(ContainerRegistrar::mark_valid_for_collating(
144
1
                root_origin(),
145
1
                2000.into()
146
            ));
147

            
148
            // We received free credits, because we cannot have more than FreeBlockProductionCredits
149
1
            let credits =
150
1
                pallet_services_payment::BlockProductionCredits::<Runtime>::get(ParaId::from(2000))
151
1
                    .unwrap_or_default();
152
1
            assert_eq!(credits, crate::FreeBlockProductionCredits::get());
153
1
        });
154
1
}
155

            
156
3
fn services_payment_restricted_call(
157
3
    origin: RuntimeOrigin,
158
3
    check: impl FnOnce(DispatchResultWithPostInfo),
159
3
) {
160
3
    ExtBuilder::default()
161
3
        .with_balances(vec![
162
3
            // Alice gets 10k extra tokens for her mapping deposit
163
3
            (AccountId::from(ALICE), 210_000 * UNIT),
164
3
            (AccountId::from(BOB), 100_000 * UNIT),
165
3
            (AccountId::from(CHARLIE), 100_000 * UNIT),
166
3
            (AccountId::from(DAVE), 100_000 * UNIT),
167
3
        ])
168
3
        .with_collators(vec![
169
3
            (AccountId::from(ALICE), 210 * UNIT),
170
3
            (AccountId::from(BOB), 100 * UNIT),
171
3
            (AccountId::from(CHARLIE), 100 * UNIT),
172
3
            (AccountId::from(DAVE), 100 * UNIT),
173
3
        ])
174
3
        .build()
175
3
        .execute_with(|| {
176
3
            run_to_block(2);
177

            
178
3
            assert_ok!(Registrar::reserve(origin_of(ALICE.into())));
179
3
            assert_ok!(ContainerRegistrar::register(
180
3
                origin_of(ALICE.into()),
181
3
                2000.into(),
182
3
                get_genesis_data_with_validation_code().0,
183
3
                Some(HeadData(vec![1u8, 2u8, 3u8]))
184
            ));
185

            
186
3
            check(ServicesPayment::set_refund_address(
187
3
                origin,
188
3
                2000.into(),
189
3
                None,
190
3
            ));
191
3
        });
192
3
}
193

            
194
#[test]
195
1
fn root_can_call_services_payment() {
196
1
    services_payment_restricted_call(root_origin(), |res| {
197
1
        assert_ok!(res);
198
1
    });
199
1
}
200

            
201
#[test]
202
1
fn manager_can_call_services_payment() {
203
1
    services_payment_restricted_call(origin_of(ALICE.into()), |res| {
204
1
        assert_ok!(res);
205
1
    });
206
1
}
207

            
208
#[test]
209
1
fn non_manager_can_call_services_payment() {
210
1
    services_payment_restricted_call(origin_of(BOB.into()), |res| {
211
1
        assert_noop!(res, DispatchError::BadOrigin);
212
1
    });
213
1
}