カウンターのインクリメント

このチュートリアルでは、いくつかの簡単な関数によってカウンターの値をインクリメントする 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 分かかります。

新しいプロジェクトの作成

新しいプロジェクトを作る手順は以下になります:

  1. ローカル PC でターミナルを開きます。

  2. 以下のコマンドを実行し、rust_counter という名前の新しいプロジェクトを作成します。

    dfx new --type=rust rust_counter
  3. 以下のコマンドで、プロジェクトディレクトリに移動します。

    cd rust_counter

デフォルトプロジェクトの変更

Hello World! Rust CDK クイックスタートでは、Rust の Canister を使ったデフォルトのプロジェクトのファイルを確認しました。

このチュートリアルを完了するには、以下の手順を踏みます。

デフォルトの Dapp を置き換え

これで Rust Dapp 用のファイルが揃ったので、lib.rs Dapp を Rust Dapp に置き換えていきます。

既存の Dapp を置き換えるには以下のようにします。

  1. 自分がルートディレクトリにいることを確認します。

  2. src/rust_counter/lib.rs ファイルをテキストエディタで開き、既存の内容を削除します。

    次に、COUNTER 変数の定義と incrementgetset の3つの関数の実装を行っていきます。

  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;
        }
    }
  4. 変更を保存して lib.rs ファイルを閉じ、次に進みます。

インターフェイス記述ファイルの更新

Candid は、Internet Computer で動作する Canister と対話するためのインターフェース記述言語(IDL)です。 Candid ファイルは、Canister が定義する各関数の名前・引数・返し値のフォーマットやデータ型など、Canister のインターフェースを言語に依存しないように記述したものです。

Candid ファイルをプロジェクトに追加することで、Rust で定義されたデータが Internet Computer 上で安全に実行されるために適切に変換されることを保証します。

Candid インターフェース記述言語の構文の詳細は Candid ガイドCandid クレートのドキュメントをご覧ください。

Candid ファイルを更新するには、以下のようにします:

  1. 自分がプロジェクトのルートディレクトリにいることを確認します。

  2. src/rust_counter/rust_counter.did ファイルをテキストエディタで開き、 incrementgetset 関数のために以下の service の定義をコピー&ペーストして書き込んでください。

    service : {
      "increment": () -> ();
      "get": () -> (nat) query;
      "set": (nat) -> ();
    }
  3. 変更を保存して rust_counter.did ファイルを閉じ、次に進んでください。

ローカル Canister 実行環境 を立ち上げる

rust_counter プロジェクトをビルドする前に、ローカル Canister 実行環境 か、Internet Computer メインネットに接続する必要があります。

ローカル Canister 実行環境 を立ち上げるには、以下のようにします:

  1. 自分がプロジェクトのルートディレクトリにいることを確認します。

  2. ローカル Canister 実行環境 をバックグラウンドで立ち上げるために、以下のコマンドを実行します:

    dfx start --background

    プラットフォームやローカルのセキュリティ設定によっては、警告が表示される場合があります。 ネットワーク接続を許可するかどうかの確認画面が表示された場合は、Allow をクリックします。

プロジェクトの登録・ビルド・デプロイ

開発環境で立ち上がっている ローカル Canister 実行環境 に接続した後に、プロジェクトの登録・ビルド・デプロイをローカル環境で行うことができます。

登録・ビルド・デプロイを行うためには、以下のようにします:

  1. プロジェクトのルートディレクトリにいることを確認します。

  2. 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 のテストのために、以下を実行します:

  1. 以下のコマンドで get 関数を呼び、COUNTER 変数の現在の値を取得します;

    dfx canister call rust_counter get

    このコマンドは、COUNTER 変数の現在の値である0を返します。

    (0 : nat)
  2. increment 関数を呼び、COUNTER 変数の値を1つずつインクリメントします:

    dfx canister call rust_counter increment

    このコマンドは変数の値(ステート)をインクリメントしますが、返し値はありません:

  3. get 関数を呼ぶコマンドを再度実行し、COUNTER 変数の現在の値を確認します。

    dfx canister call rust_counter get

    このコマンドは、更新された COUNTER 変数の値である1を返します:

    (1 : nat)
  4. 追加のコマンドを実行して、別の値を使った関数の呼び出しを試してみましょう。

    例えば、以下のようなコマンドを実行して、カウンターの値のセットや取得を試してみましょう:

    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 を返します。

ローカル Canister 実行環境 を止める

アプリケーションのテストをした後は、ローカル Canister 実行環境 がバックグラウンドで稼働し続けないように、以下の手順で停止します:

  1. ネットワークの稼働状況が表示されている端末で、Control-C を押して ローカル Canister 実行環境 を止めてください。

  2. 以下のコマンドを用いて ローカル Canister 実行環境 を停止してください:

    dfx stop