parachains.rs 83.6 KB
Newer Older
Shawn Tabrizi's avatar
Shawn Tabrizi committed
1
// Copyright 2017-2020 Parity Technologies (UK) Ltd.
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 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/>.

//! Main parachains logic. For now this is just the determination of which validators do what.

19
20
use sp_std::prelude::*;
use sp_std::result;
21
use codec::{Decode, Encode};
22

23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
use sp_runtime::{
	KeyTypeId, Perbill, RuntimeDebug,
	traits::{
		Hash as HashT, BlakeTwo256, Saturating, One, Dispatchable,
		AccountIdConversion, BadOrigin, Convert, SignedExtension, AppVerify,
	},
	transaction_validity::{TransactionValidityError, ValidTransaction, TransactionValidity},
};
use sp_staking::{
	SessionIndex,
	offence::{ReportOffence, Offence, Kind},
};
use frame_support::{
	traits::KeyOwnerProofSystem,
	dispatch::{IsSubType},
	weights::{DispatchInfo, SimpleDispatchInfo},
39
};
40
use primitives::{
Ashley's avatar
Ashley committed
41
	Balance,
42
43
	parachain::{
		self, Id as ParaId, Chain, DutyRoster, AttestedCandidate, Statement, ParachainDispatchOrigin,
44
45
		UpwardMessage, ValidatorId, ActiveParas, CollatorId, Retriable, OmittedValidationData,
		CandidateReceipt, GlobalValidationSchedule, AbridgedCandidateReceipt,
46
47
		LocalValidationData, ValidityAttestation, NEW_HEADS_IDENTIFIER, PARACHAIN_KEY_TYPE_ID,
		ValidatorSignature,
48
49
	},
};
50
use frame_support::{
51
	Parameter, dispatch::DispatchResult, decl_storage, decl_module, decl_error, ensure,
52
	traits::{Currency, Get, WithdrawReason, ExistenceRequirement, Randomness},
53
};
54
use sp_runtime::transaction_validity::InvalidTransaction;
55

Gavin Wood's avatar
Gavin Wood committed
56
use inherents::{ProvideInherent, InherentData, MakeFatalError, InherentIdentifier};
57

58
use system::{ensure_none, ensure_signed};
59
use crate::attestations::{self, IncludedBlocks};
60
use crate::registrar::Registrar;
61

62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
// ranges for iteration of general block number don't work, so this
// is a utility to get around that.
struct BlockNumberRange<N> {
	low: N,
	high: N,
}

impl<N: Saturating + One + PartialOrd + PartialEq + Clone> Iterator for BlockNumberRange<N> {
	type Item = N;

	fn next(&mut self) -> Option<N> {
		if self.low >= self.high {
			return None
		}

		let item = self.low.clone();
		self.low = self.low.clone().saturating_add(One::one());
		Some(item)
	}
}

83
84
85
86
// wrapper trait because an associated type of `Currency<Self::AccountId,Balance=Balance>`
// doesn't work.`
pub trait ParachainCurrency<AccountId> {
	fn free_balance(para_id: ParaId) -> Balance;
87
	fn deduct(para_id: ParaId, amount: Balance) -> DispatchResult;
88
89
90
91
92
93
94
95
96
97
98
}

impl<AccountId, T: Currency<AccountId>> ParachainCurrency<AccountId> for T where
	T::Balance: From<Balance> + Into<Balance>,
	ParaId: AccountIdConversion<AccountId>,
{
	fn free_balance(para_id: ParaId) -> Balance {
		let para_account = para_id.into_account();
		T::free_balance(&para_account).into()
	}

99
	fn deduct(para_id: ParaId, amount: Balance) -> DispatchResult {
100
101
102
103
104
105
		let para_account = para_id.into_account();

		// burn the fee.
		let _ = T::withdraw(
			&para_account,
			amount.into(),
Gavin Wood's avatar
Gavin Wood committed
106
			WithdrawReason::Fee.into(),
107
108
109
110
111
112
113
			ExistenceRequirement::KeepAlive,
		)?;

		Ok(())
	}
}

114
/// Interface to the persistent (stash) identities of the current validators.
115
pub struct ValidatorIdentities<T>(sp_std::marker::PhantomData<T>);
116

117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
/// A structure used to report conflicting votes by validators.
///
/// It is generic over two parameters:
/// `Proof` - proof of historical ownership of a key by some validator.
/// `Hash` - a type of a hash used in the runtime.
#[derive(RuntimeDebug, Encode, Decode)]
#[derive(Clone, Eq, PartialEq)]
pub struct DoubleVoteReport<Proof, Hash> {
	/// Identity of the double-voter.
	pub identity: ValidatorId,
	/// First vote of the double-vote.
	pub first: (Statement, ValidatorSignature),
	/// Second vote of the double-vote.
	pub second: (Statement, ValidatorSignature),
	/// Proof that the validator with `identity` id was actually a validator at `parent_hash`.
	pub proof: Proof,
	/// Parent hash of the block this offence was commited.
	pub parent_hash: Hash,
}

impl<Proof: Parameter + GetSessionNumber, Hash: AsRef<[u8]>> DoubleVoteReport<Proof, Hash> {
	fn verify<T: Trait<Proof = Proof>>(
		&self,
	) -> Result<(), DoubleVoteValidityError> {
		let first = self.first.clone();
		let second = self.second.clone();
		let id = self.identity.encode();

		T::KeyOwnerProofSystem::check_proof((PARACHAIN_KEY_TYPE_ID, id), self.proof.clone())
			.ok_or(DoubleVoteValidityError::InvalidProof)?;

		// Check signatures.
		Self::verify_vote(&first, &self.parent_hash, &self.identity)?;
		Self::verify_vote(&second, &self.parent_hash, &self.identity)?;

		match (&first.0, &second.0) {
			// If issuing a `Candidate` message on a parachain block, neither a `Valid` or
			// `Invalid` vote cannot be issued on that parachain block, as the `Candidate`
			// message is an implicit validity vote.
			(Statement::Candidate(candidate_hash), Statement::Valid(hash)) |
			(Statement::Candidate(candidate_hash), Statement::Invalid(hash)) |
			(Statement::Valid(hash), Statement::Candidate(candidate_hash)) |
			(Statement::Invalid(hash), Statement::Candidate(candidate_hash))
			if *candidate_hash == *hash => {},
			// Otherwise, it is illegal to cast both a `Valid` and
			// `Invalid` vote on a given parachain block.
			(Statement::Valid(hash_1), Statement::Invalid(hash_2)) |
			(Statement::Invalid(hash_1), Statement::Valid(hash_2))
			if *hash_1 == *hash_2 => {},
			_ => {
				return Err(DoubleVoteValidityError::NotDoubleVote);
			}
		}

		Ok(())
	}

