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