diff --git a/tuts/perform-a-runtime-upgrade/config.json b/tuts/perform-a-runtime-upgrade/config.json new file mode 100644 index 0000000..0f32742 --- /dev/null +++ b/tuts/perform-a-runtime-upgrade/config.json @@ -0,0 +1,14 @@ +{ + "slug": "config", + "lang": "en", + "title": "Perform a Runtime Upgrade", + "excerpt": "Forklessly upgrade your chain's runtime logic.", + "tags": [ "Medium", "2 Hours", "Prerequisites" ], + "versions": [ "v2.0.0-alpha.6" ], + "menu": [ + { "title": "Overview", "slug": "index" }, + { "title": "Code Changes", "slug": "code" }, + { "title": "Upgrade Transaction", "slug": "transaction" }, + { "title": "Storage Migrations", "slug": "migration" } + ] +} diff --git a/tuts/perform-a-runtime-upgrade/featured-image.png b/tuts/perform-a-runtime-upgrade/featured-image.png new file mode 100644 index 0000000..198e06b Binary files /dev/null and b/tuts/perform-a-runtime-upgrade/featured-image.png differ diff --git a/tuts/perform-a-runtime-upgrade/v2.0.0-alpha.6/code.md b/tuts/perform-a-runtime-upgrade/v2.0.0-alpha.6/code.md new file mode 100644 index 0000000..a616110 --- /dev/null +++ b/tuts/perform-a-runtime-upgrade/v2.0.0-alpha.6/code.md @@ -0,0 +1,148 @@ +--- +slug: code +lang: en +title: Code Changes +--- + +## Install the Node Template + +You should already have version `v2.0.0-alpha.6` of the [Substrate Node +Template](https://github.com/substrate-developer-hub/substrate-node-template) compiled and running on your +computer from when you completed the [Create Your First Substrate Chain +Tutorial](/tutorials/create-your-first-substrate-chain/v2.0.0-alpha.6). If you do not, please complete that +tutorial. + +> Experienced developers who truly prefer to skip that tutorial, you may install the node template according to the instructions in its readme. + +Further, you should have the chain running, as it was at the end of that tutorial. + +If you have completed that tutorial, but your chain is no longer currently running, `cd` into the directory you created in that tutorial, and run the command `./target/release/node-template --dev` to start your node again. + +## Make a Change to the Code + +Runtime upgrades are necessary when you want to change the code of a live chain. While it is generally advisable to complete the code as much as possible before launching the chain, changes after launch become necessary to do things like fix bugs or add features. + +### Primary Logic Change + +The Substrate Node Template contains a template pallet which accepts transactions to store a value and increment a value. In this tutorial we will add one extrinsic to clear the value, and leave `None` in its place. + +Open the `substrate-node-template` in your favorite code editor. Then open the file +`pallets/template/src/lib.rs` + +``` +substrate-node-template +| ++-- runtime +| ++-- pallets +| | +| +-- template +| | +| +-- Cargo.toml +| | +| +-- src +| | +| +-- lib.rs <-- Edit this file +| | +| +-- mock.rs +| | +| +-- tests.rs +| ++-- scripts +| ++-- node +| ++-- ... +``` + +In this file you will see this block of code containing two extrinsics used to set and increment the value. + +```rust +decl_module! { + /// The module declaration. + pub struct Module for enum Call where origin: T::Origin { + // --snip-- + + #[weight = frame_support::weights::SimpleDispatchInfo::default()] + pub fn do_something(origin, something: u32) -> dispatch::DispatchResult { + // --snip-- + } + + #[weight = frame_support::weights::SimpleDispatchInfo::default()] + pub fn cause_error(origin) -> dispatch::DispatchResult { + // --snip-- + } + + // TODO Add your code here. + } +} +``` + +Add the following code at the bottom of the `decl_module!` block. This code adds a third extrinsic to clear the stored value. + +```rust +/// Clears the value stored, if any +#[weight = frame_support::weights::SimpleDispatchInfo::default()] +pub fn clear_value(origin) -> dispatch::DispatchResult { + // Check it was signed and get the signer. + let _who = ensure_signed(origin)?; + + // Clear the storage value + Something::kill(); + + Ok(()) +} +``` + +Confirm that your changes are correct so far by running `cargo check -p pallet-template`. If this command completes successfully, you're ready to move on. If not, stop and fix your errors or ask for help before continuing. + +### Bumping the Spec Version + +We've already made all of the logic changes we intend to make to our code, and our runtime is perfectly valid in its current state. However, because we will be upgrading a live chain, we need to indicate that this is a new version of the runtime. In particular, it is a new `spec_version`. + +> There are multiple ways in which a runtime is versioned. Read more about runtime versioning in the rustdocs about the [`RuntimeVersion` struct](https://substrate.dev/rustdocs/v2.0.0-alpha.6/sp_version/struct.RuntimeVersion.html). + +Open the file +`runtime/src/lib.rs` + +```text +substrate-node-template +| ++-- runtime +| | +| +-- Cargo.toml +| | +| +-- src +| | +| +-- lib.rs <-- Edit this file +| ++-- pallets +| ++-- scripts +| ++-- node +| ++-- ... +``` + +Look for this section of code, and change the spec version from 1 to 2. + +```rust +/// This runtime version. +pub const VERSION: RuntimeVersion = RuntimeVersion { + spec_name: create_runtime_str!("node-template"), + impl_name: create_runtime_str!("node-template"), + authoring_version: 1, + spec_version: 1, //TODO Change this to 2 + impl_version: 1, + apis: RUNTIME_API_VERSIONS, +}; +``` + +## Recompile Your Runtime + +You're now ready to recompile your runtime. To build _just_ the runtime, and not the entire node, you may run the command. + +```bash +cargo build --release -p node-template-runtime +``` diff --git a/tuts/perform-a-runtime-upgrade/v2.0.0-alpha.6/index.md b/tuts/perform-a-runtime-upgrade/v2.0.0-alpha.6/index.md new file mode 100644 index 0000000..c02ff62 --- /dev/null +++ b/tuts/perform-a-runtime-upgrade/v2.0.0-alpha.6/index.md @@ -0,0 +1,31 @@ +--- +slug: index +lang: en +title: Overview +--- + +In this tutorial, you will perform a runtime upgrade on a live blockchain. You will use Substrate's forkless upgrade mechanism to perform the upgrade without requiring a client upgrade, and without causing a fork in the network. + +This tutorial guides you step-by-step through reproducing the results demonstrated by Ricardo Rius in his [Sub0 talk, Runtime Upgrades](https://www.crowdcast.io/e/sub0-online/8). + +We only expect that: + +* You are generally familiar with software development, writing code, and running your code. +* You have completed the [Create Your First Substrate Chain Tutorial](/tutorials/create-your-first-substrate-chain/v2.0.0-aplha.6). +* You are open to learning about the bleeding edge of blockchain development. + +If you run into an issue on this tutorial, **we are here to help!** You can [create a new +issue](https://github.com/substrate-developer-hub/tutorials/issues/new) or +contact us on [Riot](https://riot.im/app/#/room/!HzySYSaIhtyWrwiwEV:matrix.org). + +## What you will be doing + +Before we even get started, let's lay out what we are going to do over the course of this tutorial. +We will: + +1. Launch a blockchain based on a template project. +2. Modify this template project with some custom logic, after the chain has already launched. +3. Upgrade the live chain using Substrate's forkless upgrade mechanism. +4. Discuss Chain state migrations. + +Sound reasonable? Good, then let's begin! diff --git a/tuts/perform-a-runtime-upgrade/v2.0.0-alpha.6/migrations.md b/tuts/perform-a-runtime-upgrade/v2.0.0-alpha.6/migrations.md new file mode 100644 index 0000000..1896076 --- /dev/null +++ b/tuts/perform-a-runtime-upgrade/v2.0.0-alpha.6/migrations.md @@ -0,0 +1,74 @@ +--- +slug: migrations +lang: en +title: Storage Migrations +--- + +The runtime upgrade we just performed completed successfully simply by adding our new feature and incrementing our `spec_version`. In many simple and moderately complex cases this is all that's necessary. In other cases, you may restructure the way data is stored in the blockchain as well as modifying the logic. In these cases, it is necessary to include a migration path for the existing data. In this section we'll explore data migrations. + +## Primary Code Change + +For this example we will rename our storage struct from `TemplateModule` to `UpgradedTemplateModule`. To begin we open the `pallets/template/src/lib.rs` file and modify the the following line + +```rust +trait Store for Module as TemplateModule { +``` + +so that it says + +```rust +trait Store for Module as UpgradedTemplateModule { +``` + +## Bumping the Spec Version + +As before, we will open the `runtime/src/lib.rs` file and change our `spec_version`. This time we change it to 3. + +```rust +/// This runtime version. +pub const VERSION: RuntimeVersion = RuntimeVersion { + spec_name: create_runtime_str!("node-template"), + impl_name: create_runtime_str!("node-template"), + authoring_version: 1, + spec_version: 2, //TODO change this to 3 + impl_version: 1, + apis: RUNTIME_API_VERSIONS, +}; +``` + +## Writing the Migration + +Any time you change the storage struct, the name of a storage item, or the way a key is calculated in a storage map, you need to write a migration, or else the old data will not be accessible by the new code. + +As you can see from the `decl_storage!` block of our template pallet, we are only dealing with a single storage item that was, and still is called `Something`. + +The complete code for our migration looks like this, and can be inserted at the bottom of the `decl_module!` block, just like the dispatchable call we added in the previous upgrade. + +```rust +fn on_runtime_upgrade() -> frame_support::weights::Weight { + use frame_support::storage::migration::{get_storage_value, put_storage_value}; + + let value_to_migrate: Option = get_storage_value(b"TempalteModule", b"Something", &[]); + put_storage_value(b"UpgradedTemplateModule", b"Something", &[], value_to_migrate); + + 1_000 // In reality the weight of a migration should be determined by benchmarking + } +``` + +First, this code `use`s two helper functions from frame support that are designed specifically for storage migrations. You will always need to do this. + +Next, it grabs the value out of the old storage location. Notice that we need an explicit type annotation when grabbing the old data. This will always be necessary, and if you are unsure, just check the `decl_storage!` block to learn the type. As parameters, we have supplied the _old_ storage struct name, the storage item name, and an empty array. The third parameter will be necessary when working with storage maps, but we are using a plain storage value, so we leave it blank. + +Once the old value is retrieved, we put it into the new storage locations. This time we supply the _new_ storage struct name, the same storage value name, and, again, an empty array. The final parameter if the value to store that we grabbed out of the old storage location. + +TODO Do we need to kill the old storage here? Probably. + +Finally we return a weight to quantify the time it takes to execute this logic. In this tutorial I have included an arbitrary weight. But in a real network, it is important to benchmark the execution time of the function, and choose a weight appropriately. + +## Perform the Upgrade + +You're now ready to recompile your runtime, and perform the upgrade using the sudo pallet as we did with the previous upgrade. + +## That's it! + +In this tutorial, you performed two runtime upgrades on a live blockchain without causing any forks. Congratulations! You also learned how and when to write storage migrations. diff --git a/tuts/perform-a-runtime-upgrade/v2.0.0-alpha.6/transaction.md b/tuts/perform-a-runtime-upgrade/v2.0.0-alpha.6/transaction.md new file mode 100644 index 0000000..05ddb7b --- /dev/null +++ b/tuts/perform-a-runtime-upgrade/v2.0.0-alpha.6/transaction.md @@ -0,0 +1,37 @@ +--- +slug: transaction +lang: en +title: Upgrade Transaction +--- + +In this section we will perform the on-chain runtime upgrading by submitting the new runtime logic in an extrinsic. + +## Locating the Wasm Build Artifact + +At the end of the last section we compiled our runtime. Substrate Runtimes are always compiled to both Web Assembly (or Wasm) and native code so that the Wasm can be stored on the blockchain and facilitate this forkless upgrade process. Our freshly compiled runtime is stored at `./target/release/wbuild/node-template-runtime/node-template-runtime.compact.wasm`. Ensure this file exists and that it was modified recently. + +> Read more about forkless upgrades and Wasm vs native runtimes in the [executor](/kb/advanced/executor) article. + +## Starting the User Interface + +For this upgrade, we will use the Polkadot JS Apps user interface; the same UI we used in the [Create Your First Substrate Chain](/tutorials/create-your-first-substrate-chain/v2.0.0-alpha.6) Tutorial. + +In your web browser, navigate to [https://polkadot.js.org/apps](https://polkadot.js.org/apps/#/settings?rpc=ws://127.0.0.1:9944). + +On the `Settings` tab ensure that you are connected to a `Local Node` or `ws://127.0.0.1:9944`. + +> Some browsers, notably Firefox, will not connect to a local node from an https website. An easy work around is to try another browser, like Chromium. Another option is to [host this interface locally](https://github.com/polkadot-js/apps#development). + +## Submit the Extrinsic + +As you can imagine, in a real-world blockchain, we don't want just anyone to be able to change the runtime logic. There is a special extrinsic for performing these upgrades called, `system::set_code`. This special transaction cannot be called by an ordinary user, and must be called from within the blockchain itself. Substrate provides many useful pallets to provide limited access to this sensitive function as well as others like it. In a real-world blockchain you might use the Democracy or Collective pallets. Our blockchain has a very simple governance mechanism called "sudo" which allows a privileged user to call sensitive functions like `system::set_code`. In our case, the privileged user is the `Alice` account, so we will submit the upgrade transaction as her. + +Navigate to the Sudo tab in the interface, and select `system` and `set_code` from the dropdowns. Upload the `node-template-runtime.compact.wasm` file we saw previously, and submit the transaction. + +TODO screenshot + +## Try out the Results + +Once the upgrade transaction is included in a block, you should see a notification in the UI saying that a runtime upgrade has been performed, and the UI will need to be refreshed. Once you've refreshed you can navigate to the "Extrinsics" tab, select "Template Module" from the dropdown, and see that our new extrinsic, `clear_value` is now available. + +Congratulations, you've upgraded your blockchain's runtime! Traditionally the process of upgrading a blockchain would have required a coordinated effort from all (or at least most) of the node operators in the network. But in this case, you have performed the upgrade in a single transaction without even causing a fork!