	fn verify_vote(
		vote: &(Statement, ValidatorSignature),
		parent_hash: &Hash,
		authority: &ValidatorId,
	) -> Result<(), DoubleVoteValidityError> {
		let payload = localized_payload(vote.0.clone(), parent_hash);

		if !vote.1.verify(&payload[..], authority) {
			return Err(DoubleVoteValidityError::InvalidSignature);
		}

		Ok(())
	}
}

189
190
191
192
193
194
impl<T: session::Trait> Get<Vec<T::ValidatorId>> for ValidatorIdentities<T> {
	fn get() -> Vec<T::ValidatorId> {
		<session::Module<T>>::validators()
	}
}

195
196
197
198
199
200
201
202
203
204
205
206
/// A trait to get a session number the `Proof` belongs to.
pub trait GetSessionNumber {
	fn session(&self) -> SessionIndex;
}

impl GetSessionNumber for session::historical::Proof {
	fn session(&self) -> SessionIndex {
		self.session()
	}
}

pub trait Trait: attestations::Trait + session::historical::Trait + staking::Trait {
207
208
209
210
211
	/// The outer origin type.
	type Origin: From<Origin> + From<system::RawOrigin<Self::AccountId>>;

	/// The outer call dispatch type.
	type Call: Parameter + Dispatchable<Origin=<Self as Trait>::Origin>;
212
213
214

	/// Some way of interacting with balances for fees.
	type ParachainCurrency: ParachainCurrency<Self::AccountId>;
215

216
217
218
	/// Something that provides randomness in the runtime.
	type Randomness: Randomness<Self::Hash>;

219
220
221
222
223
	/// Means to determine what the current set of active parachains are.
	type ActiveParachains: ActiveParas;

	/// The way that we are able to register parachains.
	type Registrar: Registrar<Self::AccountId>;
224
225
226
227
228
229
230
231

	/// Maximum code size for parachains, in bytes. Note that this is not
	/// the entire storage burden of the parachain, as old code is stored for
	/// `SlashPeriod` blocks.
	type MaxCodeSize: Get<u32>;

	/// Max head data size.
	type MaxHeadDataSize: Get<u32>;
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255

	/// Proof type.
	///
	/// We need this type to bind the `KeyOwnerProofSystem::Proof` to necessary bounds.
	/// As soon as https://rust-lang.github.io/rfcs/2289-associated-type-bounds.html
	/// gets in this can be simplified.
	type Proof: Parameter + GetSessionNumber;

	/// Compute and check proofs of historical key owners.
	type KeyOwnerProofSystem: KeyOwnerProofSystem<
		(KeyTypeId, Vec<u8>),
		Proof = Self::Proof,
		IdentificationTuple = Self::IdentificationTuple,
	>;

	/// An identification tuple type bound to `Parameter`.
	type IdentificationTuple: Parameter;

	/// Report an offence.
	type ReportOffence: ReportOffence<
		Self::AccountId,
		Self::IdentificationTuple,
		DoubleVoteOffence<Self::IdentificationTuple>
	>;
256
257
258
259
260
261
262
263
}

/// Origin for the parachains module.
#[derive(PartialEq, Eq, Clone)]
#[cfg_attr(feature = "std", derive(Debug))]
pub enum Origin {
	/// It comes from a parachain.
	Parachain(ParaId),
Gavin Wood's avatar
Gavin Wood committed
264
}
265

266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
/// An offence that is filed if the validator has submitted a double vote.
#[derive(RuntimeDebug)]
#[cfg_attr(feature = "std", derive(Clone, PartialEq, Eq))]
pub struct DoubleVoteOffence<Offender> {
	/// The current session index in which we report a validator.
	session_index: SessionIndex,
	/// The size of the validator set in current session/era.
	validator_set_count: u32,
	/// An offender that has submitted two conflicting votes.
	offender: Offender,
}

impl<Offender: Clone> Offence<Offender> for DoubleVoteOffence<Offender> {
	const ID: Kind = *b"para:double-vote";
	type TimeSlot = SessionIndex;

	fn offenders(&self) -> Vec<Offender> {
		vec![self.offender.clone()]
	}

	fn session_index(&self) -> SessionIndex {
		self.session_index
	}

	fn validator_set_count(&self) -> u32 {
		self.validator_set_count
	}

	fn time_slot(&self) -> Self::TimeSlot {
		self.session_index
	}

	fn slash_fraction(_offenders_count: u32, _validator_set_count: u32) -> Perbill {
		// Slash 100%.
		Perbill::from_percent(100)
	}
}

304
305
306
307
308
309
310
/// Total number of individual messages allowed in the parachain -> relay-chain message queue.
const MAX_QUEUE_COUNT: usize = 100;
/// Total size of messages allowed in the parachain -> relay-chain message queue before which no
/// further messages may be added to it. If it exceeds this then the queue may contain only a
/// single message.
const WATERMARK_QUEUE_SIZE: usize = 20000;

