sc_simnode/
sproof.rs

1// Copyright (C) 2023 Polytope Labs (Caymans) Ltd.
2// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0
3
4// This program 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// This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
16
17//! Parachain inherent data provider, useful for signalling relay chain authorizations to
18//! parachain simnodes.
19
20use polkadot_sdk::*;
21
22use crate::{client::FullClientFor, with_state, ChainInfo};
23use codec::Encode;
24use cumulus_primitives_parachain_inherent::ParachainInherentData;
25use futures::lock::Mutex;
26use num_traits::AsPrimitive;
27use polkadot_primitives::PersistedValidationData;
28
29use cumulus_test_relay_sproof_builder::RelayStateSproofBuilder;
30use sp_blockchain::HeaderBackend;
31use sp_runtime::traits::{Block, Header};
32use sp_wasm_interface::{anyhow, anyhow::anyhow};
33use std::{marker::PhantomData, sync::Arc};
34
35/// Provides the inherent for parachain runtimes. Can also be manipulated to send relay chain
36/// signals to simulated node runtime.
37pub struct ParachainSproofInherentProvider<T: ChainInfo> {
38	// client type
39	client: Arc<FullClientFor<T>>,
40	// sproof builder
41	sproof_builder: Option<RelayStateSproofBuilder>,
42	// slot duration for the node
43	slot_duration: u64,
44	// phantom type
45	_phantom: PhantomData<T>,
46}
47
48/// A thread safe parachain sproof inherent provider
49pub type SharedParachainSproofInherentProvider<T> = Arc<Mutex<ParachainSproofInherentProvider<T>>>;
50
51impl<T> ParachainSproofInherentProvider<T>
52where
53	T: ChainInfo,
54	T::Runtime: staging_parachain_info::Config,
55	<<T::Block as Block>::Header as Header>::Number: AsPrimitive<u32>,
56{
57	/// Construct a new sproof-er
58	pub fn new(client: Arc<FullClientFor<T>>, slot_duration: u64) -> Self {
59		ParachainSproofInherentProvider {
60			client,
61			slot_duration,
62			sproof_builder: None,
63			_phantom: PhantomData,
64		}
65	}
66
67	/// updates the sproof to a new state
68	pub fn update_sproof_builder(&mut self, sproof: RelayStateSproofBuilder) {
69		self.sproof_builder = Some(sproof);
70	}
71
72	/// Given the current slot and parent block hash, creates the inherent that parachain-system
73	/// expects.
74	pub fn create_inherent(
75		&mut self,
76		slot: u64,
77		parent: <T::Block as Block>::Hash,
78	) -> Result<ParachainInherentData, anyhow::Error> {
79		let mut sproof = self.sproof_builder.take().unwrap_or_default();
80		sproof.para_id = with_state::<T, _>(self.client.clone(), None, || {
81			staging_parachain_info::Pallet::<T::Runtime>::parachain_id()
82		});
83		sproof.current_slot = if self.slot_duration == 12_000 {
84			// relay chain is twice as fast the parachain
85			((slot * 2) + 1).into()
86		} else {
87			// async backing is enabled
88			slot.into()
89		};
90		sproof.host_config.validation_upgrade_delay = 2;
91		sproof.host_config.max_code_size = 15 * 1024 * 1024;
92		sproof.included_para_head =
93			self.client.header(parent).ok().flatten().map(|h| Into::into(h.encode()));
94		// this makes every block random, so that you can still author blocks after reverting.
95		// instead of getting the AlreadyInChain error.
96		sproof.randomness = rand::random();
97
98		let info = self.client.info();
99		let header = self
100			.client
101			.header(info.best_hash)?
102			.ok_or_else(|| anyhow!("Couldn't fetch best header!"))?
103			.encode();
104
105		let (state_root, proof) = sproof.into_state_root_and_proof();
106
107		Ok(ParachainInherentData {
108			validation_data: PersistedValidationData {
109				parent_head: header.into(),
110				relay_parent_number: info.best_number.as_() + 100,
111				relay_parent_storage_root: state_root,
112				max_pov_size: 15 * 1024 * 1024,
113			},
114			relay_chain_state: proof,
115			downward_messages: Default::default(),
116			horizontal_messages: Default::default(),
117			collator_peer_id: None,
118			relay_parent_descendants: vec![],
119		})
120	}
121}