1
// Copyright (C) Moondance Labs Ltd.
2
// This file is part of Tanssi.
3

            
4
// Tanssi is free software: you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation, either version 3 of the License, or
7
// (at your option) any later version.
8

            
9
// Tanssi is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
// GNU General Public License for more details.
13

            
14
// You should have received a copy of the GNU General Public License
15
// along with Tanssi.  If not, see <http://www.gnu.org/licenses/>
16

            
17
use crate::get_para_id_authorities;
18
#[cfg(feature = "runtime-benchmarks")]
19
use crate::{CollatorAssignment, Session, System};
20
#[cfg(feature = "runtime-benchmarks")]
21
use pallet_session::ShouldEndSession;
22
use sp_consensus_slots::Slot;
23
#[cfg(feature = "runtime-benchmarks")]
24
use sp_std::{collections::btree_map::BTreeMap, vec};
25
#[cfg(feature = "runtime-benchmarks")]
26
use tp_traits::GetContainerChainAuthor;
27
use {
28
    super::{
29
        currency::MICRODANCE, weights::xcm::XcmWeight as XcmGenericWeights, AccountId,
30
        AllPalletsWithSystem, AssetRate, Balance, Balances, BlockNumber, ForeignAssets,
31
        ForeignAssetsCreator, MaintenanceMode, MessageQueue, ParachainInfo, ParachainSystem,
32
        PolkadotXcm, Registrar, Runtime, RuntimeBlockWeights, RuntimeCall, RuntimeEvent,
33
        RuntimeOrigin, TransactionByteFee, WeightToFee, XcmpQueue,
34
    },
35
    crate::{weights, AuthorNoting},
36
    cumulus_primitives_core::{AggregateMessageOrigin, ParaId},
37
    frame_support::{
38
        parameter_types,
39
        traits::{Everything, Nothing, PalletInfoAccess, TransformOrigin},
40
        weights::Weight,
41
    },
42
    frame_system::{pallet_prelude::BlockNumberFor, EnsureRoot},
43
    nimbus_primitives::NimbusId,
44
    pallet_xcm::XcmPassthrough,
45
    pallet_xcm_core_buyer::{
46
        CheckCollatorValidity, GetParathreadMaxCorePrice, GetParathreadParams, GetPurchaseCoreCall,
47
        ParaIdIntoAccountTruncating, XCMNotifier,
48
    },
49
    parachains_common::message_queue::{NarrowOriginToSibling, ParaIdToSibling},
50
    parity_scale_codec::{Decode, Encode},
51
    polkadot_runtime_common::xcm_sender::ExponentialPrice,
52
    scale_info::TypeInfo,
53
    sp_core::ConstU32,
54
    sp_runtime::{transaction_validity::TransactionPriority, Perbill},
55
    sp_std::vec::Vec,
56
    staging_xcm::latest::prelude::*,
57
    staging_xcm_builder::{
58
        AccountId32Aliases, AllowKnownQueryResponses, AllowSubscriptionsFrom,
59
        AllowTopLevelPaidExecutionFrom, ConvertedConcreteId, EnsureXcmOrigin, FungibleAdapter,
60
        FungiblesAdapter, IsConcrete, NoChecking, ParentIsPreset, RelayChainAsNative,
61
        SiblingParachainAsNative, SiblingParachainConvertsVia, SignedAccountId32AsNative,
62
        SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit, TrailingSetTopicAsId,
63
        UsingComponents, WeightInfoBounds, WithComputedOrigin,
64
    },
65
    staging_xcm_executor::{traits::JustTry, XcmExecutor},
66
    tp_traits::ParathreadParams,
67
};
68

            
69
parameter_types! {
70
    // Self Reserve location, defines the multilocation identifiying the self-reserve currency
71
    // This is used to match it also against our Balances pallet when we receive such
72
    // a Location: (Self Balances pallet index)
73
    // We use the RELATIVE multilocation
74
    pub SelfReserve: Location = Location {
75
        parents: 0,
76
        interior: [
77
            PalletInstance(<Balances as PalletInfoAccess>::index() as u8)
78
        ].into()
79
    };
80

            
81
    // One XCM operation is 1_000_000_000 weight - almost certainly a conservative estimate.
82
    pub UnitWeightCost: Weight = Weight::from_parts(1_000_000_000, 64 * 1024);
83

            
84
    // TODO: revisit
85
    pub const RelayNetwork: NetworkId = NetworkId::Westend;
86

            
87
    // The relay chain Origin type
88
    pub RelayChainOrigin: RuntimeOrigin = cumulus_pallet_xcm::Origin::Relay.into();
89

            
90
    pub const MaxAssetsIntoHolding: u32 = 64;
91

            
92
    /// Maximum number of instructions in a single XCM fragment. A sanity check against
93
    /// weight caculations getting too crazy.
94
    pub MaxInstructions: u32 = 100;
95

            
96
    // The universal location within the global consensus system
97
    pub UniversalLocation: InteriorLocation =
98
    [GlobalConsensus(RelayNetwork::get()), Parachain(ParachainInfo::parachain_id().into())].into();
99

            
100
    pub const BaseDeliveryFee: u128 = 100 * MICRODANCE;
101
}
102

            
103
#[cfg(feature = "runtime-benchmarks")]
104
parameter_types! {
105
    pub ReachableDest: Option<Location> = Some(Parent.into());
106
}
107

            
108
pub type XcmBarrier = (
109
    // Weight that is paid for may be consumed.
110
    TakeWeightCredit,
111
    // Expected responses are OK.
112
    TrailingSetTopicAsId<AllowKnownQueryResponses<PolkadotXcm>>,
113
    WithComputedOrigin<
114
        (
115
            // If the message is one that immediately attemps to pay for execution, then allow it.
116
            AllowTopLevelPaidExecutionFrom<Everything>,
117
            // Subscriptions for version tracking are OK.
118
            AllowSubscriptionsFrom<Everything>,
119
        ),
120
        UniversalLocation,
121
        ConstU32<8>,
122
    >,
123
);
124

            
125
/// Type for specifying how a `Location` can be converted into an `AccountId`. This is used
126
/// when determining ownership of accounts for asset transacting and when attempting to use XCM
127
/// `Transact` in order to determine the dispatch Origin.
128
pub type LocationToAccountId = (
129
    // The parent (Relay-chain) origin converts to the default `AccountId`.
130
    ParentIsPreset<AccountId>,
131
    // Sibling parachain origins convert to AccountId via the `ParaId::into`.
132
    SiblingParachainConvertsVia<polkadot_parachain_primitives::primitives::Sibling, AccountId>,
133
    // If we receive a Location of type AccountKey20, just generate a native account
134
    AccountId32Aliases<RelayNetwork, AccountId>,
135
    // Generate remote accounts according to polkadot standards
136
    staging_xcm_builder::HashedDescription<
137
        AccountId,
138
        staging_xcm_builder::DescribeFamily<staging_xcm_builder::DescribeAllTerminal>,
139
    >,
140
);
141

            
142
/// Local origins on this chain are allowed to dispatch XCM sends/executions.
143
pub type LocalOriginToLocation = SignedToAccountId32<RuntimeOrigin, AccountId, RelayNetwork>;
144

            
145
/// Means for transacting the native currency on this chain.
146
pub type CurrencyTransactor = FungibleAdapter<
147
    // Use this currency:
148
    Balances,
149
    // Use this currency when it is a fungible asset matching the given location or name:
150
    IsConcrete<SelfReserve>,
151
    // Convert an XCM Location into a local account id:
152
    LocationToAccountId,
153
    // Our chain's account ID type (we can't get away without mentioning it explicitly):
154
    AccountId,
155
    // We don't track any teleports of `Balances`.
156
    (),
157
>;
158

            
159
/// This is the type we use to convert an (incoming) XCM origin into a local `Origin` instance,
160
/// ready for dispatching a transaction with Xcm's `Transact`. There is an `OriginKind` which can
161
/// biases the kind of local `Origin` it will become.
162
pub type XcmOriginToTransactDispatchOrigin = (
163
    // Sovereign account converter; this attempts to derive an `AccountId` from the origin location
164
    // using `LocationToAccountId` and then turn that into the usual `Signed` origin. Useful for
165
    // foreign chains who want to have a local sovereign account on this chain which they control.
166
    SovereignSignedViaLocation<LocationToAccountId, RuntimeOrigin>,
167
    // Native converter for Relay-chain (Parent) location; will convert to a `Relay` origin when
168
    // recognised.
169
    RelayChainAsNative<RelayChainOrigin, RuntimeOrigin>,
170
    // Native converter for sibling Parachains; will convert to a `SiblingPara` origin when
171
    // recognised.
172
    SiblingParachainAsNative<cumulus_pallet_xcm::Origin, RuntimeOrigin>,
173
    // Native signed account converter; this just converts an `AccountId32` origin into a normal
174
    // `RuntimeOrigin::Signed` origin of the same 32-byte value.
175
    SignedAccountId32AsNative<RelayNetwork, RuntimeOrigin>,
176
    // Xcm origins can be represented natively under the Xcm pallet's Xcm origin.
177
    XcmPassthrough<RuntimeOrigin>,
178
);
179

            
180
/// Means for transacting assets on this chain.
181
pub type AssetTransactors = (CurrencyTransactor, ForeignFungiblesTransactor);
182
pub type XcmWeigher =
183
    WeightInfoBounds<XcmGenericWeights<RuntimeCall>, RuntimeCall, MaxInstructions>;
