一年以上前にEOSを試した時に簡単にコントラクトの実行についてメモしたがガラリと変わっているのでEOSのノードをDockerで動かしつつトークンをデプロイするところまでサクッと見ていく。
EOSの公式ドキュメントを参照するとMacOSやUbuntu、CentOSなどいくつかのOSにおけるインストール方法が出てくるが、Dockerを使った方がPCも汚れないし簡単に試すことができるので、Dockerを使ったEOSの立ち上げ方について説明する。Dockerを使っているのはあくまでノードの部分(nodeos)のみ。
*ここではeosstudio
が公開しているDockerイメージを利用する。執筆時点での最新Verが1.8.3なのでそれを利用しているが、その時の最新版で書き換えて良い。
EOSのノードのセットアップ
# dockerイメージを落とす
$ docker pull eostudio/eos:v1.8.3
v1.8.3: Pulling from eostudio/eos
5b7339215d1d: Already exists
14ca88e9f672: Already exists
a31c3b1caad4: Already exists
b054a26005b7: Already exists
a677768c3204: Pull complete
a743177c79c8: Pull complete
4dd68c5b6b2c: Pull complete
2a9ecc7eee10: Pull complete
Digest: sha256:725154d672654d09c86dcde6b4d2cbbec48c944b31ad4e765ec0903d63db2533
Status: Downloaded newer image for eostudio/eos:v1.8.3
docker.io/eostudio/eos:v1.8.3
# portは8888を解放。スマートコントラクトを配置するディレクトリは/path/to/contractsとしている。任意で良い。
$ docker run --name nodeos -dit -p 8888:8888 -v /path/to/contracts:/contracts eostudio/eos:v1.8.3
2b62951d170dacfc7d6e106bbfdd68cff419641b6a47ce63d6cf563b648a60b13
# dockerコンテナが動いてるのが確認できる。
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
2b62951d170d eostudio/eos:v1.8.3 "/bin/bash" 20 seconds ago Up 19 seconds 0.0.0.0:8888->8888/tcp nodeos
# コンテナの中に入る。
$ docker exec -it nodeos bash
root@2b62951d170d:/#
# コンテナ内でnodeosのコマンドを実行する。
root@2b62951d170d:/# nodeos -e -p eosio --plugin eosio::producer_plugin --plugin eosio::history_plugin --plugin eosio::chain_api_plugin --plugin eosio::history_api_plugin --plugin eosio::http_plugin -d /mnt/dev/data --config-dir /mnt/dev/config --http-server-address=0.0.0.0:8888 --access-control-allow-origin=* --contracts-console --http-validate-host=false --max-transaction-time=1000
以下の画像のようにnodeosが動き出す。
EOSのブロック情報が以下のように取得できれば成功。
$ curl http://localhost:8888/v1/chain/get_info
{"server_version":"7116e887","chain_id":"cf057bbfb72640471fd910bcb67639c22df9f92470936cddc1ade0e2f2e7dc4f","head_block_num":289,"last_irreversible_block_num":288,"last_irreversible_block_id":"0000012068f42c0c021775b7ea90535f3a5a0458d0e7ce345fc11b18ca6727b3","head_block_id":"0000012134461c28c52f92aff0dc20370d4bc5d21ddc9869538a6617267e5fca","head_block_time":"2019-09-20T08:54:33.000","head_block_producer":"eosio","virtual_block_cpu_limit":266624,"virtual_block_net_limit":1398582,"block_cpu_limit":199900,"block_net_limit":1048576,"server_version_string":"v1.8.3","fork_db_head_block_num":289,"fork_db_head_block_id":"0000012134461c28c52f92aff0dc20370d4bc5d21ddc9869538a6617267e5fca"}
EOSのコマンドラインのセットアップ
公式ページに詳しいインストール方法が書いてある。このツールはコントラクトのコンパイル等で利用される。
MacOSだとこんな感じ。
$ brew tap eosio/eosio.cdt
$ brew install eosio.cdt
Ubuntuだとこんな感じ。
$ wget https://github.com/EOSIO/eosio.cdt/releases/download/v1.6.1/eosio.cdt_1.6.1-1_amd64.deb
$ sudo apt install ./eosio.cdt_1.6.1-1_amd64.deb
Walletのセットアップ
# コンテナの中に入った状態で始める。
root@2b62951d170d:/# cleos wallet create --to-console
Creating wallet: default
Save password to use in the future to unlock this wallet.
Without password imported keys will not be retrievable.
"PW5J1GMa6QzUGVAHeiJcBv6ct7nkmAj312xGaYUg7auybF2NvTwcp"
root@2b62951d170d:/# cleos wallet open
Opened: default
root@2b62951d170d:/# cleos wallet list
Wallets:
[
"default"
]
# 上で発行したパスワード(PW5J1GMa6QzUGVAHeiJcBv6ct7nkmAj312xGaYUg7auybF2NvTwcp)を入力
root@2b62951d170d:/# cleos wallet unlock
password: Unlocked: default
# *印がunlock状態を意味する。
root@2b62951d170d:/# cleos wallet list
Wallets:
[
"default *"
]
# 新しいキーペアを作成。
root@2b62951d170d:/# cleos wallet create_key
Created new private key with a public key of: "EOS7vURhtJepaqsRSAJVSpPA9bv7U3uyv8RotpRwxLvqL7s2JDnPW"
# eosioの秘密鍵(5KQwrPbwdL6PhXujxW37FSSQZ1JiwsST4cqQzDeyXtP79zkvFD3)を入力する。
root@2b62951d170d:/# cleos wallet import
private key: imported private key for: EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV
# create_keyで作成したキーペアを元にbobというアカウントを作成する。
root@2b62951d170d:/# cleos create account eosio bob EOS7vURhtJepaqsRSAJVSpPA9bv7U3uyv8RotpRwxLvqL7s2JDnPW
executed transaction: d145f646aad4f50baa2c94a1ccabe996e8901d564dd5b66cff5339ca95d67103 200 bytes 231 us
# eosio <= eosio::newaccount {"creator":"eosio","name":"bob","owner":{"threshold":1,"keys":[{"key":"EOS7vURhtJepaqsRSAJVSpPA9bv7U...
warning: transaction executed locally, but may not be confirmed by the network yet ]
# create_keyで作成したキーペアを元にaliceというアカウントを作成する。
root@2b62951d170d:/# cleos create account eosio alice EOS7vURhtJepaqsRSAJVSpPA9bv7U3uyv8RotpRwxLvqL7s2JDnPW
executed transaction: 710cfb8ca86df0e0aebb349378141d1f46c81333d1f228a5329f71fe01641306 200 bytes 219 us
# eosio <= eosio::newaccount {"creator":"eosio","name":"alice","owner":{"threshold":1,"keys":[{"key":"EOS7vURhtJepaqsRSAJVSpPA9bv...
warning: transaction executed locally, but may not be confirmed by the network yet ]
# aliceのaccount情報はこんな感じ。
root@2b62951d170d:/# cleos get account alice
created: 2019-09-20T10:53:06.000
permissions:
owner 1: 1 EOS7vURhtJepaqsRSAJVSpPA9bv7U3uyv8RotpRwxLvqL7s2JDnPW
active 1: 1 EOS7vURhtJepaqsRSAJVSpPA9bv7U3uyv8RotpRwxLvqL7s2JDnPW
memory:
quota: unlimited used: 2.66 KiB
net bandwidth:
used: unlimited
available: unlimited
limit: unlimited
cpu bandwidth:
used: unlimited
available: unlimited
limit: unlimited
スマートコントラクトを試す
# /path/to/contractsの階層でhelloディレクトリを作る。
$ mkdir hello
$ cd hello
$ vim hello.cpp
hello.cppを以下のように編集する。実行すると、 Hello, 名前
が返ってくるだけのいたってシンプルなEOSスマートコントラクトである。
# include <eosio/eosio.hpp>
using namespace eosio;
class [[eosio::contract]] hello : public contract {
public:
using contract::contract;
[[eosio::action]]
void hi( name user ) {
print( "Hello, ", user);
}
};
このhello.cppをコンパイルする。eosio-cpp
は先ほどインストールしたeosio.cdt
に含まれている。
$ eosio-cpp hello.cpp -o hello.wasm
再びdockerコンテナに戻る。もしwalletがロックされていたら、cleos wallet unlock
で最初に発行されたパスワード(本稿ではPW5J1GMa6QzUGVAHeiJcBv6ct7nkmAj312xGaYUg7auybF2NvTwcp)を入力することで再びアンロックできる。
# コントラクト用にhelloというアカウントを作成する。
root@2b62951d170d:/# cleos create account eosio hello EOS7vURhtJepaqsRSAJVSpPA9bv7U3uyv8RotpRwxLvqL7s2JDnPW -p eosio@active
executed transaction: 93f33e70d3108b723bcdcf850e3f12e9f5944f230cadbeee8804d6a397086a1b 200 bytes 244 us
# eosio <= eosio::newaccount {"creator":"eosio","name":"hello","owner":{"threshold":1,"keys":[{"key":"EOS7vURhtJepaqsRSAJVSpPA9bv...
# helloアカウントにコントラクトをセットする。
root@2b62951d170d:/# cleos set contract hello contracts/hello -p hello@active
Reading WASM from /contracts/hello/hello.wasm...
Publishing contract...
executed transaction: 07acebc8a0492277db4581eddf7cd09b53cff6725e47a16624a18825488372ac 688 bytes 422 us
# eosio <= eosio::setcode {"account":"hello","vmtype":0,"vmversion":0,"code":"0061736d0100000001370b6000017f60027f7f0060037f7f...
# eosio <= eosio::setabi {"account":"hello","abi":"0e656f73696f3a3a6162692f312e31000102686900010475736572046e616d650100000000...
# bobアカウントから、コントラクトのメソッドhelloを実行してみる。
root@2b62951d170d:/# cleos push action hello hi '["bob"]' -p bob@active
executed transaction: f8df222edc812552dfaf6f4e72d39c9ed3300cb5ea72bec3988b077e346fa525 104 bytes 460 us
# hello <= hello::hi {"user":"bob"}
>> Hello, bob
# aliceアカウントから、コントラクトのメソッドhelloを実行してみる。
root@2b62951d170d:/# cleos push action hello hi '["bob"]' -p alice@active
executed transaction: fb6ee5f4d6ddcea43ab825867213f743da0637a39946e7e9e82cf9f7072dd872 104 bytes 432 us
# hello <= hello::hi {"user":"bob"}
>> Hello, bob
helloアクションが正常に実行されたのが確認できた。
トークンをデプロイして送金してみる
helloが表示されるだけでは面白くないので、次は、公式で出ているサンプルトークンを試してみる。
# 最初のディレクトリに戻る。
$ cd /path/to/contracts
# cloneする。
$ git clone https://github.com/EOSIO/eosio.contracts --branch v1.7.0 --single-branch
# eosio.tokenディレクトリへ(eosio.tokenとはEthereumでいうところのERC20トークン)。
$ cd eosio.contracts/contracts/eosio.token
# コンパイルする。
$ eosio-cpp -I include -o eosio.token.wasm src/eosio.token.cpp --abigen
再びdockerコンテナに戻る。
# eosのアカウントからトークン用(eosio.token)のアカウントを作成する。
root@2b62951d170d:/# cleos create account eosio eosio.token EOS6MRyAjQq8ud7hVNYcfnVPJqcVpscN5So8BhtHuGYqET5GDW5CV
executed transaction: 0dd3ce0bb9f9cd47869c0d123dc99c205ff318698b2cd4db58a0e80ba7dd1950 200 bytes 183 us
# eosio <= eosio::newaccount {"creator":"eosio","name":"eosio.token","owner":{"threshold":1,"keys":[{"key":"EOS6MRyAjQq8ud7hVNYcf...
# eos.tokenアカウントにデプロイする。
root@2b62951d170d:/# cleos set contract eosio.token contracts/eosio.contracts/contracts/eosio.token --abi eosio.token.abi -p eosio.token@active
Reading WASM from /contracts/eosio.contracts/contracts/eosio.token/eosio.token.wasm...
Publishing contract...
executed transaction: 32f940123f30c131f17d828a6e018ac3278725e1a3601e323e05aed8dee55764 6984 bytes 1198 us
# eosio <= eosio::setcode {"account":"eosio.token","vmtype":0,"vmversion":0,"code":"0061736d0100000001a0011b60000060017e006002...
# eosio <= eosio::setabi {"account":"eosio.token","abi":"0e656f73696f3a3a6162692f312e310008076163636f756e7400010762616c616e63...
# eosio.tokenのcreateアクションを実行する。aliceは 1000000000 SYS分の発行権を獲得する。'SYS'という決まりはなく'JPY'でも問題ない。
root@2b62951d170d:/# cleos push action eosio.token create '[ "alice", "1000000000.0000 SYS"]' -p eosio.token@active
executed transaction: 8c2fdcf0d38ce0220a324a1f92beb92ea416503316f0ccded26f7ad564a07553 120 bytes 1210 us
# eosio.token <= eosio.token::create {"issuer":"alice","maximum_supply":"1000000000.0000 SYS"}
# aliceは自分に対して 100 SYS 発行する。createアクションの時点ではaliceの残高は0のまま。
root@2b62951d170d:/# cleos push action eosio.token issue '[ "alice", "100.0000 SYS", "memo" ]' -p alice@active
executed transaction: c2e2717923df4bb07fe2b42e286a2a513342634380684e65a6f89a4684d19c71 128 bytes 2333 us
# eosio.token <= eosio.token::issue {"to":"alice","quantity":"100.0000 SYS","memo":"memo"}
# aliceは所有している 100 SYS のうち、 25 SYS をbobに送金する。
root@2b62951d170d:/# cleos push action eosio.token transfer '[ "alice", "bob", "25.0000 SYS", "m" ]' -p alice@active
executed transaction: d5d5c59ad6612aba2ddf52a9ef0b170d1bc8cf32f4e02caeb917f9081dd611b2 128 bytes 2751 us
# eosio.token <= eosio.token::transfer {"from":"alice","to":"bob","quantity":"25.0000 SYS","memo":"m"}
# alice <= eosio.token::transfer {"from":"alice","to":"bob","quantity":"25.0000 SYS","memo":"m"}
# bob <= eosio.token::transfer {"from":"alice","to":"bob","quantity":"25.0000 SYS","memo":"m"}
# bobの所持金を確認すると、 25 SYS になっている。
root@2b62951d170d:/# cleos get currency balance eosio.token bob SYS
25.0000 SYS
# aliceの所持金を確認すると、 75 SYS になっている。
root@2b62951d170d:/# cleos get currency balance eosio.token alice SYS
75.0000 SYS
これでEOSで標準のトークンを発行して送金してみるところまで確認できた。
dockerを閉じる時は、以下のようにすれば良い。
$ docker stop nodeos
$ docker rm nodeos
所感
- 2018年の2月頭にEOSを初めて触った時は、READMEも嘘ばっかりで地獄の様相を呈していたが、今はドキュメントもかなりまともになっていた。
- account名やaction名、eosio.tokenのシンボル名等の命名規則が厳しい。
- EOSはDPoSを採用しており、「DPoSは中央集権的なのでは」という議論もあるが、TPSを考慮しても現時点では現実的な技術なのではないかという感想。