// Copyright 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. //! A module exporting runtime API implementation functions for all runtime APIs using v1 //! primitives. //! //! Runtimes implementing the v1 runtime API are recommended to forward directly to these //! functions. use sp_std::prelude::*; use primitives::v1::{ ValidatorId, ValidatorIndex, GroupRotationInfo, CoreState, ValidationData, Id as ParaId, OccupiedCoreAssumption, SessionIndex, ValidationCode, CommittedCandidateReceipt, ScheduledCore, OccupiedCore, CoreOccupied, CoreIndex, GroupIndex, CandidateEvent, PersistedValidationData, AuthorityDiscoveryId, InboundDownwardMessage, }; use sp_runtime::traits::Zero; use frame_support::debug; use crate::{initializer, inclusion, scheduler, configuration, paras, router}; /// Implementation for the `validators` function of the runtime API. pub fn validators() -> Vec { >::validators() } /// Implementation for the `validator_groups` function of the runtime API. pub fn validator_groups() -> ( Vec>, GroupRotationInfo, ) { let groups = >::validator_groups(); let rotation_info = >::group_rotation_info(); (groups, rotation_info) } /// Implementation for the `availability_cores` function of the runtime API. pub fn availability_cores() -> Vec> { let cores = >::availability_cores(); let parachains = >::parachains(); let config = >::config(); let rotation_info = >::group_rotation_info(); let time_out_at = |backed_in_number, availability_period| { let time_out_at = backed_in_number + availability_period; if rotation_info.group_rotation_frequency == Zero::zero() { return time_out_at; } let current_window = rotation_info.last_rotation_at() + availability_period; let next_rotation = rotation_info.next_rotation_at(); // If we are within `period` blocks of rotation, timeouts are being checked // actively. We could even time out this block. if time_out_at < current_window { time_out_at } else if time_out_at <= next_rotation { // Otherwise, it will time out at the sooner of the next rotation next_rotation } else { // or the scheduled time-out. This is by definition within `period` blocks // of `next_rotation` and is thus a valid timeout block. time_out_at } }; let group_responsible_for = |backed_in_number, core_index| { match >::group_assigned_to_core(core_index, backed_in_number) { Some(g) => g, None => { debug::warn!("Could not determine the group responsible for core extracted \ from list of cores for some prior block in same session"); GroupIndex(0) } } }; let mut core_states: Vec<_> = cores.into_iter().enumerate().map(|(i, core)| match core { Some(occupied) => { CoreState::Occupied(match occupied { CoreOccupied::Parachain => { let para_id = parachains[i]; let pending_availability = > ::pending_availability(para_id) .expect("Occupied core always has pending availability; qed"); let backed_in_number = pending_availability.backed_in_number().clone(); OccupiedCore { para_id, next_up_on_available: >::next_up_on_available( CoreIndex(i as u32) ), occupied_since: backed_in_number, time_out_at: time_out_at( backed_in_number, config.chain_availability_period, ), next_up_on_time_out: >::next_up_on_time_out( CoreIndex(i as u32) ), availability: pending_availability.availability_votes().clone(), group_responsible: group_responsible_for( backed_in_number, pending_availability.core_occupied(), ), } } CoreOccupied::Parathread(p) => { let para_id = p.claim.0; let pending_availability = > ::pending_availability(para_id) .expect("Occupied core always has pending availability; qed"); let backed_in_number = pending_availability.backed_in_number().clone(); OccupiedCore { para_id, next_up_on_available: >::next_up_on_available( CoreIndex(i as u32) ), occupied_since: backed_in_number, time_out_at: time_out_at( backed_in_number, config.thread_availability_period, ), next_up_on_time_out: >::next_up_on_time_out( CoreIndex(i as u32) ), availability: pending_availability.availability_votes().clone(), group_responsible: group_responsible_for( backed_in_number, pending_availability.core_occupied(), ), } } }) } None => CoreState::Free, }).collect(); // This will overwrite only `Free` cores if the scheduler module is working as intended. for scheduled in >::scheduled() { core_states[scheduled.core.0 as usize] = CoreState::Scheduled(ScheduledCore { para_id: scheduled.para_id, collator: scheduled.required_collator().map(|c| c.clone()), }); } core_states } fn with_assumption( para_id: ParaId, assumption: OccupiedCoreAssumption, build: F, ) -> Option where Trait: inclusion::Trait, F: FnOnce() -> Option, { match assumption { OccupiedCoreAssumption::Included => { >::force_enact(para_id); build() } OccupiedCoreAssumption::TimedOut => { build() } OccupiedCoreAssumption::Free => { if >::pending_availability(para_id).is_some() { None } else { build() } } } } /// Implementation for the `full_validation_data` function of the runtime API. pub fn full_validation_data( para_id: ParaId, assumption: OccupiedCoreAssumption, ) -> Option> { with_assumption::( para_id, assumption, || Some(ValidationData { persisted: crate::util::make_persisted_validation_data::(para_id)?, transient: crate::util::make_transient_validation_data::(para_id)?, }), ) } /// Implementation for the `persisted_validation_data` function of the runtime API. pub fn persisted_validation_data( para_id: ParaId, assumption: OccupiedCoreAssumption, ) -> Option> { with_assumption::( para_id, assumption, || crate::util::make_persisted_validation_data::(para_id), ) } /// Implementation for the `check_validation_outputs` function of the runtime API. pub fn check_validation_outputs( para_id: ParaId, outputs: primitives::v1::ValidationOutputs, ) -> bool { // we strip detailed information from error here for the sake of simplicity of runtime API. >::check_validation_outputs(para_id, outputs).is_ok() } /// Implementation for the `session_index_for_child` function of the runtime API. pub fn session_index_for_child() -> SessionIndex { // Just returns the session index from `inclusion`. Runtime APIs follow // initialization so the initializer will have applied any pending session change // which is expected at the child of the block whose context the runtime API was invoked // in. // // Incidentally, this is also the rationale for why it is OK to query validators or // occupied cores or etc. and expect the correct response "for child". >::session_index() } /// Implementation for the `validation_code` function of the runtime API. pub fn validation_code( para_id: ParaId, assumption: OccupiedCoreAssumption, ) -> Option { with_assumption::( para_id, assumption, || >::current_code(¶_id), ) } /// Implementation for the `candidate_pending_availability` function of the runtime API. pub fn candidate_pending_availability(para_id: ParaId) -> Option> { >::candidate_pending_availability(para_id) } /// Implementation for the `candidate_events` function of the runtime API. // NOTE: this runs without block initialization, as it accesses events. // this means it can run in a different session than other runtime APIs at the same block. pub fn candidate_events(extract_event: F) -> Vec> where T: initializer::Trait, F: Fn(::Event) -> Option>, { use inclusion::Event as RawEvent; >::events().into_iter() .filter_map(|record| extract_event(record.event)) .map(|event| match event { RawEvent::::CandidateBacked(c, h) => CandidateEvent::CandidateBacked(c, h), RawEvent::::CandidateIncluded(c, h) => CandidateEvent::CandidateIncluded(c, h), RawEvent::::CandidateTimedOut(c, h) => CandidateEvent::CandidateTimedOut(c, h), }) .collect() } /// Get the `AuthorityDiscoveryId`s corresponding to the given `ValidatorId`s. /// Currently this request is limited to validators in the current session. /// /// We assume that every validator runs authority discovery, /// which would allow us to establish point-to-point connection to given validators. // FIXME: handle previous sessions: // https://github.com/paritytech/polkadot/issues/1461 pub fn validator_discovery(validators: Vec) -> Vec> where T: initializer::Trait + pallet_authority_discovery::Trait, { // FIXME: the mapping might be invalid if a session change happens in between the calls // use SessionInfo from https://github.com/paritytech/polkadot/pull/1691 let current_validators = >::validators(); let authorities = >::authorities(); // We assume the same ordering in authorities as in validators so we can do an index search validators.iter().map(|id| { // FIXME: linear search is slow O(n^2) // use SessionInfo from https://github.com/paritytech/polkadot/pull/1691 let validator_index = current_validators.iter().position(|v| v == id); validator_index.and_then(|i| authorities.get(i).cloned()) }).collect() } /// Implementation for the `dmq_contents` function of the runtime API. pub fn dmq_contents( recipient: ParaId, ) -> Vec> { >::dmq_contents(recipient) }