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
use cumulus_pallet_parachain_system::RelayNumberMonotonicallyIncreases;
26
#[cfg(feature = "std")]
27
use sp_version::NativeVersion;
28

            
29
#[cfg(any(feature = "std", test))]
30
pub use sp_runtime::BuildStorage;
31

            
32
pub mod migrations;
33
mod precompiles;
34
pub mod weights;
35
pub mod xcm_config;
36

            
37
use {
38
    crate::precompiles::TemplatePrecompiles,
39
    cumulus_primitives_core::AggregateMessageOrigin,
40
    dp_impl_tanssi_pallets_config::impl_tanssi_pallets_config,
41
    fp_account::EthereumSignature,
42
    fp_evm::weight_per_gas,
43
    fp_rpc::TransactionStatus,
44
    frame_support::{
45
        construct_runtime,
46
        dispatch::{DispatchClass, GetDispatchInfo},
47
        dynamic_params::{dynamic_pallet_params, dynamic_params},
48
        genesis_builder_helper::{build_state, get_preset},
49
        pallet_prelude::DispatchResult,
50
        parameter_types,
51
        traits::{
52
            ConstBool, ConstU128, ConstU32, ConstU64, ConstU8, Contains, Currency as CurrencyT,
53
            FindAuthor, Imbalance, InsideBoth, InstanceFilter, OnFinalize, OnUnbalanced,
54
        },
55
        weights::{
56
            constants::{
57
                BlockExecutionWeight, ExtrinsicBaseWeight, RocksDbWeight,
58
                WEIGHT_REF_TIME_PER_SECOND,
59
            },
60
            ConstantMultiplier, Weight, WeightToFeeCoefficient, WeightToFeeCoefficients,
61
            WeightToFeePolynomial,
62
        },
63
    },
64
    frame_system::{
65
        limits::{BlockLength, BlockWeights},
66
        EnsureRoot,
67
    },
68
    nimbus_primitives::{NimbusId, SlotBeacon},
69
    pallet_ethereum::{Call::transact, PostLogContent, Transaction as EthereumTransaction},
70
    pallet_evm::{
71
        Account as EVMAccount, EVMCurrencyAdapter, EnsureAddressNever, EnsureAddressRoot,
72
        EnsureCreateOrigin, FeeCalculator, GasWeightMapping, IdentityAddressMapping,
73
        OnChargeEVMTransaction as OnChargeEVMTransactionT, Runner,
74
    },
75
    pallet_transaction_payment::FungibleAdapter,
76
    parity_scale_codec::{Decode, Encode},
77
    polkadot_runtime_common::SlowAdjustingFeeUpdate,
78
    scale_info::TypeInfo,
79
    smallvec::smallvec,
80
    sp_api::impl_runtime_apis,
81
    sp_consensus_slots::{Slot, SlotDuration},
82
    sp_core::{Get, MaxEncodedLen, OpaqueMetadata, H160, H256, U256},
83
    sp_runtime::{
84
        create_runtime_str, generic, impl_opaque_keys,
85
        traits::{
86
            BlakeTwo256, Block as BlockT, DispatchInfoOf, Dispatchable, IdentifyAccount,
87
            IdentityLookup, PostDispatchInfoOf, UniqueSaturatedInto, Verify,
88
        },
89
        transaction_validity::{
90
            InvalidTransaction, TransactionSource, TransactionValidity, TransactionValidityError,
91
        },
92
        ApplyExtrinsicResult, BoundedVec,
93
    },
94
    sp_std::prelude::*,
95
    sp_version::RuntimeVersion,
96
};
97
pub use {
98
    sp_consensus_aura::sr25519::AuthorityId as AuraId,
99
    sp_runtime::{MultiAddress, Perbill, Permill},
100
};
101

            
102
// Polkadot imports
103
use polkadot_runtime_common::BlockHashCount;
104

            
105
pub type Precompiles = TemplatePrecompiles<Runtime>;
106

            
107
/// Alias to 512-bit hash when used in the context of a transaction signature on the chain.
108
pub type Signature = EthereumSignature;
109

            
110
/// Some way of identifying an account on the chain. We intentionally make it equivalent
111
/// to the public key of our transaction signing scheme.
112
pub type AccountId = <<Signature as Verify>::Signer as IdentifyAccount>::AccountId;
113

            
114
/// Balance of an account.
115
pub type Balance = u128;
116

            
117
/// Index of a transaction in the chain.
118
pub type Index = u32;
119

            
120
/// A hash of some data used by the chain.
121
pub type Hash = sp_core::H256;
122

            
123
/// An index to a block.
124
pub type BlockNumber = u32;
125

            
126
/// The address format for describing accounts.
127
pub type Address = AccountId;
128

            
129
/// Block header type as expected by this runtime.
130
pub type Header = generic::Header<BlockNumber, BlakeTwo256>;
131

            
132
/// Block type as expected by this runtime.
133
pub type Block = generic::Block<Header, UncheckedExtrinsic>;
134

            
135
/// A Block signed with a Justification
136
pub type SignedBlock = generic::SignedBlock<Block>;
137

            
138
/// BlockId type as expected by this runtime.
139
pub type BlockId = generic::BlockId<Block>;
140

            
141
/// The SignedExtension to the basic transaction logic.
142
pub type SignedExtra = (
143
    frame_system::CheckNonZeroSender<Runtime>,
144
    frame_system::CheckSpecVersion<Runtime>,
145
    frame_system::CheckTxVersion<Runtime>,
146
    frame_system::CheckGenesis<Runtime>,
147
    frame_system::CheckEra<Runtime>,
148
    frame_system::CheckNonce<Runtime>,
149
    frame_system::CheckWeight<Runtime>,
150
    pallet_transaction_payment::ChargeTransactionPayment<Runtime>,
151
);
152

            
153
/// Unchecked extrinsic type as expected by this runtime.
154
pub type UncheckedExtrinsic =
155
    fp_self_contained::UncheckedExtrinsic<Address, RuntimeCall, Signature, SignedExtra>;
156
/// Extrinsic type that has already been checked.
157
pub type CheckedExtrinsic =
158
    fp_self_contained::CheckedExtrinsic<AccountId, RuntimeCall, SignedExtra, H160>;
159
/// The payload being signed in transactions.
160
pub type SignedPayload = generic::SignedPayload<RuntimeCall, SignedExtra>;
161

            
162
/// Executive: handles dispatch to the various modules.
163
pub type Executive = frame_executive::Executive<
164
    Runtime,
165
    Block,
166
    frame_system::ChainContext<Runtime>,
167
    Runtime,
168
    AllPalletsWithSystem,
