try_runtime_core/common/empty_block/
production.rs

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    // We are saving state before we overwrite it while producing new block.
46    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    // Prevent it from printing all logs twice:
57    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    // And now we restore previous state.
77    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    //call::<(), Block, _>(ext, executor, "TryRuntime_execute_block", &payload).await?;
90
91    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
102/// Produces next block containing only inherents.
103pub 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    // Only RA API version 5 supports returning a mode, so need to check.
158    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
201/// Call `method` with `data` and actually save storage changes to `externalities`.
202async 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
234/// Query the relay parent offset from the runtime.
235pub 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
248/// Call `method` with `data` and return the result. `externalities` will not change.
249fn 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}