311
decl_storage! {
312
313
	trait Store for Module<T: Trait> as Parachains
	{
314
		/// All authorities' keys at the moment.
315
		pub Authorities get(fn authorities): Vec<ValidatorId>;
316
		/// The parachains registered at present.
317
		pub Code get(fn parachain_code): map hasher(twox_64_concat) ParaId => Option<Vec<u8>>;
318
		/// The heads of the parachains registered at present.
319
		pub Heads get(fn parachain_head): map hasher(twox_64_concat) ParaId => Option<Vec<u8>>;
320
321
		/// Messages ready to be dispatched onto the relay chain. It is subject to
		/// `MAX_MESSAGE_COUNT` and `WATERMARK_MESSAGE_SIZE`.
322
		pub RelayDispatchQueue: map hasher(twox_64_concat) ParaId => Vec<UpwardMessage>;
323
324
		/// Size of the dispatch queues. Separated from actual data in order to avoid costly
		/// decoding when checking receipt validity. First item in tuple is the count of messages
325
		///	second if the total length (in bytes) of the message payloads.
326
		pub RelayDispatchQueueSize: map hasher(twox_64_concat) ParaId => (u32, u32);
327
328
		/// The ordered list of ParaIds that have a `RelayDispatchQueue` entry.
		NeedsDispatch: Vec<ParaId>;
329

330
331
		/// `Some` if the parachain heads get updated in this block, along with the parachain IDs
		/// that did update. Ordered in the same way as `registrar::Active` (i.e. by ParaId).
332
		///
333
		/// `None` if not yet updated.
334
		pub DidUpdate: Option<Vec<ParaId>>;
335
336
337
338

		/// The mapping from parent block hashes to session indexes.
		///
		/// Used for double vote report validation.
339
		pub ParentToSessionIndex get(fn session_at_block):
340
341
342
343
344
345
			map hasher(twox_64_concat) T::Hash => SessionIndex;

		/// The era that is active currently.
		///
		/// Changes with the `ActiveEra` from `staking`. Upon these changes `ParentToSessionIndex`
		/// is pruned.
346
		ActiveEra get(fn active_era): Option<staking::EraIndex>;
thiolliere's avatar
thiolliere committed
347
	}
348
349
350
351
	add_extra_genesis {
		config(authorities): Vec<ValidatorId>;
		build(|config| Module::<T>::initialize_authorities(&config.authorities))
	}
352
353
}

354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
decl_error! {
	pub enum Error for Module<T: Trait> {
		/// Parachain heads must be updated only once in the block.
		TooManyHeadUpdates,
		/// Too many parachain candidates.
		TooManyParaCandidates,
		/// Proposed heads must be ascending order by parachain ID without duplicate.
		HeadsOutOfOrder,
		/// Candidate is for an unregistered parachain.
		UnregisteredPara,
		/// Invalid collator.
		InvalidCollator,
		/// The message queue is full. Messages will be added when there is space.
		QueueFull,
		/// The message origin is invalid.
		InvalidMessageOrigin,
		/// No validator group for parachain.
		NoValidatorGroup,
		/// Not enough validity votes for candidate.
		NotEnoughValidityVotes,
		/// The number of attestations exceeds the number of authorities.
		VotesExceedsAuthorities,
		/// Attesting validator not on this chain's validation duty.
		WrongValidatorAttesting,
		/// Invalid signature from attester.
		InvalidSignature,
		/// Extra untagged validity votes along with candidate.
		UntaggedVotes,
382
383
		/// Wrong parent head for parachain receipt.
		ParentMismatch,
384
385
		/// Head data was too large.
		HeadDataTooLarge,
386
387
388
389
		/// Para does not have enough balance to pay fees.
		CannotPayFees,
		/// Unexpected relay-parent for a candidate receipt.
		UnexpectedRelayParent,
390
391
392
	}
}

393
394
decl_module! {
	/// Parachains module.
395
	pub struct Module<T: Trait> for enum Call where origin: <T as system::Trait>::Origin {
396
397
		type Error = Error<T>;

398
		/// Provide candidate receipts for parachains, in ascending order by id.
399
		#[weight = SimpleDispatchInfo::FixedNormal(1_000_000)]
400
		pub fn set_heads(origin, heads: Vec<AttestedCandidate>) -> DispatchResult {
thiolliere's avatar
thiolliere committed
401
			ensure_none(origin)?;
402
			ensure!(!<DidUpdate>::exists(), Error::<T>::TooManyHeadUpdates);
403
404

			let active_parachains = Self::active_parachains();
405

406
			let parachain_count = active_parachains.len();
407
			ensure!(heads.len() <= parachain_count, Error::<T>::TooManyParaCandidates);
408

409
410
			let mut proceeded = Vec::with_capacity(heads.len());

411
412
413
414
415
			let schedule = GlobalValidationSchedule {
				max_code_size: T::MaxCodeSize::get(),
				max_head_data_size: T::MaxHeadDataSize::get(),
			};

416
417
418
419
			if !active_parachains.is_empty() {
				// perform integrity checks before writing to storage.
				{
					let mut last_id = None;
420

421
422
423
424
425
426
					let mut iter = active_parachains.iter();
					for head in &heads {
						let id = head.parachain_index();
						// proposed heads must be ascending order by parachain ID without duplicate.
						ensure!(
							last_id.as_ref().map_or(true, |x| x < &id),
427
							Error::<T>::HeadsOutOfOrder
428
429
430
						);

						// must be unknown since active parachains are always sorted.
431
						let (_, maybe_required_collator) = iter.find(|para| para.0 == id)
432
							.ok_or(Error::<T>::UnregisteredPara)?;
433
434

						if let Some((required_collator, _)) = maybe_required_collator {
435
							ensure!(required_collator == &head.candidate.collator, Error::<T>::InvalidCollator);
436
						}
437
438
439

						Self::check_upward_messages(
							id,
440
							&head.candidate.commitments.upward_messages,
441
442
443
444
							MAX_QUEUE_COUNT,
							WATERMARK_QUEUE_SIZE,
						)?;

445
446
447
						let id = head.parachain_index();
						proceeded.push(id);
						last_id = Some(id);
448
					}
449
450
				}

451
452
453
454
455
				let para_blocks = Self::check_candidates(
					&schedule,
					&heads,
					&active_parachains,
				)?;
456

457
458
				<attestations::Module<T>>::note_included(&heads, para_blocks);

459
				Self::update_routing(
460
					&heads,
461
				);
462

463
464
465
				// note: we dispatch new messages _after_ the call to `check_candidates`
				// which deducts any fees. if that were not the case, an upward message
				// could be dispatched and spend money that invalidated a candidate.
466
467
468
469
470
				Self::dispatch_upward_messages(
					MAX_QUEUE_COUNT,
					WATERMARK_QUEUE_SIZE,
					Self::dispatch_message,
				);
471
472
			}

473
			DidUpdate::put(proceeded);
474
475
476
477

			Ok(())
		}

478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
		/// Provide a proof that some validator has commited a double-vote.
		///
		/// The weight is 0; in order to avoid DoS a `SignedExtension` validation
		/// is implemented.
		#[weight = SimpleDispatchInfo::FixedNormal(0)]
		pub fn report_double_vote(
			origin,
			report: DoubleVoteReport<
				<T::KeyOwnerProofSystem as KeyOwnerProofSystem<(KeyTypeId, Vec<u8>)>>::Proof,
				T::Hash,
			>,
		) -> DispatchResult {
			let reporter = ensure_signed(origin)?;

			let validators = <session::Module<T>>::validators();
			let validator_set_count = validators.len() as u32;

			let session_index = report.proof.session();
			let DoubleVoteReport { identity, proof, .. } = report;

			// We have already checked this proof in `SignedExtension`, but we need
			// this here to get the full identification of the offender.
			let offender = T::KeyOwnerProofSystem::check_proof(
					(PARACHAIN_KEY_TYPE_ID, identity.encode()),
					proof,
				).ok_or("Invalid/outdated key ownership proof.")?;

			let offence = DoubleVoteOffence {
				session_index,
				validator_set_count,
				offender,
			};

			// Checks if this is actually a double vote are
			// implemented in `ValidateDoubleVoteReports::validete`.
			T::ReportOffence::report_offence(vec![reporter], offence)
				.map_err(|_| "Failed to report offence")?;

			Ok(())
		}

519
520
		fn on_initialize() {
			<Self as Store>::DidUpdate::kill();
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540

			let current_session = <session::Module<T>>::current_index();
			let parent_hash = <system::Module<T>>::parent_hash();

			match Self::active_era() {
				Some(era) => {
					if let Some(active_era) = <staking::Module<T>>::current_era() {
						if era != active_era {
							<Self as Store>::ActiveEra::put(active_era);
							<ParentToSessionIndex<T>>::remove_all();
						}
					}
				}
				None => {
					if let Some(active_era) = <staking::Module<T>>::current_era() {
						<Self as Store>::ActiveEra::set(Some(active_era));
					}
				}
			}
			<ParentToSessionIndex<T>>::insert(parent_hash, current_session);
541
542
		}

543
544
		fn on_finalize() {
			assert!(<Self as Store>::DidUpdate::exists(), "Parachain heads must be updated once in the block");
545
		}
Gav's avatar
Gav committed
546
	}
547
548
}

