Use try-runtime

The try-runtime tool enables you to run tests and verify operations in a simulated environment before launching a runtime to production. This guide demonstrates the basic steps for integrating the try-runtime tool into a runtime so you can use it to test a storage migration.

In general, adding the try-runtime tool to your runtime is similar to importing pallets. It involves adding the appropriate dependencies in the correct places and updating the runtime logic to to include the try-runtime features. As with pallets, be sure that you are using the appropriate tag or branch for the try-runtime tool when adding dependencies to the runtime.

Add runtime dependencies

  1. Open a terminal shell and change to the root directory for the node template.
  2. Open the runtime/Cargo.toml configuration file in a text editor.
  3. Locate the [dependencies] section and note how other pallets are imported.
  4. Add the frame-try-runtime dependency:

    [dependencies]
     frame-try-runtime = { git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.26", optional = true }
  5. Add the try-runtime-cli dependency:

    try-runtime-cli = { git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.26", optional = true }
  6. Add frame-try-runtime to the list of standard features:

    	[features]
    	default = ["std"]
    	std = [
    		"codec/std",
    		"scale-info/std",
    		"frame-try-runtime/std",
    		...
    	]
    	```
  7. Add or update try-runtime in the [features] section in include every pallet in your runtime.

    try-runtime = [
    	 "frame-executive/try-runtime",
    	 "frame-try-runtime",
    	 "frame-system/try-runtime",
    	 "pallet-aura/try-runtime",
    	 "pallet-balances/try-runtime",
    	 "pallet-nicks/try-runtime",
    	 "pallet-grandpa/try-runtime",
    	 "pallet-randomness-collective-flip/try-runtime",
    	 "pallet-sudo/try-runtime",
    	 "pallet-template/try-runtime",
    	 "pallet-timestamp/try-runtime",
    	 "pallet-transaction-payment/try-runtime",
    	]

Implement try-runtime in the runtime api

  1. Add a configuration block for the try-runtime feature.

    // Implementation of runtime's apis
    impl_runtime_apis! {
    ...
    	/* --snip-- */
    #[cfg(feature = "try-runtime")]
    impl frame_try_runtime::TryRuntime<Block> for Runtime {
       fn on_runtime_upgrade() -> (frame_support::weights::Weight, frame_support::weights::Weight) {
           log::info!("try-runtime::on_runtime_upgrade.");
           // NOTE: intentional unwrap: we don't want to propagate the error backwards, and want to
           // have a backtrace here. If any of the pre/post migration checks fail, we shall stop
           // right here and right now.
           let weight = Executive::try_runtime_upgrade().map_err(|err|{
               log::info!("try-runtime::on_runtime_upgrade failed with: {:?}", err);
               err
           }).unwrap();
           (weight, RuntimeBlockWeights::get().max_block)
       }
       fn execute_block_no_check(block: Block) -> frame_support::weights::Weight {
           Executive::execute_block_no_check(block)
       }
    }
    	```

Add node dependencies

  1. Open the node/Cargo.toml configuration file in a text editor.
  2. Locate the [dependencies] section and note how other pallets are imported.
  3. Add the frame-try-runtime dependency:

    frame-try-runtime = { git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.26", optional = true }
  4. Add the try-runtime-cli dependency:

    try-runtime-cli = { git = "https://github.com/paritytech/substrate.git", branch = "polkadot-v0.9.26", optional = true }
  5. Add or update cli and try-runtime in the [features] section.

    [features]
    ...
    cli = [ "try-runtime-cli" ]
    try-runtime = [ "node-template-runtime/try-runtime", "try-runtime-cli" ]
    ...

Add command-line subcommands

  1. Open the node/src/cli.rs file in a text editor.
/* --snip-- */
/// Try some command against runtime state.
#[cfg(feature = "try-runtime")]
TryRuntime(try_runtime_cli::TryRuntimeCmd),

/// Try some command against runtime state. Note: `try-runtime` feature must be enabled.
#[cfg(not(feature = "try-runtime"))]
TryRuntime,
/* --snip-- */

Add commands

  1. Open the node/src/commands.rs file in a text editor.
  2. Add commands

    /* --snip-- */
    #[cfg(feature = "try-runtime")]
    Some(Subcommand::TryRuntime(cmd)) => {
    	let runner = cli.create_runner(cmd)?;
    	runner.async_run(|config| {
    		// only need a runtime or a task manager to do `async_run`.
    		let registry = config.prometheus_config.as_ref().map(|cfg| &cfg.registry)let task_manager = sc_service::TaskManager::new(
    		  config.tokio_handle.clone(),
    			registry,
    		).map_err(|e| sc_cli::Error::Service(sc_service::Error::Prometheus(e)))?;
    		
    	  Ok((cmd.run::<Block, service::ExecutorDispatch>(config), task_manager))
    	})
    },
    
    #[cfg(not(feature = "try-runtime"))]
    Some(Subcommand::TryRuntime) => {
    	Err("TryRuntime wasn't enabled when building the node. \
    	You can enable it with `--features try-runtime`.".into())
    	},
    /* --snip-- */

If you're using custom pallets in your workspace, make sure you included try-runtime in the dependencies inside the pallets/pallet_name/Cargo.toml file of your workspace.

Use the try-runtime

Using the try-runtime tool is similar to writing unit tests.

To use try-runtime:

  1. Create an externalities instance.
  2. Call execute_with on instance.

Where to go next