Introduction to working with Rust
Rust is a powerful and type sound modern programming language with an active developer community. Because Rust compiles to WebAssembly, it offers a rich development environment for writing dapps to run on the Internet Computer blockchain. To help pave the way for writing dapps in Rust that can be deployed on the Internet Computer blockchain, {company-id} provides some tools to simplify the process.
Collectively, these tools are referred to as the DFINITY Canister Development Kit (CDK) for Rust and consist of the following main libraries:
Package | Description |
---|---|
ic-types | The ic-types crate defines the types used to communicate with the decentralized Internet Computer blockchain, and when building dapps to be deployed as canisters on the Internet Computer blockchain. |
ic-agent | The ic-agent library enables direct communication with the Internet Computer blockchain. |
ic-utils | The ic-utils library provides utilities for managing calls and dapps deployed as canisters. |
ic-cdk | The ic-cdk provides the core methods that enable Rust programs to interact with the Internet Computer blockchain system API. This library serves as the runtime core of the Rust CDK. |
ic-cdk-macros | The ic-cdk-macros library defines the procedural macros that facilitate building operation endpoints and APIs. This library includes macros for update , query , import and other important operations. |
ic-cdk-optimizer | The ic-cdk-optimizer is a helper library used to reduce the size of WebAssembly modules. |
The following diagram provides a simplified view of the Rust Canister Development Kit (CDK) building blocks from the lowest to highest level of abstraction.
Using Rust without SDK
You can create Rust projects to run on the IC by using Cargo and compiling your dapp to use WebAssembly as the target output.
This section provides a detailed summary of the key steps involved in deploying a Rust program as a canister on the IC. You should note, however, that the steps described here only illustrate one approach. Other implementation approaches are also possible.
Note that the Rust canister development kit (Rust CDK) provides some shortcuts to make it easier to write functions as query and update calls and includes several examples to get you started building Rust-based projects, but you can also develop dapps for the IC without using the Rust CDK. Also, it is much easier to use dfx
instead of setting up the project from scratch. See the Rust Quickstart for a much simpler walkthrough.
Create a project
Because most Rust programmers use Cargo to handle build and package management tasks, such as downloading and compiling the libraries your dapp depends on, your first step is to create a new Rust project using the Cargo command-line interface.
Alternatively, you could create a new project using SDK instead of Cargo, but creating a project using Cargo represents the typical workflow for creating Rust projects.
To create a new Rust project:
Open a terminal shell on your local computer, if you don’t already have one open.
Verify that you have Cargo installed by running the following command:
cargo --version
Change to the folder you are using for your IC or Rust sample projects.
Create a new project by running a command similar to the following:
cargo new my_rust_dapp
This command creates a new
my_rust_dapp
directory with a defaultCargo.toml
file and asrc
directory with a defaultmain.rs
file.Change to your project directory by running the following command:
cd my_rust_dapp
If you list the contents of this directory, you’ll see that it only contains the
Cargo.toml
file andsrc
directory. To compile this project to run on the IC, you’ll need some additional files.
Modify the Cargo configuration file
The Cargo.toml
file provides a manifest for each Rust package. The manifest contains sections that specify configuration details for the package. To prepare the Rust project to run on the IC, we’ll copy the default Cargo.toml
file then modify some of the configuration details for the project.
To modify the Cargo.toml
file:
Check that you are in the root directory for your project by running the
pwd
command, if necessary.Copy the default
Cargo.toml
file to thesrc
directory by running the following command:cp Cargo.toml src/Cargo.toml
Projects that run on the IC typically use one project-level
Cargo.toml
file to set up a workspace for the canister members of the project and a secondCargo.toml
file in the source code directory to configure settings for each canister.Open the
Cargo.toml
file that is the root directory of your project in a text editor.By default, the file contains the
[package]
and the[dependencies]
sections.Replace the
[package]
section with a[workspace]
section similar to the following:[workspace]
members = [
"src/my_rust_dapp",
]For information about the
[workspace]
section and[workspace]
keys, see Workspaces. For information about the other sections and keys you can configure in theCargo.toml
file, see The Manifest Format.Remove the
[dependencies]
section.Save your changes and close the file to continue.
Open the
src/Cargo.toml
file in a text editor.Add a
[lib]
section with the path to the main source code similar to the following:[lib]
path = "main.rs"Update the
[dependencies]
section with any package dependencies.Save your changes and close the file to continue.
Add a canister configuration file
When you create a new project using the SDK, the dfx new
command automatically adds a default dfx.json
configuration file to the project directory. Because we created the Rust project using Cargo, you need to manually create this file in your project directory.
To add the dfx.json
configuration file:
Check that you are still in your project directory by running the
pwd
command, if necessary.Create a new
dfx.json
configuration file in the root directory for your project.Open the
dfx.json
file in a text editor.Add the
version
andcanisters
keys with settings similar to the following to thedfx.json
file:{
"version": 1,
"canisters": {
"my_rust_dapp": {
"type": "custom",
"candid": "src/my_rust_dapp.did",
"wasm": "target/wasm32-unknown-unknown/debug/my_rust_dapp.wasm",
"build": "cargo build --target wasm32-unknown-unknown --package my_rust_dapp"
}
}
}Let’s take a closer look at these settings.
The
version
setting is used to identify the version of the software used to create the project.The
canisters
section specifies the name of the project’s canisters. In this case, there’s only one canister and it is namedmy_rust_dapp
.The
type
key is set tocustom
because this canister is not one of the currently recognized (motoko
orassets
) canister types.The
candid
key specifies the name and location of the Candid interface description file to use for this project.The
wasm
key specifies the path to the WebAssembly file generated by thecargo build
command.The
build
key specifies thecargo
command used to compile the output.
These are the minimum settings required. As you build more complex programs, you might need to include additional configuration details in the
Cargo.toml
file, thedfx.json
file, or both files.Save your changes and close the file to continue.
Create a Candid interface description file
In addition to the dfx.json
configuration file, you need to have a Candid interface description file—for example, my_rust_dapp.did
—to map your dapp’s input parameters and return value formats to their language-agnostic representation in Candid.
To add the Candid interface description file:
Check that you are still in your project directory by running the
pwd
command, if necessary.Create a new Candid interface description file—for example,
my_rust_dapp.did
—in thesrc
directory for your project.Open the Candid interface description file in a text editor and add a description for each function the dapp defines.
For example, if the
my_rust_dapp
is a simple dapp that increments a counter using theincrement
,read
, andwrite
functions, themy_rust_dapp.did
file might look like this:service : {
"increment": () -> ();
"read": () -> (nat) query;
"write": (nat) -> ();
}Save your changes and close the file to continue.
Modify the default dapp
When you create a new project, your project src
directory includes a template main.rs
file with the "Hello, World!" program.
To modify the template source code:
Open the template
src/main.rs
file in a text editor and delete the existing content.Write the program you want to deploy on the IC.
As you write your program, keep in mind that there are two types of calls—update calls and query calls—and that update functions use asynchronous messaging.
Save your changes and close the
main.rs
file.
Deploy the dapp
Before you can deploy and test your dapp, you need to do the following:
Connect to either the local canister execution environment, or to the IC blockchain mainnet.
Register a network-specific identifier for the application.
Compile the dapp with a target output of WebAssembly.
Because you configured the custom dfx.json
file with a cargo build
command that compiles to WebAssembly, you can use the dfx
command-line interface and standard work flow to perform all of the remaining steps.
To build and deploy the dapp locally:
Check that you are still in your project directory by running the
pwd
command, if necessary.Open a new terminal window or tab on your local computer and navigate to your project directory.
For example, you can do either of the following if running Terminal on macOS:
Click Shell, then select New Tab to open a new terminal in your current working directory.
Click Shell and select New Window, then run
cd ~/ic-projects/location_hello
in the new terminal if yourlocation_hello
project is in theic-projects
working folder.
You should now have two terminals open with your project directory as your current working directory**.
Start the local canister execution environment by running the following command:
dfx start
Depending on your platform and local security settings, you might see a warning displayed. If you are prompted to allow or deny incoming network connections, click Allow.
Leave the terminal that displays network operations open and switch your focus to your original terminal where you created your project.
Register a unique canister identifier for the application by running the following command:
dfx canister create --all
Build the dapp by running the following command:
dfx build
Deploy the dapp on the local canister execution environment by running the following command:
dfx canister install --all
Test functions in the dapp from the command-line or in a browser.