549
550
551
552
fn majority_of(list_len: usize) -> usize {
	list_len / 2 + list_len % 2
}

553
fn localized_payload<H: AsRef<[u8]>>(statement: Statement, parent_hash: H) -> Vec<u8> {
554
555
556
557
558
	let mut encoded = statement.encode();
	encoded.extend(parent_hash.as_ref());
	encoded
}

559
impl<T: Trait> Module<T> {
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
	/// Initialize the state of a new parachain/parathread.
	pub fn initialize_para(
		id: ParaId,
		code: Vec<u8>,
		initial_head_data: Vec<u8>,
	) {
		<Code>::insert(id, code);
		<Heads>::insert(id, initial_head_data);
	}

	pub fn cleanup_para(
		id: ParaId,
	) {
		<Code>::remove(id);
		<Heads>::remove(id);
	}

577
578
579
580
581
582
	/// Dispatch some messages from a parachain.
	fn dispatch_message(
		id: ParaId,
		origin: ParachainDispatchOrigin,
		data: &[u8],
	) {
583
		if let Ok(message_call) = <T as Trait>::Call::decode(&mut &data[..]) {
584
585
586
587
588
			let origin: <T as Trait>::Origin = match origin {
				ParachainDispatchOrigin::Signed =>
					system::RawOrigin::Signed(id.into_account()).into(),
				ParachainDispatchOrigin::Parachain =>
					Origin::Parachain(id).into(),
589
590
				ParachainDispatchOrigin::Root =>
					system::RawOrigin::Root.into(),
591
592
593
594
595
596
597
598
599
600
601
602
603
			};
			let _ok = message_call.dispatch(origin).is_ok();
			// Not much to do with the result as it is. It's up to the parachain to ensure that the
			// message makes sense.
		}
	}

