カウンターのインクリメント
このチュートリアルでは、いくつかの簡単な関数によってカウンターの値をインクリメントする Dapp を作り、値の永続性について説明します。
この Dapp は、カウンターの値(自然数)を格納する可変型変数として、 COUNTER
を宣言しています。
ここで以下の関数を考えます:
-
increment
: 現在の値を更新する関数です。値を1ずつ増加させ、戻り値はありません。 -
get
: カウンターの現在の値を返すシンプルなクエリ関数です。 -
set
: 引数で指定した数値にカウンターの値を更新する関数です。
このチュートリアルでは、Canister スマートコントラクトにデプロイされた Canister の関数を呼び出して、カウンターの値をインクリメントする簡単な例を示します。 値を増加させる関数を複数回呼び出すことで、呼び出しの間に変数の値が変わらないこと(値の永続性)を確認できます。
他のサンプル Dapps と同じように、このチュートリアルはシンプルでありながら現実的なワークフローのデモンストレーションとなっています:
-
新しいプロジェクトを作成します。
-
WebAssembly モジュールにコンパイルされる Dapp を書きます。
-
ローカル Canister 実行環境 に Canister をデプロイします。
-
Canister スマートコントラクトのメソッドを呼び出して、カウンターの値をインクリメントしたり読んだりします。
はじめる前に
プロジェクトをはじめる前に、以下を確認します:
-
インターネットに接続しており、ローカルの macOS または Linux コンピュータでターミナルにアクセスできること。
-
Rust のインストール方法 にあるように、Rust プログラミング言語と Cargo が OS にダウンロードされ、インストールされていること。
curl --proto '=https' --tlsv1.2 https://sh.rustup.rs -sSf | sh
Rust のバージョンは 1.46.0 より新しい必要があります。
-
ダウンロードとインストールの説明に従って、DFINITY Canister Software Development Kit (SDK) パッケージのダウンロードとインストールが済んでいること。
-
cmake
のインストールが済んでいること。例えば、macOS では Homebrew を使って以下のコマンドを実行します:brew install cmake
Homebrew をインストールする方法については、Homebrew のドキュメントを参照してください。
-
コンピュータ上の ローカル Canister 実行環境 プロセスが停止していること。
ローカルコンピュータ上で新たなターミナルを開く方法や、ターミナルでコマンドを実行する方法や、インストールパッケージを確認する方法がわからない場合には、初めての人のための準備を参照してください。 既に必要な前提条件を満たしている場合には、新しいプロジェクトの作成 へと進んでください。
このチュートリアルは、完走に約 20 分かかります。
新しいプロジェクトの作成
新しいプロジェクトを作る手順は以下になります:
-
ローカル PC でターミナルを開きます。
-
以下のコマンドを実行し、
rust_counter
という名前の新しいプロジェクトを作成します。dfx new --type=rust rust_counter
-
以下のコマンドで、プロジェクトディレクトリに移動します。
cd rust_counter
デフォルトプロジェクトの変更
Hello World! Rust CDK クイックスタートでは、Rust の Canister を使ったデフォルトのプロジェクトのファイルを確認しました。
このチュートリアルを完了するには、以下の手順を踏みます。
デフォルトの Dapp を置き換え
これで Rust Dapp 用のファイルが揃ったので、lib.rs
Dapp を Rust Dapp に置き換えていきます。
既存の Dapp を置き換えるには以下のようにします。
-
自分がルートディレクトリにいることを確認します。
-
src/rust_counter/lib.rs
ファイルをテキストエディタで開き、既存の内容を削除します。次に、
COUNTER
変数の定義とincrement
・get
・set
の3つの関数の実装を行っていきます。 -
下のサンプルコードを
lib.rs
にコピー&ペーストしてください。use ic_cdk_macros::*; use ic_cdk::export::candid; static mut COUNTER: Option<candid::Nat> = None; #[init] fn init() { unsafe { COUNTER = Some(candid::Nat::from(0)); } } #[update] fn increment() -> () { unsafe { COUNTER.as_mut().unwrap().0 += 1u64; } } #[query] fn get() -> candid::Nat { unsafe { COUNTER.as_mut().unwrap().clone() } } #[update] fn set(input: candid::Nat) -> () { unsafe { COUNTER.as_mut().unwrap().0 = input.0; } }
-
変更を保存して
lib.rs
ファイルを閉じ、次に進みます。
インターフェイス記述ファイルの更新
Candid は、Internet Computer で動作する Canister と対話するためのインターフェース記述言語(IDL)です。 Candid ファイルは、Canister が定義する各関数の名前・引数・返し値のフォーマットやデータ型など、Canister のインターフェースを言語に依存しないように記述したものです。
Candid ファイルをプロジェクトに追加することで、Rust で定義されたデータが Internet Computer 上で安全に実行されるために適切に変換されることを保証します。
Candid インターフェース記述言語の構文の詳細は Candid ガイドか Candid クレートのドキュメントをご覧ください。
Candid ファイルを更新するには、以下のようにします:
-
自分がプロジェクトのルートディレクトリにいることを確認します。
-
src/rust_counter/rust_counter.did
ファイルをテキストエディタで開き、increment
・get
・set
関数のために以下のservice
の定義をコピー&ペーストして書き込んでください。service : { "increment": () -> (); "get": () -> (nat) query; "set": (nat) -> (); }
-
変更を保存して
rust_counter.did
ファイルを閉じ、次に進んでください。
ローカル Canister 実行環境 を立ち上げる
rust_counter
プロジェクトをビルドする前に、ローカル Canister 実行環境 か、Internet Computer メインネットに接続する必要があります。
ローカル Canister 実行環境 を立ち上げるには、以下のようにします:
-
自分がプロジェクトのルートディレクトリにいることを確認します。
-
ローカル Canister 実行環境 をバックグラウンドで立ち上げるために、以下のコマンドを実行します:
dfx start --background
プラットフォームやローカルのセキュリティ設定によっては、警告が表示される場合があります。 ネットワーク接続を許可するかどうかの確認画面が表示された場合は、Allow をクリックします。
プロジェクトの登録・ビルド・デプロイ
開発環境で立ち上がっている ローカル Canister 実行環境 に接続した後に、プロジェクトの登録・ビルド・デプロイをローカル環境で行うことができます。
登録・ビルド・デプロイを行うためには、以下のようにします:
-
プロジェクトのルートディレクトリにいることを確認します。
-
dfx.json
に指定されている Canister を以下のコマンドで、登録・ビルド・デプロイします:dfx deploy
dfx deploy
コマンドを実行すると、以下のような実行結果に関しての情報が表示されます。Creating a wallet canister on the local network. The wallet canister on the "local" network for user "default" is "rwlgt-iiaaa-aaaaa-aaaaa-cai" Deploying all canisters. Creating canisters... Creating canister "rust_counter"... "rust_counter" canister created with canister id: "rrkah-fqaaa-aaaaa-aaaaq-cai" Creating canister "rust_counter_assets"... "rust_counter_assets" canister created with canister id: "ryjl3-tyaaa-aaaaa-aaaba-cai" Building canisters... Executing: "cargo" "build" "--target" "wasm32-unknown-unknown" "--release" "-p" "rust_counter" ... Finished release [optimized] target(s) in 53.36s Building frontend... Installing canisters... Creating UI canister on the local network. The UI canister on the "local" network is "r7inp-6aaaa-aaaaa-aaabq-cai" Installing code for canister rust_counter, with canister_id rrkah-fqaaa-aaaaa-aaaaq-cai ... Deployed canisters.
関数を読んで Dapp をテストする
Canister のデプロイに成功したら、Canister の関数を呼び出すことでテストすることができます。 このチュートリアルでは、以下をテストします。
-
get
関数を呼び、カウンターの値をクエリする。 -
increment
関数を呼び、呼ぶたびにカウンターの値をインクリメントする。 -
set
関数を呼び、引数として与えた任意の値でカウンターの値をアップデートする。
Dapp のテストのために、以下を実行します:
-
以下のコマンドで
get
関数を呼び、COUNTER
変数の現在の値を取得します;dfx canister call rust_counter get
このコマンドは、
COUNTER
変数の現在の値である0を返します。(0 : nat)
-
increment
関数を呼び、COUNTER
変数の値を1つずつインクリメントします:dfx canister call rust_counter increment
このコマンドは変数の値(ステート)をインクリメントしますが、返し値はありません:
-
get
関数を呼ぶコマンドを再度実行し、COUNTER
変数の現在の値を確認します。dfx canister call rust_counter get
このコマンドは、更新された
COUNTER
変数の値である1を返します:(1 : nat)
-
追加のコマンドを実行して、別の値を使った関数の呼び出しを試してみましょう。
例えば、以下のようなコマンドを実行して、カウンターの値のセットや取得を試してみましょう:
dfx canister call rust_counter set '(987)' dfx canister call rust_counter get
このコマンドは、現在の値である 987 を返します。
dfx canister call rust_counter increment dfx canister call rust_counter get
このコマンドは、インクリメントされた値である 988 を返します。