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

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

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

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

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

            
89
    pub const MaxAssetsIntoHolding: u32 = 64;
90

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

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

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

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

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

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

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

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

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

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

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

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

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

            
291
parameter_types! {
292
    // we just reuse the same deposits
293
    pub const ForeignAssetsAssetDeposit: Balance = 0;
294
    pub const ForeignAssetsAssetAccountDeposit: Balance = 0;
295
    pub const ForeignAssetsApprovalDeposit: Balance = 0;
296
    pub const ForeignAssetsAssetsStringLimit: u32 = 50;
297
    pub const ForeignAssetsMetadataDepositBase: Balance = 0;
298
    pub const ForeignAssetsMetadataDepositPerByte: Balance = 0;
299
    pub CheckingAccount: AccountId = PolkadotXcm::check_account();
300
}
301

            
302
#[cfg(feature = "runtime-benchmarks")]
303
/// Simple conversion of `u32` into an `AssetId` for use in benchmarking.
304
pub struct ForeignAssetBenchmarkHelper;
305
#[cfg(feature = "runtime-benchmarks")]
306
impl pallet_assets::BenchmarkHelper<AssetId> for ForeignAssetBenchmarkHelper {
307
    fn create_asset_id_parameter(id: u32) -> AssetId {
308
        id.try_into()
309
            .expect("number too large to create benchmarks")
310
    }
311
}
312
#[cfg(feature = "runtime-benchmarks")]
313
impl pallet_asset_rate::AssetKindFactory<AssetId> for ForeignAssetBenchmarkHelper {
314
    fn create_asset_kind(id: u32) -> AssetId {
315
        id.try_into()
316
            .expect("number too large to create benchmarks")
317
    }
318
}
319

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

            
345
impl pallet_foreign_asset_creator::Config for Runtime {
346
    type RuntimeEvent = RuntimeEvent;
347
    type ForeignAsset = Location;
348
    type ForeignAssetCreatorOrigin = EnsureRoot<AccountId>;
349
    type ForeignAssetModifierOrigin = EnsureRoot<AccountId>;
350
    type ForeignAssetDestroyerOrigin = EnsureRoot<AccountId>;
351
    type Fungibles = ForeignAssets;
352
    type WeightInfo = weights::pallet_foreign_asset_creator::SubstrateWeight<Runtime>;
353
    type OnForeignAssetCreated = ();
354
    type OnForeignAssetDestroyed = ();
355
}
356

            
357
impl pallet_asset_rate::Config for Runtime {
358
    type CreateOrigin = EnsureRoot<AccountId>;
359
    type RemoveOrigin = EnsureRoot<AccountId>;
360
    type UpdateOrigin = EnsureRoot<AccountId>;
361
    type Currency = Balances;
362
    type AssetKind = AssetId;
363
    type RuntimeEvent = RuntimeEvent;
364
    type WeightInfo = weights::pallet_asset_rate::SubstrateWeight<Runtime>;
365
    #[cfg(feature = "runtime-benchmarks")]
366
    type BenchmarkHelper = ForeignAssetBenchmarkHelper;
367
}
368

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

            
385
/// Multiplier used for dedicated `TakeFirstAssetTrader` with `ForeignAssets` instance.
386
pub type AssetRateAsMultiplier =
387
    parachains_common::xcm_config::AssetFeeAsExistentialDepositMultiplier<
388
        Runtime,
389
        WeightToFee,
390
        AssetRate,
391
        ForeignAssetsInstance,
392
    >;