	/// Ensure all is well with the upward messages.
	fn check_upward_messages(
		id: ParaId,
		upward_messages: &[UpwardMessage],
		max_queue_count: usize,
		watermark_queue_size: usize,
604
	) -> DispatchResult {
605
606
		// Either there are no more messages to add...
		if !upward_messages.is_empty() {
Gavin Wood's avatar
Gavin Wood committed
607
			let (count, size) = <RelayDispatchQueueSize>::get(id);
608
609
610
611
612
			ensure!(
				// ...or we are appending one message onto an empty queue...
				upward_messages.len() + count as usize == 1
				// ...or...
				|| (
Ashley's avatar
Ashley committed
613
614
				// ...the total messages in the queue ends up being no greater than the
				// limit...
615
616
617
618
619
620
621
622
					upward_messages.len() + count as usize <= max_queue_count
				&&
					// ...and the total size of the payloads in the queue ends up being no
					// greater than the limit.
					upward_messages.iter()
						.fold(size as usize, |a, x| a + x.data.len())
					<= watermark_queue_size
				),
623
				Error::<T>::QueueFull
624
			);
625
626
			if !id.is_system() {
				for m in upward_messages.iter() {
627
					ensure!(m.origin != ParachainDispatchOrigin::Root, Error::<T>::InvalidMessageOrigin);
628
629
				}
			}
630
631
632
633
		}
		Ok(())
	}

634
635
636
637
638
	/// Update routing information from the parachain heads. This queues upwards
	/// messages to the relay chain as well.
	fn update_routing(
		heads: &[AttestedCandidate],
	) {
639
640
641
642
		// we sort them in order to provide a fast lookup to ensure we can avoid duplicates in the
		// needs_dispatch queue.
		let mut ordered_needs_dispatch = NeedsDispatch::get();

643
644
645
646
		for head in heads.iter() {
			let id = head.parachain_index();

			// Queue up upwards messages (from parachains to relay chain).
647
648
			Self::queue_upward_messages(
				id,
649
				&head.candidate.commitments.upward_messages,
650
651
				&mut ordered_needs_dispatch,
			);
652
653
		}

654
		NeedsDispatch::put(ordered_needs_dispatch);
655
656
	}

657
	/// Place any new upward messages into our queue for later dispatch.
658
659
660
661
662
663
664
665
666
	///
	/// `ordered_needs_dispatch` is mutated to ensure it reflects the new value of
	/// `RelayDispatchQueueSize`. It is up to the caller to guarantee that it gets written into
	/// storage after this call.
	fn queue_upward_messages(
		id: ParaId,
		upward_messages: &[UpwardMessage],
		ordered_needs_dispatch: &mut Vec<ParaId>,
	) {
667
		if !upward_messages.is_empty() {
668
			RelayDispatchQueueSize::mutate(id, |&mut(ref mut count, ref mut len)| {
669
670
671
672
673
674
				*count += upward_messages.len() as u32;
				*len += upward_messages.iter()
					.fold(0, |a, x| a + x.data.len()) as u32;
			});
			// Should never be able to fail assuming our state is uncorrupted, but best not
			// to panic, even if it does.
675
676
677
678
679
			let _ = RelayDispatchQueue::append(id, upward_messages);
			if let Err(i) = ordered_needs_dispatch.binary_search(&id) {
				// same.
				ordered_needs_dispatch.insert(i, id);
			} else {
680
				sp_runtime::print("ordered_needs_dispatch contains id?!");
681
			}
682
683
684
		}
	}

685
686
	/// Simple FIFO dispatcher. This must be called after parachain fees are checked,
	/// as dispatched messages may spend parachain funds.
687
688
689
690
691
	fn dispatch_upward_messages(
		max_queue_count: usize,
		watermark_queue_size: usize,
		mut dispatch_message: impl FnMut(ParaId, ParachainDispatchOrigin, &[u8]),
	) {
692
693
		let queueds = NeedsDispatch::get();
		let mut drained_count = 0usize;
694
695
		let mut dispatched_count = 0usize;
		let mut dispatched_size = 0usize;
696
697
698
		for id in queueds.iter() {
			drained_count += 1;

Gavin Wood's avatar
Gavin Wood committed
699
			let (count, size) = <RelayDispatchQueueSize>::get(id);
700
701
702
703
704
705
706
707
			let count = count as usize;
			let size = size as usize;
			if dispatched_count == 0 || (
				dispatched_count + count <= max_queue_count
					&& dispatched_size + size <= watermark_queue_size
			) {
				if count > 0 {
					// still dispatching messages...
708
709
					RelayDispatchQueueSize::remove(id);
					let messages = RelayDispatchQueue::take(id);
710
711
712
713
714
715
716
717
718
719
720
721
722
					for UpwardMessage { origin, data } in messages.into_iter() {
						dispatch_message(*id, origin, &data);
					}
					dispatched_count += count;
					dispatched_size += size;
					if dispatched_count >= max_queue_count
						|| dispatched_size >= watermark_queue_size
					{
						break
					}
				}
			}
		}
723
		NeedsDispatch::put(&queueds[drained_count..]);
724
725
	}

726
	/// Calculate the current block's duty roster using system's random seed.
727
728
	/// Returns the duty roster along with the random seed.
	pub fn calculate_duty_roster() -> (DutyRoster, [u8; 32]) {
729
730
		let parachains = Self::active_parachains();
		let parachain_count = parachains.len();
731

732
		// TODO: use decode length. substrate #2794
733
		let validator_count = Self::authorities().len();
734
735
736
737
738
739
		let validators_per_parachain =
			if parachain_count == 0 {
				0
			} else {
				(validator_count - 1) / parachain_count
			};
740
741

		let mut roles_val = (0..validator_count).map(|i| match i {
742
743
			i if i < parachain_count * validators_per_parachain => {
				let idx = i / validators_per_parachain;
744
				Chain::Parachain(parachains[idx].0.clone())
745
			}
746
747
			_ => Chain::Relay,
		}).collect::<Vec<_>>();
748

749
750
		let mut seed = {
			let phrase = b"validator_role_pairs";
751
			let seed = T::Randomness::random(&phrase[..]);
752
753
754
755
756
757
758
759
760
761
762
763
764
765
			let seed_len = seed.as_ref().len();
			let needed_bytes = validator_count * 4;

			// hash only the needed bits of the random seed.
			// if earlier bits are influencable, they will not factor into
			// the seed used here.
			let seed_off = if needed_bytes >= seed_len {
				0
			} else {
				seed_len - needed_bytes
			};

			BlakeTwo256::hash(&seed.as_ref()[seed_off..])
		};
766

767
768
		let orig_seed = seed.clone().to_fixed_bytes();

769
		// shuffle
770
		for i in 0..(validator_count.saturating_sub(1)) {
771
772
			// 4 bytes of entropy used per cycle, 32 bytes entropy per hash
			let offset = (i * 4 % 32) as usize;
773
774

			// number of roles remaining to select from.
775
			let remaining = sp_std::cmp::max(1, (validator_count - i) as usize);
776

777
			// 8 32-bit ints per 256-bit seed.
778
779
			let val_index = u32::decode(&mut &seed[offset..offset + 4])
				.expect("using 4 bytes for a 32-bit quantity") as usize % remaining;
780

781
782
			if offset == 28 {
				// into the last 4 bytes - rehash to gather new entropy
783
				seed = BlakeTwo256::hash(seed.as_ref());
784
785
786
787
788
789
			}

			// exchange last item with randomly chosen first.
			roles_val.swap(remaining - 1, val_index);
		}

790
		(DutyRoster { validator_duty: roles_val, }, orig_seed)
791
	}
792

793
794
795
796
797
798
799
800
801
802
803
804
805
	/// Get the global validation schedule for all parachains.
	pub fn global_validation_schedule() -> GlobalValidationSchedule {
		GlobalValidationSchedule {
			max_code_size: T::MaxCodeSize::get(),
			max_head_data_size: T::MaxHeadDataSize::get(),
		}
	}

