基本的な依存関係
Dapp デザインのよくあるアプローチは、ある Canister スマートコントラクト(あるいは単に Canister と呼ぶ)でデータを計算または保存し、それを別の Canister で使用するというものです。 たとえ基盤となるスマートコントラクトが異なる言語で書かれていても、異なる Canister のスマートコントラクトで定義された関数を共有して使用できることは、Internet Computer で動作する Dapps を構築する際の重要な戦略となります。 このチュートリアルでは、ある言語(今回の例では Motoko)で関数を書き、そのデータを別の言語(ここではRust)で使用する方法を紹介します。
両方の Canister スマートコントラクトは同じプロジェクトに含まれています。
-
Motoko Canister は オペレーションの結果を保存するための
cell
変数を持つ Actor を作成します。 -
mul
関数は自然数を入力として受け取り、入力値を3倍にして、結果をcell
変数に格納します。 -
Rust Canister は
cell
変数の現在の値を返すシンプルなread
関数を持ちます。呼び出されるメソッドがquery
であっても、Canister 間の呼び出しを行う関数はupdate
メソッドであるべきであることに注意してください。
はじめる前に
プロジェクトをはじめる前に、以下を確認してください:
-
インターネットに接続しており、ローカルの 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 でターミナルを開きます。
-
以下のコマンドを実行し、新しいプロジェクトを作成します。
dfx new --type=rust rust_deps
-
以下のコマンドで、プロジェクトディレクトリに移動します。
cd rust_deps
デフォルトプロジェクトの変更
このチュートリアルを完了するためには、以下の手順を踏む必要があります。
Canister の初期設定の変更
このサンプルプロジェクトは、Motoko Canister と Rust Canister の2つの Canister で構成されているため、デフォルトの dfx.json
設定ファイルを変更し、Motoko Canister と Rust Canister の両方をビルドするための情報を含める必要があります。
dfx.json
を変更するには、以下のようにします:
-
自分がプロジェクトのルートディレクトリにいることを確認します。
-
テキストエディタで
dfx.json
を開きます。 -
canisters.rust_deps
セクションの上に、Motoko プログラムをビルドするための設定を挿入します。例えば、
canisters
セクションの中で、新しいmultiply_deps
キーを以下のように追加します。"multiply_deps": { "main": "src/multiply_deps/main.mo", "type": "motoko" }
-
rust_deps
にdependencies
の設定を追加します。dependencies
の設定では、ある Canister から関数をインポートし、別の Canister で使用することができます。 このチュートリアルでは、Motoko で書かれたmultiply_deps
Canister から関数をインポートし、Rust で書かれたrust_deps
Canister から使用することを考えます。+rust_deps
のフィールドは以下のようになります。"rust_deps": { "candid": "src/rust_deps/rust_deps.did", "package": "rust_deps", "type": "rust", "dependencies": [ "multiply_deps" ] }
-
ファイルから
rust_deps_assets
の設定をすべて削除します。このチュートリアルの Dapp では、フロントエンドの
asset
を使用していないので、設定ファイルからこれらの設定を削除することができます。また、このチュートリアルでは
defaults
とdfx
のキーも削除することができます。これらの不要な設定を削除した後の設定ファイルは次のようになります:
{ "canisters": { "multiply_deps": { "main": "src/multiply_deps/main.mo", "type": "motoko" }, "rust_deps": { "candid": "src/rust_deps/rust_deps.did", "package": "rust_deps", "type": "rust", "dependencies": [ "multiply_deps" ] } }, "networks": { "local": { "bind": "127.0.0.1:8000", "type": "ephemeral" } }, "version": 1 }
-
変更内容を保存し、
dfx.json
ファイルを閉じて次に進みます。
Motoko Canister スマートコントラクトの実装
次のステップでは、src/multiply_deps/main.mo
にファイルを作成して、mul
と read
関数を実装するコードを作成します。
Motoko のソースコードを書くには以下のようにします。
-
Motoko Canister のためのディレクトリを作成します。
mkdir multiply_deps
-
src/multiply_deps/main.mo
ファイルを作成し、テキストエディタで開きます。 -
以下のサンプルコードを
main.mo
ファイル内にコピー&ペーストします。actor Multiply { var cell : Nat = 1; public func mul(n:Nat) : async Nat { cell *= n*3; cell }; public query func read() : async Nat { cell }; }
-
変更を保存してファイルを閉じ、次に進みます。
デフォルトの Rust Canister スマートコントラクトの置き換え
これで Rust Canister が依存する Motoko Canister ができたので、Rust Canister をプロジェクトに追加してみましょう。
デフォルトの Rust Canister を置き換えるには以下のようにします:
-
自分がルートディレクトリにいることを確認します。
-
src/rust_deps/lib.rs
ファイルをテキストエディタで開き、内容を削除します。次のステップは、Motoko Canister をインポートし、
read
関数を実装した Rust プログラムを書くことです。 -
lib.rs
ファイルに以下のコードをコピー&ペーストします:use ic_cdk_macros::*; use ic_cdk::export::candid; #[import(canister = "multiply_deps")] struct CounterCanister; #[update] async fn read() -> candid::Nat { CounterCanister::read().await.0 }
-
src/rust_deps/lib.rs
を保存して閉じ、先に進みます。
インターフェース記述ファイルの更新
Candid は、Internet Computer で動作する Canister と対話するためのインターフェース記述言語(IDL)です。 Candid ファイルは、Canister が定義する各関数の名前・引数・返し値のフォーマットやデータ型など、Canister のインターフェースを言語に依存しないように記述したものです。
Candid ファイルをプロジェクトに追加することで、Rust で定義されたデータが Internet Computer 上で安全に実行されるために適切に変換されることを保証します。
Candid インターフェース記述言語の構文の詳細は Candid ガイドか Candid クレートのドキュメントをご覧ください。
Candid ファイルを更新するには、以下のようにします。
-
自分がプロジェクトのルートディレクトリにいることを確認します。
-
src/rust_deps/rust_deps.did
ファイルをテキストエディタで開きます。 -
read
関数のために、以下のようにservice
を定義します:service : { "read": () -> (nat); }
-
変更を保存して
deps.did
ファイルを閉じ、次に進んでください。
ローカル Canister 実行環境 を立ち上げる
プロジェクトをビルドする前に、ローカル Canister 実行環境 か、Internet Computer メインネットに接続する必要があります。
ローカル Canister 実行環境 を立ち上げるには、以下のようにします:
-
自分がプロジェクトのルートディレクトリにいることを確認します。
-
ローカル Canister 実行環境 をバックグラウンドで立ち上げるために、以下のコマンドを実行します:
dfx start --clean --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 "multiply_deps"... "multiply_deps" canister created with canister id: "rrkah-fqaaa-aaaaa-aaaaq-cai" Creating canister "rust_deps"... "rust_deps" canister created with canister id: "ryjl3-tyaaa-aaaaa-aaaba-cai" Building canisters... Executing: "cargo" "build" "--target" "wasm32-unknown-unknown" "--release" "-p" "rust_deps" ... Finished release [optimized] target(s) in 5.26s Executing: ic-cdk-optimizer -o target/wasm32-unknown-unknown/release/rust_deps.wasm target/wasm32-unknown-unknown/release/rust_deps.wasm 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 multiply_deps, with canister_id rrkah-fqaaa-aaaaa-aaaaq-cai Installing code for canister rust_deps, with canister_id ryjl3-tyaaa-aaaaa-aaaba-cai Deployed canisters.
デプロイした Canister の関数を呼ぶ
Canister のデプロイが成功すると、Canister の関数を呼ぶことでテストできるようになります。
このチュートリアルでは、以下のようにします:
-
mul
関数を呼ぶたびに、cell
変数の値を 3 倍にします。 -
read
関数を呼び出し、cell
変数の現在の値を返します。
デプロイした Canister をテストするために:
-
デプロイした Canister 上の
cell
変数の値を読み取るために Motoko Canister からread
関数を呼び出します。dfx canister call multiply_deps read
このコマンドは、変数
cell
の現在の値である1を返します。(1 : nat)
-
次のコマンドを実行して、入力された引数を3倍する
mul
関数を呼び出します。dfx canister call multiply_deps mul '(3)'
このコマンドは、変数
cell
の新しい値を返します。(9 : nat)
-
multiply_deps
Canister から関数をインポートしているrust_deps
Canister のread
関数を呼び出します。dfx canister call rust_deps read
このコマンドは、変数
cell
の現在の値を返します。(9 : nat)