lib.rs 56.2 KB
Newer Older
ddorgan's avatar
ddorgan committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// Copyright 2017-2020 Parity Technologies (UK) Ltd.
// This file is part of Polkadot.

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

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

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

//! The Polkadot runtime. This can be compiled with `#[no_std]`, ready for Wasm.

#![cfg_attr(not(feature = "std"), no_std)]
// `construct_runtime!` does a lot of recursion and requires us to increase the limit to 256.
21
#![recursion_limit = "256"]
ddorgan's avatar
ddorgan committed
22

23
use frame_support::traits::OnRuntimeUpgrade;
Albrecht's avatar
Albrecht committed
24
use pallet_transaction_payment::CurrencyAdapter;
25
use parity_scale_codec::{Decode, Encode, MaxEncodedLen};
26
use primitives::v1::{
27
	AccountId, AccountIndex, Balance, BlockNumber, CandidateEvent, CommittedCandidateReceipt,
28
29
30
	CoreState, GroupRotationInfo, Hash, Id as ParaId, InboundDownwardMessage, InboundHrmpMessage,
	Moment, Nonce, OccupiedCoreAssumption, PersistedValidationData, SessionInfo, Signature,
	ValidationCode, ValidationCodeHash, ValidatorId, ValidatorIndex,
ddorgan's avatar
ddorgan committed
31
};
32
use runtime_common::{
33
34
35
36
37
38
39
40
41
42
43
44
45
	auctions, crowdloan, impls::ToAuthor, paras_registrar, paras_sudo_wrapper, slots, xcm_sender,
	BlockHashCount, BlockLength, BlockWeights, CurrencyToVote, OffchainSolutionLengthLimit,
	OffchainSolutionWeightLimit, RocksDbWeight, SlowAdjustingFeeUpdate,
};
use sp_std::{collections::btree_map::BTreeMap, prelude::*};

use runtime_parachains::{
	configuration as parachains_configuration, dmp as parachains_dmp, hrmp as parachains_hrmp,
	inclusion as parachains_inclusion, initializer as parachains_initializer,
	origin as parachains_origin, paras as parachains_paras,
	paras_inherent as parachains_paras_inherent, reward_points as parachains_reward_points,
	runtime_api_impl::v1 as parachains_runtime_api_impl, scheduler as parachains_scheduler,
	session_info as parachains_session_info, shared as parachains_shared, ump as parachains_ump,
ddorgan's avatar
ddorgan committed
46
};
47

Gavin Wood's avatar
Gavin Wood committed
48
use xcm::latest::prelude::*;
49
use xcm_builder::{
50
51
	AccountId32Aliases, AllowTopLevelPaidExecutionFrom, AllowUnpaidExecutionFrom,
	ChildParachainAsNative, ChildParachainConvertsVia, ChildSystemParachainAsSuperuser,
52
53
54
	CurrencyAdapter as XcmCurrencyAdapter, IsChildSystemParachain, IsConcrete, LocationInverter,
	SignedAccountId32AsNative, SignedToAccountId32, SovereignSignedViaLocation, TakeWeightCredit,
	UsingComponents, WeightInfoBounds,
55
};
56
use xcm_executor::XcmExecutor;
57

58
59
60
61
use authority_discovery_primitives::AuthorityId as AuthorityDiscoveryId;
use beefy_primitives::crypto::AuthorityId as BeefyId;
use frame_support::{
	construct_runtime, parameter_types,
62
	traits::{Contains, Everything, InstanceFilter, KeyOwnerProofSystem, Nothing},
63
64
65
66
67
68
69
70
71
72
	weights::Weight,
	PalletId, RuntimeDebug,
};
use frame_system::EnsureRoot;
use pallet_grandpa::{fg_primitives, AuthorityId as GrandpaId};
use pallet_im_online::sr25519::AuthorityId as ImOnlineId;
use pallet_mmr_primitives as mmr;
use pallet_session::historical as session_historical;
use pallet_transaction_payment::{FeeDetails, RuntimeDispatchInfo};
use sp_core::OpaqueMetadata;
ddorgan's avatar
ddorgan committed
73
use sp_runtime::{
74
75
76
	create_runtime_str,
	curve::PiecewiseLinear,
	generic, impl_opaque_keys,
ddorgan's avatar
ddorgan committed
77
	traits::{
78
79
		AccountIdLookup, BlakeTwo256, Block as BlockT, ConvertInto, Extrinsic as ExtrinsicT,
		OpaqueKeys, SaturatedConversion, Verify,
ddorgan's avatar
ddorgan committed
80
	},
81
82
	transaction_validity::{TransactionPriority, TransactionSource, TransactionValidity},
	ApplyExtrinsicResult, KeyTypeId, Perbill,
ddorgan's avatar
ddorgan committed
83
};
84
use sp_staking::SessionIndex;
ddorgan's avatar
ddorgan committed
85
#[cfg(any(feature = "std", test))]
86
use sp_version::NativeVersion;
87
use sp_version::RuntimeVersion;
ddorgan's avatar
ddorgan committed
88

89
90
pub use pallet_balances::Call as BalancesCall;
pub use pallet_election_provider_multi_phase::Call as EPMCall;
ddorgan's avatar
ddorgan committed
91
#[cfg(feature = "std")]
92
pub use pallet_staking::StakerStatus;
93
pub use pallet_timestamp::Call as TimestampCall;
ddorgan's avatar
ddorgan committed
94
95
96
97
98
#[cfg(any(feature = "std", test))]
pub use sp_runtime::BuildStorage;

/// Constant values used within the runtime.
pub mod constants;
99
use constants::{currency::*, fee::*, time::*};
ddorgan's avatar
ddorgan committed
100

101
102
103
// Weights used in the runtime
mod weights;

104
105
106
// Voter bag threshold definitions.
mod voter_bags;

107
108
109
#[cfg(test)]
mod tests;

ddorgan's avatar
ddorgan committed
110
111
112
113
// Make the WASM binary available.
#[cfg(feature = "std")]
include!(concat!(env!("OUT_DIR"), "/wasm_binary.rs"));