393

            
394
// TODO: this should probably move to somewhere in the polkadot-sdk repo
395
pub struct NativeAssetReserve;
396
impl frame_support::traits::ContainsPair<Asset, Location> for NativeAssetReserve {
397
89
    fn contains(asset: &Asset, origin: &Location) -> bool {
398
89
        log::trace!(target: "xcm::contains", "NativeAssetReserve asset: {:?}, origin: {:?}", asset, origin);
399
89
        let reserve = if asset.id.0.parents == 0
400
29
            && !matches!(asset.id.0.first_interior(), Some(Parachain(_)))
401
        {
402
29
            Some(Location::here())
403
        } else {
404
60
            asset.id.0.chain_part()
405
        };
406

            
407
89
        if let Some(ref reserve) = reserve {
408
83
            if reserve == origin {
409
58
                return true;
410
25
            }
411
6
        }
412
31
        false
413
89
    }
414
}
415

            
416
pub trait Parse {
417
    /// Returns the "chain" location part. It could be parent, sibling
418
    /// parachain, or child parachain.
419
    fn chain_part(&self) -> Option<Location>;
420
    /// Returns "non-chain" location part.
421
    fn non_chain_part(&self) -> Option<Location>;
422
}
423

            
424
impl Parse for Location {
425
60
    fn chain_part(&self) -> Option<Location> {
426
60
        match (self.parents, self.first_interior()) {
427
            // sibling parachain
428
15
            (1, Some(Parachain(id))) => Some(Location::new(1, [Parachain(*id)])),
429
            // parent
430
39
            (1, _) => Some(Location::parent()),
431
            // children parachain
432
            (0, Some(Parachain(id))) => Some(Location::new(0, [Parachain(*id)])),
433
6
            _ => None,
434
        }
435
60
    }
436

            
437
    fn non_chain_part(&self) -> Option<Location> {
438
        let mut junctions = self.interior().clone();
439
        while matches!(junctions.first(), Some(Parachain(_))) {
440
            let _ = junctions.take_first();
441
        }
442

            
443
        if junctions != Here {
444
            Some(Location::new(0, junctions))
445
        } else {
446
            None
447
        }
448
    }
449
}
450

            
451
parameter_types! {
452
    pub MessageQueueServiceWeight: Weight = Perbill::from_percent(25) * RuntimeBlockWeights::get().max_block;
453
}
454

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

            
480
parameter_types! {
481
    pub const ParasUnsignedPriority: TransactionPriority = TransactionPriority::MAX;
482
    pub const XcmBuyExecutionDotRococo: u128 = XCM_BUY_EXECUTION_COST_ROCOCO;
483
}
484

            
485
pub const XCM_BUY_EXECUTION_COST_ROCOCO: u128 = 70_000_000 + 126_666_399;
486

            
487
pub struct XCMNotifierImpl;
488

            
489
impl XCMNotifier<Runtime> for XCMNotifierImpl {
490
24
    fn new_notify_query(
491
24
        responder: impl Into<Location>,
492
24
        notify: impl Into<RuntimeCall>,
493
24
        timeout: BlockNumberFor<Runtime>,
494
24
        match_querier: impl Into<Location>,
495
24
    ) -> u64 {
496
24
        pallet_xcm::Pallet::<Runtime>::new_notify_query(responder, notify, timeout, match_querier)
497
24
    }
498
}
499

            
500
parameter_types! {
501
    pub const CoreBuyingXCMQueryTtl: BlockNumber = 100;
502
    pub const AdditionalTtlForInflightOrders: BlockNumber = 5;
503
    pub const PendingBlockTtl: BlockNumber = 10;
504
    pub BuyCoreSlotDrift: Slot = Slot::from(5u64);
505
}
506

            
507
impl pallet_xcm_core_buyer::Config for Runtime {
508
    type RuntimeEvent = RuntimeEvent;
509
    type Currency = Balances;
510

            
511
    type XcmSender = XcmRouter;
512
    type GetPurchaseCoreCall = EncodedCallToBuyCore;
513
    type GetParathreadAccountId = ParaIdIntoAccountTruncating;
514
    type GetParathreadMaxCorePrice = GetMaxCorePriceFromServicesPayment;
515
    type SelfParaId = parachain_info::Pallet<Runtime>;
516
    type RelayChain = RelayChain;
517
    type GetParathreadParams = GetParathreadParamsImpl;
518
    type CheckCollatorValidity = CheckCollatorValidityImpl;
519
    type UnsignedPriority = ParasUnsignedPriority;
520
    type PendingBlocksTtl = PendingBlockTtl;
521
    type CoreBuyingXCMQueryTtl = AdditionalTtlForInflightOrders;
522
    type AdditionalTtlForInflightOrders = AdditionalTtlForInflightOrders;
523
    type BuyCoreSlotDrift = BuyCoreSlotDrift;
524
    type UniversalLocation = UniversalLocation;
525
    type RuntimeOrigin = RuntimeOrigin;
526
    type RuntimeCall = RuntimeCall;
527
    type XCMNotifier = XCMNotifierImpl;
528
    type LatestAuthorInfoFetcher = AuthorNoting;
529
    type SlotBeacon = dp_consensus::AuraDigestSlotBeacon<Runtime>;
530
    type CollatorPublicKey = NimbusId;
531
    type WeightInfo = weights::pallet_xcm_core_buyer::SubstrateWeight<Runtime>;
532
}
533

            
534
pub struct GetParathreadParamsImpl;
535

            
536
impl GetParathreadParams for GetParathreadParamsImpl {
537
24
    fn get_parathread_params(para_id: ParaId) -> Option<ParathreadParams> {
538
24
        Registrar::parathread_params(para_id)
539
24
    }
540

            
541
    #[cfg(feature = "runtime-benchmarks")]
542
    fn set_parathread_params(para_id: ParaId, parathread_params: Option<ParathreadParams>) {
543
        if let Some(parathread_params) = parathread_params {
544
            pallet_registrar::ParathreadParams::<Runtime>::insert(para_id, parathread_params);
545
        } else {
546
            pallet_registrar::ParathreadParams::<Runtime>::remove(para_id);
547
        }
548
    }
549
}
550

            
551
pub struct CheckCollatorValidityImpl;
552

            
553
impl CheckCollatorValidity<AccountId, NimbusId> for CheckCollatorValidityImpl {
554
30
    fn is_valid_collator(para_id: ParaId, public_key: NimbusId) -> bool {
555
30
        let maybe_public_keys = get_para_id_authorities(para_id);
556
30
        maybe_public_keys.is_some_and(|public_keys| public_keys.contains(&public_key))
557
30
    }
558

            
559
    #[cfg(feature = "runtime-benchmarks")]
560
    fn set_valid_collator(para_id: ParaId, account_id: AccountId, public_key: NimbusId) {
561
        let parent_number = System::block_number();
562
        let should_end_session =
563
            <Runtime as pallet_session::Config>::ShouldEndSession::should_end_session(
564
                parent_number + 1,
565
            );
566

            
567
        let session_index = if should_end_session {
568
            Session::current_index() + 1
569
        } else {
570
            Session::current_index()
571
        };
572

            
573
        pallet_authority_mapping::AuthorityIdMapping::<Runtime>::insert(
574
            session_index,
575
            BTreeMap::from_iter([(public_key, account_id.clone())]),
576
        );
577

            
578
        CollatorAssignment::set_authors_for_para_id(para_id, vec![account_id]);
579
    }
580
}
581

            
582
/// Relay chains supported by pallet_xcm_core_buyer, each relay chain has different
583
/// pallet indices for pallet_on_demand_assignment_provider
584
1164
#[derive(Debug, Default, Clone, PartialEq, Eq, Encode, Decode, TypeInfo, MaxEncodedLen)]
585
pub enum RelayChain {
586
    #[default]
587
    Westend,
588
12
    Rococo,
589
}
590

            
591
pub struct EncodedCallToBuyCore;
592

            
593
impl GetPurchaseCoreCall<RelayChain> for EncodedCallToBuyCore {
594
24
    fn get_encoded(relay_chain: RelayChain, max_amount: u128, para_id: ParaId) -> Vec<u8> {
595
24
        match relay_chain {
596
            RelayChain::Westend => {
597
12
                let call = tanssi_relay_encoder::westend::RelayCall::OnDemandAssignmentProvider(
598
12
                    tanssi_relay_encoder::westend::OnDemandAssignmentProviderCall::PlaceOrderAllowDeath {
599
12
                        max_amount,
600
12
                        para_id,
601
12
                    },
602
12
                );
603
12

            
604
12
                call.encode()
605
            }
606
            RelayChain::Rococo => {
607
12
                let call = tanssi_relay_encoder::rococo::RelayCall::OnDemandAssignmentProvider(
608
12
                    tanssi_relay_encoder::rococo::OnDemandAssignmentProviderCall::PlaceOrderAllowDeath {
609
12
                        max_amount,
610
12
                        para_id,
611
12
                    },
612
12
                );
613
12

            
614
12
                call.encode()
615
            }
616
        }
617
24
    }
618
}
619

            
620
pub struct GetMaxCorePriceFromServicesPayment;
621

            
622
impl GetParathreadMaxCorePrice for GetMaxCorePriceFromServicesPayment {
623
24
    fn get_max_core_price(para_id: ParaId) -> Option<u128> {
624
24
        pallet_services_payment::MaxCorePrice::<Runtime>::get(para_id)
625
24
    }
626
}