ICP Rust CDK学習メモ
  • ICP Rust CDK学習メモ
  • ⚙️開発環境準備
  • 開発
    • テンプレート生成 (dfx new)
    • Frontend開発
      • 1. シンプルなHTML
      • 2. Canister呼び出し
    • Backend開発
      • 1. Hello
      • 2. データ更新/参照
      • 3. ic_cdk::caller()
      • 4. ic_cdk::call()
      • 5. 動的画像生成
      • 6. staticファイル参照
      • 7. HTTPS outcalls
      • 8. Threshold ECDSA
    • Bootcamp
      • Calculator ➕✖️➖➗
      • Homework diary 📔
      • Student wall 🎨
      • MotoCoin 🪙
      • The Verifier 👨‍🏫
      • The Dapp 🚀
  • サンプル
    • 📔Diary
  • 技術情報
    • 🪪Principal
    • 🪪Internet Identity
    • 🪙Token
    • 🖼️NFT
    • 🗝️VetKey
  • ツール
    • dfx
      • dfx identity
    • quill
  • 参考情報
    • 🔗リンク集
GitBook提供
このページ内
  • ファイル構成
  • 実行例
  • 解説
  • (1) set()関数
  • (2) get()関数
  • (3) thread_local
  • 課題

役に立ちましたか?

GitHubで編集
  1. 開発
  2. Backend開発

2. データ更新/参照

前へ1. Hello次へ3. ic_cdk::caller()

最終更新 1 年前

役に立ちましたか?

Canisterにデータを保存するにはどうすればよいでしょうか。

RustもICPも初学者の自分にとって、以下の内容は急に難易度が高くなって消化不良に陥ってしまいました。

そこで、まずはユーザ関係なくCanister内にただ一つの文字列を設定/参照するサンプルを考えることにしました。

ファイル構成

任意のディレクトリに以下の4つのファイルは作成します。

Cargo.tomlとsrc/lib.rsはRust関連のファイル、dfx.jsonと canister.did (didファイル名は dfx.json内に記載の と整合性がとれていれば変えても構いません)は ICP Dapp用のファイルです。

  • dfx.json

  • canister.did

  • Cargo.toml

  • src/lib.rs

はじめのうちは各ファイルの関連性がよく分かりませんが、何度かDappサンプルを書いていくうちになんとなく分かってくると思います。

{
  "canisters": {
    "backend": {
      "candid": "./backend.did",
      "package": "icptest",
      "type": "rust"
    }
  },
  "defaults": {
    "build": {
      "args": "",
      "packtool": ""
    }
  },
  "version": 1
}

set()とget()の2つのI/Fを用意することにしました。set()の引数は文字列、get()の戻り値は文字列です。更新を伴わない参照系のget()には query を指定すると良いでしょう。

service : {
    "set": (text) -> ();
    "get": () -> (text) query;
}

cargo new <プロジェクト名> --libで新規作成したものに、[lib]セクションと、[dependencies]セクションを追加したものです。

[package]
name = "icptest"
version = "0.1.0"
edition = "2021"

[lib]
crate-type = ["cdylib"]

[dependencies]
candid = "0.9.3"
ic-cdk = "0.10.0"

私自身、Rust初学者でICP Dapp開発も間もないので、試行錯誤しつつ少しずつ理解しながらという手探り状態ですので最適なプログラムとはいえませんが、以下、作成したプログラムを示します。

use std::cell::RefCell;

thread_local! {
    static VALUE: RefCell<String> = RefCell::default();
}

#[ic_cdk::update]
fn set(text: String) {
    VALUE.with(|value| {
        *value.borrow_mut() = text;
    });
}

#[ic_cdk::query]
fn get() -> String {
    VALUE.with(|value| {
        value.borrow().clone()
    })
}

実行例

解説

(1) set()関数

サンプルプログラム内で定義しているset()関数は、更新系処理となるため、Outer attributeにic_cdk::updateを指定します。

(2) get()関数

サンプルプログラム内で定義したset()関数は、get()関数は、更新系処理となるため、Outer attributeにic_cdk::queryを指定します。

(3) thread_local

Canisterのデータはthread_local内に保持するのがいいようです。以下を参考にするとよいでしょう。

Intro to Building on the IC in Rust

https://youtu.be/163yRgrOSC8?t=461

課題

実は、上記のプログラムを修正して再度CanisterにDeployし直すと、保存していたデータが消えてしまうという課題があります。

これは、一般的なプログラムにおいて、プログラムを再度起動しなおすとプログラム内のメモリが初期化されることと同じようなものとイメージすると分かりやすいかもしれません。そのため、アップデートが行われる前にデータを永続化して、新しいプログラム側で読み直す必要があります。

この課題への対応方法につきましては、別途、改めて説明したいと思います。

https://internetcomputer.org/docs/current/developer-docs/backend/rust/rust-profile
dfx.json
backend.did
Cargo.toml
src/lib.rs