114
/// Runtime version (Westend).
ddorgan's avatar
ddorgan committed
115
116
117
118
pub const VERSION: RuntimeVersion = RuntimeVersion {
	spec_name: create_runtime_str!("westend"),
	impl_name: create_runtime_str!("parity-westend"),
	authoring_version: 2,
119
	spec_version: 9110,
120
	impl_version: 0,
121
	#[cfg(not(feature = "disable-runtime-api"))]
ddorgan's avatar
ddorgan committed
122
	apis: RUNTIME_API_VERSIONS,
123
	#[cfg(feature = "disable-runtime-api")]
124
	apis: version::create_apis_vec![[]],
125
	transaction_version: 7,
ddorgan's avatar
ddorgan committed
126
127
};

128
129
130
131
/// The BABE epoch configuration at genesis.
pub const BABE_GENESIS_EPOCH_CONFIG: babe_primitives::BabeEpochConfiguration =
	babe_primitives::BabeEpochConfiguration {
		c: PRIMARY_PROBABILITY,
132
		allowed_slots: babe_primitives::AllowedSlots::PrimaryAndSecondaryVRFSlots,
133
134
	};

ddorgan's avatar
ddorgan committed
135
136
137
/// Native version.
#[cfg(any(feature = "std", test))]
pub fn native_version() -> NativeVersion {
138
	NativeVersion { runtime_version: VERSION, can_author_with: Default::default() }
ddorgan's avatar
ddorgan committed
139
140
}

141
/// Allow everything.
142
pub struct BaseFilter;
143
144
impl Contains<Call> for BaseFilter {
	fn contains(_: &Call) -> bool {
145
		true
ddorgan's avatar
ddorgan committed
146
147
148
149
150
	}
}

parameter_types! {
	pub const Version: RuntimeVersion = VERSION;
151
	pub const SS58Prefix: u8 = 42;
ddorgan's avatar
ddorgan committed
152
153
}

154
impl frame_system::Config for Runtime {
155
	type BaseCallFilter = BaseFilter;
156
157
	type BlockWeights = BlockWeights;
	type BlockLength = BlockLength;
ddorgan's avatar
ddorgan committed
158
159
160
161
162
163
164
	type Origin = Origin;
	type Call = Call;
	type Index = Nonce;
	type BlockNumber = BlockNumber;
	type Hash = Hash;
	type Hashing = BlakeTwo256;
	type AccountId = AccountId;
165
	type Lookup = AccountIdLookup<AccountId, ()>;
ddorgan's avatar
ddorgan committed
166
167
168
	type Header = generic::Header<BlockNumber, BlakeTwo256>;
	type Event = Event;
	type BlockHashCount = BlockHashCount;
169
	type DbWeight = RocksDbWeight;
ddorgan's avatar
ddorgan committed
170
	type Version = Version;
171
	type PalletInfo = PalletInfo;
172
	type AccountData = pallet_balances::AccountData<Balance>;
ddorgan's avatar
ddorgan committed
173
174
	type OnNewAccount = ();
	type OnKilledAccount = ();
175
	type SystemWeightInfo = weights::frame_system::WeightInfo<Runtime>;
176
	type SS58Prefix = SS58Prefix;
177
	type OnSetCode = ();
ddorgan's avatar
ddorgan committed
178
179
}

180
parameter_types! {
181
182
	pub MaximumSchedulerWeight: Weight = Perbill::from_percent(80) *
		BlockWeights::get().max_block;
183
184
185
	pub const MaxScheduledPerBlock: u32 = 50;
}

186
impl pallet_scheduler::Config for Runtime {
ddorgan's avatar
ddorgan committed
187
188
	type Event = Event;
	type Origin = Origin;
189
	type PalletsOrigin = OriginCaller;
ddorgan's avatar
ddorgan committed
190
	type Call = Call;
191
	type MaximumWeight = MaximumSchedulerWeight;
192
	type ScheduleOrigin = EnsureRoot<AccountId>;
193
	type MaxScheduledPerBlock = MaxScheduledPerBlock;
194
	type WeightInfo = weights::pallet_scheduler::WeightInfo<Runtime>;
ddorgan's avatar
ddorgan committed
195
196
197
}

parameter_types! {
198
	pub const EpochDuration: u64 = EPOCH_DURATION_IN_SLOTS as u64;
ddorgan's avatar
ddorgan committed
199
	pub const ExpectedBlockTime: Moment = MILLISECS_PER_BLOCK;
200
201
	pub const ReportLongevity: u64 =
		BondingDuration::get() as u64 * SessionsPerEra::get() as u64 * EpochDuration::get();
ddorgan's avatar
ddorgan committed
202
203
}

204
impl pallet_babe::Config for Runtime {
ddorgan's avatar
ddorgan committed
205
206
207
208
	type EpochDuration = EpochDuration;
	type ExpectedBlockTime = ExpectedBlockTime;

	// session module is the trigger
209
	type EpochChangeTrigger = pallet_babe::ExternalTrigger;
210

211
212
	type DisabledValidators = Session;

213
214
215
216
	type KeyOwnerProofSystem = Historical;

	type KeyOwnerProof = <Self::KeyOwnerProofSystem as KeyOwnerProofSystem<(
		KeyTypeId,
217
		pallet_babe::AuthorityId,
218
219
220
221
	)>>::Proof;

	type KeyOwnerIdentification = <Self::KeyOwnerProofSystem as KeyOwnerProofSystem<(
		KeyTypeId,
222
		pallet_babe::AuthorityId,
223
224
225
	)>>::IdentificationTuple;

	type HandleEquivocation =
226
		pallet_babe::EquivocationHandler<Self::KeyOwnerIdentification, Offences, ReportLongevity>;
227
228

	type WeightInfo = ();
229
230

	type MaxAuthorities = MaxAuthorities;
ddorgan's avatar
ddorgan committed
231
232
233
}

parameter_types! {
234
	pub const IndexDeposit: Balance = 100 * CENTS;
ddorgan's avatar
ddorgan committed
235
236
}

237
impl pallet_indices::Config for Runtime {
ddorgan's avatar
ddorgan committed
238
239
240
241
	type AccountIndex = AccountIndex;
	type Currency = Balances;
	type Deposit = IndexDeposit;
	type Event = Event;
242
	type WeightInfo = weights::pallet_indices::WeightInfo<Runtime>;
ddorgan's avatar
ddorgan committed
243
244
245
246
}

