6.81 KB
Newer Older
// Copyright 2019-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
// 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 <>.

//! A module for tracking all attestations that fell on a given candidate receipt.
//! In the future, it is planned that this module will handle dispute resolution
//! as well.

use rstd::prelude::*;
use codec::{Encode, Decode};
use frame_support::{
	decl_storage, decl_module, decl_error, ensure, dispatch::DispatchResult, traits::Get
use primitives::{Hash, parachain::{AttestedCandidate, AbridgedCandidateReceipt, Id as ParaId}};
use sp_runtime::RuntimeDebug;
use sp_staking::SessionIndex;
Gavin Wood's avatar
Gavin Wood committed
use inherents::{ProvideInherent, InherentData, MakeFatalError, InherentIdentifier};
use system::ensure_none;

/// Parachain blocks included in a recent relay-chain block.
#[derive(Encode, Decode)]
pub struct IncludedBlocks<T: Trait> {
	/// The actual relay chain block number where blocks were included.
	pub actual_number: T::BlockNumber,
	/// The session index at this block.
	pub session: SessionIndex,
	/// The randomness seed at this block.
	pub random_seed: [u8; 32],
	/// All parachain IDs active at this block.
	pub active_parachains: Vec<ParaId>,
	/// Hashes of the parachain candidates included at this block.
	pub para_blocks: Vec<Hash>,

/// Attestations kept over time on a parachain block.
#[derive(Encode, Decode)]
pub struct BlockAttestations<T: Trait> {
	valid: Vec<T::AccountId>, // stash account ID of voter.
	invalid: Vec<T::AccountId>, // stash account ID of voter.

/// Additional attestations on a parachain block, after it was included.
#[derive(Encode, Decode, Clone, PartialEq, RuntimeDebug)]
pub struct MoreAttestations;

/// Something which processes rewards for received attestations.
pub trait RewardAttestation {
	/// Reward immediate attestations on parachain blocks. The argument is an iterable of
	/// validator indices of the attesting validators.
	fn reward_immediate(validator_indices: impl IntoIterator<Item=u32>);

impl RewardAttestation for () {
	fn reward_immediate(validator_indices: impl IntoIterator<Item=u32>) {
		// ensure side-effecting iterators do work.
		for _ in validator_indices {}

impl<T: staking::Trait> RewardAttestation for staking::Module<T> {
	fn reward_immediate(validator_indices: impl IntoIterator<Item=u32>) {
Gavin Wood's avatar
Gavin Wood committed
		use staking::SessionInterface;

		// The number of points to reward for a validity statement.
		const STAKING_REWARD_POINTS: u32 = 20;

Gavin Wood's avatar
Gavin Wood committed
		let validators = T::SessionInterface::validators();

		let validator_rewards = validator_indices.into_iter()
			.filter_map(|i| validators.get(i as usize).cloned())
			.map(|v| (v, STAKING_REWARD_POINTS));

pub trait Trait: session::Trait {
	/// How many blocks ago we're willing to accept attestations for.
	type AttestationPeriod: Get<Self::BlockNumber>;

	/// Get a list of the validators' underlying identities.
	type ValidatorIdentities: Get<Vec<Self::AccountId>>;

	/// Hook for rewarding validators upon attesting.
	type RewardAttestation: RewardAttestation;

decl_storage! {
	trait Store for Module<T: Trait> as Attestations {
		/// A mapping from modular block number (n % AttestationPeriod)
		/// to session index and the list of candidate hashes.
Gavin Wood's avatar
Gavin Wood committed
		pub RecentParaBlocks: map hasher(blake2_256) T::BlockNumber => Option<IncludedBlocks<T>>;

		/// Attestations on a recent parachain block.
Gavin Wood's avatar
Gavin Wood committed
		pub ParaBlockAttestations:
			double_map hasher(blake2_256) T::BlockNumber, hasher(blake2_128) Hash
			=> Option<BlockAttestations<T>>;

		// Did we already have more attestations included in this block?
		DidUpdate: bool;

decl_error! {
	pub enum Error for Module<T: Trait> {
		/// More attestations can be added only once in a block.

decl_module! {
	/// Parachain-attestations module.
	pub struct Module<T: Trait> for enum Call where origin: <T as system::Trait>::Origin {
		type Error = Error<T>;

		/// Provide candidate receipts for parachains, in ascending order by id.
		fn more_attestations(origin, _more: MoreAttestations) -> DispatchResult {
			ensure!(!DidUpdate::exists(), Error::<T>::TooManyAttestations);


		fn on_finalize(_n: T::BlockNumber) {

impl<T: Trait> Module<T> {
	/// Update recent candidates to contain the already-checked parachain candidates.
	pub(crate) fn note_included(heads: &[AttestedCandidate], para_blocks: IncludedBlocks<T>) {
		let attestation_period = T::AttestationPeriod::get();
		let mod_num = para_blocks.actual_number % attestation_period;

		// clear old entry that was in this place.
		if let Some(old_entry) = <RecentParaBlocks<T>>::take(&mod_num) {

		let validators = T::ValidatorIdentities::get();

		// make new entry.
		for (head, hash) in heads.iter().zip(&para_blocks.para_blocks) {
			let mut valid = Vec::new();
			let invalid = Vec::new();

				let attesting_indices = head.validator_indices
					.filter(|(_, bit)| *bit)
					.inspect(|&(auth_index, _)| {
						if let Some(stash_id) = validators.get(auth_index) {
					.map(|(i, _)| i as u32);


			let summary = BlockAttestations {
				receipt: head.candidate().clone(),

			<ParaBlockAttestations<T>>::insert(&para_blocks.actual_number, hash, &summary);

		<RecentParaBlocks<T>>::insert(&mod_num, &para_blocks);

/// An identifier for inherent data that provides after-the-fact attestations
/// on already included parachain blocks.
pub const MORE_ATTESTATIONS_IDENTIFIER: InherentIdentifier = *b"par-atts";

pub type InherentType = MoreAttestations;

impl<T: Trait> ProvideInherent for Module<T> {
	type Call = Call<T>;
Gavin Wood's avatar
Gavin Wood committed
	type Error = MakeFatalError<inherents::Error>;

	fn create_inherent(data: &InherentData) -> Option<Self::Call> {