Ontologyを用いたスマートコントラクト開発 vol.1 : Ontologyの概要からトークン発行まで
みなさんこんにちは。LayerX開発部の Sal Mitsuzawa です。イベントで海外プロジェクトの通訳などを担当させていただいたりしています。Ethereum以外のブロックチェーンについての調査や、実際にスマートコントラクトの開発を普段行っているので、何回かに分けてEthereum以外のブロックチェーンプラットフォームについてご紹介していきたいと思います。初回はOntologyという上海をベースにしたプロジェクトをご紹介したいと思います。Vol.1を読んでいただくことで
- Ontologyの特徴は何か?
- Ontologyを利用したローカル環境でのスマートコントラクト開発
- OEP-4 Token (OntologyにおけるERC20)のテストネットへのデプロイ
- Ontology各種開発ツールチェーンの利用法 / エコシステム
- Appendix: Verifiable Random Function / VBFTについて
について触れていただけると考えています。
一通り読むことで、Ontology上で難なくスマートコントラクトを書くことができるようになると思います。
Ontologyとは?
Ontologyは上海を拠点にするブロックチェーンプロジェクトです。2014年に創業されたOnchainという会社のプロジェクトであり、Onchainは同時に別のブロックチェーンプロジェクトであるNEOも立ち上げています。そのような経緯からOntologyの立ち上げ時にNEOのトークンホルダーにOntologyのガバナンストークンであるONTがAirDropされたり、Ontology、NEO両者共に、後述するデュアルトークンモデルを採用していたりと共通点が多く見られます。
共通点は多く見られるものの、現在は別のプラットフォームであり、各国での開発者コミュニティなども別々に活動しています。
Ontologyの特徴は何か?
- OntologyにはコンセンサスアルゴリズムにVBFTを採用しておりブロック生成時間が短い
- ONTとONGのデュアルトークンモデルを採用している
- PythonやGoといったよく知られたプログラミング言語でスマートコントラクトを開発できる
という特徴があります。
Ontologyのトークンモデル
OntologyにはONTとONGの2種類のトークンが存在します。
ONTはステーキングに用いるガバナンストークンで、ONGはスマートコントラクトのデプロイやトランザクションの実行時に支払うGas (ONT GAS = ONG) として用いられます。
トランザクションの実行者はONGをトランザクションフィーとして支払い、トランザクションを実行します。トランザクションの承認者(=マイナー)はブロック生成時に、ブロックに含まれるトランザクションのフィーをブロック生成の報酬として分け合います。
ONTトークンの保持者は、より多くのトランザクションフィーをブロック報酬として受け取ろうと、Ontologyプラットフォームを世の中に広めようとするインセンティブが働きます。
デュアルトークンモデルはNEOのトークンモデルと同じであり、トークンを分けている理由は下記解説に詳しいです。
Clarification on NEO, GAS and Consensus Nodes
設計の意図を簡単に述べると
- ONGはトランザクションの実行に使うものなので、極力価格を安く安定させたい
- ONTトークンを保持することで、Ontology経済圏の発展に連動して得られるONGの量が増えるため、経済圏の発展と価値を連動させたい
となります。
2つの異なる意図を1つのトークンに持たせるとインセンティブが衝突して機能不全に陥る可能性を考慮して、トークンを2つに分けていると言えます。
Ontologyのコンセンサスアルゴリズム
OntologyはVRF(Verifiable Random Function)と呼ばれる関数を用いて、ブロック生成に関与するノードのグループ=Consensus Nodeを選出するVBFTと呼ばれるコンセンサスアルゴリズムを採用しています。選出にVRFではなくトークンホルダーによる投票を用いる方式をDBFT(Delegated Byzantine Fault Tolerance)と呼び、VBFTの採用前はOntologyもDBFTを採用していました。Ontologyの公式ブログのリリースによると
VBFT is a new consensus algorithm that combines PoS, VRF (Verifiable Random Function), and BFT.
という意味でVBFTと命名をしているようです。
Ontology上のスマートコントラクトの開発の話に焦点を当てたいため、VBFTの実際の動き、ブロック報酬の分配に関する特徴に関してはAppendixに譲ることにして、ここではコンセンサスのプロセスを簡単に述べます。
VRFに関して端的に述べると、ランダムな値が生成されていることを誰でも検証できる擬似ランダム関数のことを指します。乱数の生成者は秘密鍵と何らかの関数を用いてランダム値とランダム値を生成した証明のペアを生成し、生成に利用した秘密鍵に対応する公開鍵を用いることで、誰もが正しいプロセスで与えられたランダム値が生成されていることを確認できます。
VRFをノードの選出に用いることでブロック生成に関与するノードを選ぶ際に、選出が公正なプロセスで行われていること、つまり、悪意を持って偏らせることが行われていないことをネットワークの参加者が検証できます。
Ontologyの特徴
開発状況に関してまだ詳しく追えていない部分もありますが、下記も特徴として挙げられます。
- Public / Privateチェーン間の連携をしやすくするという設計思想
- Decentralized ID(DID)を用いた分散的な本人確認システムを利用できる
- Data Exchangeや信用スコアリングの仕組みもプラットフォームで提供する
さて、Ontologyの概要を把握したところで、スマートコントラクトの開発に入ってきましょう。
Ontology上スマートコントラクト開発
Ontology上のスマートコントラクトはPython/C#等、ブロックチェーンに馴染みのないエンジニアでも触れたことのある言語で記述することができます。2018年10月末段階で公式には
サポート中
- C#, VB.Net, F#
- Java, Kotlin
- Python
- C, C++
サポート予定
- Go
- Rust
- JavaScript
と発表されています。以下、Pythonでの実装に関して紹介します。
1. ローカル環境でのスマートコントラクト開発
NOTE: 先日 Ontologyを利用したスマートコントラクト開発ワークショップを行いましたが、ローカルのノードを立てるのに苦慮している方が結構いたので、ローカル環境でうまくいかなかった場合も2.のテストネットへのデプロイへ進んでいただいて構いません
Ontologyでスマートコントラクトを開発するために
- Ontologyのネットワークのノードをローカルに立てる
- ローカル環境でのONT / ONG
- Online IDE SmartX + Hello Worldの実行
を順に紹介させていただきます。
Ontologyのネットワークのノードをローカルに立てる
github.com/ontio/ontologyにアクセスし、Ontologyのノードをインストールします。Releasesからバイナリを落とすと手軽です。
Go言語で書かれているのでREADMEにあるように
go get github.com/ontio/ontology
cd $GOPATH/src/github.com/ontio/ontology
glide install
make all
を実行しても構いません。
バイナリを落とした方はバイナリ自体を
mv BINARY_NAME ontology
とリネームして実行権限を付与してください。
まずは、ローカルのONT/ONGを管理するためのwalletを作成します。
./ontology account add -d # dはdefaultのd
# パスワードの設定を要求される
# 同じディレクトリ内にwallet.datが生成されているのを確認する
下記のようにアカウントが生成されます。
Password:
Re-enter Password:
Index:1
Label:
Address:Ad9HUuTPj3AwJ2y8bn2QFkhsEVLy8J7jZc # アドレス(適当です)
Public key:xxxxxx
Signature scheme:SHA256withECDSA
Create account successfully.
下記コマンドでローカルのノードを立ち上げます
./ontology --testmode --rest --ws --localrpc
ローカル環境でのONT / ONG
下記コマンドでローカル環境のONT/ONG残高を確認します
./ontology asset balance 0
# or
./ontology asset balance Ad9HUuTPj3AwJ2y8bn2QFkhsEVLy8J7jZc
# アドレスでもindexでも指定できます
またHTTPのエンドポイントでも確認することができます
% curl http://localhost:20334/api/v1/balance/Ad9HUuTPj3AwJ2y8bn2QFkhsEVLy8J7jZc | jq .
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 108 100 108 0 0 20003 0 --:--:-- --:--:-- --:--:-- 21600
{
"Action": "getbalance",
"Desc": "SUCCESS",
"Error": 0,
"Result": {
"ont": "1000000000",
"ong": "0"
},
"Version": "1.0.0"
}
アカウントをもう1つ作成して(./ontology account add -dをもう一回実行して)ONTをtransferしてみます
./ontology asset transfer --from 1 --to 2 --amount 1000
残高確認
./ontology asset balance 1
BalanceOf:AG7U5KJFK3vCdtsjYHyEKT3uqGajzULefE
ONT:999999000
ONG:0
./ontology asset balance 2
BalanceOf:AXT1aGcXw65NiUwsdQNunvWJHarWCDA1sZ
ONT:1000
ONG:0
また、ONTではなくONGを転送してみます
./ontology asset unboundong 1 # GASをunboundする *詳しくは述べませんが必要です
./ontology asset withdrawong 1 # パスワード入力
./ontology asset balance 1
BalanceOf:AG7U5KJFK3vCdtsjYHyEKT3uqGajzULefE
ONT:999999000
ONG:52843100./ontology asset balance 2
BalanceOf:AXT1aGcXw65NiUwsdQNunvWJHarWCDA1sZ
ONT:1000
ONG:300000
一旦ここまでで、ONTトークンとONGトークンを2つのアカウントで持つことができました。
小咄: 当初 — asset ongオプションがわからずソースコードを見て判断しました(笑)
Online IDE SmartX + Hello Worldの実行
コマンドラインでコントラクトのバイトコードを生成してもいいのですが、手間がかかるので、EthereumでいうRemixに相当するSmartXというOnline IDEを利用します。
へアクセスするとログイン画面が立ち上がります。ここではONTのWalletをimportするか、Githubでのログインを求められます。
「选择文件」(中国語ですが)と書いてあるフォームの脇のボタンをクリックし、先程生成したwallet.datをimportします(ファイルのアップロードを求められるので、wallet.datを指定して OKを押します。
またMetaMaskに該当するBrowser WalletであるCyano Walletをインストールします。Cyano WalletこちらのリンクからChrome Web Storeに飛ぶことができます。下記のgifの用にCyano Wallet上にアカウントの作成を行います。接続をテストネットに切り替え
作成したアカウントにONGをtransferしておきます
./ontology asset transfer --from 1 --to AH5GpQsGQMnLhJceA8pYVoqe8cw46xV1ga --amount 10000000 --asset ong
Cyano Wallet上に残高がうまく表示されない方は
Cyano WalletのNetwork設定のホストの部分を
127.0.0.1:20336
と明示するといいかもしれません。
これで準備完了です。
SmartXのトップページから Create Project →Python →テンプレートでBlankを指定します。
HelloWorldは下記のコードになります。
from boa.interop.System.Runtime import Log
def Main(operation, args):
if operation == 'Hello': # operationを見てDispatch
msg = args[0]
return Hello(msg)
return False
def Hello(msg):
Notify(msg) # 公式チュートリアルだとここがLog()になっているようですが...
return True
Main関数がOntologyのスマートコントラクトの実行のエントリーポイントになります。第一引数に operationの名前、第二引数にoperationに引き渡す引数がListで入ってくるので、Main関数内でifを書いて分岐します。
コンパイルするとByteCode等が生成されます。Deployのところで必要事項を記入しDeployボタンを押します。Providerが見当たらない的なエラーが出る場合はChromeをReloadしてください。
NOTE: エラーメッセージが中国語で出ますが、google翻訳等を駆使してください😓
残高が充分でないと残高不足のエラーがでてデプロイが失敗するので、その場合はONGを適当な量transferしてください。
デプロイするとContract Hashが決定しSmartX上から実行できるようになります。今回はLogを吐き出す=チェーンに記録をしているのでRunを押すとCyano Wallet が立ち上がり、ONG消費のConfirmationが行われます。
エラーが出る場合:
./ontology --testmode # 他のオプションを外す
ローカルのノードは挙動が不安定になることがあるようなので、ノードを起動し直したりなどして進めてみてください。
実行
SmartXから実行します。
SmartXのログが出力されると思います。ここに表示されるのは16進のバイトコードなので、Toolsのタブを使って出力された文字列を変換します。
これでHello Worldが完了です。
NOTE: ContractHashについて
Contract Hashは実はdeploy前のcompileの段階で生成されています。ソースコードもしくはByteCodeを単純にハッシュ化しただけのものであり、`./ontology asset balance xxx` に指定しても残高を確認することはできません。まだきちんと調査しきってはいませんが、Ethereumでいうpayable的な概念を実現するためには少し遠回りをする必要があるかもしれません。
2.OEP-4 tokenの発行 & テストネットへのデプロイ
さて、ローカルネットでへのデプロイと実行は結構困難が伴ったと思いますが、テストネットへのデプロイはそれほど大変ではありません。
本節では
- テストネット用のONGトークンを入手し
- ERC20のOntology版であるOEP-4トークンのdeploy
- テストネットで動作させる
ここまでを行います。
テストネット用のONGトークンの入手
公式ドキュメントを追っていくと「Discordで問い合わせればもらえる」と書いてありますが、最近ONGトークン配布用のHTTPエンドポイントが公開され
https://developer.ont.io/applyOng/<YOUR_ADDRESS>
を叩くことでテストネットのONGを入手することができます。
curl
で叩いて 200 OK
が返ってくれば成功です。
OEP-4トークンのdeploy
OEP-4トークンはEthereumのERC20のOntology版です。10円玉や100円玉や商店で利用できるポイントのような、独自のトークンを発行したいときに用いられる標準規格です。
基本的なI/FはEthereumと同じです。サンプルコードが下記にGithubに上がっているので開いてSmartXにコピペして、下記の部分をアレンジしてみましょう。
OWNERがトークンの発行者です。このサンプルの実装では、デプロイ後に初期化関数を呼ぶとOWNERのアドレスに全トークンが割り当てられます。
先ほどと同じ様にcompile -> deployをし init関数を実行します。
残高を確認するためにContract Hashをメモします。僕の場合は
31a833ea0b60f1eb13c9949e225abd76d3a66a8d
です。Cyano Walletで残高を確認してみましょう。
無事トークン発行から残高確認まで実施することができました。
試したい方は発行したトークンのtransferも実施してみるといいかもしれません。Cyano Walletで別のアカウントを作成し、上記のようにContract Hashを読み込ませることでことで、Cyano Wallet上で簡単にtransferできます(mnemonicのメモを忘れずに!)
勿論CLI経由でtransferすることもできます。
下記のリンクからOntologyの日本人開発者コミュニティのDiscordに参加することができます。
もし、招待リンクが機能していなかったら
masashi.salvador.mitsuzawa@layerx.co.jp
までご連絡ください。Discordでは、開発者同士の交流、Ontologyの最新情報の共有や、賞金付きハッカソンの情報、Bounty Programの詳細などを流していきます。
3. Ontology各種開発ツールチェーンについて
細かい使用方法は別の回の記事に譲るとして、ここではOntologyが提供しているツールチェインについて紹介します。
Client SDK
WebやiOS / AndroidクライントからOntology上のスマートコントラクトにアクセスするためのSDKです。下記言語で提供され Kotlin SDK / Swift SDKも近日公開されるそうです。
- Golang SDK(https://github.com/ontio/ontology-go-sdk)
- Java SDK(https://github.com/ontio/ontology-java-sdk)
- Python SDK(https://github.com/ontio/ontology-python-sdk)
- TS SDK (Java SDK(https://github.com/ontio/ontology-ts-sdk)
Ontologyブロックチェーンとの基本的なやり取りや、ウォレットファイルの管理、DIDの管理などを行えます。
dAPI
OEP-6という通信プロトコルに則りOntologyのブロックチェーンとインタラクションするための軽量JavaScriptライブラリ。Ethereumでいうweb3的な存在です。
スマートコントラクト向けテスティングフレームワーク
Punica
EthereumでいうTruffle的な立ち位置のプロジェクト: 公式サイト
コントラクトのデプロイや関数の実行SmartXと連動したステップ実行などに対応しているようです。
以上 Ontologyプラットフォームを利用したトークンの作成に関して述べました。Ehtereum上のスマートコントラクトと勝手が違うところも存在しますが、Solidity等の新しい言語を覚えることなく実装できるので、若干スマートコントラクトを身近に感じられるのではないでしょうか?
Ontologyはメインネットのローンチイベントを日本で開催したようで、今後も賞金付きハッカソンの実施、ドキュメントの日本語訳プロジェクト(報酬付き)など企画されているようです。
直近のハッカソンの申込みは下記から行えます。最高のスマートコントラクトを開発して賞金ゲットを目指してみてくださいmm
また。ハッカソン情報や開発者向けの情報を下記Discordで配信します。
興味ある方はご参加ください。
vol.2ではdAPIの使い方やOntology上のNon Fungible Tokenについて話をする予定です。
Appendix A: How VBFT works?
ブロック提出者と承認者を選出する
OntologyはコンセンサスアルゴリズムとしてDBFT、最近ではVerifiable Random Functionを用いたVBFTを採用しています。DBFTはDelegated Byzantine Fault Toleranceの略称です。DBFTのブロック生成には下記の3種類のノードが関与します。
- Consensus Node (7ノード)
- Candidate Node(42ノード)
- Dynamic Participants Node
報酬の配分などの仕組みは下記の公式Mediumの記事に詳しいです。Ontology Announces the Triones Node Incentive Model
また、こちらからノードの一覧を見ることもできます。
masterブランチを見る感じ投票の部分はまだ実装中に見えますが、先日来日したOntologyのエンジニアの方と話した所、Dynamic Participants Nodeはネットワークのメンテナンス(=ブロック生成)に直接関与してないので後回しなっているというようなニュアンスの話をされました。
投票がある場合は、理論的にはDynamic Participants Nodeが投票を行いCandidate NodeとConsensus Nodeどちらかになり得る候補を選び出し、ONTトークンの保有量順に Consensus Node : Candidate Nodeが1:6になるように(全部で49ノードの場合は上位7位までをConsensus Nodeに、それ以外をCandidate Nodeに)なるように選び出します。
現状は投票機能は実装されていないため、下記の方法で選出が行われます。
ONTトークンのステーキング量の多い上位の一定数のノードからVerifiable Random Functionを用いてConsensus Nodeを選出し、Consensus Nodeの中からブロックの提出を行うBlock Proposer、提出されたBlockの検証を行い次のブロックへのvoteを行うConfirmation Node、そしてvote結果を検証するVerification Nodeそれぞれを選出する際に、予測困難な公平なランダム性を発生させるためにVerifiable Random Functionが利用されています。
BlockのProposerはVRFで複数選出され、それぞれ独立してブロックを生成します。同じ様にConfirmation Nodeも同様に複数選出され、Confirmation Nodeはネットワークからブロックを集め新しく提出されたブロックの検証をし、最も優先度の高いブロックを投票で決めます。その後、この投票の結果を別途VRFにより選出されてたVerification Nodeが検証し、ブロック生成が行われます。
Appendix B: Ontologyのブロック報酬の分配における工夫
Ontologyはブロック報酬の分配に工夫をしています。公式ブログに載っている工夫を軽く解説します。DBFT / VBFTを調べる上での個人的な疑問としては
「投票を行うコンセンサスアルゴリズムで、投票者は報酬を受け取ることができるのだろうか?=投票者に投票をするインセンティブはあるのだろうか?」
という点でした。上記ブログに記載されている図にVoterにも報酬配分があることを示す図が載っていたのですが。実際にはvoterへのインセンティブは考慮されていないようです(Ontologyのエンジニアと先日ディスカッションしました)
工夫されている点は下記です
- Consensus NodeとCandidate Nodeで報酬を50:50で分ける
- Consensus NodeとCandidate Nodeの数の比率は 1 : 7
- Stake量が多いとConsensus Nodeになることができるが、Consensus Nodeへの報酬分配の量は、Stake量が多すぎると逆に減少する: 図のような曲線に従います
最後の点に関しては複数アドレスを生成すれば報酬分配量の減少を回避することができてしまいますが、ONTトークンが一極集中しないように寝られていることがわかります 。
Appendix C: Ontologyハマりどころ
ハマりどころ色々あるので解説します。
トランザクション実行時にエラーになるけどログが出ない
loglevelを変更します
./ontology --testmode --networkid 3 --loglevel 0
これで詳細なログが出力されるようになります。
デプロイ成功しているのにコントラクトの関数呼び出しがTimeout
SmartX上のログの表示は少しバグっています。
例えばコントラクトデプロイ時のバグが下記だとします。
2018/10/30 18:49:26 Deploy: {"Action":"Notify","Desc":"SUCCESS","Error":0,"Result":{"TxHash":"94306c15932c0b62cdd1acca3139c6cbebdae4ddbb9c1189263aa9534da47e44","State":1,"GasConsumed":10000000000,"Notify":[{"ContractAddress":"0200000000000000000000000000000000000000","States":["transfer","AVP2tuBG7ZTgGrJyHyaQJh37vgvFuLBEz1","AFmseVrdL9f9oyCzZefL9tG6UbviEH9ugK",10000000000]}]},"Version":"1.0.0"}
Desc: “SUCCESS” となっていますがResultの “State”が1になっています。公式ドキュメントによると
The value of State is 1, indicating that the transaction execution is successful. When the State value is 0, it indicates that the execution failed.
とのことなので、 — loglevel 0などのオプションをつけてノードを立ち上げ、トラブルシューティングをする必要があります。
gaspriceオプション
ローカルのノードの`ontology` コマンドgaspriceとか指定できるoptionあるから、ONGを保持してなくても開発/実行できる?
実際下記のオプションを与えて実行すると gasなしで実行できるように見えますし、ドキュメントにもそんな感じのことが書いてあります
./ontology --disable-tx-pool-pre-exec --rest --ws --localrpc --gaslimit 1 --gasprice 0 --testmode --networkid 3 --loglevel 0
SmartXから実行しようとするとCyano Walletを利用すると思います。Cyano WalletではGas Price=0に指定してトランザクションを実行できないので、 ontologyがトランザクションをハンドリングしている下記のコードで`isBalanceSufficient`のチェックに引っかかりトランザクションを実行できません(故に、デプロイも失敗します)
if tx.GasPrice != 0 {
// 中略
balance, err := isBalanceSufficient(tx.Payer, cache, config, store, gasLimit*tx.GasPrice)
if err != nil {
if err := costInvalidGas(tx.Payer, balance, config, stateBatch, store, notify); err != nil {
return err
}
return err
}
厄介なのが、SmartX上だとこのケースのエラーが「SUCCESS」として表示されることです(pull-req出すか改善要望を送るか考え中)
Appendix D: What is VRF?
公開鍵暗号を用いて乱数生成者が適切な手続きに従ってランダム値を生成することをだれもが検証できるようにした疑似ランダム関数のことです。電子署名の仕組み(commit-reveal)と疑似ランダム関数を組み合わせたような感じになっています。
IETFで仕様が議論されているようなので、実際のやり方などは見ると理解が進みます。長くなりそうなので、こちらは別ブログにまとめます。
AppendixのAppendix(苦労話も含めたあれこれ)
オマケ参照のこと