parameter_types! {
	pub const ExistentialDeposit: Balance = 1 * CENTS;
247
	pub const MaxLocks: u32 = 50;
Gavin Wood's avatar
Gavin Wood committed
248
	pub const MaxReserves: u32 = 50;
ddorgan's avatar
ddorgan committed
249
250
}

251
impl pallet_balances::Config for Runtime {
ddorgan's avatar
ddorgan committed
252
253
254
255
256
	type Balance = Balance;
	type DustRemoval = ();
	type Event = Event;
	type ExistentialDeposit = ExistentialDeposit;
	type AccountStore = System;
257
	type MaxLocks = MaxLocks;
Gavin Wood's avatar
Gavin Wood committed
258
259
	type MaxReserves = MaxReserves;
	type ReserveIdentifier = [u8; 8];
260
	type WeightInfo = weights::pallet_balances::WeightInfo<Runtime>;
ddorgan's avatar
ddorgan committed
261
262
263
264
}

parameter_types! {
	pub const TransactionByteFee: Balance = 10 * MILLICENTS;
265
266
267
	/// This value increases the priority of `Operational` transactions by adding
	/// a "virtual tip" that's equal to the `OperationalFeeMultiplier * final_fee`.
	pub const OperationalFeeMultiplier: u8 = 5;
ddorgan's avatar
ddorgan committed
268
269
}

270
impl pallet_transaction_payment::Config for Runtime {
Albrecht's avatar
Albrecht committed
271
	type OnChargeTransaction = CurrencyAdapter<Balances, ToAuthor<Runtime>>;
ddorgan's avatar
ddorgan committed
272
	type TransactionByteFee = TransactionByteFee;
273
	type OperationalFeeMultiplier = OperationalFeeMultiplier;
ddorgan's avatar
ddorgan committed
274
	type WeightToFee = WeightToFee;
275
	type FeeMultiplierUpdate = SlowAdjustingFeeUpdate<Self>;
ddorgan's avatar
ddorgan committed
276
277
278
279
280
}

parameter_types! {
	pub const MinimumPeriod: u64 = SLOT_DURATION / 2;
}
281
impl pallet_timestamp::Config for Runtime {
ddorgan's avatar
ddorgan committed
282
283
284
	type Moment = u64;
	type OnTimestampSet = Babe;
	type MinimumPeriod = MinimumPeriod;
285
	type WeightInfo = weights::pallet_timestamp::WeightInfo<Runtime>;
ddorgan's avatar
ddorgan committed
286
287
288
289
290
291
}

parameter_types! {
	pub const UncleGenerations: u32 = 0;
}

292
impl pallet_authorship::Config for Runtime {
293
	type FindAuthor = pallet_session::FindAccountFromAuthorIndex<Self, Babe>;
ddorgan's avatar
ddorgan committed
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
	type UncleGenerations = UncleGenerations;
	type FilterUncle = ();
	type EventHandler = (Staking, ImOnline);
}

parameter_types! {
	pub const Period: BlockNumber = 10 * MINUTES;
	pub const Offset: BlockNumber = 0;
}

impl_opaque_keys! {
	pub struct SessionKeys {
		pub grandpa: Grandpa,
		pub babe: Babe,
		pub im_online: ImOnline,
309
		pub para_validator: Initializer,
310
		pub para_assignment: ParaSessionInfo,
ddorgan's avatar
ddorgan committed
311
312
313
314
		pub authority_discovery: AuthorityDiscovery,
	}
}

315
impl pallet_session::Config for Runtime {
ddorgan's avatar
ddorgan committed
316
317
	type Event = Event;
	type ValidatorId = AccountId;
318
	type ValidatorIdOf = pallet_staking::StashOf<Self>;
ddorgan's avatar
ddorgan committed
319
320
	type ShouldEndSession = Babe;
	type NextSessionRotation = Babe;
321
	type SessionManager = pallet_session::historical::NoteHistoricalRoot<Self, Staking>;
ddorgan's avatar
ddorgan committed
322
323
	type SessionHandler = <SessionKeys as OpaqueKeys>::KeyTypeIdProviders;
	type Keys = SessionKeys;
324
	type WeightInfo = weights::pallet_session::WeightInfo<Runtime>;
ddorgan's avatar
ddorgan committed
325
326
}

327
impl pallet_session::historical::Config for Runtime {
328
329
	type FullIdentification = pallet_staking::Exposure<AccountId, Balance>;
	type FullIdentificationOf = pallet_staking::ExposureOf<Runtime>;
ddorgan's avatar
ddorgan committed
330
331
}

332
parameter_types! {
333
334
	// phase durations. 1/4 of the last session for each.
	pub const SignedPhase: u32 = EPOCH_DURATION_IN_SLOTS / 4;
335
	pub const UnsignedPhase: u32 = EPOCH_DURATION_IN_SLOTS / 4;
336

337
338
	// signed config
	pub const SignedMaxSubmissions: u32 = 128;
339
340
	pub const SignedDepositBase: Balance = deposit(2, 0);
	pub const SignedDepositByte: Balance = deposit(0, 10) / 1024;
341
342
	// Each good submission will get 1 WND as reward
	pub SignedRewardBase: Balance = 1 * UNITS;
343
	pub SolutionImprovementThreshold: Perbill = Perbill::from_rational(5u32, 10_000);
344

345
346
	// 1 hour session, 15 minutes unsigned phase, 4 offchain executions.
	pub OffchainRepeat: BlockNumber = UnsignedPhase::get() / 4;
347
348
349
350
351

	/// Whilst `UseNominatorsAndUpdateBagsList` or `UseNominatorsMap` is in use, this can still be a
	/// very large value. Once the `BagsList` is in full motion, staking might open its door to many
	/// more nominators, and this value should instead be what is a "safe" number (e.g. 22500).
	pub const VoterSnapshotPerBlock: u32 = 22_500;
352
353
}

354
355
sp_npos_elections::generate_solution_type!(
	#[compact]
356
357
358
359
360
	pub struct NposCompactSolution16::<
		VoterIndex = u32,
		TargetIndex = u16,
		Accuracy = sp_runtime::PerU16,
	>(16)
361
362
);

