domain_block_preprocessor/
inherents.rs1use sp_api::{ApiExt, ProvideRuntimeApi};
17use sp_blockchain::HeaderBackend;
18use sp_domains::{DomainId, DomainsApi, DomainsDigestItem};
19use sp_inherents::{CreateInherentDataProviders, InherentData, InherentDataProvider};
20use sp_messenger::MessengerApi;
21use sp_runtime::traits::{Block as BlockT, Header, NumberFor};
22use sp_timestamp::InherentType;
23use std::error::Error;
24use std::sync::Arc;
25
26pub async fn get_inherent_data<CClient, CBlock, Block>(
27 consensus_client: Arc<CClient>,
28 consensus_block_hash: CBlock::Hash,
29 parent_hash: Block::Hash,
30 domain_id: DomainId,
31) -> Result<InherentData, sp_blockchain::Error>
32where
33 CBlock: BlockT,
34 Block: BlockT,
35 CClient: ProvideRuntimeApi<CBlock> + HeaderBackend<CBlock>,
36 CClient::Api:
37 DomainsApi<CBlock, Block::Header> + MessengerApi<CBlock, NumberFor<CBlock>, CBlock::Hash>,
38{
39 let create_inherent_data_providers =
40 CreateInherentDataProvider::new(consensus_client, Some(consensus_block_hash), domain_id);
41 let inherent_data_providers = <CreateInherentDataProvider<_, _> as CreateInherentDataProviders<
42 Block,
43 (),
44 >>::create_inherent_data_providers(
45 &create_inherent_data_providers, parent_hash, ()
46 )
47 .await?;
48 let mut inherent_data = InherentData::new();
49 inherent_data_providers
50 .provide_inherent_data(&mut inherent_data)
51 .await
52 .map_err(|err| {
53 sp_blockchain::Error::Application(Box::from(format!(
54 "failed to provide inherent data: {err:?}"
55 )))
56 })?;
57
58 Ok(inherent_data)
59}
60
61pub(crate) fn is_runtime_upgraded<CClient, CBlock, Block>(
62 consensus_client: &Arc<CClient>,
63 consensus_block_hash: CBlock::Hash,
64 domain_id: DomainId,
65) -> Result<bool, sp_blockchain::Error>
66where
67 CClient: ProvideRuntimeApi<CBlock> + HeaderBackend<CBlock>,
68 CClient::Api: DomainsApi<CBlock, Block::Header>,
69 CBlock: BlockT,
70 Block: BlockT,
71{
72 let runtime_api = consensus_client.runtime_api();
73
74 let runtime_id = runtime_api
75 .runtime_id(consensus_block_hash, domain_id)?
76 .ok_or(sp_blockchain::Error::Application(Box::from(format!(
77 "No RuntimeId found for {domain_id:?}"
78 ))))?;
79
80 let domains_api_version = runtime_api
84 .api_version::<dyn DomainsApi<CBlock, CBlock::Header>>(consensus_block_hash)?
85 .unwrap_or(1);
87
88 let is_upgraded = if domains_api_version >= 2 {
89 let runtime_upgrades = runtime_api.runtime_upgrades(consensus_block_hash)?;
90 runtime_upgrades.contains(&runtime_id)
91 } else {
92 let header = consensus_client.header(consensus_block_hash)?.ok_or(
93 sp_blockchain::Error::MissingHeader(format!(
94 "No header found for {consensus_block_hash:?}"
95 )),
96 )?;
97 header
98 .digest()
99 .logs
100 .iter()
101 .filter_map(|log| log.as_domain_runtime_upgrade())
102 .any(|upgraded_runtime_id| upgraded_runtime_id == runtime_id)
103 };
104
105 Ok(is_upgraded)
106}
107
108pub fn extract_domain_runtime_upgrade_code<CClient, CBlock, Block>(
110 consensus_client: &Arc<CClient>,
111 consensus_block_hash: CBlock::Hash,
112 domain_id: DomainId,
113) -> Result<Option<Vec<u8>>, sp_blockchain::Error>
114where
115 CClient: ProvideRuntimeApi<CBlock> + HeaderBackend<CBlock>,
116 CClient::Api: DomainsApi<CBlock, Block::Header>,
117 CBlock: BlockT,
118 Block: BlockT,
119{
120 if is_runtime_upgraded::<_, _, Block>(consensus_client, consensus_block_hash, domain_id)? {
121 let new_domain_runtime = consensus_client
122 .runtime_api()
123 .domain_runtime_code(consensus_block_hash, domain_id)?
124 .ok_or_else(|| {
125 sp_blockchain::Error::Application(Box::from(format!(
126 "No new runtime code for {domain_id:?}"
127 )))
128 })?;
129
130 Ok(Some(new_domain_runtime))
131 } else {
132 Ok(None)
133 }
134}
135
136#[derive(Debug)]
137pub struct CreateInherentDataProvider<CClient, CBlock: BlockT> {
138 consensus_client: Arc<CClient>,
139 maybe_consensus_block_hash: Option<CBlock::Hash>,
140 domain_id: DomainId,
141}
142
143impl<CClient, CBlock: BlockT + Clone> Clone for CreateInherentDataProvider<CClient, CBlock> {
144 fn clone(&self) -> Self {
145 Self {
146 consensus_client: self.consensus_client.clone(),
147 maybe_consensus_block_hash: self.maybe_consensus_block_hash,
148 domain_id: self.domain_id,
149 }
150 }
151}
152
153impl<CClient, CBlock: BlockT> CreateInherentDataProvider<CClient, CBlock> {
154 pub fn new(
155 consensus_client: Arc<CClient>,
156 maybe_consensus_block_hash: Option<CBlock::Hash>,
157 domain_id: DomainId,
158 ) -> Self {
159 Self {
160 consensus_client,
161 maybe_consensus_block_hash,
162 domain_id,
163 }
164 }
165}
166
167#[async_trait::async_trait]
168impl<CClient, CBlock, Block> CreateInherentDataProviders<Block, ()>
169 for CreateInherentDataProvider<CClient, CBlock>
170where
171 Block: BlockT,
172 CBlock: BlockT,
173 CClient: ProvideRuntimeApi<CBlock> + HeaderBackend<CBlock>,
174 CClient::Api:
175 DomainsApi<CBlock, Block::Header> + MessengerApi<CBlock, NumberFor<CBlock>, CBlock::Hash>,
176{
177 type InherentDataProviders = (
178 sp_timestamp::InherentDataProvider,
179 sp_block_fees::InherentDataProvider,
180 sp_executive::InherentDataProvider,
181 sp_messenger::InherentDataProvider,
182 sp_domain_sudo::InherentDataProvider,
183 sp_evm_tracker::InherentDataProvider,
184 );
185
186 async fn create_inherent_data_providers(
187 &self,
188 _parent: Block::Hash,
189 _extra_args: (),
190 ) -> Result<Self::InherentDataProviders, Box<dyn Error + Send + Sync>> {
191 let consensus_block_hash = self
197 .maybe_consensus_block_hash
198 .unwrap_or(self.consensus_client.info().best_hash);
199
200 let runtime_api = self.consensus_client.runtime_api();
201 let domains_api_version = runtime_api
205 .api_version::<dyn DomainsApi<CBlock, CBlock::Header>>(consensus_block_hash)?
206 .unwrap_or(1);
208
209 let timestamp = if domains_api_version >= 3 {
210 runtime_api.domain_timestamp(consensus_block_hash)?
211 } else {
212 #[allow(deprecated)]
213 runtime_api.timestamp(consensus_block_hash)?
214 };
215 let timestamp_provider =
216 sp_timestamp::InherentDataProvider::new(InherentType::new(timestamp));
217
218 let maybe_runtime_upgrade_code = extract_domain_runtime_upgrade_code::<_, _, Block>(
219 &self.consensus_client,
220 consensus_block_hash,
221 self.domain_id,
222 )?;
223 let runtime_upgrade_provider =
224 sp_executive::InherentDataProvider::new(maybe_runtime_upgrade_code);
225
226 let consensus_chain_byte_fee = if domains_api_version >= 3 {
227 runtime_api.consensus_transaction_byte_fee(consensus_block_hash)?
228 } else {
229 #[allow(deprecated)]
230 runtime_api.consensus_chain_byte_fee(consensus_block_hash)?
231 };
232 let storage_price_provider =
233 sp_block_fees::InherentDataProvider::new(consensus_chain_byte_fee);
234
235 let domain_chains_allowlist_update =
236 runtime_api.domain_chains_allowlist_update(consensus_block_hash, self.domain_id)?;
237 let messenger_inherent_provider =
238 sp_messenger::InherentDataProvider::new(sp_messenger::InherentType {
239 maybe_updates: domain_chains_allowlist_update,
240 });
241
242 let maybe_domain_sudo_call =
243 runtime_api.domain_sudo_call(consensus_block_hash, self.domain_id)?;
244 let domain_sudo_call_inherent_provider =
245 sp_domain_sudo::InherentDataProvider::new(maybe_domain_sudo_call);
246
247 let maybe_evm_domain_contract_creation_allowed_by_call = if domains_api_version >= 4 {
248 runtime_api.evm_domain_contract_creation_allowed_by_call(
249 consensus_block_hash,
250 self.domain_id,
251 )?
252 } else {
253 None
254 };
255 let evm_domain_contract_creation_allowed_by_call_inherent_provider =
256 sp_evm_tracker::InherentDataProvider::new(
257 maybe_evm_domain_contract_creation_allowed_by_call,
258 );
259
260 Ok((
261 timestamp_provider,
262 storage_price_provider,
263 runtime_upgrade_provider,
264 messenger_inherent_provider,
265 domain_sudo_call_inherent_provider,
266 evm_domain_contract_creation_allowed_by_call_inherent_provider,
267 ))
268 }
269}