try_runtime_core/common/empty_block/
production.rs

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    // We are saving state before we overwrite it while producing new block.
45    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    // Prevent it from printing all logs twice:
56    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    // And now we restore previous state.
76    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    //call::<(), Block, _>(ext, executor, "TryRuntime_execute_block", &payload).await?;
89
90    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
101/// Produces next block containing only inherents.
102pub 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    // Only RA API version 5 supports returning a mode, so need to check.
151    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
194/// Call `method` with `data` and actually save storage changes to `externalities`.
195async 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
227/// Call `method` with `data` and return the result. `externalities` will not change.
228fn 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}