363
364
365
impl pallet_election_provider_multi_phase::Config for Runtime {
	type Event = Event;
	type Currency = Balances;
366
	type EstimateCallFee = TransactionPayment;
367
368
	type SignedPhase = SignedPhase;
	type UnsignedPhase = UnsignedPhase;
369
370
371
372
373
374
375
376
	type SignedMaxSubmissions = SignedMaxSubmissions;
	type SignedRewardBase = SignedRewardBase;
	type SignedDepositBase = SignedDepositBase;
	type SignedDepositByte = SignedDepositByte;
	type SignedDepositWeight = ();
	type SignedMaxWeight = Self::MinerMaxWeight;
	type SlashHandler = (); // burn slashes
	type RewardHandler = (); // nothing to do upon rewards
377
	type SolutionImprovementThreshold = SolutionImprovementThreshold;
378
	type MinerMaxWeight = OffchainSolutionWeightLimit; // For now use the one from staking.
379
	type MinerMaxLength = OffchainSolutionLengthLimit;
380
	type OffchainRepeat = OffchainRepeat;
381
	type MinerTxPriority = NposSolutionPriority;
382
	type DataProvider = Staking;
383
	type Solution = NposCompactSolution16;
Kian Paimani's avatar
Kian Paimani committed
384
	type Fallback = pallet_election_provider_multi_phase::NoFallback<Self>;
385
386
	type Solver = frame_election_provider_support::SequentialPhragmen<
		AccountId,
Kian Paimani's avatar
Kian Paimani committed
387
		pallet_election_provider_multi_phase::SolutionAccuracyOf<Self>,
388
389
		runtime_common::elections::OffchainRandomBalancing,
	>;
390
	type BenchmarkingConfig = runtime_common::elections::BenchmarkConfig;
391
	type ForceOrigin = EnsureRoot<AccountId>;
Kian Paimani's avatar
Kian Paimani committed
392
	type WeightInfo = weights::pallet_election_provider_multi_phase::WeightInfo<Self>;
393
394
395
396
397
398
399
400
401
402
403
404
	type VoterSnapshotPerBlock = VoterSnapshotPerBlock;
}

parameter_types! {
	pub const BagThresholds: &'static [u64] = &voter_bags::THRESHOLDS;
}

impl pallet_bags_list::Config for Runtime {
	type Event = Event;
	type VoteWeightProvider = Staking;
	type WeightInfo = weights::pallet_bags_list::WeightInfo<Runtime>;
	type BagThresholds = BagThresholds;
405
406
}

ddorgan's avatar
ddorgan committed
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
pallet_staking_reward_curve::build! {
	const REWARD_CURVE: PiecewiseLinear<'static> = curve!(
		min_inflation: 0_025_000,
		max_inflation: 0_100_000,
		ideal_stake: 0_500_000,
		falloff: 0_050_000,
		max_piece_count: 40,
		test_precision: 0_005_000,
	);
}

parameter_types! {
	// Six sessions in an era (6 hours).
	pub const SessionsPerEra: SessionIndex = 6;
	// 28 eras for unbonding (7 days).
422
	pub const BondingDuration: pallet_staking::EraIndex = 28;
423
	// 27 eras in which slashes can be cancelled (slightly less than 7 days).
424
	pub const SlashDeferDuration: pallet_staking::EraIndex = 27;
ddorgan's avatar
ddorgan committed
425
426
	pub const RewardCurve: &'static PiecewiseLinear<'static> = &REWARD_CURVE;
	pub const MaxNominatorRewardedPerValidator: u32 = 64;
427
	pub const OffendingValidatorsThreshold: Perbill = Perbill::from_percent(17);
ddorgan's avatar
ddorgan committed
428
429
}

Kian Paimani's avatar
Kian Paimani committed
430
431
432
433
434
impl frame_election_provider_support::onchain::Config for Runtime {
	type Accuracy = runtime_common::elections::OnOnChainAccuracy;
	type DataProvider = Staking;
}

435
impl pallet_staking::Config for Runtime {
436
	const MAX_NOMINATIONS: u32 =
437
		<NposCompactSolution16 as sp_npos_elections::NposSolution>::LIMIT as u32;
ddorgan's avatar
ddorgan committed
438
439
	type Currency = Balances;
	type UnixTime = Timestamp;
440
	type CurrencyToVote = CurrencyToVote;
ddorgan's avatar
ddorgan committed
441
442
443
444
445
446
447
448
	type RewardRemainder = ();
	type Event = Event;
	type Slash = ();
	type Reward = ();
	type SessionsPerEra = SessionsPerEra;
	type BondingDuration = BondingDuration;
	type SlashDeferDuration = SlashDeferDuration;
	// A majority of the council can cancel the slash.
449
	type SlashCancelOrigin = EnsureRoot<AccountId>;
ddorgan's avatar
ddorgan committed
450
	type SessionInterface = Self;
Kian Paimani's avatar
Kian Paimani committed
451
	type EraPayout = pallet_staking::ConvertCurve<RewardCurve>;
ddorgan's avatar
ddorgan committed
452
	type MaxNominatorRewardedPerValidator = MaxNominatorRewardedPerValidator;
453
	type OffendingValidatorsThreshold = OffendingValidatorsThreshold;
ddorgan's avatar
ddorgan committed
454
	type NextNewSession = Session;
455
	type ElectionProvider = ElectionProviderMultiPhase;
Kian Paimani's avatar
Kian Paimani committed
456
	type GenesisElectionProvider = runtime_common::elections::GenesisElectionOf<Self>;
457
458
459
	// Use the nominators map to iter voters, but also perform the bags-list migration and keep
	// it up-to-date.
	type SortedListProvider = runtime_common::elections::UseNominatorsAndUpdateBagsList<Runtime>;
460
	type WeightInfo = weights::pallet_staking::WeightInfo<Runtime>;
ddorgan's avatar
ddorgan committed
461
462
463
464
465
466
}

parameter_types! {
	pub const LaunchPeriod: BlockNumber = 7 * DAYS;
	pub const VotingPeriod: BlockNumber = 7 * DAYS;
	pub const FastTrackVotingPeriod: BlockNumber = 3 * HOURS;
467
	pub const MinimumDeposit: Balance = 100 * CENTS;
ddorgan's avatar
ddorgan committed
468
469
470
471
472
	pub const EnactmentPeriod: BlockNumber = 8 * DAYS;
	pub const CooloffPeriod: BlockNumber = 7 * DAYS;
	// One cent: $10,000 / MB
	pub const PreimageByteDeposit: Balance = 10 * MILLICENTS;
	pub const InstantAllowed: bool = true;
473
	pub const MaxAuthorities: u32 = 100_000;
ddorgan's avatar
ddorgan committed
474
475
}