	/// Get the local validation schedule for a particular parachain.
	pub fn local_validation_data(id: &parachain::Id) -> Option<LocalValidationData> {
		Self::parachain_head(id).map(|parent_head| LocalValidationData {
			parent_head: primitives::parachain::HeadData(parent_head),
			balance: T::ParachainCurrency::free_balance(*id),
806
807
808
		})
	}

809
810
811
812
813
	/// Get the currently active set of parachains.
	pub fn active_parachains() -> Vec<(ParaId, Option<(CollatorId, Retriable)>)> {
		T::ActiveParachains::active_paras()
	}

814
815
	// check the attestations on these candidates. The candidates should have been checked
	// that each candidates' chain ID is valid.
816
	fn check_candidates(
817
		schedule: &GlobalValidationSchedule,
818
819
		attested_candidates: &[AttestedCandidate],
		active_parachains: &[(ParaId, Option<(CollatorId, Retriable)>)]
820
	) -> sp_std::result::Result<IncludedBlocks<T>, sp_runtime::DispatchError>
821
	{
822
823
824
825
		// returns groups of slices that have the same chain ID.
		// assumes the inner slice is sorted by id.
		struct GroupedDutyIter<'a> {
			next_idx: usize,
826
			inner: &'a [(usize, ParaId)],
827
828
829
		}

		impl<'a> GroupedDutyIter<'a> {
830
			fn new(inner: &'a [(usize, ParaId)]) -> Self {
831
832
833
				GroupedDutyIter { next_idx: 0, inner }
			}

834
			fn group_for(&mut self, wanted_id: ParaId) -> Option<&'a [(usize, ParaId)]> {
835
836
837
838
839
840
841
842
843
844
845
				while let Some((id, keys)) = self.next() {
					if wanted_id == id {
						return Some(keys)
					}
				}

				None
			}
		}

		impl<'a> Iterator for GroupedDutyIter<'a> {
846
			type Item = (ParaId, &'a [(usize, ParaId)]);
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861

			fn next(&mut self) -> Option<Self::Item> {
				if self.next_idx == self.inner.len() { return None }
				let start_idx = self.next_idx;
				self.next_idx += 1;
				let start_id = self.inner[start_idx].1;

				while self.inner.get(self.next_idx).map_or(false, |&(_, ref id)| id == &start_id) {
					self.next_idx += 1;
				}

				Some((start_id, &self.inner[start_idx..self.next_idx]))
			}
		}

862
863
		let authorities = Self::authorities();
		let (duty_roster, random_seed) = Self::calculate_duty_roster();
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886

		// convert a duty roster, which is originally a Vec<Chain>, where each
		// item corresponds to the same position in the session keys, into
		// a list containing (index, parachain duty) where indices are into the session keys.
		// this list is sorted ascending by parachain duty, just like the
		// parachain candidates are.
		let make_sorted_duties = |duty: &[Chain]| {
			let mut sorted_duties = Vec::with_capacity(duty.len());
			for (val_idx, duty) in duty.iter().enumerate() {
				let id = match duty {
					Chain::Relay => continue,
					Chain::Parachain(id) => id,
				};

				let idx = sorted_duties.binary_search_by_key(&id, |&(_, ref id)| id)
					.unwrap_or_else(|idx| idx);

				sorted_duties.insert(idx, (val_idx, *id));
			}

			sorted_duties
		};

887
888
		// computes the omitted validation data for a particular parachain.
		let full_candidate = |abridged: &AbridgedCandidateReceipt|
889
			-> sp_std::result::Result<CandidateReceipt, sp_runtime::DispatchError>
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
		{
			let para_id = abridged.parachain_index;
			let parent_head = match Self::parachain_head(&para_id)
				.map(primitives::parachain::HeadData)
			{
				Some(p) => p,
				None => Err(Error::<T>::ParentMismatch)?,
			};

			let omitted = OmittedValidationData {
				global_validation: schedule.clone(),
				local_validation: LocalValidationData {
					parent_head,
					balance: T::ParachainCurrency::free_balance(para_id),
				},
			};

			Ok(abridged.clone().complete(omitted))
		};

910
911
		let sorted_validators = make_sorted_duties(&duty_roster.validator_duty);

912
		let parent_hash = <system::Module<T>>::parent_hash();
913
914
915
916
		let localized_payload = |statement: Statement| localized_payload(statement, parent_hash);

		let mut validator_groups = GroupedDutyIter::new(&sorted_validators[..]);

917
		let mut para_block_hashes = Vec::new();
918

919
		for candidate in attested_candidates {
920
921
			let para_id = candidate.parachain_index();
			let validator_group = validator_groups.group_for(para_id)
922
				.ok_or(Error::<T>::NoValidatorGroup)?;
923

924
925
926
927
928
929
			// NOTE: when changing this to allow older blocks,
			// care must be taken in the availability store pruning to ensure that
			// data is stored correctly. A block containing a candidate C can be
			// orphaned before a block containing C is finalized. Care must be taken
			// not to prune the data for C simply because an orphaned block contained
			// it.
930
			ensure!(
931
932
				candidate.candidate().relay_parent.as_ref() == parent_hash.as_ref(),
				Error::<T>::UnexpectedRelayParent,
933
934
			);

935
936
			ensure!(
				candidate.validity_votes.len() >= majority_of(validator_group.len()),
937
				Error::<T>::NotEnoughValidityVotes,
938
939
			);

940
941
			ensure!(
				candidate.validity_votes.len() <= authorities.len(),
942
				Error::<T>::VotesExceedsAuthorities,
943
944
			);

945
			ensure!(
946
				schedule.max_head_data_size >= candidate.candidate().head_data.0.len() as _,
947
948
949
				Error::<T>::HeadDataTooLarge,
			);

950
951
952
953
954
955
956
957
			let full_candidate = full_candidate(candidate.candidate())?;
			let fees = full_candidate.commitments.fees;

			ensure!(
				full_candidate.local_validation.balance >= full_candidate.commitments.fees,
				Error::<T>::CannotPayFees,
			);

958
959
			T::ParachainCurrency::deduct(para_id, fees)?;

960
			let candidate_hash = candidate.candidate().hash();
961
962
963
			let mut encoded_implicit = None;
			let mut encoded_explicit = None;

964
965
			let mut expected_votes_len = 0;
			for (vote_index, (auth_index, _)) in candidate.validator_indices
966
967
968
				.iter()
				.enumerate()
				.filter(|(_, bit)| *bit)
969
				.enumerate()
970
			{
971
				let validity_attestation = match candidate.validity_votes.get(vote_index) {
972
					None => Err(Error::<T>::NotEnoughValidityVotes)?,
973
974
975
976
977
					Some(v) => {
						expected_votes_len = vote_index + 1;
						v
					}
				};
978
979

				if validator_group.iter().find(|&(idx, _)| *idx == auth_index).is_none() {
980
					Err(Error::<T>::WrongValidatorAttesting)?
981
982
983
984
985
				}

				let (payload, sig) = match validity_attestation {
					ValidityAttestation::Implicit(sig) => {
						let payload = encoded_implicit.get_or_insert_with(|| localized_payload(
986
							Statement::Candidate(candidate_hash),
987
988
989
990
991
992
						));

						(payload, sig)
					}
					ValidityAttestation::Explicit(sig) => {
						let payload = encoded_explicit.get_or_insert_with(|| localized_payload(
993
							Statement::Valid(candidate_hash),
994
995
996
997
998
999
1000
						));

						(payload, sig)
					}
				};

				ensure!(
1001
					sig.verify(&payload[..], &authorities[auth_index]),
1002
					Error::<T>::InvalidSignature,
1003
1004
				);
			}
1005

1006
			ensure!(
1007
				candidate.validity_votes.len() == expected_votes_len,
1008
				Error::<T>::UntaggedVotes
1009
			);
1010
1011

			para_block_hashes.push(candidate_hash);
1012
1013
		}

1014
1015
1016
1017
		Ok(IncludedBlocks {
			actual_number: <system::Module<T>>::block_number(),
			session: <session::Module<T>>::current_index(),
			random_seed,
1018
			active_parachains: active_parachains.iter().map(|x| x.0).collect(),
1019
1020
			para_blocks: para_block_hashes,
		})
1021
1022
	}

