try_runtime/
main.rs

1// This file is part of try-runtime-cli.
2
3// Copyright (C) Parity Technologies (UK) Ltd.
4// SPDX-License-Identifier: Apache-2.0
5
6// Licensed under the Apache License, Version 2.0 (the "License");
7// you may not use this file except in compliance with the License.
8// You may obtain a copy of the License at
9//
10// 	http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17
18//! # Try-runtime
19//!
20//! Substrate's programmatic testing framework.
21//!
22//! > As the name suggests, `try-runtime` is a detailed testing framework that gives you a lot of
23//! > control over what is being executed in which environment. It is recommended that user's first
24//! > familiarize themselves with substrate in depth, particularly the execution model. It is
25//! > critical
26//! > to deeply understand how the wasm/client/runtime interactions, and the runtime apis work in
27//! > the
28//! > substrate runtime, before commencing to working with `try-runtime`.
29//!
30//! #### Resources
31//!
32//! Some resources about the above:
33//!
34//! 1. <https://www.crowdcast.io/e/substrate-seminar/41>
35//! 2. <https://docs.substrate.io/fundamentals/runtime-development/>
36//! 3. <https://www.youtube.com/watch?v=a_u3KMG-n-I>
37//!
38//! ---
39//!
40//! ## Background Knowledge
41//!
42//! The basis of all try-runtime commands is the same: connect to a live node, scrape its *state*
43//! and put it inside a [`TestExternalities`], then call into a *specific runtime-api* using the
44//! given state and some *runtime*. Multiple node URIs can be provided to enable parallel state
45//! downloads for improved performance.
46//!
47//! Alternatively, the state could come from a snapshot file.
48//!
49//! All of the variables in the above statement are made *italic*. Let's look at each of them:
50//!
51//! 1. **State** is the key-value pairs of data that comprise the canonical information that any
52//!    blockchain is keeping. A state can be full (all key-value pairs), or be partial (only pairs
53//!    related to some pallets/prefixes). Moreover, some keys are special and are not related to
54//!    specific pallets, known as [`well_known_keys`] in substrate. The most important of these is
55//!    the `:CODE:` key, which contains the code used for execution, when wasm execution is chosen.
56//!
57//! 2. *A runtime-api* call is a call into a function defined in the runtime, *on top of a given
58//!    state*. Each subcommand of `try-runtime` utilizes a specific *runtime-api*.
59//!
60//! 3. Finally, the **runtime** is the actual code that is used to execute the aforementioned
61//!    runtime-api. Everything in this crate assumes wasm execution, which means the runtime that
62//!    you use is the one stored onchain, namely under the `:CODE:` key.
63//!
64//! To recap, a typical try-runtime command does the following:
65//!
66//! 1. Download the state of a live chain, and write to an `externalities`.
67//! 2. Overwrite the `:CODE:` with a given wasm blob
68//! 3. Test some functionality via calling a runtime-api.
69//!
70//! ## Installation
71
72//!```bash
73//! # Install latest version (recommended for local development)
74//! cargo install --git https://github.com/paritytech/try-runtime-cli --locked
75//! # Install a specific version (recommended for tools like CI)
76//! cargo install --git https://github.com/paritytech/try-runtime-cli --tag vX.Y.Z --locked
77//! try-runtime --help
78//! try-runtime on-runtime-upgrade --help
79//! ```
80//!
81//! ## Usage
82//!
83//! To use any of the provided commands, [`SharedParams`] must be provided. The most important of
84//! which being [`SharedParams::runtime`], which specifies which runtime to use. Furthermore,
85//! [`SharedParams::overwrite_state_version`] can be used to alter the state-version (see
86//! <https://forum.polkadot.network/t/state-trie-migration/852> for more info).
87//!
88//! Then, the specific command has to be specified. See [`Action`] for more information about each
89//! command's specific customization flags, and assumptions regarding the runtime being used.
90//!
91//! Briefly, this CLI is capable of executing:
92//!
93//! * [`Action::OnRuntimeUpgrade`]: execute all the [`OnRuntimeUpgrade`] hooks.
94//! * [`Action::ExecuteBlock`]: re-execute the given block.
95//! * [`Action::FastForward`]: execute [`OnRuntimeUpgrade`] hooks, then fast-forward the chain a
96//!   given number of blocks while checking try-state invarients.
97//! * [`Action::OffchainWorker`]: re-execute the given block's offchain worker code path.
98//! * [`Action::FollowChain`]: continuously execute the blocks of a remote chain on top of a given
99//!   runtime.
100//! * [`Action::CreateSnapshot`]: Create a snapshot file from a remote node.
101//!
102//! Finally, to make sure there are no errors regarding this, always run any `try-runtime` command
103//! with `executor=trace` logging targets, which will specify which runtime is being used per api
104//! call. Moreover, `remote-ext`, `try-runtime` and `runtime` logs targets will also be useful.
105//!
106//! ## Spec name check
107//!
108//! A common pitfall is that you might be running some test on top of the state of chain `x`, with
109//! the runtime of chain `y`. To avoid this all commands do a spec-name check before executing
110//! anything by default. This will check the, if any alterations are being made to the `:CODE:`,
111//! then the spec names match. The spec versions are warned, but are not mandated to match.
112//!
113//! > If anything, in most cases, we expect spec-versions to NOT match, because try-runtime is all
114//! > about testing unreleased runtimes.
115//!
116//! ## Note on signature and state-root checks
117//!
118//! All of the commands calling into `TryRuntime_execute_block` ([`Action::ExecuteBlock`] and
119//! [`Action::FollowChain`]) disable both state root and signature checks. This is because in 99%
120//! of the cases, the runtime that is being tested is different from the one that is stored in the
121//! canonical chain state. This implies:
122//!
123//! 1. the state root will NEVER match, because `:CODE:` is different between the two.
124//! 2. replaying all transactions will fail, because the spec-version is part of the transaction
125//!    signature.
126//!
127//! ## Best Practices
128//!
129//! Try-runtime is all about battle-testing unreleased runtimes. The following list of suggestions
130//! help developers maximize their testing coverage and make the best use of `try-runtime` features.
131//!
132//! ### Testing Runtime Upgrades
133//!
134//! One of the most powerful abilities of `try-runtime` is using the
135//! [`OnRuntimeUpgrade::pre_upgrade`] and [`OnRuntimeUpgrade::post_upgrade`] hooks to test runtime
136//! upgrades implemented with [`OnRuntimeUpgrade`]. [`OnRuntimeUpgrade`] can be implemented inside
137//! the pallet, or standalone in a runtime to define a migration to execute next runtime upgrade. In
138//! both cases, these methods can be added:
139//!
140//! ```ignore
141//! #[cfg(feature = "try-runtime")]
142//! fn pre_upgrade() -> Result<Vec<u8>, TryRuntimeError> {}
143//!
144//! #[cfg(feature = "try-runtime")]
145//! fn post_upgrade(state: Vec<u8>) -> Result<(), TryRuntimeError> {}
146//! ```
147//!
148//! (The pallet macro syntax will support this simply as a part of `#[pallet::hooks]`).
149//!
150//! These hooks will be called when you execute the [`Action::OnRuntimeUpgrade`] command, before and
151//! after the migration. [`OnRuntimeUpgrade::pre_upgrade`] returns a [`Vec<u8>`] that can contain
152//! arbitrary encoded data (usually some pre-upgrade state) which will be passed to
153//! [`OnRuntimeUpgrade::pre_upgrade`] after upgrading and used for post checking.
154//!
155//! **Note on Multi-Block Migrations (MBM):** If the runtime uses MBMs, the standard
156//! `pre_upgrade` and `post_upgrade` checks might be skipped by the executive. To
157//! force these hooks to run synchronously for testing, use the `--disable-mbm-checks` flag.
158//!
159//! ### [`VersionedMigration`]
160//!
161//! It is strongly suggested to use [`VersionedMigration`] when writing custom migrations for
162//! pallets.
163//!
164//! ### State Consistency
165//!
166//! Similarly, each pallet can expose a function in `#[pallet::hooks]` section as follows:
167//!
168//! ```ignore
169//! #[cfg(feature = "try-runtime")]
170//! fn try_state(_: BlockNumber) -> Result<(), TryRuntimeError> {}
171//! ```
172//!
173//! which is called on numerous code paths in the try-runtime tool. These checks should ensure that
174//! the state of the pallet is consistent and correct. See [`TryState`] for more info.
175//!
176//! ### Logging
177//!
178//! It is super helpful to make sure your migration code uses logging (always with a `runtime` log
179//! target prefix, e.g. `runtime::balance`) and state exactly at which stage it is, and what it is
180//! doing.
181//!
182//! ## Examples
183//!
184//! For the following examples, we assume the existence of the following:
185//!
186//! 1. a substrate node compiled with `--features try-runtime`, called `substrate`. This will be the
187//!    running node that you connect to, and provide a wasm blob that has try-runtime functionality
188//!    enabled.
189//! 2. the `try-runtime` CLI binary on your path.
190//!
191//! ```bash
192//! # this is like your running deployed node.
193//! cargo build --features try-runtime --release && cp target/release/substrate .
194//! ```
195//!
196//! > The above example is with `substrate`'s `kitchensink-runtime`, but is applicable to any
197//! > substrate-based chain.
198//!
199//! * Run the migrations of a given runtime on top of a live state.
200//!
201//! ```bash
202//! # Assuming local nodes are running (e.g., `./substrate --dev --tmp --ws-port 9999`).
203//! # Multiple --uri flags can be provided for parallel state download.
204//! try-runtime \
205//!     --runtime /path-to-substrate/target/release/wbuild/my-runtime.wasm \
206//!     on-runtime-upgrade \
207//!     --disable-mbm-checks \
208//!     live \
209//!     --uri ws://localhost:9999 \
210//!     --uri ws://localhost:9998
211//!     ...
212//! ```
213//!
214//! To speed up state download, you can provide multiple URIs for parallel fetching:
215//!
216//! ```bash
217//! # assuming multiple substrate nodes running on ports 9999, 9998, 9997
218//! try-runtime \
219//!     --runtime /path-to-substrate/target/release/wbuild/my-runtime.wasm \
220//!     on-runtime-upgrade \
221//!     live \
222//!     --uri ws://localhost:9999 \
223//!     --uri ws://localhost:9998 \
224//!     --uri ws://localhost:9997
225//! ```
226//!
227//! * Same as the previous example, but run it at specific block number's state and using the live
228//!   polkadot network. This means that this block hash's state should not yet have been pruned by
229//!   the node running at `rpc.polkadot.io`. Multiple `--uri` flags can be provided for parallel
230//!   state download.
231//!
232//! ```bash
233//! try-runtime \
234//!     --runtime /path-to-polkadot-runtimes/target/release/wbuild/polkadot-runtime/polkadot-runtime.wasm \
235//!     on-runtime-upgrade \
236//!     live --uri wss://rpc.polkadot.io:443 \
237//!     # replace with your desired block hash!
238//!     --at 0xa1b16c1efd889a9f17375ec4dd5c1b4351a2be17fa069564fced10d23b9b3836
239//! ```
240//!
241//! * Now, let's use a snapshot file. First, we create the snapshot:
242//!
243//! ```bash
244//! try-runtime --runtime existing create-snapshot --uri ws://localhost:9999 -- my-snapshot.snap
245//! 2022-12-13 10:28:17.516  INFO                 main remote-ext: since no at is provided, setting it to latest finalized head, 0xe7d0b614dfe89af65b33577aae46a6f958c974bf52f8a5e865a0f4faeb578d22
246//! 2022-12-13 10:28:17.516  INFO                 main remote-ext: since no prefix is filtered, the data for all pallets will be downloaded
247//! 2022-12-13 10:28:17.550  INFO                 main remote-ext: writing snapshot of 1611464 bytes to "node-268@latest.snap"
248//! 2022-12-13 10:28:17.551  INFO                 main remote-ext: initialized state externalities with storage root 0x925e4e95de4c08474fb7f976c4472fa9b8a1091619cd7820a793bf796ee6d932 and state_version V1
249//! ```
250//!
251//! For faster snapshot creation with large state, use multiple RPC endpoints:
252//!
253//! ```bash
254//! try-runtime --runtime existing create-snapshot \
255//!     --uri ws://localhost:9999 \
256//!     --uri ws://localhost:9998 \
257//!     -- my-snapshot.snap
258//! ```
259//!
260//! > Note that the snapshot contains the `existing` runtime, which does not have the correct
261//! > `try-runtime` feature. In the following commands, we still need to overwrite the runtime.
262//!
263//! Then, we can use it to have the same command as before, `on-runtime-upgrade`
264//!
265//! ```bash
266//! try-runtime \
267//!     --runtime /path-to-substrate/target/release/wbuild/my-runtime.wasm \
268//!     on-runtime-upgrade \
269//!     snap -p my-snapshot.snap
270//! ```
271//!
272//! * Execute the latest finalized block with the given runtime.
273//!
274//! ```bash
275//! try-runtime \
276//!     --runtime /path-to-substrate/target/release/wbuild/my-runtime.wasm \
277//!     execute-block live \
278//!     --uri ws://localhost:9999
279//! ```
280//!
281//! This can still be customized at a given block with `--at`. If you want to use a snapshot, you
282//! can still use `--block-ws-uri` to provide a node form which the block data can be fetched.
283//!
284//! Moreover, this runs the [`TryState`] hooks as well. The hooks to run can be customized with the
285//! `--try-state`. For example:
286//!
287//! ```bash
288//! try-runtime \
289//!     --runtime /path-to-substrate/target/release/wbuild/my-runtime.wasm \
290//!    execute-block \
291//!    --try-state System,Staking \
292//!    live \
293//!    --uri ws://localhost:9999 \
294//!    --pallet System Staking
295//! ```
296//!
297//! Will only run the `try-state` of the two given pallets. When running `try-state` against
298//! some real chain data it can take a long time for the command to execute since it has to
299//! query all the key-value pairs. In scenarios like above where we only want to run the
300//! `try-state` for some specific pallets, we can use the `--pallet` option to specify from
301//! which pallets we want to query the state. This will greatly decrease the execution time.
302//!
303//! See [`TryStateSelect`] for more information.
304//!
305//! * Follow our live chain's blocks using `follow-chain`, whilst running the try-state of 3 pallets
306//!   in a round robin fashion
307//!
308//! ```bash
309//! try-runtime \
310//!     --runtime /path-to-substrate/target/release/wbuild/my-runtime.wasm \
311//!     follow-chain \
312//!     --uri ws://localhost:9999 \
313//!     --try-state rr-3
314//! ```
315//!
316//! [`VersionedMigration`]: frame_support::migrations::VersionedMigration
317//! [`OnRuntimeUpgrade`]: frame_support::traits::OnRuntimeUpgrade
318//! [`OnRuntimeUpgrade::pre_upgrade`]: frame_support::traits::OnRuntimeUpgrade::pre_upgrade
319//! [`OnRuntimeUpgrade::post_upgrade`]: frame_support::traits::OnRuntimeUpgrade::post_upgrade
320//! [`TryStateSelect`]: frame_support::traits::TryStateSelect
321//! [`TryState`]: frame_support::traits::TryState
322//! [`TestExternalities`]: sp_state_machine::TestExternalities
323//! [`well_known_keys`]: sp_storage::well_known_keys
324//! [`Action`]: try_runtime_core::commands::Action
325//! [`Action::FollowChain`]: try_runtime_core::commands::Action::FollowChain
326//! [`Action::OnRuntimeUpgrade`]: try_runtime_core::commands::Action::OnRuntimeUpgrade
327//! [`Action::ExecuteBlock`]: try_runtime_core::commands::Action::ExecuteBlock
328//! [`Action::OffchainWorker`]: try_runtime_core::commands::Action::OffchainWorker
329//! [`Action::CreateSnapshot`]: try_runtime_core::commands::Action::CreateSnapshot
330//! [`Action::FastForward`]: try_runtime_core::commands::Action::FastForward
331//! [`SharedParams`]: try_runtime_core::common::shared_parameters::SharedParams
332//! [`SharedParams::runtime`]: try_runtime_core::common::shared_parameters::SharedParams::runtime
333//! [`SharedParams::overwrite_state_version`]: try_runtime_core::common::shared_parameters::SharedParams::overwrite_state_version
334
335use std::env;
336
337use clap::Parser;
338use sp_runtime::{
339    generic::{Block, Header},
340    traits::BlakeTwo256,
341    OpaqueExtrinsic,
342};
343use try_runtime_core::commands::TryRuntime;
344
345fn init_env() {
346    if env::var(env_logger::DEFAULT_FILTER_ENV).is_err() {
347        env::set_var(env_logger::DEFAULT_FILTER_ENV, "info");
348    }
349    env_logger::init();
350}
351
352#[tokio::main]
353async fn main() {
354    init_env();
355
356    let cmd = TryRuntime::parse();
357    cmd.run::<Block<Header<u32, BlakeTwo256>, OpaqueExtrinsic>, sp_io::SubstrateHostFunctions>()
358        .await
359        .unwrap();
360}