476
impl pallet_offences::Config for Runtime {
ddorgan's avatar
ddorgan committed
477
	type Event = Event;
478
	type IdentificationTuple = pallet_session::historical::IdentificationTuple<Self>;
ddorgan's avatar
ddorgan committed
479
480
481
	type OnOffenceHandler = Staking;
}

482
483
484
impl pallet_authority_discovery::Config for Runtime {
	type MaxAuthorities = MaxAuthorities;
}
ddorgan's avatar
ddorgan committed
485
486

parameter_types! {
487
	pub const NposSolutionPriority: TransactionPriority = TransactionPriority::max_value() / 2;
ddorgan's avatar
ddorgan committed
488
	pub const ImOnlineUnsignedPriority: TransactionPriority = TransactionPriority::max_value();
489
490
491
	pub const MaxKeys: u32 = 10_000;
	pub const MaxPeerInHeartbeats: u32 = 10_000;
	pub const MaxPeerDataEncodingSize: u32 = 1_000;
ddorgan's avatar
ddorgan committed
492
493
}

494
impl pallet_im_online::Config for Runtime {
ddorgan's avatar
ddorgan committed
495
496
	type AuthorityId = ImOnlineId;
	type Event = Event;
497
	type ValidatorSet = Historical;
498
	type NextSessionRotation = Babe;
ddorgan's avatar
ddorgan committed
499
	type ReportUnresponsiveness = Offences;
500
	type UnsignedPriority = ImOnlineUnsignedPriority;
501
	type WeightInfo = weights::pallet_im_online::WeightInfo<Runtime>;
502
503
504
	type MaxKeys = MaxKeys;
	type MaxPeerInHeartbeats = MaxPeerInHeartbeats;
	type MaxPeerDataEncodingSize = MaxPeerDataEncodingSize;
ddorgan's avatar
ddorgan committed
505
506
}

507
impl pallet_grandpa::Config for Runtime {
ddorgan's avatar
ddorgan committed
508
	type Event = Event;
509
510
511
512
513
514
515
516
517
518
519
520
	type Call = Call;

	type KeyOwnerProofSystem = Historical;

	type KeyOwnerProof =
		<Self::KeyOwnerProofSystem as KeyOwnerProofSystem<(KeyTypeId, GrandpaId)>>::Proof;

	type KeyOwnerIdentification = <Self::KeyOwnerProofSystem as KeyOwnerProofSystem<(
		KeyTypeId,
		GrandpaId,
	)>>::IdentificationTuple;

521
522
523
524
525
	type HandleEquivocation = pallet_grandpa::EquivocationHandler<
		Self::KeyOwnerIdentification,
		Offences,
		ReportLongevity,
	>;
526
527

	type WeightInfo = ();
528
	type MaxAuthorities = MaxAuthorities;
ddorgan's avatar
ddorgan committed
529
530
}

531
532
/// Submits a transaction with the node's public and signature type. Adheres to the signed extension
/// format of the chain.
533
534
impl<LocalCall> frame_system::offchain::CreateSignedTransaction<LocalCall> for Runtime
where
535
536
	Call: From<LocalCall>,
{
537
	fn create_transaction<C: frame_system::offchain::AppCrypto<Self::Public, Self::Signature>>(
538
539
540
		call: Call,
		public: <Signature as Verify>::Signer,
		account: AccountId,
541
		nonce: <Runtime as frame_system::Config>::Index,
542
	) -> Option<(Call, <UncheckedExtrinsic as ExtrinsicT>::SignaturePayload)> {
543
		use sp_runtime::traits::StaticLookup;
544
		// take the biggest period possible.
545
546
		let period =
			BlockHashCount::get().checked_next_power_of_two().map(|c| c / 2).unwrap_or(2) as u64;
547
548
549

		let current_block = System::block_number()
			.saturated_into::<u64>()
550
551
			// The `System::block_number` is initialized with `n+1`,
			// so the actual block number is `n`.
552
553
554
			.saturating_sub(1);
		let tip = 0;
		let extra: SignedExtra = (
555
556
557
			frame_system::CheckSpecVersion::<Runtime>::new(),
			frame_system::CheckTxVersion::<Runtime>::new(),
			frame_system::CheckGenesis::<Runtime>::new(),
558
559
560
561
			frame_system::CheckMortality::<Runtime>::from(generic::Era::mortal(
				period,
				current_block,
			)),
562
563
564
			frame_system::CheckNonce::<Runtime>::from(nonce),
			frame_system::CheckWeight::<Runtime>::new(),
			pallet_transaction_payment::ChargeTransactionPayment::<Runtime>::from(tip),
565
		);
566
567
568
569
570
571
		let raw_payload = SignedPayload::new(call, extra)
			.map_err(|e| {
				log::warn!("Unable to create signed payload: {:?}", e);
			})
			.ok()?;
		let signature = raw_payload.using_encoded(|payload| C::sign(payload, public))?;
572
		let (call, extra, _) = raw_payload.deconstruct();
573
574
		let address = <Runtime as frame_system::Config>::Lookup::unlookup(account);
		Some((call, (address, signature, extra)))
575
	}
ddorgan's avatar
ddorgan committed
576
577
}

578
impl frame_system::offchain::SigningTypes for Runtime {
579
580
581
582
	type Public = <Signature as Verify>::Signer;
	type Signature = Signature;
}

583
584
impl<C> frame_system::offchain::SendTransactionTypes<C> for Runtime
where
585
586
587
588
589
590
	Call: From<C>,
{
	type OverarchingCall = Call;
	type Extrinsic = UncheckedExtrinsic;
}

