Ontlogyでのスマートコントラクト開発 (1) : 概観とLocalでのOnline IDE (SmartX)を利用した開発
目的
Ontologyを利用してスマートコントラクトを開発できるように道を引く
まとめ
まだ発展途上なのでハマりどころは多い
実は公式ドキュメント+公式ブログに過不足なく情報がある
が、散ってるので非常にとっつきずらい
Ethereumってその点でもすごいなと
テストネットのONGのもらい方とかむずいw
しかももらえない... orz
ベストプラクティス
ローカルネットを立ち上げて、ONGトークンをローカルで適当に生成してコントラクトをデプロイ
Compile & deployはSmartXを利用
コントラクトの関数のお試し実行はSmartXだと出来ない(バグがある)
コマンドで実行したほうがいい
ライブラリのインストールの仕方なども未整備
色々な言語で開発できるが、SmartXが対応しているのはPythonとC#のみ
Pythonも補完が効いたりするわけではない
Truffle的なのがないので、SmartXを使わないと若干面倒そうではある
トークンモデル
(2)以降でやること
OEP-4の開発
ライブラリのインストール方法、ディレクトリ構造のハンドリング
web3に該当するライブラリの利用法
Goでコントラクトを書いてみる
C#でコントラクトを書いてみる
テストネットへのデプロイ
開発ドキュメントに則ってOntology上のスマートコントラクトを開発する
開発ドキュメント:
Ontology上のスマートコントラクトとは?
https://gyazo.com/ee461a53da47c610d5cb30973d2318c3
上図によるとNEOとVMが同じなことが分かる(ので、恐らくNEO上で動くコントラクトはOntology上でも動作する)
逆はどうかと言うとNative Contract(機械語に近いものを書くのか?)というものがあり、VMを利用しないのでこちらは恐らくNEO上では動作しない。ONG(GAS)について調べるついでに出てきたので追記すると、Native ContractはOntologyのチェーンに予め埋め込まれているONGの割り当てルール / ONTを送信した時にsenderとreceiverを判別してONGを割り当てるgovernance contractなどのことを指すようだ。これらは予め組み込まれているので "Native" Contractと呼ばれるのだろう。
https://gyazo.com/b383c808db8042367ed0accbf7dc4116
The Native contract is a contract written directly on the underlying level of Ontology. It has high execution efficiency and is greatly optimized for common contracts. Its services include Oracle, DID, and rights management, and data exchanges will be implemented by Native contracts
NeoVM Contactは C#やPythonで記述できる。基本的に始めにあつかうのはNeoVM Contractだろう。
使うVMをSmart Contract Dispatch Centerで判別して実際にどこで実行するかDispatchするようだ。WasmVMという名前が図の上では出てくるが、詳しい説明は特にない。
https://gyazo.com/a25f5ceb52aa87213dcc90fda6356d3c
Online IDEのSmartX
こちらからONT IDを作成してログインするか、Githubログインも最近実装されて利用できるようだ moonty_sal.iconは一旦Githubアカウントでログインすることに決めた。(WalletをインストールするとONT IDの発行もできます)
Create Projectを押すと利用する言語の選択画面が立ち上がる (踏み絵感を感じるw
https://gyazo.com/5534d8046472021f5ae77ecd32177e8e
テンプレートからHelloWorldを選択した直後がこんな感じ
https://gyazo.com/f40e364bc57b3a5672e5ae49f3c142b4
Compileを押すと右のPaneにABIとAVM ByteCodeが表示される (AVM?)
https://gyazo.com/84ec0af706bc2e74bb9686c8eae27f7d
前にNeo Hackathonでコードを拝見したときにも感じたが operation ( = どの関数を実行するか)がMain関数に渡ってくるので if文でディスパッチするのが通常の書き方のようだ
code: helloworld.py
from boa.interop.System.Runtime import Log
def Main(operation, args):
if operation == 'Hello': # operationを見てDispatch
return Hello(msg)
return False
def Hello(msg):
Log(msg) # 処理の実態
return True
下記のように、テストネットは無料で利用できるらしいので一旦HelloWorldをテストネットにデプロイするとして
Next, you can deploy the smart contract on the blockchain by clicking the Deploy button. If you choose to deploy the contract on the TestNet, it is free, that is, no gas will be consumed. The result of the deployment will be printed in the output box. You can copy the results of the transaction hash to the Ontology blockchain browser to further confirm the success of the deployment.
SmartXからテストネットもしくはローカルネットにdeployを試みることにする。
https://gyazo.com/f6c10562a6cfa0322a2502887902e2c0
必要項目を入力しないと「请填写智能合约的每项信息。」と中国語でエラーが出ます。Google翻訳で英語にすると
Please fill in each item of the smart contract.
という意味だそうです。項目を入力しdeployボタンを推しますが、現状ではChromeにOntologyネットワークにつなぎに行くためのWalletが入っていないため「没有安装插件。您可以从Chrome应用商店里安装Cyano wallet作为Provider」とエラーが出ます。
No plugins installed. You can install Cyano wallet as a Provider from the Chrome App Store.
Cyano Walletが必要とのことなので
https://gyazo.com/075e9325a52adac1c7c44fcb4ac8c652
こんな感じでMainnet / TestNetの切り替えを行えます。一旦TestNetを選択してdeployすることに。
https://gyazo.com/a1291336852e053d7f736d517bd3cb35
The deployment failed. Please check if the wallet has enough balance.
TestNetはGas Priceが0という話をドキュメントの中で見かけた気がしましたが、残高不足で怒られるので、別途testNetのONTGASをもらうことにしてLocalのPrivate Networkにデプロイを試みます。
code: error message in local ontology
2018/10/04 15:20:21.925437 INFO GID 65, CurrentBlockHeight = 867 2018/10/04 15:20:23.874979 WARN GID 43, TxnPool verify error: unknown error 2018/10/04 15:20:23.875051 WARN GID 43, SendRawTransaction verified d9968cfe134f889962f98e9da93d89c91a550dc11431f77ecc05ef5bf569359d error: transactor ff4140ec5a81cb311a54da12852ffb3bfed28a86 has no balance enough to cover gas cost 10000000000 2018/10/04 15:20:27.917378 INFO GID 251, current block height 867, increment validator block cache range: [858, 868) LocalのGasPriceを0にするための設定
code: ローカル開発の際に利用すべきコマンド
./ontology --disable-tx-pool-pre-exec --rest --ws --localrpc --gaslimit 1 --gasprice 0 --testmode --networkid 3
https://gyazo.com/11f1d8d4e79ac14482808e29632eff6c
デプロイが成功するとContractのアドレスが生成され、SmartX上から実行できるようになります。
SmartX上のコンソールに
{ "Action": "Notify", "Desc": "SUCCESS", "Error": 0, "Result": { "TxHash": "6c5e747ff685eca22e6d9491a5116ca7375bb0ff4079db1e6c4759957f64032e", "State": 0, "GasConsumed": 0, "Notify": [] }, "Version": "1.0.0" }
これが表示され、Successしていることが見て取れます
SmartX上から、hello 関数の引数を入力して実行します
2018/10/04 15:58:50.438665 WARN GID 41, TxnPool verify error: unknown error 2018/10/04 15:58:50.438727 WARN GID 41, SendRawTransaction verified 2f805eeab047cb956ee38c9962d4d8581776e6b3bf2e6645b24ed42a891a9cd4 error: NeoVmService Get contract code from db fail !? ...
このエラーはここで吐かれているようです。
code: txhashを確認する
% ./ontology info status 856b5c26d014cdc379474efcfe576f75b626c954a2d92f4ca4514779941697c4
Transaction states:
{
"TxHash": "856b5c26d014cdc379474efcfe576f75b626c954a2d92f4ca4514779941697c4",
"State": 0,
"GasConsumed": 0,
"Notify": []
}
こちらにトランザクションの実行結果に関する記述があります
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.
When the State value is 0, it indicates that the execution failed.
なるほど?ということで実はコントラクトデプロイに失敗しているようだ。それはどうやらローカルのデータストア関連の問題らしい。どうする?ということで深く追うことに(トホホ...
code: loglevelをdebugに
/ontology --disable-tx-pool-pre-exec --rest --ws --localrpc --gaslimit 1 --gasprice 0 --testmode --networkid 3 --loglevel 0
code: debug log でデプロイ時にエラーが出ているのを確認
2018/10/04 23:38:55.071903 DEBUG GID 112, github.com/ontio/ontology/consensus/solo.(*SoloService).makeBlock solo.go:157 2018/10/04 23:38:55.071986 INFO GID 112, current block height 2743, increment validator block cache range: [2735, 2744) 2018/10/04 23:38:55.072074 DEBUG GID 129, github.com/ontio/ontology/txnpool/proc.(*TxPoolActor).Receive txnpool_actor.go:311 txpool actor receives getting tx pool req from nonhost/future$c 2018/10/04 23:38:55.072655 DEBUG GID 112, github.com/ontio/ontology/core/store/ledgerstore.(*LedgerStoreImp).handleTransaction ledger_store.go:708 HandleDeployTransaction tx 86ed136f59f136644d8a6f33cd6eb0bdf94928d3e689a75733e91d701b8fbc11 error payer gas insufficient, need 10000000000 , only have 0 code: tx_hander.go
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
}
GasPrice が 0に指定されていない場合はisBalanceSufficientを読んでしまうようです。Cyano WalletはGaspriceを0に指定できないので詰んでいる....
まず、起動時に作成したcoinbase的なアドレスが保持しているONTトークン(GASない方)
code: ONT残高とONG残高
% ./ontology asset balance 1
BalanceOf:ARYvJ4Hh7mv9nB1eFyRkRQA9iVEiwVksig
ONT:1000000000
ONG:0
% ./ontology asset unboundong 1
Unbound ONG:
Account:ARYvJ4Hh7mv9nB1eFyRkRQA9iVEiwVksig
ONG:0
ONTは持っているがGASは持っていない、testmodeで起動していればブロックは生成されるはずだが、ONTGASは付与されない。という状況です。
ONG is the associated gas of ONT, which is gradually released from ONT, but it needs to be manually extracted into your own account;
The reason why the number of ONGs that can be extracted at this time is zero is because the account has not activated the release of ONG. You can use below transfer method to activate it;
ONTのTransferを1度でも実行しないとONTGASは供給されないようです。
ということで、2つめのアカウントを生成してONTを送金します
./ontology account add -d # アカウント作成
code: account creation
% ./ontology account add -d
Use default setting '-t ecdsa -b 256 -s SHA256withECDSA'
signature algorithm: ecdsa
curve: P-256
signature scheme: SHA256withECDSA
Password:
Re-enter Password:
Index:2
Label:
Address:AcnpHtuE7BPCHRRbxJMHAAzRgfcJR6YZiF
Public key:02a5ad73b2f4aa9e5c8d23df874f2da001b755ba0aa687f625b95537a3a58f04ea
Signature scheme:SHA256withECDSA
Create account successfully.
送金を実行します
code: transfer実行
./ontology asset transfer --from 1 --to 2 --amount 100000000
トランザクション承認後、残高の確認
code: 残高の確認
% ./ontology asset balance 1
BalanceOf:ARYvJ4Hh7mv9nB1eFyRkRQA9iVEiwVksig
ONT:900000000
ONG:0
% ./ontology asset balance 2
BalanceOf:AcnpHtuE7BPCHRRbxJMHAAzRgfcJR6YZiF
ONT:100000000
ONG:0
code: GASの確認コマンドを実行
Unbound ONG:
Account:ARYvJ4Hh7mv9nB1eFyRkRQA9iVEiwVksig
ONG:41739720 # 増えている!
引き出しコマンドを実行しないと実際に利用できない仕様なので
code: 引き出しコマンドの実行
% ./ontology asset withdrawong 1
Password:
Withdraw ONG:
Account:ARYvJ4Hh7mv9nB1eFyRkRQA9iVEiwVksig
Amount:41739720
TxHash:834c0ce7b9608ef0f6537262ae8e8b22ecbad47c30fc95c4d8d3aa90096304ce
Tip:
Using './ontology info status 834c0ce7b9608ef0f6537262ae8e8b22ecbad47c30fc95c4d8d3aa90096304ce' to query transaction status.
% ./ontology asset balance 1
BalanceOf:ARYvJ4Hh7mv9nB1eFyRkRQA9iVEiwVksig
ONT:900000000
ONG:41739720
手に入れたGASをブラウザウォレット側に送金する。GASの送金コマンドが見つからない & --helpしてもontではなくgasを送る方法がピンとこなかったのでソースコードを見て判断することに code: GASを送るコマンド
% ./ontology asset transfer --from 1 --to AU3GVsrLJDxgVC35PybteS4ZBtvZVaR28x --amount 10000 --asset ong
Password:
Transfer ONG
From:ARYvJ4Hh7mv9nB1eFyRkRQA9iVEiwVksig
To:AU3GVsrLJDxgVC35PybteS4ZBtvZVaR28x
Amount:10000
TxHash:fd70d51f01776f460235a542f413dc20e179603da4feb9ccd47581a9a54f4d39
--asset ong ... オプションで ongを指定するとongを送金できます
https://gyazo.com/e8c91af9d3f97b63213b2b7ac9eb9b32
大勝利...
満を持してデプロイを実行します。
code: デプロイの結果
2018/10/5 0:13:55 Deploy: {"Action":"Notify","Desc":"SUCCESS","Error":0,"Result":{"TxHash":"c63e1b3db5aa6c0a13a675df2bfd39e1fbdc390c3449729276243f476bb24be5","State":1,"GasConsumed":10000000000,"Notify":[{"ContractAddress":"0200000000000000000000000000000000000000","States":"transfer","AU3GVsrLJDxgVC35PybteS4ZBtvZVaR28x","AFmseVrdL9f9oyCzZefL9tG6UbviEH9ugK",10000000000}]},"Version":"1.0.0"} state = 1 ...ぶち上がる..
https://gyazo.com/8051655d006f827471bd4407e37f6433
2018/10/5 0:19:18 Invoke: {"result":[],"transaction":"35ff2c1ce9e5bff379c0e3621f4c056af025740c2da82560d00a7f8e8d3c6beb"}
ここで疑問
Log関数を呼び出すだけなのにトランザクションを発行している
Logを書かなければ署名しなくて良い?とおもい、Log関数を消してみるも、署名は要求されていそう
resultが[] ???
まだ試練が.. SmartX上での実行はうまく行かなそうなのでコマンドで実行します
code: コントラクトの書き換え:ただの足し算
from boa.interop.System.Runtime import Log
def Main(operation, args):
if operation == 'Add':
return Add(a, b)
return False
def Add(a, b):
return a + b
code: 実行
./ontology contract invoke --address 01ef272b0f2c9d8e825ab16ea57aeb460cf58452 --params string:Add,int:1,int:2 --prepare --return int code: 結果
Invoke:5284f50c46eb7aa56eb15a828e9d2c0f2b27ef01 Params:["Add",1,2] Contract invoke successfully
Gas limit:20000
Return:3
ぶち上がる。。。この実行に際して署名は要求されなかったので、やはりsolidity でいうview or pureを呼ぶ際はGASは必要ないようです。
その(1)は一旦ここまでとします。
周辺ツール
Browser Wallet
https://gyazo.com/a98294dec034daa90a68467097e2a7d6
Official Desktop Wallet
GtihubのReleaseからdmgをダウンロードしてインストールすれば普通に入ります。
https://gyazo.com/ece5d227160d4fbd65490a62039028c6
アドレスを発行したところ
https://gyazo.com/47f1776521d83b0322c205dfad5b6e32
ONT IDもここから発行できる(がONTGASトークンが必要...)
https://gyazo.com/1dcdf79ebf792bd26df8c181423962d3
https://gyazo.com/b2fc5add046587322e11f0c3ef58bc9e
Stakeの様子も確認できる
TestNet上のWalletもこれで作れる
https://gyazo.com/16fcbc980ea554ff673307f22ec8168a
Localへのインストール
code:sh
-- output--
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 1023 100 1023 0 0 1161 0 --:--:-- --:--:-- --:--:-- 1161
Downloading ontology-darwin-amd64...
contology was successfully download 🎉
アカウント作成
code: ontlogy account作成
./ontology account add -d
Use default setting '-t ecdsa -b 256 -s SHA256withECDSA'
signature algorithm: ecdsa
curve: P-256
signature scheme: SHA256withECDSA
code: ontology起動
./ontology --testmode # ローカルで実行 //Run command $ ./ontology --testmode can start single-host test net.
./ontology --rest --ws --localrpc --gaslimit 20000 --gasprice 0 --testmode # Gas Priceを0に (2)
./ontology --networkid 2
テストネットのONG(ONTGAS)はDiscordでくれって言えばもらえるそうなので、Walletを作成して依頼してみます。
記事末尾のReferencesにDiscordのアドレスを記載しています。
(2) の設定でローカル開発ができるかと思いきや、OntologyはTransaction実行者が十分なONTGASを持っているかをチェックし、持っていなければトランザクションを実行させないような仕組みになっているため、下記のように--disable-tx-pool-pre-execというOptionを付ける必要があります
code: ローカル開発の際に利用すべきコマンド
./ontology --disable-tx-pool-pre-exec --rest --ws --localrpc --gaslimit 1 --gasprice 0 --testmode --networkid 3
上記に貼ったO WalletでネットワークをTestnetに切り替えてWalletを発行しなおします
(Testnet <-> Mainnetの切り替えをしても表示されるアドレスが変わらなかったので、TestNetに接続している状態にしてWalletを作り直しています
code: address in testnet
AHuj1ycU7T4biEkCU1rjgPtky28MbvUsDP # ワイのやつです。これをDiscordではってONGをもらう
次回
コードサンプルとAPI一覧を見ながら実際の書き方のお作法やどういう時にどういう記述をするかを追っていく。
Python SDKのAPI一覧
あまりコードサンプルがないので、Ontology or NEO から適当にプロジェクトを見つけてきて参考にすることにする
Narrativeという会社がMediumにERC-20とNEP-5(NEOVMにおけるトークンスターンダード)の違いについて書いていたので、その会社のトークンセール用のコントラクトを見てみることにする。
References
Ontologyが提供しているスタック
Ontology Dapp SDK
Ethereumで言うところのweb3
deployに関するドキュメント
ONGについて記述されている記事
テストネット上のONGのもらい方も個々に書いてある
Developers can request for free TestNet ONG in the testnet-ong-requests channel in our Discord.
ここでくれ!って言えばもらえるそうです
GASの払い出し方に関する詳細な記述(DBFTでVoterにも収益配分をする旨)
Ontology がサポートしていること
Scalable lightweight universal smart contract
Scalable WASM contract support
Crosschain interactive protocol (processing)
Multiple encryption algorithm support
Highly optimized transaction processing speed
P2P link layer encryption (optional module)
Multiple consensus algorithm support (VBFT/DBFT/RBFT/SBFT/PoW)
Quick block generation time