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::*;
use rstd::{result, collections::btree_map::BTreeMap};
use parity_codec::{Decode, HasCompact};
use srml_support::{decl_storage, decl_module, fail, ensure};
use sr_primitives::traits::{Hash as HashT, BlakeTwo256, Member, CheckedConversion, Saturating, One};
use sr_primitives::weights::SimpleDispatchInfo;
use primitives::{Hash, Balance, parachain::{
self, Id as ParaId, Chain, DutyRoster, AttestedCandidate, Statement, AccountIdConversion,
ParachainDispatchOrigin, UpwardMessage, BlockIngressRoots, ActiveParas, CollatorId,
DispatchOrigins
use {system, session};
StorageValue, StorageMap, storage::AppendableStorageMap, Parameter, Dispatchable, dispatch::Result,
traits::{Currency, WithdrawReason, ExistenceRequirement}
#[cfg(feature = "std")]
use srml_support::storage::hashed::generator;
use inherents::{ProvideInherent, InherentData, RuntimeString, MakeFatalError, InherentIdentifier};
#[cfg(any(feature = "std", test))]
use sr_primitives::{StorageOverlay, ChildrenStorageOverlay};
#[cfg(any(feature = "std", test))]
use rstd::marker::PhantomData;
// 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)
}
}
// creates a range iterator between `low` and `high`. `low` must be <= `high`.
fn number_range<N>(low: N, high: N) -> BlockNumberRange<N> {
BlockNumberRange { low, high }
}
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
// 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;
fn deduct(para_id: ParaId, amount: Balance) -> Result;
}
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(¶_account).into()
}
fn deduct(para_id: ParaId, amount: Balance) -> Result {
let para_account = para_id.into_account();
// burn the fee.
let _ = T::withdraw(
¶_account,
amount.into(),
WithdrawReason::Fee,
ExistenceRequirement::KeepAlive,
)?;
Ok(())
}
}
/// 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>;
/// Some way of interacting with balances for fees.
type ParachainCurrency: ParachainCurrency<Self::AccountId>;
/// Means to determine what the current set of active parachains are.
type ActiveParachains: ActiveParas;
}
/// 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),
// 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
];
/// 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;
trait Store for Module<T: Trait> as Parachains {
// 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>>;
// The watermark heights of the parachains registered at present.
// For every parachain, this is the block height from which all messages targeting
// that parachain have been processed. Can be `None` only if the parachain doesn't exist.
pub Watermarks get(watermark): map ParaId => Option<T::BlockNumber>;
/// Unrouted ingress. Maps (BlockNumber, to_chain) pairs to [(from_chain, egress_root)].
///
/// There may be an entry under (i, p) in this map for every i between the parachain's
/// watermark and the current block.
pub UnroutedIngress: map (T::BlockNumber, ParaId) => Option<Vec<(ParaId, Hash)>>;
/// Messages ready to be dispatched onto the relay chain. It is subject to
/// `MAX_MESSAGE_COUNT` and `WATERMARK_MESSAGE_SIZE`.
pub RelayDispatchQueue: map ParaId => Vec<UpwardMessage>;
/// 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
// second if the total length (in bytes) of the message payloads.
pub RelayDispatchQueueSize: map ParaId => (u32, u32);
/// The ordered list of ParaIds that have a `RelayDispatchQueue` entry.
NeedsDispatch: Vec<ParaId>;
// Did the parachain heads get updated in this block?
DidUpdate: bool;
}
add_extra_genesis {
config(parachains): Vec<(ParaId, Vec<u8>, Vec<u8>)>;
build(|storage: &mut StorageOverlay, _: &mut ChildrenStorageOverlay, config: &GenesisConfig<T>| {
use sr_primitives::traits::Zero;
p.sort_unstable_by_key(|&(ref id, _, _)| *id);
p.dedup_by_key(|&mut (ref id, _, _)| *id);
let only_ids: Vec<_> = p.iter().map(|&(ref id, _, _)| id).cloned().collect();
<Parachains as generator::StorageValue<_>>::put(&only_ids, storage);
// no ingress -- a chain cannot be routed to until it is live.
<Code as generator::StorageMap<_, _>>::insert(&id, &code, storage);
<Heads as generator::StorageMap<_, _>>::insert(&id, &genesis, storage);
<Watermarks<T> as generator::StorageMap<_, _>>::insert(&id, &Zero::zero(), storage);
}
});
}
}
decl_module! {
/// Parachains module.
pub struct Module<T: Trait> for enum Call where origin: <T as system::Trait>::Origin {
/// Provide candidate receipts for parachains, in ascending order by id.
#[weight = SimpleDispatchInfo::FixedNormal(1_000_000)]
fn set_heads(origin, heads: Vec<AttestedCandidate>) -> Result {
ensure!(!<DidUpdate>::exists(), "Parachain heads must be updated only once in the block");
let mut active_parachains = Self::active_parachains();
active_parachains.sort_by_key(|(id, _)| id);
// TODO: verify that the heads each come from the right collator, if one is specified.
let parachain_count = active_parachains.len();
ensure!(heads.len() <= parachain_count, "Too many parachain candidates");
if !active_parachains.is_empty() {
// perform integrity checks before writing to storage.
{
let mut last_id = None;
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),
"candidate out of order"
);
// must be unknown since active parachains are always sorted.
let (_, maybe_required_collator, origins) = iter.find(|para| para.0 == id)
.ok_or("candidate for unregistered parachain {}")?;
if let Some(required_collator) = maybe_required_collator {
ensure!(required_collator == head.candidate.collator, "invalid collator");
}
Self::check_upward_messages(
id,
&head.candidate.upward_messages,
MAX_QUEUE_COUNT,
WATERMARK_QUEUE_SIZE,
)?;
Self::check_egress_queue_roots(&head, &active_parachains)?;
last_id = Some(head.parachain_index());
}
Self::check_candidates(&heads)?;
let current_number = <system::Module<T>>::block_number();
Self::update_routing(
current_number,
&heads
);
Self::dispatch_upward_messages(
&active_parachains,
MAX_QUEUE_COUNT,
WATERMARK_QUEUE_SIZE,
Self::dispatch_message,
);
Ok(())
}
/// Register a parachain with given code.
/// Fails if given ID is already used.
#[weight = SimpleDispatchInfo::FixedOperational(5_000_000)]
pub fn register_parachain(origin, id: ParaId, code: Vec<u8>, initial_head_data: Vec<u8>) -> Result {
ensure_root(origin)?;
<Self as ParachainRegistrar<T::AccountId>>::register_parachain(id, code, initial_head_data)
}
/// Deregister a parachain with given id
#[weight = SimpleDispatchInfo::FixedOperational(10_000)]
pub fn deregister_parachain(origin, id: ParaId) -> Result {
ensure_root(origin)?;
<Self as ParachainRegistrar<T::AccountId>>::deregister_parachain(id)
assert!(<Self as Store>::DidUpdate::take(), "Parachain heads must be updated once in the block");
}
fn majority_of(list_len: usize) -> usize {
list_len / 2 + list_len % 2
}
fn localized_payload(statement: Statement, parent_hash: ::primitives::Hash) -> Vec<u8> {
let mut encoded = statement.encode();
encoded.extend(parent_hash.as_ref());
encoded
}
impl<T: Trait> Module<T> {
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
/// Initialize the state of a new parachain/parathread.
fn initialize_para(
id: ParaId,
code: Vec<u8>,
initial_head_data: Vec<u8>,
) {
<Code>::insert(id, code);
<Heads>::insert(id, initial_head_data);
// Because there are no ordering guarantees that inherents
// are applied before regular transactions, a parachain candidate could
// be registered before the `UpdateHeads` inherent is processed. If so, messages
// could be sent to a parachain in the block it is registered.
<Watermarks<T>>::insert(id, <system::Module<T>>::block_number().saturating_sub(One::one()));
}
fn cleanup_para(
id: ParaId,
) {
<Code>::remove(id);
<Heads>::remove(id);
let watermark = <Watermarks<T>>::take(id);
// clear all routing entries _to_. But not those _from_.
if let Some(watermark) = watermark {
let now = <system::Module<T>>::block_number();
// iterate over all blocks between watermark and now + 1 (since messages might
// have already been sent to `id` in this block.
for unrouted_block in number_range(watermark, now).map(|n| n.saturating_add(One::one())) {
<UnroutedIngress<T>>::remove(&(unrouted_block, id));
}
}
}
/// Dispatch some messages from a parachain.
fn dispatch_message(
id: ParaId,
origin: ParachainDispatchOrigin,
data: &[u8],
) {
if let Some(message_call) = T::Call::decode(&mut &data[..]) {
let origin: <T as Trait>::Origin = match origin {
ParachainDispatchOrigin::Signed =>
system::RawOrigin::Signed(id.into_account()).into(),
ParachainDispatchOrigin::Parachain =>
Origin::Parachain(id).into(),
ParachainDispatchOrigin::Root =>
system::RawOrigin::Root.into(),
};
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],
origins: DispatchOrigins,
max_queue_count: usize,
watermark_queue_size: usize,
) -> Result {
// Either there are no more messages to add...
if !upward_messages.is_empty() {
let (count, size) = <RelayDispatchQueueSize>::get(id);
ensure!(
// ...or we are appending one message onto an empty queue...
upward_messages.len() + count as usize == 1
// ...or...
|| (
// ...the total messages in the queue ends up being no greater than the
// limit...
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
),
"Messages added when queue full"
);
if origins != DispatchOrigins::Root {
for m in upward_messages.iter() {
ensure!(m.origin != Root, "bad message origin");
}
}
/// Update routing information from the parachain heads. This queues upwards
/// messages to the relay chain as well.
fn update_routing(
now: T::BlockNumber,
heads: &[AttestedCandidate],
) {
// TODO: per-chain watermark
// https://github.com/paritytech/polkadot/issues/286
let watermark = now.saturating_sub(One::one());
let mut ingress_update = BTreeMap::new();
// 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();
ordered_needs_dispatch.sort_unstable();
for head in heads.iter() {
let id = head.parachain_index();
<Heads>::insert(id, &head.candidate.head_data.0);
let last_watermark = <Watermarks<T>>::mutate(id, |mark| {
rstd::mem::replace(mark, Some(watermark))
});
if let Some(last_watermark) = last_watermark {
// Discard routed ingress.
for routed_height in number_range(last_watermark, watermark) {
<UnroutedIngress<T>>::remove(&(routed_height, id));
}
}
// place our egress root to `to` into the ingress table for (now, `to`).
for &(to, root) in &head.candidate.egress_queue_roots {
ingress_update.entry(to).or_insert_with(Vec::new).push((id, root));
}
// Queue up upwards messages (from parachains to relay chain).
Self::queue_upward_messages(
id,
&head.candidate.upward_messages,
&ordered_needs_dispatch[..]
);
}
// apply the ingress update.
for (to, ingress_roots) in ingress_update {
<UnroutedIngress<T>>::insert((now, to), ingress_roots);
}
}
/// Place any new upward messages into our queue for later dispatch.
fn queue_upward_messages(
id: ParaId,
upward_messages: &[UpwardMessage],
ordered_needs_dispatch: &[ParaId],
) {
<RelayDispatchQueueSize>::mutate(id, |&mut(ref mut count, ref mut len)| {
*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.
let _ = RelayDispatchQueue::append(id, upward_messages);
if ordered_needs_dispatch.binary_search(&id).is_err() {
NeedsDispatch::append(id);
}
/// Simple FIFO dispatcher.
fn dispatch_upward_messages(
now: T::BlockNumber,
max_queue_count: usize,
watermark_queue_size: usize,
mut dispatch_message: impl FnMut(ParaId, ParachainDispatchOrigin, &[u8]),
) {
let queueds = NeedsDispatch::get();
let mut drained_count = 0usize;
let mut dispatched_count = 0usize;
let mut dispatched_size = 0usize;
for id in queueds.iter() {
drained_count += 1;
let (count, size) = <RelayDispatchQueueSize>::get(id);
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...
RelayDispatchQueueSize::remove(id);
let messages = RelayDispatchQueue::take(id);
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
}
}
}
}
HasDisatchQueue::put_ref(&qd[drained_count..]);
/// Calculate the current block's duty roster using system's random seed.
pub fn calculate_duty_roster() -> DutyRoster {
let parachains = Self::active_parachains();
let parachain_count = parachains.len();
// TODO: should be maintaining its own PV "authority" set rather than getting them from Aura
let validator_count = crate::Aura::authorities().len();
let validators_per_parachain =
if parachain_count == 0 {
0
} else {
(validator_count - 1) / parachain_count
};
let mut roles_val = (0..validator_count).map(|i| match i {
i if i < parachain_count * validators_per_parachain => {
let idx = i / validators_per_parachain;
Chain::Parachain(parachains[idx].0.clone())
_ => Chain::Relay,
}).collect::<Vec<_>>();
let mut seed = {
let phrase = b"validator_role_pairs";
let seed = system::Module::<T>::random(&phrase[..]);
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..])
};
// shuffle
for i in 0..(validator_count - 1) {
// 4 bytes of entropy used per cycle, 32 bytes entropy per hash
let offset = (i * 4 % 32) as usize;
// number of roles remaining to select from.
let remaining = (validator_count - i) as usize;
let val_index = u32::decode(&mut &seed[offset..offset + 4])
.expect("using 4 bytes for a 32-bit quantity") as usize % remaining;
if offset == 28 {
// into the last 4 bytes - rehash to gather new entropy
seed = BlakeTwo256::hash(seed.as_ref());
}
// exchange last item with randomly chosen first.
roles_val.swap(remaining - 1, val_index);
}
DutyRoster {
validator_duty: roles_val,
}
}
/// Calculate the ingress to a specific parachain.
/// Complexity: O(n) in the number of blocks since the parachain's watermark.
/// invoked off-chain.
/// Yields a structure containing all unrouted ingress to the parachain.
pub fn ingress(to: ParaId) -> Option<Vec<(T::BlockNumber, BlockIngressRoots)>> {
let watermark = <Watermarks<T>>::get(to)?;
let now = <system::Module<T>>::block_number();
Some(number_range(watermark.saturating_add(One::one()),now)
.filter_map(|unrouted_height| {
<UnroutedIngress<T>>::get(&(unrouted_height, to)).map(|roots| {
(unrouted_height, BlockIngressRoots(roots))
})
/// Get the parachain status necessary for validation.
pub fn parachain_status(id: ¶chain::Id) -> Option<parachain::Status> {
let balance = T::ParachainCurrency::free_balance(*id);
Self::parachain_head(id).map(|head_data| parachain::Status {
head_data: parachain::HeadData(head_data),
balance,
// TODO: https://github.com/paritytech/polkadot/issues/92
// plug in some real values here. most likely governable.
fee_schedule: parachain::FeeSchedule {
base: 0,
per_byte: 0,
}
})
}
/// Get the currently active set of parachains.
fn active_parachains() -> Vec<(ParaId, Option<CollatorId>, DispatchOrigins)> {
T::ActiveParas::active_paras()
}
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
fn check_egress_queue_roots(head: &AttestedCandidate, active_parachains: &[ParaId]) -> Result {
let mut last_egress_id = None;
let mut iter = active_parachains.iter();
for (egress_para_id, root) in &head.candidate.egress_queue_roots {
// egress routes should be ascending order by parachain ID without duplicate.
ensure!(
last_egress_id.as_ref().map_or(true, |x| x < &egress_para_id),
"Egress routes out of order by ID"
);
// a parachain can't route to self
ensure!(
*egress_para_id != head.candidate.parachain_index,
"Parachain routing to self"
);
// no empty trie roots
ensure!(
*root != EMPTY_TRIE_ROOT.into(),
"Empty trie root included"
);
// can't route to a parachain which doesn't exist
ensure!(
iter.find(|x| x == &egress_para_id).is_some(),
"Routing to non-existent parachain"
);
last_egress_id = Some(egress_para_id)
}
Ok(())
}
// check the attestations on these candidates. The candidates should have been checked
// that each candidates' chain ID is valid.
fn check_candidates(attested_candidates: &[AttestedCandidate]) -> Result{
use primitives::parachain::ValidityAttestation;
use sr_primitives::traits::Verify;
// returns groups of slices that have the same chain ID.
// assumes the inner slice is sorted by id.
struct GroupedDutyIter<'a> {
next_idx: usize,
}
impl<'a> GroupedDutyIter<'a> {
fn new(inner: &'a [(usize, ParaId)]) -> Self {
GroupedDutyIter { next_idx: 0, inner }
}
fn group_for(&mut self, wanted_id: ParaId) -> Option<&'a [(usize, ParaId)]> {
while let Some((id, keys)) = self.next() {
if wanted_id == id {
return Some(keys)
}
}
None
}
}
impl<'a> Iterator for GroupedDutyIter<'a> {
type Item = (ParaId, &'a [(usize, ParaId)]);
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]))
}
}
let authorities = super::Aura::authorities();
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
let duty_roster = Self::calculate_duty_roster();
// 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
};
let sorted_validators = make_sorted_duties(&duty_roster.validator_duty);
let parent_hash = super::System::parent_hash();
let localized_payload = |statement: Statement| localized_payload(statement, parent_hash);
let mut validator_groups = GroupedDutyIter::new(&sorted_validators[..]);
for candidate in attested_candidates {
let para_id = candidate.parachain_index();
let validator_group = validator_groups.group_for(para_id)
.ok_or("no validator group for parachain")?;
ensure!(
candidate.validity_votes.len() >= majority_of(validator_group.len()),
"Not enough validity attestations"
);
let fees = candidate.candidate().fees;
T::ParachainCurrency::deduct(para_id, fees)?;
let mut candidate_hash = None;
let mut encoded_implicit = None;
let mut encoded_explicit = None;
// track which voters have voted already, 1 bit per authority.
let mut track_voters = bitvec![0; authorities.len()];
for (auth_index, validity_attestation) in &candidate.validity_votes {
let auth_index = *auth_index as usize;
// protect against double-votes.
match validator_group.iter().find(|&(idx, _)| *idx == auth_index) {
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
None => return Err("Attesting validator not on this chain's validation duty."),
Some(&(idx, _)) => {
if track_voters.get(idx) {
return Err("Voter already attested validity once")
}
track_voters.set(idx, true)
}
}
let (payload, sig) = match validity_attestation {
ValidityAttestation::Implicit(sig) => {
let payload = encoded_implicit.get_or_insert_with(|| localized_payload(
Statement::Candidate(candidate.candidate.clone()),
));
(payload, sig)
}
ValidityAttestation::Explicit(sig) => {
let hash = candidate_hash
.get_or_insert_with(|| candidate.candidate.hash())
.clone();
let payload = encoded_explicit.get_or_insert_with(|| localized_payload(
Statement::Valid(hash),
));
(payload, sig)
}
};
ensure!(
sig.verify(&payload[..], &authorities[auth_index]),
"Candidate validity attestation signature is bad."
);
}
}
Ok(())
}
// TODO: Consider integrating if needed. (https://github.com/paritytech/polkadot/issues/223)
/// 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
});
match x {
Some(x) => x,
None => panic!("Invalid polkadot block asserted at {:?}", self.file_line),
pub const INHERENT_IDENTIFIER: InherentIdentifier = *b"newheads";
pub type InherentType = Vec<AttestedCandidate>;
impl<T: Trait> ProvideInherent for Module<T> {
type Call = Call<T>;
type Error = MakeFatalError<RuntimeString>;
const INHERENT_IDENTIFIER: InherentIdentifier = INHERENT_IDENTIFIER;
fn create_inherent(data: &InherentData) -> Option<Self::Call> {
let data = data.get_data::<InherentType>(&INHERENT_IDENTIFIER)
.expect("Parachain heads could not be decoded.")
.expect("No parachain heads found in inherent data.");
asynchronous rob
committed
/// Ensure that the origin `o` represents a parachain.
/// Returns `Ok` with the parachain ID that effected the extrinsic or an `Err` otherwise.
pub fn ensure_parachain<OuterOrigin>(o: OuterOrigin) -> result::Result<ParaId, &'static str>
where OuterOrigin: Into<result::Result<Origin, OuterOrigin>>
{
match o.into() {
Ok(Origin::Parachain(id)) => Ok(id),
_ => Err("bad origin: expected to be a parachain origin"),
}
}
#[cfg(test)]
mod tests {
use super::*;
use super::Call as ParachainsCall;
use sr_io::{TestExternalities, with_externalities};
use substrate_primitives::{H256, Blake2Hasher};
use sr_primitives::{
Perbill,
traits::{BlakeTwo256, IdentityLookup, ConvertInto},
testing::{UintAuthorityId, Header},
parachain::{CandidateReceipt, HeadData, ValidityAttestation, ValidatorIndex}, SessionKey,
BlockNumber, AuraId
use srml_support::{
impl_outer_origin, impl_outer_dispatch, assert_ok, assert_err, parameter_types,
};
impl_outer_origin! {
pub enum Origin for Test {
parachains
}
}
impl_outer_dispatch! {
pub enum Call for Test where origin: Origin {
parachains::Parachains,
}
parameter_types! {
pub const BlockHashCount: u64 = 250;
pub const MaximumBlockWeight: u32 = 4 * 1024 * 1024;
pub const MaximumBlockLength: u32 = 4 * 1024 * 1024;
pub const AvailableBlockRatio: Perbill = Perbill::from_percent(75);
impl system::Trait for Test {
type Origin = Origin;
type BlockNumber = u64;
type Hash = H256;
type AccountId = u64;
type Lookup = IdentityLookup<u64>;
type Header = Header;
type WeightMultiplierUpdate = ();
type BlockHashCount = BlockHashCount;
type MaximumBlockWeight = MaximumBlockWeight;
type MaximumBlockLength = MaximumBlockLength;
type AvailableBlockRatio = AvailableBlockRatio;
parameter_types! {
pub const Period: BlockNumber = 1;
pub const Offset: BlockNumber = 0;
}
impl session::Trait for Test {
type OnSessionEnding = ();
type Keys = UintAuthorityId;
type ShouldEndSession = session::PeriodicSessions<Period, Offset>;
type SessionHandler = ();
impl timestamp::Trait for Test {
type Moment = u64;
impl aura::Trait for Test {
type HandleReport = aura::StakingSlasher<Test>;
type AuthorityId = AuraId;
}
parameter_types! {
pub const ExistentialDeposit: Balance = 0;
pub const TransferFee: Balance = 0;
pub const CreationFee: Balance = 0;
pub const TransactionBaseFee: Balance = 0;
pub const TransactionByteFee: Balance = 0;
}
impl balances::Trait for Test {
type OnFreeBalanceZero = ();
type OnNewAccount = ();
type Event = ();
type TransactionPayment = ();
type DustRemoval = ();
type TransferPayment = ();
type ExistentialDeposit = ExistentialDeposit;
type TransferFee = TransferFee;
type CreationFee = CreationFee;
type TransactionBaseFee = TransactionBaseFee;
type TransactionByteFee = TransactionByteFee;
}
parameter_types! {
pub const SessionsPerEra: session::SessionIndex = 6;
pub const BondingDuration: staking::EraIndex = 24 * 28;
}
impl staking::Trait for Test {
type OnRewardMinted = ();
type CurrencyToVote = ();
type Event = ();
type Currency = balances::Module<Test>;
type Slash = ();
type Reward = ();
type SessionsPerEra = SessionsPerEra;
type BondingDuration = BondingDuration;
type SessionInterface = Self;
type Time = timestamp::Module<Test>;
impl Trait for Test {
type Origin = Origin;
type Call = Call;
type ParachainCurrency = balances::Module<Test>;
type Parachains = Module<Test>;
type System = system::Module<Test>;
fn new_test_ext(parachains: Vec<(ParaId, Vec<u8>, Vec<u8>)>) -> TestExternalities<Blake2Hasher> {
let mut t = system::GenesisConfig::default().build_storage::<Test>().unwrap().0;
let authority_keys = [
Ed25519Keyring::Alice,
Ed25519Keyring::Bob,
Ed25519Keyring::Charlie,
Ed25519Keyring::Dave,
Ed25519Keyring::Eve,
Ed25519Keyring::Ferdie,
Ed25519Keyring::One,
Ed25519Keyring::Two,
t.extend(session::GenesisConfig::<Test>{
validators: validator_keys.iter().map(|k| crate::AccountId::from(*k)).collect(),
t.extend(GenesisConfig::<Test>{
t.extend(aura::GenesisConfig::<Test>{
authorities: authority_keys.iter().map(|k| SessionKey::from(*k)).collect(),
}.build_storage().unwrap().0);
fn set_heads(v: Vec<AttestedCandidate>) -> ParachainsCall<Test> {
ParachainsCall::set_heads(v)
}