ddorgan's avatar
ddorgan committed
591
592
parameter_types! {
	// Minimum 100 bytes/KSM deposited (1 CENT/byte)
593
	pub const BasicDeposit: Balance = 1000 * CENTS;       // 258 bytes on-chain
ddorgan's avatar
ddorgan committed
594
	pub const FieldDeposit: Balance = 250 * CENTS;        // 66 bytes on-chain
595
	pub const SubAccountDeposit: Balance = 200 * CENTS;   // 53 bytes on-chain
ddorgan's avatar
ddorgan committed
596
597
	pub const MaxSubAccounts: u32 = 100;
	pub const MaxAdditionalFields: u32 = 100;
598
	pub const MaxRegistrars: u32 = 20;
ddorgan's avatar
ddorgan committed
599
600
}

601
impl pallet_identity::Config for Runtime {
ddorgan's avatar
ddorgan committed
602
603
604
605
606
607
608
609
	type Event = Event;
	type Currency = Balances;
	type Slashed = ();
	type BasicDeposit = BasicDeposit;
	type FieldDeposit = FieldDeposit;
	type SubAccountDeposit = SubAccountDeposit;
	type MaxSubAccounts = MaxSubAccounts;
	type MaxAdditionalFields = MaxAdditionalFields;
610
	type MaxRegistrars = MaxRegistrars;
611
612
	type RegistrarOrigin = frame_system::EnsureRoot<AccountId>;
	type ForceOrigin = frame_system::EnsureRoot<AccountId>;
613
	type WeightInfo = weights::pallet_identity::WeightInfo<Runtime>;
ddorgan's avatar
ddorgan committed
614
615
}

616
impl pallet_utility::Config for Runtime {
617
618
	type Event = Event;
	type Call = Call;
619
	type WeightInfo = weights::pallet_utility::WeightInfo<Runtime>;
620
621
}

ddorgan's avatar
ddorgan committed
622
parameter_types! {
623
624
	// One storage item; key size is 32; value is size 4+4+16+32 bytes = 56 bytes.
	pub const DepositBase: Balance = deposit(1, 88);
ddorgan's avatar
ddorgan committed
625
	// Additional storage item size of 32 bytes.
626
	pub const DepositFactor: Balance = deposit(0, 32);
ddorgan's avatar
ddorgan committed
627
628
629
	pub const MaxSignatories: u16 = 100;
}

630
impl pallet_multisig::Config for Runtime {
ddorgan's avatar
ddorgan committed
631
632
633
	type Event = Event;
	type Call = Call;
	type Currency = Balances;
634
635
	type DepositBase = DepositBase;
	type DepositFactor = DepositFactor;
ddorgan's avatar
ddorgan committed
636
	type MaxSignatories = MaxSignatories;
637
	type WeightInfo = weights::pallet_multisig::WeightInfo<Runtime>;
ddorgan's avatar
ddorgan committed
638
639
640
}

parameter_types! {
641
	pub const ConfigDepositBase: Balance = 500 * CENTS;
ddorgan's avatar
ddorgan committed
642
643
	pub const FriendDepositFactor: Balance = 50 * CENTS;
	pub const MaxFriends: u16 = 9;
644
	pub const RecoveryDeposit: Balance = 500 * CENTS;
ddorgan's avatar
ddorgan committed
645
646
}

647
impl pallet_recovery::Config for Runtime {
ddorgan's avatar
ddorgan committed
648
649
650
651
652
653
654
655
656
657
	type Event = Event;
	type Call = Call;
	type Currency = Balances;
	type ConfigDepositBase = ConfigDepositBase;
	type FriendDepositFactor = FriendDepositFactor;
	type MaxFriends = MaxFriends;
	type RecoveryDeposit = RecoveryDeposit;
}

parameter_types! {
658
	pub const MinVestedTransfer: Balance = 100 * CENTS;
ddorgan's avatar
ddorgan committed
659
660
}

661
impl pallet_vesting::Config for Runtime {
ddorgan's avatar
ddorgan committed
662
663
664
665
	type Event = Event;
	type Currency = Balances;
	type BlockNumberToBalance = ConvertInto;
	type MinVestedTransfer = MinVestedTransfer;
666
	type WeightInfo = weights::pallet_vesting::WeightInfo<Runtime>;
667
	const MAX_VESTING_SCHEDULES: u32 = 28;
ddorgan's avatar
ddorgan committed
668
669
}

670
impl pallet_sudo::Config for Runtime {
ddorgan's avatar
ddorgan committed
671
672
673
674
	type Event = Event;
	type Call = Call;
}

675
676
677
678
679
680
parameter_types! {
	// One storage item; key size 32, value size 8; .
	pub const ProxyDepositBase: Balance = deposit(1, 8);
	// Additional storage item size of 33 bytes.
	pub const ProxyDepositFactor: Balance = deposit(0, 33);
	pub const MaxProxies: u16 = 32;
681
682
683
	pub const AnnouncementDepositBase: Balance = deposit(1, 8);
	pub const AnnouncementDepositFactor: Balance = deposit(0, 66);
	pub const MaxPending: u16 = 32;
684
685
686
}

/// The type used to represent the kinds of proxying allowed.
687
#[derive(
688
689
690
691
692
693
694
695
696
697
698
	Copy,
	Clone,
	Eq,
	PartialEq,
	Ord,
	PartialOrd,
	Encode,
	Decode,
	RuntimeDebug,
	MaxEncodedLen,
	scale_info::TypeInfo,