184

            
185
/// The means for routing XCM messages which are not for local execution into the right message
186
/// queues.
187
pub type XcmRouter = (
188
    // Two routers - use UMP to communicate with the relay chain:
189
    cumulus_primitives_utility::ParentAsUmp<ParachainSystem, PolkadotXcm, PriceForParentDelivery>,
190
    // ..and XCMP to communicate with the sibling chains.
191
    XcmpQueue,
192
);
193

            
194
pub struct XcmConfig;
195
impl staging_xcm_executor::Config for XcmConfig {
196
    type RuntimeCall = RuntimeCall;
197
    type XcmSender = XcmRouter;
198
    type AssetTransactor = AssetTransactors;
199
    type OriginConverter = XcmOriginToTransactDispatchOrigin;
200
    type IsReserve = NativeAssetReserve;
201
    type IsTeleporter = ();
202
    type UniversalLocation = UniversalLocation;
203
    type Barrier = XcmBarrier;
204
    type Weigher = XcmWeigher;
205
    // Local token trader only
206
    // TODO: update once we have a way to do fees
207
    type Trader = (
208
        UsingComponents<WeightToFee, SelfReserve, AccountId, Balances, ()>,
209
        cumulus_primitives_utility::TakeFirstAssetTrader<
210
            AccountId,
211
            AssetRateAsMultiplier,
212
            // Use this currency when it is a fungible asset matching the given location or name:
213
            (ConvertedConcreteId<AssetId, Balance, ForeignAssetsCreator, JustTry>,),
214
            ForeignAssets,
215
            (),
216
        >,
217
    );
218
    type ResponseHandler = PolkadotXcm;
219
    type AssetTrap = PolkadotXcm;
220
    type AssetClaims = PolkadotXcm;
221
    type SubscriptionService = PolkadotXcm;
222
    type PalletInstancesInfo = AllPalletsWithSystem;
223
    type MaxAssetsIntoHolding = MaxAssetsIntoHolding;
224
    type AssetLocker = ();
225
    type AssetExchanger = ();
226
    type FeeManager = ();
227
    type MessageExporter = ();
228
    type UniversalAliases = Nothing;
229
    type CallDispatcher = RuntimeCall;
230
    type SafeCallFilter = Everything;
231
    type Aliasers = Nothing;
232
    type TransactionalProcessor = staging_xcm_builder::FrameTransactionalProcessor;
233
    type HrmpNewChannelOpenRequestHandler = ();
234
    type HrmpChannelAcceptedHandler = ();
235
    type HrmpChannelClosingHandler = ();
236
}
237

            
238
impl pallet_xcm::Config for Runtime {
239
    type RuntimeEvent = RuntimeEvent;
240
    type SendXcmOrigin = EnsureXcmOrigin<RuntimeOrigin, LocalOriginToLocation>;
241
    type XcmRouter = XcmRouter;
242
    type ExecuteXcmOrigin = EnsureXcmOrigin<RuntimeOrigin, LocalOriginToLocation>;
243
    type XcmExecuteFilter = Everything;
244
    type XcmExecutor = XcmExecutor<XcmConfig>;
245
    type XcmTeleportFilter = Nothing;
246
    type XcmReserveTransferFilter = Everything;
247
    type Weigher = XcmWeigher;
248
    type UniversalLocation = UniversalLocation;
249
    type RuntimeOrigin = RuntimeOrigin;
250
    type RuntimeCall = RuntimeCall;
251
    const VERSION_DISCOVERY_QUEUE_SIZE: u32 = 100;
252
    type AdvertisedXcmVersion = pallet_xcm::CurrentXcmVersion;
253
    type Currency = Balances;
254
    type CurrencyMatcher = ();
255
    type TrustedLockers = ();
256
    type SovereignAccountOf = LocationToAccountId;
257
    type MaxLockers = ConstU32<8>;
258
    type MaxRemoteLockConsumers = ConstU32<0>;
259
    type RemoteLockConsumerIdentifier = ();
260
    // TODO pallet-xcm weights
261
    type WeightInfo = weights::pallet_xcm::SubstrateWeight<Runtime>;
262
    type AdminOrigin = EnsureRoot<AccountId>;
263
}
264

            
265
pub type PriceForSiblingParachainDelivery =
266
    ExponentialPrice<SelfReserve, BaseDeliveryFee, TransactionByteFee, XcmpQueue>;