1023
1024
1025
1026
1027
1028
1029
	fn initialize_authorities(authorities: &[ValidatorId]) {
		if !authorities.is_empty() {
			assert!(Authorities::get().is_empty(), "Authorities are already initialized!");
			Authorities::put(authorities);
		}
	}

1030
/*
1031
	// TODO: Consider integrating if needed. (https://github.com/paritytech/polkadot/issues/223)
1032
1033
1034
1035
1036
1037
	/// Extract the parachain heads from the block.
	pub fn parachain_heads(&self) -> &[CandidateReceipt] {
		let x = self.inner.extrinsics.get(PARACHAINS_SET_POSITION as usize).and_then(|xt| match xt.function {
			Call::Parachains(ParachainsCall::set_heads(ref x)) => Some(&x[..]),
			_ => None
		});
1038

1039
1040
1041
		match x {
			Some(x) => x,
			None => panic!("Invalid polkadot block asserted at {:?}", self.file_line),
1042
1043
		}
	}
1044
*/
1045
1046
}

1047
impl<T: Trait> sp_runtime::BoundToRuntimeAppPublic for Module<T> {
Gavin Wood's avatar
Gavin Wood committed
1048
1049
1050
	type Public = ValidatorId;
}

1051
impl<T: Trait> session::OneSessionHandler<T::AccountId> for Module<T> {
1052
	type Key = ValidatorId;
1053

Gavin Wood's avatar
Gavin Wood committed
1054
1055
1056
	fn on_genesis_session<'a, I: 'a>(validators: I)
		where I: Iterator<Item=(&'a T::AccountId, Self::Key)>
	{
1057
		Self::initialize_authorities(&validators.map(|(_, key)| key).collect::<Vec<_>>());
Gavin Wood's avatar
Gavin Wood committed
1058
1059
	}

1060
1061
1062
1063
	fn on_new_session<'a, I: 'a>(changed: bool, validators: I, _queued: I)
		where I: Iterator<Item=(&'a T::AccountId, Self::Key)>
	{
		if changed {
1064
			<Self as Store>::Authorities::put(validators.map(|(_, key)| key).collect::<Vec<_>>());
1065
1066
1067
1068
1069
1070
		}
	}

	fn on_disabled(_i: usize) { }
}

1071
pub type InherentType = Vec<AttestedCandidate>;
1072

1073
1074
impl<T: Trait> ProvideInherent for Module<T> {
	type Call = Call<T>;
Gavin Wood's avatar
Gavin Wood committed
1075
	type Error = MakeFatalError<inherents::Error>;
1076
	const INHERENT_IDENTIFIER: InherentIdentifier = NEW_HEADS_IDENTIFIER;
1077

1078
	fn create_inherent(data: &InherentData) -> Option<Self::Call> {
1079
		let data = data.get_data::<InherentType>(&NEW_HEADS_IDENTIFIER)
1080
1081
			.expect("Parachain heads could not be decoded.")
			.expect("No parachain heads found in inherent data.");
1082

1083
		Some(Call::set_heads(data))
1084
1085
1086
	}
}

1087
1088
/// Ensure that the origin `o` represents a parachain.
/// Returns `Ok` with the parachain ID that effected the extrinsic or an `Err` otherwise.
1089
pub fn ensure_parachain<OuterOrigin>(o: OuterOrigin) -> result::Result<ParaId, BadOrigin>
1090
1091
1092
1093
	where OuterOrigin: Into<result::Result<Origin, OuterOrigin>>
{
	match o.into() {
		Ok(Origin::Parachain(id)) => Ok(id),
1094
		_ => Err(BadOrigin),
1095
1096
1097
	}
}

1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194

/// Ensure that double vote reports are only processed if valid.
#[derive(Encode, Decode, Clone, Eq, PartialEq)]
pub struct ValidateDoubleVoteReports<T>(sp_std::marker::PhantomData<T>);

impl<T> sp_std::fmt::Debug for ValidateDoubleVoteReports<T> where
{
	fn fmt(&self, f: &mut sp_std::fmt::Formatter) -> sp_std::fmt::Result {
		write!(f, "ValidateDoubleVoteReports<T>")
	}
}

/// Custom validity error used while validating double vote reports.
#[derive(RuntimeDebug)]
#[repr(u8)]
pub enum DoubleVoteValidityError {
	/// The authority being reported is not in the authority set.
	NotAnAuthority = 0,

	/// Failed to convert offender's `FullIdentificationOf`.
	FailedToConvertId = 1,

	/// The signature on one or both of the statements in the report is wrong.
	InvalidSignature = 2,

	/// The two statements in the report are not conflicting.
	NotDoubleVote = 3,

	/// Invalid report. Indicates that statement doesn't match the attestation on one of the votes.
	InvalidReport = 4,

	/// The proof provided in the report is not valid.
	InvalidProof = 5,
}

impl<T: Trait + Send + Sync> SignedExtension for ValidateDoubleVoteReports<T> where
	<T as system::Trait>::Call: IsSubType<Module<T>, T>
{
	const IDENTIFIER: &'static str = "ValidateDoubleVoteReports";
	type AccountId = T::AccountId;
	type Call = <T as system::Trait>::Call;
	type AdditionalSigned = ();
	type Pre = ();
	type DispatchInfo = DispatchInfo;

	fn additional_signed(&self)
		-> sp_std::result::Result<Self::AdditionalSigned, TransactionValidityError>
	{
		Ok(())
	}

	fn validate(
		&self,
		_who: &Self::AccountId,
		call: &Self::Call,
		_info: DispatchInfo,
		_len: usize,
	) -> TransactionValidity {
		let r = ValidTransaction::default();

		if let Some(local_call) = call.is_sub_type() {
			if let Call::report_double_vote(report) = local_call {
				let validators = <session::Module<T>>::validators();
				let parent_hash = report.parent_hash;

				let expected_session = Module::<T>::session_at_block(parent_hash);
				let session = report.proof.session();

				if session != expected_session {
					return Err(InvalidTransaction::BadProof.into());
				}

				let authorities = Module::<T>::authorities();
				let offender_idx = match authorities.iter().position(|a| *a == report.identity) {
					Some(idx) => idx,
					None => return Err(InvalidTransaction::Custom(
						DoubleVoteValidityError::NotAnAuthority as u8).into()
					),
				};

				if T::FullIdentificationOf::convert(validators[offender_idx].clone()).is_none() {
					return Err(InvalidTransaction::Custom(
						DoubleVoteValidityError::FailedToConvertId as u8).into()
					);
				}

				report
					.verify::<T>()
					.map_err(|e| TransactionValidityError::from(InvalidTransaction::Custom(e as u8)))?;
			}
		}

		Ok(r)
	}
}


1195
1196
1197
#[cfg(test)]
mod tests {
	use super::*;
1198
	use super::Call as ParachainsCall;
1199
	use bitvec::{bitvec, vec::BitVec};
1200
1201
1202
1203
	use sp_io::TestExternalities;
	use sp_core::{H256, Blake2Hasher};
	use sp_trie::NodeCodec;
	use sp_runtime::{
1204
1205
1206
1207
1208
1209
		impl_opaque_keys,
		Perbill, curve::PiecewiseLinear, testing::{Header},
		traits::{
			BlakeTwo256, IdentityLookup, OnInitialize, OnFinalize, SaturatedConversion,
			OpaqueKeys,
		},
1210
	};
1211
	use primitives::{
Gavin Wood's avatar
Gavin Wood committed
1212
1213
		parachain::{
			CandidateReceipt, HeadData, ValidityAttestation, ValidatorId, Info as ParaInfo,
1214
			Scheduling, LocalValidationData, CandidateCommitments,
Gavin Wood's avatar
Gavin Wood committed
1215
		},
1216
		BlockNumber,
1217
	};
1218
	use keyring::Sr25519Keyring;
1219
	use frame_support::{
Ashley's avatar
Ashley committed
1220
		impl_outer_origin, impl_outer_dispatch, assert_ok, assert_err, parameter_types,
1221
	};
1222
	use crate::parachains;
1223
1224
	use crate::registrar;
	use crate::slots;
1225
1226
	use session::{SessionHandler, SessionManager};
	use staking::EraIndex;
1227

Ashley's avatar
Ashley committed
1228
1229
1230
1231
1232
1233
	// result of <NodeCodec<Blake2Hasher> as trie_db::NodeCodec<Blake2Hasher>>::hashed_null_node()
	const EMPTY_TRIE_ROOT: [u8; 32] = [
		3, 23, 10, 46, 117, 151, 183, 183, 227, 216, 76, 5, 57, 29, 19, 154,
		98, 177, 87, 231, 135, 134, 216, 192, 130, 242, 157, 207, 76, 17, 19, 20
	];

1234
	impl_outer_origin! {
1235
1236
1237
1238
1239
1240
1241
1242
1243
		pub enum Origin for Test {
			parachains
		}
	}

	impl_outer_dispatch! {
		pub enum Call for Test where origin: Origin {
			parachains::Parachains,
		}
1244
1245
	}

1246
1247
1248
1249
1250
1251
	impl_opaque_keys! {
		pub struct TestSessionKeys {
			pub parachain_validator: super::Module<Test>,
		}
	}

Gav Wood's avatar
Gav Wood committed
1252
	#[derive(Clone, Eq, PartialEq)]
1253
	pub struct Test;
1254
	parameter_types! {
1255
		pub const BlockHashCount: u32 = 250;
1256
1257
1258
		pub const MaximumBlockWeight: u32 = 4 * 1024 * 1024;
		pub const MaximumBlockLength: u32 = 4 * 1024 * 1024;
		pub const AvailableBlockRatio: Perbill = Perbill::from_percent(75);
1259
	}
Gavin Wood's avatar