699
)]
700
701
702
703
pub enum ProxyType {
	Any,
	NonTransfer,
	Staking,
704
	SudoBalances,
Chevdor's avatar
Chevdor committed
705
	IdentityJudgement,
Shawn Tabrizi's avatar
Shawn Tabrizi committed
706
	CancelProxy,
707
	Auction,
708
}
709
710
711
712
713
impl Default for ProxyType {
	fn default() -> Self {
		Self::Any
	}
}
714
715
716
717
impl InstanceFilter<Call> for ProxyType {
	fn filter(&self, c: &Call) -> bool {
		match self {
			ProxyType::Any => true,
718
719
			ProxyType::NonTransfer => matches!(
				c,
720
721
722
				Call::System(..) |
				Call::Babe(..) |
				Call::Timestamp(..) |
723
724
725
				Call::Indices(pallet_indices::Call::claim{..}) |
				Call::Indices(pallet_indices::Call::free{..}) |
				Call::Indices(pallet_indices::Call::freeze{..}) |
726
727
728
729
730
731
732
733
734
				// Specifically omitting Indices `transfer`, `force_transfer`
				// Specifically omitting the entire Balances pallet
				Call::Authorship(..) |
				Call::Staking(..) |
				Call::Session(..) |
				Call::Grandpa(..) |
				Call::ImOnline(..) |
				Call::Utility(..) |
				Call::Identity(..) |
735
736
737
738
739
740
				Call::Recovery(pallet_recovery::Call::as_recovered{..}) |
				Call::Recovery(pallet_recovery::Call::vouch_recovery{..}) |
				Call::Recovery(pallet_recovery::Call::claim_recovery{..}) |
				Call::Recovery(pallet_recovery::Call::close_recovery{..}) |
				Call::Recovery(pallet_recovery::Call::remove_recovery{..}) |
				Call::Recovery(pallet_recovery::Call::cancel_recovered{..}) |
741
				// Specifically omitting Recovery `create_recovery`, `initiate_recovery`
742
743
				Call::Vesting(pallet_vesting::Call::vest{..}) |
				Call::Vesting(pallet_vesting::Call::vest_other{..}) |
744
745
746
747
				// Specifically omitting Vesting `vested_transfer`, and `force_vested_transfer`
				Call::Scheduler(..) |
				// Specifically omitting Sudo pallet
				Call::Proxy(..) |
748
				Call::Multisig(..) |
749
750
				Call::Registrar(paras_registrar::Call::register{..}) |
				Call::Registrar(paras_registrar::Call::deregister{..}) |
751
				// Specifically omitting Registrar `swap`
752
				Call::Registrar(paras_registrar::Call::reserve{..}) |
753
754
				Call::Crowdloan(..) |
				Call::Slots(..) |
755
				Call::Auctions(..) // Specifically omitting the entire XCM Pallet
756
			),
757
758
759
			ProxyType::Staking => {
				matches!(c, Call::Staking(..) | Call::Session(..) | Call::Utility(..))
			},
760
			ProxyType::SudoBalances => match c {
761
				Call::Sudo(pallet_sudo::Call::sudo { call: ref x }) => {
762
763
					matches!(x.as_ref(), &Call::Balances(..))
				},
Gavin Wood's avatar
Gavin Wood committed
764
				Call::Utility(..) => true,
765
766
				_ => false,
			},
767
768
			ProxyType::IdentityJudgement => matches!(
				c,
769
				Call::Identity(pallet_identity::Call::provide_judgement { .. }) | Call::Utility(..)
Shawn Tabrizi's avatar
Shawn Tabrizi committed
770
			),
771
			ProxyType::CancelProxy => {
772
				matches!(c, Call::Proxy(pallet_proxy::Call::reject_announcement { .. }))
773
			},
774
775
776
777
			ProxyType::Auction => matches!(
				c,
				Call::Auctions(..) | Call::Crowdloan(..) | Call::Registrar(..) | Call::Slots(..)
			),
778
779
780
781
782
783
784
785
786
		}
	}
	fn is_superset(&self, o: &Self) -> bool {
		match (self, o) {
			(x, y) if x == y => true,
			(ProxyType::Any, _) => true,
			(_, ProxyType::Any) => false,
			(ProxyType::NonTransfer, _) => true,
			_ => false,
787
788
789
790
		}
	}
}

791
impl pallet_proxy::Config for Runtime {
792
793
794
795
796
797
798
	type Event = Event;
	type Call = Call;
	type Currency = Balances;
	type ProxyType = ProxyType;
	type ProxyDepositBase = ProxyDepositBase;
	type ProxyDepositFactor = ProxyDepositFactor;
	type MaxProxies = MaxProxies;
799
	type WeightInfo = weights::pallet_proxy::WeightInfo<Runtime>;
800
801
802
803
	type MaxPending = MaxPending;
	type CallHasher = BlakeTwo256;
	type AnnouncementDepositBase = AnnouncementDepositBase;
	type AnnouncementDepositFactor = AnnouncementDepositFactor;
804
805
}

806
807
impl parachains_origin::Config for Runtime {}

808
impl parachains_configuration::Config for Runtime {
809
	type WeightInfo = weights::runtime_parachains_configuration::WeightInfo<Runtime>;
810
}
811
812
813
814
815
816
817

impl parachains_shared::Config for Runtime {}

impl parachains_session_info::Config for Runtime {}

impl parachains_inclusion::Config for Runtime {
	type Event = Event;
asynchronous rob's avatar
asynchronous rob committed
818
	type DisputesHandler = ();
819
820
821
822
823
824
	type RewardValidators = parachains_reward_points::RewardValidatorsWithEraPoints<Runtime>;
}

impl parachains_paras::Config for Runtime {
	type Origin = Origin;
	type Event = Event;
825
	type WeightInfo = weights::runtime_parachains_paras::WeightInfo<Runtime>;
826
827
828
829
830
831
832
}

parameter_types! {
	pub const FirstMessageFactorPercent: u64 = 100;
}

impl parachains_ump::Config for Runtime {
833
834
	type Event = Event;
	type UmpSink = crate::parachains_ump::XcmSink<XcmExecutor<XcmConfig>, Runtime>;
835
	type FirstMessageFactorPercent = FirstMessageFactorPercent;
836
	type ExecuteOverweightOrigin = EnsureRoot<AccountId>;
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
}

impl parachains_dmp::Config for Runtime {}

impl parachains_hrmp::Config for Runtime {
	type Event = Event;
	type Origin = Origin;
	type Currency = Balances;
}

impl parachains_paras_inherent::Config for Runtime {}

impl parachains_scheduler::Config for Runtime {}

impl parachains_initializer::Config for Runtime {
	type Randomness = pallet_babe::RandomnessFromOneEpochAgo<Runtime>;
	type ForceOrigin = EnsureRoot<AccountId>;
854
	type WeightInfo = weights::runtime_parachains_initializer::WeightInfo<Runtime>;
855
856
857
858
859
860
861
862
863
864
865
866
867
}

impl paras_sudo_wrapper::Config for Runtime {}

parameter_types! {
	pub const ParaDeposit: Balance = 2000 * CENTS;
	pub const DataDepositPerByte: Balance = deposit(0, 1);
}