267

            
268
pub type PriceForParentDelivery =
269
    ExponentialPrice<SelfReserve, BaseDeliveryFee, TransactionByteFee, ParachainSystem>;
270

            
271
impl cumulus_pallet_xcmp_queue::Config for Runtime {
272
    type RuntimeEvent = RuntimeEvent;
273
    type ChannelInfo = ParachainSystem;
274
    type VersionWrapper = PolkadotXcm;
275
    type ControllerOrigin = EnsureRoot<AccountId>;
276
    type ControllerOriginConverter = XcmOriginToTransactDispatchOrigin;
277
    type WeightInfo = weights::cumulus_pallet_xcmp_queue::SubstrateWeight<Runtime>;
278
    type PriceForSiblingDelivery = PriceForSiblingParachainDelivery;
279
    // Enqueue XCMP messages from siblings for later processing.
280
    type XcmpQueue = TransformOrigin<MessageQueue, AggregateMessageOrigin, ParaId, ParaIdToSibling>;
281
    type MaxInboundSuspended = sp_core::ConstU32<1_000>;
282
}
283

            
284
impl cumulus_pallet_xcm::Config for Runtime {
285
    type RuntimeEvent = RuntimeEvent;
286
    type XcmExecutor = XcmExecutor<XcmConfig>;
287
}
288

            
289
parameter_types! {
290
    pub const RelayOrigin: AggregateMessageOrigin = AggregateMessageOrigin::Parent;
291
}
292

            
293
impl cumulus_pallet_dmp_queue::Config for Runtime {
294
    type WeightInfo = weights::cumulus_pallet_dmp_queue::SubstrateWeight<Runtime>;
295
    type RuntimeEvent = RuntimeEvent;
296
    type DmpSink = frame_support::traits::EnqueueWithOrigin<MessageQueue, RelayOrigin>;
297
}
298

            
299
parameter_types! {
300
    // we just reuse the same deposits
301
    pub const ForeignAssetsAssetDeposit: Balance = 0;
302
    pub const ForeignAssetsAssetAccountDeposit: Balance = 0;
303
    pub const ForeignAssetsApprovalDeposit: Balance = 0;
304
    pub const ForeignAssetsAssetsStringLimit: u32 = 50;
305
    pub const ForeignAssetsMetadataDepositBase: Balance = 0;
306
    pub const ForeignAssetsMetadataDepositPerByte: Balance = 0;
307
    pub CheckingAccount: AccountId = PolkadotXcm::check_account();
308
}
309

            
310
#[cfg(feature = "runtime-benchmarks")]
311
/// Simple conversion of `u32` into an `AssetId` for use in benchmarking.
312
pub struct ForeignAssetBenchmarkHelper;
313
#[cfg(feature = "runtime-benchmarks")]
314
impl pallet_assets::BenchmarkHelper<AssetId> for ForeignAssetBenchmarkHelper {
315
    fn create_asset_id_parameter(id: u32) -> AssetId {
316
        id.try_into()
317
            .expect("number too large to create benchmarks")
318
    }
319
}
320
#[cfg(feature = "runtime-benchmarks")]
321
impl pallet_asset_rate::AssetKindFactory<AssetId> for ForeignAssetBenchmarkHelper {
322
    fn create_asset_kind(id: u32) -> AssetId {
323
        id.try_into()
324
            .expect("number too large to create benchmarks")
325
    }
326
}
327

            
328
pub type AssetId = u16;
329
pub type ForeignAssetsInstance = pallet_assets::Instance1;
330
impl pallet_assets::Config<ForeignAssetsInstance> for Runtime {
331
    type RuntimeEvent = RuntimeEvent;
332
    type Balance = Balance;
333
    type AssetId = AssetId;
334
    type AssetIdParameter = AssetId;
335
    type Currency = Balances;
336
    type CreateOrigin = frame_support::traits::NeverEnsureOrigin<AccountId>;
337
    type ForceOrigin = EnsureRoot<AccountId>;
338
    type AssetDeposit = ForeignAssetsAssetDeposit;
339
    type MetadataDepositBase = ForeignAssetsMetadataDepositBase;
340
    type MetadataDepositPerByte = ForeignAssetsMetadataDepositPerByte;
341
    type ApprovalDeposit = ForeignAssetsApprovalDeposit;
342
    type StringLimit = ForeignAssetsAssetsStringLimit;
343
    type Freezer = ();
344
    type Extra = ();
345
    type WeightInfo = weights::pallet_assets::SubstrateWeight<Runtime>;
346
    type CallbackHandle = ();
347
    type AssetAccountDeposit = ForeignAssetsAssetAccountDeposit;
348
    type RemoveItemsLimit = frame_support::traits::ConstU32<1000>;
349
    #[cfg(feature = "runtime-benchmarks")]
350
    type BenchmarkHelper = ForeignAssetBenchmarkHelper;
351
}
352

            
353
impl pallet_foreign_asset_creator::Config for Runtime {
354
    type RuntimeEvent = RuntimeEvent;
355
    type ForeignAsset = Location;
356
    type ForeignAssetCreatorOrigin = EnsureRoot<AccountId>;
357
    type ForeignAssetModifierOrigin = EnsureRoot<AccountId>;
358
    type ForeignAssetDestroyerOrigin = EnsureRoot<AccountId>;
359
    type Fungibles = ForeignAssets;
360
    type WeightInfo = weights::pallet_foreign_asset_creator::SubstrateWeight<Runtime>;
361
    type OnForeignAssetCreated = ();
362
    type OnForeignAssetDestroyed = ();
363
}
364

            
365
impl pallet_asset_rate::Config for Runtime {
366
    type CreateOrigin = EnsureRoot<AccountId>;
367
    type RemoveOrigin = EnsureRoot<AccountId>;
368
    type UpdateOrigin = EnsureRoot<AccountId>;
369
    type Currency = Balances;
370
    type AssetKind = AssetId;
371
    type RuntimeEvent = RuntimeEvent;
372
    type WeightInfo = weights::pallet_asset_rate::SubstrateWeight<Runtime>;
373
    #[cfg(feature = "runtime-benchmarks")]
374
    type BenchmarkHelper = ForeignAssetBenchmarkHelper;
375
}
376

            
377
/// Means for transacting foreign assets from different global consensus.
378
pub type ForeignFungiblesTransactor = FungiblesAdapter<
379
    // Use this fungibles implementation:
