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::*, RuntimeOrigin},
21
    alloc::vec,
22
    cumulus_primitives_core::{ParaId, Weight},
23
    dp_consensus::runtime_decl_for_tanssi_authority_assignment_api::TanssiAuthorityAssignmentApiV1,
24
    dp_core::well_known_keys,
25
    frame_support::{assert_err, assert_noop, assert_ok, BoundedVec},
26
    frame_system::ConsumedWeight,
27
    nimbus_primitives::NIMBUS_KEY_ID,
28
    pallet_author_noting_runtime_api::runtime_decl_for_author_noting_api::AuthorNotingApi,
29
    pallet_migrations::Migration,
30
    pallet_registrar_runtime_api::{
31
        runtime_decl_for_registrar_api::RegistrarApi, ContainerChainGenesisData,
32
    },
33
    pallet_stream_payment::StreamConfig,
34
    parity_scale_codec::Encode,
35
    sp_consensus_aura::AURA_ENGINE_ID,
36
    sp_core::Get,
37
    sp_runtime::{
38
        traits::{BadOrigin, BlakeTwo256, Dispatchable, OpaqueKeys},
39
        DigestItem,
40
    },
41
    tanssi_runtime_common::migrations::MigrateServicesPaymentAddCollatorAssignmentCredits,
42
    test_relay_sproof_builder::{HeaderAs, ParaHeaderSproofBuilder, ParaHeaderSproofBuilderItem},
43
    tp_stream_payment_common::{
44
        AssetId as StreamPaymentAssetId, TimeUnit as StreamPaymentTimeUnit,
45
    },
46
    tp_traits::{ContainerChainBlockInfo, SlotFrequency},