impl paras_registrar::Config for Runtime {
	type Event = Event;
	type Origin = Origin;
	type Currency = Balances;
868
	type OnSwap = (Crowdloan, Slots);
869
870
871
872
873
874
875
876
877
878
879
880
881
882
	type ParaDeposit = ParaDeposit;
	type DataDepositPerByte = DataDepositPerByte;
	type WeightInfo = weights::runtime_common_paras_registrar::WeightInfo<Runtime>;
}

parameter_types! {
	pub const LeasePeriod: BlockNumber = 28 * DAYS;
}

impl slots::Config for Runtime {
	type Event = Event;
	type Currency = Balances;
	type Registrar = Registrar;
	type LeasePeriod = LeasePeriod;
883
	type LeaseOffset = ();
884
885
886
	type WeightInfo = weights::runtime_common_slots::WeightInfo<Runtime>;
}

887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
parameter_types! {
	pub const CrowdloanId: PalletId = PalletId(*b"py/cfund");
	pub const SubmissionDeposit: Balance = 100 * 100 * CENTS;
	pub const MinContribution: Balance = 100 * CENTS;
	pub const RemoveKeysLimit: u32 = 500;
	// Allow 32 bytes for an additional memo to a crowdloan.
	pub const MaxMemoLength: u8 = 32;
}

impl crowdloan::Config for Runtime {
	type Event = Event;
	type PalletId = CrowdloanId;
	type SubmissionDeposit = SubmissionDeposit;
	type MinContribution = MinContribution;
	type RemoveKeysLimit = RemoveKeysLimit;
	type Registrar = Registrar;
	type Auctioneer = Auctions;
	type MaxMemoLength = MaxMemoLength;
	type WeightInfo = weights::runtime_common_crowdloan::WeightInfo<Runtime>;
}

parameter_types! {
	// The average auction is 7 days long, so this will be 70% for ending period.
	// 5 Days = 72000 Blocks @ 6 sec per block
	pub const EndingPeriod: BlockNumber = 5 * DAYS;
	// ~ 1000 samples per day -> ~ 20 blocks per sample -> 2 minute samples
	pub const SampleLength: BlockNumber = 2 * MINUTES;
}

impl auctions::Config for Runtime {
	type Event = Event;
	type Leaser = Slots;
	type Registrar = Registrar;
	type EndingPeriod = EndingPeriod;
	type SampleLength = SampleLength;
	type Randomness = pallet_babe::RandomnessFromOneEpochAgo<Runtime>;
	type InitiateOrigin = EnsureRoot<AccountId>;
	type WeightInfo = weights::runtime_common_auctions::WeightInfo<Runtime>;
}

927
parameter_types! {
928
929
	pub const WndLocation: MultiLocation = Here.into();
	pub const Ancestry: MultiLocation = Here.into();
930
	pub WestendNetwork: NetworkId = NetworkId::Named(b"Westend".to_vec());
931
	pub CheckAccount: AccountId = XcmPallet::check_account();
932
933
}

934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
pub type LocationConverter =
	(ChildParachainConvertsVia<ParaId, AccountId>, AccountId32Aliases<WestendNetwork, AccountId>);

pub type LocalAssetTransactor = XcmCurrencyAdapter<
	// Use this currency:
	Balances,
	// Use this currency when it is a fungible asset matching the given location or name:
	IsConcrete<WndLocation>,
	// We can convert the MultiLocations with our converter above:
	LocationConverter,
	// Our chain's account ID type (we can't get away without mentioning it explicitly):
	AccountId,
	// It's a native asset so we keep track of the teleports to maintain total issuance.
	CheckAccount,
>;
949
950
951
952
953
954
955
956
957
958
959
960

type LocalOriginConverter = (
	SovereignSignedViaLocation<LocationConverter, Origin>,
	ChildParachainAsNative<parachains_origin::Origin, Origin>,
	SignedAccountId32AsNative<WestendNetwork, Origin>,
	ChildSystemParachainAsSuperuser<ParaId, Origin>,
);

/// The XCM router. When we want to send an XCM message, we use this type. It amalgamates all of our
/// individual routers.
pub type XcmRouter = (
	// Only one router so far - use DMP to communicate with child parachains.
Gavin Wood's avatar
Gavin Wood committed
961
	xcm_sender::ChildParachainRouter<Runtime, xcm::AlwaysRelease>,
962
963
);

964
parameter_types! {
965
	pub const Westmint: MultiLocation = Parachain(1000).into();
Gavin Wood's avatar
Gavin Wood committed
966
	pub const WestendForWestmint: (MultiAssetFilter, MultiLocation) =
967
		(Wild(AllOf { fun: WildFungible, id: Concrete(WndLocation::get()) }), Westmint::get());
968
	pub const MaxInstructions: u32 = 100;
969
}
970
pub type TrustedTeleporters = (xcm_builder::Case<WestendForWestmint>,);
971

972
973
974
975
976
/// The barriers one of which must be passed for an XCM message to be executed.
pub type Barrier = (
	// Weight that is paid for may be consumed.
	TakeWeightCredit,
	// If the message is one that immediately attemps to pay for execution, then allow it.
977
	AllowTopLevelPaidExecutionFrom<Everything>,
978
979
980
981
982
983
984
985
986
987
988
	// Messages coming from system parachains need not pay for execution.
	AllowUnpaidExecutionFrom<IsChildSystemParachain<ParaId>>,
);

pub struct XcmConfig;
impl xcm_executor::Config for XcmConfig {
	type Call = Call;
	type XcmSender = XcmRouter;
	type AssetTransactor = LocalAssetTransactor;
	type OriginConverter = LocalOriginConverter;
	type IsReserve = ();
989
	type IsTeleporter = TrustedTeleporters;
990
	type LocationInverter = LocationInverter<Ancestry>;
991
	type Barrier = Barrier;
992
	type Weigher = WeightInfoBounds<weights::xcm::WestendXcmWeight<Call>, Call, MaxInstructions>;
993
	type Trader = UsingComponents<WeightToFee, WndLocation, AccountId, Balances, ToAuthor<Runtime>>;
994
995
996
	type ResponseHandler = XcmPallet;
	type AssetTrap = XcmPallet;
	type AssetClaims = XcmPallet;
997
	type SubscriptionService = XcmPallet;
998
999
}

1000
/// Type to convert an `Origin` type value into a `MultiLocation` value which represents an interior location
For faster browsing, not all history is shown. View entire blame