1use std::{ops::DerefMut, str::FromStr, sync::Arc};
2
3use array_bytes::Hexify;
4use parity_scale_codec::{Decode, Encode};
5use sc_cli::Result;
6use sc_executor::{HostFunctions, WasmExecutor};
7use sp_core::H256;
8use sp_inherents::InherentData;
9use sp_runtime::{
10 traits::{Block as BlockT, HashingFor, Header, NumberFor, One},
11 DeserializeOwned, Digest, ExtrinsicInclusionMode,
12};
13use sp_state_machine::TestExternalities;
14use sp_std::fmt::Debug;
15use tokio::sync::Mutex;
16
17use super::inherents::{pre_apply::pre_apply_inherents, providers::InherentProvider};
18use crate::{
19 common::{
20 empty_block::inherents::providers::ProviderVariant, misc_logging::LogLevelGuard,
21 state::state_machine_call,
22 },
23 full_extensions,
24};
25
26pub async fn mine_block<Block, HostFns: HostFunctions>(
27 ext_mutex: Arc<Mutex<TestExternalities<HashingFor<Block>>>>,
28 executor: &WasmExecutor<HostFns>,
29 previous_block_building_info: Option<(InherentData, Digest)>,
30 parent_header: Block::Header,
31 provider_variant: ProviderVariant,
32 try_state: frame_try_runtime::TryStateSelect,
33) -> Result<(
34 (InherentData, Digest),
35 Block::Header,
36 Option<ExtrinsicInclusionMode>,
37)>
38where
39 Block: BlockT<Hash = H256> + DeserializeOwned,
40 Block::Header: DeserializeOwned,
41 <Block::Hash as FromStr>::Err: Debug,
42 NumberFor<Block>: FromStr,
43 <NumberFor<Block> as FromStr>::Err: Debug,
44{
45 let mut ext_guard = ext_mutex.lock().await;
47 let ext = ext_guard.deref_mut();
48 let backend = ext.as_backend();
49 drop(ext_guard);
50
51 log::info!(
52 "Producing new empty block at height {:?}",
53 *parent_header.number() + One::one()
54 );
55
56 let muffle = LogLevelGuard::only_errors();
58 let (next_block, new_block_building_info, mode) = produce_next_block::<Block, HostFns>(
59 ext_mutex.clone(),
60 executor,
61 parent_header.clone(),
62 provider_variant,
63 previous_block_building_info,
64 )
65 .await?;
66 drop(muffle);
67
68 log::info!(
69 "Produced a new block ({})",
70 next_block.header().hash().as_bytes().hexify_prefixed()
71 );
72
73 let mut ext_guard = ext_mutex.lock().await;
74 let ext = ext_guard.deref_mut();
75
76 ext.backend = backend;
78
79 pre_apply_inherents::<Block>(ext);
80 let state_root_check = true;
81 let signature_check = true;
82 let payload = (
83 next_block.clone(),
84 state_root_check,
85 signature_check,
86 try_state.clone(),
87 )
88 .encode();
89 if try_state == frame_try_runtime::TryStateSelect::None {
92 call::<(), Block, _>(ext, executor, "Core_execute_block", &next_block.encode()).await?;
93 } else {
94 call::<(), Block, _>(ext, executor, "TryRuntime_execute_block", &payload).await?;
95 }
96
97 log::info!("Executed the new block");
98
99 Ok((new_block_building_info, next_block.header().clone(), mode))
100}
101
102pub async fn produce_next_block<Block, HostFns: HostFunctions>(
104 ext_mutex: Arc<Mutex<TestExternalities<HashingFor<Block>>>>,
105 executor: &WasmExecutor<HostFns>,
106 parent_header: Block::Header,
107 chain: ProviderVariant,
108 previous_block_building_info: Option<(InherentData, Digest)>,
109) -> Result<(
110 Block,
111 (InherentData, Digest),
112 Option<ExtrinsicInclusionMode>,
113)>
114where
115 Block: BlockT<Hash = H256> + DeserializeOwned,
116 Block::Header: DeserializeOwned,
117 <Block::Hash as FromStr>::Err: Debug,
118 NumberFor<Block>: FromStr,
119 <NumberFor<Block> as FromStr>::Err: Debug,
120{
121 let rp_offset = {
122 let ext_guard = ext_mutex.lock().await;
123 relay_parent_offset::<Block, HostFns>(&ext_guard, executor)
124 };
125
126 let (inherent_data_provider, pre_digest) =
127 <ProviderVariant as InherentProvider<Block>>::get_inherent_providers_and_pre_digest(
128 &chain,
129 previous_block_building_info,
130 parent_header.clone(),
131 ext_mutex.clone(),
132 rp_offset,
133 )?;
134
135 let mut ext_guard = ext_mutex.lock().await;
136 let ext = ext_guard.deref_mut();
137
138 pre_apply_inherents::<Block>(ext);
139 drop(ext_guard);
140
141 let inherent_data = inherent_data_provider
142 .create_inherent_data()
143 .await
144 .map_err(|s| sc_cli::Error::Input(s.to_string()))?;
145 let digest = Digest { logs: pre_digest };
146
147 let header = Block::Header::new(
148 *parent_header.number() + One::one(),
149 Default::default(),
150 Default::default(),
151 parent_header.hash(),
152 digest.clone(),
153 );
154
155 let mut ext_guard = ext_mutex.lock().await;
156 let ext = ext_guard.deref_mut();
157 let mode = if core_version::<Block, HostFns>(ext, executor)? >= 5 {
159 let mode = call::<ExtrinsicInclusionMode, Block, _>(
160 ext,
161 executor,
162 "Core_initialize_block",
163 &header.encode(),
164 )
165 .await?;
166 Some(mode)
167 } else {
168 call::<(), Block, _>(ext, executor, "Core_initialize_block", &header.encode()).await?;
169 None
170 };
171
172 let extrinsics = dry_call::<Vec<Block::Extrinsic>, Block, _>(
173 ext,
174 executor,
175 "BlockBuilder_inherent_extrinsics",
176 &inherent_data.encode(),
177 )?;
178
179 for xt in &extrinsics {
180 call::<(), Block, _>(ext, executor, "BlockBuilder_apply_extrinsic", &xt.encode()).await?;
181 }
182
183 let header = dry_call::<Block::Header, Block, _>(
184 ext,
185 executor,
186 "BlockBuilder_finalize_block",
187 &[0u8; 0],
188 )?;
189
190 call::<(), Block, _>(ext, executor, "BlockBuilder_finalize_block", &[0u8; 0]).await?;
191 ext.commit_all().unwrap();
192 drop(ext_guard);
193
194 Ok((
195 Block::new(header, extrinsics),
196 (inherent_data, digest),
197 mode,
198 ))
199}
200
201async fn call<T: Decode, Block: BlockT, HostFns: HostFunctions>(
203 externalities: &mut TestExternalities<HashingFor<Block>>,
204 executor: &WasmExecutor<HostFns>,
205 method: &'static str,
206 data: &[u8],
207) -> Result<T> {
208 let (mut changes, result) = state_machine_call::<Block, HostFns>(
209 externalities,
210 executor,
211 method,
212 data,
213 full_extensions(executor.clone()),
214 )?;
215
216 let storage_changes =
217 changes.drain_storage_changes(&externalities.backend, externalities.state_version)?;
218
219 externalities.backend.apply_transaction(
220 storage_changes.transaction_storage_root,
221 storage_changes.transaction,
222 );
223
224 T::decode(&mut &*result).map_err(|e| sc_cli::Error::Input(format!("{:?}", e)))
225}
226
227pub fn core_version<Block: BlockT, HostFns: HostFunctions>(
228 externalities: &TestExternalities<HashingFor<Block>>,
229 executor: &WasmExecutor<HostFns>,
230) -> Result<u32> {
231 dry_call::<u32, Block, HostFns>(externalities, executor, "Core_version", &[])
232}
233
234pub fn relay_parent_offset<Block: BlockT, HostFns: HostFunctions>(
236 externalities: &TestExternalities<HashingFor<Block>>,
237 executor: &WasmExecutor<HostFns>,
238) -> u32 {
239 dry_call::<u32, Block, HostFns>(
240 externalities,
241 executor,
242 "RelayParentOffsetApi_relay_parent_offset",
243 &[],
244 )
245 .unwrap_or(0)
246}
247
248fn dry_call<T: Decode, Block: BlockT, HostFns: HostFunctions>(
250 externalities: &TestExternalities<HashingFor<Block>>,
251 executor: &WasmExecutor<HostFns>,
252 method: &'static str,
253 data: &[u8],
254) -> Result<T> {
255 let (_, result) = state_machine_call::<Block, HostFns>(
256 externalities,
257 executor,
258 method,
259 data,
260 full_extensions(executor.clone()),
261 )?;
262
263 Ok(<T>::decode(&mut &*result)?)
264}