47
};
48

            
49
20
fn set_dummy_boot_node(para_manager: RuntimeOrigin, para_id: ParaId) {
50
    use pallet_data_preservers::{NodeType, ParaIdsFilter, Profile};
51

            
52
20
    let profile = Profile {
53
20
        bootnode_url: Some(
54
20
            b"/ip4/127.0.0.1/tcp/33049/ws/p2p/12D3KooWHVMhQDHBpj9vQmssgyfspYecgV6e3hH1dQVDUkUbCYC9"
55
20
                .to_vec()
56
20
                .try_into()
57
20
                .expect("to fit in BoundedVec"),
58
20
        ),
59
20
        direct_rpc_urls: Default::default(),
60
20
        proxy_rpc_urls: Default::default(),
61
20
        para_ids: ParaIdsFilter::AnyParaId,
62
20
        node_type: NodeType::Substrate,
63
20
        additional_info: Default::default(),
64
20
        assignment_request: tp_data_preservers_common::ProviderRequest::Free,
65
20
    };
66

            
67
20
    let profile_id = pallet_data_preservers::NextProfileId::<Runtime>::get();
68
20
    let profile_owner = AccountId::new([1u8; 32]);
69
20
    DataPreservers::force_create_profile(RuntimeOrigin::root(), profile, profile_owner)
70
20
        .expect("profile create to succeed");
71

            
72
20
    DataPreservers::start_assignment(
73
20
        para_manager,
74
20
        profile_id,
75
20
        para_id,
76
20
        tp_data_preservers_common::AssignerExtra::Free,
77
    )
78
20
    .expect("assignement to work");
79

            
80
20
    assert!(
81
20
        pallet_data_preservers::Assignments::<Runtime>::get(para_id).contains(&profile_id),
82
        "profile should be correctly assigned"
83
    );
84
20
}
85

            
86
#[test]
87
1
fn genesis_balances() {
88
1
    ExtBuilder::default()
89
1
        .with_balances(vec![
90
1
            // Alice gets 10k extra tokens for her mapping deposit
91
1
            (AccountId::from(ALICE), 210_000 * UNIT),
92
1
            (AccountId::from(BOB), 100_000 * UNIT),
93
1
            (AccountId::from(CHARLIE), 100_000 * UNIT),
94
1
            (AccountId::from(DAVE), 100_000 * UNIT),
95
1
        ])
96
1
        .with_collators(vec![
97
1
            // Remove ALICE and BOB from collators
98
1
            (AccountId::from(CHARLIE), 100 * UNIT),
99
1
            (AccountId::from(DAVE), 100 * UNIT),
100
1
        ])
101
1
        .build()
102
1
        .execute_with(|| {
103
1
            assert_eq!(
104
1
                Balances::usable_balance(AccountId::from(ALICE)),
105
                210_000 * UNIT,
106
            );
107
1
            assert_eq!(
108
1
                Balances::usable_balance(AccountId::from(BOB)),
109
                100_000 * UNIT,
110
            );
111
1
        });
112
1
}
113

            
114
#[test]
115
1
fn genesis_para_registrar() {
116
1
    ExtBuilder::default()
117
1
        .with_empty_parachains(vec![1001, 1002])
118
1
        .build()
119
1
        .execute_with(|| {
120
1
            assert_eq!(
121
1
                Registrar::registered_para_ids(),
122
1
                vec![1001.into(), 1002.into()]
123
            );
124
1
        });
125
1
}
126

            
127
#[test]
128
1
fn genesis_para_registrar_deregister() {
129
1
    ExtBuilder::default()
130
1
        .with_empty_parachains(vec![1001, 1002])
131
1
        .build()
132
1
        .execute_with(|| {
133
1
            assert_eq!(
134
1
                Registrar::registered_para_ids(),
135
1
                vec![1001.into(), 1002.into()]
136
            );
137

            
138
1
            run_to_block(2);
139
1
            assert_ok!(Registrar::deregister(root_origin(), 1002.into()), ());
140

            
141
            // Pending
142
1
            assert_eq!(
143
1
                Registrar::pending_registered_para_ids(),
144
1
                vec![(2u32, BoundedVec::try_from(vec![1001u32.into()]).unwrap())]
145
            );
146

            
147
1
            run_to_session(1);
148
1
            assert_eq!(
149
1
                Registrar::pending_registered_para_ids(),
150
1
                vec![(2u32, BoundedVec::try_from(vec![1001u32.into()]).unwrap())]
151
            );
152
1
            assert_eq!(
153
1
                Registrar::registered_para_ids(),
154
1
                vec![1001.into(), 1002.into()]
155
            );
156

            
157
1
            run_to_session(2);
158
1
            assert_eq!(Registrar::pending_registered_para_ids(), vec![]);
159
1
            assert_eq!(Registrar::registered_para_ids(), vec![1001.into()]);
160
1
        });
161
1
}
162

            
163
#[test]
164
1
fn genesis_para_registrar_runtime_api() {
165
1
    ExtBuilder::default()
166
1
        .with_empty_parachains(vec![1001, 1002])
167
1
        .build()
168
1
        .execute_with(|| {
169
1
            assert_eq!(
170
1
                Registrar::registered_para_ids(),
171
1
                vec![1001.into(), 1002.into()]
172
            );
173
1
            assert_eq!(Runtime::registered_paras(), vec![1001.into(), 1002.into()]);
174

            
175
1
            run_to_block(2);
176
1
            assert_ok!(Registrar::deregister(root_origin(), 1002.into()), ());
177
1
            assert_eq!(Runtime::registered_paras(), vec![1001.into(), 1002.into()]);
178

            
179
1
            run_to_session(1);
180
1
            assert_eq!(
181
1
                Registrar::registered_para_ids(),
182
1
                vec![1001.into(), 1002.into()]
183
            );
184
1
            assert_eq!(Runtime::registered_paras(), vec![1001.into(), 1002.into()]);
185

            
186
1
            run_to_session(2);
187
1
            assert_eq!(Registrar::registered_para_ids(), vec![1001.into()]);
188
1
            assert_eq!(Runtime::registered_paras(), vec![1001.into()]);
189
1
        });
190
1
}
191

            
192
#[test]
193
1
fn genesis_para_registrar_container_chain_genesis_data_runtime_api() {
194
1
    let genesis_data_1001 = empty_genesis_data();
195
1
    let genesis_data_1002 = ContainerChainGenesisData {
196
1
        storage: BoundedVec::try_from(vec![(b"key".to_vec(), b"value".to_vec()).into()]).unwrap(),
197
1
        name: Default::default(),
198
1
        id: Default::default(),
199
1
        fork_id: Default::default(),
200
1
        extensions: BoundedVec::try_from(vec![]).unwrap(),
201
1
        properties: Default::default(),
202
1
    };
203
1
    ExtBuilder::default()
204
1
        .with_para_ids(vec![
205
1
            ParaRegistrationParams {
206
1
                para_id: 1001,
207
1
                genesis_data: genesis_data_1001.clone(),
208
1
                block_production_credits: u32::MAX,
209
1
                collator_assignment_credits: u32::MAX,
210
1
                parathread_params: None,
211
1
            },ParaRegistrationParams {
212
1
                para_id: 1002,
213
1
                genesis_data: genesis_data_1002.clone(),
214
1
                block_production_credits: u32::MAX,
215
1
                collator_assignment_credits: u32::MAX,
216
1
                parathread_params: None,
217
1
            },        ])
218
1
        .build()
219
1
        .execute_with(|| {
220
1
            assert_eq!(
221
1
                Registrar::registered_para_ids(),
222
1
                vec![1001.into(), 1002.into()]
223
            );
224
1
            assert_eq!(Runtime::registered_paras(), vec![1001.into(), 1002.into()]);
225

            
226
1
            assert_eq!(
227
1
                Runtime::genesis_data(1001.into()).as_ref(),
228
1
                Some(&genesis_data_1001)
229
            );
230
1
            assert_eq!(
231
1
                Runtime::genesis_data(1002.into()).as_ref(),
232
1
                Some(&genesis_data_1002)
233
            );
234
1
            assert_eq!(Runtime::genesis_data(1003.into()).as_ref(), None);
235

            
236
            // This API cannot be used to get the genesis data of the orchestrator chain,
237
            // with id 100
238
            // TODO: where is that 100 defined?
239
1
            assert_eq!(Runtime::genesis_data(100.into()).as_ref(), None);
240

            
241
1
            run_to_block(2);
242
1
            assert_ok!(Registrar::deregister(root_origin(), 1002.into()), ());
243

            
244
1
            assert_eq!(Runtime::genesis_data(1002.into()).as_ref(), Some(&genesis_data_1002), "Deregistered container chain genesis data should not be removed until after 2 sessions");
245

            
246
1
            let genesis_data_1003 = ContainerChainGenesisData {
247
1
                storage: BoundedVec::try_from(vec![(b"key3".to_vec(), b"value3".to_vec()).into()]).unwrap(),
248
1
                name: Default::default(),
249
1
                id: Default::default(),
250
1
                fork_id: Default::default(),
251
1
                extensions: BoundedVec::try_from(vec![]).unwrap(),
252
1
                properties: Default::default(),
253
1
            };
254
1
            assert_ok!(
255
1
                Registrar::register(
256
1
                    origin_of(ALICE.into()),
257
1
                    1003.into(),
258
1
                    genesis_data_1003.clone(),
259
1
                    None
260
                ),
261
                ()
262
            );
263

            
264
            // Registered container chains are inserted immediately
265
1
            assert_eq!(
266
1
                Runtime::genesis_data(1003.into()).as_ref(),
267
1
                Some(&genesis_data_1003)
268
            );
269

            
270
            // Deregistered container chain genesis data is removed after 2 sessions
271
1
            run_to_session(2u32);
272
1
            assert_eq!(Runtime::genesis_data(1002.into()).as_ref(), None);
273
1
        });
274
1
}
275

            
276
#[test]
277
1
fn test_author_collation_aura() {
278
1
    ExtBuilder::default()
279
1
        .with_empty_parachains(vec![1001, 1002])
280
1
        .build()
281
1
        .execute_with(|| {
282
1
            run_to_block(5);
283
            // Assert current slot gets updated
284
1
            assert_eq!(current_slot(), 4u64);
285
            // slot 4, alice
286
1
            assert!(current_author() == AccountId::from(ALICE));
287

            
288
1
            run_to_block(6);
289

            
290
1
            assert_eq!(current_slot(), 5u64);
291
            // slot 5, bob
292
1
            assert!(current_author() == AccountId::from(BOB));
293
1
        });
294
1
}
295

            
296
#[test]
297
1
fn test_author_collation_aura_change_of_authorities_on_session() {
298
1
    ExtBuilder::default()
299
1
        .with_balances(vec![
300
1
            // Alice gets 10k extra tokens for her mapping deposit
301
1
            (AccountId::from(ALICE), 210_000 * UNIT),
302
1
            (AccountId::from(BOB), 100_000 * UNIT),
303
1
            (AccountId::from(CHARLIE), 100_000 * UNIT),
304
1
            (AccountId::from(DAVE), 100_000 * UNIT),
305
1
        ])
306
1
        .with_empty_parachains(vec![1001, 1002])
307
1
        .build()
308
1
        .execute_with(|| {
309
1
            run_to_block(2);
310
            // Assert current slot gets updated
311
1
            assert_eq!(current_slot(), 1u64);
312
1
            assert!(current_author() == AccountId::from(BOB));
313

            
314
            // We change invulnerables
315
            // We first need to set the keys
316
1
            let alice_id = get_aura_id_from_seed(&AccountId::from(ALICE).to_string());
317
1
            let bob_id = get_aura_id_from_seed(&AccountId::from(BOB).to_string());
318

            
319
1
            let charlie_id = get_aura_id_from_seed(&AccountId::from(CHARLIE).to_string());
320
1
            let dave_id = get_aura_id_from_seed(&AccountId::from(DAVE).to_string());
321

            
322
            // Set CHARLIE and DAVE keys
323
1
            assert_ok!(Session::set_keys(
324
1
                origin_of(CHARLIE.into()),
325
1
                crate::SessionKeys {
326
1
                    nimbus: charlie_id.clone(),
327
1
                },
328
1
                vec![]
329
            ));
330
1
            assert_ok!(Session::set_keys(
331
1
                origin_of(DAVE.into()),
332
1
                crate::SessionKeys {
333
1
                    nimbus: dave_id.clone(),
334
1
                },
335
1
                vec![]
336
            ));
337

            
338
            // Change invulnerables
339
1
            assert_ok!(Invulnerables::remove_invulnerable(
340
1
                root_origin(),
341
1
                ALICE.into()
342
            ));
343
1
            assert_ok!(Invulnerables::remove_invulnerable(
344
1
                root_origin(),
345
1
                BOB.into()
346
            ));
347
1
            assert_ok!(Invulnerables::add_invulnerable(
348
1
                root_origin(),
349
1
                CHARLIE.into()
350
            ));
351
1
            assert_ok!(Invulnerables::add_invulnerable(root_origin(), DAVE.into()));
352

            
353
            // SESSION CHANGE. First session. it takes 2 sessions to see the change
354
1
            run_to_session(1u32);
355
1
            let author = get_orchestrator_current_author().unwrap();
356

            
357
1
            assert_eq!(current_author(), author);
358
1
            assert!(authorities() == vec![alice_id.clone(), bob_id.clone()]);
359

            
360
            // Invulnerables should have triggered on new session authorities change
361
1
            run_to_session(2u32);
362
1
            let author_after_changes = get_orchestrator_current_author().unwrap();
363

            
364
1
            assert_eq!(current_author(), author_after_changes);
365
1
            assert_eq!(authorities(), vec![charlie_id, dave_id]);
366
1
        });
367
1
}
368

            
369
#[test]
370
1
fn test_author_collation_aura_add_assigned_to_paras() {
371
1
    ExtBuilder::default()
372
1
        .with_balances(vec![
373
1
            // Alice gets 10k extra tokens for her mapping deposit
374
1
            (AccountId::from(ALICE), 210_000 * UNIT),
375
1
            (AccountId::from(BOB), 100_000 * UNIT),
376
1
            (AccountId::from(CHARLIE), 100_000 * UNIT),
377
1
            (AccountId::from(DAVE), 100_000 * UNIT),
378
1
        ])
379
1
        .with_empty_parachains(vec![1001, 1002])
380
1
        .build()
381
1
        .execute_with(|| {
382
1
            run_to_block(2);
383
            // Assert current slot gets updated
384
1
            assert_eq!(current_slot(), 1u64);
385
1
            assert!(current_author() == AccountId::from(BOB));
386

            
387
            // We change invulnerables
388
            // We first need to set the keys
389
1
            let alice_id = get_aura_id_from_seed(&AccountId::from(ALICE).to_string());
390
1
            let bob_id = get_aura_id_from_seed(&AccountId::from(BOB).to_string());
391

            
392
1
            let charlie_id = get_aura_id_from_seed(&AccountId::from(CHARLIE).to_string());
393
1
            let dave_id = get_aura_id_from_seed(&AccountId::from(DAVE).to_string());
394

            
395
            // Set CHARLIE and DAVE keys
396
1
            assert_ok!(Session::set_keys(
397
1
                origin_of(CHARLIE.into()),
398
1
                crate::SessionKeys { nimbus: charlie_id },
399
1
                vec![]
400
            ));
401
1
            assert_ok!(Session::set_keys(
402
1
                origin_of(DAVE.into()),
403
1
                crate::SessionKeys { nimbus: dave_id },
404
1
                vec![]
405
            ));
406

            
407
            // Add new invulnerables
408
1
            assert_ok!(Invulnerables::add_invulnerable(
409
1
                root_origin(),
410
1
                CHARLIE.into()
411
            ));
412
1
            assert_ok!(Invulnerables::add_invulnerable(root_origin(), DAVE.into()));
413

            
414
            // SESSION CHANGE. First session. it takes 2 sessions to see the change
415
1
            run_to_session(1u32);
416
1
            let author = get_orchestrator_current_author().unwrap();
417

            
418
1
            assert_eq!(current_author(), author);
419
1
            assert_eq!(authorities(), vec![alice_id.clone(), bob_id.clone()]);
420

            
421
            // Invulnerables should have triggered on new session authorities change
422
            // However charlie and dave should have gone to one para (1001)
423
1
            run_to_session(2u32);
424
1
            assert_eq!(authorities(), vec![alice_id, bob_id]);
425
1
            let assignment = CollatorAssignment::collator_container_chain();
426
1
            assert_eq!(
427
1
                assignment.container_chains[&1001u32.into()],
428
1
                vec![CHARLIE.into(), DAVE.into()]
429
            );
430
1
        });
431
1
}
432

            
433
#[test]
434
1
fn test_authors_without_paras() {
435
1
    ExtBuilder::default()
436
1
        .with_balances(vec![
437
1
            // Alice gets 10k extra tokens for her mapping deposit
438
1
            (AccountId::from(ALICE), 210_000 * UNIT),
439
1
            (AccountId::from(BOB), 100_000 * UNIT),
440
1
            (AccountId::from(CHARLIE), 100_000 * UNIT),
441
1
            (AccountId::from(DAVE), 100_000 * UNIT),
442
1
        ])
443
1
        .with_collators(vec![
444
1
            (AccountId::from(ALICE), 210 * UNIT),
445
1
            (AccountId::from(BOB), 100 * UNIT),
446
1
            (AccountId::from(CHARLIE), 100 * UNIT),
447
1
            (AccountId::from(DAVE), 100 * UNIT),
448
1
        ])
449
1
        .build()
450
1
        .execute_with(|| {
451
1
            run_to_block(2);
452
            // Assert current slot gets updated
453
1
            assert_eq!(current_slot(), 1u64);
454
1
            assert!(current_author() == AccountId::from(BOB));
455

            
456
            // Only Alice and Bob collate for our chain
457
1
            let alice_id = get_aura_id_from_seed(&AccountId::from(ALICE).to_string());
458
1
            let bob_id = get_aura_id_from_seed(&AccountId::from(BOB).to_string());
459
1
            let charlie_id = get_aura_id_from_seed(&AccountId::from(CHARLIE).to_string());
460
1
            let dave_id = get_aura_id_from_seed(&AccountId::from(DAVE).to_string());
461

            
462
            // It does not matter if we insert more collators, only two will be assigned
463
1
            assert_eq!(authorities(), vec![alice_id.clone(), bob_id.clone()]);
464

            
465
            // Set moondance collators to min 2 max 5
466
1
            assert_ok!(
467
1
                Configuration::set_min_orchestrator_collators(root_origin(), 2),
468
                ()
469
            );
470
1
            assert_ok!(
471
1
                Configuration::set_max_orchestrator_collators(root_origin(), 5),
472
                ()
473
            );
474

            
475
1
            run_to_session(2);
476
1
            assert_eq!(authorities(), vec![alice_id, bob_id, charlie_id, dave_id]);
477
1
        });
478
1
}
479

            
480
#[test]
481
1
fn test_authors_paras_inserted_a_posteriori() {
482
1
    ExtBuilder::default()
483
1
        .with_balances(vec![
484
1
            // Alice gets 10k extra tokens for her mapping deposit
485
1
            (AccountId::from(ALICE), 210_000 * UNIT),
486
1
            (AccountId::from(BOB), 100_000 * UNIT),
487
1
            (AccountId::from(CHARLIE), 100_000 * UNIT),
488
1
            (AccountId::from(DAVE), 100_000 * UNIT),
489
1
        ])
490
1
        .with_collators(vec![
491
1
            (AccountId::from(ALICE), 210 * UNIT),
492
1
            (AccountId::from(BOB), 100 * UNIT),
493
1
            (AccountId::from(CHARLIE), 100 * UNIT),
494
1
            (AccountId::from(DAVE), 100 * UNIT),
495
1
        ])
496
1
        .build()
497
1
        .execute_with(|| {
498
1
            run_to_block(2);
499
            // Assert current slot gets updated
500
1
            assert_eq!(current_slot(), 1u64);
501
1
            assert!(current_author() == AccountId::from(BOB));
502

            
503
            // Alice and Bob collate in our chain
504
1
            let alice_id = get_aura_id_from_seed(&AccountId::from(ALICE).to_string());
505
1
            let bob_id = get_aura_id_from_seed(&AccountId::from(BOB).to_string());
506

            
507
1
            assert_eq!(authorities(), vec![alice_id, bob_id]);
508

            
509
1
            assert_ok!(Registrar::register(
510
1
                origin_of(ALICE.into()),
511
1
                1001.into(),
512
1
                empty_genesis_data(),
513
1
                None
514
            ));
515
1
            set_dummy_boot_node(origin_of(ALICE.into()), 1001.into());
516
1
            assert_ok!(Registrar::mark_valid_for_collating(
517
1
                root_origin(),
518
1
                1001.into()
519
            ));
520
1
            assert_ok!(ServicesPayment::purchase_credits(
521
1
                origin_of(ALICE.into()),
522
1
                1001.into(),
523
1
                block_credits_to_required_balance(1000, 1001.into())
524
            ));
525
1
            assert_ok!(Registrar::register(
526
1
                origin_of(ALICE.into()),
527
1
                1002.into(),
528
1
                empty_genesis_data(),
529
1
                None
530
            ));
531
1
            set_dummy_boot_node(origin_of(ALICE.into()), 1002.into());
532
1
            assert_ok!(Registrar::mark_valid_for_collating(
533
1
                root_origin(),
534
1
                1002.into()
535
            ));
536
1
            assert_ok!(ServicesPayment::purchase_credits(
537
1
                origin_of(ALICE.into()),
538
1
                1002.into(),
539
1
                block_credits_to_required_balance(1000, 1002.into())
540
            ));
541

            
542
            // Assignment should happen after 2 sessions
543
1
            run_to_session(1u32);
544
1
            let assignment = CollatorAssignment::collator_container_chain();
545
1
            assert!(assignment.container_chains.is_empty());
546
1
            run_to_session(2u32);
547

            
548
            // Charlie and Dave should be assigned to para 1001
549
1
            let assignment = CollatorAssignment::collator_container_chain();
550
1
            assert_eq!(
551
1
                assignment.container_chains[&1001u32.into()],
552
1
                vec![CHARLIE.into(), DAVE.into()]
553
            );
554
1
        });
555
1
}
556

            
557
#[test]
558
1
fn test_authors_paras_inserted_a_posteriori_with_collators_already_assigned() {
559
1
    ExtBuilder::default()
560
1
        .with_balances(vec![
561
1
            // Alice gets 10k extra tokens for her mapping deposit
562
1
            (AccountId::from(ALICE), 210_000 * UNIT),
563
1
            (AccountId::from(BOB), 100_000 * UNIT),
564
1
            (AccountId::from(CHARLIE), 100_000 * UNIT),
565
1
            (AccountId::from(DAVE), 100_000 * UNIT),
566
1
        ])
567
1
        .with_collators(vec![
568
1
            (AccountId::from(ALICE), 210 * UNIT),
569
1
            (AccountId::from(BOB), 100 * UNIT),
570
1
            (AccountId::from(CHARLIE), 100 * UNIT),
571
1
            (AccountId::from(DAVE), 100 * UNIT),
572
1
        ])
573
1
        .with_config(pallet_configuration::HostConfiguration {
574
1
            max_collators: 100,
575
1
            min_orchestrator_collators: 2,
576
1
            max_orchestrator_collators: 5,
577
1
            collators_per_container: 2,
578
1
            full_rotation_period: 0,
579
1
            ..Default::default()
580
1
        })
581
1
        .build()
582
1
        .execute_with(|| {
583
1
            run_to_block(2);
584
            // Assert current slot gets updated
585
1
            assert_eq!(current_slot(), 1u64);
586
1
            assert!(current_author() == AccountId::from(BOB));
587

            
588
            // Alice and Bob collate in our chain
589
1
            let alice_id = get_aura_id_from_seed(&AccountId::from(ALICE).to_string());
590
1
            let bob_id = get_aura_id_from_seed(&AccountId::from(BOB).to_string());
591
1
            let charlie_id = get_aura_id_from_seed(&AccountId::from(CHARLIE).to_string());
592
1
            let dave_id = get_aura_id_from_seed(&AccountId::from(DAVE).to_string());
593

            
594
1
            assert_eq!(authorities(), vec![alice_id, bob_id, charlie_id, dave_id]);
595

            
596
1
            assert_ok!(Registrar::register(
597
1
                origin_of(ALICE.into()),
598
1
                1001.into(),
599
1
                empty_genesis_data(),
600
1
                None
601
            ));
602
1
            set_dummy_boot_node(origin_of(ALICE.into()), 1001.into());
603
1
            assert_ok!(Registrar::mark_valid_for_collating(
604
1
                root_origin(),
605
1
                1001.into()
606
            ));
607
1
            assert_ok!(ServicesPayment::purchase_credits(
608
1
                origin_of(ALICE.into()),
609
1
                1001.into(),
610
1
                block_credits_to_required_balance(1000, 1001.into())
611
            ));
612

            
613
            // Assignment should happen after 2 sessions
614
1
            run_to_session(1u32);
615
1
            let assignment = CollatorAssignment::collator_container_chain();
616
1
            assert!(assignment.container_chains.is_empty());
617
1
            run_to_session(2u32);
618

            
619
            // Charlie and Dave are now assigned to para 1001
620
1
            let assignment = CollatorAssignment::collator_container_chain();
621
1
            assert_eq!(
622
1
                assignment.container_chains[&1001u32.into()],
623
1
                vec![CHARLIE.into(), DAVE.into()]
624
            );
625
1
            assert_eq!(
626
                assignment.orchestrator_chain,
627
1
                vec![ALICE.into(), BOB.into()]
628
            );
629
1
        });
630
1
}
631

            
632
#[test]
633
1
fn test_paras_registered_but_zero_credits() {
634
1
    ExtBuilder::default()
635
1
        .with_balances(vec![
636
1
            // Alice gets 10k extra tokens for her mapping deposit
637
1
            (AccountId::from(ALICE), 210_000 * UNIT),
638
1
            (AccountId::from(BOB), 100_000 * UNIT),
639
1
            (AccountId::from(CHARLIE), 100_000 * UNIT),
640
1
            (AccountId::from(DAVE), 100_000 * UNIT),
641
1
        ])
642
1
        .with_collators(vec![
643
1
            (AccountId::from(ALICE), 210 * UNIT),
644
1
            (AccountId::from(BOB), 100 * UNIT),
645
1
            (AccountId::from(CHARLIE), 100 * UNIT),
646
1
            (AccountId::from(DAVE), 100 * UNIT),
647
1
        ])
648
1
        .build()
649
1
        .execute_with(|| {
650
1
            run_to_block(2);
651
            // Assert current slot gets updated
652
1
            assert_eq!(current_slot(), 1u64);
653
1
            assert!(current_author() == AccountId::from(BOB));
654

            
655
            // Alice and Bob collate in our chain
656
1
            let alice_id = get_aura_id_from_seed(&AccountId::from(ALICE).to_string());
657
1
            let bob_id = get_aura_id_from_seed(&AccountId::from(BOB).to_string());
658

            
659
1
            assert_eq!(authorities(), vec![alice_id, bob_id]);
660

            
661
1
            assert_ok!(Registrar::register(
662
1
                origin_of(ALICE.into()),
663
1
                1001.into(),
664
1
                empty_genesis_data(),
665
1
                None
666
            ));
667
1
            set_dummy_boot_node(origin_of(ALICE.into()), 1001.into());
668
1
            assert_ok!(Registrar::mark_valid_for_collating(
669
1
                root_origin(),
670
1
                1001.into()
671
            ));
672
            // Need to reset credits to 0 because now parachains are given free credits on register
673
1
            assert_ok!(ServicesPayment::set_block_production_credits(
674
1
                root_origin(),
675
1
                1001.into(),
676
                0
677
            ));
678

            
679
            // Assignment should happen after 2 sessions
680
1
            run_to_session(1u32);
681
1
            let assignment = CollatorAssignment::collator_container_chain();
682
1
            assert!(assignment.container_chains.is_empty());
683
1
            run_to_session(2u32);
684

            
685
            // Nobody should be assigned to para 1001
686
1
            let assignment = CollatorAssignment::collator_container_chain();
687
1
            assert_eq!(assignment.container_chains.get(&1001u32.into()), None);
688
1
        });
689
1
}
690

            
691
#[test]
692
1
fn test_paras_registered_but_not_enough_credits() {
693
1
    ExtBuilder::default()
694
1
        .with_balances(vec![
695
1
            // Alice gets 10k extra tokens for her mapping deposit
696
1
            (AccountId::from(ALICE), 210_000 * UNIT),
697
1
            (AccountId::from(BOB), 100_000 * UNIT),
698
1
            (AccountId::from(CHARLIE), 100_000 * UNIT),
699
1
            (AccountId::from(DAVE), 100_000 * UNIT),
700
1
        ])
701
1
        .with_collators(vec![
702
1
            (AccountId::from(ALICE), 210 * UNIT),
703
1
            (AccountId::from(BOB), 100 * UNIT),
704
1
            (AccountId::from(CHARLIE), 100 * UNIT),
705
1
            (AccountId::from(DAVE), 100 * UNIT),
706
1
        ])
707
1
        .build()
708
1
        .execute_with(|| {
709
1
            run_to_block(2);
710
            // Assert current slot gets updated
711
1
            assert_eq!(current_slot(), 1u64);
712
1
            assert!(current_author() == AccountId::from(BOB));
713

            
714
            // Alice and Bob collate in our chain
715
1
            let alice_id = get_aura_id_from_seed(&AccountId::from(ALICE).to_string());
716
1
            let bob_id = get_aura_id_from_seed(&AccountId::from(BOB).to_string());
717

            
718
1
            assert_eq!(authorities(), vec![alice_id, bob_id]);
719

            
720
1
            assert_ok!(Registrar::register(
721
1
                origin_of(ALICE.into()),
722
1
                1001.into(),
723
1
                empty_genesis_data(),
724
1
                None
725
            ));
726
1
            set_dummy_boot_node(origin_of(ALICE.into()), 1001.into());
727
1
            assert_ok!(Registrar::mark_valid_for_collating(
728
1
                root_origin(),
729
1
                1001.into()
730
            ));
731
            // Need to reset credits to 0 because now parachains are given free credits on register
732
1
            assert_ok!(ServicesPayment::set_block_production_credits(
733
1
                root_origin(),
734
1
                1001.into(),
735
                0
736
            ));
737
            // Purchase 1 credit less that what is needed
738
1
            let credits_1001 = crate::Period::get() - 1;
739
1
            assert_ok!(ServicesPayment::set_block_production_credits(
740
1
                root_origin(),
741
1
                1001.into(),
742
1
                credits_1001
743
            ));
744

            
745
            // Assignment should happen after 2 sessions
746
1
            run_to_session(1u32);
747
1
            let assignment = CollatorAssignment::collator_container_chain();
748
1
            assert!(assignment.container_chains.is_empty());
749
1
            run_to_session(2u32);
750
            // Nobody should be assigned to para 1001
751
1
            let assignment = CollatorAssignment::collator_container_chain();
752
1
            assert_eq!(assignment.container_chains.get(&1001u32.into()), None);
753

            
754
            // Now purchase the missing block credit
755
1
            assert_ok!(ServicesPayment::set_block_production_credits(
756
1
                root_origin(),
757
1
                1001.into(),
758
1
                credits_1001 + 1
759
            ));
760

            
761
1
            run_to_session(4u32);
762
            // Charlie and Dave should be assigned to para 1001
763
1
            let assignment = CollatorAssignment::collator_container_chain();
764
1
            assert_eq!(
765
1
                assignment.container_chains[&1001u32.into()],
766
1
                vec![CHARLIE.into(), DAVE.into()]
767
            );
768
1
        });
769
1
}
770

            
771
#[test]
772
1
fn test_paras_registered_but_only_credits_for_1_session() {
773
1
    ExtBuilder::default()
774
1
        .with_balances(vec![
775
1
            // Alice gets 10k extra tokens for her mapping deposit
776
1
            (AccountId::from(ALICE), 210_000 * UNIT),
777
1
            (AccountId::from(BOB), 100_000 * UNIT),
778
1
            (AccountId::from(CHARLIE), 100_000 * UNIT),
779
1
            (AccountId::from(DAVE), 100_000 * UNIT),
780
1
        ])
781
1
        .with_collators(vec![
782
1
            (AccountId::from(ALICE), 210 * UNIT),
783
1
            (AccountId::from(BOB), 100 * UNIT),
784
1
            (AccountId::from(CHARLIE), 100 * UNIT),
785
1
            (AccountId::from(DAVE), 100 * UNIT),
786
1
        ])
787
1
        .build()
788
1
        .execute_with(|| {
789
1
            run_to_block(2);
790
            // Assert current slot gets updated
791
1
            assert_eq!(current_slot(), 1u64);
792
1
            assert!(current_author() == AccountId::from(BOB));
793

            
794
            // Alice and Bob collate in our chain
795
1
            let alice_id = get_aura_id_from_seed(&AccountId::from(ALICE).to_string());
796
1
            let bob_id = get_aura_id_from_seed(&AccountId::from(BOB).to_string());
797

            
798
1
            assert_eq!(authorities(), vec![alice_id, bob_id]);
799

            
800
1
            assert_ok!(Registrar::register(
801
1
                origin_of(ALICE.into()),
802
1
                1001.into(),
803
1
                empty_genesis_data(),
804
1
                None
805
            ));
806
1
            set_dummy_boot_node(origin_of(ALICE.into()), 1001.into());
807
1
            assert_ok!(Registrar::mark_valid_for_collating(
808
1
                root_origin(),
809
1
                1001.into()
810
            ));
811
            // Need to reset credits to 0 because now parachains are given free credits on register
812
1
            assert_ok!(ServicesPayment::set_block_production_credits(
813
1
                root_origin(),
814
1
                1001.into(),
815
                0
816
            ));
817
            // Purchase only enough credits for 1 session
818
1
            let credits_1001 = crate::Period::get();
819
1
            assert_ok!(ServicesPayment::set_block_production_credits(
820
1
                root_origin(),
821
1
                1001.into(),
822
1
                credits_1001
823
            ));
824

            
825
            // Assignment should happen after 2 sessions
826
1
            run_to_session(1u32);
827
1
            let assignment = CollatorAssignment::collator_container_chain();
828
1
            assert!(assignment.container_chains.is_empty());
829
1
            run_to_session(2u32);
830
            // Charlie and Dave should be assigned to para 1001
831
1
            let assignment = CollatorAssignment::collator_container_chain();
832
1
            assert_eq!(
833
1
                assignment.container_chains[&1001u32.into()],
834
1
                vec![CHARLIE.into(), DAVE.into()]
835
            );
836

            
837
            // No credits are consumed if the container chain is not producing blocks
838
1
            run_block();
839
1
            let credits =
840
1
                pallet_services_payment::BlockProductionCredits::<Runtime>::get(ParaId::from(1001))
841
1
                    .unwrap_or_default();
842
1
            assert_eq!(credits, credits_1001);
843

            
844
            // Simulate block inclusion from container chain 1001
845
1
            let mut sproof = ParaHeaderSproofBuilder::default();
846
1
            let slot: u64 = 5;
847
1
            let s = ParaHeaderSproofBuilderItem {
848
1
                para_id: 1001.into(),
849
1
                author_id: HeaderAs::NonEncoded(sp_runtime::generic::Header::<u32, BlakeTwo256> {
850
1
                    parent_hash: Default::default(),
851
1
                    number: 1,
852
1
                    state_root: Default::default(),
853
1
                    extrinsics_root: Default::default(),
854
1
                    digest: sp_runtime::generic::Digest {
855
1
                        logs: vec![DigestItem::PreRuntime(AURA_ENGINE_ID, slot.encode())],
856
1
                    },
857
1
                }),
858
1
            };
859
1
            sproof.items.push(s);
860
1
            set_author_noting_inherent_data(sproof);
861

            
862
1
            run_block();
863
1
            let credits =
864
1
                pallet_services_payment::BlockProductionCredits::<Runtime>::get(ParaId::from(1001))
865
1
                    .unwrap_or_default();
866
1
            assert_eq!(credits, credits_1001 - 1);
867

            
868
1
            run_to_session(4u32);
869
            // Nobody should be assigned to para 1001
870
1
            let assignment = CollatorAssignment::collator_container_chain();
871
1
            assert_eq!(assignment.container_chains.get(&1001u32.into()), None,);
872

            
873
            // The container chain only produced one block, so it only consumed one block credit.
874
            // (it could have produced more blocks, but at most it would have consumed `Period::get()` credits)
875
1
            let credits =
876
1
                pallet_services_payment::BlockProductionCredits::<Runtime>::get(ParaId::from(1001))
877
1
                    .unwrap_or_default();
878
1
            assert_eq!(credits, credits_1001 - 1);
879
1
        });
880
1
}
881

            
882
#[test]
883
1
fn test_parachains_deregister_collators_re_assigned() {
884
1
    ExtBuilder::default()
885
1
        .with_balances(vec![
886
1
            // Alice gets 10k extra tokens for her mapping deposit
887
1
            (AccountId::from(ALICE), 210_000 * UNIT),
888
1
            (AccountId::from(BOB), 100_000 * UNIT),
889
1
            (AccountId::from(CHARLIE), 100_000 * UNIT),
890
1
            (AccountId::from(DAVE), 100_000 * UNIT),
891
1
        ])
892
1
        .with_collators(vec![
893
1
            (AccountId::from(ALICE), 210 * UNIT),
894
1
            (AccountId::from(BOB), 100 * UNIT),
895
1
            (AccountId::from(CHARLIE), 100 * UNIT),
896
1
            (AccountId::from(DAVE), 100 * UNIT),
897
1
        ])
898
1
        .with_empty_parachains(vec![1001, 1002])
899
1
        .build()
900
1
        .execute_with(|| {
901
1
            run_to_block(2);
902
            // Assert current slot gets updated
903
1
            assert_eq!(current_slot(), 1u64);
904
1
            assert!(current_author() == AccountId::from(BOB));
905

            
906
            // Alice and Bob are authorities
907
1
            let alice_id = get_aura_id_from_seed(&AccountId::from(ALICE).to_string());
908
1
            let bob_id = get_aura_id_from_seed(&AccountId::from(BOB).to_string());
909

            
910
1
            assert_eq!(authorities(), vec![alice_id, bob_id]);
911

            
912
            // Charlie and Dave to 1001
913
1
            let assignment = CollatorAssignment::collator_container_chain();
914
1
            assert_eq!(
915
1
                assignment.container_chains[&1001u32.into()],
916
1
                vec![CHARLIE.into(), DAVE.into()]
917
            );
918

            
919
1
            assert_ok!(Registrar::deregister(root_origin(), 1001.into()), ());
920

            
921
            // Assignment should happen after 2 sessions
922
1
            run_to_session(1u32);
923

            
924
1
            let assignment = CollatorAssignment::collator_container_chain();
925
1
            assert_eq!(
926
1
                assignment.container_chains[&1001u32.into()],
927
1
                vec![CHARLIE.into(), DAVE.into()]
928
            );
929

            
930
1
            run_to_session(2u32);
931

            
932
            // Charlie and Dave should be assigne dot para 1002 this time
933
1
            let assignment = CollatorAssignment::collator_container_chain();
934
1
            assert_eq!(
935
1
                assignment.container_chains[&1002u32.into()],
936
1
                vec![CHARLIE.into(), DAVE.into()]
937
            );
938
1
        });
939
1
}
940

            
941
#[test]
942
1
fn test_parachains_deregister_collators_config_change_reassigned() {
943
1
    ExtBuilder::default()
944
1
        .with_balances(vec![
945
1
            // Alice gets 10k extra tokens for her mapping deposit
946
1
            (AccountId::from(ALICE), 210_000 * UNIT),
947
1
            (AccountId::from(BOB), 100_000 * UNIT),
948
1
            (AccountId::from(CHARLIE), 100_000 * UNIT),
949
1
            (AccountId::from(DAVE), 100_000 * UNIT),
950
1
        ])
951
1
        .with_collators(vec![
952
1
            (AccountId::from(ALICE), 210 * UNIT),
953
1
            (AccountId::from(BOB), 100 * UNIT),
954
1
            (AccountId::from(CHARLIE), 100 * UNIT),
955
1
            (AccountId::from(DAVE), 100 * UNIT),
956
1
        ])
957
1
        .with_empty_parachains(vec![1001, 1002])
958
1
        .build()
959
1
        .execute_with(|| {
960
1
            run_to_block(2);
961
            // Assert current slot gets updated
962
1
            assert_eq!(current_slot(), 1u64);
963
1
            assert!(current_author() == AccountId::from(BOB));
964

            
965
            // Alice and Bob are authorities
966
1
            let alice_id = get_aura_id_from_seed(&AccountId::from(ALICE).to_string());
967
1
            let bob_id = get_aura_id_from_seed(&AccountId::from(BOB).to_string());
968

            
969
1
            assert_eq!(authorities(), vec![alice_id, bob_id]);
970

            
971
            // Set orchestrator collators to 1
972
1
            assert_ok!(
973
1
                Configuration::set_max_orchestrator_collators(root_origin(), 1),
974
                ()
975
            );
976

            
977
            // Set container chain collators to 3
978
1
            assert_ok!(
979
1
                Configuration::set_collators_per_container(root_origin(), 3),
980
                ()
981
            );
982

            
983
            // Charlie and Dave to 1001
984
1
            let assignment = CollatorAssignment::collator_container_chain();
985
1
            assert_eq!(
986
1
                assignment.container_chains[&1001u32.into()],
987
1
                vec![CHARLIE.into(), DAVE.into()]
988
            );
989

            
990
            // Assignment should happen after 2 sessions
991
1
            run_to_session(1u32);
992

            
993
1
            let assignment = CollatorAssignment::collator_container_chain();
994
1
            assert_eq!(
995
1
                assignment.container_chains[&1001u32.into()],
996
1
                vec![CHARLIE.into(), DAVE.into()]
997
            );
998

            
999
1
            run_to_session(2u32);
            // Charlie, Dave and BOB should be assigne dot para 1001 this time
1
            let assignment = CollatorAssignment::collator_container_chain();
1
            assert_eq!(
1
                assignment.container_chains[&1001u32.into()],
1
                vec![CHARLIE.into(), DAVE.into(), BOB.into()]
            );
1
            assert_eq!(assignment.orchestrator_chain, vec![ALICE.into()]);
1
        });
1
}
#[test]
1
fn test_orchestrator_collators_with_non_sufficient_collators() {
1
    ExtBuilder::default()
1
        .with_balances(vec![
1
            // Alice gets 10k extra tokens for her mapping deposit
1
            (AccountId::from(ALICE), 210_000 * UNIT),
1
        ])
1
        .with_collators(vec![(AccountId::from(ALICE), 210 * UNIT)])
1
        .with_empty_parachains(vec![1001, 1002])
1
        .build()
1
        .execute_with(|| {
1
            run_to_block(2);
            // Assert current slot gets updated
1
            assert_eq!(current_slot(), 1u64);
1
            assert!(current_author() == AccountId::from(ALICE));
            // Alice and Bob are authorities
1
            let alice_id = get_aura_id_from_seed(&AccountId::from(ALICE).to_string());
1
            assert_eq!(authorities(), vec![alice_id]);
1
        });
1
}
#[test]
1
fn test_configuration_on_session_change() {
1
    ExtBuilder::default().build().execute_with(|| {
1
        assert_eq!(Configuration::config().max_collators, 100);
1
        assert_eq!(Configuration::config().min_orchestrator_collators, 2);
1
        assert_eq!(Configuration::config().collators_per_container, 2);
1
        assert_ok!(Configuration::set_max_collators(root_origin(), 50), ());
1
        run_to_session(1u32);
1
        assert_ok!(
1
            Configuration::set_min_orchestrator_collators(root_origin(), 20),
            ()
        );
1
        assert_eq!(Configuration::config().max_collators, 100);
1
        assert_eq!(Configuration::config().min_orchestrator_collators, 2);
1
        assert_eq!(Configuration::config().collators_per_container, 2);
1
        run_to_session(2u32);
1
        assert_ok!(
1
            Configuration::set_collators_per_container(root_origin(), 10),
            ()
        );
1
        assert_eq!(Configuration::config().max_collators, 50);
1
        assert_eq!(Configuration::config().min_orchestrator_collators, 2);
1
        assert_eq!(Configuration::config().collators_per_container, 2);
1
        run_to_session(3u32);
1
        assert_eq!(Configuration::config().max_collators, 50);
1
        assert_eq!(Configuration::config().min_orchestrator_collators, 20);
1
        assert_eq!(Configuration::config().collators_per_container, 2);
1
        run_to_session(4u32);
1
        assert_eq!(Configuration::config().max_collators, 50);
1
        assert_eq!(Configuration::config().min_orchestrator_collators, 20);
1
        assert_eq!(Configuration::config().collators_per_container, 10);
1
    });
1
}
#[test]
1
fn test_author_collation_aura_add_assigned_to_paras_runtime_api() {
1
    ExtBuilder::default()
1
        .with_balances(vec![
1
            // Alice gets 10k extra tokens for her mapping deposit
1
            (AccountId::from(ALICE), 210_000 * UNIT),
1
            (AccountId::from(BOB), 100_000 * UNIT),
1
            (AccountId::from(CHARLIE), 100_000 * UNIT),
1
            (AccountId::from(DAVE), 100_000 * UNIT),
1
        ])
1
        .with_empty_parachains(vec![1001, 1002])
1
        .build()
1
        .execute_with(|| {
1
            run_to_block(2);
            // Assert current slot gets updated
1
            assert_eq!(current_slot(), 1u64);
1
            assert!(current_author() == AccountId::from(BOB));
1
            assert_eq!(
1
                parachain_collators(100.into()),
1
                Some(vec![ALICE.into(), BOB.into()])
            );
1
            assert_eq!(parachain_collators(1001.into()), Some(vec![]));
1
            assert_eq!(
1
                current_collator_parachain_assignment(ALICE.into()),
1
                Some(100.into())
            );
1
            assert_eq!(
1
                future_collator_parachain_assignment(ALICE.into()),
1
                Some(100.into())
            );
1
            assert_eq!(current_collator_parachain_assignment(CHARLIE.into()), None);
1
            assert_eq!(future_collator_parachain_assignment(CHARLIE.into()), None);
            // We change invulnerables
            // We first need to set the keys
1
            let alice_id = get_aura_id_from_seed(&AccountId::from(ALICE).to_string());
1
            let bob_id = get_aura_id_from_seed(&AccountId::from(BOB).to_string());
1
            let charlie_id = get_aura_id_from_seed(&AccountId::from(CHARLIE).to_string());
1
            let dave_id = get_aura_id_from_seed(&AccountId::from(DAVE).to_string());
            // Set CHARLIE and DAVE keys
1
            assert_ok!(Session::set_keys(
1
                origin_of(CHARLIE.into()),
1
                crate::SessionKeys { nimbus: charlie_id },
1
                vec![]
            ));
1
            assert_ok!(Session::set_keys(
1
                origin_of(DAVE.into()),
1
                crate::SessionKeys { nimbus: dave_id },
1
                vec![]
            ));
            // Set new invulnerables
1
            assert_ok!(Invulnerables::add_invulnerable(
1
                root_origin(),
1
                CHARLIE.into()
            ));
1
            assert_ok!(Invulnerables::add_invulnerable(root_origin(), DAVE.into()));
            // SESSION CHANGE. First session. it takes 2 sessions to see the change
1
            run_to_session(1u32);
1
            let author = get_orchestrator_current_author().unwrap();
1
            assert_eq!(current_author(), author);
1
            assert_eq!(authorities(), vec![alice_id.clone(), bob_id.clone()]);
1
            assert_eq!(
1
                parachain_collators(100.into()),
1
                Some(vec![ALICE.into(), BOB.into()])
            );
1
            assert_eq!(parachain_collators(1001.into()), Some(vec![]));
1
            assert_eq!(current_collator_parachain_assignment(CHARLIE.into()), None);
1
            assert_eq!(
1
                future_collator_parachain_assignment(CHARLIE.into()),
1
                Some(1001.into())
            );
            // Invulnerables should have triggered on new session authorities change
            // However charlie and dave shoudl have gone to one para (1001)
1
            run_to_session(2u32);
1
            assert_eq!(authorities(), vec![alice_id, bob_id]);
1
            let assignment = CollatorAssignment::collator_container_chain();
1
            assert_eq!(
1
                assignment.container_chains[&1001u32.into()],
1
                vec![CHARLIE.into(), DAVE.into()]
            );
1
            assert_eq!(
1
                parachain_collators(100.into()),
1
                Some(vec![ALICE.into(), BOB.into()])
            );
1
            assert_eq!(
1
                parachain_collators(1001.into()),
1
                Some(vec![CHARLIE.into(), DAVE.into()])
            );
1
            assert_eq!(
1
                current_collator_parachain_assignment(CHARLIE.into()),
1
                Some(1001.into())
            );
1
            assert_eq!(
1
                future_collator_parachain_assignment(CHARLIE.into()),
1
                Some(1001.into())
            );
            // Remove BOB
1
            assert_ok!(Invulnerables::remove_invulnerable(
1
                root_origin(),
1
                BOB.into()
            ));
1
            run_to_session(3u32);
1
            assert_eq!(
1
                parachain_collators(100.into()),
1
                Some(vec![ALICE.into(), BOB.into()])
            );
1
            assert_eq!(
1
                parachain_collators(1001.into()),
1
                Some(vec![CHARLIE.into(), DAVE.into()])
            );
1
            assert_eq!(
1
                current_collator_parachain_assignment(BOB.into()),
1
                Some(100.into())
            );
1
            assert_eq!(future_collator_parachain_assignment(BOB.into()), None);
1
            run_to_session(4u32);
1
            assert_eq!(
1
                parachain_collators(100.into()),
1
                Some(vec![ALICE.into(), CHARLIE.into()])
            );
1
            assert_eq!(parachain_collators(1001.into()), Some(vec![]));
1
            assert_eq!(current_collator_parachain_assignment(BOB.into()), None);
1
            assert_eq!(future_collator_parachain_assignment(BOB.into()), None);
1
        });
1
}
#[test]
1
fn test_consensus_runtime_api() {
1
    ExtBuilder::default()
1
        .with_balances(vec![
1
            // Alice gets 10k extra tokens for her mapping deposit
1
            (AccountId::from(ALICE), 210_000 * UNIT),
1
            (AccountId::from(BOB), 100_000 * UNIT),
1
            (AccountId::from(CHARLIE), 100_000 * UNIT),
1
            (AccountId::from(DAVE), 100_000 * UNIT),
1
        ])
1
        .with_empty_parachains(vec![1001, 1002])
1
        .build()
1
        .execute_with(|| {
1
            run_to_block(2);
1
            let alice_id = get_aura_id_from_seed(&AccountId::from(ALICE).to_string());
1
            let bob_id = get_aura_id_from_seed(&AccountId::from(BOB).to_string());
1
            let charlie_id = get_aura_id_from_seed(&AccountId::from(CHARLIE).to_string());
1
            let dave_id = get_aura_id_from_seed(&AccountId::from(DAVE).to_string());
1
            assert_eq!(
1
                Runtime::para_id_authorities(100.into()),
1
                Some(vec![alice_id.clone(), bob_id.clone()])
            );
1
            assert_eq!(Runtime::para_id_authorities(1001.into()), Some(vec![]));
1
            assert_eq!(
1
                Runtime::check_para_id_assignment(alice_id.clone()),
1
                Some(100.into())
            );
1
            assert_eq!(
1
                Runtime::check_para_id_assignment(bob_id.clone()),
1
                Some(100.into())
            );
1
            assert_eq!(Runtime::check_para_id_assignment(charlie_id.clone()), None);
1
            assert_eq!(Runtime::check_para_id_assignment(dave_id.clone()), None);
            // Set CHARLIE and DAVE keys
1
            assert_ok!(Session::set_keys(
1
                origin_of(CHARLIE.into()),
1
                crate::SessionKeys {
1
                    nimbus: charlie_id.clone(),
1
                },
1
                vec![]
            ));
1
            assert_ok!(Session::set_keys(
1
                origin_of(DAVE.into()),
1
                crate::SessionKeys {
1
                    nimbus: dave_id.clone(),
1
                },
1
                vec![]
            ));
            // Set new invulnerables
1
            assert_ok!(Invulnerables::add_invulnerable(
1
                root_origin(),
1
                CHARLIE.into()
            ));
1
            assert_ok!(Invulnerables::add_invulnerable(root_origin(), DAVE.into()));
1
            run_to_session(2u32);
1
            assert_eq!(
1
                Runtime::para_id_authorities(100.into()),
1
                Some(vec![alice_id.clone(), bob_id.clone()])
            );
1
            assert_eq!(
1
                Runtime::para_id_authorities(1001.into()),
1
                Some(vec![charlie_id.clone(), dave_id.clone()])
            );
1
            assert_eq!(
1
                Runtime::check_para_id_assignment(alice_id),
1
                Some(100.into())
            );
1
            assert_eq!(Runtime::check_para_id_assignment(bob_id), Some(100.into()));
1
            assert_eq!(
1
                Runtime::check_para_id_assignment(charlie_id),
1
                Some(1001.into())
            );
1
            assert_eq!(
1
                Runtime::check_para_id_assignment(dave_id),
1
                Some(1001.into())
            );
1
        });
1
}
#[test]
1
fn test_consensus_runtime_api_session_changes() {
    // The test shoul return always the assiignment on the next epoch
    // Meaning that we need to see before the session change block
    // if we can predict correctly
1
    ExtBuilder::default()
1
        .with_balances(vec![
1
            // Alice gets 10k extra tokens for her mapping deposit
1
            (AccountId::from(ALICE), 210_000 * UNIT),
1
            (AccountId::from(BOB), 100_000 * UNIT),
1
            (AccountId::from(CHARLIE), 100_000 * UNIT),
1
            (AccountId::from(DAVE), 100_000 * UNIT),
1
        ])
1
        .with_empty_parachains(vec![1001, 1002])
1
        .build()
1
        .execute_with(|| {
1
            run_to_block(2);
1
            let alice_id = get_aura_id_from_seed(&AccountId::from(ALICE).to_string());
1
            let bob_id = get_aura_id_from_seed(&AccountId::from(BOB).to_string());
1
            let charlie_id = get_aura_id_from_seed(&AccountId::from(CHARLIE).to_string());
1
            let dave_id = get_aura_id_from_seed(&AccountId::from(DAVE).to_string());
1
            assert_eq!(
1
                Runtime::para_id_authorities(100.into()),
1
                Some(vec![alice_id.clone(), bob_id.clone()])
            );
1
            assert_eq!(Runtime::para_id_authorities(1001.into()), Some(vec![]));
1
            assert_eq!(
1
                Runtime::check_para_id_assignment(alice_id.clone()),
1
                Some(100.into())
            );
1
            assert_eq!(
1
                Runtime::check_para_id_assignment(bob_id.clone()),
1
                Some(100.into())
            );
1
            assert_eq!(Runtime::check_para_id_assignment(charlie_id.clone()), None);
1
            assert_eq!(Runtime::check_para_id_assignment(dave_id.clone()), None);
            // Set CHARLIE and DAVE keys
1
            assert_ok!(Session::set_keys(
1
                origin_of(CHARLIE.into()),
1
                crate::SessionKeys {
1
                    nimbus: charlie_id.clone(),
1
                },
1
                vec![]
            ));
1
            assert_ok!(Session::set_keys(
1
                origin_of(DAVE.into()),
1
                crate::SessionKeys {
1
                    nimbus: dave_id.clone(),
1
                },
1
                vec![]
            ));
            // Set new invulnerables
1
            assert_ok!(Invulnerables::add_invulnerable(
1
                root_origin(),
1
                CHARLIE.into()
            ));
1
            assert_ok!(Invulnerables::add_invulnerable(root_origin(), DAVE.into()));
1
            let session_two_edge = crate::Period::get() * 2;
            // Let's run just 2 blocks before the session 2 change first
            // Prediction should still be identical, as we are not in the
            // edge of a session change
1
            run_to_block(session_two_edge - 2);
1
            assert_eq!(
1
                Runtime::para_id_authorities(100.into()),
1
                Some(vec![alice_id.clone(), bob_id.clone()])
            );
1
            assert_eq!(Runtime::para_id_authorities(1001.into()), Some(vec![]));
1
            assert_eq!(
1
                Runtime::check_para_id_assignment(alice_id.clone()),
1
                Some(100.into())
            );
1
            assert_eq!(
1
                Runtime::check_para_id_assignment(bob_id.clone()),
1
                Some(100.into())
            );
1
            assert_eq!(Runtime::check_para_id_assignment(charlie_id.clone()), None);
1
            assert_eq!(Runtime::check_para_id_assignment(dave_id.clone()), None);
            // Now we run to session edge -1. Here we should predict already with
            // authorities of the next block!
1
            run_to_block(session_two_edge - 1);
1
            assert_eq!(
1
                Runtime::para_id_authorities(100.into()),
1
                Some(vec![alice_id.clone(), bob_id.clone()])
            );
1
            assert_eq!(
1
                Runtime::para_id_authorities(1001.into()),
1
                Some(vec![charlie_id.clone(), dave_id.clone()])
            );
1
            assert_eq!(
1
                Runtime::check_para_id_assignment(alice_id),
1
                Some(100.into())
            );
1
            assert_eq!(Runtime::check_para_id_assignment(bob_id), Some(100.into()));
1
            assert_eq!(
1
                Runtime::check_para_id_assignment(charlie_id),
1
                Some(1001.into())
            );
1
            assert_eq!(
1
                Runtime::check_para_id_assignment(dave_id),
1
                Some(1001.into())
            );
1
        });
1
}
#[test]
1
fn test_consensus_runtime_api_next_session() {
1
    ExtBuilder::default()
1
        .with_balances(vec![
1
            // Alice gets 10k extra tokens for her mapping deposit
1
            (AccountId::from(ALICE), 210_000 * UNIT),
1
            (AccountId::from(BOB), 100_000 * UNIT),
1
            (AccountId::from(CHARLIE), 100_000 * UNIT),
1
            (AccountId::from(DAVE), 100_000 * UNIT),
1
        ])
1
        .with_empty_parachains(vec![1001, 1002])
1
        .build()
1
        .execute_with(|| {
1
            run_to_block(2);
1
            let alice_id = get_aura_id_from_seed(&AccountId::from(ALICE).to_string());
1
            let bob_id = get_aura_id_from_seed(&AccountId::from(BOB).to_string());
1
            let charlie_id = get_aura_id_from_seed(&AccountId::from(CHARLIE).to_string());
1
            let dave_id = get_aura_id_from_seed(&AccountId::from(DAVE).to_string());
1
            assert_eq!(
1
                Runtime::para_id_authorities(100.into()),
1
                Some(vec![alice_id.clone(), bob_id.clone()])
            );
1
            assert_eq!(Runtime::para_id_authorities(1001.into()), Some(vec![]));
1
            assert_eq!(
1
                Runtime::check_para_id_assignment(alice_id.clone()),
1
                Some(100.into())
            );
1
            assert_eq!(
1
                Runtime::check_para_id_assignment(bob_id.clone()),
1
                Some(100.into())
            );
1
            assert_eq!(Runtime::check_para_id_assignment(charlie_id.clone()), None);
1
            assert_eq!(Runtime::check_para_id_assignment(dave_id.clone()), None);
            // In the next session the assignment will not change
1
            assert_eq!(
1
                Runtime::check_para_id_assignment_next_session(alice_id.clone()),
1
                Some(100.into())
            );
1
            assert_eq!(
1
                Runtime::check_para_id_assignment_next_session(bob_id.clone()),
1
                Some(100.into())
            );
1
            assert_eq!(
1
                Runtime::check_para_id_assignment_next_session(charlie_id.clone()),
                None,
            );
1
            assert_eq!(
1
                Runtime::check_para_id_assignment_next_session(dave_id.clone()),
                None,
            );
            // Set CHARLIE and DAVE keys
1
            assert_ok!(Session::set_keys(
1
                origin_of(CHARLIE.into()),
1
                crate::SessionKeys {
1
                    nimbus: charlie_id.clone(),
1
                },
1
                vec![]
            ));
1
            assert_ok!(Session::set_keys(
1
                origin_of(DAVE.into()),
1
                crate::SessionKeys {
1
                    nimbus: dave_id.clone(),
1
                },
1
                vec![]
            ));
            // Set new invulnerables
1
            assert_ok!(Invulnerables::add_invulnerable(
1
                root_origin(),
1
                CHARLIE.into()
            ));
1
            assert_ok!(Invulnerables::add_invulnerable(root_origin(), DAVE.into()));
1
            let session_two_edge = crate::Period::get() * 2;
            // Let's run just 2 blocks before the session 2 change first
            // Prediction should still be identical, as we are not in the
            // edge of a session change
1
            run_to_block(session_two_edge - 2);
1
            assert_eq!(
1
                Runtime::para_id_authorities(100.into()),
1
                Some(vec![alice_id.clone(), bob_id.clone()])
            );
1
            assert_eq!(Runtime::para_id_authorities(1001.into()), Some(vec![]));
1
            assert_eq!(
1
                Runtime::check_para_id_assignment(alice_id.clone()),
1
                Some(100.into())
            );
1
            assert_eq!(
1
                Runtime::check_para_id_assignment(bob_id.clone()),
1
                Some(100.into())
            );
1
            assert_eq!(Runtime::check_para_id_assignment(charlie_id.clone()), None);
1
            assert_eq!(Runtime::check_para_id_assignment(dave_id.clone()), None);
            // But in the next session the assignment will change, so future api returns different value
1
            assert_eq!(
1
                Runtime::check_para_id_assignment_next_session(alice_id.clone()),
1
                Some(100.into())
            );
1
            assert_eq!(
1
                Runtime::check_para_id_assignment_next_session(bob_id.clone()),
1
                Some(100.into())
            );
1
            assert_eq!(
1
                Runtime::check_para_id_assignment_next_session(charlie_id.clone()),
1
                Some(1001.into()),
            );
1
            assert_eq!(
1
                Runtime::check_para_id_assignment_next_session(dave_id.clone()),
1
                Some(1001.into()),
            );
            // Now we run to session edge -1. Here we should predict already with
            // authorities of the next block!
1
            run_to_block(session_two_edge - 1);
1
            assert_eq!(
1
                Runtime::para_id_authorities(100.into()),
1
                Some(vec![alice_id.clone(), bob_id.clone()])
            );
1
            assert_eq!(
1
                Runtime::para_id_authorities(1001.into()),
1
                Some(vec![charlie_id.clone(), dave_id.clone()])
            );
1
            assert_eq!(
1
                Runtime::check_para_id_assignment(alice_id.clone()),
1
                Some(100.into())
            );
1
            assert_eq!(
1
                Runtime::check_para_id_assignment(bob_id.clone()),
1
                Some(100.into())
            );
1
            assert_eq!(
1
                Runtime::check_para_id_assignment(charlie_id.clone()),
1
                Some(1001.into())
            );
1
            assert_eq!(
1
                Runtime::check_para_id_assignment(dave_id.clone()),
1
                Some(1001.into())
            );
            // check_para_id_assignment_next_session returns the same value as check_para_id_assignment
            // because we are on a session boundary
1
            assert_eq!(
1
                Runtime::check_para_id_assignment_next_session(alice_id),
1
                Some(100.into())
            );
1
            assert_eq!(
1
                Runtime::check_para_id_assignment_next_session(bob_id),
1
                Some(100.into())
            );
1
            assert_eq!(
1
                Runtime::check_para_id_assignment_next_session(charlie_id),
1
                Some(1001.into())
            );
1
            assert_eq!(
1
                Runtime::check_para_id_assignment_next_session(dave_id),
1
                Some(1001.into())
            );
1
        });
1
}
#[test]
1
fn test_author_noting_self_para_id_not_noting() {
1
    ExtBuilder::default().build().execute_with(|| {
1
        let mut sproof = ParaHeaderSproofBuilder::default();
1
        let slot: u64 = 5;
1
        let self_para = parachain_info::Pallet::<Runtime>::get();
1
        let s = ParaHeaderSproofBuilderItem {
1
            para_id: self_para,
1
            author_id: HeaderAs::NonEncoded(sp_runtime::generic::Header::<u32, BlakeTwo256> {
1
                parent_hash: Default::default(),
1
                number: Default::default(),
1
                state_root: Default::default(),
1
                extrinsics_root: Default::default(),
1
                digest: sp_runtime::generic::Digest {
1
                    logs: vec![DigestItem::PreRuntime(AURA_ENGINE_ID, slot.encode())],
1
                },
1
            }),
1
        };
1
        sproof.items.push(s);
1
        set_author_noting_inherent_data(sproof);
1
        assert_eq!(AuthorNoting::latest_author(self_para), None);
1
    });
1
}
#[test]
1
fn test_author_noting_not_self_para() {
1
    ExtBuilder::default()
1
        .with_balances(vec![
1
            // Alice gets 10k extra tokens for her mapping deposit
1
            (AccountId::from(ALICE), 210_000 * UNIT),
1
            (AccountId::from(BOB), 100_000 * UNIT),
1
            (AccountId::from(CHARLIE), 100_000 * UNIT),
1
            (AccountId::from(DAVE), 100_000 * UNIT),
1
        ])
1
        .with_collators(vec![
1
            (AccountId::from(ALICE), 210 * UNIT),
1
            (AccountId::from(BOB), 100 * UNIT),
1
            (AccountId::from(CHARLIE), 100 * UNIT),
1
            (AccountId::from(DAVE), 100 * UNIT),
1
        ])
1
        .with_empty_parachains(vec![1001, 1002])
1
        .build()
1
        .execute_with(|| {
1
            let mut sproof = ParaHeaderSproofBuilder::default();
1
            let slot: u64 = 5;
1
            let other_para: ParaId = 1001u32.into();
            // Charlie and Dave to 1001
1
            let assignment = CollatorAssignment::collator_container_chain();
1
            assert_eq!(
1
                assignment.container_chains[&1001u32.into()],
1
                vec![CHARLIE.into(), DAVE.into()]
            );
1
            let s = ParaHeaderSproofBuilderItem {
1
                para_id: other_para,
1
                author_id: HeaderAs::NonEncoded(sp_runtime::generic::Header::<u32, BlakeTwo256> {
1
                    parent_hash: Default::default(),
1
                    number: 1,
1
                    state_root: Default::default(),
1
                    extrinsics_root: Default::default(),
1
                    digest: sp_runtime::generic::Digest {
1
                        logs: vec![DigestItem::PreRuntime(AURA_ENGINE_ID, slot.encode())],
1
                    },
1
                }),
1
            };
1
            sproof.items.push(s);
1
            set_author_noting_inherent_data(sproof);
1
            assert_eq!(
1
                AuthorNoting::latest_author(other_para),
1
                Some(ContainerChainBlockInfo {
1
                    block_number: 1,
1
                    author: AccountId::from(DAVE),
1
                    latest_slot_number: 0.into(),
1
                })
            );
1
        });
1
}
#[test]
1
fn test_author_noting_set_author_and_kill_author_data() {
1
    ExtBuilder::default()
1
        .with_balances(vec![
1
            // Alice gets 10k extra tokens for her mapping deposit
1
            (AccountId::from(ALICE), 210_000 * UNIT),
1
            (AccountId::from(BOB), 100_000 * UNIT),
1
            (AccountId::from(CHARLIE), 100_000 * UNIT),
1
            (AccountId::from(DAVE), 100_000 * UNIT),
1
        ])
1
        .with_collators(vec![
1
            (AccountId::from(ALICE), 210 * UNIT),
1
            (AccountId::from(BOB), 100 * UNIT),
1
            (AccountId::from(CHARLIE), 100 * UNIT),
1
            (AccountId::from(DAVE), 100 * UNIT),
1
        ])
1
        .with_empty_parachains(vec![1001, 1002])
1
        .build()
1
        .execute_with(|| {
1
            let other_para: ParaId = 1001u32.into();
1
            assert_ok!(AuthorNoting::set_author(
1
                root_origin(),
1
                other_para,
                1,
1
                AccountId::from(DAVE),
1
                1.into()
            ));
1
            assert_eq!(
1
                AuthorNoting::latest_author(other_para),
1
                Some(ContainerChainBlockInfo {
1
                    block_number: 1,
1
                    author: AccountId::from(DAVE),
1
                    latest_slot_number: 1.into(),
1
                })
            );
1
            assert_ok!(AuthorNoting::kill_author_data(root_origin(), other_para));
1
            assert_eq!(AuthorNoting::latest_author(other_para), None);
1
        });
1
}
#[test]
1
fn test_author_noting_set_author_and_kill_author_data_bad_origin() {
1
    ExtBuilder::default()
1
        .with_balances(vec![
1
            // Alice gets 10k extra tokens for her mapping deposit
1
            (AccountId::from(ALICE), 210_000 * UNIT),
1
            (AccountId::from(BOB), 100_000 * UNIT),
1
            (AccountId::from(CHARLIE), 100_000 * UNIT),
1
            (AccountId::from(DAVE), 100_000 * UNIT),
1
        ])
1
        .with_collators(vec![
1
            (AccountId::from(ALICE), 210 * UNIT),
1
            (AccountId::from(BOB), 100 * UNIT),
1
            (AccountId::from(CHARLIE), 100 * UNIT),
1
            (AccountId::from(DAVE), 100 * UNIT),
1
        ])
1
        .with_empty_parachains(vec![1001, 1002])
1
        .build()
1
        .execute_with(|| {
1
            let other_para: ParaId = 1001u32.into();
1
            assert_noop!(
1
                AuthorNoting::set_author(
1
                    origin_of(ALICE.into()),
1
                    other_para,
                    1,
1
                    AccountId::from(DAVE),
1
                    1.into()
                ),
1
                BadOrigin
            );
1
            assert_noop!(
1
                AuthorNoting::kill_author_data(origin_of(ALICE.into()), other_para),
1
                BadOrigin
            );
1
        });
1
}
#[test]
1
fn test_author_noting_runtime_api() {
1
    ExtBuilder::default()
1
        .with_balances(vec![
1
            // Alice gets 10k extra tokens for her mapping deposit
1
            (AccountId::from(ALICE), 210_000 * UNIT),
1
            (AccountId::from(BOB), 100_000 * UNIT),
1
            (AccountId::from(CHARLIE), 100_000 * UNIT),
1
            (AccountId::from(DAVE), 100_000 * UNIT),
1
        ])
1
        .with_collators(vec![
1
            (AccountId::from(ALICE), 210 * UNIT),
1
            (AccountId::from(BOB), 100 * UNIT),
1
            (AccountId::from(CHARLIE), 100 * UNIT),
1
            (AccountId::from(DAVE), 100 * UNIT),
1
        ])
1
        .with_empty_parachains(vec![1001, 1002])
1
        .build()
1
        .execute_with(|| {
1
            let mut sproof = ParaHeaderSproofBuilder::default();
1
            let slot: u64 = 5;
1
            let other_para: ParaId = 1001u32.into();
            // Charlie and Dave to 1001
1
            let assignment = CollatorAssignment::collator_container_chain();
1
            assert_eq!(
1
                assignment.container_chains[&1001u32.into()],
1
                vec![CHARLIE.into(), DAVE.into()]
            );
1
            let s = ParaHeaderSproofBuilderItem {
1
                para_id: other_para,
1
                author_id: HeaderAs::NonEncoded(sp_runtime::generic::Header::<u32, BlakeTwo256> {
1
                    parent_hash: Default::default(),
1
                    number: 1,
1
                    state_root: Default::default(),
1
                    extrinsics_root: Default::default(),
1
                    digest: sp_runtime::generic::Digest {
1
                        logs: vec![DigestItem::PreRuntime(AURA_ENGINE_ID, slot.encode())],
1
                    },
1
                }),
1
            };
1
            sproof.items.push(s);
1
            set_author_noting_inherent_data(sproof);
1
            assert_eq!(
1
                AuthorNoting::latest_author(other_para),
1
                Some(ContainerChainBlockInfo {
1
                    block_number: 1,
1
                    author: AccountId::from(DAVE),
1
                    latest_slot_number: 0.into(),
1
                })
            );
1
            assert_eq!(
1
                Runtime::latest_author(other_para),
1
                Some(AccountId::from(DAVE))
            );
1
            assert_eq!(Runtime::latest_block_number(other_para), Some(1));
1
        });
1
}
#[test]
1
fn session_keys_key_type_id() {
1
    assert_eq!(crate::SessionKeys::key_ids(), vec![NIMBUS_KEY_ID]);
1
}
#[test]
1
fn test_session_keys_with_authority_mapping() {
1
    ExtBuilder::default()
1
        .with_balances(vec![
1
            // Alice gets 10k extra tokens for her mapping deposit
1
            (AccountId::from(ALICE), 210_000 * UNIT),
1
            (AccountId::from(BOB), 100_000 * UNIT),
1
            (AccountId::from(CHARLIE), 100_000 * UNIT),
1
            (AccountId::from(DAVE), 100_000 * UNIT),
1
        ])
1
        .with_empty_parachains(vec![1001, 1002])
1
        .build()
1
        .execute_with(|| {
1
            run_to_block(2);
1
            let key_mapping_session_0 = AuthorityMapping::authority_id_mapping(0).unwrap();
1
            let alice_id = get_aura_id_from_seed(&AccountId::from(ALICE).to_string());
1
            let bob_id = get_aura_id_from_seed(&AccountId::from(BOB).to_string());
1
            let alice_id_2 = get_aura_id_from_seed("ALICE2");
1
            let bob_id_2 = get_aura_id_from_seed("BOB2");
1
            assert_eq!(key_mapping_session_0.len(), 2);
1
            assert_eq!(key_mapping_session_0.get(&alice_id), Some(&ALICE.into()));
1
            assert_eq!(key_mapping_session_0.get(&bob_id), Some(&BOB.into()));
            // Everything should match to aura
1
            assert_eq!(authorities(), vec![alice_id.clone(), bob_id.clone()]);
            // Change Alice and Bob keys to something different
            // for now lets change it to alice_2 and bob_2
1
            assert_ok!(Session::set_keys(
1
                origin_of(ALICE.into()),
1
                crate::SessionKeys {
1
                    nimbus: alice_id_2.clone(),
1
                },
1
                vec![]
            ));
1
            assert_ok!(Session::set_keys(
1
                origin_of(BOB.into()),
1
                crate::SessionKeys {
1
                    nimbus: bob_id_2.clone(),
1
                },
1
                vec![]
            ));
1
            run_to_session(1u32);
1
            let key_mapping_session_0 = AuthorityMapping::authority_id_mapping(0).unwrap();
1
            assert_eq!(key_mapping_session_0.len(), 2);
1
            assert_eq!(key_mapping_session_0.get(&alice_id), Some(&ALICE.into()));
1
            assert_eq!(key_mapping_session_0.get(&bob_id), Some(&BOB.into()));
1
            let key_mapping_session_1 = AuthorityMapping::authority_id_mapping(1).unwrap();
1
            assert_eq!(key_mapping_session_1.len(), 2);
1
            assert_eq!(key_mapping_session_1.get(&alice_id), Some(&ALICE.into()));
1
            assert_eq!(key_mapping_session_1.get(&bob_id), Some(&BOB.into()));
            // Everything should match to aura
1
            assert_eq!(authorities(), vec![alice_id.clone(), bob_id.clone()]);
            //
1
            run_to_session(2u32);
1
            assert!(AuthorityMapping::authority_id_mapping(0).is_none());
1
            let key_mapping_session_1 = AuthorityMapping::authority_id_mapping(1).unwrap();
1
            assert_eq!(key_mapping_session_1.len(), 2);
1
            assert_eq!(key_mapping_session_1.get(&alice_id), Some(&ALICE.into()));
1
            assert_eq!(key_mapping_session_1.get(&bob_id), Some(&BOB.into()));
1
            let key_mapping_session_2 = AuthorityMapping::authority_id_mapping(2).unwrap();
1
            assert_eq!(key_mapping_session_2.len(), 2);
1
            assert_eq!(key_mapping_session_2.get(&alice_id_2), Some(&ALICE.into()));
1
            assert_eq!(key_mapping_session_2.get(&bob_id_2), Some(&BOB.into()));
            // Everything should match to aura
1
            assert_eq!(authorities(), vec![alice_id_2, bob_id_2]);
1
        });
1
}
#[test]
1
fn test_session_keys_with_authority_assignment() {
1
    ExtBuilder::default()
1
        .with_balances(vec![
1
            // Alice gets 10k extra tokens for her mapping deposit
1
            (AccountId::from(ALICE), 210_000 * UNIT),
1
            (AccountId::from(BOB), 100_000 * UNIT),
1
            (AccountId::from(CHARLIE), 100_000 * UNIT),
1
            (AccountId::from(DAVE), 100_000 * UNIT),
1
        ])
1
        .with_empty_parachains(vec![1001, 1002])
1
        .build()
1
        .execute_with(|| {
1
            run_to_block(2);
1
            let alice_id = get_aura_id_from_seed(&AccountId::from(ALICE).to_string());
1
            let bob_id = get_aura_id_from_seed(&AccountId::from(BOB).to_string());
1
            let alice_id_2 = get_aura_id_from_seed("ALICE2");
1
            let bob_id_2 = get_aura_id_from_seed("BOB2");
1
            let key_mapping_session_0 = AuthorityAssignment::collator_container_chain(0).unwrap();
1
            assert_eq!(
                key_mapping_session_0.orchestrator_chain,
1
                vec![alice_id.clone(), bob_id.clone()],
            );
1
            assert_eq!(
1
                CollatorAssignment::collator_container_chain().orchestrator_chain,
1
                vec![AccountId::from(ALICE), AccountId::from(BOB)],
            );
1
            let key_mapping_session_1 = AuthorityAssignment::collator_container_chain(1).unwrap();
1
            assert_eq!(key_mapping_session_1, key_mapping_session_0,);
1
            let old_assignment_session_1 =
1
                CollatorAssignment::pending_collator_container_chain().unwrap();
1
            assert_eq!(
                old_assignment_session_1,
1
                CollatorAssignment::collator_container_chain(),
            );
1
            let key_mapping_session_2 = AuthorityAssignment::collator_container_chain(2);
1
            assert!(key_mapping_session_2.is_none());
            // Everything should match to aura
1
            assert_eq!(authorities(), vec![alice_id.clone(), bob_id.clone()]);
            // Change Alice and Bob keys to something different
            // for now lets change it to alice_2 and bob_2
1
            assert_ok!(Session::set_keys(
1
                origin_of(ALICE.into()),
1
                crate::SessionKeys {
1
                    nimbus: alice_id_2.clone(),
1
                },
1
                vec![]
            ));
1
            assert_ok!(Session::set_keys(
1
                origin_of(BOB.into()),
1
                crate::SessionKeys {
1
                    nimbus: bob_id_2.clone(),
1
                },
1
                vec![]
            ));
1
            run_to_session(1u32);
1
            let old_key_mapping_session_1 = key_mapping_session_1;
            // Session 0 got removed
1
            let key_mapping_session_0 = AuthorityAssignment::collator_container_chain(0);
1
            assert!(key_mapping_session_0.is_none());
            // The values at session 1 did not change
1
            let key_mapping_session_1 = AuthorityAssignment::collator_container_chain(1).unwrap();
1
            assert_eq!(key_mapping_session_1, old_key_mapping_session_1,);
1
            assert_eq!(
1
                CollatorAssignment::collator_container_chain(),
                old_assignment_session_1,
            );
            // Session 2 uses the new keys
1
            let key_mapping_session_2 = AuthorityAssignment::collator_container_chain(2).unwrap();
1
            assert_eq!(
                key_mapping_session_2.orchestrator_chain,
1
                vec![alice_id_2.clone(), bob_id_2.clone()],
            );
1
            assert_eq!(CollatorAssignment::pending_collator_container_chain(), None);
1
            let key_mapping_session_3 = AuthorityAssignment::collator_container_chain(3);
1
            assert!(key_mapping_session_3.is_none());
            // Everything should match to aura
1
            assert_eq!(authorities(), vec![alice_id, bob_id]);
1
            run_to_session(2u32);
            // Session 1 got removed
1
            let key_mapping_session_1 = AuthorityAssignment::collator_container_chain(1);
1
            assert!(key_mapping_session_1.is_none());
            // Session 2 uses the new keys
1
            let key_mapping_session_2 = AuthorityAssignment::collator_container_chain(2).unwrap();
1
            assert_eq!(
                key_mapping_session_2.orchestrator_chain,
1
                vec![alice_id_2.clone(), bob_id_2.clone()],
            );
1
            assert_eq!(
                old_assignment_session_1,
1
                CollatorAssignment::collator_container_chain(),
            );
            // Session 3 uses the new keys
1
            let key_mapping_session_3 = AuthorityAssignment::collator_container_chain(3).unwrap();
1
            assert_eq!(
                key_mapping_session_3.orchestrator_chain,
1
                vec![alice_id_2.clone(), bob_id_2.clone()],
            );
1
            assert_eq!(CollatorAssignment::pending_collator_container_chain(), None);
1
            let key_mapping_session_4 = AuthorityAssignment::collator_container_chain(4);
1
            assert!(key_mapping_session_4.is_none());
            // Everything should match to aura
1
            assert_eq!(authorities(), vec![alice_id_2, bob_id_2]);
1
        });
1
}
2
fn call_transfer(
2
    dest: sp_runtime::MultiAddress<sp_runtime::AccountId32, ()>,
2
    value: u128,
2
) -> RuntimeCall {
2
    RuntimeCall::Balances(pallet_balances::Call::transfer_allow_death { dest, value })
2
}
#[test]
1
fn test_proxy_any() {
1
    ExtBuilder::default()
1
        .with_balances(vec![
1
            // Alice gets 10k extra tokens for her mapping deposit
1
            (AccountId::from(ALICE), 210_000 * UNIT),
1
            (AccountId::from(BOB), 100_000 * UNIT),
1
            (AccountId::from(CHARLIE), 100_000 * UNIT),
1
            (AccountId::from(DAVE), 100_000 * UNIT),
1
        ])
1
        .build()
1
        .execute_with(|| {
1
            run_to_block(2);
1
            let delay = 0;
1
            assert_ok!(Proxy::add_proxy(
1
                origin_of(ALICE.into()),
1
                AccountId::from(BOB).into(),
1
                ProxyType::Any,
1
                delay
            ));
1
            let balance_before = System::account(AccountId::from(BOB)).data.free;
1
            let call = Box::new(call_transfer(AccountId::from(BOB).into(), 200_000));
1
            assert_ok!(Proxy::proxy(
1
                origin_of(BOB.into()),
1
                AccountId::from(ALICE).into(),
1
                None,
1
                call
            ));
1
            let balance_after = System::account(AccountId::from(BOB)).data.free;
1
            assert_eq!(balance_after, balance_before + 200_000);
1
        });
1
}
#[test]
1
fn test_proxy_non_transfer() {
1
    ExtBuilder::default()
1
        .with_balances(vec![
1
            // Alice gets 10k extra tokens for her mapping deposit
1
            (AccountId::from(ALICE), 210_000 * UNIT),
1
            (AccountId::from(BOB), 100_000 * UNIT),
1
            (AccountId::from(CHARLIE), 100_000 * UNIT),
1
            (AccountId::from(DAVE), 100_000 * UNIT),
1
        ])
1
        .build()
1
        .execute_with(|| {
1
            run_to_block(2);
1
            let delay = 0;
1
            assert_ok!(Proxy::add_proxy(
1
                origin_of(ALICE.into()),
1
                AccountId::from(BOB).into(),
1
                ProxyType::NonTransfer,
1
                delay
            ));
1
            let balance_before = System::account(AccountId::from(BOB)).data.free;
1
            let call = Box::new(call_transfer(AccountId::from(BOB).into(), 200_000));
            // The extrinsic succeeds but the call is filtered, so no transfer is actually done
1
            assert_ok!(Proxy::proxy(
1
                origin_of(BOB.into()),
1
                AccountId::from(ALICE).into(),
1
                None,
1
                call
            ));
1
            let balance_after = System::account(AccountId::from(BOB)).data.free;
1
            assert_eq!(balance_after, balance_before);
1
        });
1
}
#[test]
1
fn test_proxy_utility() {
    // All proxy types should be able to use Utility pallet, but we ensure
    // subcalls don't allow to circumvent filters.
    // Dummy match to ensure we update this test when adding new proxy types.
1
    match ProxyType::Any {
        ProxyType::Any
        | ProxyType::NonTransfer
        | ProxyType::Governance
        | ProxyType::Staking
        | ProxyType::CancelProxy
        | ProxyType::Balances
        | ProxyType::Registrar
1
        | ProxyType::SudoRegistrar => (),
    };
    // All except for any
1
    let proxy_types = &[
1
        ProxyType::NonTransfer,
1
        ProxyType::Governance,
1
        ProxyType::Staking,
1
        ProxyType::CancelProxy,
1
        ProxyType::Balances,
1
        ProxyType::Registrar,
1
        ProxyType::SudoRegistrar,
1
    ];
8
    for &proxy_type in proxy_types {
7
        ExtBuilder::default()
7
            .with_balances(vec![
7
                // Alice gets 10k extra tokens for her mapping deposit
7
                (AccountId::from(ALICE), 210_000 * UNIT),
7
                (AccountId::from(BOB), 100_000 * UNIT),
7
                (AccountId::from(CHARLIE), 100_000 * UNIT),
7
                (AccountId::from(DAVE), 100_000 * UNIT),
7
            ])
7
            .with_sudo(AccountId::from(ALICE))
7
            .build()
7
            .execute_with(|| {
7
                assert_ok!(Proxy::add_proxy(
7
                    origin_of(ALICE.into()),
7
                    AccountId::from(BOB).into(),
7
                    proxy_type,
                    0
                ));
7
                let free_balance = Balances::free_balance(AccountId::from(BOB));
7
                assert_ok!(Proxy::proxy(
7
                    origin_of(BOB.into()),
7
                    AccountId::from(ALICE).into(),
7
                    None,
7
                    Box::new(
7
                        pallet_sudo::Call::sudo {
7
                            call: Box::new(
7
                                pallet_utility::Call::batch {
7
                                    calls: vec![pallet_balances::Call::force_set_balance {
7
                                        who: AccountId::from(BOB).into(),
7
                                        new_free: 42424242424242
7
                                    }
7
                                    .into()]
7
                                }
7
                                .into()
7
                            )
7
                        }
7
                        .into()
                    )
                ));
7
                assert_eq!(Balances::free_balance(AccountId::from(BOB)), free_balance);
7
            });
    }
1
}
#[test]
1
fn check_well_known_keys() {
    use frame_support::traits::PalletInfo;
    // Pallet is named "Paras" in Polkadot.
1
    assert_eq!(
        well_known_keys::PARAS_HEADS_INDEX,
1
        frame_support::storage::storage_prefix(b"Paras", b"Heads")
    );
    // Tanssi storage. Since we cannot access the storages themselves,
    // we test the pallet prefix matches and then compute manually the full prefix.
1
    assert_eq!(
1
        crate::PalletInfo::name::<AuthorityAssignment>(),
        Some("AuthorityAssignment")
    );
1
    assert_eq!(
        well_known_keys::AUTHORITY_ASSIGNMENT_PREFIX,
1
        frame_support::storage::storage_prefix(b"AuthorityAssignment", b"CollatorContainerChain")
    );
1
    assert_eq!(crate::PalletInfo::name::<Session>(), Some("Session"));
1
    assert_eq!(
        well_known_keys::SESSION_INDEX,
1
        frame_support::storage::storage_prefix(b"Session", b"CurrentIndex")
    );
1
}
#[test]
1
fn test_reward_to_invulnerable() {
    // Alice, Bob, Charlie are invulnerables
1
    ExtBuilder::default()
1
        .with_balances(vec![
1
            // Alice gets 10k extra tokens for her mapping deposit
1
            (AccountId::from(ALICE), 210_000 * UNIT),
1
            (AccountId::from(BOB), 100_000 * UNIT),
1
            (AccountId::from(CHARLIE), 100_000 * UNIT),
1
            (AccountId::from(DAVE), 100_000 * UNIT),
1
        ])
1
        .with_collators(vec![
1
            (AccountId::from(ALICE), 210 * UNIT),
1
            (AccountId::from(BOB), 100 * UNIT),
1
            (AccountId::from(CHARLIE), 100 * UNIT),
1
        ])
1
        .with_empty_parachains(vec![1001, 1002])
1
        .build()
1
        .execute_with(|| {
1
            run_to_block(2);
            // We make delegations to ALICE so that she is an elligible candidate.
            // However since she is an invulnerable she should get all the
            // rewards.
            // wait for next session so that ALICE is elected
1
            run_to_session(4u32);
1
            let account: AccountId = ALICE.into();
1
            let balance_before = System::account(account.clone()).data.free;
1
            let summary = (0..100)
2
                .find_map(|_| {
2
                    let summary = run_block();
2
                    if summary.author_id == ALICE.into() {
1
                        Some(summary)
                    } else {
1
                        None
                    }
2
                })
1
                .unwrap_or_else(|| panic!("ALICE doesn't seem to author any blocks"));
1
            let balance_after = System::account(account).data.free;
1
            let all_rewards = RewardsPortion::get() * summary.inflation;
            // rewards are shared between orchestrator and registered paras
1
            let orchestrator_rewards = all_rewards / 3;
1
            assert_eq!(
                orchestrator_rewards,
1
                balance_after - balance_before,
                "alice should get the correct reward portion"
            );
1
        });
1
}
#[test]
1
fn test_reward_to_invulnerable_with_key_change() {
1
    ExtBuilder::default()
1
        .with_balances(vec![
1
            // Alice gets 10k extra tokens for her mapping deposit
1
            (AccountId::from(ALICE), 210_000 * UNIT),
1
            (AccountId::from(BOB), 100_000 * UNIT),
1
            (AccountId::from(CHARLIE), 100_000 * UNIT),
1
            (AccountId::from(DAVE), 100_000 * UNIT),
1
        ])
1
        .with_collators(vec![(AccountId::from(ALICE), 210 * UNIT)])
1
        .with_empty_parachains(vec![1001, 1002])
1
        .build()
1
        .execute_with(|| {
1
            run_to_block(2);
1
            run_to_session(2u32);
            // change key, this should be reflected 2 sessions afterward
1
            let alice_new_key = get_aura_id_from_seed(&AccountId::from(DAVE).to_string());
1
            assert_ok!(Session::set_keys(
1
                origin_of(ALICE.into()),
1
                crate::SessionKeys {
1
                    nimbus: alice_new_key,
1
                },
1
                vec![]
            ));
1
            run_to_session(4u32);
1
            let account: AccountId = ALICE.into();
1
            let balance_before = System::account(account.clone()).data.free;
1
            let summary = run_block();
1
            assert_eq!(summary.author_id, ALICE.into());
1
            let balance_after = System::account(account).data.free;
1
            let all_rewards = RewardsPortion::get() * summary.inflation;
            // rewards are shared between orchestrator and registered paras
1
            let orchestrator_rewards = all_rewards / 3;
1
            assert_eq!(
                orchestrator_rewards,
1
                balance_after - balance_before,
                "alice should get the correct reward portion"
            );
1
        });
1
}
#[test]
1
fn test_can_buy_credits_before_registering_para() {
1
    ExtBuilder::default()
1
        .with_balances(vec![
1
            // Alice gets 10k extra tokens for her mapping deposit
1
            (AccountId::from(ALICE), 210_000 * UNIT),
1
            (AccountId::from(BOB), 100_000 * UNIT),
1
            (AccountId::from(CHARLIE), 100_000 * UNIT),
1
            (AccountId::from(DAVE), 100_000 * UNIT),
1
        ])
1
        .with_collators(vec![
1
            (AccountId::from(ALICE), 210 * UNIT),
1
            (AccountId::from(BOB), 100 * UNIT),
1
            (AccountId::from(CHARLIE), 100 * UNIT),
1
            (AccountId::from(DAVE), 100 * UNIT),
1
        ])
1
        .build()
1
        .execute_with(|| {
1
            run_to_block(2);
            // Try to buy the maximum amount of credits
1
            let balance_before = System::account(AccountId::from(ALICE)).data.free;
1
            assert_ok!(ServicesPayment::purchase_credits(
1
                origin_of(ALICE.into()),
1
                1001.into(),
1
                block_credits_to_required_balance(u32::MAX, 1001.into())
            ));
1
            let balance_after = System::account(AccountId::from(ALICE)).data.free;
            // Now parachain tank should have this amount
1
            let balance_tank = System::account(ServicesPayment::parachain_tank(1001.into()))
1
                .data
1
                .free;
1
            assert_eq!(
                balance_tank,
1
                block_credits_to_required_balance(u32::MAX, 1001.into())
            );
1
            let expected_cost = block_credits_to_required_balance(u32::MAX, 1001.into());
1
            assert_eq!(balance_before - balance_after, expected_cost);
1
        });
1
}
#[test]
1
fn test_cannot_mark_valid_para_with_no_bootnodes() {
1
    ExtBuilder::default()
1
        .with_balances(vec![
1
            // Alice gets 10k extra tokens for her mapping deposit
1
            (AccountId::from(ALICE), 210_000 * UNIT),
1
            (AccountId::from(BOB), 100_000 * UNIT),
1
            (AccountId::from(CHARLIE), 100_000 * UNIT),
1
            (AccountId::from(DAVE), 100_000 * UNIT),
1
        ])
1
        .with_collators(vec![
1
            (AccountId::from(ALICE), 210 * UNIT),
1
            (AccountId::from(BOB), 100 * UNIT),
1
            (AccountId::from(CHARLIE), 100 * UNIT),
1
            (AccountId::from(DAVE), 100 * UNIT),
1
        ])
1
        .build()
1
        .execute_with(|| {
1
            run_to_block(2);
1
            assert_ok!(Registrar::register(
1
                origin_of(ALICE.into()),
1
                1001.into(),
1
                empty_genesis_data(),
1
                None
            ));
1
            assert_noop!(
1
                Registrar::mark_valid_for_collating(root_origin(), 1001.into()),
1
                pallet_data_preservers::Error::<Runtime>::NoBootNodes,
            );
1
        });
1
}
#[test]
1
fn test_can_buy_credits_before_registering_para_and_receive_free_credits() {
1
    ExtBuilder::default()
1
        .with_balances(vec![
1
            // Alice gets 10k extra tokens for her mapping deposit
1
            (AccountId::from(ALICE), 210_000 * UNIT),
1
            (AccountId::from(BOB), 100_000 * UNIT),
1
            (AccountId::from(CHARLIE), 100_000 * UNIT),
1
            (AccountId::from(DAVE), 100_000 * UNIT),
1
        ])
1
        .with_collators(vec![
1
            (AccountId::from(ALICE), 210 * UNIT),
1
            (AccountId::from(BOB), 100 * UNIT),
1
            (AccountId::from(CHARLIE), 100 * UNIT),
1
            (AccountId::from(DAVE), 100 * UNIT),
1
        ])
1
        .build()
1
        .execute_with(|| {
1
            run_to_block(2);
            // Try to buy (FreeBlockProductionCredits - 1) credits
1
            let balance_before = System::account(AccountId::from(ALICE)).data.free;
1
            assert_ok!(ServicesPayment::purchase_credits(
1
                origin_of(ALICE.into()),
1
                1001.into(),
1
                block_credits_to_required_balance(
1
                    crate::FreeBlockProductionCredits::get() - 1,
1
                    1001.into()
                )
            ));
1
            let balance_after = System::account(AccountId::from(ALICE)).data.free;
            // Now parachain tank should have this amount
1
            let balance_tank = System::account(ServicesPayment::parachain_tank(1001.into()))
1
                .data
1
                .free;
1
            assert_eq!(
                balance_tank,
1
                block_credits_to_required_balance(
1
                    crate::FreeBlockProductionCredits::get() - 1,
1
                    1001.into()
                )
            );
1
            let expected_cost = block_credits_to_required_balance(
1
                crate::FreeBlockProductionCredits::get() - 1,
1
                1001.into(),
            );
1
            assert_eq!(balance_before - balance_after, expected_cost);
            // Now register para
1
            assert_ok!(Registrar::register(
1
                origin_of(ALICE.into()),
1
                1001.into(),
1
                empty_genesis_data(),
1
                None
            ));
1
            set_dummy_boot_node(origin_of(ALICE.into()), 1001.into());
1
            assert_ok!(Registrar::mark_valid_for_collating(
1
                root_origin(),
1
                1001.into()
            ));
            // We received aññ free credits, because we cannot have more than FreeBlockProductionCredits
1
            let credits =
1
                pallet_services_payment::BlockProductionCredits::<Runtime>::get(ParaId::from(1001))
1
                    .unwrap_or_default();
1
            assert_eq!(credits, crate::FreeBlockProductionCredits::get());
1
        });
1
}
#[test]
1
fn test_deregister_and_register_again_does_not_give_free_credits() {
1
    ExtBuilder::default()
1
        .with_balances(vec![
1
            // Alice gets 10k extra tokens for her mapping deposit
1
            (AccountId::from(ALICE), 210_000 * UNIT),
1
            (AccountId::from(BOB), 100_000 * UNIT),
1
            (AccountId::from(CHARLIE), 100_000 * UNIT),
1
            (AccountId::from(DAVE), 100_000 * UNIT),
1
        ])
1
        .with_collators(vec![
1
            (AccountId::from(ALICE), 210 * UNIT),
1
            (AccountId::from(BOB), 100 * UNIT),
1
            (AccountId::from(CHARLIE), 100 * UNIT),
1
            (AccountId::from(DAVE), 100 * UNIT),
1
        ])
1
        .build()
1
        .execute_with(|| {
1
            run_to_block(2);
            // Register
1
            assert_ok!(Registrar::register(
1
                origin_of(ALICE.into()),
1
                1001.into(),
1
                empty_genesis_data(),
1
                None
            ),);
1
            set_dummy_boot_node(origin_of(ALICE.into()), 1001.into());
1
            assert_ok!(Registrar::mark_valid_for_collating(
1
                root_origin(),
1
                1001.into()
            ),);
            // We received free credits
1
            let credits =
1
                pallet_services_payment::BlockProductionCredits::<Runtime>::get(ParaId::from(1001))
1
                    .unwrap_or_default();
1
            assert_eq!(credits, crate::FreeBlockProductionCredits::get());
            // Deregister after 1 session
1
            run_to_session(1);
1
            assert_ok!(Registrar::deregister(root_origin(), 1001.into()), ());
1
            run_to_session(3);
1
            let credits_before_2nd_register =
1
                pallet_services_payment::BlockProductionCredits::<Runtime>::get(ParaId::from(1001))
1
                    .unwrap_or_default();
            // We spent some credits because this container chain had collators for 1 session
1
            assert_ne!(
                credits_before_2nd_register,
1
                crate::FreeBlockProductionCredits::get()
            );
            // Register again
1
            assert_ok!(Registrar::register(
1
                origin_of(ALICE.into()),
1
                1001.into(),
1
                empty_genesis_data(),
1
                None
            ),);
1
            set_dummy_boot_node(origin_of(ALICE.into()), 1001.into());
1
            assert_ok!(Registrar::mark_valid_for_collating(
1
                root_origin(),
1
                1001.into()
            ),);
            // No more free credits
1
            let credits =
1
                pallet_services_payment::BlockProductionCredits::<Runtime>::get(ParaId::from(1001))
1
                    .unwrap_or_default();
1
            assert_eq!(credits, credits_before_2nd_register);
1
        });
1
}
#[test]
1
fn test_register_parathread_not_allowed() {
1
    ExtBuilder::default()
1
        .with_balances(vec![
1
            // Alice gets 10k extra tokens for her mapping deposit
1
            (AccountId::from(ALICE), 210_000 * UNIT),
1
            (AccountId::from(BOB), 100_000 * UNIT),
1
            (AccountId::from(CHARLIE), 100_000 * UNIT),
1
            (AccountId::from(DAVE), 100_000 * UNIT),
1
        ])
1
        .with_collators(vec![
1
            (AccountId::from(ALICE), 210 * UNIT),
1
            (AccountId::from(BOB), 100 * UNIT),
1
            (AccountId::from(CHARLIE), 100 * UNIT),
1
            (AccountId::from(DAVE), 100 * UNIT),
1
        ])
1
        .build()
1
        .execute_with(|| {
1
            run_to_block(2);
1
            assert_noop!(
1
                RuntimeCall::Registrar(pallet_registrar::Call::<Runtime>::register_parathread {
1
                    para_id: 3001.into(),
1
                    slot_frequency: SlotFrequency { min: 1, max: 1 },
1
                    genesis_data: empty_genesis_data(),
1
                    head_data: None
1
                })
1
                .dispatch(
1
                    <Runtime as frame_system::Config>::RuntimeOrigin::signed(AccountId::from(
                        ALICE
                    ))
                ),
1
                frame_system::Error::<Runtime>::CallFiltered
            );
1
        });
1
}
#[test]
1
fn test_register_parathread_genesis() {
1
    let parathread_params = tp_traits::ParathreadParams {
1
        slot_frequency: SlotFrequency { min: 1, max: 1 },
1
    };
1
    ExtBuilder::default()
1
        .with_balances(vec![
1
            // Alice gets 10k extra tokens for her mapping deposit
1
            (AccountId::from(ALICE), 210_000 * UNIT),
1
            (AccountId::from(BOB), 100_000 * UNIT),
1
            (AccountId::from(CHARLIE), 100_000 * UNIT),
1
            (AccountId::from(DAVE), 100_000 * UNIT),
1
        ])
1
        .with_collators(vec![
1
            (AccountId::from(ALICE), 210 * UNIT),
1
            (AccountId::from(BOB), 100 * UNIT),
1
            (AccountId::from(CHARLIE), 100 * UNIT),
1
            (AccountId::from(DAVE), 100 * UNIT),
1
        ])
1
        .with_para_ids(vec![ParaRegistrationParams {
1
            para_id: 3001,
1
            genesis_data: empty_genesis_data(),
1
            block_production_credits: u32::MAX,
1
            collator_assignment_credits: u32::MAX,
1
            parathread_params: Some(parathread_params.clone()),
1
        }])
1
        .build()
1
        .execute_with(|| {
1
            run_to_block(2);
1
            assert_eq!(Registrar::registered_para_ids(), vec![3001.into()]);
1
            assert_eq!(
1
                pallet_registrar::ParathreadParams::<Runtime>::get(ParaId::from(3001)),
1
                Some(parathread_params)
            );
1
            let assignment = CollatorAssignment::collator_container_chain();
1
            assert_eq!(
1
                assignment.container_chains[&ParaId::from(3001)],
1
                vec![CHARLIE.into()]
            );
1
        });
1
}
#[test]
1
fn test_ed_plus_block_credit_session_purchase_works() {
1
    ExtBuilder::default()
1
        .with_balances(vec![
1
            // Alice gets 10k extra tokens for her mapping deposit
1
            (AccountId::from(ALICE), 210_000 * UNIT),
1
            (AccountId::from(BOB), 100_000 * UNIT),
1
            (AccountId::from(CHARLIE), 100_000 * UNIT),
1
            (AccountId::from(DAVE), 100_000 * UNIT),
1
        ])
1
        .with_collators(vec![
1
            (AccountId::from(ALICE), 210 * UNIT),
1
            (AccountId::from(BOB), 100 * UNIT),
1
            (AccountId::from(CHARLIE), 100 * UNIT),
1
            (AccountId::from(DAVE), 100 * UNIT),
1
        ])
1
        .build()
1
        .execute_with(|| {
1
            run_to_block(2);
            // Assert current slot gets updated
1
            assert_eq!(current_slot(), 1u64);
1
            assert!(current_author() == AccountId::from(BOB));
            // Alice and Bob collate in our chain
1
            let alice_id = get_aura_id_from_seed(&AccountId::from(ALICE).to_string());
1
            let bob_id = get_aura_id_from_seed(&AccountId::from(BOB).to_string());
1
            assert_eq!(authorities(), vec![alice_id, bob_id]);
1
            assert_ok!(Registrar::register(
1
                origin_of(ALICE.into()),
1
                1001.into(),
1
                empty_genesis_data(),
1
                None
            ));
1
            set_dummy_boot_node(origin_of(ALICE.into()), 1001.into());
1
            assert_ok!(Registrar::mark_valid_for_collating(
1
                root_origin(),
1
                1001.into()
            ));
            // Need to reset credits to 0 because now parachains are given free credits on register
1
            assert_ok!(ServicesPayment::set_block_production_credits(
1
                root_origin(),
1
                1001.into(),
                0
            ));
1
            let credits_1001 = block_credits_to_required_balance(crate::Period::get(), 1001.into())
1
                + crate::EXISTENTIAL_DEPOSIT;
            // Fill the tank
1
            assert_ok!(ServicesPayment::purchase_credits(
1
                origin_of(ALICE.into()),
1
                1001.into(),
1
                credits_1001
            ));
            // Assignment should happen after 2 sessions
1
            run_to_session(1u32);
1
            let assignment = CollatorAssignment::collator_container_chain();
1
            assert!(assignment.container_chains.is_empty());
1
            run_to_session(2u32);
            // Charlie and Dave should be assigned to para 1001
1
            let assignment = CollatorAssignment::collator_container_chain();
1
            assert_eq!(
1
                assignment.container_chains[&1001u32.into()],
1
                vec![CHARLIE.into(), DAVE.into()]
            );
            // Simulate block inclusion from container chain 1001
1
            let mut sproof: ParaHeaderSproofBuilder = ParaHeaderSproofBuilder::default();
1
            let slot: u64 = 5;
1
            let s = ParaHeaderSproofBuilderItem {
1
                para_id: 1001.into(),
1
                author_id: HeaderAs::NonEncoded(sp_runtime::generic::Header::<u32, BlakeTwo256> {
1
                    parent_hash: Default::default(),
1
                    number: 1,
1
                    state_root: Default::default(),
1
                    extrinsics_root: Default::default(),
1
                    digest: sp_runtime::generic::Digest {
1
                        logs: vec![DigestItem::PreRuntime(AURA_ENGINE_ID, slot.encode())],
1
                    },
1
                }),
1
            };
1
            sproof.items.push(s);
1
            set_author_noting_inherent_data(sproof);
1
            run_block();
            // After this it should not be assigned anymore, since credits are not payable
1
            run_to_session(3u32);
            // Nobody should be assigned to para 1001
1
            let assignment = CollatorAssignment::collator_container_chain();
1
            assert_eq!(assignment.container_chains.get(&1001u32.into()), None,);
1
        });
1
}
#[test]
1
fn test_ed_plus_block_credit_session_minus_1_purchase_fails() {
1
    ExtBuilder::default()
1
        .with_balances(vec![
1
            // Alice gets 10k extra tokens for her mapping deposit
1
            (AccountId::from(ALICE), 210_000 * UNIT),
1
            (AccountId::from(BOB), 100_000 * UNIT),
1
            (AccountId::from(CHARLIE), 100_000 * UNIT),
1
            (AccountId::from(DAVE), 100_000 * UNIT),
1
        ])
1
        .with_collators(vec![
1
            (AccountId::from(ALICE), 210 * UNIT),
1
            (AccountId::from(BOB), 100 * UNIT),
1
            (AccountId::from(CHARLIE), 100 * UNIT),
1
            (AccountId::from(DAVE), 100 * UNIT),
1
        ])
1
        .build()
1
        .execute_with(|| {
1
            run_to_block(2);
            // Assert current slot gets updated
1
            assert_eq!(current_slot(), 1u64);
1
            assert!(current_author() == AccountId::from(BOB));
            // Alice and Bob collate in our chain
1
            let alice_id = get_aura_id_from_seed(&AccountId::from(ALICE).to_string());
1
            let bob_id = get_aura_id_from_seed(&AccountId::from(BOB).to_string());
1
            assert_eq!(authorities(), vec![alice_id, bob_id]);
1
            assert_ok!(Registrar::register(
1
                origin_of(ALICE.into()),
1
                1001.into(),
1
                empty_genesis_data(),
1
                None
            ));
1
            set_dummy_boot_node(origin_of(ALICE.into()), 1001.into());
1
            assert_ok!(Registrar::mark_valid_for_collating(
1
                root_origin(),
1
                1001.into()
            ));
            // Need to reset credits to 0 because now parachains are given free credits on register
1
            assert_ok!(ServicesPayment::set_block_production_credits(
1
                root_origin(),
1
                1001.into(),
                0
            ));
1
            let credits_1001 = block_credits_to_required_balance(crate::Period::get(), 1001.into())
1
                + crate::EXISTENTIAL_DEPOSIT
1
                - 1;
            // Fill the tank
1
            assert_ok!(ServicesPayment::purchase_credits(
1
                origin_of(ALICE.into()),
1
                1001.into(),
1
                credits_1001
            ));
            // Assignment should happen after 2 sessions
1
            run_to_session(1u32);
1
            let assignment = CollatorAssignment::collator_container_chain();
1
            assert!(assignment.container_chains.is_empty());
1
            run_to_session(2u32);
            // Charlie and Dave should not be assigned to para 1001
1
            let assignment = CollatorAssignment::collator_container_chain();
1
            assert_eq!(assignment.container_chains.get(&1001u32.into()), None,);
1
        });
1
}
#[test]
1
fn test_reassignment_ed_plus_two_block_credit_session_purchase_works() {
1
    ExtBuilder::default()
1
        .with_balances(vec![
1
            // Alice gets 10k extra tokens for her mapping deposit
1
            (AccountId::from(ALICE), 210_000 * UNIT),
1
            (AccountId::from(BOB), 100_000 * UNIT),
1
            (AccountId::from(CHARLIE), 100_000 * UNIT),
1
            (AccountId::from(DAVE), 100_000 * UNIT),
1
        ])
1
        .with_collators(vec![
1
            (AccountId::from(ALICE), 210 * UNIT),
1
            (AccountId::from(BOB), 100 * UNIT),
1
            (AccountId::from(CHARLIE), 100 * UNIT),
1
            (AccountId::from(DAVE), 100 * UNIT),
1
        ])
1
        .build()
1
        .execute_with(|| {
1
            run_to_block(2);
            // Assert current slot gets updated
1
            assert_eq!(current_slot(), 1u64);
1
            assert!(current_author() == AccountId::from(BOB));
            // Alice and Bob collate in our chain
1
            let alice_id = get_aura_id_from_seed(&AccountId::from(ALICE).to_string());
1
            let bob_id = get_aura_id_from_seed(&AccountId::from(BOB).to_string());
1
            assert_eq!(authorities(), vec![alice_id, bob_id]);
1
            assert_ok!(Registrar::register(
1
                origin_of(ALICE.into()),
1
                1001.into(),
1
                empty_genesis_data(),
1
                None
            ));
1
            set_dummy_boot_node(origin_of(ALICE.into()), 1001.into());
1
            assert_ok!(Registrar::mark_valid_for_collating(
1
                root_origin(),
1
                1001.into()
            ));
            // Need to reset credits to 0 because now parachains are given free credits on register
1
            assert_ok!(ServicesPayment::set_block_production_credits(
1
                root_origin(),
1
                1001.into(),
                0
            ));
            // On reassignment the blocks credits needed should be enough for the current session and the next one
1
            let credits_1001 =
1
                block_credits_to_required_balance(crate::Period::get() * 2, 1001.into())
1
                    + crate::EXISTENTIAL_DEPOSIT;
            // Fill the tank
1
            assert_ok!(ServicesPayment::purchase_credits(
1
                origin_of(ALICE.into()),
1
                1001.into(),
1
                credits_1001
            ));
            // Assignment should happen after 2 sessions
1
            run_to_session(1u32);
1
            let assignment = CollatorAssignment::collator_container_chain();
1
            assert!(assignment.container_chains.is_empty());
1
            run_to_session(2u32);
            // Charlie and Dave should be assigned to para 1001
1
            let assignment = CollatorAssignment::collator_container_chain();
1
            assert_eq!(
1
                assignment.container_chains[&1001u32.into()],
1
                vec![CHARLIE.into(), DAVE.into()]
            );
            // Simulate block inclusion from container chain 1001
1
            let mut sproof: ParaHeaderSproofBuilder = ParaHeaderSproofBuilder::default();
1
            let slot: u64 = 5;
1
            let s = ParaHeaderSproofBuilderItem {
1
                para_id: 1001.into(),
1
                author_id: HeaderAs::NonEncoded(sp_runtime::generic::Header::<u32, BlakeTwo256> {
1
                    parent_hash: Default::default(),
1
                    number: 1,
1
                    state_root: Default::default(),
1
                    extrinsics_root: Default::default(),
1
                    digest: sp_runtime::generic::Digest {
1
                        logs: vec![DigestItem::PreRuntime(AURA_ENGINE_ID, slot.encode())],
1
                    },
1
                }),
1
            };
1
            sproof.items.push(s);
1
            set_author_noting_inherent_data(sproof);
1
            run_block();
            // Session 3 should still be assigned
1
            run_to_session(3u32);
            // Charlie and Dave should be assigned to para 1001
1
            let assignment = CollatorAssignment::collator_container_chain();
1
            assert_eq!(
1
                assignment.container_chains[&1001u32.into()],
1
                vec![CHARLIE.into(), DAVE.into()]
            );
            // After this it should not be assigned anymore, since credits are not payable
1
            run_to_session(4u32);
            // Nobody should be assigned to para 1001
1
            let assignment = CollatorAssignment::collator_container_chain();
1
            assert_eq!(assignment.container_chains.get(&1001u32.into()), None,);
1
        });
1
}
#[test]
1
fn test_reassignment_ed_plus_two_block_credit_session_minus_1_purchase_fails() {
1
    ExtBuilder::default()
1
        .with_balances(vec![
1
            // Alice gets 10k extra tokens for her mapping deposit
1
            (AccountId::from(ALICE), 210_000 * UNIT),
1
            (AccountId::from(BOB), 100_000 * UNIT),
1
            (AccountId::from(CHARLIE), 100_000 * UNIT),
1
            (AccountId::from(DAVE), 100_000 * UNIT),
1
        ])
1
        .with_collators(vec![
1
            (AccountId::from(ALICE), 210 * UNIT),
1
            (AccountId::from(BOB), 100 * UNIT),
1
            (AccountId::from(CHARLIE), 100 * UNIT),
1
            (AccountId::from(DAVE), 100 * UNIT),
1
        ])
1
        .build()
1
        .execute_with(|| {
1
            run_to_block(2);
            // Assert current slot gets updated
1
            assert_eq!(current_slot(), 1u64);
1
            assert!(current_author() == AccountId::from(BOB));
            // Alice and Bob collate in our chain
1
            let alice_id = get_aura_id_from_seed(&AccountId::from(ALICE).to_string());
1
            let bob_id = get_aura_id_from_seed(&AccountId::from(BOB).to_string());
1
            assert_eq!(authorities(), vec![alice_id, bob_id]);
1
            assert_ok!(Registrar::register(
1
                origin_of(ALICE.into()),
1
                1001.into(),
1
                empty_genesis_data(),
1
                None
            ));
1
            set_dummy_boot_node(origin_of(ALICE.into()), 1001.into());
1
            assert_ok!(Registrar::mark_valid_for_collating(
1
                root_origin(),
1
                1001.into()
            ));
            // Need to reset credits to 0 because now parachains are given free credits on register
1
            assert_ok!(ServicesPayment::set_block_production_credits(
1
                root_origin(),
1
                1001.into(),
                0
            ));
1
            let credits_1001 =
1
                block_credits_to_required_balance(crate::Period::get() * 2, 1001.into())
1
                    + crate::EXISTENTIAL_DEPOSIT
1
                    - 1;
            // Fill the tank
1
            assert_ok!(ServicesPayment::purchase_credits(
1
                origin_of(ALICE.into()),
1
                1001.into(),
1
                credits_1001
            ));
            // Assignment should happen after 2 sessions
1
            run_to_session(1u32);
1
            let assignment = CollatorAssignment::collator_container_chain();
1
            assert!(assignment.container_chains.is_empty());
1
            run_to_session(2u32);
            // Charlie and Dave should be assigned to para 1001
1
            let assignment = CollatorAssignment::collator_container_chain();
1
            assert_eq!(
1
                assignment.container_chains[&1001u32.into()],
1
                vec![CHARLIE.into(), DAVE.into()]
            );
            // Simulate block inclusion from container chain 1001
1
            let mut sproof: ParaHeaderSproofBuilder = ParaHeaderSproofBuilder::default();
1
            let slot: u64 = 5;
1
            let s = ParaHeaderSproofBuilderItem {
1
                para_id: 1001.into(),
1
                author_id: HeaderAs::NonEncoded(sp_runtime::generic::Header::<u32, BlakeTwo256> {
1
                    parent_hash: Default::default(),
1
                    number: 1,
1
                    state_root: Default::default(),
1
                    extrinsics_root: Default::default(),
1
                    digest: sp_runtime::generic::Digest {
1
                        logs: vec![DigestItem::PreRuntime(AURA_ENGINE_ID, slot.encode())],
1
                    },
1
                }),
1
            };
1
            sproof.items.push(s);
1
            set_author_noting_inherent_data(sproof);
1
            run_block();
            // After this it should not be assigned anymore, since credits are not payable
1
            run_to_session(3u32);
            // Nobody should be assigned to para 1001
1
            let assignment = CollatorAssignment::collator_container_chain();
1
            assert_eq!(assignment.container_chains.get(&1001u32.into()), None,);
1
        });
1
}
#[test]
1
fn test_credits_with_purchase_can_be_combined() {
1
    ExtBuilder::default()
1
        .with_balances(vec![
1
            // Alice gets 10k extra tokens for her mapping deposit
1
            (AccountId::from(ALICE), 210_000 * UNIT),
1
            (AccountId::from(BOB), 100_000 * UNIT),
1
            (AccountId::from(CHARLIE), 100_000 * UNIT),
1
            (AccountId::from(DAVE), 100_000 * UNIT),
1
        ])
1
        .with_collators(vec![
1
            (AccountId::from(ALICE), 210 * UNIT),
1
            (AccountId::from(BOB), 100 * UNIT),
1
            (AccountId::from(CHARLIE), 100 * UNIT),
1
            (AccountId::from(DAVE), 100 * UNIT),
1
        ])
1
        .build()
1
        .execute_with(|| {
1
            run_to_block(2);
            // Assert current slot gets updated
1
            assert_eq!(current_slot(), 1u64);
1
            assert!(current_author() == AccountId::from(BOB));
            // Alice and Bob collate in our chain
1
            let alice_id = get_aura_id_from_seed(&AccountId::from(ALICE).to_string());
1
            let bob_id = get_aura_id_from_seed(&AccountId::from(BOB).to_string());
1
            assert_eq!(authorities(), vec![alice_id, bob_id]);
1
            assert_ok!(Registrar::register(
1
                origin_of(ALICE.into()),
1
                1001.into(),
1
                empty_genesis_data(),
1
                None
            ));
1
            set_dummy_boot_node(origin_of(ALICE.into()), 1001.into());
1
            assert_ok!(Registrar::mark_valid_for_collating(
1
                root_origin(),
1
                1001.into()
            ));
            // Set 1 session of free credits and purchase 1 session of credits
1
            assert_ok!(ServicesPayment::set_block_production_credits(
1
                root_origin(),
1
                1001.into(),
1
                crate::Period::get()
            ));
1
            let credits_1001 = block_credits_to_required_balance(crate::Period::get(), 1001.into())
1
                + crate::EXISTENTIAL_DEPOSIT;
            // Fill the tank
1
            assert_ok!(ServicesPayment::purchase_credits(
1
                origin_of(ALICE.into()),
1
                1001.into(),
1
                credits_1001
            ));
            // Assignment should happen after 2 sessions
1
            run_to_session(1u32);
1
            let assignment = CollatorAssignment::collator_container_chain();
1
            assert!(assignment.container_chains.is_empty());
1
            run_to_session(2u32);
            // Charlie and Dave should be assigned to para 1001
1
            let assignment = CollatorAssignment::collator_container_chain();
1
            assert_eq!(
1
                assignment.container_chains[&1001u32.into()],
1
                vec![CHARLIE.into(), DAVE.into()]
            );
1
        });
1
}
#[test]
1
fn stream_payment_works() {
1
    ExtBuilder::default()
1
        .with_balances(vec![
1
            (AccountId::from(ALICE), 100_000 * UNIT),
1
            (AccountId::from(BOB), 100_000 * UNIT),
1
            (AccountId::from(CHARLIE), 100_000 * UNIT),
1
        ])
1
        .with_collators(vec![
1
            (AccountId::from(CHARLIE), 100 * UNIT),
1
            (AccountId::from(DAVE), 100 * UNIT),
1
        ])
1
        .build()
1
        .execute_with(|| {
            use pallet_stream_payment::{ChangeKind, StreamConfig};
1
            assert_ok!(StreamPayment::open_stream(
1
                origin_of(ALICE.into()),
1
                BOB.into(),
1
                StreamConfig {
1
                    rate: 2 * UNIT,
1
                    asset_id: StreamPaymentAssetId::Native,
1
                    time_unit: StreamPaymentTimeUnit::BlockNumber,
1
                    minimum_request_deadline_delay: 0,
1
                    soft_minimum_deposit: 0,
1
                },
1
                1_000 * UNIT,
            ));
1
            run_block();
1
            assert_ok!(StreamPayment::perform_payment(origin_of(CHARLIE.into()), 0));
1
            assert_eq!(
1
                Balances::free_balance(AccountId::from(BOB)),
                100_000 * UNIT + 2 * UNIT
            );
1
            assert_ok!(StreamPayment::request_change(
1
                origin_of(ALICE.into()),
                0,
1
                ChangeKind::Suggestion,
1
                StreamConfig {
1
                    rate: 1 * UNIT,
1
                    asset_id: StreamPaymentAssetId::Native,
1
                    time_unit: StreamPaymentTimeUnit::BlockNumber,
1
                    minimum_request_deadline_delay: 0,
1
                    soft_minimum_deposit: 0,
1
                },
1
                None,
            ));
1
            assert_ok!(StreamPayment::accept_requested_change(
1
                origin_of(BOB.into()),
                0,
                1, // nonce
1
                None,
            ));
1
            run_block();
1
            assert_ok!(StreamPayment::close_stream(origin_of(BOB.into()), 0));
1
            assert_eq!(
1
                Balances::free_balance(AccountId::from(BOB)),
                100_000 * UNIT + 3 * UNIT
            );
1
            assert_eq!(
1
                Balances::free_balance(AccountId::from(ALICE)),
                100_000 * UNIT - 3 * UNIT
            );
1
        });
1
}
#[test]
1
fn test_ed_plus_collator_assignment_session_purchase_works() {
1
    ExtBuilder::default()
1
        .with_balances(vec![
1
            // Alice gets 10k extra tokens for her mapping deposit
1
            (AccountId::from(ALICE), 210_000 * UNIT),
1
            (AccountId::from(BOB), 100_000 * UNIT),
1
            (AccountId::from(CHARLIE), 100_000 * UNIT),
1
            (AccountId::from(DAVE), 100_000 * UNIT),
1
        ])
1
        .with_collators(vec![
1
            (AccountId::from(ALICE), 210 * UNIT),
1
            (AccountId::from(BOB), 100 * UNIT),
1
            (AccountId::from(CHARLIE), 100 * UNIT),
1
            (AccountId::from(DAVE), 100 * UNIT),
1
        ])
1
        .build()
1
        .execute_with(|| {
1
            run_to_block(2);
            // Assert current slot gets updated
1
            assert_eq!(current_slot(), 1u64);
1
            assert!(current_author() == AccountId::from(BOB));
            // Alice and Bob collate in our chain
1
            let alice_id = get_aura_id_from_seed(&AccountId::from(ALICE).to_string());
1
            let bob_id = get_aura_id_from_seed(&AccountId::from(BOB).to_string());
1
            assert_eq!(authorities(), vec![alice_id, bob_id]);
1
            assert_ok!(Registrar::register(
1
                origin_of(ALICE.into()),
1
                1001.into(),
1
                empty_genesis_data(),
1
                None
            ));
1
            set_dummy_boot_node(origin_of(ALICE.into()), 1001.into());
1
            assert_ok!(Registrar::mark_valid_for_collating(
1
                root_origin(),
1
                1001.into()
            ));
            // Need to reset credits to 0 because now parachains are given free credits on register
1
            assert_ok!(ServicesPayment::set_collator_assignment_credits(
1
                root_origin(),
1
                1001.into(),
                0
            ));
1
            let credits_1001 = collator_assignment_credits_to_required_balance(1, 1001.into())
1
                + crate::EXISTENTIAL_DEPOSIT;
            // Fill the tank
1
            assert_ok!(ServicesPayment::purchase_credits(
1
                origin_of(ALICE.into()),
1
                1001.into(),
1
                credits_1001
            ));
            // Assignment should happen after 2 sessions
1
            run_to_session(1u32);
1
            let assignment = CollatorAssignment::collator_container_chain();
1
            assert!(assignment.container_chains.is_empty());
1
            run_to_session(2u32);
            // Charlie and Dave should be assigned to para 1001
1
            let assignment = CollatorAssignment::collator_container_chain();
1
            assert_eq!(
1
                assignment.container_chains[&1001u32.into()],
1
                vec![CHARLIE.into(), DAVE.into()]
            );
            // Simulate block inclusion from container chain 1001
1
            let mut sproof: ParaHeaderSproofBuilder = ParaHeaderSproofBuilder::default();
1
            let slot: u64 = 5;
1
            let s = ParaHeaderSproofBuilderItem {
1
                para_id: 1001.into(),
1
                author_id: HeaderAs::NonEncoded(sp_runtime::generic::Header::<u32, BlakeTwo256> {
1
                    parent_hash: Default::default(),
1
                    number: 1,
1
                    state_root: Default::default(),
1
                    extrinsics_root: Default::default(),
1
                    digest: sp_runtime::generic::Digest {
1
                        logs: vec![DigestItem::PreRuntime(AURA_ENGINE_ID, slot.encode())],
1
                    },
1
                }),
1
            };
1
            sproof.items.push(s);
1
            set_author_noting_inherent_data(sproof);
1
            run_block();
            // After this it should not be assigned anymore, since credits are not payable
1
            run_to_session(4u32);
            // Nobody should be assigned to para 1001
1
            let assignment = CollatorAssignment::collator_container_chain();
1
            assert_eq!(assignment.container_chains.get(&1001u32.into()), None,);
1
        });
1
}
#[test]
1
fn test_ed_plus_collator_assignment_credit_session_minus_1_purchase_fails() {
1
    ExtBuilder::default()
1
        .with_balances(vec![
1
            // Alice gets 10k extra tokens for her mapping deposit
1
            (AccountId::from(ALICE), 210_000 * UNIT),
1
            (AccountId::from(BOB), 100_000 * UNIT),
1
            (AccountId::from(CHARLIE), 100_000 * UNIT),
1
            (AccountId::from(DAVE), 100_000 * UNIT),
1
        ])
1
        .with_collators(vec![
1
            (AccountId::from(ALICE), 210 * UNIT),
1
            (AccountId::from(BOB), 100 * UNIT),
1
            (AccountId::from(CHARLIE), 100 * UNIT),
1
            (AccountId::from(DAVE), 100 * UNIT),
1
        ])
1
        .build()
1
        .execute_with(|| {
1
            run_to_block(2);
            // Assert current slot gets updated
1
            assert_eq!(current_slot(), 1u64);
1
            assert!(current_author() == AccountId::from(BOB));
            // Alice and Bob collate in our chain
1
            let alice_id = get_aura_id_from_seed(&AccountId::from(ALICE).to_string());
1
            let bob_id = get_aura_id_from_seed(&AccountId::from(BOB).to_string());
1
            assert_eq!(authorities(), vec![alice_id, bob_id]);
1
            assert_ok!(Registrar::register(
1
                origin_of(ALICE.into()),
1
                1001.into(),
1
                empty_genesis_data(),
1
                None
            ));
1
            set_dummy_boot_node(origin_of(ALICE.into()), 1001.into());
1
            assert_ok!(Registrar::mark_valid_for_collating(
1
                root_origin(),
1
                1001.into()
            ));
            // Need to reset credits to 0 because now parachains are given free credits on register
1
            assert_ok!(ServicesPayment::set_collator_assignment_credits(
1
                root_origin(),
1
                1001.into(),
                0
            ));
1
            let credits_1001 = collator_assignment_credits_to_required_balance(1, 1001.into())
1
                + crate::EXISTENTIAL_DEPOSIT
1
                - 1;
            // Fill the tank
1
            assert_ok!(ServicesPayment::purchase_credits(
1
                origin_of(ALICE.into()),
1
                1001.into(),
1
                credits_1001
            ));
            // Assignment should happen after 2 sessions
1
            run_to_session(1u32);
1
            let assignment = CollatorAssignment::collator_container_chain();
1
            assert!(assignment.container_chains.is_empty());
1
            run_to_session(2u32);
            // Charlie and Dave should not be assigned to para 1001
1
            let assignment = CollatorAssignment::collator_container_chain();
1
            assert_eq!(assignment.container_chains.get(&1001u32.into()), None,);
1
        });
1
}
#[test]
1
fn test_collator_assignment_credits_with_purchase_can_be_combined() {
1
    ExtBuilder::default()
1
        .with_balances(vec![
1
            // Alice gets 10k extra tokens for her mapping deposit
1
            (AccountId::from(ALICE), 210_000 * UNIT),
1
            (AccountId::from(BOB), 100_000 * UNIT),
1
            (AccountId::from(CHARLIE), 100_000 * UNIT),
1
            (AccountId::from(DAVE), 100_000 * UNIT),
1
        ])
1
        .with_collators(vec![
1
            (AccountId::from(ALICE), 210 * UNIT),
1
            (AccountId::from(BOB), 100 * UNIT),
1
            (AccountId::from(CHARLIE), 100 * UNIT),
1
            (AccountId::from(DAVE), 100 * UNIT),
1
        ])
1
        .build()
1
        .execute_with(|| {
1
            run_to_block(2);
            // Assert current slot gets updated
1
            assert_eq!(current_slot(), 1u64);
1
            assert!(current_author() == AccountId::from(BOB));
            // Alice and Bob collate in our chain
1
            let alice_id = get_aura_id_from_seed(&AccountId::from(ALICE).to_string());
1
            let bob_id = get_aura_id_from_seed(&AccountId::from(BOB).to_string());
1
            assert_eq!(authorities(), vec![alice_id, bob_id]);
1
            assert_ok!(Registrar::register(
1
                origin_of(ALICE.into()),
1
                1001.into(),
1
                empty_genesis_data(),
1
                None
            ));
1
            set_dummy_boot_node(origin_of(ALICE.into()), 1001.into());
1
            assert_ok!(Registrar::mark_valid_for_collating(
1
                root_origin(),
1
                1001.into()
            ));
            // We assign one session to free credits
1
            assert_ok!(ServicesPayment::set_collator_assignment_credits(
1
                root_origin(),
1
                1001.into(),
                1
            ));
            // We buy another session through the tank
1
            let credits_1001 = collator_assignment_credits_to_required_balance(1, 1001.into())
1
                + crate::EXISTENTIAL_DEPOSIT;
            // Fill the tank
1
            assert_ok!(ServicesPayment::purchase_credits(
1
                origin_of(ALICE.into()),
1
                1001.into(),
1
                credits_1001
            ));
            // Assignment should happen after 2 sessions
1
            run_to_session(1u32);
1
            let assignment = CollatorAssignment::collator_container_chain();
1
            assert!(assignment.container_chains.is_empty());
1
            run_to_session(2u32);
            // Charlie and Dave should be assigned to para 1001
1
            let assignment = CollatorAssignment::collator_container_chain();
1
            assert_eq!(
1
                assignment.container_chains[&1001u32.into()],
1
                vec![CHARLIE.into(), DAVE.into()]
            );
1
        });
1
}
#[test]
1
fn test_block_credits_and_collator_assignation_credits_through_tank() {
1
    ExtBuilder::default()
1
        .with_balances(vec![
1
            // Alice gets 10k extra tokens for her mapping deposit
1
            (AccountId::from(ALICE), 210_000 * UNIT),
1
            (AccountId::from(BOB), 100_000 * UNIT),
1
            (AccountId::from(CHARLIE), 100_000 * UNIT),
1
            (AccountId::from(DAVE), 100_000 * UNIT),
1
        ])
1
        .with_collators(vec![
1
            (AccountId::from(ALICE), 210 * UNIT),
1
            (AccountId::from(BOB), 100 * UNIT),
1
            (AccountId::from(CHARLIE), 100 * UNIT),
1
            (AccountId::from(DAVE), 100 * UNIT),
1
        ])
1
        .build()
1
        .execute_with(|| {
1
            run_to_block(2);
            // Assert current slot gets updated
1
            assert_eq!(current_slot(), 1u64);
1
            assert!(current_author() == AccountId::from(BOB));
            // Alice and Bob collate in our chain
1
            let alice_id = get_aura_id_from_seed(&AccountId::from(ALICE).to_string());
1
            let bob_id = get_aura_id_from_seed(&AccountId::from(BOB).to_string());
1
            assert_eq!(authorities(), vec![alice_id, bob_id]);
1
            assert_ok!(Registrar::register(
1
                origin_of(ALICE.into()),
1
                1001.into(),
1
                empty_genesis_data(),
1
                None
            ));
1
            set_dummy_boot_node(origin_of(ALICE.into()), 1001.into());
1
            assert_ok!(Registrar::mark_valid_for_collating(
1
                root_origin(),
1
                1001.into()
            ));
            // We make all free credits 0
1
            assert_ok!(ServicesPayment::set_collator_assignment_credits(
1
                root_origin(),
1
                1001.into(),
                0
            ));
1
            assert_ok!(ServicesPayment::set_block_production_credits(
1
                root_origin(),
1
                1001.into(),
                0
            ));
            // We buy 2 sessions through tank
1
            let collator_assignation_credits =
1
                collator_assignment_credits_to_required_balance(2, 1001.into());
1
            let block_production_credits =
1
                block_credits_to_required_balance(crate::Period::get() * 2, 1001.into());
            // Fill the tank
1
            assert_ok!(ServicesPayment::purchase_credits(
1
                origin_of(ALICE.into()),
1
                1001.into(),
1
                collator_assignation_credits
1
                    + block_production_credits
1
                    + crate::EXISTENTIAL_DEPOSIT
            ));
            // Assignment should happen after 2 sessions
1
            run_to_session(1u32);
1
            let assignment = CollatorAssignment::collator_container_chain();
1
            assert!(assignment.container_chains.is_empty());
1
            run_to_session(2u32);
            // Charlie and Dave should be assigned to para 1001
1
            let assignment = CollatorAssignment::collator_container_chain();
1
            assert_eq!(
1
                assignment.container_chains[&1001u32.into()],
1
                vec![CHARLIE.into(), DAVE.into()]
            );
            // After this it should not be assigned anymore, since credits are not payable
1
            run_to_session(4u32);
            // Nobody should be assigned to para 1001
1
            let assignment = CollatorAssignment::collator_container_chain();
1
            assert_eq!(assignment.container_chains.get(&1001u32.into()), None,);
1
        });
1
}
#[test]
1
fn test_migration_services_collator_assignment_payment() {
1
    ExtBuilder::default().build().execute_with(|| {
        // Register a new parachain with no credits
1
        assert_ok!(Registrar::register(
1
            origin_of(ALICE.into()),
1
            1001.into(),
1
            empty_genesis_data(),
1
            None
        ));
1
        set_dummy_boot_node(origin_of(ALICE.into()), 1001.into());
1
        assert_ok!(Registrar::mark_valid_for_collating(
1
            root_origin(),
1
            1001.into()
        ));
        // Register another parachain with no credits, do not mark this as valid for collation
1
        assert_ok!(Registrar::register(
1
            origin_of(ALICE.into()),
1
            1002.into(),
1
            empty_genesis_data(),
1
            None
        ));
1
        set_dummy_boot_node(origin_of(ALICE.into()), 1002.into());
1
        assert_ok!(Registrar::mark_valid_for_collating(
1
            root_origin(),
1
            1002.into()
        ));
        // Need to reset credits to 0 because now parachains are given free credits on register
1
        assert_ok!(ServicesPayment::set_collator_assignment_credits(
1
            root_origin(),
1
            1001.into(),
            0
        ));
1
        assert_ok!(ServicesPayment::set_collator_assignment_credits(
1
            root_origin(),
1
            1002.into(),
            0
        ));
1
        let credits_1001 =
1
            pallet_services_payment::CollatorAssignmentCredits::<Runtime>::get(ParaId::from(1001))
1
                .unwrap_or_default();
1
        assert_eq!(credits_1001, 0);
1
        let credits_1002 =
1
            pallet_services_payment::CollatorAssignmentCredits::<Runtime>::get(ParaId::from(1002))
1
                .unwrap_or_default();
1
        assert_eq!(credits_1002, 0);
        // Apply migration
1
        let migration =
1
            MigrateServicesPaymentAddCollatorAssignmentCredits::<Runtime>(Default::default());
1
        migration.migrate(Default::default());
        // Both parachains have been given credits
1
        let credits_1001 =
1
            pallet_services_payment::CollatorAssignmentCredits::<Runtime>::get(ParaId::from(1001))
1
                .unwrap_or_default();
1
        assert_eq!(credits_1001, crate::FreeCollatorAssignmentCredits::get());
1
        let credits_1002 =
1
            pallet_services_payment::CollatorAssignmentCredits::<Runtime>::get(ParaId::from(1002))
1
                .unwrap_or_default();
1
        assert_eq!(credits_1002, crate::FreeCollatorAssignmentCredits::get());
1
    });
1
}
#[test]
1
fn test_max_collators_uses_pending_value() {
    // Start with max_collators = 100, and collators_per_container = 2
    // Set max_collators = 2, and collators_per_container = 3
    // It should be impossible to have more than 2 collators per container at any point in time
1
    ExtBuilder::default()
1
        .with_balances(vec![
1
            // Alice gets 10k extra tokens for her mapping deposit
1
            (AccountId::from(ALICE), 210_000 * UNIT),
1
            (AccountId::from(BOB), 100_000 * UNIT),
1
            (AccountId::from(CHARLIE), 100_000 * UNIT),
1
            (AccountId::from(DAVE), 100_000 * UNIT),
1
        ])
1
        .with_collators(vec![
1
            (AccountId::from(ALICE), 210 * UNIT),
1
            (AccountId::from(BOB), 100 * UNIT),
1
            (AccountId::from(CHARLIE), 100 * UNIT),
1
            (AccountId::from(DAVE), 100 * UNIT),
1
        ])
1
        .with_empty_parachains(vec![1001])
1
        .with_config(pallet_configuration::HostConfiguration {
1
            max_collators: 100,
1
            min_orchestrator_collators: 1,
1
            max_orchestrator_collators: 1,
1
            collators_per_container: 2,
1
            full_rotation_period: 24,
1
            ..Default::default()
1
        })
1
        .build()
1
        .execute_with(|| {
1
            run_to_block(2);
            // Initial assignment: 1 collator in orchestrator chain and 2 collators in container 1001
1
            let assignment = CollatorAssignment::collator_container_chain();
1
            assert_eq!(assignment.container_chains[&1001u32.into()].len(), 2);
1
            assert_eq!(assignment.orchestrator_chain.len(), 1);
1
            assert_ok!(Configuration::set_max_collators(root_origin(), 2));
1
            assert_ok!(Configuration::set_collators_per_container(root_origin(), 3));
            // Check invariant for all intermediate assignments. We set collators_per_container = 3
            // but we also set max_collators = 2, so no collators will be assigned to container
            // chains after the change is applied.
5
            for session in 1..=4 {
4
                run_to_session(session);
4
                let assignment = CollatorAssignment::collator_container_chain();
4
                assert!(
4
                    assignment.container_chains[&1001u32.into()].len() <= 2,
                    "session {}: {} collators assigned to container chain 1001",
                    session,
                    assignment.container_chains[&1001u32.into()].len()
                );
            }
            // Final assignment: because max_collators = 2, there are only 2 collators, one in
            // orchestrator chain, and the other one idle
1
            let assignment = CollatorAssignment::collator_container_chain();
1
            assert_eq!(assignment.container_chains[&1001u32.into()].len(), 0);
1
            assert_eq!(assignment.orchestrator_chain.len(), 1);
1
        });
1
}
#[test]
1
fn test_slow_adjusting_multiplier_changes_in_response_to_consumed_weight() {
1
    ExtBuilder::default()
1
        .with_collators(vec![
1
            (AccountId::from(ALICE), 210 * UNIT),
1
            (AccountId::from(BOB), 100 * UNIT),
1
            (AccountId::from(CHARLIE), 100 * UNIT),
1
            (AccountId::from(DAVE), 100 * UNIT),
1
        ])
1
        .build()
1
        .execute_with(|| {
1
            end_block();
            // If the block is full, the multiplier increases
1
            let before_multiplier = TransactionPayment::next_fee_multiplier();
1
            start_block();
1
            let max_block_weights = crate::RuntimeBlockWeights::get();
1
            frame_support::storage::unhashed::put(
1
                &frame_support::storage::storage_prefix(b"System", b"BlockWeight"),
3
                &ConsumedWeight::new(|class| {
3
                    max_block_weights
3
                        .get(class)
3
                        .max_total
3
                        .unwrap_or(Weight::MAX)
3
                }),
            );
1
            end_block();
1
            let current_multiplier = TransactionPayment::next_fee_multiplier();
1
            assert!(current_multiplier > before_multiplier);
            // If the block is empty, the multiplier decreases
1
            let before_multiplier = TransactionPayment::next_fee_multiplier();
1
            start_block();
1
            frame_support::storage::unhashed::put(
1
                &frame_support::storage::storage_prefix(b"System", b"BlockWeight"),
3
                &ConsumedWeight::new(|_class| Weight::zero()),
            );
1
            end_block();
1
            let current_multiplier = TransactionPayment::next_fee_multiplier();
1
            assert!(current_multiplier < before_multiplier);
1
        });
1
}
#[test]
1
fn test_collator_assignment_tip_priority_on_congestion() {
1
    ExtBuilder::default()
1
        .with_balances(vec![
1
            (AccountId::from(ALICE), 210_000 * UNIT),
1
            (AccountId::from(BOB), 100_000 * UNIT),
1
            (AccountId::from(CHARLIE), 100_000 * UNIT),
1
            (AccountId::from(DAVE), 100_000 * UNIT),
1
        ])
1
        .with_collators(vec![
1
            (AccountId::from(ALICE), 210 * UNIT),
1
            (AccountId::from(BOB), 100 * UNIT),
1
            (AccountId::from(CHARLIE), 100 * UNIT),
1
            (AccountId::from(DAVE), 100 * UNIT),
1
        ])
1
        .with_empty_parachains(vec![1001, 1002, 1003])
1
        .build()
1
        .execute_with(|| {
1
            let para_id = 1003u32;
1
            let tank_funds = 100 * UNIT;
1
            let max_tip = 1 * UNIT;
1
            assert_eq!(
1
                CollatorAssignment::collator_container_chain().container_chains[&1003u32.into()]
1
                    .len(),
                0
            );
            // Send funds to tank
1
            assert_ok!(ServicesPayment::purchase_credits(
1
                origin_of(ALICE.into()),
1
                para_id.into(),
1
                tank_funds,
            ));
            // Set tip for 1003
1
            assert_ok!(ServicesPayment::set_max_tip(
1
                root_origin(),
1
                para_id.into(),
1
                Some(max_tip),
            ));
1
            run_to_session(2);
1
            assert_eq!(
1
                CollatorAssignment::collator_container_chain().container_chains[&para_id.into()]
1
                    .len(),
                2,
            );
1
        });
1
}
#[test]
1
fn test_collator_assignment_tip_charged_on_congestion() {
1
    ExtBuilder::default()
1
        .with_balances(vec![
1
            (AccountId::from(ALICE), 210_000 * UNIT),
1
            (AccountId::from(BOB), 100_000 * UNIT),
1
            (AccountId::from(CHARLIE), 100_000 * UNIT),
1
            (AccountId::from(DAVE), 100_000 * UNIT),
1
        ])
1
        .with_collators(vec![
1
            (AccountId::from(ALICE), 210 * UNIT),
1
            (AccountId::from(BOB), 100 * UNIT),
1
            (AccountId::from(CHARLIE), 100 * UNIT),
1
            (AccountId::from(DAVE), 100 * UNIT),
1
        ])
1
        .with_empty_parachains(vec![1001, 1002, 1003])
1
        .build()
1
        .execute_with(|| {
1
            let tank_funds = 100 * UNIT;
1
            let max_tip = 1 * UNIT;
1
            let para_id = 1003u32;
            // Send funds to tank
1
            assert_ok!(ServicesPayment::purchase_credits(
1
                origin_of(ALICE.into()),
1
                para_id.into(),
1
                tank_funds,
            ));
            // Set tip for para_id
1
            assert_ok!(ServicesPayment::set_max_tip(
1
                root_origin(),
1
                para_id.into(),
1
                Some(max_tip),
            ));
1
            run_to_session(1);
1
            assert_eq!(
1
                Balances::usable_balance(ServicesPayment::parachain_tank(para_id.into())),
1
                tank_funds - max_tip,
            );
1
        });
1
}
#[test]
1
fn test_collator_assignment_tip_not_assigned_on_insufficient_balance() {
1
    ExtBuilder::default()
1
        .with_balances(vec![
1
            (AccountId::from(ALICE), 210_000 * UNIT),
1
            (AccountId::from(BOB), 100_000 * UNIT),
1
            (AccountId::from(CHARLIE), 100_000 * UNIT),
1
            (AccountId::from(DAVE), 100_000 * UNIT),
1
        ])
1
        .with_collators(vec![
1
            (AccountId::from(ALICE), 210 * UNIT),
1
            (AccountId::from(BOB), 100 * UNIT),
1
            (AccountId::from(CHARLIE), 100 * UNIT),
1
            (AccountId::from(DAVE), 100 * UNIT),
1
        ])
1
        .with_empty_parachains(vec![1001, 1002, 1003])
1
        .build()
1
        .execute_with(|| {
1
            let tank_funds = 1 * UNIT;
1
            let max_tip = 1 * UNIT;
1
            let para_id = 1003u32;
            // Send insufficient funds to tank for tip for 2 sessions
1
            assert_ok!(ServicesPayment::purchase_credits(
1
                origin_of(ALICE.into()),
1
                para_id.into(),
1
                tank_funds,
            ));
            // Set tip for para_id
1
            assert_ok!(ServicesPayment::set_max_tip(
1
                root_origin(),
1
                para_id.into(),
1
                Some(max_tip),
            ));
1
            run_to_session(1);
1
            assert_eq!(
1
                CollatorAssignment::collator_container_chain().container_chains[&para_id.into()]
1
                    .len(),
                0
            );
1
        });
1
}
#[test]
1
fn test_collator_assignment_tip_only_charge_willing_paras() {
1
    ExtBuilder::default()
1
        .with_balances(vec![
1
            (AccountId::from(ALICE), 210_000 * UNIT),
1
            (AccountId::from(BOB), 100_000 * UNIT),
1
            (AccountId::from(CHARLIE), 100_000 * UNIT),
1
            (AccountId::from(DAVE), 100_000 * UNIT),
1
            (AccountId::from(EVE), 100_000 * UNIT),
1
            (AccountId::from(FERDIE), 100_000 * UNIT),
1
        ])
1
        .with_collators(vec![
1
            (AccountId::from(ALICE), 210 * UNIT),
1
            (AccountId::from(BOB), 100 * UNIT),
1
            (AccountId::from(CHARLIE), 100 * UNIT),
1
            (AccountId::from(DAVE), 100 * UNIT),
1
            (AccountId::from(EVE), 100 * UNIT),
1
            (AccountId::from(FERDIE), 100 * UNIT),
1
        ])
1
        .with_empty_parachains(vec![1001, 1002, 1003])
1
        .build()
1
        .execute_with(|| {
1
            let tank_funds = 100 * UNIT;
1
            let max_tip = 1 * UNIT;
1
            let para_id_with_tip = 1003u32;
1
            let para_id_without_tip = 1001u32;
            // Send funds to tank to both paras
1
            assert_ok!(ServicesPayment::purchase_credits(
1
                origin_of(ALICE.into()),
1
                para_id_with_tip.into(),
1
                tank_funds,
            ));
1
            assert_ok!(ServicesPayment::purchase_credits(
1
                origin_of(ALICE.into()),
1
                para_id_without_tip.into(),
1
                tank_funds,
            ));
            // Only set tip for 1003
1
            assert_ok!(ServicesPayment::set_max_tip(
1
                root_origin(),
1
                para_id_with_tip.into(),
1
                Some(max_tip),
            ));
1
            run_to_session(2);
1
            let assignment = CollatorAssignment::collator_container_chain().container_chains;
            // 2 out of the 3 paras should have collators assigned, with one paying tip to get
            // prioritized, and the other selected at random that should not be charged any tips
1
            assert_eq!(assignment[&para_id_with_tip.into()].len(), 2);
1
            assert_eq!(
1
                Balances::usable_balance(ServicesPayment::parachain_tank(para_id_with_tip.into())),
1
                tank_funds - max_tip * 2,
            );
1
            assert_eq!(assignment[&para_id_without_tip.into()].len(), 2);
1
            assert_eq!(
1
                Balances::usable_balance(ServicesPayment::parachain_tank(
1
                    para_id_without_tip.into()
                )),
                tank_funds,
            );
1
        });
1
}
#[test]
1
fn test_collator_assignment_tip_withdraw_min_tip() {
1
    ExtBuilder::default()
1
        .with_balances(vec![
1
            (AccountId::from(ALICE), 210_000 * UNIT),
1
            (AccountId::from(BOB), 100_000 * UNIT),
1
            (AccountId::from(CHARLIE), 100_000 * UNIT),
1
            (AccountId::from(DAVE), 100_000 * UNIT),
1
            (AccountId::from(EVE), 100_000 * UNIT),
1
            (AccountId::from(FERDIE), 100_000 * UNIT),
1
        ])
1
        .with_collators(vec![
1
            (AccountId::from(ALICE), 210 * UNIT),
1
            (AccountId::from(BOB), 100 * UNIT),
1
            (AccountId::from(CHARLIE), 100 * UNIT),
1
            (AccountId::from(DAVE), 100 * UNIT),
1
            (AccountId::from(EVE), 100 * UNIT),
1
            (AccountId::from(FERDIE), 100 * UNIT),
1
        ])
1
        .with_empty_parachains(vec![1001, 1002, 1003])
1
        .build()
1
        .execute_with(|| {
1
            let tank_funds = 100 * UNIT;
1
            let max_tip_1003 = 3 * UNIT;
1
            let max_tip_1002 = 2 * UNIT;
1
            let para_id_1003 = 1003u32;
1
            let para_id_1002 = 1002u32;
            // Send funds to tank to both paras
1
            assert_ok!(ServicesPayment::purchase_credits(
1
                origin_of(ALICE.into()),
1
                para_id_1003.into(),
1
                tank_funds,
            ));
1
            assert_ok!(ServicesPayment::purchase_credits(
1
                origin_of(ALICE.into()),
1
                para_id_1002.into(),
1
                tank_funds,
            ));
            // Set tips
1
            assert_ok!(ServicesPayment::set_max_tip(
1
                root_origin(),
1
                para_id_1003.into(),
1
                Some(max_tip_1003),
            ));
1
            assert_ok!(ServicesPayment::set_max_tip(
1
                root_origin(),
1
                para_id_1002.into(),
1
                Some(max_tip_1002),
            ));
1
            run_to_session(2);
1
            assert_eq!(
1
                CollatorAssignment::collator_container_chain().container_chains
1
                    [&para_id_1003.into()]
1
                    .len(),
                2
            );
1
            assert_eq!(
1
                CollatorAssignment::collator_container_chain().container_chains
1
                    [&para_id_1002.into()]
1
                    .len(),
                2
            );
            // Should have withdrawn the lowest tip from both paras
1
            assert_eq!(
1
                Balances::usable_balance(ServicesPayment::parachain_tank(para_id_1003.into())),
1
                tank_funds - max_tip_1002 * 2,
            );
1
            assert_eq!(
1
                Balances::usable_balance(ServicesPayment::parachain_tank(para_id_1002.into())),
1
                tank_funds - max_tip_1002 * 2,
            );
1
        });
1
}
#[test]
1
fn test_migration_data_preservers_profile_content() {
1
    ExtBuilder::default()
1
        .with_balances(vec![(AccountId::from(DAVE), 100_000 * UNIT)])
1
        .build()
1
        .execute_with(|| {
            use frame_support::{migration::put_storage_value, Blake2_128Concat, StorageHasher};
            use pallet_data_preservers::{
                migrations::{OldProfile, OldRegisteredProfile, ProfileMode},
                NodeType, ParaIdsFilter, Profile, RegisteredProfile,
            };
            use sp_runtime::traits::Zero;
            use tanssi_runtime_common::migrations::DataPreserversProfileContentMigration;
            use tp_stream_payment_common::AssetId;
1
            let bootnode_profile = OldRegisteredProfile::<Runtime> {
1
                account: ALICE.into(),
1
                deposit: 42u128,
1
                assignment: None,
1
                profile: OldProfile {
1
                    url: b"alice".to_vec().try_into().unwrap(),
1
                    para_ids: ParaIdsFilter::AnyParaId,
1
                    assignment_request: tp_data_preservers_common::ProviderRequest::Free,
1
                    mode: ProfileMode::Bootnode,
1
                },
1
            };
1
            let substrate_rpc_profile = OldRegisteredProfile::<Runtime> {
1
                account: BOB.into(),
1
                deposit: 43u128,
1
                assignment: Some((
1
                    ParaId::from(1042),
1
                    tp_data_preservers_common::AssignmentWitness::Free,
1
                )),
1

            
1
                profile: OldProfile {
1
                    url: b"bob".to_vec().try_into().unwrap(),
1
                    para_ids: ParaIdsFilter::AnyParaId,
1
                    assignment_request: tp_data_preservers_common::ProviderRequest::Free,
1
                    mode: ProfileMode::Rpc {
1
                        supports_ethereum_rpcs: false,
1
                    },
1
                },
1
            };
1
            let stream_config = pallet_stream_payment::StreamConfig {
1
                time_unit: tp_stream_payment_common::TimeUnit::BlockNumber,
1
                asset_id: AssetId::Native,
1
                rate: 100u128,
1
                minimum_request_deadline_delay: Zero::zero(),
1
                soft_minimum_deposit: Zero::zero(),
1
            };
1
            let frontier_rpc_profile = OldRegisteredProfile::<Runtime> {
1
                account: CHARLIE.into(),
1
                deposit: 44u128,
1
                assignment: Some((
1
                    ParaId::from(1043),
1
                    tp_data_preservers_common::AssignmentWitness::StreamPayment { stream_id: 200 },
1
                )),
1
                profile: OldProfile {
1
                    url: b"charlie".to_vec().try_into().unwrap(),
1
                    para_ids: ParaIdsFilter::AnyParaId,
1
                    assignment_request: tp_data_preservers_common::ProviderRequest::StreamPayment {
1
                        config: stream_config,
1
                    },
1
                    mode: ProfileMode::Rpc {
1
                        supports_ethereum_rpcs: true,
1
                    },
1
                },
1
            };
1
            let pallet_prefix: &[u8] = b"DataPreservers";
1
            let storage_item_prefix: &[u8] = b"Profiles";
1
            put_storage_value(
1
                pallet_prefix,
1
                storage_item_prefix,
1
                &Blake2_128Concat::hash(&0u64.encode()),
1
                bootnode_profile,
            );
1
            put_storage_value(
1
                pallet_prefix,
1
                storage_item_prefix,
1
                &Blake2_128Concat::hash(&1u64.encode()),
1
                substrate_rpc_profile,
            );
1
            put_storage_value(
1
                pallet_prefix,
1
                storage_item_prefix,
1
                &Blake2_128Concat::hash(&2u64.encode()),
1
                frontier_rpc_profile,
            );
1
            let migration = DataPreserversProfileContentMigration::<Runtime>(Default::default());
1
            migration.migrate(Default::default());
1
            assert_eq!(
1
                pallet_data_preservers::Profiles::<Runtime>::get(0),
1
                Some(RegisteredProfile {
1
                    account: ALICE.into(),
1
                    deposit: 42u128,
1
                    assignment: None,
1
                    profile: Profile {
1
                        para_ids: ParaIdsFilter::AnyParaId,
1
                        assignment_request: tp_data_preservers_common::ProviderRequest::Free,
1
                        node_type: NodeType::Substrate,
1
                        additional_info: Default::default(),
1
                        direct_rpc_urls: Default::default(),
1
                        proxy_rpc_urls: Default::default(),
1
                        bootnode_url: Some(b"alice".to_vec().try_into().unwrap())
1
                    }
1
                })
            );
1
            assert_eq!(
1
                pallet_data_preservers::Profiles::<Runtime>::get(1),
1
                Some(RegisteredProfile {
1
                    account: BOB.into(),
1
                    deposit: 43u128,
1
                    assignment: Some((
1
                        ParaId::from(1042),
1
                        tp_data_preservers_common::AssignmentWitness::Free
1
                    )),
1
                    profile: Profile {
1
                        para_ids: ParaIdsFilter::AnyParaId,
1
                        assignment_request: tp_data_preservers_common::ProviderRequest::Free,
1
                        node_type: NodeType::Substrate,
1
                        additional_info: Default::default(),
1
                        direct_rpc_urls: {
1
                            let url = b"bob".to_vec().try_into().unwrap();
1
                            let urls = vec![url].try_into().unwrap();
1
                            urls
1
                        },
1
                        proxy_rpc_urls: Default::default(),
1
                        bootnode_url: None
1
                    }
1
                })
            );
1
            assert_eq!(
1
                pallet_data_preservers::Profiles::<Runtime>::get(2),
1
                Some(RegisteredProfile {
1
                    account: CHARLIE.into(),
1
                    deposit: 44u128,
1
                    assignment: Some((
1
                        ParaId::from(1043),
1
                        tp_data_preservers_common::AssignmentWitness::StreamPayment {
1
                            stream_id: 200,
1
                        }
1
                    )),
1
                    profile: Profile {
1
                        para_ids: ParaIdsFilter::AnyParaId,
1
                        assignment_request:
1
                            tp_data_preservers_common::ProviderRequest::StreamPayment {
1
                                config: stream_config
1
                            },
1
                        node_type: NodeType::Frontier,
1
                        additional_info: Default::default(),
1
                        direct_rpc_urls: {
1
                            let url = b"charlie".to_vec().try_into().unwrap();
1
                            let urls = vec![url].try_into().unwrap();
1
                            urls
1
                        },
1
                        proxy_rpc_urls: Default::default(),
1
                        bootnode_url: None
1
                    }
1
                })
            );
1
        })
1
}
#[test]
1
fn test_migration_registrar_reserves_to_hold() {
1
    ExtBuilder::default()
1
        .with_balances(vec![(AccountId::from(DAVE), 100_000 * UNIT)])
1
        .build()
1
        .execute_with(|| {
            use {
                frame_support::traits::{fungible::InspectHold, ReservableCurrency},
                pallet_registrar::DepositInfo,
                tanssi_runtime_common::migrations::RegistrarReserveToHoldMigration,
            };
1
            let deposit: Balance = 100 * UNIT;
1
            let account: AccountId = DAVE.into();
1
            assert_ok!(Balances::reserve(&account, deposit));
1
            pallet_registrar::RegistrarDeposit::<Runtime>::insert(
1
                ParaId::from(1001),
1
                DepositInfo {
1
                    creator: account.clone(),
1
                    deposit,
1
                },
            );
1
            assert_eq!(Balances::reserved_balance(&account), deposit.clone(),);
            // Apply migration
1
            let migration = RegistrarReserveToHoldMigration::<Runtime>(Default::default());
1
            migration.migrate(Default::default());
            // Holds also count as reserved balance, so the total reserved amount
            // shouldn't change after the migration
1
            assert_eq!(Balances::reserved_balance(&account), deposit.clone(),);
1
            assert_eq!(
1
                Balances::balance_on_hold(
1
                    &pallet_registrar::HoldReason::RegistrarDeposit.into(),
1
                    &account
                ),
                deposit
            );
1
        })
1
}
#[test]
1
fn test_migration_stream_payment_config_new_fields() {
1
    ExtBuilder::default().build().execute_with(|| {
        use pallet_stream_payment::{
            migrations::{OldChangeRequest, OldStream, OldStreamConfig},
            ChangeKind, ChangeRequest, DepositChange, Party, Stream, StreamConfig,
        };
        use tanssi_runtime_common::migrations::MigrateStreamPaymentNewConfigFields;
1
        frame_support::storage::unhashed::put(
1
            &pallet_stream_payment::Streams::<Runtime>::hashed_key_for(0),
1
            &OldStream::<AccountId, StreamPaymentTimeUnit, StreamPaymentAssetId, Balance> {
1
                source: ALICE.into(),
1
                target: BOB.into(),
1
                config: OldStreamConfig {
1
                    time_unit: StreamPaymentTimeUnit::Timestamp,
1
                    asset_id: StreamPaymentAssetId::Native,
1
                    rate: 41,
1
                },
1
                deposit: 42,
1
                last_time_updated: 43,
1
                request_nonce: 44,
1
                pending_request: Some(OldChangeRequest {
1
                    requester: Party::Source,
1
                    kind: ChangeKind::Mandatory { deadline: 45 },
1
                    new_config: OldStreamConfig {
1
                        time_unit: StreamPaymentTimeUnit::BlockNumber,
1
                        asset_id: StreamPaymentAssetId::Native,
1
                        rate: 46,
1
                    },
1
                    deposit_change: Some(DepositChange::Absolute(47)),
1
                }),
1
                opening_deposit: 48,
1
            },
        );
1
        frame_support::storage::unhashed::put(
1
            &pallet_stream_payment::Streams::<Runtime>::hashed_key_for(1),
1
            &OldStream::<AccountId, StreamPaymentTimeUnit, StreamPaymentAssetId, Balance> {
1
                source: CHARLIE.into(),
1
                target: ALICE.into(),
1
                config: OldStreamConfig {
1
                    time_unit: StreamPaymentTimeUnit::Timestamp,
1
                    asset_id: StreamPaymentAssetId::Native,
1
                    rate: 100,
1
                },
1
                deposit: 101,
1
                last_time_updated: 102,
1
                request_nonce: 103,
1
                pending_request: None,
1
                opening_deposit: 104,
1
            },
        );
1
        let migration = MigrateStreamPaymentNewConfigFields::<Runtime>(Default::default());
1
        migration.migrate(Default::default());
1
        assert_eq!(
1
            pallet_stream_payment::Streams::<Runtime>::get(0).unwrap(),
1
            Stream {
1
                source: ALICE.into(),
1
                target: BOB.into(),
1
                config: StreamConfig {
1
                    time_unit: StreamPaymentTimeUnit::Timestamp,
1
                    asset_id: StreamPaymentAssetId::Native,
1
                    rate: 41,
1
                    minimum_request_deadline_delay: 0,
1
                    soft_minimum_deposit: 0,
1
                },
1
                deposit: 42,
1
                last_time_updated: 43,
1
                request_nonce: 44,
1
                pending_request: Some(ChangeRequest {
1
                    requester: Party::Source,
1
                    kind: ChangeKind::Mandatory { deadline: 45 },
1
                    new_config: StreamConfig {
1
                        time_unit: StreamPaymentTimeUnit::BlockNumber,
1
                        asset_id: StreamPaymentAssetId::Native,
1
                        rate: 46,
1
                        minimum_request_deadline_delay: 0,
1
                        soft_minimum_deposit: 0,
1
                    },
1
                    deposit_change: Some(DepositChange::Absolute(47)),
1
                }),
1
                opening_deposit: 48,
1
            }
        );
1
        assert_eq!(
1
            pallet_stream_payment::Streams::<Runtime>::get(1).unwrap(),
1
            Stream {
1
                source: CHARLIE.into(),
1
                target: ALICE.into(),
1
                config: StreamConfig {
1
                    time_unit: StreamPaymentTimeUnit::Timestamp,
1
                    asset_id: StreamPaymentAssetId::Native,
1
                    rate: 100,
1
                    minimum_request_deadline_delay: 0,
1
                    soft_minimum_deposit: 0,
1
                },
1
                deposit: 101,
1
                last_time_updated: 102,
1
                request_nonce: 103,
1
                pending_request: None,
1
                opening_deposit: 104,
1
            }
        );
1
    })
1
}
#[test]
1
fn test_container_deregister_unassign_data_preserver() {
1
    ExtBuilder::default()
1
        .with_balances(vec![
1
            (AccountId::from(ALICE), 210_000 * UNIT),
1
            (AccountId::from(BOB), 100_000 * UNIT),
1
        ])
1
        .build()
1
        .execute_with(|| {
            use pallet_data_preservers::{
                AssignerParameterOf, NodeType, ParaIdsFilter, Profile, ProviderRequestOf,
            };
1
            let profile = Profile {
1
                bootnode_url: Some(b"test".to_vec().try_into().unwrap()),
1
                direct_rpc_urls: Default::default(),
1
                proxy_rpc_urls: Default::default(),
1
                para_ids: ParaIdsFilter::AnyParaId,
1
                node_type: NodeType::Substrate,
1
                additional_info: Default::default(),
1
                assignment_request: ProviderRequestOf::<Runtime>::Free,
1
            };
1
            let para_id = ParaId::from(1002);
1
            let profile_id = 0u64;
1
            assert_ok!(Registrar::register(
1
                origin_of(ALICE.into()),
1
                para_id,
1
                empty_genesis_data(),
1
                None
            ));
1
            assert_ok!(DataPreservers::create_profile(
1
                origin_of(BOB.into()),
1
                profile.clone(),
            ));
            // Start assignment
1
            assert_ok!(DataPreservers::start_assignment(
1
                origin_of(ALICE.into()),
1
                profile_id,
1
                para_id,
1
                AssignerParameterOf::<Runtime>::Free
            ));
1
            assert!(pallet_data_preservers::Assignments::<Runtime>::get(para_id).contains(&0u64));
            // Deregister from Registrar
1
            assert_ok!(Registrar::deregister(root_origin(), para_id), ());
            // Check DataPreserver assignment has been cleared
1
            assert!(pallet_data_preservers::Assignments::<Runtime>::get(para_id).is_empty());
1
        });
1
}
#[test]
1
fn test_data_preserver_with_stream_payment() {
1
    ExtBuilder::default()
1
        .with_balances(vec![
1
            (AccountId::from(ALICE), 210_000 * UNIT),
1
            (AccountId::from(BOB), 100_000 * UNIT),
1
        ])
1
        .build()
1
        .execute_with(|| {
            use pallet_data_preservers::{
                AssignerParameterOf, NodeType, ParaIdsFilter, Profile, ProviderRequestOf,
            };
1
            let profile = Profile {
1
                bootnode_url: Some(b"test".to_vec().try_into().unwrap()),
1
                direct_rpc_urls: Default::default(),
1
                proxy_rpc_urls: Default::default(),
1
                para_ids: ParaIdsFilter::AnyParaId,
1
                node_type: NodeType::Substrate,
1
                additional_info: Default::default(),
1
                assignment_request: ProviderRequestOf::<Runtime>::StreamPayment {
1
                    config: StreamConfig {
1
                        time_unit: StreamPaymentTimeUnit::BlockNumber,
1
                        asset_id: StreamPaymentAssetId::Native,
1
                        rate: 42,
1
                        minimum_request_deadline_delay: 0,
1
                        soft_minimum_deposit: 0,
1
                    },
1
                },
1
            };
1
            let para_id = ParaId::from(1002);
1
            let profile_id = 0u64;
1
            assert_ok!(Registrar::register(
1
                origin_of(ALICE.into()),
1
                para_id,
1
                empty_genesis_data(),
1
                None
            ));
1
            assert_ok!(DataPreservers::create_profile(
1
                origin_of(BOB.into()),
1
                profile.clone(),
            ));
            // Start assignment
1
            assert_ok!(DataPreservers::start_assignment(
1
                origin_of(ALICE.into()),
1
                profile_id,
1
                para_id,
1
                AssignerParameterOf::<Runtime>::StreamPayment {
1
                    initial_deposit: 1_000
1
                }
            ));
1
            assert!(
1
                pallet_data_preservers::Assignments::<Runtime>::get(para_id).contains(&profile_id)
            );
1
            let profile = pallet_data_preservers::Profiles::<Runtime>::get(profile_id)
1
                .expect("profile to exists");
1
            let (assigned_para_id, witness) = profile.assignment.expect("profile to be assigned");
1
            assert_eq!(assigned_para_id, para_id);
1
            assert_eq!(
                witness,
                tp_data_preservers_common::AssignmentWitness::StreamPayment { stream_id: 0 }
            );
1
        });
1
}
#[test]
1
fn test_data_preserver_kind_needs_to_match() {
1
    ExtBuilder::default()
1
        .with_balances(vec![
1
            (AccountId::from(ALICE), 210_000 * UNIT),
1
            (AccountId::from(BOB), 100_000 * UNIT),
1
        ])
1
        .build()
1
        .execute_with(|| {
            use pallet_data_preservers::{
                AssignerParameterOf, NodeType, ParaIdsFilter, Profile, ProviderRequestOf,
            };
1
            let profile = Profile {
1
                bootnode_url: Some(b"test".to_vec().try_into().unwrap()),
1
                direct_rpc_urls: Default::default(),
1
                proxy_rpc_urls: Default::default(),
1
                para_ids: ParaIdsFilter::AnyParaId,
1
                node_type: NodeType::Substrate,
1
                additional_info: Default::default(),
1
                assignment_request: ProviderRequestOf::<Runtime>::Free,
1
            };
1
            let para_id = ParaId::from(1002);
1
            let profile_id = 0u64;
1
            assert_ok!(Registrar::register(
1
                origin_of(ALICE.into()),
1
                para_id,
1
                empty_genesis_data(),
1
                None
            ));
1
            assert_ok!(DataPreservers::create_profile(
1
                origin_of(BOB.into()),
1
                profile.clone(),
            ));
            // Start assignment
1
            assert_err!(
1
                DataPreservers::start_assignment(
1
                    origin_of(ALICE.into()),
1
                    profile_id,
1
                    para_id,
1
                    AssignerParameterOf::<Runtime>::StreamPayment {
1
                        initial_deposit: 1_000
1
                    }
                ),
1
                pallet_data_preservers::Error::<Runtime>::AssignmentPaymentRequestParameterMismatch
            );
1
        });
1
}
#[test]
1
fn test_registrar_extrinsic_permissions() {
1
    ExtBuilder::default()
1
        .with_balances(vec![
1
            (
1
                cumulus_primitives_core::relay_chain::AccountId::from(ALICE),
1
                210_000 * UNIT,
1
            ),
1
            (
1
                cumulus_primitives_core::relay_chain::AccountId::from(BOB),
1
                100_000 * UNIT,
1
            ),
1
        ])
1
        .with_empty_parachains(vec![1001])
1
        .build()
1
        .execute_with(|| {
1
            let para_id = ParaId::from(1001);
            // Pause container chain should fail if not para manager
1
            assert_noop!(
1
                Registrar::pause_container_chain(origin_of(BOB.into()), para_id),
1
                BadOrigin
            );
            // Set Bob as para manager
1
            assert_ok!(Registrar::set_para_manager(
1
                root_origin(),
1
                para_id,
1
                AccountId::from(BOB)
            ));
            // Pause container chain should succeed if para manager
1
            assert_ok!(
1
                Registrar::pause_container_chain(origin_of(BOB.into()), para_id),
                ()
            );
1
        });
1
}