EOSIOの概要と準備編はこちら:https://qiita.com/YukiSekiguchi/items/623359857269aff74586
スマートコントラクトの実装
ようやくスマートコントラクトの実装に移る。
2.1 Hello World!
まずはhelloディレクトリを作成。
cd <ローカルの作業用ディレクトリの絶対パス>
mkdir hello
cd hello
続いて、hello.cppを実装する。
#include <eosiolib/eosio.hpp>
#include <eosiolib/print.hpp>
using namespace eosio;
class hello : public contract {
public:
using contract::contract;
[[eosio::action]]
void hi( account_name user ) {
print( "Hello, ", name{user} );
}
};
EOSIO_ABI( hello, (hi) )
- 1-2行目:必要なライブラリをインクルード
- 4行目:
eosio
名前空間のものを修飾せずに使えるようにする - 6行目:
contract
クラスを継承したhello
クラスの宣言 - 7行目:アクセス修飾子
public
- 8行目:
contract::contract
名前空間のものを修飾せずに使えるように - 10行目:コンパイラがABIを作成するための属性
- 11行目:
account_name
型の変数user
を引数とするメソッドhi
の定義 - 12行目:アカウント名を
name{user}
で取得してprint
する - 16行目:
hello
というコントラクトを実行するためのマクロ(?)
これをコンパイルする。
eosio-cpp -o hello.wasm hello.cpp --abigen
これでwasm
形式のバイナリファイルと、hello.abi
というjson形式のファイルが出来上がる(この辺はイーサリアム同様)。
hello.abi
の中身はこんな感じ。
$ cat hello.abi
{
"____comment": "This file was generated with eosio-abigen. DO NOT EDIT Mon Oct 1 00:06:48 2018",
"version": "eosio::abi/1.0",
"structs": [
{
"name": "hi",
"base": "",
"fields": [
{
"name": "user",
"type": "name"
}
]
}
],
"types": [],
"actions": [
{
"name": "hi",
"type": "hi",
"ricardian_contract": ""
}
],
"tables": [],
"ricardian_clauses": [],
"abi_extensions": []
}
--volume
オプションをつけてdocker
コマンドを実行したため、うまくいけばコンパイルしたファイル群はコンテナ側に入っているはず。ちゃんと入っていない場合はdocker cp
で運ぶ。
ブロックチェーン上で他のユーザーがアクセスできるようにするため、コントラクト用にアカウントを作成する。
cleos create account eosio hello YOUR_PUBLIC_KEY -p eosio@active
あとはこのアカウントでブロックチェーン上にコントラクトをbroadcastする
cleos set contract hello <コンテナの、コンパイルしたファイルが入っているパス> -p hello@active
これでブロックチェーン上の誰でもこのコントラクトを利用できるようになる。
Reading WASM from /home/hello/hello.wasm...
Publishing contract...
executed transaction: 6ca2cb39d7a23c95cb678b30ae9ffe9cc76abf8d0e32bca2f68a258fc0ced56f 1520 bytes 449 us
# eosio <= eosio::setcode {"account":"hello","vmtype":0,"vmversion":0,"code":"0061736d0100000001320a60027f7e0060027f7f00600001...
# eosio <= eosio::setabi {"account":"hello","abi":"0e656f73696f3a3a6162692f312e30000102686900010475736572046e616d650100000000...
warning: transaction executed locally, but may not be confirmed by the network yet ]
早速このコントラクトを使ってみる。
cleos push action hello hi '["bob"]' -p bob@active
これはhello
というアカウントのhi
コントラクトを '["bob"]'
というjson形式の引数で、bob
というアカウントがactive
というパーミッションレベルで実行するものである。
これがうまくいくと、
executed transaction: 32913c03fe13777654f33f4a6e622dd4d1119a8122d509f01204d179e7e3a33d 104 bytes 315 us
# hello <= hello::hi {"user":"bob"}
>> Hello, bob
warning: transaction executed locally, but may not be confirmed by the network yet ]
となる。docker logs --tail 100 eosio
でコンテナのログを表示すると、
2018-09-30T15:47:09.002 thread-0 producer_plugin.cpp:1419 produce_block ] Produced block 0001729f34805d46... #94879 @ 2018-09-30T15:47:09.000 signed by eosio [trxs: 0, lib: 94878, confirmed: 0]
2018-09-30T15:47:09.099 thread-0 apply_context.cpp:28 print_debug ]
[(hello,hi)->hello]: CONSOLE OUTPUT BEGIN =====================
Hello, bob
[(hello,hi)->hello]: CONSOLE OUTPUT END =====================
となっていてコントラクトを実行したブロックが追加されたことがわかる。
コードからして当然だが、alice
でbob
にhi
することができる。
$cleos push action hello hi '["bob"]' -p alice@active
executed transaction: f62c114ea4e2eabe0db9924b5146a2486a7fb9db0733e2845dcdb7cfa4f5a0f4 104 bytes 294 us
# hello <= hello::hi {"user":"bob"}
>> Hello, bob
warning: transaction executed locally, but may not be confirmed by the network yet ]
コードを変えることで、bob
しかbob
にhi
できないようにする。
具体的には
void hi( account_name user ) {
require_auth( user );
print( "Hello, ", name{user} );
}
とする。require_auth
は、コントラクトを実行したユーザーが引数であるuser
であるかどうかを確かめるメソッドである。
これを再度コンパイル・broadcastし直す。
eosio-cpp -o hello.wasm hello.cpp --abigen
cleos set contract hello <コンテナの、コンパイルしたファイルが入っているパス> -p hello@active
ちなみにwasm
が更新されていない状態でcleos set contract...
し直すと以下のようなエラーが出る
$ cleos set contract hello /home/hello -p hello@owner
Reading WASM from /home/hello/hello.wasm...
Publishing contract...
Error 3160008: Contract is already running this version of code
今度はalice
でbob
にhi
しようとすると
$cleos push action hello hi '["bob"]' -p alice@active
Error 3090004: Missing required authority
Ensure that you have the related authority inside your transaction!;
If you are currently using 'cleos push action' command, try to add the relevant authority using -p option.
というエラーが出る。一方でalice
でalice
にhi
してみると
$ cleos push action hello hi '["alice"]' -p alice@active
executed transaction: 887d64024e1d9254560df4243ff127308f31fd86f8c6838728bf195d43167e07 104 bytes 481 us
# hello <= hello::hi {"user":"alice"}
>> Hello, alice
warning: transaction executed locally, but may not be confirmed by the network yet ]
となる。
超簡単なスマートコントラクトが実装できた。次回は独自の仮想通貨トークンを発行してやりとりしてみる。