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_attr(not(feature = "std"), no_std)]
18
// `construct_runtime!` does a lot of recursion and requires us to increase the limit to 256.
19
#![recursion_limit = "256"]
20

            
21
// Make the WASM binary available.
22
#[cfg(feature = "std")]
23
include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs"));
24

            
25
extern crate alloc;
26

            
27
#[cfg(feature = "std")]
28
use sp_version::NativeVersion;
29
use {
30
    frame_support::{
31
        storage::{with_storage_layer, with_transaction},
32
        traits::{ExistenceRequirement, WithdrawReasons},
33
    },
34
    pallet_services_payment::ProvideCollatorAssignmentCost,
35
    polkadot_runtime_common::SlowAdjustingFeeUpdate,
36
};
37

            
38
#[cfg(any(feature = "std", test))]
39
pub use sp_runtime::BuildStorage;
40
use sp_runtime::{DispatchError, TransactionOutcome};
41

            
42
pub mod weights;
43

            
44
#[cfg(test)]
45
mod tests;
46

            
47
use {
48
    cumulus_pallet_parachain_system::RelayNumberMonotonicallyIncreases,
49
    cumulus_primitives_core::{relay_chain::SessionIndex, BodyId, ParaId},
50
    frame_support::{
51
        construct_runtime,
52
        dispatch::{DispatchClass, DispatchErrorWithPostInfo},
53
        genesis_builder_helper::{build_state, get_preset},
54
        pallet_prelude::DispatchResult,
55
        parameter_types,
56
        traits::{
57
            fungible::{Balanced, Credit, Inspect, InspectHold, Mutate, MutateHold},
58
            tokens::{
59
                imbalance::ResolveTo, PayFromAccount, Precision, Preservation,
60
                UnityAssetBalanceConversion,
61
            },
62
            ConstBool, ConstU128, ConstU32, ConstU64, ConstU8, Contains, EitherOfDiverse,
63
            EverythingBut, Imbalance, InsideBoth, InstanceFilter, OnUnbalanced,
64
        },
65
        weights::{
66
            constants::{
67
                BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight,
68
                WEIGHT_REF_TIME_PER_SECOND,
69
            },
70
            ConstantMultiplier, Weight, WeightToFeeCoefficient, WeightToFeeCoefficients,
71
            WeightToFeePolynomial,
72
        },
73
        PalletId,
74
    },
75
    frame_system::{
76
        limits::{BlockLength, BlockWeights},
77
        EnsureNever, EnsureRoot,
78
    },
79
    nimbus_primitives::{NimbusId, SlotBeacon},
80
    pallet_balances::NegativeImbalance,
81
    pallet_invulnerables::InvulnerableRewardDistribution,
82
    pallet_registrar::RegistrarHooks,
83
    pallet_registrar_runtime_api::ContainerChainGenesisData,
84
    pallet_services_payment::{BalanceOf, ProvideBlockProductionCost},
85
    pallet_session::{SessionManager, ShouldEndSession},
86
    pallet_stream_payment_runtime_api::{StreamPaymentApiError, StreamPaymentApiStatus},
87
    pallet_transaction_payment::FungibleAdapter,
88
    polkadot_runtime_common::BlockHashCount,
89
    scale_info::prelude::format,
90
    serde::{Deserialize, Serialize},
91
    smallvec::smallvec,
92
    sp_api::impl_runtime_apis,
93
    sp_consensus_slots::{Slot, SlotDuration},
94
    sp_core::{crypto::KeyTypeId, Get, MaxEncodedLen, OpaqueMetadata, H256},
95
    sp_runtime::{
96
        generic, impl_opaque_keys,
97
        traits::{
98
            AccountIdConversion, AccountIdLookup, BlakeTwo256, Block as BlockT, ConvertInto,
99
            IdentityLookup, Verify,
100
        },
101
        transaction_validity::{TransactionSource, TransactionValidity},
102
        AccountId32, ApplyExtrinsicResult, Cow,
103
    },
104
    sp_std::{
105
        collections::{btree_map::BTreeMap, btree_set::BTreeSet},
106
        marker::PhantomData,
107
        prelude::*,
108
    },
109
    sp_version::RuntimeVersion,
110
    tp_traits::{
111
        apply, derive_storage_traits, GetContainerChainAuthor, GetHostConfiguration,
112
        GetSessionContainerChains, MaybeSelfChainBlockAuthor, ParaIdAssignmentHooks,
113
        RelayStorageRootProvider, RemoveInvulnerables, ShouldRotateAllCollators,
114
    },
115
};
116
pub use {
117
    dp_core::{AccountId, Address, Balance, BlockNumber, Hash, Header, Index, Signature},
118
    sp_runtime::{MultiAddress, Perbill, Permill},
119
};
120

            
121
/// Block type as expected by this runtime.
122
pub type Block = generic::Block<Header, UncheckedExtrinsic>;
123
/// A Block signed with a Justification
124
pub type SignedBlock = generic::SignedBlock<Block>;
125
/// BlockId type as expected by this runtime.
126
pub type BlockId = generic::BlockId<Block>;
127

            
128
/// CollatorId type expected by this runtime.
129
pub type CollatorId = AccountId;
130

            
131
/// The `TxExtension` to the basic transaction logic.
132
pub type TxExtension = (
133
    frame_system::CheckNonZeroSender<Runtime>,
134
    frame_system::CheckSpecVersion<Runtime>,
135
    frame_system::CheckTxVersion<Runtime>,
136
    frame_system::CheckGenesis<Runtime>,
137
    frame_system::CheckEra<Runtime>,
138
    frame_system::CheckNonce<Runtime>,
139
    frame_system::CheckWeight<Runtime>,
140
    pallet_transaction_payment::ChargeTransactionPayment<Runtime>,
141
    cumulus_primitives_storage_weight_reclaim::StorageWeightReclaim<Runtime>,
142
);
143

            
144
/// Unchecked extrinsic type as expected by this runtime.
145
pub type UncheckedExtrinsic =
146
    generic::UncheckedExtrinsic<Address, RuntimeCall, Signature, TxExtension>;
147

            
148
/// Extrinsic type that has already been checked.
149
pub type CheckedExtrinsic = generic::CheckedExtrinsic<AccountId, RuntimeCall, TxExtension>;
150

            
151
/// Executive: handles dispatch to the various modules.
152
pub type Executive = frame_executive::Executive<
153
    Runtime,
154
    Block,
155
    frame_system::ChainContext<Runtime>,
156
    Runtime,
157
    AllPalletsWithSystem,
