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
    cumulus_primitives_core::{relay_chain::HeadData, ParaId},
22
    frame_support::{assert_noop, assert_ok, pallet_prelude::DispatchResultWithPostInfo},
23
    sp_runtime::DispatchError,
24
    sp_std::vec,
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
1

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

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

            
61
1
            assert_eq!(
62
1
                balance_tank,
63
1
                block_credits_to_required_balance(u32::MAX, 2000.into())
64
1
            );
65

            
66
1
            let expected_cost = block_credits_to_required_balance(u32::MAX, 2000.into());
67
1
            assert_eq!(balance_before - balance_after, expected_cost);
68
1
        });
69
1
}
70

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

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

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

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

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

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

            
131
1
            run_to_session(2);
132
1

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

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

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

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

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

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

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

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

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

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