最近、Flowを勉強してCadenceを触っているので、そのメモとして、FlowとCadenceの概要について整理。
BitcointやEthereumのようなブロックチェーンの1つ
ブロックチェーンの専門家ではなく、一般人に向けて開発されている
デジタルアイテムの「所有」を実現したいというモチベーションで開発がスタートした
リソース指向の言語で開発できる
4種類のノードが存在する
Collection, Consensus, Execution, Verification
マシンスペックに応じて、4種類の役割を分担することで、効率的な処理を実現している
Etherium は1種類のノードで全ての役割を担っている
エンドユーザーが使うアプリケーションからのアクセスは最初に Access Node が受け、その後、4種類のノードにトランザクションが送られる仕組み
概要を知れるTED Talk
Flowを扱うためのプログラミング言語
強力な静的型付け言語
リソース指向プログラミング
リソースが一度に一箇所にしか存在できない、コピーできない、削除されない、といった特徴がある
これによってデジタルの所有権をモデリングしやすくなっている - 関数とトランザクションの前後条件
関数とトランザクションの前後に条件を記述して、テストができる
更新可能
最小権限の原則
アセット:ブロックチェーンを使って所有権を主張したいモノそのもの。
アカウント:ユーザーが持っているコントラクトとストレージ。通常はウォレットに格納して利用する。
コントラクト:リソースやインターフェース、関数を定義したプログラム。アカウントにデプロイすることで利用できる。
リソース:独自に定義されたフィールドと関数を持つ複合型のプログラム。
トランザクション/スクリプト:コントラクトのリソースや関数を使って、オンチェーンで取引や参照などのロジックを実行するプログラム。
Capability:アカウントストレージにアクセスするためのリファレンス。
公式解説ページ:
アカウントとは、Flow ブロックチェーンを扱う上での個人個人が管理する対象のこと
Flow では秘密鍵を複数持てる(multi sig)
Flow ではアカウント内に2つの領域がある
コントラクト領域
スマートコントラクトのプログラムを格納する領域
アカウントの所有者はここにコントラクトをデプロイし、管理する
トランザクションやスクリプトはこの領域には直接アクセスできない(ストレージを経由してコントラクトを利用することになる)
他のコントラクトからコントラクトを利用するためには専用のインターフェースを定義する必要がある
ファイルシステム領域
アカウントが所有するオブジェクトと capability(実行可能な関数へのリファレンス)を格納する領域
トランザクションやスクリプトからアクセスできる
どのアカウントもファイルシステムの root には storage
private
public
という3つのドメインだけが存在する
storage
: 全てのオブジェクト(token や NFT など)を保存する。アカウントの所有者のみがアクセスできる
private
: storage に保存したオブジェクトへの capability を保存する。アカウントの所有者とアクセス権を持っている人だけがアクセスできる
public
: ネットワーク内の誰もがアカウントの情報を参照できるような capability を保存する
公式解説ページ:
コントラクトはアカウントのオーナーが追加、更新、削除できるコード
変数、関数、リソース、インターフェース、Capability などを定義する
コントラクトのサンプル:
pub contract HelloWorld {
pub let greeting: String // 変数定義
pub fun hello(): String { // 関数定義
return self.greeting
}
init() { // 初期化処理
self.greeting = "Hello World!"
}
}
各アカウントのコントラクトは、トランザクションや他のアカウントから import
することによって利用できる。
ただし変数や関数にはアクセス制御がされている
pub/access(all)
は誰でも利用可能
access(account)
はコントラクトの作成者のみ利用可能
access(contract)
はそのコントラクト内でのみ利用可能
priv/access(self)
は現在のスコープ以下のみ利用可能
pub/access(all)
> access(account)
> access(contract)
> priv/access(self)
の順にスコープが狭くなる
詳細は https://developers.flow.com/cadence/language/access-control を参照
init()関数はデプロイ時のみ稼働する。デプロイ後はデプロイしたアカウントであっても利用できない
import HelloWorld from 0x02
log(HelloWorld.hello()) // prints "Hello World!"
log(HelloWorld.greeting) // prints "Hello World!"
HelloWorld.init() // Error
公式解説ページ:
リソースとは、データと関数の集まりであり、構造体や Class に似ている cadence 独自の考え方。
構造体や Class との違いはコピーができない点
リソースは以下のルールに従うよう作られている
1つの場所にだけ存在できる(コピーして同時に複数の場所に存在することはできない)
リソースは取り出された時、確実にある場所から他の場所への移動しなければならない
リソースはスコープの外側には移動できず、そのスコープ内で最後にはどこかに保存するか、破壊するかを明示しなければならない
上記ルールに従うことで、コーディングミスによるリソースの紛失やリソースのコピーを防ぎ、所有権の主張ができる状態を生み出している
インスタンス化したリソースは、アカウントのストレージに保存し、リソースの所有権をアカウントに直接結びつけている
トランザクションが稼働するマシンのストレージを使わないため、アカウント間で自由にリソースを転送できる
公式解説ページ:
トランザクションとしてオンチェーンで実行させたいプログラム
データの変更が伴う処理に利用され、そのためにはそのデータの更新権限を取得する必要がある
データの更新権限を取得するには、トランザクションのプログラムに対して対象データを保存しているアカウントが秘密鍵で署名する必要がある
署名したアカウントは Authorizers や Signers と呼ばれる
例えば アカウント A と アカウント B で NFT の所有者を変更したい時には、アカウント A と B でトランザクションを承認(sign)することになる
トランザクション実行にはガス代がかかる
トランザクションコードの例:
import HelloWorld from 0x01
transaction {
prepare(acct: AuthAccount) {}
execute {
log(HelloWorld.hello())
log(HelloWorld.greeting)
}
}
トランザクションとは異なり、データの変更が発生しない、情報を参照するだけの処理のことを指す
そのため、署名のプロセスは発生しない
ガス代はかからない
スマートコントラクトを実装する
実装
エミュレータ環境でテスト
テストネット環境にデプロイして動作確認
メインネット環境にデプロイして動作確認
フロントエンド/バックエンドを実装する
スマートコントラクトを実際に書いて試せる Palyground を Flow 公式が用意している
Flow のテストネット
エミュレータ、テストネット、メインネットでの開発に使えるコマンド
flow emulator
でエミュレータを起動したり
flow deply
でコントラクトをデプロイしたり
といった使い方ができる
cadence で書かれた NFT マーケットプレイスのサンプルプロジェクト
NBA Top Shot のコントラクトの実装