Skip to content
parachains.rs 29.9 KiB
Newer Older
// Copyright 2017 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/>.

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

use rstd::prelude::*;
Gavin Wood's avatar
Gavin Wood committed
use codec::{Decode, HasCompact};
use bitvec::BigEndian;
Gavin Wood's avatar
Gavin Wood committed
use sr_primitives::traits::{Hash as HashT, BlakeTwo256, Member};
use primitives::{Hash, parachain::{Id as ParaId, Chain, DutyRoster, AttestedCandidate, Statement, AccountIdConversion}};
Gavin Wood's avatar
Gavin Wood committed
use srml_support::{StorageValue, StorageMap, Parameter, dispatch::Result};
#[cfg(feature = "std")]
use srml_support::storage::hashed::generator;
use inherents::{ProvideInherent, InherentData, RuntimeString, MakeFatalError, InherentIdentifier};

#[cfg(any(feature = "std", test))]
Gav Wood's avatar
Gav Wood committed
use sr_primitives::{StorageOverlay, ChildrenStorageOverlay};
#[cfg(any(feature = "std", test))]
use rstd::marker::PhantomData;

thiolliere's avatar
thiolliere committed
use system::ensure_none;
Gavin Wood's avatar
Gavin Wood committed
/// Parachain registration API.
pub trait ParachainRegistrar<AccountId> {
	/// An identifier for a parachain.
	type ParaId: Member + Parameter + Default + AccountIdConversion<AccountId> + Copy + HasCompact;

	/// Create a new unique parachain identity for later registration.
	fn new_id() -> Self::ParaId;

	/// Register a parachain with given `code` and `initial_head_data`. `id` must not yet be registered or it will
	/// result in a error.
	fn register_parachain(id: Self::ParaId, code: Vec<u8>, initial_head_data: Vec<u8>) -> Result;

	/// Deregister a parachain with given `id`. If `id` is not currently registered, an error is returned.
	fn deregister_parachain(id: Self::ParaId) -> Result;
}

impl<T: Trait> ParachainRegistrar<T::AccountId> for Module<T> {
	type ParaId = ParaId;
	fn new_id() -> ParaId {
		<NextFreeId<T>>::mutate(|n| { let r = *n; *n = ParaId::from(u32::from(*n) + 1); r })
	}
	fn register_parachain(id: ParaId, code: Vec<u8>, initial_head_data: Vec<u8>) -> Result {
		let mut parachains = Self::active_parachains();
		match parachains.binary_search(&id) {
			Ok(_) => fail!("Parachain already exists"),
			Err(idx) => parachains.insert(idx, id),
		}

		<Code<T>>::insert(id, code);
		<Parachains<T>>::put(parachains);
		<Heads<T>>::insert(id, initial_head_data);

		Ok(())
	}
	fn deregister_parachain(id: ParaId) -> Result {
		let mut parachains = Self::active_parachains();
		match parachains.binary_search(&id) {
			Ok(idx) => { parachains.remove(idx); }
			Err(_) => return Ok(()),
		}

		<Code<T>>::remove(id);
		<Heads<T>>::remove(id);

		// clear all routing entries to and from other parachains.
		for other in parachains.iter().cloned() {
			<Routing<T>>::remove((id, other));
			<Routing<T>>::remove((other, id));
		}

		<Parachains<T>>::put(parachains);

		Ok(())
	}
}

pub trait Trait: session::Trait {
}
// 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
];

Gav's avatar
Gav committed
	trait Store for Module<T: Trait> as Parachains {
		// Vector of all parachain IDs.
		pub Parachains get(active_parachains): Vec<ParaId>;
Gav's avatar
Gav committed
		// The parachains registered at present.
		pub Code get(parachain_code): map ParaId => Option<Vec<u8>>;
		// The heads of the parachains registered at present.
		pub Heads get(parachain_head): map ParaId => Option<Vec<u8>>;
		// message routing roots (from, to).
		pub Routing: map (ParaId, ParaId) => Option<Hash>;
Gav's avatar
Gav committed

		// Did the parachain heads get updated in this block?
		DidUpdate: bool;
Gavin Wood's avatar
Gavin Wood committed

		/// The next unused ParaId value.
		NextFreeId: ParaId;
	}
	add_extra_genesis {
		config(parachains): Vec<(ParaId, Vec<u8>, Vec<u8>)>;
		config(_phdata): PhantomData<T>;
Gav Wood's avatar
Gav Wood committed
		build(|storage: &mut StorageOverlay, _: &mut ChildrenStorageOverlay, config: &GenesisConfig<T>| {
			let mut p = config.parachains.clone();
			p.sort_unstable_by_key(|&(ref id, _, _)| id.clone());
			p.dedup_by_key(|&mut (ref id, _, _)| id.clone());

			let only_ids: Vec<_> = p.iter().map(|&(ref id, _, _)| id).cloned().collect();

			<Parachains<T> as generator::StorageValue<_>>::put(&only_ids, storage);

			for (id, code, genesis) in p {
				// no ingress -- a chain cannot be routed to until it is live.
				<Code<T> as generator::StorageMap<_, _>>::insert(&id, &code, storage);
				<Heads<T> as generator::StorageMap<_, _>>::insert(&id, &genesis, storage);
			}
		});
	}
}

decl_module! {
	/// Parachains module.
	pub struct Module<T: Trait> for enum Call where origin: T::Origin {
		/// Provide candidate receipts for parachains, in ascending order by id.
		fn set_heads(origin, heads: Vec<AttestedCandidate>) -> Result {
thiolliere's avatar
thiolliere committed
			ensure_none(origin)?;
			ensure!(!<DidUpdate<T>>::exists(), "Parachain heads must be updated only once in the block");

			let active_parachains = Self::active_parachains();

			// perform integrity checks before writing to storage.
			{
				let n_parachains = active_parachains.len();
				ensure!(heads.len() <= n_parachains, "Too many parachain candidates");

				let mut last_id = None;
				let mut iter = active_parachains.iter();
				for head in &heads {
					// proposed heads must be ascending order by parachain ID without duplicate.
					ensure!(
						last_id.as_ref().map_or(true, |x| x < &head.parachain_index()),
						"Parachain candidates out of order by ID"
					);

					// must be unknown since active parachains are always sorted.
					ensure!(
						iter.find(|x| x == &&head.parachain_index()).is_some(),
						"Submitted candidate for unregistered or out-of-order parachain {}"
					);

					Self::check_egress_queue_roots(&head, &active_parachains)?;

					last_id = Some(head.parachain_index());
			Self::check_attestations(&heads)?;

			for head in heads {
				let id = head.parachain_index();
				<Heads<T>>::insert(id, head.candidate.head_data.0);

				// update egress.
				for &(to, root) in &head.candidate.egress_queue_roots {
					<Routing<T>>::insert((id, to), root);
				}
			}

			<DidUpdate<T>>::put(true);

			Ok(())
		}

		/// Register a parachain with given code.
		/// Fails if given ID is already used.
		pub fn register_parachain(id: ParaId, code: Vec<u8>, initial_head_data: Vec<u8>) -> Result {
Gavin Wood's avatar
Gavin Wood committed
			<Self as ParachainRegistrar<T::AccountId>>::register_parachain(id, code, initial_head_data)
Loading full blame...