169
>;
170

            
171
pub mod currency {
172
    use super::Balance;
173

            
174
    pub const MICROUNIT: Balance = 1_000_000_000_000;
175
    pub const MILLIUNIT: Balance = 1_000_000_000_000_000;
176
    pub const UNIT: Balance = 1_000_000_000_000_000_000;
177
    pub const KILOUNIT: Balance = 1_000_000_000_000_000_000_000;
178

            
179
    pub const STORAGE_BYTE_FEE: Balance = 100 * MICROUNIT;
180

            
181
    pub const fn deposit(items: u32, bytes: u32) -> Balance {
182
        items as Balance * 100 * MILLIUNIT + (bytes as Balance) * STORAGE_BYTE_FEE
183
    }
184
}
185

            
186
impl fp_self_contained::SelfContainedCall for RuntimeCall {
187
    type SignedInfo = H160;
188

            
189
    fn is_self_contained(&self) -> bool {
190
        match self {
191
            RuntimeCall::Ethereum(call) => call.is_self_contained(),
192
            _ => false,
193
        }
194
    }
195

            
196
    fn check_self_contained(&self) -> Option<Result<Self::SignedInfo, TransactionValidityError>> {
197
        match self {
198
            RuntimeCall::Ethereum(call) => call.check_self_contained(),
199
            _ => None,
200
        }
201
    }
202

            
203
    fn validate_self_contained(
204
        &self,
205
        info: &Self::SignedInfo,
206
        dispatch_info: &DispatchInfoOf<RuntimeCall>,
207
        len: usize,
208
    ) -> Option<TransactionValidity> {
209
        match self {
210
            RuntimeCall::Ethereum(call) => call.validate_self_contained(info, dispatch_info, len),
211
            _ => None,
212
        }
213
    }
214

            
215
    fn pre_dispatch_self_contained(
216
        &self,
217
        info: &Self::SignedInfo,
218
        dispatch_info: &DispatchInfoOf<RuntimeCall>,
219
        len: usize,
220
    ) -> Option<Result<(), TransactionValidityError>> {
221
        match self {
222
            RuntimeCall::Ethereum(call) => {
223
                call.pre_dispatch_self_contained(info, dispatch_info, len)
224
            }
225
            _ => None,
226
        }
227
    }
228

            
229
    fn apply_self_contained(
230
        self,
231
        info: Self::SignedInfo,
232
    ) -> Option<sp_runtime::DispatchResultWithInfo<PostDispatchInfoOf<Self>>> {
233
        match self {
234
            call @ RuntimeCall::Ethereum(pallet_ethereum::Call::transact { .. }) => {
235
                Some(call.dispatch(RuntimeOrigin::from(
236
                    pallet_ethereum::RawOrigin::EthereumTransaction(info),
237
                )))
238
            }
239
            _ => None,
240
        }
241
    }
242
}
243

            
244
#[derive(Clone)]
245
pub struct TransactionConverter;
246

            
247
impl fp_rpc::ConvertTransaction<UncheckedExtrinsic> for TransactionConverter {
248
    fn convert_transaction(&self, transaction: pallet_ethereum::Transaction) -> UncheckedExtrinsic {
249
        UncheckedExtrinsic::new_unsigned(
250
            pallet_ethereum::Call::<Runtime>::transact { transaction }.into(),
251
        )
252
    }
253
}
254

            
255
impl fp_rpc::ConvertTransaction<opaque::UncheckedExtrinsic> for TransactionConverter {
256
    fn convert_transaction(
257
        &self,
258
        transaction: pallet_ethereum::Transaction,
259
    ) -> opaque::UncheckedExtrinsic {
260
        let extrinsic = UncheckedExtrinsic::new_unsigned(
261
            pallet_ethereum::Call::<Runtime>::transact { transaction }.into(),
262
        );
263
        let encoded = extrinsic.encode();
264
        opaque::UncheckedExtrinsic::decode(&mut &encoded[..])
265
            .expect("Encoded extrinsic is always valid")
266
    }
267
}
268

            
269
/// Handles converting a weight scalar to a fee value, based on the scale and granularity of the
270
/// node's balance type.
271
///
272
/// This should typically create a mapping between the following ranges:
273
///   - `[0, MAXIMUM_BLOCK_WEIGHT]`
274
///   - `[Balance::min, Balance::max]`
275
///
276
/// Yet, it can be used for any other sort of change to weight-fee. Some examples being:
277
///   - Setting it to `0` will essentially disable the weight fee.
278
///   - Setting it to `1` will cause the literal `#[weight = x]` values to be charged.
279
pub struct WeightToFee;
280
impl WeightToFeePolynomial for WeightToFee {
281
    type Balance = Balance;
282
30
    fn polynomial() -> WeightToFeeCoefficients<Self::Balance> {
283
30
        // in Rococo, extrinsic base weight (smallest non-zero weight) is mapped to 1 MILLIUNIT:
284
30
        // in our template, we map to 1/10 of that, or 1/10 MILLIUNIT
285
30
        let p = currency::MILLIUNIT / 10;
286
30
        let q = 100 * Balance::from(ExtrinsicBaseWeight::get().ref_time());
287
30
        smallvec![WeightToFeeCoefficient {
288
            degree: 1,
289
            negative: false,
290
            coeff_frac: Perbill::from_rational(p % q, q),
291
            coeff_integer: p / q,
292
        }]
293
30
    }
294
}
295

            
296
/// Opaque types. These are used by the CLI to instantiate machinery that don't need to know
297
/// the specifics of the runtime. They can then be made to be agnostic over specific formats
298
/// of data like extrinsics, allowing for them to continue syncing the network through upgrades
299
/// to even the core data structures.
300
pub mod opaque {
301
    use {
302
        super::*,
303
        sp_runtime::{generic, traits::BlakeTwo256},
304
    };
305

            
306
    pub use sp_runtime::OpaqueExtrinsic as UncheckedExtrinsic;
307
    /// Opaque block header type.
308
    pub type Header = generic::Header<BlockNumber, BlakeTwo256>;
309
    /// Opaque block type.
310
    pub type Block = generic::Block<Header, UncheckedExtrinsic>;
311
    /// Opaque block identifier type.
312
    pub type BlockId = generic::BlockId<Block>;
313
}
314

            
315
mod impl_on_charge_evm_transaction;
316

            
317
impl_opaque_keys! {
318
    pub struct SessionKeys { }
319
}
320

            
321
#[sp_version::runtime_version]
322
pub const VERSION: RuntimeVersion = RuntimeVersion {
323
    spec_name: create_runtime_str!("frontier-template"),
324
    impl_name: create_runtime_str!("frontier-template"),
325
    authoring_version: 1,
326
    spec_version: 700,
327
    impl_version: 0,
328
    apis: RUNTIME_API_VERSIONS,
329
    transaction_version: 1,
330
    state_version: 1,
331
};
332

            
333
/// This determines the average expected block time that we are targeting.
334
/// Blocks will be produced at a minimum duration defined by `SLOT_DURATION`.
335
/// `SLOT_DURATION` is picked up by `pallet_timestamp` which is in turn picked
336
/// up by `pallet_aura` to implement `fn slot_duration()`.
337
///
338
/// Change this to adjust the block time.
339
pub const MILLISECS_PER_BLOCK: u64 = 6000;
340

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

            
345
// Time is measured by number of blocks.
346
pub const MINUTES: BlockNumber = 60_000 / (MILLISECS_PER_BLOCK as BlockNumber);
347
pub const HOURS: BlockNumber = MINUTES * 60;
348
pub const DAYS: BlockNumber = HOURS * 24;
349

            
350
/// The existential deposit. Set to 0 because this is an ethereum-like chain
351
/// We set this to one for runtime-benchmarks because plenty of the benches we
352
/// incorporate from parity assume ED != 0
353
#[cfg(feature = "runtime-benchmarks")]
354
pub const EXISTENTIAL_DEPOSIT: Balance = 1 * currency::MILLIUNIT;
355
#[cfg(not(feature = "runtime-benchmarks"))]
356
pub const EXISTENTIAL_DEPOSIT: Balance = 0;
357

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

            
362
/// We allow `Normal` extrinsics to fill up the block up to 75%, the rest can be used by
363
/// `Operational` extrinsics.
364
const NORMAL_DISPATCH_RATIO: Perbill = Perbill::from_percent(75);
365

            
366
/// We allow for 0.5 of a second of compute with a 12 second average block time.
367
const MAXIMUM_BLOCK_WEIGHT: Weight = Weight::from_parts(
368
    WEIGHT_REF_TIME_PER_SECOND.saturating_div(2),
369
    cumulus_primitives_core::relay_chain::MAX_POV_SIZE as u64,
370
);
371

            
372
/// We allow for 500ms of compute with a 12 second average block time.
373
pub const WEIGHT_MILLISECS_PER_BLOCK: u64 = 500;
374

            
375
/// The version information used to identify this runtime when compiled natively.
376
#[cfg(feature = "std")]
377
pub fn native_version() -> NativeVersion {
378
    NativeVersion {
379
        runtime_version: VERSION,
380
        can_author_with: Default::default(),
381
    }
382
}
383

            
384
parameter_types! {
385
    pub const Version: RuntimeVersion = VERSION;
386

            
387
    // This part is copied from Substrate's `bin/node/runtime/src/lib.rs`.
388
    //  The `RuntimeBlockLength` and `RuntimeBlockWeights` exist here because the
389
    // `DeletionWeightLimit` and `DeletionQueueDepth` depend on those to parameterize
390
    // the lazy contract deletion.
391
    pub RuntimeBlockLength: BlockLength =
392
        BlockLength::max_with_normal_ratio(5 * 1024 * 1024, NORMAL_DISPATCH_RATIO);
393
    pub RuntimeBlockWeights: BlockWeights = BlockWeights::builder()
394
        .base_block(BlockExecutionWeight::get())
395
18
        .for_class(DispatchClass::all(), |weights| {
396
18
            weights.base_extrinsic = ExtrinsicBaseWeight::get();
397
18
        })
398
6
        .for_class(DispatchClass::Normal, |weights| {
399
6
            weights.max_total = Some(NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT);
400
6
        })
401
6
        .for_class(DispatchClass::Operational, |weights| {
402
6
            weights.max_total = Some(MAXIMUM_BLOCK_WEIGHT);
403
6
            // Operational transactions have some extra reserved space, so that they
404
6
            // are included even if block reached `MAXIMUM_BLOCK_WEIGHT`.
405
6
            weights.reserved = Some(
406
6
                MAXIMUM_BLOCK_WEIGHT - NORMAL_DISPATCH_RATIO * MAXIMUM_BLOCK_WEIGHT
407
6
            );
408
6
        })
409
        .avg_block_initialization(AVERAGE_ON_INITIALIZE_RATIO)
410
        .build_or_panic();
411
    pub const SS58Prefix: u16 = 42;
412
}
413

            
414
// Configure FRAME pallets to include in runtime.
415
impl frame_system::Config for Runtime {
416
    /// The identifier used to distinguish between accounts.
417
    type AccountId = AccountId;
418
    /// The aggregated dispatch type that is available for extrinsics.
419
    type RuntimeCall = RuntimeCall;
420
    /// The lookup mechanism to get account ID from whatever is passed in dispatchers.
421
    type Lookup = IdentityLookup<AccountId>;
422
    /// The index type for storing how many extrinsics an account has signed.
423
    type Nonce = Index;
424
    /// The index type for blocks.
425
    type Block = Block;
426
    /// The type for hashing blocks and tries.
427
    type Hash = Hash;
428
    /// The hashing algorithm used.
429
    type Hashing = BlakeTwo256;
430
    /// The ubiquitous event type.
431
    type RuntimeEvent = RuntimeEvent;
432
    /// The ubiquitous origin type.
433
    type RuntimeOrigin = RuntimeOrigin;
434
    /// Maximum number of block number to block hash mappings to keep (oldest pruned first).
435
    type BlockHashCount = BlockHashCount;
436
    /// Runtime version.
437
    type Version = Version;
438
    /// Converts a module to an index of this module in the runtime.
439
    type PalletInfo = PalletInfo;
440
    /// The data to be stored in an account.
441
    type AccountData = pallet_balances::AccountData<Balance>;
442
    /// What to do if a new account is created.
443
    type OnNewAccount = ();
444
    /// What to do if an account is fully reaped from the system.
445
    type OnKilledAccount = ();
446
    /// The weight of database operations that the runtime can invoke.
447
    type DbWeight = RocksDbWeight;
448
    /// The basic call filter to use in dispatchable.
449
    type BaseCallFilter = InsideBoth<MaintenanceMode, TxPause>;
450
    /// Weight information for the extrinsics of this pallet.
451
    type SystemWeightInfo = weights::frame_system::SubstrateWeight<Runtime>;
452
    /// Block & extrinsics weights: base values and limits.
453
    type BlockWeights = RuntimeBlockWeights;
454
    /// The maximum length of a block (in bytes).
455
    type BlockLength = RuntimeBlockLength;
456
    /// This is used as an identifier of the chain. 42 is the generic substrate prefix.
457
    type SS58Prefix = SS58Prefix;
458
    /// The action to take on a Runtime Upgrade
459
    type OnSetCode = cumulus_pallet_parachain_system::ParachainSetCode<Self>;
460
    type MaxConsumers = frame_support::traits::ConstU32<16>;
461
    type RuntimeTask = RuntimeTask;
462
    type SingleBlockMigrations = ();
463
    type MultiBlockMigrator = ();
464
    type PreInherents = ();
465
    type PostInherents = ();
466
    type PostTransactions = ();
467
}
468

            
469
parameter_types! {
470
    pub const TransactionByteFee: Balance = 1;
471
}
472

            
473
impl pallet_transaction_payment::Config for Runtime {
474
    type RuntimeEvent = RuntimeEvent;
475
    // This will burn the fees
476
    type OnChargeTransaction = FungibleAdapter<Balances, ()>;
477
    type OperationalFeeMultiplier = ConstU8<5>;
478
    type WeightToFee = WeightToFee;
479
    type LengthToFee = ConstantMultiplier<Balance, TransactionByteFee>;
480
    type FeeMultiplierUpdate = SlowAdjustingFeeUpdate<Self>;
481
}
482

            
483
parameter_types! {
484
    pub const ExistentialDeposit: Balance = EXISTENTIAL_DEPOSIT;
485
}
486

            
487
impl pallet_balances::Config for Runtime {
488
    type MaxLocks = ConstU32<50>;
489
    /// The type for recording an account's balance.
490
    type Balance = Balance;
491
    /// The ubiquitous event type.
492
    type RuntimeEvent = RuntimeEvent;
493
    type DustRemoval = ();
494
    type ExistentialDeposit = ExistentialDeposit;
495
    type AccountStore = System;
496
    type MaxReserves = ConstU32<50>;
497
    type ReserveIdentifier = [u8; 8];
498
    type FreezeIdentifier = RuntimeFreezeReason;
499
    type MaxFreezes = ConstU32<0>;
500
    type RuntimeHoldReason = RuntimeHoldReason;
501
    type RuntimeFreezeReason = RuntimeFreezeReason;
502
    type WeightInfo = weights::pallet_balances::SubstrateWeight<Runtime>;
503
}
504

            
505
parameter_types! {
506
    pub const ReservedXcmpWeight: Weight = MAXIMUM_BLOCK_WEIGHT.saturating_div(4);
507
    pub const ReservedDmpWeight: Weight = MAXIMUM_BLOCK_WEIGHT.saturating_div(4);
508
    pub const RelayOrigin: AggregateMessageOrigin = AggregateMessageOrigin::Parent;
509
}
510

            
511
pub const RELAY_CHAIN_SLOT_DURATION_MILLIS: u32 = 6000;
512
pub const UNINCLUDED_SEGMENT_CAPACITY: u32 = 3;
513
pub const BLOCK_PROCESSING_VELOCITY: u32 = 1;
514

            
515
type ConsensusHook = pallet_async_backing::consensus_hook::FixedVelocityConsensusHook<
516
    Runtime,
