referrerpolicy=no-referrer-when-downgrade

polkadot_node_core_parachains_inherent/
lib.rs

1// Copyright (C) Parity Technologies (UK) Ltd.
2// This file is part of Polkadot.
3
4// Polkadot is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8
9// Polkadot is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12// GNU General Public License for more details.
13
14// You should have received a copy of the GNU General Public License
15// along with Polkadot.  If not, see <http://www.gnu.org/licenses/>.
16
17//! The parachain inherent data provider
18//!
19//! Parachain backing and approval is an off-chain process, but the parachain needs to progress on
20//! chain as well. To make it progress on chain a block producer needs to forward information about
21//! the state of a parachain to the runtime. This information is forwarded through an inherent to
22//! the runtime. Here we provide the [`ParachainsInherentDataProvider`] that requests the relevant
23//! data from the provisioner subsystem and creates the the inherent data that the runtime will use
24//! to create an inherent.
25
26#![deny(unused_crate_dependencies, unused_results)]
27
28use futures::{select, FutureExt};
29use polkadot_node_subsystem::{
30	errors::SubsystemError, messages::ProvisionerMessage, overseer::Handle,
31};
32use polkadot_primitives::{Block, Hash, InherentData as ParachainsInherentData};
33use std::{sync::Arc, time};
34
35pub(crate) const LOG_TARGET: &str = "parachain::parachains-inherent";
36
37/// How long to wait for the provisioner, before giving up.
38const PROVISIONER_TIMEOUT: time::Duration = core::time::Duration::from_millis(2500);
39
40/// Provides the parachains inherent data.
41pub struct ParachainsInherentDataProvider<C: sp_blockchain::HeaderBackend<Block>> {
42	pub client: Arc<C>,
43	pub overseer: polkadot_overseer::Handle,
44	pub parent: Hash,
45}
46
47impl<C: sp_blockchain::HeaderBackend<Block>> ParachainsInherentDataProvider<C> {
48	/// Create a new [`Self`].
49	pub fn new(client: Arc<C>, overseer: polkadot_overseer::Handle, parent: Hash) -> Self {
50		ParachainsInherentDataProvider { client, overseer, parent }
51	}
52
53	/// Create a new instance of the [`ParachainsInherentDataProvider`].
54	pub async fn create(
55		client: Arc<C>,
56		mut overseer: Handle,
57		parent: Hash,
58	) -> Result<ParachainsInherentData, Error> {
59		let pid = async {
60			let (sender, receiver) = futures::channel::oneshot::channel();
61			gum::trace!(
62				target: LOG_TARGET,
63				relay_parent = ?parent,
64				"Inherent data requested by Babe"
65			);
66			overseer.wait_for_activation(parent, sender).await;
67			receiver
68				.await
69				.map_err(|_| Error::ClosedChannelAwaitingActivation)?
70				.map_err(|e| Error::Subsystem(e))?;
71
72			let (sender, receiver) = futures::channel::oneshot::channel();
73			gum::trace!(
74				target: LOG_TARGET,
75				relay_parent = ?parent,
76				"Requesting inherent data (after having waited for activation)"
77			);
78			overseer
79				.send_msg(
80					ProvisionerMessage::RequestInherentData(parent, sender),
81					std::any::type_name::<Self>(),
82				)
83				.await;
84
85			receiver.await.map_err(|_| Error::ClosedChannelAwaitingInherentData)
86		};
87
88		let mut timeout = futures_timer::Delay::new(PROVISIONER_TIMEOUT).fuse();
89
90		let parent_header = match client.header(parent) {
91			Ok(Some(h)) => h,
92			Ok(None) => return Err(Error::ParentHeaderNotFound(parent)),
93			Err(err) => return Err(Error::Blockchain(err)),
94		};
95
96		let res = select! {
97			pid = pid.fuse() => pid,
98			_ = timeout => Err(Error::Timeout),
99		};
100
101		let inherent_data = match res {
102			Ok(pd) => ParachainsInherentData {
103				bitfields: pd.bitfields.into_iter().map(Into::into).collect(),
104				backed_candidates: pd.backed_candidates,
105				disputes: pd.disputes,
106				parent_header,
107			},
108			Err(err) => {
109				gum::debug!(
110					target: LOG_TARGET,
111					%err,
112					"Could not get provisioner inherent data; injecting default data",
113				);
114				ParachainsInherentData {
115					bitfields: Vec::new(),
116					backed_candidates: Vec::new(),
117					disputes: Vec::new(),
118					parent_header,
119				}
120			},
121		};
122
123		Ok(inherent_data)
124	}
125}
126
127#[async_trait::async_trait]
128impl<C: sp_blockchain::HeaderBackend<Block>> sp_inherents::InherentDataProvider
129	for ParachainsInherentDataProvider<C>
130{
131	async fn provide_inherent_data(
132		&self,
133		dst_inherent_data: &mut sp_inherents::InherentData,
134	) -> Result<(), sp_inherents::Error> {
135		let inherent_data = ParachainsInherentDataProvider::create(
136			self.client.clone(),
137			self.overseer.clone(),
138			self.parent,
139		)
140		.await
141		.map_err(|e| sp_inherents::Error::Application(Box::new(e)))?;
142
143		dst_inherent_data
144			.put_data(polkadot_primitives::PARACHAINS_INHERENT_IDENTIFIER, &inherent_data)
145	}
146
147	async fn try_handle_error(
148		&self,
149		_identifier: &sp_inherents::InherentIdentifier,
150		_error: &[u8],
151	) -> Option<Result<(), sp_inherents::Error>> {
152		// Inherent isn't checked and can not return any error
153		None
154	}
155}
156
157#[derive(thiserror::Error, Debug)]
158pub enum Error {
159	#[error("Blockchain error")]
160	Blockchain(#[from] sp_blockchain::Error),
161	#[error("Timeout: provisioner did not return inherent data after {:?}", PROVISIONER_TIMEOUT)]
162	Timeout,
163	#[error("Could not find the parent header in the blockchain: {:?}", _0)]
164	ParentHeaderNotFound(Hash),
165	#[error("Closed channel from overseer when awaiting activation")]
166	ClosedChannelAwaitingActivation,
167	#[error("Closed channel from provisioner when awaiting inherent data")]
168	ClosedChannelAwaitingInherentData,
169	#[error("Subsystem failed")]
170	Subsystem(#[from] SubsystemError),
171}