Modify the runtime
In Explore the code, you learned about the manifest files and Rust modules that make up the default node template. Now that you have a general idea of what the runtime source code looks like, let's look at how easy it is for you to make a few simple changes to customize the runtime.
For this simple demonstration, you are going to do the following:
- Add a pallet that has some functionality you want to use.
- Change some constant values.
- Update the runtime version.
- Recompile the runtime to include your changes.
- Submit a transaction to update the runtime stored on-chain.
You'll also see another application that uses the Polkadot-JS API and how you can use the hosted version of that application to view the chain state and submit transactions.
Before you begin
When you run a node in development mode using the --dev
command-line option, it starts in a clean state with the first block.
To best illustrate how to modify and update the runtime, you should restart the default node template with its default runtime so that it starts producing blocks.
To restart the node with the default runtime:
- Open a terminal shell on your computer.
- Change to the root directory where you compiled the Substrate node template.
-
Start the local node in development mode by running the following command:
cargo run --release -- --dev
After you start the node, you can connect to it using a browser-based application built using the Polkadot-JS API.
To connect to the running node:
-
Open the Polkadot/Substrate Portal in a Chrome or a Chromium-based browser.
If you use a more restrictive browser—such as Firefox—you might find that connections between the Polkadot/Substrate Portal and the node are blocked.
-
Connect to the Development network and the default local node endpoint
127.0.0.1:9944
, if necessary.In most cases, the Polkadot/Substrate Portal initializes the connection to the running local node automatically. If required, click Unknown to display the network selection menu, then select Development and Local Node, then click Switch.
-
Notice that under Development, the node template version is the default version 100.
Add a pallet
The most common way to start building with Substrate and FRAME involves adding pallets, either by importing one from the existing library or by creating your own. Creating your own pallet from scratch isn't difficult, but it requires more work designing the application logic, storage requirements, error handling, and so on. To keep things simple, let's add a pallet by importing one from the existing library.
By default, the node template doesn't include the Utility pallet. If this pallet contains functions you want to use, you can add it to the default runtime.
To add the Utility pallet:
- Open a second terminal shell on your computer and change to the node template root directory.
- Open the runtime manifest—
runtime/Cargo.toml
in your code editor. -
Locate the
[dependencies]
section and add the Utility pallet as a dependency.For example, you should add a single line similar to the following.
pallet-utility = { version = "4.0.0-dev", default-features = false, git = "https://github.com/paritytech/polkadot-sdk.git", branch = "polkadot-vX.Y.Z" }
Be sure to replace
branch = "polkadot-vX.Y.Z"
with the Polkadot branch used for other pallets.You can copy any existing pallet dependency as a model to ensure that the branch setting for the
pallet-utility
dependency is the same as the branch setting for all other pallets. -
Locate the
[features]
section and add the Utility pallet to the list of default features for the standard binary.For example:
[features] default = ["std"] std = [ ... "pallet-utility/std", ... ]
You'll learn more about building features for the standard and WebAssembly binaries in Rust and WebAssembly.
- Save your changes and close the
Cargo.toml
file. - Open the
runtime/src/lib.rs
file in your code editor. -
Add the implementation for the
Config
trait for the Utility pallet.For example:
impl pallet_utility::Config for Runtime { type RuntimeEvent = RuntimeEvent; type RuntimeCall = RuntimeCall; type PalletsOrigin = OriginCaller; type WeightInfo = pallet_utility::weights::SubstrateWeight<Runtime>; }
Every pallet has a
Config
trait for the specific parameters and types it requires. You can always look at the Rust documentation for a pallet to learn more about its configuration requirements. For example, you can view the Rust documentation for the pallet-utility. -
Add the Utility pallet inside the
construct_runtime!
macro.For example:
construct_runtime!( pub struct Runtime where Block = Block, NodeBlock = opaque::Block, UncheckedExtrinsic = UncheckedExtrinsic { System: frame_system, RandomnessCollectiveFlip: pallet_randomness_collective_flip, Timestamp: pallet_timestamp, Aura: pallet_aura, ... Utility: pallet_utility, // Add this line ... }
You can learn more about how the
construct_runtime
macro works in FRAME macros and Runtime construction macros.
Change constant values
By default, the Balances pallet in the node template defines an EXISTENTIAL_DEPOSIT
constant.
The EXISTENTIAL_DEPOSIT
represents the minimum balance that an account must have to be considered a valid active account.
By default, the constant is defined as a 128-bit unsigned integer type with a value of 500.
To keep things simple, you're going to change the value of this constant from 500 to 1000.
To update a constant value:
- Open the
runtime/src/lib.rs
file in your code editor. -
Locate the
EXISTENTIAL_DEPOSIT
for the Balances pallet./// Existential deposit. pub const EXISTENTIAL_DEPOSIT: u128 = 500;
-
Update the value for the EXISTENTIAL_DEPOSIT.
pub const EXISTENTIAL_DEPOSIT: u128 = 1000 // Update this value.
Update the runtime version
By default, the node template identifies the default runtime version in the VERSION
constant using the spec_version
and a value of 100.
To indicate that you've made changes to the default runtime, you're going to change the spec_version
from 100 to 101.
Note that updating the spec_version
isn't strictly required for the changes you've made to the default runtime in the Quick start.
However, by updating the version you can see the basic steps involved in performing a forkless upgrade.
To update the runtime version:
- Open the
runtime/src/lib.rs
file in your code editor. -
Locate the
runtime_version
macro.#[sp_version::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: 100, impl_version: 1, apis: RUNTIME_API_VERSIONS, transaction_version: 1, state_version: 1, };
-
Update the
spec_version
to specify the new runtime version.spec_version: 101, // Change the spec_version from 100 to 101
- Save your changes and close the
runtime/src/lib.rs
file.
At this point, you've modified the runtime code and changed the version information. However, the running node is still using the previously-compiled version of the runtime. If you are still connected to the running node using the Polkadot/Substrate Portal, you can see the node template version is still the default version 100 and the chain state for the balances constant existentialDeposit is still 500.
Recompile the runtime
Before you can update the node template to use your modified runtime, you must recompile the runtime.
To recompile the runtime package:
- Open a second terminal shell and change to the root directory where you compiled the node template.
-
Recompile the runtime by running the following command:
cargo build --release --package node-template-runtime
The
--release
command-line option requires a longer compile time. However, it generates a smaller build artifact that is better suited for submitting to the blockchain network. Storage optimization is critical for any blockchain. With this command, the build artifacts are output to thetarget/release
directory. The WebAssembly build artifacts are in thetarget/release/wbuild/node-template-runtime
directory. For example, if you list the contents of thetarget/release/wbuild/node-template-runtime
directory, you should see the following WebAssembly artifacts:node_template_runtime.compact.compressed.wasm node_template_runtime.compact.wasm node_template_runtime.wasm
Submit a transaction
You now have an updated WebAssembly object that describes the modified runtime. However, the running node isn't using the upgraded runtime yet. To update the runtime stored on-chain, you must submit a transaction that changes the WebAssembly object to use.
To update the runtime:
- In the Polkadot/Substrate Portal, click Developer and select Extrinsics.
- Select the administrative Alice account.
- Select the sudo pallet and the sudoUncheckedWeight(call, weight) function.
- Select system and setCode(code) as the call to make using the Alice account.
-
Click file upload, then select or drag and drop the compact and compressed WebAssembly file—
node_template_runtime.compact.compressed.wasm
—that you generated for the updated runtime.For example, navigate to the
target/release/wbuild/node-template-runtime
directory and selectnode_template_runtime.compact.compressed.wasm
as the file to upload. -
Leave both of the weight parameters set to the default value of
0
. - Click Submit Transaction.
- Review the authorization, then click Sign and Submit.
Verify the modified runtime
After the transaction is included in a block, you can verify that you're using the modified runtime.
To verify your changes:
-
In the Polkadot/Substrate Portal, click Network and select Explorer to see that there has been a successful
sudo.Sudid
event. -
Check that the node template version is now
101
.For example:
- Click Developer and select Extrinsics.
-
Click submit the following extrinsic and scroll to the bottom of the list to verify that the utility pallet is available as an option.
- Click Developer , select Chain state, then click Constants.
-
Select the balances pallet, select existentialDeposit, then click + to query the constant value.
Where to go next
After verifying the changes, you know that you have a customized version of the node template running and have successfully upgraded your local node to use your modified runtime.
That's quite an achievement, but there's a lot more you can do. To dig deeper into concepts and core components, review topics in the Learn section or start building on what you've learned so far by exploring topics in the Build section.