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
    frame_support::{
19
        assert_ok,
20
        weights::{Weight, WeightToFee},
21
    },
22
    frontier_template_emulated_chain::FrontierTemplateParaPallet,
23
    parity_scale_codec::Encode,
24
    simple_template_emulated_chain::SimpleTemplateParaPallet,
25
    westend_emulated_chain::WestendRelayPallet,
26
    westend_system_emulated_network::westend_emulated_chain::westend_runtime::Dmp,
27
    westend_system_emulated_network::{
28
        DanceboxPara as Dancebox, FrontierTemplatePara as FrontierTemplate,
29
        SimpleTemplatePara as SimpleTemplate, WestendRelay as Westend,
30
    },
31
    xcm::{
32
        latest::prelude::{Junctions::*, *},
33
        VersionedLocation, VersionedXcm,
34
    },
35
    xcm_builder::{ParentIsPreset, SiblingParachainConvertsVia},
36
    xcm_emulator::{
37
        assert_expected_events, bx, Chain, Parachain as Para, RelayChain as Relay, TestExt,
38
    },
39
    xcm_executor::traits::ConvertLocation,
40
};
41

            
42
#[test]
43
1
fn transact_sudo_from_relay_hits_barrier_dancebox_without_buy_exec() {
44
1
    Westend::execute_with(|| {
45
1
        Dmp::make_parachain_reachable(Dancebox::para_id());
46
1
    });
47
1

            
48
1
    let call = <Dancebox as Chain>::RuntimeCall::Configuration(pallet_configuration::Call::<
49
1
        <Dancebox as Chain>::Runtime,
50
1
    >::set_max_collators {
51
1
        new: 50,
52
1
    })
53
1
    .encode()
54
1
    .into();
55
1

            
56
1
    // XcmPallet send arguments
57
1
    let sudo_origin = <Westend as Chain>::RuntimeOrigin::root();
58
1
    let dancebox_para_destination: VersionedLocation =
59
1
        Westend::child_location_of(Dancebox::para_id()).into();
60
1

            
61
1
    let weight_limit = WeightLimit::Unlimited;
62
1
    let fallback_max_weight = Some(Weight::from_parts(1000000000, 200000));
63
1
    let origin_kind = OriginKind::Superuser;
64
1
    let check_origin = None;
65
1

            
66
1
    let xcm = VersionedXcm::from(Xcm(vec![
67
1
        UnpaidExecution {
68
1
            weight_limit,
69
1
            check_origin,
70
1
        },
71
1
        Transact {
72
1
            fallback_max_weight,
73
1
            origin_kind,
74
1
            call,
75
1
        },
76
1
    ]));
77
1

            
78
1
    // Send XCM message from Relay Chain
79
1
    Westend::execute_with(|| {
80
1
        assert_ok!(<Westend as WestendRelayPallet>::XcmPallet::send(
81
1
            sudo_origin,
82
1
            bx!(dancebox_para_destination),
83
1
            bx!(xcm),
84
1
        ));
85

            
86
        type RuntimeEvent = <Westend as Chain>::RuntimeEvent;
87

            
88
1
        assert_expected_events!(
89
            Westend,
90
            vec![
91
1
                RuntimeEvent::XcmPallet(pallet_xcm::Event::Sent { .. }) => {},
92
            ]
93
        );
94
1
    });
95
1

            
96
1
    // Receive XCM message in Assets Parachain
97
1
    Dancebox::execute_with(|| {
98
1
        Dancebox::assert_dmp_queue_incomplete(None);
99
1
    });
100
1
}
101

            
102
#[test]
103
1
fn transact_sudo_from_relay_does_not_have_sudo_power() {
104
1
    Westend::execute_with(|| {
105
1
        Dmp::make_parachain_reachable(Dancebox::para_id());
106
1
    });
107
1

            
108
1
    let call = <Dancebox as Chain>::RuntimeCall::Configuration(pallet_configuration::Call::<
109
1
        <Dancebox as Chain>::Runtime,
110
1
    >::set_max_collators {
111
1
        new: 50,
112
1
    })
113
1
    .encode()
114
1
    .into();
115
1

            
116
1
    // XcmPallet send arguments
117
1
    let sudo_origin = <Westend as Chain>::RuntimeOrigin::root();
118
1
    let dancebox_para_destination: VersionedLocation =
119
1
        Westend::child_location_of(Dancebox::para_id()).into();
120
1

            
121
1
    let fallback_max_weight = Some(Weight::from_parts(1000000000, 200000));
122
1
    let origin_kind = OriginKind::Superuser;
123
1

            
124
1
    let buy_execution_fee_amount =
125
1
        dancebox_runtime::WeightToFee::weight_to_fee(&Weight::from_parts(10_000_000_000, 300_000));
126
1

            
127
1
    let buy_execution_fee = Asset {
128
1
        id: dancebox_runtime::xcm_config::SelfReserve::get().into(),
129
1
        fun: Fungible(buy_execution_fee_amount),
130
1
    };
131
1

            
132
1
    let xcm = VersionedXcm::from(Xcm(vec![
133
1
        WithdrawAsset(vec![buy_execution_fee.clone()].into()),
134
1
        BuyExecution {
135
1
            fees: buy_execution_fee.clone(),
136
1
            weight_limit: Unlimited,
137
1
        },
138
1
        Transact {
139
1
            fallback_max_weight,
140
1
            origin_kind,
141
1
            call,
142
1
        },
143
1
    ]));
144
1

            
145
1
    // Send XCM message from Relay Chain
146
1
    Westend::execute_with(|| {
147
1
        assert_ok!(<Westend as WestendRelayPallet>::XcmPallet::send(
148
1
            sudo_origin,
149
1
            bx!(dancebox_para_destination),
150
1
            bx!(xcm),
151
1
        ));
152

            
153
        type RuntimeEvent = <Westend as Chain>::RuntimeEvent;
154

            
155
1
        assert_expected_events!(
156
            Westend,
157
            vec![
158
1
                RuntimeEvent::XcmPallet(pallet_xcm::Event::Sent { .. }) => {},
159
            ]
160
        );
161
1
    });
162
1

            
163
1
    // Receive XCM message in Assets Parachain
164
1
    Dancebox::execute_with(|| {
165
1
        Dancebox::assert_dmp_queue_incomplete(None);
166
1
    });
167
1
}
168

            
169
#[test]
170
1
fn transact_sudo_from_relay_has_signed_origin_powers() {
171
1
    Westend::execute_with(|| {
172
1
        Dmp::make_parachain_reachable(Dancebox::para_id());
173
1
    });
174
1

            
175
1
    let call = <Dancebox as Chain>::RuntimeCall::System(frame_system::Call::<
176
1
        <Dancebox as Chain>::Runtime,
177
1
    >::remark_with_event {
178
1
        remark: b"Test".to_vec(),
179
1
    })
180
1
    .encode()
181
1
    .into();
182
1

            
183
1
    // XcmPallet send arguments
184
1
    let sudo_origin = <Westend as Chain>::RuntimeOrigin::root();
185
1
    let dancebox_para_destination: VersionedLocation =
186
1
        Westend::child_location_of(Dancebox::para_id()).into();
187
1

            
188
1
    let fallback_max_weight = Some(Weight::from_parts(1000000000, 200000));
189
1
    let origin_kind = OriginKind::SovereignAccount;
190
1

            
191
1
    let buy_execution_fee_amount = dancebox_runtime::WeightToFee::weight_to_fee(
192
1
        &Weight::from_parts(10_000_000_000_000, 300_000),
193
1
    );
194
1

            
195
1
    let buy_execution_fee = Asset {
196
1
        id: dancebox_runtime::xcm_config::SelfReserve::get().into(),
197
1
        fun: Fungible(buy_execution_fee_amount),
198
1
    };
199
1

            
200
1
    let xcm = VersionedXcm::from(Xcm(vec![
201
1
        WithdrawAsset(vec![buy_execution_fee.clone()].into()),
202
1
        BuyExecution {
203
1
            fees: buy_execution_fee.clone(),
204
1
            weight_limit: Unlimited,
205
1
        },
206
1
        Transact {
207
1
            fallback_max_weight,
208
1
            origin_kind,
209
1
            call,
210
1
        },
211
1
    ]));
212
1

            
213
1
    // Send XCM message from Relay Chain
214
1
    Westend::execute_with(|| {
215
1
        assert_ok!(<Westend as WestendRelayPallet>::XcmPallet::send(
216
1
            sudo_origin,
217
1
            bx!(dancebox_para_destination),
218
1
            bx!(xcm),
219
1
        ));
220

            
221
        type RuntimeEvent = <Westend as Chain>::RuntimeEvent;
222

            
223
1
        assert_expected_events!(
224
            Westend,
225
            vec![
226
1
                RuntimeEvent::XcmPallet(pallet_xcm::Event::Sent { .. }) => {},
227
            ]
228
        );
229
1
    });
230
1

            
231
1
    // Receive XCM message in Assets Parachain
232
1
    Dancebox::execute_with(|| {
233
        type RuntimeEvent = <Dancebox as Chain>::RuntimeEvent;
234
1
        assert_expected_events!(
235
            Dancebox,
236
            vec![
237
1
                RuntimeEvent::System(
238
1
                    frame_system::Event::Remarked {
239
1
                        sender,
240
1
                        ..
241
1
                    }) => {
242
1
                    sender: *sender == ParentIsPreset::<dancebox_runtime::AccountId>::convert_location(&Location::parent()).unwrap(),
243
                },
244
            ]
245
        );
246
1
    });
247
1
}
248

            
249
#[test]
250
1
fn transact_sudo_from_frontier_has_signed_origin_powers() {
251
1
    let call = <Dancebox as Chain>::RuntimeCall::System(frame_system::Call::<
252
1
        <Dancebox as Chain>::Runtime,
253
1
    >::remark_with_event {
254
1
        remark: b"Test".to_vec(),
255
1
    })
256
1
    .encode()
257
1
    .into();
258
1

            
259
1
    // XcmPallet send arguments
260
1
    let sudo_origin = <FrontierTemplate as Chain>::RuntimeOrigin::root();
261
1
    let dancebox_para_destination: VersionedLocation = Location {
262
1
        parents: 1,
263
1
        interior: X1([Parachain(Dancebox::para_id().into())].into()),
264
1
    }
265
1
    .into();
266
1

            
267
1
    let fallback_max_weight = Some(Weight::from_parts(1000000000, 200000));
268
1
    let origin_kind = OriginKind::SovereignAccount;
269
1

            
270
1
    let buy_execution_fee_amount = dancebox_runtime::WeightToFee::weight_to_fee(
271
1
        &Weight::from_parts(10_000_000_000_000, 300_000),
272
1
    );
273
1

            
274
1
    let buy_execution_fee = Asset {
275
1
        id: dancebox_runtime::xcm_config::SelfReserve::get().into(),
276
1
        fun: Fungible(buy_execution_fee_amount),
277
1
    };
278
1

            
279
1
    let xcm = VersionedXcm::from(Xcm(vec![
280
1
        WithdrawAsset(vec![buy_execution_fee.clone()].into()),
281
1
        BuyExecution {
282
1
            fees: buy_execution_fee.clone(),
283
1
            weight_limit: Unlimited,
284
1
        },
285
1
        Transact {
286
1
            fallback_max_weight,
287
1
            origin_kind,
288
1
            call,
289
1
        },
290
1
    ]));
291
1

            
292
1
    // Send XCM message from Frontier Template
293
1
    FrontierTemplate::execute_with(|| {
294
1
        assert_ok!(
295
1
            <FrontierTemplate as FrontierTemplateParaPallet>::PolkadotXcm::send(
296
1
                sudo_origin,
297
1
                bx!(dancebox_para_destination),
298
1
                bx!(xcm),
299
1
            )
300
1
        );
301

            
302
        type RuntimeEvent = <FrontierTemplate as Chain>::RuntimeEvent;
303

            
304
1
        assert_expected_events!(
305
            FrontierTemplate,
306
            vec![
307
1
                RuntimeEvent::PolkadotXcm(pallet_xcm::Event::Sent { .. }) => {},
308
            ]
309
        );
310
1
    });
311
1

            
312
1
    // Receive XCM message in Assets Parachain
313
1
    Dancebox::execute_with(|| {
314
        type RuntimeEvent = <Dancebox as Chain>::RuntimeEvent;
315
1
        assert_expected_events!(
316
            Dancebox,
317
            vec![
318
1
                RuntimeEvent::System(
319
1
                    frame_system::Event::Remarked {
320
1
                        sender,
321
1
                        ..
322
1
                    }) => {
323
1
                    sender: *sender ==  SiblingParachainConvertsVia::<polkadot_parachain_primitives::primitives::Sibling, dancebox_runtime::AccountId>::convert_location(
324
1
                        &Location{ parents: 1, interior: X1([Parachain(2001u32)].into())}
325
1
                    ).unwrap(),
326
                },
327
            ]
328
        );
329
1
    });
330
1
}
331

            
332
#[test]
333
1
fn transact_sudo_from_simple_has_signed_origin_powers() {
334
1
    let call = <Dancebox as Chain>::RuntimeCall::System(frame_system::Call::<
335
1
        <Dancebox as Chain>::Runtime,
336
1
    >::remark_with_event {
337
1
        remark: b"Test".to_vec(),
338
1
    })
339
1
    .encode()
340
1
    .into();
341
1

            
342
1
    // XcmPallet send arguments
343
1
    let sudo_origin = <SimpleTemplate as Chain>::RuntimeOrigin::root();
344
1
    let dancebox_para_destination: VersionedLocation = Location {
345
1
        parents: 1,
346
1
        interior: X1([Parachain(Dancebox::para_id().into())].into()),
347
1
    }
348
1
    .into();
349
1

            
350
1
    let fallback_max_weight = Some(Weight::from_parts(1000000000, 200000));
351
1
    let origin_kind = OriginKind::SovereignAccount;
352
1

            
353
1
    let buy_execution_fee_amount = dancebox_runtime::WeightToFee::weight_to_fee(
354
1
        &Weight::from_parts(10_000_000_000_000, 300_000),
355
1
    );
356
1

            
357
1
    let buy_execution_fee = Asset {
358
1
        id: dancebox_runtime::xcm_config::SelfReserve::get().into(),
359
1
        fun: Fungible(buy_execution_fee_amount),
360
1
    };
361
1

            
362
1
    let xcm = VersionedXcm::from(Xcm(vec![
363
1
        WithdrawAsset(vec![buy_execution_fee.clone()].into()),
364
1
        BuyExecution {
365
1
            fees: buy_execution_fee.clone(),
366
1
            weight_limit: Unlimited,
367
1
        },
368
1
        Transact {
369
1
            fallback_max_weight,
370
1
            origin_kind,
371
1
            call,
372
1
        },
373
1
    ]));
374
1

            
375
1
    // Send XCM message from Relay Chain
376
1
    SimpleTemplate::execute_with(|| {
377
1
        assert_ok!(
378
1
            <SimpleTemplate as SimpleTemplateParaPallet>::PolkadotXcm::send(
379
1
                sudo_origin,
380
1
                bx!(dancebox_para_destination),
381
1
                bx!(xcm),
382
1
            )
383
1
        );
384

            
385
        type RuntimeEvent = <SimpleTemplate as Chain>::RuntimeEvent;
386

            
387
1
        assert_expected_events!(
388
            SimpleTemplate,
389
            vec![
390
1
                RuntimeEvent::PolkadotXcm(pallet_xcm::Event::Sent { .. }) => {},
391
            ]
392
        );
393
1
    });
394
1

            
395
1
    // Receive XCM message in Assets Parachain
396
1
    Dancebox::execute_with(|| {
397
        type RuntimeEvent = <Dancebox as Chain>::RuntimeEvent;
398
1
        assert_expected_events!(
399
            Dancebox,
400
            vec![
401
1
                RuntimeEvent::System(
402
1
                    frame_system::Event::Remarked {
403
1
                        sender,
404
1
                        ..
405
1
                    }) => {
406
1
                    sender: *sender ==  SiblingParachainConvertsVia::<polkadot_parachain_primitives::primitives::Sibling, dancebox_runtime::AccountId>::convert_location(
407
1
                        &Location{ parents: 1, interior: X1([Parachain(2002u32)].into())}
408
1
                    ).unwrap(),
409
                },
410
            ]
411
        );
412
1
    });
413
1
}