517
    BLOCK_PROCESSING_VELOCITY,
518
    UNINCLUDED_SEGMENT_CAPACITY,
519
>;
520

            
521
impl cumulus_pallet_parachain_system::Config for Runtime {
522
    type WeightInfo = weights::cumulus_pallet_parachain_system::SubstrateWeight<Runtime>;
523
    type RuntimeEvent = RuntimeEvent;
524
    type OnSystemEvent = ();
525
    type SelfParaId = parachain_info::Pallet<Runtime>;
526
    type OutboundXcmpMessageSource = XcmpQueue;
527
    type DmpQueue = frame_support::traits::EnqueueWithOrigin<MessageQueue, RelayOrigin>;
528
    type ReservedDmpWeight = ReservedDmpWeight;
529
    type XcmpMessageHandler = XcmpQueue;
530
    type ReservedXcmpWeight = ReservedXcmpWeight;
531
    type CheckAssociatedRelayNumber = RelayNumberMonotonicallyIncreases;
532
    type ConsensusHook = ConsensusHook;
533
}
534

            
535
pub struct ParaSlotProvider;
536
impl Get<(Slot, SlotDuration)> for ParaSlotProvider {
537
104
    fn get() -> (Slot, SlotDuration) {
538
104
        let slot = u64::from(<Runtime as pallet_author_inherent::Config>::SlotBeacon::slot());
539
104
        (Slot::from(slot), SlotDuration::from_millis(SLOT_DURATION))
540
104
    }
541
}
542

            
543
parameter_types! {
544
    pub const ExpectedBlockTime: u64 = MILLISECS_PER_BLOCK;
545
}
546

            
547
impl pallet_async_backing::Config for Runtime {
548
    type AllowMultipleBlocksPerSlot = ConstBool<true>;
549
    type GetAndVerifySlot =
550
        pallet_async_backing::ParaSlot<RELAY_CHAIN_SLOT_DURATION_MILLIS, ParaSlotProvider>;
551
    type ExpectedBlockTime = ExpectedBlockTime;
552
}
553

            
554
impl parachain_info::Config for Runtime {}
555

            
556
parameter_types! {
557
    pub const Period: u32 = 6 * HOURS;
558
    pub const Offset: u32 = 0;
559
}
560

            
561
impl pallet_sudo::Config for Runtime {
562
    type RuntimeCall = RuntimeCall;
563
    type RuntimeEvent = RuntimeEvent;
564
    type WeightInfo = weights::pallet_sudo::SubstrateWeight<Runtime>;
565
}
566

            
567
impl pallet_utility::Config for Runtime {
568
    type RuntimeEvent = RuntimeEvent;
569
    type RuntimeCall = RuntimeCall;
570
    type PalletsOrigin = OriginCaller;
571
    type WeightInfo = weights::pallet_utility::SubstrateWeight<Runtime>;
572
}
573

            
574
/// The type used to represent the kinds of proxying allowed.
575
#[cfg_attr(feature = "std", derive(serde::Serialize, serde::Deserialize))]
576
#[derive(
577
    Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Encode, Decode, Debug, MaxEncodedLen, TypeInfo,