158
>;
159

            
160
/// DANCE, the native token, uses 12 decimals of precision.
161
pub mod currency {
162
    use super::Balance;
163

            
164
    // Provide a common factor between runtimes based on a supply of 10_000_000 tokens.
165
    pub const SUPPLY_FACTOR: Balance = 100;
166

            
167
    pub const MICRODANCE: Balance = 1_000_000;
168
    pub const MILLIDANCE: Balance = 1_000_000_000;
169
    pub const DANCE: Balance = 1_000_000_000_000;
170
    pub const KILODANCE: Balance = 1_000_000_000_000_000;
171

            
172
    pub const STORAGE_BYTE_FEE: Balance = 100 * MICRODANCE * SUPPLY_FACTOR;
173
    pub const STORAGE_ITEM_FEE: Balance = 100 * MILLIDANCE * SUPPLY_FACTOR;
174

            
175
1
    pub const fn deposit(items: u32, bytes: u32) -> Balance {
176
1
        items as Balance * STORAGE_ITEM_FEE + (bytes as Balance) * STORAGE_BYTE_FEE
177
1
    }
178
}
179

            
180
/// Handles converting a weight scalar to a fee value, based on the scale and granularity of the
181
/// node's balance type.
182
///
183
/// This should typically create a mapping between the following ranges:
184
///   - `[0, MAXIMUM_BLOCK_WEIGHT]`
185
///   - `[Balance::min, Balance::max]`
186
///
187
/// Yet, it can be used for any other sort of change to weight-fee. Some examples being:
188
///   - Setting it to `0` will essentially disable the weight fee.
189
///   - Setting it to `1` will cause the literal `#[weight = x]` values to be charged.
190
pub struct WeightToFee;
191
impl WeightToFeePolynomial for WeightToFee {
192
    type Balance = Balance;
193
    fn polynomial() -> WeightToFeeCoefficients<Self::Balance> {
194
        // in Rococo, extrinsic base weight (smallest non-zero weight) is mapped to 1 MILLIUNIT:
195
        // in our template, we map to 1/10 of that, or 1/10 MILLIUNIT
196
        let p = MILLIUNIT / 10;
197
        let q = 100 * Balance::from(ExtrinsicBaseWeight::get().ref_time());
198
        smallvec![WeightToFeeCoefficient {
199
            degree: 1,
200
            negative: false,
201
            coeff_frac: Perbill::from_rational(p % q, q),
202
            coeff_integer: p / q,
203
        }]
204
    }
205
}
206

            
207
/// Opaque types. These are used by the CLI to instantiate machinery that don't need to know
208
/// the specifics of the runtime. They can then be made to be agnostic over specific formats
209
/// of data like extrinsics, allowing for them to continue syncing the network through upgrades
210
/// to even the core data structures.
211
pub mod opaque {
212
    use {
213
        super::*,
214
        sp_runtime::{generic, traits::BlakeTwo256},
215
    };
216

            
217
    pub use sp_runtime::OpaqueExtrinsic as UncheckedExtrinsic;
218
    /// Opaque block header type.
219
    pub type Header = generic::Header<BlockNumber, BlakeTwo256>;
220
    /// Opaque block type.
221
    pub type Block = generic::Block<Header, UncheckedExtrinsic>;
222
    /// Opaque block identifier type.
223
    pub type BlockId = generic::BlockId<Block>;
224
}
225

            
226
impl_opaque_keys! {
227
    pub struct SessionKeys {
228
        pub nimbus: Initializer,
229
    }
230
}
231

            
232
#[sp_version::runtime_version]
233
pub const VERSION: RuntimeVersion = RuntimeVersion {
234
    spec_name: Cow::Borrowed("flashbox"),
235
    impl_name: Cow::Borrowed("flashbox"),
236
    authoring_version: 1,
237
    spec_version: 1200,
238
    impl_version: 0,
239
    apis: RUNTIME_API_VERSIONS,
240
    transaction_version: 1,
241
    system_version: 1,
242
};
243

            
244
/// This determines the average expected block time that we are targeting.
245
/// Blocks will be produced at a minimum duration defined by `SLOT_DURATION`.
246
/// `SLOT_DURATION` is picked up by `pallet_timestamp` which is in turn picked
247
/// up by `pallet_aura` to implement `fn slot_duration()`.
248
///
249
/// Change this to adjust the block time.
250
pub const MILLISECS_PER_BLOCK: u64 = 6000;
251

            
252
// NOTE: Currently it is not possible to change the slot duration after the chain has started.
253
//       Attempting to do so will brick block production.
254
pub const SLOT_DURATION: u64 = MILLISECS_PER_BLOCK;
255

            
256
// Time is measured by number of blocks.
257
pub const MINUTES: BlockNumber = 60_000 / (MILLISECS_PER_BLOCK as BlockNumber);
258
pub const HOURS: BlockNumber = MINUTES * 60;
259
pub const DAYS: BlockNumber = HOURS * 24;
260

            
261
// Unit = the base number of indivisible units for balances
262
pub const UNIT: Balance = 1_000_000_000_000;
263
pub const MILLIUNIT: Balance = 1_000_000_000;
264
pub const MICROUNIT: Balance = 1_000_000;
265

            
266
/// The existential deposit. Set to 1/10 of the Connected Relay Chain.
267
pub const EXISTENTIAL_DEPOSIT: Balance = MILLIUNIT;
268

            
269
/// We assume that ~5% of the block weight is consumed by `on_initialize` handlers. This is
270
/// used to limit the maximal weight of a single extrinsic.
271
const AVERAGE_ON_INITIALIZE_RATIO: Perbill = Perbill::from_percent(5);
272

            
273
/// We allow `Normal` extrinsics to fill up the block up to 75%, the rest can be used by
274
/// `Operational` extrinsics.
275
const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75);
276

            
277
/// We allow for 2 seconds of compute with a 6 second average block time
278
const MAXIMUM_BLOCK_WEIGHT: Weight = Weight::from_parts(
279
    WEIGHT_REF_TIME_PER_SECOND.saturating_mul(2),
280
    cumulus_primitives_core::relay_chain::MAX_POV_SIZE as u64,
281
);
282

            
283
/// The version information used to identify this runtime when compiled natively.
284
#[cfg(feature = "std")]
285
pub fn native_version() -> NativeVersion {
286
    NativeVersion {
287
        runtime_version: VERSION,
288
        can_author_with: Default::default(),
289
    }
290
}
291

            
292
parameter_types! {
293
    pub const Version: RuntimeVersion = VERSION;
294

            
295
    // This part is copied from Substrate's `bin/node/runtime/src/lib.rs`.
296
    //  The `RuntimeBlockLength` and `RuntimeBlockWeights` exist here because the
297
    // `DeletionWeightLimit` and `DeletionQueueDepth` depend on those to parameterize
298
    // the lazy contract deletion.
299
    pub RuntimeBlockLength: BlockLength =
300
        BlockLength::max_with_normal_ratio(5 * 1024 * 1024, NORMAL_DISPATCH_RATIO);
301
    pub RuntimeBlockWeights: BlockWeights = BlockWeights::builder()
302
        .base_block(BlockExecutionWeight::get())
303
3267
        .for_class(DispatchClass::all(), |weights| {
304
3267
            weights.base_extrinsic = ExtrinsicBaseWeight::get();
305
3267
        })
306
1089
        .for_class(DispatchClass::Normal, |weights| {
307
1089
            weights.max_total = Some(NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT);
308
1089
        })
309
1089
        .for_class(DispatchClass::Operational, |weights| {
310
1089
            weights.max_total = Some(MAXIMUM_BLOCK_WEIGHT);
311
1089
            // Operational transactions have some extra reserved space, so that they
312
1089
            // are included even if block reached `MAXIMUM_BLOCK_WEIGHT`.
313
1089
            weights.reserved = Some(
314
1089
                MAXIMUM_BLOCK_WEIGHT - NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT
315
1089
            );
316
1089
        })
317
        .avg_block_initialization(AVERAGE_ON_INITIALIZE_RATIO)
318
        .build_or_panic();
319
    pub const SS58Prefix: u16 = 42;
320
}
321

            
322
// Configure FRAME pallets to include in runtime.
323

            
324
impl frame_system::Config for Runtime {
325
    /// The identifier used to distinguish between accounts.
326
    type AccountId = AccountId;
327
    /// The aggregated dispatch type that is available for extrinsics.
328
    type RuntimeCall = RuntimeCall;
329
    /// The lookup mechanism to get account ID from whatever is passed in dispatchers.
330
    type Lookup = AccountIdLookup<AccountId, ()>;
331
    /// The index type for storing how many extrinsics an account has signed.
332
    type Nonce = Index;
333
    /// The index type for blocks.
334
    type Block = Block;
335
    /// The type for hashing blocks and tries.
336
    type Hash = Hash;
337
    /// The hashing algorithm used.
338
    type Hashing = BlakeTwo256;
339
    /// The ubiquitous event type.
340
    type RuntimeEvent = RuntimeEvent;
341
    /// The ubiquitous origin type.
342
    type RuntimeOrigin = RuntimeOrigin;
343
    /// Maximum number of block number to block hash mappings to keep (oldest pruned first).
344
    type BlockHashCount = BlockHashCount;
345
    /// Runtime version.
346
    type Version = Version;
347
    /// Converts a module to an index of this module in the runtime.
348
    type PalletInfo = PalletInfo;
349
    /// The data to be stored in an account.
350
    type AccountData = pallet_balances::AccountData<Balance>;
351
    /// What to do if a new account is created.
352
    type OnNewAccount = ();
353
    /// What to do if an account is fully reaped from the system.
354
    type OnKilledAccount = ();
355
    /// The weight of database operations that the runtime can invoke.
356
    type DbWeight = RocksDbWeight;
357
    /// The basic call filter to use in dispatchable.
358
    type BaseCallFilter = InsideBoth<MaintenanceMode, TxPause>;
359
    /// Weight information for the extrinsics of this pallet.
360
    type SystemWeightInfo = weights::frame_system::SubstrateWeight<Runtime>;
361
    /// Block & extrinsics weights: base values and limits.
362
    type BlockWeights = RuntimeBlockWeights;
363
    /// The maximum length of a block (in bytes).
364
    type BlockLength = RuntimeBlockLength;
365
    /// This is used as an identifier of the chain. 42 is the generic substrate prefix.
366
    type SS58Prefix = SS58Prefix;
367
    /// The action to take on a Runtime Upgrade
368
    type OnSetCode = cumulus_pallet_parachain_system::ParachainSetCode<Self>;
369
    type MaxConsumers = frame_support::traits::ConstU32<16>;
370
    type RuntimeTask = RuntimeTask;
371
    type SingleBlockMigrations = ();
372
    type MultiBlockMigrator = MultiBlockMigrations;
373
    type PreInherents = ();
374
    type PostInherents = ();
375
    type PostTransactions = ();
376
    type ExtensionsWeightInfo = ();
377
}
378

            
379
impl pallet_timestamp::Config for Runtime {
380
    /// A timestamp: milliseconds since the unix epoch.
381
    type Moment = u64;
382
    type OnTimestampSet = dp_consensus::OnTimestampSet<
383
        <Self as pallet_author_inherent::Config>::SlotBeacon,
384
        ConstU64<{ SLOT_DURATION }>,
385
    >;
386
    type MinimumPeriod = ConstU64<{ SLOT_DURATION / 2 }>;
387
    type WeightInfo = weights::pallet_timestamp::SubstrateWeight<Runtime>;
388
}
389

            
390
pub struct CanAuthor;
391
impl nimbus_primitives::CanAuthor<NimbusId> for CanAuthor {
392
1054
    fn can_author(author: &NimbusId, slot: &u32) -> bool {
393
1054
        let authorities = AuthorityAssignment::collator_container_chain(Session::current_index())
394
1054
            .expect("authorities should be set")
395
1054
            .orchestrator_chain;
396
1054

            
397
1054
        if authorities.is_empty() {
398
            return false;
399
1054
        }
400
1054

            
401
1054
        let author_index = (*slot as usize) % authorities.len();
402
1054
        let expected_author = &authorities[author_index];
403
1054

            
404
1054
        expected_author == author
405
1054
    }
406
    #[cfg(feature = "runtime-benchmarks")]
407
    fn get_authors(_slot: &u32) -> Vec<NimbusId> {
408
        AuthorityAssignment::collator_container_chain(Session::current_index())
409
            .expect("authorities should be set")
410
            .orchestrator_chain
411
    }
412
}
413

            
414
impl pallet_author_inherent::Config for Runtime {
415
    type AuthorId = NimbusId;
416
    type AccountLookup = dp_consensus::NimbusLookUp;
417
    type CanAuthor = CanAuthor;
418
    type SlotBeacon = dp_consensus::AuraDigestSlotBeacon<Runtime>;
419
    type WeightInfo = weights::pallet_author_inherent::SubstrateWeight<Runtime>;
420
}
421

            
422
parameter_types! {
423
    pub const ExistentialDeposit: Balance = EXISTENTIAL_DEPOSIT;
424
}
425

            
426
impl pallet_balances::Config for Runtime {
427
    type MaxLocks = ConstU32<50>;
428
    /// The type for recording an account's balance.
429
    type Balance = Balance;
430
    /// The ubiquitous event type.
431
    type RuntimeEvent = RuntimeEvent;
432
    type DustRemoval = ();
433
    type ExistentialDeposit = ExistentialDeposit;
434
    type AccountStore = System;
435
    type MaxReserves = ConstU32<50>;
436
    type ReserveIdentifier = [u8; 8];
437
    type FreezeIdentifier = RuntimeFreezeReason;
438
    type MaxFreezes = ConstU32<10>;
439
    type RuntimeHoldReason = RuntimeHoldReason;
440
    type RuntimeFreezeReason = RuntimeFreezeReason;
441
    type DoneSlashHandler = ();
442
    type WeightInfo = weights::pallet_balances::SubstrateWeight<Runtime>;
443
}
444

            
445
pub struct DealWithFees<R>(sp_std::marker::PhantomData<R>);
446
impl<R> OnUnbalanced<Credit<R::AccountId, pallet_balances::Pallet<R>>> for DealWithFees<R>
447
where
448
    R: pallet_balances::Config + pallet_treasury::Config + frame_system::Config,
449
    pallet_treasury::NegativeImbalanceOf<R>: From<NegativeImbalance<R>>,
450
{
451
    // this seems to be called for substrate-based transactions
452
    fn on_unbalanceds(
453
        mut fees_then_tips: impl Iterator<Item = Credit<R::AccountId, pallet_balances::Pallet<R>>>,
454
    ) {
455
        if let Some(fees) = fees_then_tips.next() {
456
            // 80% is burned, 20% goes to the treasury
457
            // Same policy applies for tips as well
458
            let burn_percentage = 80;
459
            let treasury_percentage = 20;
460

            
461
            let (_, to_treasury) = fees.ration(burn_percentage, treasury_percentage);
462
            ResolveTo::<pallet_treasury::TreasuryAccountId<R>, pallet_balances::Pallet<R>>::on_unbalanced(to_treasury);
463
            // Balances pallet automatically burns dropped Negative Imbalances by decreasing total_supply accordingly
464
            // We need to convert the new Credit type to a negative imbalance
465
            // handle tip if there is one
466
            if let Some(tip) = fees_then_tips.next() {
467
                let (_, to_treasury) = tip.ration(burn_percentage, treasury_percentage);
468
                ResolveTo::<pallet_treasury::TreasuryAccountId<R>, pallet_balances::Pallet<R>>::on_unbalanced(to_treasury);
469
            }
470
        }
471
    }
472

            
473
    // this is called from pallet_evm for Ethereum-based transactions
474
    // (technically, it calls on_unbalanced, which calls this when non-zero)
475
    fn on_nonzero_unbalanced(amount: Credit<R::AccountId, pallet_balances::Pallet<R>>) {
476
        // 80% is burned, 20% goes to the treasury
477
        let burn_percentage = 80;
478
        let treasury_percentage = 20;
479

            
480
        let (_, to_treasury) = amount.ration(burn_percentage, treasury_percentage);
481
        ResolveTo::<pallet_treasury::TreasuryAccountId<R>, pallet_balances::Pallet<R>>::on_unbalanced(to_treasury);
482
    }
483
}
484

            
485
parameter_types! {
486
    pub const TransactionByteFee: Balance = 1;
487
}
488

            
489
impl pallet_transaction_payment::Config for Runtime {
490
    type RuntimeEvent = RuntimeEvent;
491
    // This will burn the fees
492
    type OnChargeTransaction = FungibleAdapter<Balances, DealWithFees<Runtime>>;
493
    type OperationalFeeMultiplier = ConstU8<5>;
494
    type WeightToFee = WeightToFee;
495
    type LengthToFee = ConstantMultiplier<Balance, TransactionByteFee>;
496
    type FeeMultiplierUpdate = SlowAdjustingFeeUpdate<Self>;
497
    type WeightInfo = ();
498
}
499

            
500
pub const RELAY_CHAIN_SLOT_DURATION_MILLIS: u32 = 6000;
501
pub const UNINCLUDED_SEGMENT_CAPACITY: u32 = 3;
502
pub const BLOCK_PROCESSING_VELOCITY: u32 = 1;
503

            
504
type ConsensusHook = pallet_async_backing::consensus_hook::FixedVelocityConsensusHook<
505
    Runtime,
506
    BLOCK_PROCESSING_VELOCITY,
507
    UNINCLUDED_SEGMENT_CAPACITY,