380
    ForeignAssets,
381
    // Use this currency when it is a fungible asset matching the given location or name:
382
    (ConvertedConcreteId<AssetId, Balance, ForeignAssetsCreator, JustTry>,),
383
    // Convert an XCM Location into a local account id:
384
    LocationToAccountId,
385
    // Our chain's account ID type (we can't get away without mentioning it explicitly):
386
    AccountId,
387
    // We dont need to check teleports here.
388
    NoChecking,
389
    // The account to use for tracking teleports.
390
    CheckingAccount,
391
>;
392

            
393
/// Multiplier used for dedicated `TakeFirstAssetTrader` with `ForeignAssets` instance.
394
pub type AssetRateAsMultiplier =
395
    parachains_common::xcm_config::AssetFeeAsExistentialDepositMultiplier<
396
        Runtime,
397
        WeightToFee,
398
        AssetRate,
399
        ForeignAssetsInstance,
400
    >;
401

            
402
// TODO: this should probably move to somewhere in the polkadot-sdk repo
403
pub struct NativeAssetReserve;
404
impl frame_support::traits::ContainsPair<Asset, Location> for NativeAssetReserve {
405
54
    fn contains(asset: &Asset, origin: &Location) -> bool {
406
54
        log::trace!(target: "xcm::contains", "NativeAssetReserve asset: {:?}, origin: {:?}", asset, origin);
407
54
        let reserve = if asset.id.0.parents == 0
408
14
            && !matches!(asset.id.0.first_interior(), Some(Parachain(_)))
409
        {
410
14
            Some(Location::here())
411
        } else {
412
40
            asset.id.0.chain_part()
413
        };
414

            
415
54
        if let Some(ref reserve) = reserve {
416
52
            if reserve == origin {
417
34
                return true;
418
18
            }
419
2
        }
420
20
        false
421
54
    }
422
}
423

            
424
pub trait Parse {
425
    /// Returns the "chain" location part. It could be parent, sibling
426
    /// parachain, or child parachain.
427
    fn chain_part(&self) -> Option<Location>;
428
    /// Returns "non-chain" location part.
429
    fn non_chain_part(&self) -> Option<Location>;
430
}
431

            
432
impl Parse for Location {
433
40
    fn chain_part(&self) -> Option<Location> {
434
40
        match (self.parents, self.first_interior()) {
435
            // sibling parachain
436
10
            (1, Some(Parachain(id))) => Some(Location::new(1, [Parachain(*id)])),
437
            // parent
438
28
            (1, _) => Some(Location::parent()),
439
            // children parachain
440
            (0, Some(Parachain(id))) => Some(Location::new(0, [Parachain(*id)])),
441
2
            _ => None,
442
        }
443
40
    }
444

            
445
    fn non_chain_part(&self) -> Option<Location> {
446
        let mut junctions = self.interior().clone();
447
        while matches!(junctions.first(), Some(Parachain(_))) {
448
            let _ = junctions.take_first();
449
        }
450

            
451
        if junctions != Here {
452
            Some(Location::new(0, junctions))
453
        } else {
454
            None
455
        }
456
    }
457
}
458

            
459
parameter_types! {
460
    pub MessageQueueServiceWeight: Weight = Perbill::from_percent(25) * RuntimeBlockWeights::get().max_block;
461
}
462

            
463
impl pallet_message_queue::Config for Runtime {
464
    type RuntimeEvent = RuntimeEvent;
465
    type WeightInfo = weights::pallet_message_queue::SubstrateWeight<Runtime>;
466
    #[cfg(feature = "runtime-benchmarks")]
467
    type MessageProcessor = pallet_message_queue::mock_helpers::NoopMessageProcessor<
468
        cumulus_primitives_core::AggregateMessageOrigin,
469
    >;
470
    #[cfg(not(feature = "runtime-benchmarks"))]
471
    type MessageProcessor = staging_xcm_builder::ProcessXcmMessage<
472
        AggregateMessageOrigin,
473
        XcmExecutor<XcmConfig>,
474
        RuntimeCall,
475
    >;
476
    type Size = u32;
477
    // The XCMP queue pallet is only ever able to handle the `Sibling(ParaId)` origin:
478
    type QueueChangeHandler = NarrowOriginToSibling<XcmpQueue>;
479
    // NarrowOriginToSibling calls XcmpQueue's is_pause if Origin is sibling. Allows all other origins
480
    type QueuePausedQuery = (MaintenanceMode, NarrowOriginToSibling<XcmpQueue>);
481
    // TODO verify values
482
    type HeapSize = sp_core::ConstU32<{ 64 * 1024 }>;
483
    type MaxStale = sp_core::ConstU32<8>;
484
    type ServiceWeight = MessageQueueServiceWeight;
485
    type IdleMaxServiceWeight = MessageQueueServiceWeight;
486
}
487

            
488
parameter_types! {
489
    pub const ParasUnsignedPriority: TransactionPriority = TransactionPriority::MAX;
490
    pub const XcmBuyExecutionDotRococo: u128 = XCM_BUY_EXECUTION_COST_ROCOCO;
491
}
492

            
493
pub const XCM_BUY_EXECUTION_COST_ROCOCO: u128 = 70_000_000 + 126_666_399;
494

            
495
pub struct XCMNotifierImpl;
496

            
497
impl XCMNotifier<Runtime> for XCMNotifierImpl {
498
10
    fn new_notify_query(
499
10
        responder: impl Into<Location>,
500
10
        notify: impl Into<RuntimeCall>,
501
10
        timeout: BlockNumberFor<Runtime>,
502
10
        match_querier: impl Into<Location>,
503
10
    ) -> u64 {
504
10
        pallet_xcm::Pallet::<Runtime>::new_notify_query(responder, notify, timeout, match_querier)
505
10
    }
506
}
507

            
508
parameter_types! {
509
    pub const CoreBuyingXCMQueryTtl: BlockNumber = 100;
510
    pub const AdditionalTtlForInflightOrders: BlockNumber = 5;
511
    pub const PendingBlockTtl: BlockNumber = 10;
512
    pub BuyCoreSlotDrift: Slot = Slot::from(5u64);
513
}
514

            
515
impl pallet_xcm_core_buyer::Config for Runtime {
516
    type RuntimeEvent = RuntimeEvent;
517
    type Currency = Balances;
518

            
519
    type XcmSender = XcmRouter;
520
    type GetPurchaseCoreCall = EncodedCallToBuyCore;
521
    type GetParathreadAccountId = ParaIdIntoAccountTruncating;
522
    type GetParathreadMaxCorePrice = GetMaxCorePriceFromServicesPayment;
523
    type SelfParaId = parachain_info::Pallet<Runtime>;
524
    type RelayChain = RelayChain;
525
    type GetParathreadParams = GetParathreadParamsImpl;
526
    type CheckCollatorValidity = CheckCollatorValidityImpl;
527
    type UnsignedPriority = ParasUnsignedPriority;
528
    type PendingBlocksTtl = PendingBlockTtl;
529
    type CoreBuyingXCMQueryTtl = AdditionalTtlForInflightOrders;
530
    type AdditionalTtlForInflightOrders = AdditionalTtlForInflightOrders;
531
    type BuyCoreSlotDrift = BuyCoreSlotDrift;
532
    type UniversalLocation = UniversalLocation;
533
    type RuntimeOrigin = RuntimeOrigin;
534
    type RuntimeCall = RuntimeCall;
535
    type XCMNotifier = XCMNotifierImpl;
536
    type LatestAuthorInfoFetcher = AuthorNoting;
537
    type SlotBeacon = dp_consensus::AuraDigestSlotBeacon<Runtime>;
538
    type CollatorPublicKey = NimbusId;
539
    type WeightInfo = weights::pallet_xcm_core_buyer::SubstrateWeight<Runtime>;
540
}
541

            
542
pub struct GetParathreadParamsImpl;
543

            
544
impl GetParathreadParams for GetParathreadParamsImpl {
545
16
    fn get_parathread_params(para_id: ParaId) -> Option<ParathreadParams> {
546
16
        Registrar::parathread_params(para_id)
547
16
    }
548

            
549
    #[cfg(feature = "runtime-benchmarks")]
550
    fn set_parathread_params(para_id: ParaId, parathread_params: Option<ParathreadParams>) {
551
        if let Some(parathread_params) = parathread_params {
552
            pallet_registrar::ParathreadParams::<Runtime>::insert(para_id, parathread_params);
553
        } else {
554
            pallet_registrar::ParathreadParams::<Runtime>::remove(para_id);
555
        }
556
    }
557
}
558

            
559
pub struct CheckCollatorValidityImpl;
560

            
561
impl CheckCollatorValidity<AccountId, NimbusId> for CheckCollatorValidityImpl {
562
8
    fn is_valid_collator(para_id: ParaId, public_key: NimbusId) -> bool {
563
8
        let maybe_public_keys = get_para_id_authorities(para_id);
564
8
        maybe_public_keys.is_some_and(|public_keys| public_keys.contains(&public_key))
565
8
    }
566

            
567
    #[cfg(feature = "runtime-benchmarks")]
568
    fn set_valid_collator(para_id: ParaId, account_id: AccountId, public_key: NimbusId) {
569
        let parent_number = System::block_number();
570
        let should_end_session =
571
            <Runtime as pallet_session::Config>::ShouldEndSession::should_end_session(
572
                parent_number + 1,
573
            );
574

            
575
        let session_index = if should_end_session {
576
            Session::current_index() + 1
577
        } else {
578
            Session::current_index()
579
        };
580

            
581
        pallet_authority_mapping::AuthorityIdMapping::<Runtime>::insert(
582
            session_index,
583
            BTreeMap::from_iter([(public_key, account_id.clone())]),
584
        );
585

            
586
        CollatorAssignment::set_authors_for_para_id(para_id, vec![account_id]);
587
    }
588
}
589

            
590
/// Relay chains supported by pallet_xcm_core_buyer, each relay chain has different
591
/// pallet indices for pallet_on_demand_assignment_provider
592
528
#[derive(Debug, Default, Clone, PartialEq, Eq, Encode, Decode, TypeInfo)]
593
pub enum RelayChain {
594
    #[default]
595
    Westend,
596
6
    Rococo,
597
}
598

            
599
pub struct EncodedCallToBuyCore;
600

            
601
impl GetPurchaseCoreCall<RelayChain> for EncodedCallToBuyCore {
602
16
    fn get_encoded(relay_chain: RelayChain, max_amount: u128, para_id: ParaId) -> Vec<u8> {
603
16
        match relay_chain {
604
            RelayChain::Westend => {
605
4
                let call = tanssi_relay_encoder::westend::RelayCall::OnDemandAssignmentProvider(
606
4
                    tanssi_relay_encoder::westend::OnDemandAssignmentProviderCall::PlaceOrderAllowDeath {
607
4
                        max_amount,
608
4
                        para_id,
609
4
                    },
610
4
                );
611
4

            
612
4
                call.encode()
613
            }
614
            RelayChain::Rococo => {
615
12
                let call = tanssi_relay_encoder::rococo::RelayCall::OnDemandAssignmentProvider(
616
12
                    tanssi_relay_encoder::rococo::OnDemandAssignmentProviderCall::PlaceOrderAllowDeath {
617
12
                        max_amount,
618
12
                        para_id,
619
12
                    },
620
12
                );
621
12

            
622
12
                call.encode()
623
            }
624
        }
625
16
    }
626
}
627

            
628
pub struct GetMaxCorePriceFromServicesPayment;
629

            
630
impl GetParathreadMaxCorePrice for GetMaxCorePriceFromServicesPayment {
631
16
    fn get_max_core_price(para_id: ParaId) -> Option<u128> {
632
16
        pallet_services_payment::MaxCorePrice::<Runtime>::get(para_id)
633
16
    }
634
}