578
)]
579
#[allow(clippy::unnecessary_cast)]
580
pub enum ProxyType {
581
    /// All calls can be proxied. This is the trivial/most permissive filter.
582
    Any = 0,
583
    /// Only extrinsics that do not transfer funds.
584
    NonTransfer = 1,
585
    /// Only extrinsics related to governance (democracy and collectives).
586
    Governance = 2,
587
    /// Allow to veto an announced proxy call.
588
    CancelProxy = 3,
589
    /// Allow extrinsic related to Balances.
590
    Balances = 4,
591
}
592

            
593
impl Default for ProxyType {
594
    fn default() -> Self {
595
        Self::Any
596
    }
597
}
598

            
599
// Be careful: Each time this filter is modified, the substrate filter must also be modified
600
// consistently.
601
impl pallet_evm_precompile_proxy::EvmProxyCallFilter for ProxyType {
602
    fn is_evm_proxy_call_allowed(
603
        &self,
604
        call: &pallet_evm_precompile_proxy::EvmSubCall,
605
        recipient_has_code: bool,
606
        gas: u64,
607
    ) -> precompile_utils::EvmResult<bool> {
608
        Ok(match self {
609
            ProxyType::Any => true,
610
            ProxyType::NonTransfer => false,
611
            ProxyType::Governance => false,
612
            // The proxy precompile does not contain method cancel_proxy
613
            ProxyType::CancelProxy => false,
614
            ProxyType::Balances => {
615
                // Allow only "simple" accounts as recipient (no code nor precompile).
616
                // Note: Checking the presence of the code is not enough because some precompiles
617
                // have no code.
618
                !recipient_has_code
619
                    && !precompile_utils::precompile_set::is_precompile_or_fail::<Runtime>(
620
                        call.to.0, gas,
621
                    )?
622
            }
623
        })
624
    }
625
}
626

            
627
impl InstanceFilter<RuntimeCall> for ProxyType {
628
    fn filter(&self, c: &RuntimeCall) -> bool {
629
        // Since proxy filters are respected in all dispatches of the Utility
630
        // pallet, it should never need to be filtered by any proxy.
631
        if let RuntimeCall::Utility(..) = c {
632
            return true;
633
        }
634

            
635
        match self {
636
            ProxyType::Any => true,
637
            ProxyType::NonTransfer => {
638
                matches!(
639
                    c,
640
                    RuntimeCall::System(..)
641
                        | RuntimeCall::ParachainSystem(..)
642
                        | RuntimeCall::Timestamp(..)
643
                        | RuntimeCall::Proxy(..)
644
                )
645
            }
646
            // We don't have governance yet
647
            ProxyType::Governance => false,
648
            ProxyType::CancelProxy => matches!(
649
                c,
650
                RuntimeCall::Proxy(pallet_proxy::Call::reject_announcement { .. })
651
            ),
652
            ProxyType::Balances => {
653
                matches!(c, RuntimeCall::Balances(..))
654
            }
655
        }
656
    }
657

            
658
    fn is_superset(&self, o: &Self) -> bool {
659
        match (self, o) {
660
            (x, y) if x == y => true,
661
            (ProxyType::Any, _) => true,
662
            (_, ProxyType::Any) => false,
663
            _ => false,
664
        }
665
    }
666
}
667

            
668
impl pallet_proxy::Config for Runtime {
669
    type RuntimeEvent = RuntimeEvent;
670
    type RuntimeCall = RuntimeCall;
671
    type Currency = Balances;
672
    type ProxyType = ProxyType;
673
    // One storage item; key size 32, value size 8
674
    type ProxyDepositBase = ConstU128<{ currency::deposit(1, 8) }>;
675
    // Additional storage item size of 21 bytes (20 bytes AccountId + 1 byte sizeof(ProxyType)).
676
    type ProxyDepositFactor = ConstU128<{ currency::deposit(0, 21) }>;
677
    type MaxProxies = ConstU32<32>;
678
    type MaxPending = ConstU32<32>;
679
    type CallHasher = BlakeTwo256;
680
    type AnnouncementDepositBase = ConstU128<{ currency::deposit(1, 8) }>;
681
    // Additional storage item size of 56 bytes:
682
    // - 20 bytes AccountId
683
    // - 32 bytes Hasher (Blake2256)
684
    // - 4 bytes BlockNumber (u32)
685
    type AnnouncementDepositFactor = ConstU128<{ currency::deposit(0, 56) }>;
686
    type WeightInfo = weights::pallet_proxy::SubstrateWeight<Runtime>;
687
}
688

            
689
pub struct XcmExecutionManager;
690
impl xcm_primitives::PauseXcmExecution for XcmExecutionManager {
691
    fn suspend_xcm_execution() -> DispatchResult {
692
        XcmpQueue::suspend_xcm_execution(RuntimeOrigin::root())
693
    }
694
    fn resume_xcm_execution() -> DispatchResult {
695
        XcmpQueue::resume_xcm_execution(RuntimeOrigin::root())
696
    }
697
}
698

            
699
impl pallet_migrations::Config for Runtime {
700
    type RuntimeEvent = RuntimeEvent;
701
    type MigrationsList = (migrations::TemplateMigrations<Runtime, XcmpQueue, PolkadotXcm>,);
702
    type XcmExecutionManager = XcmExecutionManager;
703
}
704

            
705
/// Maintenance mode Call filter
706
pub struct MaintenanceFilter;
707
impl Contains<RuntimeCall> for MaintenanceFilter {
708
    fn contains(c: &RuntimeCall) -> bool {
709
        !matches!(
710
            c,
711
            RuntimeCall::Balances(_)
712
                | RuntimeCall::Ethereum(_)
713
                | RuntimeCall::EVM(_)
714
                | RuntimeCall::PolkadotXcm(_)
715
        )
716
    }
717
}
718

            
719
/// Normal Call Filter
720
/// We dont allow to create nor mint assets, this for now is disabled
721
/// We only allow transfers. For now creation of assets will go through
722
/// asset-manager, while minting/burning only happens through xcm messages
723
/// This can change in the future
724
pub struct NormalFilter;
725
impl Contains<RuntimeCall> for NormalFilter {
726
    fn contains(c: &RuntimeCall) -> bool {
727
        !matches!(
728
            c,
729
            // Filtering the EVM prevents possible re-entrancy from the precompiles which could
730
            // lead to unexpected scenarios.
731
            // See https://github.com/PureStake/sr-moonbeam/issues/30
732
            // Note: It is also assumed that EVM calls are only allowed through `Origin::Root` so
733
            // this can be seen as an additional security
734
            RuntimeCall::EVM(_)
735
        )
736
    }
737
}
738

            
739
impl pallet_maintenance_mode::Config for Runtime {
740
    type RuntimeEvent = RuntimeEvent;
741
    type NormalCallFilter = NormalFilter;
742
    type MaintenanceCallFilter = MaintenanceFilter;
743
    type MaintenanceOrigin = EnsureRoot<AccountId>;
744
    type XcmExecutionManager = XcmExecutionManager;
745
}
746

            
747
#[dynamic_params(RuntimeParameters, pallet_parameters::Parameters::<Runtime>)]
748
pub mod dynamic_params {
749
    use super::*;
750

            
751
    #[dynamic_pallet_params]
752
    #[codec(index = 3)]
753
    pub mod contract_deploy_filter {
754
        #[codec(index = 0)]
755
        pub static AllowedAddressesToCreate: DeployFilter = DeployFilter::All;
756
        #[codec(index = 1)]
757
        pub static AllowedAddressesToCreateInner: DeployFilter = DeployFilter::All;
758
    }
759
}
760

            
761
impl pallet_parameters::Config for Runtime {
762
    type AdminOrigin = EnsureRoot<AccountId>;
763
    type RuntimeEvent = RuntimeEvent;
764
    type RuntimeParameters = RuntimeParameters;
765
    type WeightInfo = weights::pallet_parameters::SubstrateWeight<Runtime>;
766
}
767

            
768
#[cfg(feature = "runtime-benchmarks")]
769
impl Default for RuntimeParameters {
770
    fn default() -> Self {
771
        RuntimeParameters::ContractDeployFilter(
772
            dynamic_params::contract_deploy_filter::Parameters::AllowedAddressesToCreate(
773
                dynamic_params::contract_deploy_filter::AllowedAddressesToCreate,
774
                Some(DeployFilter::All),
775
            ),
776
        )
777
    }
778
}
779

            
780
#[derive(Clone, PartialEq, Encode, Decode, TypeInfo, Eq, MaxEncodedLen, Debug)]
781
pub enum DeployFilter {
782
    All,
783
    Whitelisted(BoundedVec<H160, ConstU32<100>>),
784
}
785

            
786
pub struct AddressFilter<Runtime, AddressList>(sp_std::marker::PhantomData<(Runtime, AddressList)>);
787
impl<Runtime, AddressList> EnsureCreateOrigin<Runtime> for AddressFilter<Runtime, AddressList>
788
where
789
    Runtime: pallet_evm::Config,
790
    AddressList: Get<DeployFilter>,
791
{
792
    fn check_create_origin(address: &H160) -> Result<(), pallet_evm::Error<Runtime>> {
793
        let deploy_filter: DeployFilter = AddressList::get();
794

            
795
        match deploy_filter {
796
            DeployFilter::All => Ok(()),
797
            DeployFilter::Whitelisted(addresses_vec) => {
798
                if !addresses_vec.contains(address) {
799
                    Err(pallet_evm::Error::<Runtime>::CreateOriginNotAllowed)
800
                } else {
801
                    Ok(())
802
                }
803
            }
804
        }
805
    }
806
}
807

            
808
// To match ethereum expectations
809
const BLOCK_GAS_LIMIT: u64 = 15_000_000;
810

            
811
impl pallet_evm_chain_id::Config for Runtime {}
812

            
813
pub struct FindAuthorAdapter;
814
impl FindAuthor<H160> for FindAuthorAdapter {
815
153
    fn find_author<'a, I>(digests: I) -> Option<H160>
816
153
    where
817
153
        I: 'a + IntoIterator<Item = (sp_runtime::ConsensusEngineId, &'a [u8])>,
818
153
    {
819
153
        if let Some(author) = AuthorInherent::find_author(digests) {
820
            return Some(H160::from_slice(&author.encode()[0..20]));
821
153
        }
822
153
        None
823
153
    }