508
>;
509

            
510
impl cumulus_pallet_parachain_system::Config for Runtime {
511
    type WeightInfo = weights::cumulus_pallet_parachain_system::SubstrateWeight<Runtime>;
512
    type RuntimeEvent = RuntimeEvent;
513
    type OnSystemEvent = ();
514
    type SelfParaId = parachain_info::Pallet<Runtime>;
515
    type OutboundXcmpMessageSource = ();
516
    // Ignore all DMP messages by enqueueing them into `()`:
517
    type DmpQueue = frame_support::traits::EnqueueWithOrigin<(), sp_core::ConstU8<0>>;
518
    type ReservedDmpWeight = ();
519
    type XcmpMessageHandler = ();
520
    type ReservedXcmpWeight = ();
521
    type CheckAssociatedRelayNumber = RelayNumberMonotonicallyIncreases;
522
    type ConsensusHook = ConsensusHook;
523
    type SelectCore = cumulus_pallet_parachain_system::DefaultCoreSelector<Runtime>;
524
}
525

            
526
pub struct ParaSlotProvider;
527
impl Get<(Slot, SlotDuration)> for ParaSlotProvider {
528
68
    fn get() -> (Slot, SlotDuration) {
529
68
        let slot = u64::from(<Runtime as pallet_author_inherent::Config>::SlotBeacon::slot());
530
68
        (Slot::from(slot), SlotDuration::from_millis(SLOT_DURATION))
531
68
    }
532
}
533

            
534
parameter_types! {
535
    pub const ExpectedBlockTime: u64 = MILLISECS_PER_BLOCK;
536
}
537

            
538
impl pallet_async_backing::Config for Runtime {
539
    type AllowMultipleBlocksPerSlot = ConstBool<true>;
540
    type GetAndVerifySlot =
541
        pallet_async_backing::ParaSlot<RELAY_CHAIN_SLOT_DURATION_MILLIS, ParaSlotProvider>;
542
    type ExpectedBlockTime = ExpectedBlockTime;
543
}
544

            
545
pub struct OwnApplySession;
546
impl pallet_initializer::ApplyNewSession<Runtime> for OwnApplySession {
547
164
    fn apply_new_session(
548
164
        _changed: bool,
549
164
        session_index: u32,
550
164
        all_validators: Vec<(AccountId, NimbusId)>,
551
164
        queued: Vec<(AccountId, NimbusId)>,
552
164
    ) {
553
164
        // We first initialize Configuration
554
164
        Configuration::initializer_on_new_session(&session_index);
555
164
        // Next: Registrar
556
164
        Registrar::initializer_on_new_session(&session_index);
557
164
        // Next: AuthorityMapping
558
164
        AuthorityMapping::initializer_on_new_session(&session_index, &all_validators);
559
164

            
560
537
        let next_collators = queued.iter().map(|(k, _)| k.clone()).collect();
561
164

            
562
164
        // Next: CollatorAssignment
563
164
        let assignments =
564
164
            CollatorAssignment::initializer_on_new_session(&session_index, next_collators);
565
164

            
566
164
        let queued_id_to_nimbus_map = queued.iter().cloned().collect();
567
164
        AuthorityAssignment::initializer_on_new_session(
568
164
            &session_index,
569
164
            &queued_id_to_nimbus_map,
570
164
            &assignments.next_assignment,
571
164
        );
572
164
    }
573
}
574

            
575
impl pallet_initializer::Config for Runtime {
576
    type SessionIndex = u32;
577

            
578
    /// The identifier type for an authority.
579
    type AuthorityId = NimbusId;
580

            
581
    type SessionHandler = OwnApplySession;
582
}
583

            
584
impl parachain_info::Config for Runtime {}
585

            
586
pub struct CollatorsFromInvulnerables;
587

            
588
/// Play the role of the session manager.
589
impl SessionManager<CollatorId> for CollatorsFromInvulnerables {
590
233
    fn new_session(index: SessionIndex) -> Option<Vec<CollatorId>> {
591
233
        log::info!(
592
            "assembling new collators for new session {} at #{:?}",
593
            index,
594
            <frame_system::Pallet<Runtime>>::block_number(),
595
        );
596

            
597
233
        let invulnerables = Invulnerables::invulnerables().to_vec();
598
233
        let target_session_index = index.saturating_add(1);
599
233
        let max_collators =
600
233
            <Configuration as GetHostConfiguration<u32>>::max_collators(target_session_index);
601
233
        let collators = invulnerables
602
233
            .iter()
603
233
            .take(max_collators as usize)
604
233
            .cloned()
605
233
            .collect();
606
233

            
607
233
        Some(collators)
608
233
    }
609
164
    fn start_session(_: SessionIndex) {
610
164
        // we don't care.
611
164
    }
612
95
    fn end_session(_: SessionIndex) {
613
95
        // we don't care.
614
95
    }
615
}
616

            
617
parameter_types! {
618
    pub const Period: u32 = prod_or_fast!(5 * MINUTES, 1 * MINUTES);
619
    pub const Offset: u32 = 0;
620
}
621

            
622
impl pallet_session::Config for Runtime {
623
    type RuntimeEvent = RuntimeEvent;
624
    type ValidatorId = <Self as frame_system::Config>::AccountId;
625
    // we don't have stash and controller, thus we don't need the convert as well.
626
    type ValidatorIdOf = ConvertInto;
627
    type ShouldEndSession = pallet_session::PeriodicSessions<Period, Offset>;
628
    type NextSessionRotation = pallet_session::PeriodicSessions<Period, Offset>;
629
    type SessionManager = CollatorsFromInvulnerables;
630
    // Essentially just Aura, but let's be pedantic.
631
    type SessionHandler = <SessionKeys as sp_runtime::traits::OpaqueKeys>::KeyTypeIdProviders;
632
    type Keys = SessionKeys;
633
    type WeightInfo = weights::pallet_session::SubstrateWeight<Runtime>;
634
}
635

            
636
pub struct RemoveInvulnerablesImpl;
637

            
638
impl RemoveInvulnerables<CollatorId> for RemoveInvulnerablesImpl {
639
249
    fn remove_invulnerables(
640
249
        collators: &mut Vec<CollatorId>,
641
249
        num_invulnerables: usize,
642
249
    ) -> Vec<CollatorId> {
643
249
        if num_invulnerables == 0 {
644
            return vec![];
645
249
        }
646
249
        // TODO: check if this works on session changes
647
249
        let all_invulnerables = pallet_invulnerables::Invulnerables::<Runtime>::get();
648
249
        if all_invulnerables.is_empty() {
649
            return vec![];
650
249
        }
651
249
        let mut invulnerables = vec![];
652
249
        // TODO: use binary_search when invulnerables are sorted
653
393
        collators.retain(|x| {
654
393
            if invulnerables.len() < num_invulnerables && all_invulnerables.contains(x) {
655
313
                invulnerables.push(x.clone());
656
313
                false
657
            } else {
658
80
                true
659
            }
660
393
        });
661
249

            
662
249
        invulnerables
663
249
    }
664
}
665

            
666
pub struct ParaIdAssignmentHooksImpl;
667

            
668
impl ParaIdAssignmentHooksImpl {
669
251
    fn charge_para_ids_internal(
670
251
        blocks_per_session: tp_traits::BlockNumber,
671
251
        para_id: ParaId,
672
251
        currently_assigned: &BTreeSet<ParaId>,
673
251
        maybe_tip: &Option<BalanceOf<Runtime>>,
674
251
    ) -> Result<Weight, DispatchError> {
675
        use frame_support::traits::Currency;
676
        type ServicePaymentCurrency = <Runtime as pallet_services_payment::Config>::Currency;
677

            
678
        // Check if the container chain has enough credits for a session assignments
679
244
        let maybe_assignment_imbalance =
680
251
            if  pallet_services_payment::Pallet::<Runtime>::burn_collator_assignment_free_credit_for_para(&para_id).is_err() {
681
15
                let (amount_to_charge, _weight) =
682
15
                    <Runtime as pallet_services_payment::Config>::ProvideCollatorAssignmentCost::collator_assignment_cost(&para_id);
683
15
                Some(<ServicePaymentCurrency as Currency<AccountId>>::withdraw(
684
15
                    &pallet_services_payment::Pallet::<Runtime>::parachain_tank(para_id),
685
15
                    amount_to_charge,
686
15
                    WithdrawReasons::FEE,
687
15
                    ExistenceRequirement::KeepAlive,
688
15
                )?)
689
            } else {
690
236
                None
691
            };
692

            
693
244
        if let Some(tip) = maybe_tip {
694
196
            if let Err(e) = pallet_services_payment::Pallet::<Runtime>::charge_tip(&para_id, tip) {
695
                // Return assignment imbalance to tank on error
696
1
                if let Some(assignment_imbalance) = maybe_assignment_imbalance {
697
                    <Runtime as pallet_services_payment::Config>::Currency::resolve_creating(
698
                        &pallet_services_payment::Pallet::<Runtime>::parachain_tank(para_id),
699
                        assignment_imbalance,
700
                    );
701
1
                }
702
1
                return Err(e);
703
195
            }
704
48
        }
705

            
706
243
        if let Some(assignment_imbalance) = maybe_assignment_imbalance {
707
8
            <Runtime as pallet_services_payment::Config>::OnChargeForCollatorAssignment::on_unbalanced(assignment_imbalance);
708
235
        }
709

            
710
        // If the para has been assigned collators for this session it must have enough block credits
711
        // for the current and the next session.
712
243
        let block_credits_needed = if currently_assigned.contains(&para_id) {
713
129
            blocks_per_session * 2
714
        } else {
715
114
            blocks_per_session
716
        };
717
        // Check if the container chain has enough credits for producing blocks
718
243
        let free_block_credits =
719
243
            pallet_services_payment::BlockProductionCredits::<Runtime>::get(para_id)
720
243
                .unwrap_or_default();
721
243
        let remaining_block_credits = block_credits_needed.saturating_sub(free_block_credits);
722
243
        let (block_production_costs, _) =
723
243
            <Runtime as pallet_services_payment::Config>::ProvideBlockProductionCost::block_cost(
724
243
                &para_id,
725
243
            );
726
243
        // Check if we can withdraw
727
243
        let remaining_block_credits_to_pay =
728
243
            u128::from(remaining_block_credits).saturating_mul(block_production_costs);
729
243
        let remaining_to_pay = remaining_block_credits_to_pay;
730
243
        // This should take into account whether we tank goes below ED
731
243
        // The true refers to keepAlive
732
243
        Balances::can_withdraw(
733
243
            &pallet_services_payment::Pallet::<Runtime>::parachain_tank(para_id),
734
243
            remaining_to_pay,
735
243
        )
736
243
        .into_result(true)?;
737
        // TODO: Have proper weight
738
229
        Ok(Weight::zero())
739
251
    }
740
}
741

            
742
impl<AC> ParaIdAssignmentHooks<BalanceOf<Runtime>, AC> for ParaIdAssignmentHooksImpl {
743
328
    fn pre_assignment(para_ids: &mut Vec<ParaId>, currently_assigned: &BTreeSet<ParaId>) {
744
328
        let blocks_per_session = Period::get();
745
328
        para_ids.retain(|para_id| {
746
192
            with_transaction(|| {
747
192
                let max_tip =
748
192
                    pallet_services_payment::MaxTip::<Runtime>::get(para_id).unwrap_or_default();
749
192
                TransactionOutcome::Rollback(Self::charge_para_ids_internal(
750
192
                    blocks_per_session,
751
192
                    *para_id,
752
192
                    currently_assigned,
753
192
                    &Some(max_tip),
754
192
                ))
755
192
            })
756
192
            .is_ok()
757
328
        });
758
328
    }
759

            
760
164
    fn post_assignment(
761
164
        current_assigned: &BTreeSet<ParaId>,
762
164
        new_assigned: &mut BTreeMap<ParaId, Vec<AC>>,
763
164
        maybe_tip: &Option<BalanceOf<Runtime>>,
764
164
    ) -> Weight {
765
164
        let blocks_per_session = Period::get();
766
164
        let mut total_weight = Weight::zero();
767
170
        new_assigned.retain(|&para_id, collators| {
768
170
            // Short-circuit in case collators are empty
769
170
            if collators.is_empty() {
770
111
                return true;
771
59
            }
772
59
            with_storage_layer(|| {
773
59
                Self::charge_para_ids_internal(
774
59
                    blocks_per_session,
775
59
                    para_id,
776
59
                    current_assigned,
777
59
                    maybe_tip,
778
59
                )
779
59
            })
780
59
            .inspect(|weight| {
781
59
                total_weight += *weight;
782
59
            })
783
59
            .is_ok()
784
170
        });
785
164
        total_weight
786
164
    }
787

            
788
    /// Make those para ids valid by giving them enough credits, for benchmarking.
789
    #[cfg(feature = "runtime-benchmarks")]
790
    fn make_valid_para_ids(para_ids: &[ParaId]) {
791
        use frame_support::assert_ok;
792

            
793
        let blocks_per_session = Period::get();
794
        // Enough credits to run any benchmark
795
        let block_credits = 20 * blocks_per_session;
796
        let session_credits = 20;
797

            
798
        for para_id in para_ids {
799
            assert_ok!(ServicesPayment::set_block_production_credits(
800
                RuntimeOrigin::root(),
801
                *para_id,
802
                block_credits,
803
            ));
804
            assert_ok!(ServicesPayment::set_collator_assignment_credits(
805
                RuntimeOrigin::root(),
806
                *para_id,
807
                session_credits,
808
            ));
809
        }
810
    }
811
}
812

            
813
pub struct NeverRotateCollators;
814

            
815
impl ShouldRotateAllCollators<u32> for NeverRotateCollators {
816
164
    fn should_rotate_all_collators(_: u32) -> bool {
817
164
        false
818
164
    }
819
}
820

            
821
impl pallet_collator_assignment::Config for Runtime {
822
    type RuntimeEvent = RuntimeEvent;
823
    type HostConfiguration = Configuration;
824
    type ContainerChains = Registrar;
825
    type SessionIndex = u32;
826
    type SelfParaId = ParachainInfo;
827
    type ShouldRotateAllCollators = NeverRotateCollators;
828
    type GetRandomnessForNextBlock = ();
829
    type RemoveInvulnerables = RemoveInvulnerablesImpl;
830
    type ParaIdAssignmentHooks = ParaIdAssignmentHooksImpl;
831
    type CollatorAssignmentTip = ServicesPayment;
832
    type Currency = Balances;
833
    type ForceEmptyOrchestrator = ConstBool<false>;
834
    type CoreAllocationConfiguration = ();
835
    type WeightInfo = weights::pallet_collator_assignment::SubstrateWeight<Runtime>;
836
}
837

            
838
impl pallet_authority_assignment::Config for Runtime {
839
    type SessionIndex = u32;
840
    type AuthorityId = NimbusId;
841
}
842

            
843
pub const FIXED_BLOCK_PRODUCTION_COST: u128 = 1 * currency::MICRODANCE;
844
pub const FIXED_COLLATOR_ASSIGNMENT_COST: u128 = 100 * currency::MICRODANCE;
845

            
846
pub struct BlockProductionCost<Runtime>(PhantomData<Runtime>);
847
impl ProvideBlockProductionCost<Runtime> for BlockProductionCost<Runtime> {
848
261
    fn block_cost(_para_id: &ParaId) -> (u128, Weight) {
849
261
        (FIXED_BLOCK_PRODUCTION_COST, Weight::zero())
850
261
    }
851
}
852

            
853
pub struct CollatorAssignmentCost<Runtime>(PhantomData<Runtime>);
854
impl ProvideCollatorAssignmentCost<Runtime> for CollatorAssignmentCost<Runtime> {
855
19
    fn collator_assignment_cost(_para_id: &ParaId) -> (u128, Weight) {
856
19
        (FIXED_COLLATOR_ASSIGNMENT_COST, Weight::zero())
857
19
    }
858
}
859

            
860
parameter_types! {
861
    // 60 days worth of blocks
862
    pub const FreeBlockProductionCredits: BlockNumber = 60 * DAYS;
863
    // 60 days worth of blocks
864
    pub const FreeCollatorAssignmentCredits: u32 = FreeBlockProductionCredits::get()/Period::get();
865
}
866

            
867
impl pallet_services_payment::Config for Runtime {
868
    type RuntimeEvent = RuntimeEvent;
869
    /// Handler for fees
870
    type OnChargeForBlock = ();
871
    type OnChargeForCollatorAssignment = ();
872
    type OnChargeForCollatorAssignmentTip = ();
873
    /// Currency type for fee payment
874
    type Currency = Balances;
875
    /// Provider of a block cost which can adjust from block to block
876
    type ProvideBlockProductionCost = BlockProductionCost<Runtime>;
877
    /// Provider of a block cost which can adjust from block to block
878
    type ProvideCollatorAssignmentCost = CollatorAssignmentCost<Runtime>;
879
    /// The maximum number of block credits that can be accumulated
880
    type FreeBlockProductionCredits = FreeBlockProductionCredits;
881
    /// The maximum number of session credits that can be accumulated
882
    type FreeCollatorAssignmentCredits = FreeCollatorAssignmentCredits;
883
    type ManagerOrigin =
884
        EitherOfDiverse<pallet_registrar::EnsureSignedByManager<Runtime>, EnsureRoot<AccountId>>;
885
    type WeightInfo = weights::pallet_services_payment::SubstrateWeight<Runtime>;
886
}
887

            
888
parameter_types! {
889
    pub const ProfileDepositBaseFee: Balance = currency::STORAGE_ITEM_FEE;
890
    pub const ProfileDepositByteFee: Balance = currency::STORAGE_BYTE_FEE;
891
    #[derive(Clone)]
892
    pub const MaxAssignmentsPerParaId: u32 = 10;
893
    #[derive(Clone)]
894
    pub const MaxNodeUrlLen: u32 = 200;
895
}
896

            
897
#[apply(derive_storage_traits)]
898
#[derive(Copy, Serialize, Deserialize, MaxEncodedLen)]
899
pub enum PreserversAssignementPaymentRequest {
900
49
    Free,
901
    StreamPayment {
902
        config: pallet_stream_payment::StreamConfigOf<Runtime>,
903
    },
904
}
905

            
906
#[apply(derive_storage_traits)]
907
#[derive(Copy, Serialize, Deserialize)]
908
pub enum PreserversAssignementPaymentExtra {
909
    Free,
910
    StreamPayment { initial_deposit: Balance },
911
}
912

            
913
#[apply(derive_storage_traits)]
914
#[derive(Copy, Serialize, Deserialize, MaxEncodedLen)]
915
pub enum PreserversAssignementPaymentWitness {
916
24
    Free,
917
    StreamPayment {
918
        stream_id: <Runtime as pallet_stream_payment::Config>::StreamId,
919
    },
920
}
921

            
922
pub struct PreserversAssignementPayment;
923

            
924
impl pallet_data_preservers::AssignmentPayment<AccountId> for PreserversAssignementPayment {
925
    /// Providers requests which kind of payment it accepts.
926
    type ProviderRequest = PreserversAssignementPaymentRequest;
927
    /// Extra parameter the assigner provides.
928
    type AssignerParameter = PreserversAssignementPaymentExtra;
929
    /// Represents the succesful outcome of the assignment.
930
    type AssignmentWitness = PreserversAssignementPaymentWitness;
931

            
932
21
    fn try_start_assignment(
933
21
        assigner: AccountId,
934
21
        provider: AccountId,
935
21
        request: &Self::ProviderRequest,
936
21
        extra: Self::AssignerParameter,
937
21
    ) -> Result<Self::AssignmentWitness, DispatchErrorWithPostInfo> {
938
21
        let witness = match (request, extra) {
939
21
            (Self::ProviderRequest::Free, Self::AssignerParameter::Free) => {
940
21
                Self::AssignmentWitness::Free
941
            }
942
            (
943
                Self::ProviderRequest::StreamPayment { config },
944
                Self::AssignerParameter::StreamPayment { initial_deposit },
945
            ) => {
946
                let stream_id = StreamPayment::open_stream_returns_id(
947
                    assigner,
948
                    provider,
949
                    *config,
950
                    initial_deposit,
951
                )?;
952

            
953
                Self::AssignmentWitness::StreamPayment { stream_id }
954
            }
955
            _ => Err(
956
                pallet_data_preservers::Error::<Runtime>::AssignmentPaymentRequestParameterMismatch,
957
            )?,
958
        };
959

            
960
21
        Ok(witness)
961
21
    }
962

            
963
    fn try_stop_assignment(
964
        provider: AccountId,
965
        witness: Self::AssignmentWitness,
966
    ) -> Result<(), DispatchErrorWithPostInfo> {
967
        match witness {
968
            Self::AssignmentWitness::Free => (),
969
            Self::AssignmentWitness::StreamPayment { stream_id } => {
970
                StreamPayment::close_stream(RuntimeOrigin::signed(provider), stream_id)?;
971
            }
972
        }
973

            
974
        Ok(())
975
    }
976

            
977
    /// Return the values for a free assignment if it is supported.
978
    /// This is required to perform automatic migration from old Bootnodes storage.
979
1
    fn free_variant_values() -> Option<(
980
1
        Self::ProviderRequest,
981
1
        Self::AssignerParameter,
982
1
        Self::AssignmentWitness,
983
1
    )> {
984
1
        Some((
985
1
            Self::ProviderRequest::Free,
986
1
            Self::AssignerParameter::Free,
987
1
            Self::AssignmentWitness::Free,
988
1
        ))
989
1
    }
990

            
991
    // The values returned by the following functions should match with each other.
992
    #[cfg(feature = "runtime-benchmarks")]
993
    fn benchmark_provider_request() -> Self::ProviderRequest {
994
        PreserversAssignementPaymentRequest::Free
995
    }
996

            
997
    #[cfg(feature = "runtime-benchmarks")]
998
    fn benchmark_assigner_parameter() -> Self::AssignerParameter {
999
        PreserversAssignementPaymentExtra::Free
    }
    #[cfg(feature = "runtime-benchmarks")]
    fn benchmark_assignment_witness() -> Self::AssignmentWitness {
        PreserversAssignementPaymentWitness::Free
    }
}
pub type DataPreserversProfileId = u64;
impl pallet_data_preservers::Config for Runtime {
    type RuntimeEvent = RuntimeEvent;
    type RuntimeHoldReason = RuntimeHoldReason;
    type Currency = Balances;
    type WeightInfo = weights::pallet_data_preservers::SubstrateWeight<Runtime>;
    type ProfileId = DataPreserversProfileId;
    type ProfileDeposit = tp_traits::BytesDeposit<ProfileDepositBaseFee, ProfileDepositByteFee>;
    type AssignmentPayment = PreserversAssignementPayment;
    type AssignmentOrigin = pallet_registrar::EnsureSignedByManager<Runtime>;
    type ForceSetProfileOrigin = EnsureRoot<AccountId>;
    type MaxAssignmentsPerParaId = MaxAssignmentsPerParaId;
    type MaxNodeUrlLen = MaxNodeUrlLen;
    type MaxParaIdsVecLen = MaxLengthParaIds;
}
impl pallet_author_noting::Config for Runtime {
    type RuntimeEvent = RuntimeEvent;
    type ContainerChains = CollatorAssignment;
    type SlotBeacon = dp_consensus::AuraDigestSlotBeacon<Runtime>;
    type ContainerChainAuthor = CollatorAssignment;
    type AuthorNotingHook = (InflationRewards, ServicesPayment);
    type RelayOrPara = pallet_author_noting::ParaMode<
        cumulus_pallet_parachain_system::RelaychainDataProvider<Self>,
    >;
    type MaxContainerChains = MaxLengthParaIds;
    type WeightInfo = weights::pallet_author_noting::SubstrateWeight<Runtime>;
}
parameter_types! {
    pub const PotId: PalletId = PalletId(*b"PotStake");
    pub const MaxCandidates: u32 = 1000;
    pub const MinCandidates: u32 = 5;
    pub const SessionLength: BlockNumber = 5;
    pub const MaxInvulnerables: u32 = 200;
    pub const ExecutiveBody: BodyId = BodyId::Executive;
}
impl pallet_invulnerables::Config for Runtime {
    type RuntimeEvent = RuntimeEvent;
    type UpdateOrigin = EnsureRoot<AccountId>;
    type MaxInvulnerables = MaxInvulnerables;
    type CollatorId = CollatorId;
    type CollatorIdOf = ConvertInto;
    type CollatorRegistration = Session;
    type WeightInfo = weights::pallet_invulnerables::SubstrateWeight<Runtime>;
    #[cfg(feature = "runtime-benchmarks")]
    type Currency = Balances;
}
parameter_types! {
    #[derive(Clone)]
    pub const MaxLengthParaIds: u32 = 200u32;
    pub const MaxEncodedGenesisDataSize: u32 = 5_000_000u32; // 5MB
}
pub struct CurrentSessionIndexGetter;
impl tp_traits::GetSessionIndex<u32> for CurrentSessionIndexGetter {
    /// Returns current session index.
40
    fn session_index() -> u32 {
40
        Session::current_index()
40
    }
}
impl pallet_configuration::Config for Runtime {
    type SessionDelay = ConstU32<2>;
    type SessionIndex = u32;
    type CurrentSessionIndex = CurrentSessionIndexGetter;
    type ForceEmptyOrchestrator = ConstBool<false>;
    type WeightInfo = weights::pallet_configuration::SubstrateWeight<Runtime>;
}
pub struct FlashboxRegistrarHooks;
impl RegistrarHooks for FlashboxRegistrarHooks {
20
    fn para_marked_valid_for_collating(para_id: ParaId) -> Weight {
20
        // Give free credits but only once per para id
20
        ServicesPayment::give_free_credits(&para_id)
20
    }
6
    fn para_deregistered(para_id: ParaId) -> Weight {
        // Clear pallet_author_noting storage
6
        if let Err(e) = AuthorNoting::kill_author_data(RuntimeOrigin::root(), para_id) {
            log::warn!(
                "Failed to kill_author_data after para id {} deregistered: {:?}",
                u32::from(para_id),
                e,
            );
6
        }
        // Remove bootnodes from pallet_data_preservers
6
        DataPreservers::para_deregistered(para_id);
6

            
6
        ServicesPayment::para_deregistered(para_id);
6

            
6
        Weight::default()
6
    }
21
    fn check_valid_for_collating(para_id: ParaId) -> DispatchResult {
21
        // To be able to call mark_valid_for_collating, a container chain must have bootnodes
21
        DataPreservers::check_valid_for_collating(para_id)
21
    }
    #[cfg(feature = "runtime-benchmarks")]
    fn benchmarks_ensure_valid_for_collating(para_id: ParaId) {
        use {
            frame_support::traits::EnsureOriginWithArg,
            pallet_data_preservers::{ParaIdsFilter, Profile, ProfileMode},
        };
        let profile = Profile {
            url: b"/ip4/127.0.0.1/tcp/33049/ws/p2p/12D3KooWHVMhQDHBpj9vQmssgyfspYecgV6e3hH1dQVDUkUbCYC9"
                    .to_vec()
                    .try_into()
                    .expect("to fit in BoundedVec"),
            para_ids: ParaIdsFilter::AnyParaId,
            mode: ProfileMode::Bootnode,
            assignment_request: PreserversAssignementPaymentRequest::Free,
        };
        let profile_id = pallet_data_preservers::NextProfileId::<Runtime>::get();
        let profile_owner = AccountId::new([1u8; 32]);
        DataPreservers::force_create_profile(RuntimeOrigin::root(), profile, profile_owner)
            .expect("profile create to succeed");
        let para_manager =
            <Runtime as pallet_data_preservers::Config>::AssignmentOrigin::try_successful_origin(
                &para_id,
            )
            .expect("should be able to get para manager");
        DataPreservers::start_assignment(
            para_manager,
            profile_id,
            para_id,
            PreserversAssignementPaymentExtra::Free,
        )
        .expect("assignement to work");
        assert!(
            pallet_data_preservers::Assignments::<Runtime>::get(para_id).contains(&profile_id),
            "profile should be correctly assigned"
        );
    }
}
pub struct PalletRelayStorageRootProvider;
impl RelayStorageRootProvider for PalletRelayStorageRootProvider {
    fn get_relay_storage_root(relay_block_number: u32) -> Option<H256> {
        pallet_relay_storage_roots::pallet::RelayStorageRoot::<Runtime>::get(relay_block_number)
    }
    #[cfg(feature = "runtime-benchmarks")]
    fn set_relay_storage_root(relay_block_number: u32, storage_root: Option<H256>) {
        pallet_relay_storage_roots::pallet::RelayStorageRootKeys::<Runtime>::mutate(|x| {
            if storage_root.is_some() {
                if x.is_full() {
                    let key = x.remove(0);
                    pallet_relay_storage_roots::pallet::RelayStorageRoot::<Runtime>::remove(key);
                }
                let pos = x.iter().position(|x| *x >= relay_block_number);
                if let Some(pos) = pos {
                    if x[pos] != relay_block_number {
                        x.try_insert(pos, relay_block_number).unwrap();
                    }
                } else {
                    // Push at end
                    x.try_push(relay_block_number).unwrap();
                }
            } else {
                let pos = x.iter().position(|x| *x == relay_block_number);
                if let Some(pos) = pos {
                    x.remove(pos);
                }
            }
        });
        pallet_relay_storage_roots::pallet::RelayStorageRoot::<Runtime>::set(
            relay_block_number,
            storage_root,
        );
    }
}
parameter_types! {
    pub const DepositAmount: Balance = 100 * UNIT;
}
impl pallet_registrar::Config for Runtime {
    type RuntimeEvent = RuntimeEvent;
    type RegistrarOrigin = EnsureRoot<AccountId>;
    type MarkValidForCollatingOrigin = EnsureRoot<AccountId>;
    type MaxLengthParaIds = MaxLengthParaIds;
    type MaxGenesisDataSize = MaxEncodedGenesisDataSize;
    type RegisterWithRelayProofOrigin = EnsureNever<AccountId>;
    type RelayStorageRootProvider = PalletRelayStorageRootProvider;
    type SessionDelay = ConstU32<2>;
    type SessionIndex = u32;
    type CurrentSessionIndex = CurrentSessionIndexGetter;
    type Currency = Balances;
    type DepositAmount = DepositAmount;
    type RegistrarHooks = FlashboxRegistrarHooks;
    type RuntimeHoldReason = RuntimeHoldReason;
    type InnerRegistrar = ();
    type WeightInfo = weights::pallet_registrar::SubstrateWeight<Runtime>;
}
impl pallet_authority_mapping::Config for Runtime {
    type SessionIndex = u32;
    type SessionRemovalBoundary = ConstU32<2>;
    type AuthorityId = NimbusId;
}
impl pallet_sudo::Config for Runtime {
    type RuntimeCall = RuntimeCall;
    type RuntimeEvent = RuntimeEvent;
    type WeightInfo = weights::pallet_sudo::SubstrateWeight<Runtime>;
}
impl pallet_utility::Config for Runtime {
    type RuntimeEvent = RuntimeEvent;
    type RuntimeCall = RuntimeCall;
    type PalletsOrigin = OriginCaller;
    type WeightInfo = weights::pallet_utility::SubstrateWeight<Runtime>;
}
/// The type used to represent the kinds of proxies allowed.
#[apply(derive_storage_traits)]
#[derive(Copy, Ord, PartialOrd, MaxEncodedLen)]
#[allow(clippy::unnecessary_cast)]
pub enum ProxyType {
1
    /// All calls can be proxied. This is the trivial/most permissive filter.
    Any = 0,
2
    /// Only extrinsics that do not transfer funds.
    NonTransfer = 1,
1
    /// Only extrinsics related to governance (democracy and collectives).
    Governance = 2,
1
    /// Only extrinsics related to staking.
    Staking = 3,
1
    /// Allow to veto an announced proxy call.
    CancelProxy = 4,
1
    /// Allow extrinsic related to Balances.
    Balances = 5,
1
    /// Allow extrinsics related to Registrar
    Registrar = 6,
1
    /// Allow extrinsics related to Registrar that needs to be called through Sudo
    SudoRegistrar = 7,
}
impl Default for ProxyType {
    fn default() -> Self {
        Self::Any
    }
}
impl InstanceFilter<RuntimeCall> for ProxyType {
9
    fn filter(&self, c: &RuntimeCall) -> bool {
9
        // Since proxy filters are respected in all dispatches of the Utility
9
        // pallet, it should never need to be filtered by any proxy.
9
        if let RuntimeCall::Utility(..) = c {
            return true;
9
        }
9

            
9
        match self {
1
            ProxyType::Any => true,
            ProxyType::NonTransfer => {
2
                matches!(
2
                    c,
                    RuntimeCall::System(..)
                        | RuntimeCall::ParachainSystem(..)
                        | RuntimeCall::Timestamp(..)
                        | RuntimeCall::Proxy(..)
                        | RuntimeCall::Registrar(..)
                )
            }
            // We don't have governance yet
1
            ProxyType::Governance => false,
1
            ProxyType::Staking => matches!(c, RuntimeCall::Session(..)),
1
            ProxyType::CancelProxy => matches!(
                c,
                RuntimeCall::Proxy(pallet_proxy::Call::reject_announcement { .. })
            ),
            ProxyType::Balances => {
1
                matches!(c, RuntimeCall::Balances(..))
            }
            ProxyType::Registrar => {
1
                matches!(
1
                    c,
                    RuntimeCall::Registrar(..) | RuntimeCall::DataPreservers(..)
                )
            }
1
            ProxyType::SudoRegistrar => match c {
1
                RuntimeCall::Sudo(pallet_sudo::Call::sudo { call: ref x }) => {
1
                    matches!(
1
                        x.as_ref(),
                        &RuntimeCall::Registrar(..) | &RuntimeCall::DataPreservers(..)
                    )
                }
                _ => false,
            },
        }
9
    }
    fn is_superset(&self, o: &Self) -> bool {
        match (self, o) {
            (x, y) if x == y => true,
            (ProxyType::Any, _) => true,
            (_, ProxyType::Any) => false,
            _ => false,
        }
    }
}
impl pallet_proxy::Config for Runtime {
    type RuntimeEvent = RuntimeEvent;
    type RuntimeCall = RuntimeCall;
    type Currency = Balances;
    type ProxyType = ProxyType;
    // One storage item; key size 32, value size 8
    type ProxyDepositBase = ConstU128<{ currency::deposit(1, 8) }>;
    // Additional storage item size of 33 bytes (32 bytes AccountId + 1 byte sizeof(ProxyType)).
    type ProxyDepositFactor = ConstU128<{ currency::deposit(0, 33) }>;
    type MaxProxies = ConstU32<32>;
    type MaxPending = ConstU32<32>;
    type CallHasher = BlakeTwo256;
    type AnnouncementDepositBase = ConstU128<{ currency::deposit(1, 8) }>;
    // Additional storage item size of 68 bytes:
    // - 32 bytes AccountId
    // - 32 bytes Hasher (Blake2256)
    // - 4 bytes BlockNumber (u32)
    type AnnouncementDepositFactor = ConstU128<{ currency::deposit(0, 68) }>;
    type WeightInfo = weights::pallet_proxy::SubstrateWeight<Runtime>;
}
impl pallet_migrations::Config for Runtime {
    type RuntimeEvent = RuntimeEvent;
    type MigrationsList = (tanssi_runtime_common::migrations::FlashboxMigrations<Runtime>,);
    type XcmExecutionManager = ();
}
parameter_types! {
    pub MbmServiceWeight: Weight = Perbill::from_percent(80) * RuntimeBlockWeights::get().max_block;
}
impl pallet_multiblock_migrations::Config for Runtime {
    type RuntimeEvent = RuntimeEvent;
    #[cfg(not(feature = "runtime-benchmarks"))]
    type Migrations = pallet_identity::migration::v2::LazyMigrationV1ToV2<Runtime>;
    // Benchmarks need mocked migrations to guarantee that they succeed.
    #[cfg(feature = "runtime-benchmarks")]
    type Migrations = pallet_multiblock_migrations::mock_helpers::MockedMigrations;
    type CursorMaxLen = ConstU32<65_536>;
    type IdentifierMaxLen = ConstU32<256>;
    type MigrationStatusHandler = ();
    type FailedMigrationHandler = frame_support::migrations::FreezeChainOnFailedMigration;
    type MaxServiceWeight = MbmServiceWeight;
    type WeightInfo = weights::pallet_multiblock_migrations::SubstrateWeight<Runtime>;
}
/// Maintenance mode Call filter
pub struct MaintenanceFilter;
impl Contains<RuntimeCall> for MaintenanceFilter {
    fn contains(c: &RuntimeCall) -> bool {
        !matches!(
            c,
            RuntimeCall::Balances(..)
                | RuntimeCall::Registrar(..)
                | RuntimeCall::Session(..)
                | RuntimeCall::System(..)
                | RuntimeCall::Utility(..)
        )
    }
}
/// We allow everything but registering parathreads
pub struct IsRegisterParathreads;
impl Contains<RuntimeCall> for IsRegisterParathreads {
86
    fn contains(c: &RuntimeCall) -> bool {
85
        matches!(
1
            c,
            RuntimeCall::Registrar(pallet_registrar::Call::register_parathread { .. })
        )
86
    }
}
impl pallet_maintenance_mode::Config for Runtime {
    type RuntimeEvent = RuntimeEvent;
    type NormalCallFilter = EverythingBut<IsRegisterParathreads>;
    type MaintenanceCallFilter = MaintenanceFilter;
    type MaintenanceOrigin = EnsureRoot<AccountId>;
    type XcmExecutionManager = ();
}
parameter_types! {
    pub const MaxStorageRoots: u32 = 10; // 1 minute of relay blocks
}
impl pallet_relay_storage_roots::Config for Runtime {
    type RelaychainStateProvider = cumulus_pallet_parachain_system::RelaychainDataProvider<Self>;
    type MaxStorageRoots = MaxStorageRoots;
    type WeightInfo = weights::pallet_relay_storage_roots::SubstrateWeight<Runtime>;
}
impl pallet_root_testing::Config for Runtime {
    type RuntimeEvent = RuntimeEvent;
}
parameter_types! {
    pub StakingAccount: AccountId32 = PalletId(*b"POOLSTAK").into_account_truncating();
    pub const InitialManualClaimShareValue: u128 = currency::MILLIDANCE;
    pub const InitialAutoCompoundingShareValue: u128 = currency::MILLIDANCE;
    pub const MinimumSelfDelegation: u128 = 10 * currency::KILODANCE;
    pub const RewardsCollatorCommission: Perbill = Perbill::from_percent(20);
    // Need to wait 2 sessions before being able to join or leave staking pools
    pub const StakingSessionDelay: u32 = 2;
}
parameter_types! {
    pub ParachainBondAccount: AccountId32 = PalletId(*b"ParaBond").into_account_truncating();
    pub PendingRewardsAccount: AccountId32 = PalletId(*b"PENDREWD").into_account_truncating();
    // The equation to solve is:
    // initial_supply * (1.05) = initial_supply * (1+x)^5_259_600
    // we should solve for x = (1.05)^(1/5_259_600) -1 -> 0.000000009 per block or 9/1_000_000_000
    // 1% in the case of dev mode
    // TODO: check if we can put the prod inflation for tests too
    // TODO: better calculus for going from annual to block inflation (if it can be done)
    pub const InflationRate: Perbill = prod_or_fast!(Perbill::from_parts(9), Perbill::from_percent(1));
    // 30% for parachain bond, so 70% for staking
    pub const RewardsPortion: Perbill = Perbill::from_percent(70);
}
pub struct GetSelfChainBlockAuthor;
impl MaybeSelfChainBlockAuthor<AccountId32> for GetSelfChainBlockAuthor {
2108
    fn get_block_author() -> Option<AccountId32> {
2108
        // TODO: we should do a refactor here, and use either authority-mapping or collator-assignemnt
2108
        // we should also make sure we actually account for the weight of these
2108
        // although most of these should be cached as they are read every block
2108
        let slot = u64::from(<Runtime as pallet_author_inherent::Config>::SlotBeacon::slot());
2108
        let self_para_id = ParachainInfo::get();
2108
        CollatorAssignment::author_for_slot(slot.into(), self_para_id)
2108
    }
}
pub struct OnUnbalancedInflation;
impl frame_support::traits::OnUnbalanced<Credit<AccountId, Balances>> for OnUnbalancedInflation {
1054
    fn on_nonzero_unbalanced(credit: Credit<AccountId, Balances>) {
1054
        let _ = <Balances as Balanced<_>>::resolve(&ParachainBondAccount::get(), credit);
1054
    }
}
impl pallet_inflation_rewards::Config for Runtime {
    type RuntimeEvent = RuntimeEvent;
    type Currency = Balances;
    type ContainerChains = Registrar;
    type GetSelfChainBlockAuthor = GetSelfChainBlockAuthor;
    type InflationRate = InflationRate;
    type OnUnbalanced = OnUnbalancedInflation;
    type PendingRewardsAccount = PendingRewardsAccount;
    type StakingRewardsDistributor = InvulnerableRewardDistribution<Self, Balances, ()>;
    type RewardsPortion = RewardsPortion;
}
impl pallet_tx_pause::Config for Runtime {
    type RuntimeEvent = RuntimeEvent;
    type RuntimeCall = RuntimeCall;
    type PauseOrigin = EnsureRoot<AccountId>;
    type UnpauseOrigin = EnsureRoot<AccountId>;
    type WhitelistedCalls = ();
    type MaxNameLen = ConstU32<256>;
    type WeightInfo = weights::pallet_tx_pause::SubstrateWeight<Runtime>;
}
#[apply(derive_storage_traits)]
#[derive(Copy, Serialize, Deserialize, MaxEncodedLen)]
pub enum StreamPaymentAssetId {
11
    Native,
}
pub struct StreamPaymentAssets;
impl pallet_stream_payment::Assets<AccountId, StreamPaymentAssetId, Balance>
    for StreamPaymentAssets
{
2
    fn transfer_deposit(
2
        asset_id: &StreamPaymentAssetId,
2
        from: &AccountId,
2
        to: &AccountId,
2
        amount: Balance,
2
    ) -> frame_support::pallet_prelude::DispatchResult {
2
        match asset_id {
2
            StreamPaymentAssetId::Native => {
2
                // We remove the hold before transfering.
2
                Self::decrease_deposit(asset_id, from, amount)?;
2
                Balances::transfer(from, to, amount, Preservation::Preserve).map(|_| ())
            }
        }
2
    }
1
    fn increase_deposit(
1
        asset_id: &StreamPaymentAssetId,
1
        account: &AccountId,
1
        amount: Balance,
1
    ) -> frame_support::pallet_prelude::DispatchResult {
1
        match asset_id {
1
            StreamPaymentAssetId::Native => Balances::hold(
1
                &pallet_stream_payment::HoldReason::StreamPayment.into(),
1
                account,
1
                amount,
1
            ),
1
        }
1
    }
3
    fn decrease_deposit(
3
        asset_id: &StreamPaymentAssetId,
3
        account: &AccountId,
3
        amount: Balance,
3
    ) -> frame_support::pallet_prelude::DispatchResult {
3
        match asset_id {
3
            StreamPaymentAssetId::Native => Balances::release(
3
                &pallet_stream_payment::HoldReason::StreamPayment.into(),
3
                account,
3
                amount,
3
                Precision::Exact,
3
            )
3
            .map(|_| ()),
3
        }
3
    }
    fn get_deposit(asset_id: &StreamPaymentAssetId, account: &AccountId) -> Balance {
        match asset_id {
            StreamPaymentAssetId::Native => Balances::balance_on_hold(
                &pallet_stream_payment::HoldReason::StreamPayment.into(),
                account,
            ),
        }
    }
    /// Benchmarks: should return the asset id which has the worst performance when interacting
    /// with it.
    #[cfg(feature = "runtime-benchmarks")]
    fn bench_worst_case_asset_id() -> StreamPaymentAssetId {
        StreamPaymentAssetId::Native
    }
    /// Benchmarks: should return the another asset id which has the worst performance when interacting
    /// with it afther `bench_worst_case_asset_id`. This is to benchmark the worst case when changing config
    /// from one asset to another.
    #[cfg(feature = "runtime-benchmarks")]
    fn bench_worst_case_asset_id2() -> StreamPaymentAssetId {
        StreamPaymentAssetId::Native
    }
    /// Benchmarks: should set the balance for the asset id returned by `bench_worst_case_asset_id`.
    #[cfg(feature = "runtime-benchmarks")]
    fn bench_set_balance(asset_id: &StreamPaymentAssetId, account: &AccountId, amount: Balance) {
        // only one asset id
        let StreamPaymentAssetId::Native = asset_id;
        Balances::set_balance(account, amount);
    }
}
#[apply(derive_storage_traits)]
#[derive(Copy, Serialize, Deserialize, MaxEncodedLen)]
pub enum TimeUnit {
7
    BlockNumber,
4
    Timestamp,
    // TODO: Container chains/relay block number.
}
pub struct TimeProvider;
impl pallet_stream_payment::TimeProvider<TimeUnit, Balance> for TimeProvider {
4
    fn now(unit: &TimeUnit) -> Option<Balance> {
4
        match *unit {
4
            TimeUnit::BlockNumber => Some(System::block_number().into()),
            TimeUnit::Timestamp => Some(Timestamp::get().into()),
        }
4
    }
    /// Benchmarks: should return the time unit which has the worst performance calling
    /// `TimeProvider::now(unit)` with.
    #[cfg(feature = "runtime-benchmarks")]
    fn bench_worst_case_time_unit() -> TimeUnit {
        // Both BlockNumber and Timestamp cost the same (1 db read), but overriding timestamp
        // doesn't work well in benches, while block number works fine.
        TimeUnit::BlockNumber
    }
    /// Benchmarks: sets the "now" time for time unit returned by `worst_case_time_unit`.
    #[cfg(feature = "runtime-benchmarks")]
    fn bench_set_now(instant: Balance) {
        System::set_block_number(instant as u32)
    }
}
type StreamId = u64;
parameter_types! {
    // 1 entry, storing 173 bytes on-chain
    pub const OpenStreamHoldAmount: Balance = currency::deposit(1, 173);
}
impl pallet_stream_payment::Config for Runtime {
    type RuntimeEvent = RuntimeEvent;
    type StreamId = StreamId;
    type TimeUnit = TimeUnit;
    type Balance = Balance;
    type AssetId = StreamPaymentAssetId;
    type Assets = StreamPaymentAssets;
    type Currency = Balances;
    type OpenStreamHoldAmount = OpenStreamHoldAmount;
    type RuntimeHoldReason = RuntimeHoldReason;
    type TimeProvider = TimeProvider;
    type WeightInfo = weights::pallet_stream_payment::SubstrateWeight<Runtime>;
}
parameter_types! {
    // 1 entry, storing 258 bytes on-chain
    pub const BasicDeposit: Balance = currency::deposit(1, 258);
    // 1 entry, storing 53 bytes on-chain
    pub const SubAccountDeposit: Balance = currency::deposit(1, 53);
    // Additional bytes adds 0 entries, storing 1 byte on-chain
    pub const ByteDeposit: Balance = currency::deposit(0, 1);
    pub const UsernameDeposit: Balance = currency::deposit(0, 32);
    pub const MaxSubAccounts: u32 = 100;
    pub const MaxAdditionalFields: u32 = 100;
    pub const MaxRegistrars: u32 = 20;
}
impl pallet_identity::Config for Runtime {
    type RuntimeEvent = RuntimeEvent;
    type Currency = Balances;
    type BasicDeposit = BasicDeposit;
    type ByteDeposit = ByteDeposit;
    type UsernameDeposit = UsernameDeposit;
    type SubAccountDeposit = SubAccountDeposit;
    type MaxSubAccounts = MaxSubAccounts;
    type MaxRegistrars = MaxRegistrars;
    type IdentityInformation = pallet_identity::legacy::IdentityInfo<MaxAdditionalFields>;
    // Slashed balances are burnt
    type Slashed = ();
    type ForceOrigin = EnsureRoot<AccountId>;
    type RegistrarOrigin = EnsureRoot<AccountId>;
    type OffchainSignature = Signature;
    type SigningPublicKey = <Signature as Verify>::Signer;
    type UsernameAuthorityOrigin = EnsureRoot<Self::AccountId>;
    type PendingUsernameExpiration = ConstU32<{ 7 * DAYS }>;
    type UsernameGracePeriod = ConstU32<{ 30 * DAYS }>;
    type MaxSuffixLength = ConstU32<7>;
    type MaxUsernameLength = ConstU32<32>;
    type WeightInfo = weights::pallet_identity::SubstrateWeight<Runtime>;
}
parameter_types! {
    pub const TreasuryId: PalletId = PalletId(*b"tns/tsry");
    pub const ProposalBond: Permill = Permill::from_percent(5);
    pub TreasuryAccount: AccountId = Treasury::account_id();
    pub const MaxBalance: Balance = Balance::max_value();
    pub const SpendPeriod: BlockNumber = prod_or_fast!(6 * DAYS, 1 * MINUTES);
}
impl pallet_treasury::Config for Runtime {
    type PalletId = TreasuryId;
    type Currency = Balances;
    type RejectOrigin = EnsureRoot<AccountId>;
    type RuntimeEvent = RuntimeEvent;
    // If proposal gets rejected, bond goes to treasury
    type SpendPeriod = SpendPeriod;
    type Burn = ();
    type BurnDestination = ();
    type MaxApprovals = ConstU32<100>;
    type WeightInfo = weights::pallet_treasury::SubstrateWeight<Runtime>;
    type SpendFunds = ();
    type SpendOrigin =
        frame_system::EnsureWithSuccess<EnsureRoot<AccountId>, AccountId, MaxBalance>;
    type AssetKind = ();
    type Beneficiary = AccountId;
    type BeneficiaryLookup = IdentityLookup<AccountId>;
    type Paymaster = PayFromAccount<Balances, TreasuryAccount>;
    type BalanceConverter = UnityAssetBalanceConversion;
    type PayoutPeriod = ConstU32<{ 30 * DAYS }>;
    type BlockNumberProvider = System;
    #[cfg(feature = "runtime-benchmarks")]
    type BenchmarkHelper = tanssi_runtime_common::benchmarking::TreasuryBenchmarkHelper<Runtime>;
}
parameter_types! {
    // One storage item; key size 32; value is size 4+4+16+32. Total = 1 * (32 + 56)
    pub const DepositBase: Balance = currency::deposit(1, 88);
    // Additional storage item size of 32 bytes.
    pub const DepositFactor: Balance = currency::deposit(0, 32);
    pub const MaxSignatories: u32 = 100;
}
impl pallet_multisig::Config for Runtime {
    type RuntimeEvent = RuntimeEvent;
    type RuntimeCall = RuntimeCall;
    type Currency = Balances;
    type DepositBase = DepositBase;
    type DepositFactor = DepositFactor;
    type MaxSignatories = MaxSignatories;
    type WeightInfo = weights::pallet_multisig::SubstrateWeight<Runtime>;
}
// Create the runtime by composing the FRAME pallets that were previously configured.
192422
construct_runtime!(
17876
    pub enum Runtime
17876
    {
17876
        // System support stuff.
17876
        System: frame_system = 0,
17876
        ParachainSystem: cumulus_pallet_parachain_system = 1,
17876
        Timestamp: pallet_timestamp = 2,
17876
        ParachainInfo: parachain_info = 3,
17876
        Sudo: pallet_sudo = 4,
17876
        Utility: pallet_utility = 5,
17876
        Proxy: pallet_proxy = 6,
17876
        Migrations: pallet_migrations = 7,
17876
        MultiBlockMigrations: pallet_multiblock_migrations = 121,
17876
        MaintenanceMode: pallet_maintenance_mode = 8,
17876
        TxPause: pallet_tx_pause = 9,
17876

            
17876
        // Monetary stuff.
17876
        Balances: pallet_balances = 10,
17876
        TransactionPayment: pallet_transaction_payment = 11,
17876
        StreamPayment: pallet_stream_payment = 12,
17876

            
17876
        // Other utilities
17876
        Identity: pallet_identity = 15,
17876
        Multisig: pallet_multisig = 16,
17876

            
17876
        // ContainerChain management. It should go before Session for Genesis
17876
        Registrar: pallet_registrar = 20,
17876
        Configuration: pallet_configuration = 21,
17876
        CollatorAssignment: pallet_collator_assignment = 22,
17876
        Initializer: pallet_initializer = 23,
17876
        AuthorNoting: pallet_author_noting = 24,
17876
        AuthorityAssignment: pallet_authority_assignment = 25,
17876
        ServicesPayment: pallet_services_payment = 26,
17876
        DataPreservers: pallet_data_preservers = 27,
17876

            
17876
        // Collator support. The order of these 6 are important and shall not change.
17876
        Invulnerables: pallet_invulnerables = 30,
17876
        Session: pallet_session = 31,
17876
        AuthorityMapping: pallet_authority_mapping = 32,
17876
        AuthorInherent: pallet_author_inherent = 33,
17876
        // InflationRewards must be after Session and AuthorInherent
17876
        InflationRewards: pallet_inflation_rewards = 35,
17876

            
17876
        // Treasury stuff.
17876
        Treasury: pallet_treasury::{Pallet, Storage, Config<T>, Event<T>, Call} = 40,
17876

            
17876
        // More system support stuff
17876
        RelayStorageRoots: pallet_relay_storage_roots = 60,
17876

            
17876
        RootTesting: pallet_root_testing = 100,
17876
        AsyncBacking: pallet_async_backing::{Pallet, Storage} = 110,
17876
    }
193884
);
#[cfg(feature = "runtime-benchmarks")]
mod benches {
    frame_benchmarking::define_benchmarks!(
        [frame_system, frame_system_benchmarking::Pallet::<Runtime>]
        [cumulus_pallet_parachain_system, ParachainSystem]
        [pallet_timestamp, Timestamp]
        [pallet_sudo, Sudo]
        [pallet_utility, Utility]
        [pallet_proxy, Proxy]
        [pallet_tx_pause, TxPause]
        [pallet_balances, Balances]
        [pallet_stream_payment, StreamPayment]
        [pallet_identity, Identity]
        [pallet_multiblock_migrations, MultiBlockMigrations]
        [pallet_multisig, Multisig]
        [pallet_registrar, Registrar]
        [pallet_configuration, Configuration]
        [pallet_collator_assignment, CollatorAssignment]
        [pallet_author_noting, AuthorNoting]
        [pallet_services_payment, ServicesPayment]
        [pallet_data_preservers, DataPreservers]
        [pallet_invulnerables, Invulnerables]
        [pallet_session, SessionBench::<Runtime>]
        [pallet_author_inherent, AuthorInherent]
        [pallet_treasury, Treasury]
        [pallet_relay_storage_roots, RelayStorageRoots]
    );
}
impl_runtime_apis! {
    impl sp_consensus_aura::AuraApi<Block, NimbusId> for Runtime {
        fn slot_duration() -> sp_consensus_aura::SlotDuration {
            sp_consensus_aura::SlotDuration::from_millis(SLOT_DURATION)
        }
        fn authorities() -> Vec<NimbusId> {
            // Check whether we need to fetch the next authorities or current ones
            let parent_number = System::block_number();
            let should_end_session = <Runtime as pallet_session::Config>::ShouldEndSession::should_end_session(parent_number + 1);
            let session_index = if should_end_session {
                Session::current_index() +1
            }
            else {
                Session::current_index()
            };
            pallet_authority_assignment::CollatorContainerChain::<Runtime>::get(session_index)
                .expect("authorities for current session should exist")
                .orchestrator_chain
        }
    }
    impl sp_api::Core<Block> for Runtime {
        fn version() -> RuntimeVersion {
            VERSION
        }
        fn execute_block(block: Block) {
            Executive::execute_block(block)
        }
        fn initialize_block(header: &<Block as BlockT>::Header) -> sp_runtime::ExtrinsicInclusionMode {
            Executive::initialize_block(header)
        }
    }
    impl sp_api::Metadata<Block> for Runtime {
        fn metadata() -> OpaqueMetadata {
            OpaqueMetadata::new(Runtime::metadata().into())
        }
        fn metadata_at_version(version: u32) -> Option<OpaqueMetadata> {
            Runtime::metadata_at_version(version)
        }
        fn metadata_versions() -> Vec<u32> {
            Runtime::metadata_versions()
        }
    }
    impl sp_block_builder::BlockBuilder<Block> for Runtime {
        fn apply_extrinsic(extrinsic: <Block as BlockT>::Extrinsic) -> ApplyExtrinsicResult {
            Executive::apply_extrinsic(extrinsic)
        }
        fn finalize_block() -> <Block as BlockT>::Header {
            Executive::finalize_block()
        }
        fn inherent_extrinsics(data: sp_inherents::InherentData) -> Vec<<Block as BlockT>::Extrinsic> {
            data.create_extrinsics()
        }
        fn check_inherents(
            block: Block,
            data: sp_inherents::InherentData,
        ) -> sp_inherents::CheckInherentsResult {
            data.check_extrinsics(&block)
        }
    }
    impl sp_transaction_pool::runtime_api::TaggedTransactionQueue<Block> for Runtime {
        fn validate_transaction(
            source: TransactionSource,
            tx: <Block as BlockT>::Extrinsic,
            block_hash: <Block as BlockT>::Hash,
        ) -> TransactionValidity {
            Executive::validate_transaction(source, tx, block_hash)
        }
    }
    impl sp_offchain::OffchainWorkerApi<Block> for Runtime {
        fn offchain_worker(header: &<Block as BlockT>::Header) {
            Executive::offchain_worker(header)
        }
    }
    impl sp_session::SessionKeys<Block> for Runtime {
        fn generate_session_keys(seed: Option<Vec<u8>>) -> Vec<u8> {
            SessionKeys::generate(seed)
        }
        fn decode_session_keys(
            encoded: Vec<u8>,
        ) -> Option<Vec<(Vec<u8>, KeyTypeId)>> {
            SessionKeys::decode_into_raw_public_keys(&encoded)
        }
    }
    impl frame_system_rpc_runtime_api::AccountNonceApi<Block, AccountId, Index> for Runtime {
        fn account_nonce(account: AccountId) -> Index {
            System::account_nonce(account)
        }
    }
    impl cumulus_primitives_core::CollectCollationInfo<Block> for Runtime {
        fn collect_collation_info(header: &<Block as BlockT>::Header) -> cumulus_primitives_core::CollationInfo {
            ParachainSystem::collect_collation_info(header)
        }
    }
    impl sp_genesis_builder::GenesisBuilder<Block> for Runtime {
        fn build_state(config: Vec<u8>) -> sp_genesis_builder::Result {
            build_state::<RuntimeGenesisConfig>(config)
        }
        fn get_preset(id: &Option<sp_genesis_builder::PresetId>) -> Option<Vec<u8>> {
            get_preset::<RuntimeGenesisConfig>(id, |_| None)
        }
        fn preset_names() -> Vec<sp_genesis_builder::PresetId> {
            vec![]
        }
    }
    #[cfg(feature = "runtime-benchmarks")]
    impl frame_benchmarking::Benchmark<Block> for Runtime {
        fn benchmark_metadata(
            extra: bool,
        ) -> (
            Vec<frame_benchmarking::BenchmarkList>,
            Vec<frame_support::traits::StorageInfo>,
        ) {
            use cumulus_pallet_session_benchmarking::Pallet as SessionBench;
            use frame_benchmarking::{Benchmarking, BenchmarkList};
            use frame_support::traits::StorageInfoTrait;
            let mut list = Vec::<BenchmarkList>::new();
            list_benchmarks!(list, extra);
            let storage_info = AllPalletsWithSystem::storage_info();
            (list, storage_info)
        }
        fn dispatch_benchmark(
            config: frame_benchmarking::BenchmarkConfig,
        ) -> Result<Vec<frame_benchmarking::BenchmarkBatch>, alloc::string::String> {
            use frame_benchmarking::{BenchmarkBatch, Benchmarking, BenchmarkError};
            use sp_core::storage::TrackedStorageKey;
            impl frame_system_benchmarking::Config for Runtime {
                fn setup_set_code_requirements(code: &sp_std::vec::Vec<u8>) -> Result<(), BenchmarkError> {
                    ParachainSystem::initialize_for_set_code_benchmark(code.len() as u32);
                    Ok(())
                }
                fn verify_set_code() {
                    System::assert_last_event(cumulus_pallet_parachain_system::Event::<Runtime>::ValidationFunctionStored.into());
                }
            }
            use cumulus_pallet_session_benchmarking::Pallet as SessionBench;
            impl cumulus_pallet_session_benchmarking::Config for Runtime {}
            let whitelist: Vec<TrackedStorageKey> = vec![
                // Block Number
                hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef702a5c1b19ab7a04f536c519aca4983ac")
                    .to_vec()
                    .into(),
                // Total Issuance
                hex_literal::hex!("c2261276cc9d1f8598ea4b6a74b15c2f57c875e4cff74148e4628f264b974c80")
                    .to_vec()
                    .into(),
                // Execution Phase
                hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef7ff553b5a9862a516939d82b3d3d8661a")
                    .to_vec()
                    .into(),
                // Event Count
                hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef70a98fdbe9ce6c55837576c60c7af3850")
                    .to_vec()
                    .into(),
                // System Events
                hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef780d41e5e16056765bc8461851072c9d7")
                    .to_vec()
                    .into(),
                // The transactional storage limit.
                hex_literal::hex!("3a7472616e73616374696f6e5f6c6576656c3a")
                    .to_vec()
                    .into(),
                // ParachainInfo ParachainId
                hex_literal::hex!(  "0d715f2646c8f85767b5d2764bb2782604a74d81251e398fd8a0a4d55023bb3f")
                    .to_vec()
                    .into(),
            ];
            let mut batches = Vec::<BenchmarkBatch>::new();
            let params = (&config, &whitelist);
            add_benchmarks!(params, batches);
            Ok(batches)
        }
    }
    #[cfg(feature = "try-runtime")]
    impl frame_try_runtime::TryRuntime<Block> for Runtime {
        fn on_runtime_upgrade(checks: frame_try_runtime::UpgradeCheckSelect) -> (Weight, Weight) {
            let weight = Executive::try_runtime_upgrade(checks).unwrap();
            (weight, RuntimeBlockWeights::get().max_block)
        }
        fn execute_block(
            block: Block,
            state_root_check: bool,
            signature_check: bool,
            select: frame_try_runtime::TryStateSelect,
        ) -> Weight {
            // NOTE: intentional unwrap: we don't want to propagate the error backwards, and want to
            // have a backtrace here.
            Executive::try_execute_block(block, state_root_check, signature_check, select).unwrap()
        }
    }
    impl pallet_collator_assignment_runtime_api::CollatorAssignmentApi<Block, AccountId, ParaId> for Runtime {
        /// Return the parachain that the given `AccountId` is collating for.
        /// Returns `None` if the `AccountId` is not collating.
8
        fn current_collator_parachain_assignment(account: AccountId) -> Option<ParaId> {
8
            let assigned_collators = CollatorAssignment::collator_container_chain();
8
            let self_para_id = ParachainInfo::get();
8

            
8
            assigned_collators.para_id_of(&account, self_para_id)
8
        }
        /// Return the parachain that the given `AccountId` will be collating for
        /// in the next session change.
        /// Returns `None` if the `AccountId` will not be collating.
6
        fn future_collator_parachain_assignment(account: AccountId) -> Option<ParaId> {
6
            let assigned_collators = CollatorAssignment::pending_collator_container_chain();
6

            
6
            match assigned_collators {
4
                Some(assigned_collators) => {
4
                    let self_para_id = ParachainInfo::get();
4

            
4
                    assigned_collators.para_id_of(&account, self_para_id)
                }
                None => {
2
                    Self::current_collator_parachain_assignment(account)
                }
            }
6
        }
        /// Return the list of collators of the given `ParaId`.
        /// Returns `None` if the `ParaId` is not in the registrar.
14
        fn parachain_collators(para_id: ParaId) -> Option<Vec<AccountId>> {
14
            let assigned_collators = CollatorAssignment::collator_container_chain();
14
            let self_para_id = ParachainInfo::get();
14

            
14
            if para_id == self_para_id {
9
                Some(assigned_collators.orchestrator_chain)
            } else {
5
                assigned_collators.container_chains.get(&para_id).cloned()
            }
14
        }
        /// Returns the list of `ParaId` of registered chains with at least some
        /// collators. This filters out parachains with no assigned collators.
        /// Since runtime APIs are called on top of a parent block, we need to be carefull
        /// at session boundaries. If the next block will change session, this function returns
        /// the parachains relevant for the next session.
        fn parachains_with_some_collators() -> Vec<ParaId> {
            use tp_traits::{GetContainerChainsWithCollators, ForSession};
            // We should return the container-chains for the session in which we are kicking in
            let parent_number = System::block_number();
            let should_end_session = <Runtime as pallet_session::Config>::ShouldEndSession::should_end_session(parent_number + 1);
            let for_session = if should_end_session { ForSession::Next } else { ForSession::Current };
            CollatorAssignment::container_chains_with_collators(for_session)
                .into_iter()
                .filter_map(
                    |(para_id, collators)| (!collators.is_empty()).then_some(para_id)
                ).collect()
        }
    }
    impl pallet_registrar_runtime_api::RegistrarApi<Block, ParaId> for Runtime {
        /// Return the registered para ids
5
        fn registered_paras() -> Vec<ParaId> {
5
            // We should return the container-chains for the session in which we are kicking in
5
            let parent_number = System::block_number();
5
            let should_end_session = <Runtime as pallet_session::Config>::ShouldEndSession::should_end_session(parent_number + 1);
5
            let session_index = if should_end_session {
                Session::current_index() +1
            }
            else {
5
                Session::current_index()
            };
5
            let container_chains = Registrar::session_container_chains(session_index);
5
            let mut para_ids = vec![];
5
            para_ids.extend(container_chains.parachains);
5
            para_ids.extend(container_chains.parathreads.into_iter().map(|(para_id, _)| para_id));
5

            
5
            para_ids
5
        }
        /// Fetch genesis data for this para id
7
        fn genesis_data(para_id: ParaId) -> Option<ContainerChainGenesisData> {
7
            Registrar::para_genesis_data(para_id)
7
        }
        /// Fetch boot_nodes for this para id
        fn boot_nodes(para_id: ParaId) -> Vec<Vec<u8>> {
            DataPreservers::assignments_profiles(para_id)
                .filter(|profile| profile.mode == pallet_data_preservers::ProfileMode::Bootnode)
                .map(|profile| profile.url.into())
                .collect()
        }
    }
    impl pallet_author_noting_runtime_api::AuthorNotingApi<Block, AccountId, BlockNumber, ParaId> for Runtime
        where
        AccountId: parity_scale_codec::Codec,
        BlockNumber: parity_scale_codec::Codec,
        ParaId: parity_scale_codec::Codec,
    {
1
        fn latest_block_number(para_id: ParaId) -> Option<BlockNumber> {
1
            AuthorNoting::latest_author(para_id).map(|info| info.block_number)
1
        }
1
        fn latest_author(para_id: ParaId) -> Option<AccountId> {
1
            AuthorNoting::latest_author(para_id).map(|info| info.author)
1
        }
    }
    impl dp_consensus::TanssiAuthorityAssignmentApi<Block, NimbusId> for Runtime {
        /// Return the current authorities assigned to a given paraId
1070
        fn para_id_authorities(para_id: ParaId) -> Option<Vec<NimbusId>> {
1070
            let parent_number = System::block_number();
1070

            
1070
            let should_end_session = <Runtime as pallet_session::Config>::ShouldEndSession::should_end_session(parent_number + 1);
1070
            let session_index = if should_end_session {
99
                Session::current_index() +1
            }
            else {
971
                Session::current_index()
            };
1070
            let assigned_authorities = AuthorityAssignment::collator_container_chain(session_index)?;
1070
            let self_para_id = ParachainInfo::get();
1070

            
1070
            if para_id == self_para_id {
1062
                Some(assigned_authorities.orchestrator_chain)
            } else {
8
                assigned_authorities.container_chains.get(&para_id).cloned()
            }
1070
        }
        /// Return the paraId assigned to a given authority
32
        fn check_para_id_assignment(authority: NimbusId) -> Option<ParaId> {
32
            let parent_number = System::block_number();
32
            let should_end_session = <Runtime as pallet_session::Config>::ShouldEndSession::should_end_session(parent_number + 1);
32
            let session_index = if should_end_session {
8
                Session::current_index() +1
            }
            else {
24
                Session::current_index()
            };
32
            let assigned_authorities = AuthorityAssignment::collator_container_chain(session_index)?;
32
            let self_para_id = ParachainInfo::get();
32

            
32
            assigned_authorities.para_id_of(&authority, self_para_id)
32
        }
        /// Return the paraId assigned to a given authority on the next session.
        /// On session boundary this returns the same as `check_para_id_assignment`.
12
        fn check_para_id_assignment_next_session(authority: NimbusId) -> Option<ParaId> {
12
            let session_index = Session::current_index() + 1;
12
            let assigned_authorities = AuthorityAssignment::collator_container_chain(session_index)?;
12
            let self_para_id = ParachainInfo::get();
12

            
12
            assigned_authorities.para_id_of(&authority, self_para_id)
12
        }
    }
    impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi<Block, Balance>
    for Runtime {
        fn query_info(
            uxt: <Block as BlockT>::Extrinsic,
            len: u32,
        ) -> pallet_transaction_payment_rpc_runtime_api::RuntimeDispatchInfo<Balance> {
            TransactionPayment::query_info(uxt, len)
        }
        fn query_fee_details(
            uxt: <Block as BlockT>::Extrinsic,
            len: u32,
        ) -> pallet_transaction_payment::FeeDetails<Balance> {
            TransactionPayment::query_fee_details(uxt, len)
        }
        fn query_weight_to_fee(weight: Weight) -> Balance {
            TransactionPayment::weight_to_fee(weight)
        }
        fn query_length_to_fee(length: u32) -> Balance {
            TransactionPayment::length_to_fee(length)
        }
    }
    impl pallet_stream_payment_runtime_api::StreamPaymentApi<Block, StreamId, Balance, Balance>
    for Runtime {
        fn stream_payment_status(
            stream_id: StreamId,
            now: Option<Balance>,
        ) -> Result<StreamPaymentApiStatus<Balance>, StreamPaymentApiError> {
            match StreamPayment::stream_payment_status(stream_id, now) {
                Ok(pallet_stream_payment::StreamPaymentStatus {
                    payment, deposit_left, stalled
                }) => Ok(StreamPaymentApiStatus {
                    payment, deposit_left, stalled
                }),
                Err(pallet_stream_payment::Error::<Runtime>::UnknownStreamId)
                => Err(StreamPaymentApiError::UnknownStreamId),
                Err(e) => Err(StreamPaymentApiError::Other(format!("{e:?}")))
            }
        }
    }
    impl pallet_data_preservers_runtime_api::DataPreserversApi<Block, DataPreserversProfileId, ParaId> for Runtime {
        fn get_active_assignment(
            profile_id: DataPreserversProfileId,
        ) -> pallet_data_preservers_runtime_api::Assignment<ParaId> {
            use pallet_data_preservers_runtime_api::Assignment;
            use pallet_stream_payment::StreamPaymentStatus;
            let Some((para_id, witness)) = pallet_data_preservers::Profiles::<Runtime>::get(profile_id)
                .and_then(|x| x.assignment) else
            {
                return Assignment::NotAssigned;
            };
            match witness {
                PreserversAssignementPaymentWitness::Free => Assignment::Active(para_id),
                PreserversAssignementPaymentWitness::StreamPayment { stream_id } => {
                    // Error means no Stream exists with that ID or some issue occured when computing
                    // the status. In that case we cannot consider the assignment as active.
                    let Ok(StreamPaymentStatus { stalled, .. }) = StreamPayment::stream_payment_status( stream_id, None) else {
                        return Assignment::Inactive(para_id);
                    };
                    if stalled {
                        Assignment::Inactive(para_id)
                    } else {
                        Assignment::Active(para_id)
                    }
                },
            }
        }
    }
    impl async_backing_primitives::UnincludedSegmentApi<Block> for Runtime {
        fn can_build_upon(
            included_hash: <Block as BlockT>::Hash,
            slot: async_backing_primitives::Slot,
        ) -> bool {
            ConsensusHook::can_build_upon(included_hash, slot)
        }
    }
    impl dp_slot_duration_runtime_api::TanssiSlotDurationApi<Block> for Runtime {
        fn slot_duration() -> u64 {
            SLOT_DURATION
        }
    }
    impl pallet_services_payment_runtime_api::ServicesPaymentApi<Block, Balance, ParaId> for Runtime {
        fn block_cost(para_id: ParaId) -> Balance {
            let (block_production_costs, _) = <Runtime as pallet_services_payment::Config>::ProvideBlockProductionCost::block_cost(&para_id);
            block_production_costs
        }
        fn collator_assignment_cost(para_id: ParaId) -> Balance {
            let (collator_assignment_costs, _) = <Runtime as pallet_services_payment::Config>::ProvideCollatorAssignmentCost::collator_assignment_cost(&para_id);
            collator_assignment_costs
        }
    }
}
#[allow(dead_code)]
struct CheckInherents;
// TODO: this should be removed but currently if we remove it the relay does not check anything
// related to other inherents that are not parachain-system
#[allow(deprecated)]
impl cumulus_pallet_parachain_system::CheckInherents<Block> for CheckInherents {
    fn check_inherents(
        block: &Block,
        relay_state_proof: &cumulus_pallet_parachain_system::RelayChainStateProof,
    ) -> sp_inherents::CheckInherentsResult {
        let relay_chain_slot = relay_state_proof
            .read_slot()
            .expect("Could not read the relay chain slot from the proof");
        let inherent_data =
            cumulus_primitives_timestamp::InherentDataProvider::from_relay_chain_slot_and_duration(
                relay_chain_slot,
                sp_std::time::Duration::from_secs(6),
            )
            .create_inherent_data()
            .expect("Could not create the timestamp inherent data");
        inherent_data.check_extrinsics(block)
    }
}
cumulus_pallet_parachain_system::register_validate_block! {
    Runtime = Runtime,
    CheckInherents = CheckInherents,
    BlockExecutor = pallet_author_inherent::BlockExecutor::<Runtime, Executive>,
}
#[macro_export]
macro_rules! prod_or_fast {
    ($prod:expr, $test:expr) => {
        if cfg!(feature = "fast-runtime") {
            $test
        } else {
            $prod
        }
    };
    ($prod:expr, $test:expr, $env:expr) => {
        if cfg!(feature = "fast-runtime") {
            core::option_env!($env)
                .map(|s| s.parse().ok())
                .flatten()
                .unwrap_or($test)
        } else {
            $prod
        }
    };
}