824
}
825

            
826
parameter_types! {
827
    pub BlockGasLimit: U256 = U256::from(BLOCK_GAS_LIMIT);
828
    pub PrecompilesValue: TemplatePrecompiles<Runtime> = TemplatePrecompiles::<_>::new();
829
    pub WeightPerGas: Weight = Weight::from_parts(weight_per_gas(BLOCK_GAS_LIMIT, NORMAL_DISPATCH_RATIO, WEIGHT_MILLISECS_PER_BLOCK), 0);
830
    pub SuicideQuickClearLimit: u32 = 0;
831
}
832

            
833
impl_on_charge_evm_transaction!();
834
impl pallet_evm::Config for Runtime {
835
    type FeeCalculator = BaseFee;
836
    type GasWeightMapping = pallet_evm::FixedGasWeightMapping<Self>;
837
    type WeightPerGas = WeightPerGas;
838
    type BlockHashMapping = pallet_ethereum::EthereumBlockHashMapping<Self>;
839
    type CallOrigin = EnsureAddressRoot<AccountId>;
840
    type WithdrawOrigin = EnsureAddressNever<AccountId>;
841
    type AddressMapping = IdentityAddressMapping;
842
    type CreateOrigin =
843
        AddressFilter<Runtime, dynamic_params::contract_deploy_filter::AllowedAddressesToCreate>;
844
    type CreateInnerOrigin = AddressFilter<
845
        Runtime,
846
        dynamic_params::contract_deploy_filter::AllowedAddressesToCreateInner,
847
    >;
848
    type Currency = Balances;
849
    type RuntimeEvent = RuntimeEvent;
850
    type PrecompilesType = TemplatePrecompiles<Self>;
851
    type PrecompilesValue = PrecompilesValue;
852
    type ChainId = EVMChainId;
853
    type BlockGasLimit = BlockGasLimit;
854
    type Runner = pallet_evm::runner::stack::Runner<Self>;
855
    type OnChargeTransaction = OnChargeEVMTransaction<()>;
856
    type OnCreate = ();
857
    type FindAuthor = FindAuthorAdapter;
858
    // TODO: update in the future
859
    type GasLimitPovSizeRatio = ();
860
    type SuicideQuickClearLimit = SuicideQuickClearLimit;
861
    type Timestamp = Timestamp;
862
    type WeightInfo = ();
863
}
864

            
865
parameter_types! {
866
    pub const PostBlockAndTxnHashes: PostLogContent = PostLogContent::BlockAndTxnHashes;
867
}
868

            
869
impl pallet_ethereum::Config for Runtime {
870
    type RuntimeEvent = RuntimeEvent;
871
    type StateRoot = pallet_ethereum::IntermediateStateRoot<Self>;
872
    type PostLogContent = PostBlockAndTxnHashes;
873
    type ExtraDataLength = ConstU32<30>;
874
}
875

            
876
parameter_types! {
877
    pub BoundDivision: U256 = U256::from(1024);
878
}
879

            
880
parameter_types! {
881
    pub DefaultBaseFeePerGas: U256 = U256::from(2_000_000_000);
882
    pub DefaultElasticity: Permill = Permill::from_parts(125_000);
883
}
884

            
885
pub struct BaseFeeThreshold;
886
impl pallet_base_fee::BaseFeeThreshold for BaseFeeThreshold {
887
    fn lower() -> Permill {
888
        Permill::zero()
889
    }
890
    fn ideal() -> Permill {
891
        Permill::from_parts(500_000)
892
    }
893
    fn upper() -> Permill {
894
        Permill::from_parts(1_000_000)
895
    }
896
}
897

            
898
impl pallet_base_fee::Config for Runtime {
899
    type RuntimeEvent = RuntimeEvent;
900
    type Threshold = BaseFeeThreshold;
901
    type DefaultBaseFeePerGas = DefaultBaseFeePerGas;
902
    type DefaultElasticity = DefaultElasticity;
903
}
904

            
905
impl pallet_root_testing::Config for Runtime {
906
    type RuntimeEvent = RuntimeEvent;
907
}
908

            
909
impl pallet_tx_pause::Config for Runtime {
910
    type RuntimeEvent = RuntimeEvent;
911
    type RuntimeCall = RuntimeCall;
912
    type PauseOrigin = EnsureRoot<AccountId>;
913
    type UnpauseOrigin = EnsureRoot<AccountId>;
914
    type WhitelistedCalls = ();
915
    type MaxNameLen = ConstU32<256>;
916
    type WeightInfo = weights::pallet_tx_pause::SubstrateWeight<Runtime>;
917
}
918

            
919
impl dp_impl_tanssi_pallets_config::Config for Runtime {
920
    const SLOT_DURATION: u64 = SLOT_DURATION;
921
    type TimestampWeights = weights::pallet_timestamp::SubstrateWeight<Runtime>;
922
    type AuthorInherentWeights = weights::pallet_author_inherent::SubstrateWeight<Runtime>;
923
    type AuthoritiesNotingWeights = weights::pallet_cc_authorities_noting::SubstrateWeight<Runtime>;
924
}
925

            
926
parameter_types! {
927
    // One storage item; key size 32 + 20; value is size 4+4+16+20. Total = 1 * (52 + 44)
928
    pub const DepositBase: Balance = currency::deposit(1, 96);
929
    // Additional storage item size of 20 bytes.
930
    pub const DepositFactor: Balance = currency::deposit(0, 20);
931
    pub const MaxSignatories: u32 = 100;
932
}
933

            
934
impl pallet_multisig::Config for Runtime {
935
    type RuntimeEvent = RuntimeEvent;
936
    type RuntimeCall = RuntimeCall;
937
    type Currency = Balances;
938
    type DepositBase = DepositBase;
939
    type DepositFactor = DepositFactor;
940
    type MaxSignatories = MaxSignatories;
941
    type WeightInfo = weights::pallet_multisig::SubstrateWeight<Runtime>;
942
}
943

            
944
impl_tanssi_pallets_config!(Runtime);
945

            
946
// Create the runtime by composing the FRAME pallets that were previously configured.
947
18127
construct_runtime!(
948
1908
    pub enum Runtime
949
1908
    {
950
1908
        // System support stuff.
951
1908
        System: frame_system = 0,
952
1908
        ParachainSystem: cumulus_pallet_parachain_system = 1,
953
1908
        Timestamp: pallet_timestamp = 2,
954
1908
        ParachainInfo: parachain_info = 3,
955
1908
        Sudo: pallet_sudo = 4,
956
1908
        Utility: pallet_utility = 5,
957
1908
        Proxy: pallet_proxy = 6,
958
1908
        Migrations: pallet_migrations = 7,
959
1908
        MaintenanceMode: pallet_maintenance_mode = 8,
960
1908
        TxPause: pallet_tx_pause = 9,
961
1908

            
962
1908
        // Monetary stuff.
963
1908
        Balances: pallet_balances = 10,
964
1908

            
965
1908
        // Other utilities
966
1908
        Multisig: pallet_multisig = 16,
967
1908
        Parameters: pallet_parameters = 17,
968
1908

            
969
1908
        // ContainerChain
970
1908
        AuthoritiesNoting: pallet_cc_authorities_noting = 50,
971
1908
        AuthorInherent: pallet_author_inherent = 51,
972
1908

            
973
1908
        // Frontier
974
1908
        Ethereum: pallet_ethereum = 60,
975
1908
        EVM: pallet_evm = 61,
976
1908
        EVMChainId: pallet_evm_chain_id = 62,
977
1908
        BaseFee: pallet_base_fee = 64,
978
1908
        TransactionPayment: pallet_transaction_payment = 66,
979
1908

            
980
1908
        // XCM
981
1908
        XcmpQueue: cumulus_pallet_xcmp_queue::{Pallet, Storage, Event<T>} = 70,
982
1908
        CumulusXcm: cumulus_pallet_xcm::{Pallet, Event<T>, Origin} = 71,
983
1908
        DmpQueue: cumulus_pallet_dmp_queue::{Pallet, Call, Storage, Event<T>} = 72,
984
1908
        PolkadotXcm: pallet_xcm::{Pallet, Call, Storage, Event<T>, Origin, Config<T>} = 73,
985
1908
        MessageQueue: pallet_message_queue::{Pallet, Call, Storage, Event<T>} = 74,
986
1908
        ForeignAssets: pallet_assets::<Instance1>::{Pallet, Call, Storage, Event<T>} = 75,
987
1908
        ForeignAssetsCreator: pallet_foreign_asset_creator::{Pallet, Call, Storage, Event<T>} = 76,
988
1908
        AssetRate: pallet_asset_rate::{Pallet, Call, Storage, Event<T>} = 77,
989
1908
        XcmExecutorUtils: pallet_xcm_executor_utils::{Pallet, Call, Storage, Event<T>} = 78,
990
1908

            
991
1908
        RootTesting: pallet_root_testing = 100,
992
1908
        AsyncBacking: pallet_async_backing::{Pallet, Storage} = 110,
993
1908
    }
994
18127
);
995

            
996
#[cfg(feature = "runtime-benchmarks")]
997
mod benches {
998
    frame_benchmarking::define_benchmarks!(
999
        [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_multisig, Multisig]
        [pallet_parameters, Parameters]
        [pallet_cc_authorities_noting, AuthoritiesNoting]
        [pallet_author_inherent, AuthorInherent]
        [cumulus_pallet_xcmp_queue, XcmpQueue]
        [cumulus_pallet_dmp_queue, DmpQueue]
        [pallet_xcm, PalletXcmExtrinsicsBenchmark::<Runtime>]
        [pallet_xcm_benchmarks::generic, pallet_xcm_benchmarks::generic::Pallet::<Runtime>]
        [pallet_message_queue, MessageQueue]
        [pallet_assets, ForeignAssets]
        [pallet_foreign_asset_creator, ForeignAssetsCreator]
        [pallet_asset_rate, AssetRate]
        [pallet_xcm_executor_utils, XcmExecutorUtils]
    );
}
16564
impl_runtime_apis! {
9032
    impl sp_api::Core<Block> for Runtime {
9032
        fn version() -> RuntimeVersion {
            VERSION
        }
9032

            
9032
        fn execute_block(block: Block) {
            Executive::execute_block(block)
        }
9032

            
9032
        fn initialize_block(header: &<Block as BlockT>::Header) -> sp_runtime::ExtrinsicInclusionMode {
            Executive::initialize_block(header)
        }
9032
    }
9032

            
9032
    impl sp_api::Metadata<Block> for Runtime {
9032
        fn metadata() -> OpaqueMetadata {
            OpaqueMetadata::new(Runtime::metadata().into())
        }
9032

            
9032
        fn metadata_at_version(version: u32) -> Option<OpaqueMetadata> {
            Runtime::metadata_at_version(version)
        }
9032

            
9032
        fn metadata_versions() -> Vec<u32> {
            Runtime::metadata_versions()
        }
9032
    }
9032

            
9032
    impl sp_block_builder::BlockBuilder<Block> for Runtime {
9032
        fn apply_extrinsic(extrinsic: <Block as BlockT>::Extrinsic) -> ApplyExtrinsicResult {
            Executive::apply_extrinsic(extrinsic)
        }
9032

            
9032
        fn finalize_block() -> <Block as BlockT>::Header {
            Executive::finalize_block()
        }
9032

            
9032
        fn inherent_extrinsics(data: sp_inherents::InherentData) -> Vec<<Block as BlockT>::Extrinsic> {
            data.create_extrinsics()
        }
9032

            
9032
        fn check_inherents(
            block: Block,
            data: sp_inherents::InherentData,
        ) -> sp_inherents::CheckInherentsResult {
            data.check_extrinsics(&block)
        }
9032
    }
9032

            
9032
    impl sp_transaction_pool::runtime_api::TaggedTransactionQueue<Block> for Runtime {
9032
        fn validate_transaction(
            source: TransactionSource,
            xt: <Block as BlockT>::Extrinsic,
            block_hash: <Block as BlockT>::Hash,
        ) -> TransactionValidity {
            // Filtered calls should not enter the tx pool as they'll fail if inserted.
            // If this call is not allowed, we return early.
            if !<Runtime as frame_system::Config>::BaseCallFilter::contains(&xt.0.function) {
9032
                return InvalidTransaction::Call.into();
9032
            }
9032

            
9032
            // This runtime uses Substrate's pallet transaction payment. This
9032
            // makes the chain feel like a standard Substrate chain when submitting
9032
            // frame transactions and using Substrate ecosystem tools. It has the downside that
9032
            // transaction are not prioritized by gas_price. The following code reprioritizes
9032
            // transactions to overcome this.
9032
            //
9032
            // A more elegant, ethereum-first solution is
9032
            // a pallet that replaces pallet transaction payment, and allows users
9032
            // to directly specify a gas price rather than computing an effective one.
9032
            // #HopefullySomeday
9032

            
9032
            // First we pass the transactions to the standard FRAME executive. This calculates all the
9032
            // necessary tags, longevity and other properties that we will leave unchanged.
9032
            // This also assigns some priority that we don't care about and will overwrite next.
9032
            let mut intermediate_valid = Executive::validate_transaction(source, xt.clone(), block_hash)?;
9032

            
9032
            let dispatch_info = xt.get_dispatch_info();
9032

            
9032
            // If this is a pallet ethereum transaction, then its priority is already set
9032
            // according to effective priority fee from pallet ethereum. If it is any other kind of
9032
            // transaction, we modify its priority. The goal is to arrive at a similar metric used
9032
            // by pallet ethereum, which means we derive a fee-per-gas from the txn's tip and
9032
            // weight.
9032
            Ok(match &xt.0.function {
9032
                RuntimeCall::Ethereum(transact { .. }) => intermediate_valid,
9032
                _ if dispatch_info.class != DispatchClass::Normal => intermediate_valid,
9032
                _ => {
9032
                    let tip = match xt.0.signature {
9032
                        None => 0,
9032
                        Some((_, _, ref signed_extra)) => {
                            // Yuck, this depends on the index of charge transaction in Signed Extra
                            let charge_transaction = &signed_extra.7;
                            charge_transaction.tip()
9032
                        }
9032
                    };
9032

            
9032
                    let effective_gas =
                        <Runtime as pallet_evm::Config>::GasWeightMapping::weight_to_gas(
                            dispatch_info.weight
                        );
9032
                    let tip_per_gas = if effective_gas > 0 {
9032
                        tip.saturating_div(u128::from(effective_gas))
9032
                    } else {
9032
                        0
9032
                    };
9032

            
9032
                    // Overwrite the original prioritization with this ethereum one
9032
                    intermediate_valid.priority = tip_per_gas as u64;
                    intermediate_valid
9032
                }
9032
            })
9032
        }
9032
    }
9032

            
9032
    impl sp_offchain::OffchainWorkerApi<Block> for Runtime {
9032
        fn offchain_worker(header: &<Block as BlockT>::Header) {
            Executive::offchain_worker(header)
        }
9032
    }
9032

            
9032
    impl sp_session::SessionKeys<Block> for Runtime {
9032
        fn generate_session_keys(seed: Option<Vec<u8>>) -> Vec<u8> {
            SessionKeys::generate(seed)
        }
9032

            
9032
        fn decode_session_keys(
            encoded: Vec<u8>,
        ) -> Option<Vec<(Vec<u8>, sp_core::crypto::KeyTypeId)>> {
            SessionKeys::decode_into_raw_public_keys(&encoded)
        }
9032
    }
9032

            
9032
    impl frame_system_rpc_runtime_api::AccountNonceApi<Block, AccountId, Index> for Runtime {
9032
        fn account_nonce(account: AccountId) -> Index {
            System::account_nonce(account)
        }
9032
    }
9032

            
9032
    impl cumulus_primitives_core::CollectCollationInfo<Block> for Runtime {
9032
        fn collect_collation_info(header: &<Block as BlockT>::Header) -> cumulus_primitives_core::CollationInfo {
            ParachainSystem::collect_collation_info(header)
        }
9032
    }
9032

            
9032
    impl async_backing_primitives::UnincludedSegmentApi<Block> for Runtime {
9032
        fn can_build_upon(
            included_hash: <Block as BlockT>::Hash,
            slot: async_backing_primitives::Slot,
        ) -> bool {
            ConsensusHook::can_build_upon(included_hash, slot)
        }
9032
    }
9032

            
9032
    impl sp_genesis_builder::GenesisBuilder<Block> for Runtime {
9032
        fn build_state(config: Vec<u8>) -> sp_genesis_builder::Result {
            build_state::<RuntimeGenesisConfig>(config)
        }
9032

            
9032
        fn get_preset(id: &Option<sp_genesis_builder::PresetId>) -> Option<Vec<u8>> {
            get_preset::<RuntimeGenesisConfig>(id, |_| None)
        }
9032
        fn preset_names() -> Vec<sp_genesis_builder::PresetId> {
            vec![]
        }
9032
    }
9032

            
9032
    #[cfg(feature = "runtime-benchmarks")]
9032
    impl frame_benchmarking::Benchmark<Block> for Runtime {
9032
        fn benchmark_metadata(
9032
            extra: bool,
9032
        ) -> (
9032
            Vec<frame_benchmarking::BenchmarkList>,
9032
            Vec<frame_support::traits::StorageInfo>,
9032
        ) {
9032
            use frame_benchmarking::{Benchmarking, BenchmarkList};
9032
            use frame_support::traits::StorageInfoTrait;
9032
            use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark;
9032

            
9032
            let mut list = Vec::<BenchmarkList>::new();
9032
            list_benchmarks!(list, extra);
9032

            
9032
            let storage_info = AllPalletsWithSystem::storage_info();
9032
            (list, storage_info)
9032
        }
9032

            
9032
        fn dispatch_benchmark(
9032
            config: frame_benchmarking::BenchmarkConfig,
9032
        ) -> Result<Vec<frame_benchmarking::BenchmarkBatch>, sp_runtime::RuntimeString> {
9032
            use frame_benchmarking::{BenchmarkBatch, Benchmarking, BenchmarkError};
9032
            use sp_core::storage::TrackedStorageKey;
9032
            use staging_xcm::latest::prelude::*;
9032
            impl frame_system_benchmarking::Config for Runtime {
9032
                fn setup_set_code_requirements(code: &sp_std::vec::Vec<u8>) -> Result<(), BenchmarkError> {
9032
                    ParachainSystem::initialize_for_set_code_benchmark(code.len() as u32);
9032
                    Ok(())
9032
                }
9032

            
9032
                fn verify_set_code() {
9032
                    System::assert_last_event(cumulus_pallet_parachain_system::Event::<Runtime>::ValidationFunctionStored.into());
9032
                }
9032
            }
9032
            use xcm_config::SelfReserve;
9032

            
9032
            parameter_types! {
9032
                pub ExistentialDepositAsset: Option<Asset> = Some((
9032
                    SelfReserve::get(),
9032
                    ExistentialDeposit::get()
9032
                ).into());
9032
            }
9032

            
9032
            impl pallet_xcm_benchmarks::Config for Runtime {
9032
                type XcmConfig = xcm_config::XcmConfig;
9032
                type AccountIdConverter = xcm_config::LocationToAccountId;
9032
                type DeliveryHelper = cumulus_primitives_utility::ToParentDeliveryHelper<
9032
                    xcm_config::XcmConfig,
9032
                    ExistentialDepositAsset,
9032
                    xcm_config::PriceForParentDelivery,
9032
                >;
9032
                fn valid_destination() -> Result<Location, BenchmarkError> {
9032
                    Ok(Location::parent())
9032
                }
9032
                fn worst_case_holding(_depositable_count: u32) -> Assets {
9032
                    // We only care for native asset until we support others
9032
                    // TODO: refactor this case once other assets are supported
9032
                    vec![Asset{
9032
                        id: AssetId(SelfReserve::get()),
9032
                        fun: Fungible(u128::MAX),
9032
                    }].into()
9032
                }
9032
            }
9032

            
9032
            impl pallet_xcm_benchmarks::generic::Config for Runtime {
9032
                type TransactAsset = Balances;
9032
                type RuntimeCall = RuntimeCall;
9032

            
9032
                fn worst_case_response() -> (u64, Response) {
9032
                    (0u64, Response::Version(Default::default()))
9032
                }
9032

            
9032
                fn worst_case_asset_exchange() -> Result<(Assets, Assets), BenchmarkError> {
9032
                    Err(BenchmarkError::Skip)
9032
                }
9032

            
9032
                fn universal_alias() -> Result<(Location, Junction), BenchmarkError> {
9032
                    Err(BenchmarkError::Skip)
9032
                }
9032

            
9032
                fn transact_origin_and_runtime_call() -> Result<(Location, RuntimeCall), BenchmarkError> {
9032
                    Ok((Location::parent(), frame_system::Call::remark_with_event { remark: vec![] }.into()))
9032
                }
9032

            
9032
                fn subscribe_origin() -> Result<Location, BenchmarkError> {
9032
                    Ok(Location::parent())
9032
                }
9032

            
9032
                fn fee_asset() -> Result<Asset, BenchmarkError> {
9032
                    Ok(Asset {
9032
                        id: AssetId(SelfReserve::get()),
9032
                        fun: Fungible(ExistentialDeposit::get()*100),
9032
                    })
9032
                }
9032

            
9032
                fn claimable_asset() -> Result<(Location, Location, Assets), BenchmarkError> {
9032
                    let origin = Location::parent();
9032
                    let assets: Assets = (Location::parent(), 1_000u128).into();
9032
                    let ticket = Location { parents: 0, interior: Here };
9032
                    Ok((origin, ticket, assets))
9032
                }
9032

            
9032
                fn unlockable_asset() -> Result<(Location, Location, Asset), BenchmarkError> {
9032
                    Err(BenchmarkError::Skip)
9032
                }
9032

            
9032
                fn export_message_origin_and_destination(
9032
                ) -> Result<(Location, NetworkId, InteriorLocation), BenchmarkError> {
9032
                    Err(BenchmarkError::Skip)
9032
                }
9032

            
9032
                fn alias_origin() -> Result<(Location, Location), BenchmarkError> {
9032
                    Err(BenchmarkError::Skip)
9032
                }
9032
            }
9032

            
9032
            use pallet_xcm::benchmarking::Pallet as PalletXcmExtrinsicsBenchmark;
9032
            impl pallet_xcm::benchmarking::Config for Runtime {
9032
                type DeliveryHelper = ();
9032
                fn get_asset() -> Asset {
9032
                    Asset {
9032
                        id: AssetId(SelfReserve::get()),
9032
                        fun: Fungible(ExistentialDeposit::get()),
9032
                    }
9032
                }
9032

            
9032
                fn reachable_dest() -> Option<Location> {
9032
                    Some(Parent.into())
9032
                }
9032

            
9032
                fn teleportable_asset_and_dest() -> Option<(Asset, Location)> {
9032
                    // Relay/native token can be teleported between AH and Relay.
9032
                    Some((
9032
                        Asset {
9032
                            fun: Fungible(EXISTENTIAL_DEPOSIT),
9032
                            id: Parent.into()
9032
                        },
9032
                        Parent.into(),
9032
                    ))
9032
                }
9032

            
9032
                fn reserve_transferable_asset_and_dest() -> Option<(Asset, Location)> {
9032
                    use xcm_config::SelfReserve;
9032
                    // AH can reserve transfer native token to some random parachain.
9032
                    let random_para_id = 43211234;
9032

            
9032
                    ParachainSystem::open_outbound_hrmp_channel_for_benchmarks_or_tests(
9032
                        random_para_id.into()
9032
                    );
9032
                    let who = frame_benchmarking::whitelisted_caller();
9032
                    // Give some multiple of the existential deposit
9032
                    let balance = EXISTENTIAL_DEPOSIT * 1000;
9032
                    let _ = <Balances as frame_support::traits::Currency<_>>::make_free_balance_be(
9032
                        &who, balance,
9032
                    );
9032
                    Some((
9032
                        Asset {
9032
                            fun: Fungible(balance),
9032
                            id: SelfReserve::get().into()
9032
                        },
9032
                        ParentThen(Parachain(random_para_id).into()).into(),
9032
                    ))
9032
                }
9032

            
9032
                fn set_up_complex_asset_transfer(
9032
                ) -> Option<(Assets, u32, Location, Box<dyn FnOnce()>)> {
9032
                    use xcm_config::SelfReserve;
9032
                    // Transfer to Relay some local AH asset (local-reserve-transfer) while paying
9032
                    // fees using teleported native token.
9032
                    // (We don't care that Relay doesn't accept incoming unknown AH local asset)
9032
                    let dest = Parent.into();
9032

            
9032
                    let fee_amount = EXISTENTIAL_DEPOSIT;
9032
                    let fee_asset: Asset = (SelfReserve::get(), fee_amount).into();
9032

            
9032
                    let who = frame_benchmarking::whitelisted_caller();
9032
                    // Give some multiple of the existential deposit
9032
                    let balance = fee_amount + EXISTENTIAL_DEPOSIT * 1000;
9032
                    let _ = <Balances as frame_support::traits::Currency<_>>::make_free_balance_be(
9032
                        &who, balance,
9032
                    );
9032

            
9032
                    // verify initial balance
9032
                    assert_eq!(Balances::free_balance(who), balance);
9032

            
9032
                    // set up local asset
9032
                    let asset_amount = 10u128;
9032
                    let initial_asset_amount = asset_amount * 10;
9032

            
9032
                    let (asset_id, asset_location) = pallet_foreign_asset_creator::benchmarks::create_default_minted_asset::<Runtime>(
9032
                        initial_asset_amount,
9032
                        who
9032
                    );
9032

            
9032
                    let transfer_asset: Asset = (asset_location, asset_amount).into();
9032

            
9032
                    let assets: Assets = vec![fee_asset.clone(), transfer_asset].into();
9032
                    let fee_index = if assets.get(0).unwrap().eq(&fee_asset) { 0 } else { 1 };
9032

            
9032
                    // verify transferred successfully
9032
                    let verify = Box::new(move || {
9032
                        // verify native balance after transfer, decreased by transferred fee amount
9032
                        // (plus transport fees)
9032
                        assert!(Balances::free_balance(who) <= balance - fee_amount);
9032
                        // verify asset balance decreased by exactly transferred amount
9032
                        assert_eq!(
9032
                            ForeignAssets::balance(asset_id, who),
9032
                            initial_asset_amount - asset_amount,
9032
                        );
9032
                    });
9032
                    Some((assets, fee_index as u32, dest, verify))
9032
                }
9032
            }
9032

            
9032
            let whitelist: Vec<TrackedStorageKey> = vec![
9032
                // Block Number
9032
                hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef702a5c1b19ab7a04f536c519aca4983ac")
9032
                    .to_vec()
9032
                    .into(),
9032
                // Total Issuance
9032
                hex_literal::hex!("c2261276cc9d1f8598ea4b6a74b15c2f57c875e4cff74148e4628f264b974c80")
9032
                    .to_vec()
9032
                    .into(),
9032
                // Execution Phase
9032
                hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef7ff553b5a9862a516939d82b3d3d8661a")
9032
                    .to_vec()
9032
                    .into(),
9032
                // Event Count
9032
                hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef70a98fdbe9ce6c55837576c60c7af3850")
9032
                    .to_vec()
9032
                    .into(),
9032
                // System Events
9032
                hex_literal::hex!("26aa394eea5630e07c48ae0c9558cef780d41e5e16056765bc8461851072c9d7")
9032
                    .to_vec()
9032
                    .into(),
9032
                // The transactional storage limit.
9032
                hex_literal::hex!("3a7472616e73616374696f6e5f6c6576656c3a")
9032
                    .to_vec()
9032
                    .into(),
9032

            
9032
                // ParachainInfo ParachainId
9032
                hex_literal::hex!(  "0d715f2646c8f85767b5d2764bb2782604a74d81251e398fd8a0a4d55023bb3f")
9032
                    .to_vec()
9032
                    .into(),
9032
            ];
9032

            
9032
            let mut batches = Vec::<BenchmarkBatch>::new();
9032
            let params = (&config, &whitelist);
9032

            
9032
            add_benchmarks!(params, batches);
9032

            
9032
            Ok(batches)
9032
        }
9032
    }
9032

            
9032
    #[cfg(feature = "try-runtime")]
9032
    impl frame_try_runtime::TryRuntime<Block> for Runtime {
9032
        fn on_runtime_upgrade(checks: frame_try_runtime::UpgradeCheckSelect) -> (Weight, Weight) {
9032
            let weight = Executive::try_runtime_upgrade(checks).unwrap();
9032
            (weight, RuntimeBlockWeights::get().max_block)
9032
        }
9032

            
9032
        fn execute_block(
9032
            block: Block,
9032
            state_root_check: bool,
9032
            signature_check: bool,
9032
            select: frame_try_runtime::TryStateSelect,
9032
        ) -> Weight {
9032
            // NOTE: intentional unwrap: we don't want to propagate the error backwards, and want to
9032
            // have a backtrace here.
9032
            Executive::try_execute_block(block, state_root_check, signature_check, select).unwrap()
9032
        }
9032
    }
9032

            
9032
    impl fp_rpc::EthereumRuntimeRPCApi<Block> for Runtime {
9032
        fn chain_id() -> u64 {
            <Runtime as pallet_evm::Config>::ChainId::get()
        }
9032

            
9032
        fn account_basic(address: H160) -> EVMAccount {
            let (account, _) = pallet_evm::Pallet::<Runtime>::account_basic(&address);
            account
        }
9032

            
9032
        fn gas_price() -> U256 {
            let (gas_price, _) = <Runtime as pallet_evm::Config>::FeeCalculator::min_gas_price();
            gas_price
        }
9032

            
9032
        fn account_code_at(address: H160) -> Vec<u8> {
            pallet_evm::AccountCodes::<Runtime>::get(address)
        }
9032

            
9032
        fn author() -> H160 {
            <pallet_evm::Pallet<Runtime>>::find_author()
        }
9032

            
9032
        fn storage_at(address: H160, index: U256) -> H256 {
            let mut tmp = [0u8; 32];
            index.to_big_endian(&mut tmp);
            pallet_evm::AccountStorages::<Runtime>::get(address, H256::from_slice(&tmp[..]))
        }
9032

            
9032
        fn call(
            from: H160,
            to: H160,
            data: Vec<u8>,
            value: U256,
            gas_limit: U256,
            max_fee_per_gas: Option<U256>,
            max_priority_fee_per_gas: Option<U256>,
            nonce: Option<U256>,
            _estimate: bool,
            access_list: Option<Vec<(H160, Vec<H256>)>>,
        ) -> Result<pallet_evm::CallInfo, sp_runtime::DispatchError> {
            let is_transactional = false;
            let validate = true;
            <Runtime as pallet_evm::Config>::Runner::call(
                from,
                to,
                data,
                value,
                gas_limit.min(u64::MAX.into()).low_u64(),
                max_fee_per_gas,
                max_priority_fee_per_gas,
                nonce,
                access_list.unwrap_or_default(),
                is_transactional,
                validate,
                None,
                None,
                <Runtime as pallet_evm::Config>::config(),
            ).map_err(|err| err.error.into())
        }
9032

            
9032
        fn create(
            from: H160,
            data: Vec<u8>,
            value: U256,
            gas_limit: U256,
            max_fee_per_gas: Option<U256>,
            max_priority_fee_per_gas: Option<U256>,
            nonce: Option<U256>,
            _estimate: bool,
            access_list: Option<Vec<(H160, Vec<H256>)>>,
        ) -> Result<pallet_evm::CreateInfo, sp_runtime::DispatchError> {
            let is_transactional = false;
            let validate = true;
            <Runtime as pallet_evm::Config>::Runner::create(
                from,
                data,
                value,
                gas_limit.min(u64::MAX.into()).low_u64(),
                max_fee_per_gas,
                max_priority_fee_per_gas,
                nonce,
                access_list.unwrap_or_default(),
                is_transactional,
                validate,
                None,
                None,
                <Runtime as pallet_evm::Config>::config(),
            ).map_err(|err| err.error.into())
        }
9032

            
9032
        fn current_transaction_statuses() -> Option<Vec<TransactionStatus>> {
            pallet_ethereum::CurrentTransactionStatuses::<Runtime>::get()
        }
9032

            
9032
        fn current_block() -> Option<pallet_ethereum::Block> {
            pallet_ethereum::CurrentBlock::<Runtime>::get()
        }
9032

            
9032
        fn current_receipts() -> Option<Vec<pallet_ethereum::Receipt>> {
            pallet_ethereum::CurrentReceipts::<Runtime>::get()
        }
9032

            
9032
        fn current_all() -> (
            Option<pallet_ethereum::Block>,
            Option<Vec<pallet_ethereum::Receipt>>,
            Option<Vec<TransactionStatus>>,
        ) {
            (
                pallet_ethereum::CurrentBlock::<Runtime>::get(),
                pallet_ethereum::CurrentReceipts::<Runtime>::get(),
                pallet_ethereum::CurrentTransactionStatuses::<Runtime>::get()
            )
        }
9032

            
9032
        fn extrinsic_filter(
            xts: Vec<<Block as BlockT>::Extrinsic>,
        ) -> Vec<EthereumTransaction> {
            xts.into_iter().filter_map(|xt| match xt.0.function {
9032
                RuntimeCall::Ethereum(transact { transaction }) => Some(transaction),
9032
                _ => None
9032
            }).collect::<Vec<EthereumTransaction>>()
        }
9032

            
9032
        fn elasticity() -> Option<Permill> {
            Some(pallet_base_fee::Elasticity::<Runtime>::get())
        }
9032

            
9032
        fn gas_limit_multiplier_support() {}
9032

            
9032
        fn pending_block(xts: Vec<<Block as BlockT>::Extrinsic>) -> (Option<pallet_ethereum::Block>, Option<sp_std::prelude::Vec<TransactionStatus>>) {
9032
            for ext in xts.into_iter() {
                let _ = Executive::apply_extrinsic(ext);
            }
9032

            
9032
            Ethereum::on_finalize(System::block_number() + 1);
            (
                pallet_ethereum::CurrentBlock::<Runtime>::get(),
                pallet_ethereum::CurrentTransactionStatuses::<Runtime>::get()
            )
         }
9032
    }
9032

            
9032
    impl fp_rpc::ConvertTransactionRuntimeApi<Block> for Runtime {
9032
        fn convert_transaction(
            transaction: pallet_ethereum::Transaction
        ) -> <Block as BlockT>::Extrinsic {
            UncheckedExtrinsic::new_unsigned(
                pallet_ethereum::Call::<Runtime>::transact { transaction }.into(),
            )
        }
9032
    }
9032

            
9032
    impl pallet_transaction_payment_rpc_runtime_api::TransactionPaymentApi<Block, Balance>
9032
    for Runtime {
9032
        fn query_info(
            uxt: <Block as BlockT>::Extrinsic,
            len: u32,
        ) -> pallet_transaction_payment_rpc_runtime_api::RuntimeDispatchInfo<Balance> {
            TransactionPayment::query_info(uxt, len)
        }
9032

            
9032
        fn query_fee_details(
            uxt: <Block as BlockT>::Extrinsic,
            len: u32,
        ) -> pallet_transaction_payment::FeeDetails<Balance> {
            TransactionPayment::query_fee_details(uxt, len)
        }
9032

            
9032
        fn query_weight_to_fee(weight: Weight) -> Balance {
            TransactionPayment::weight_to_fee(weight)
        }
9032

            
9032
        fn query_length_to_fee(length: u32) -> Balance {
            TransactionPayment::length_to_fee(length)
        }
9032
    }
9032

            
9032
    impl dp_slot_duration_runtime_api::TanssiSlotDurationApi<Block> for Runtime {
9032
        fn slot_duration() -> u64 {
            SLOT_DURATION
        }
9032
    }
16564
}
#[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>,
}