IOST 次世代ブロックチェーンの旗手 ~IRC20トークン発行~

Yuya Sugano
26 min readJul 15, 2019

--

IOSTはスケーラビリティの問題に対応するシャーディングや非中央集権性を確保するPoB(Proof-of-Believability)の実装という特徴を持つブロックチェーンです。Ethereum/EOS/TRONに続くDappsのパブリックなブロックチェーン基盤で、ローンチから1か月後にはEthereumのトランザクション数を超えました。既にインキュベーター、金融やゲームなど様々な分野のプレイヤーからなるコミュニティを形成しています。前回の記事ではEDSやPoBなどのアーキテクチャをまとめました。この記事ではハンズオンを取り扱います。

Powerful phrase on the top page obut seems not exaggerated

目次です。今回は太字の後半部分です(『IOSTとは』のみ再掲)。斜線のEDS/PoB/IOST VM V8は前回掲載済み。

  • IOSTとは
  • EDS(Efficient Distributed Sharding)
  • PoB(Proof of Believability)
  • IOST VM V8 アーキテクチャ
  • ローカルノードを起動
  • サンプルコードの実行
  • IRC20トークンの実装

IOSTとは

これまでのブロックチェーンの基盤にはTPS(Transaction Per Second)の低さに起因する問題がありました。IOSTは最大で 100,000 TPS までスケールすることを目指す次世代のブロックチェーンです。[1]

IOST is an ultra-fast, decentralised blockchain network based on the next-generation consensus algorithm “Proof of Believability” (PoB). Led by a team of proven founders and backed by world-class investors, our mission is to be the underlying architecture for online services that meets the security and scalability needs of a decentralized economy.

スケーラビリティの問題に対応するEDS(Efficient Distributed Sharding)という技術や、PoS(Proof-of-Stake)で問題となるコンセンサスの中央集権化に対応するPoB(Proof-of-Believability)という仕組みで注目を集めています。

EthereumのスマートコントラクトによるDApps(特にCryptoKittiesはEthereumのトランザクション全体の10%を占めると言われる)では、取引量の多さからネットワークが逼迫し、15 TPSの処理を巡ってガスコストが高騰する問題が発生しました。[2]

IOSTはライヴネットで 8000 TPS をベンチマークしており、Javascriptによるスマートコントラクトの開発サポートなど、オンラインサービスを実装するモダンなブロックチェーン基盤として利用しやすいように設計されています。IOSTでは以下の機能や特徴をビルトインで持っています。

  • スマートコントラクト実装(Dapps)
  • プライベートトランザクション
  • 非中央集権の分散型ストレージ
  • 分散型マーケットプレースのユーザ評価追跡
  • IoTノードと呼ばれる軽量なノード
  • ブロックチェーンからの適切な報酬分配

前回の記事ではEDS(Efficient Distributed Sharding)やPoB(Proof of Believability)といった技術的側面について書きました。[3]

今回はローカルノードを走らせてチュートリアルにあるサンプルのスマートコントラクトを触ってみたいと思います。

ローカルノードを起動

テストするためのローカルノード(プライベート)を構築します。Dockerで公式イメージが提供されているのでそのまま使うこととします。

またAWS(Amazon Web Services)マーケットプレイスにDocker環境およびiServerやiWalletが乗ったイメージがあるのでDocker環境がない方はAWSを利用しても良いかもしれません。[4]

IOST AMI runs iServer and iWallet natively

使用したDockerの環境です。

$ docker version
Client:
Version: 18.09.7
API version: 1.39
Go version: go1.10.8
Git commit: 2d0083d
Built: Thu Jun 27 17:56:17 2019
OS/Arch: linux/amd64
Experimental: false
Server: Docker Engine - Community
Engine:
Version: 18.09.7
API version: 1.39 (minimum version 1.12)
Go version: go1.10.8
Git commit: 2d0083d
Built: Thu Jun 27 17:23:02 2019
OS/Arch: linux/amd64
Experimental: false

公式のイメージは iostio/iost-node です。 docker pull iostio/iost-node として最新のタグのイメージを取得してください。

$ docker pull iostio/iost-node
$ docker images
iostio/iost-node latest 66d694bc2c7b 4 weeks ago 216MB
centos latest 9f38484d220f 4 months ago 202MB

素直にDockerイメージを走らせます。Genesisファイルの作成とブロックの生成が始まることを確認してください。

$ docker run -p 30000-30003:30000-30003 iostio/iost-node
Info 2019-07-13 01:02:27.453 main.go:74 Config Information:
acc:
id: producer000
seckey: 1rA******
algorithm: ed25519
genesis: /var/lib/iserver/genesis
vm:
jspath: vm/v8vm/v8/libjs/
loglevel: ""
db:
ldbpath: /var/lib/iserver/storage/
snapshot:
enable: false
filepath: /var/lib/iserver/storage/snapshot.tar.gz
...
debug:
listenaddr: 0.0.0.0:30003
version:
netname: debugnet
protocolversion: "1.0"
docker run -p 30000–30003:30000–30003 iostio/iost-node

詳細についてはこちらの記事が参考になります。[5]

サンプルコードの実行

IOSTのブロックチェーンのアカウント操作やコントラクトとのやり取りにはiWalletのクライアントが必要です。iWalletとAPIは内部的には同様の動作となっていてRPC APIへの呼び出しを行います。

golangの v11.x 以上と git LFS の v2.5.2 以上がインストールされていることを確認してください。 gvm の使用が簡便でおすすめです。iWalletのインストール方法です。

$ go get -d github.com/iost-official/go-iost
package github.com/iost-official/go-iost: no buildable Go source files in /home/iost/src/github.com/iost-official/go-iost
$ cd $GOPATH/src/github.com/iost-official/go-iost
$ git lfs pull
$ make build install
$ cd vm/v8vm/v8/; make deploy; cd ../../..

アカウントの作成やトランザクションの送付、コントラクトのデプロイもこのiWalletからの操作で行うことができます。 admin アカウントの残高、iGASおよびiRAMを確認するコマンドは以下のようになります。

テストのために admin をインポートしています。

$ iwallet account import admin 2yquS3ySrGWPEKywCPzX4RTJugqRh7kJSo5aehsLYPEWkUxBWA39oMrZ7ZxuM4fgyXYs2cPwh5n8aNNpH5x2VyK1
import account admin done
$ iwallet --server 127.0.0.1:30002 balance admin{
"name": "admin",
"balance": 20999997618.36,
"gasInfo": {
"currentTotal": 30000000,
"transferableGas": 0,
"pledgeGas": 30000000,
"increaseSpeed": 115,
"limit": 30000000,
"pledgedInfo": [
{
"pledger": "admin",
"amount": 100
},
{
"pledger": "foundation",
"amount": 100
},
{
"pledger": "producer000",
"amount": 100
}
]
},
"ramInfo": {
"available": "100000",
"used": "0",
"total": "100000"
},
...

iGASやiRAMについては以下の記事を参照してください。[6]

一言でいうとiGASはトランザクション生成の際に消費され、iRAMはDappsを作成するときに必要なストレージに使用されます。iGASはIOSTをデポジットして受け取れることに対して、iRAMは購入制のようです。

IOSTのコントラクトはJavascriptでコーディングできます。定番の『Hello World』をやってみたいと思います。 HelloWorld.js という名前のファイルを作成してください。 hello 関数では1つの引数を取り、hello, と連結した文字列を返します。

class HelloWorld {
init() {} // initialize function of the contract
hello(someone) {
return "hello, " + someone
}
}
module.exports = HelloWorld;

以下のように HelloWorld.abi というファイルを作成し、JSONでABI(Application Binary Interface)を定義してください。

{
"lang": "javascript",
"version": "1.0.0",
"abi": [
{
"name": "hello",
"args": [
"string"
]
}
]
}

ABIを手動で用意しましたがコンパイルして自動生成することも可能です。この場合ファイル名は HelloWorld.js.abi となります。コマンドは iwallet compile filename です。

$ iwallet compile HelloWorld.js
Successfully generated abi file as: HelloWorld.js.abi

準備はたったこれだけです。iwalletのpublishコマンドでローカルノードのチェーンにコントラクトをデプロイできます。

$ iwallet --server localhost:30002 --account admin publish HelloWorld.js HelloWorld.abi
Connecting to server localhost:30002 ...
Sending transaction...
Transaction:
{
"time": "1562994465796365352",
"expiration": "1562994555796365352",
"gasRatio": 1,
"gasLimit": 1000000,
"delay": "0",
"chainId": 1024,
"actions": [

以下のエラーが出る場合があります。 chain_id ですが 1020 を指定する必要があります。 1024 はメインネット用のIDで、iWalletのデフォルト値です。

ERROR: send tx error rpc error: code = Unknown desc = VerifyError invalid chain_id, should be 1020, yours:1024

IDを 1020 と指定してコントラクトをpublishしてください。以下のようにトランザクションハッシュとコントラクトに割り当てられたIDが返却されます。

$ iwallet --server localhost:30002 --account admin --chain_id=1020 publish HelloWorld.js HelloWorld.abi
Connecting to server localhost:30002 ...
Sending transaction...
Transaction:
{
"time": "1562995429343213531",
"expiration": "1562995519343213531",
"gasRatio": 1,
"gasLimit": 1000000,
"delay": "0",
"chainId": 1020,
"actions": [
{
...
}
Transaction has been sent.
The transaction hash is: BJ2FNEfyhggmEAnPFHy2MPsonhK1wJYvRHdz1HC3FAuV
Checking transaction receipt...
Transaction receipt:
{
"txHash": "BJ2FNEfyhggmEAnPFHy2MPsonhK1wJYvRHdz1HC3FAuV",
"gasUsage": 249207,
"ramUsage": {
"admin": "498"
},
"statusCode": "SUCCESS",
"message": "",
"returns": [
"[\"ContractBJ2FNEfyhggmEAnPFHy2MPsonhK1wJYvRHdz1HC3FAuV\"]"
],
"receipts": [
]
}
SUCCESS! Transaction has been irreversible
The contract id is: ContractBJ2FNEfyhggmEAnPFHy2MPsonhK1wJYvRHdz1HC3FAuV
  • Transaction hash: BJ2FNEfyhggmEAnPFHy2MPsonhK1wJYvRHdz1HC3FAuV
  • Contract id: ContractBJ2FNEfyhggmEAnPFHy2MPsonhK1wJYvRHdz1HC3FAuV

デプロイしたコントラクトを呼び出してdeveloperという文字列を hello 関数へ渡してみます。 hello, developer が返ってきました。

$ iwallet --server localhost:30002 --account admin --chain_id=1020 call "ContractBJ2FNEfyhggmEAnPFHy2MPsonhK1wJYvRHdz1HC3FAuV" "hello" '["developer"]'
...
Transaction receipt:
{
"txHash": "7P6V1qTQXDhGaXaCYWVArrXWs2fExQ42Y9RTYYb4pYP7",
"gasUsage": 33745,
"ramUsage": {
},
"statusCode": "SUCCESS",
"message": "",
"returns": [
"[\"hello, developer\"]"
]
,
"receipts": [
]
}

トランザクションハッシュから同じ内容をいつでも確認できます。

$ iwallet receipt 7P6V1qTQXDhGaXaCYWVArrXWs2fExQ42Y9RTYYb4pYP7

サンプルコードの実行は以上です。JSが使えるので簡単ですね。

IRC20トークンの発行

IRC20トークンはIOSTにおけるトークン実装の標準で、EthereumにおけるERC20のようなトークンです。但し、インターフェースや実装はERC20とは異なりますので確認した上で使用してください(特にメインネット上で行う場合)。[7]

IOSTでは token.iost として既にトークンのコントラクトが用意されています。IRC20トークンを発行したい場合は、パラメータを渡して token.iost コントラクトを呼び出すだけです。以下のようなファンクションが定義されています。ここではIRC20トークンを作成および発行し、2つのアカウント間でのトークンの授受をテストしてみます。

// create tokenSymbol 
create(tokenSymbol, issuer, totalSupply, configJson);
issue(tokenSymbol, to, amountStr);
transfer(tokenSymbol, from, to, amountStr, memo);
transferFreeze(tokenSymbol, from, to, amountStr, unfreezeTime, memo);
destroy(tokenSymbol, from, amountStr);
// query interfaces
balanceOf(tokenSymbol, from);
supply(tokenSymbol);
totalSupply(tokenSymbol);

create(tokenSymbol, issuer, totalSupply, configJson)

まずは create でトークンを作ります。tokenSymbolは2文字以上の文字列で_も使用可能とのことです。ここではシンボルを testtoken としています。issuerは基本的にアカウントですが、コントラクトをissuerとすることもできます。

コントラクトがissuerの場合は対象のコントラクトが別のコントラクトをコールする際に別のコントラクトからトークン発行をできるように許可することができます。その際に呼び出しは blockchain.call ではなく blockchain.callWithAuthority を使用します。

$ iwallet call token.iost create '["testtoken", "admin", 2
1000000000, {"decimal": 8, "fullName": "token for test"}]' --account admin --chain_id=1020

以下がサポートされているconfigjsonの項目です。

{
"decimal": number between 0~19,
"canTransfer": true/false, the token can not be transferd if canTransfer is false,
"fullName": string describes the full name of the token
}

まずは iwallet call token.iost create でIRC20トークンを作成してください。

issue(tokenSymbol, acc, amountStr)

token.iost を使用してIRC20トークンの作成ができました。次に issue を使用してadminアカウントとbankoneアカウントでトークンを発行してみます。

adminアカウント側の操作です。

$ iwallet call token.iost issue '["testtoken", "admin", "1000"]' --account admin --chain_id=1020
...
The transaction hash is: 4b59MbvxqJGYRkFFq254h6xqVmKJccq87uPxLptr6ggo
Checking transaction receipt...
Transaction has been sent! Waiting for being packed...Transaction receipt:
{
"txHash": "4b59MbvxqJGYRkFFq254h6xqVmKJccq87uPxLptr6ggo",
"gasUsage": 7430,
"ramUsage": {
"admin": "51"
},
"statusCode": "SUCCESS",
"message": "",
"returns": [
"[]"
],
"receipts": [
{
"funcName": "token.iost/issue",
"content": "[\"testtoken\",\"admin\",\"1000\"]"
}
]
}

bankoneというアカウントを作成してから、トークン発行してみます。

$ iwallet --account admin account create bankone --initial_balance 10 --initial_gas_pledge 10 --initial_ram 10 --chain_id=1020
...
The IOST account ID is: bankone
Owner permission key: CAA68PYxMMSzxt4SBTAktTveqJLoWqzeu7V8F4KAcC2P
Active permission key: CAA68PYxMMSzxt4SBTAktTveqJLoWqzeu7V8F4KAcC2P
...
$ iwallet call token.iost issue '["testtoken", "bankone", "100.5"]' --account admin --chain_id=1020
...
The transaction hash is: EFKZXNgcS4hNxSjV8t7TJh3DB3J5Fh7oyppKKHEKMJ97
Checking transaction receipt...
Transaction receipt:
{
"txHash": "EFKZXNgcS4hNxSjV8t7TJh3DB3J5Fh7oyppKKHEKMJ97",
"gasUsage": 7490,
"ramUsage": {
"admin": "53"
},
"statusCode": "SUCCESS",
"message": "",
"returns": [
"[]"
],
"receipts": [
{
"funcName": "token.iost/issue",
"content": "[\"testtoken\",\"bankone\",\"100.5\"]"
}
]
}

トークン発行は完了です。

transfer(tokenSymbol, accFrom, accTo, amountStr, memo)

transfer ではaccFromからaccToへamountStrだけトークンを送信します。memoはこの送付についてのコメントなどを512バイト以下の文字列で付与できます。adminアカウントからbankoneアカウントへ住宅のデポジットを送ってみたいと思います。

memoに Security deposit for house と入れてみました。

$ iwallet call token.iost transfer '["testtoken", "
admin", "bankone", "0.5", "Security deposit for house"]' --account admin --chain_id=1020
...
The transaction hash is: EG1Uj3cFCbWdUWzUwkdcBMW9dDrasVW1Cn6WCpwdyLcq
Checking transaction receipt...
Transaction receipt:
{
"txHash": "EG1Uj3cFCbWdUWzUwkdcBMW9dDrasVW1Cn6WCpwdyLcq",
"gasUsage": 8820,
"ramUsage": {
},
"statusCode": "SUCCESS",
"message": "",
"returns": [
"[]"
],
"receipts": [
{
"funcName": "token.iost/transfer",
"content": "[\"testtoken\",\"admin\",\"bankone\",\"0.5\",\"Security deposit for house\"]"

}
]
}

adminアカウントからbankoneへ 0.5 testtoken 送付したので、adminアカウントの残高は 999.5 testtoken です。

またbankoneはadminアカウントから 0.5 testtoken 受け取ったので 110 testtoken へ残高は増加しているはずです。

balanceOf(tokenSymbol, acc)

balanceOf を使用して対象トークンのアカウント残高を確認してみましょう。adminアカウントは 999.5 testtoken、bankoneアカウントは 110 testtoken であることが確認できました。

$ iwallet call token.iost balanceOf '["testtoken", "admin"]' --account admin --chain_id=1020
...
The transaction hash is: DobzkoemmDZr7P9bTEacdFkdEcVgcaCJD7RVuMCovrbu
Checking transaction receipt...
Transaction receipt:
{
"txHash": "DobzkoemmDZr7P9bTEacdFkdEcVgcaCJD7RVuMCovrbu",
"gasUsage": 4675,
"ramUsage": {
},
"statusCode": "SUCCESS",
"message": "",
"returns": [
"[\"999.5\"]"
]
,
"receipts": [
]
}

bankoneアカウントの残高確認です。

$ iwallet call token.iost balanceOf '["testtoken", "bankone"]' --account admin --chain_id=1020
...
The transaction hash is: CmJQxCz5xnUnayW5no974GTzfr7ZnFHkQdTUAgijC4aU
Checking transaction receipt...
Transaction receipt:
{
"txHash": "CmJQxCz5xnUnayW5no974GTzfr7ZnFHkQdTUAgijC4aU",
"gasUsage": 4675,
"ramUsage": {
},
"statusCode": "SUCCESS",
"message": "",
"returns": [
"[\"101\"]"
]
,
"receipts": [
]
}

その他にもトークンを一定時間凍結する transferFreeze やトークンをバーンする destroy が実装されています。

ローカルノードの起動とサンプルコードおよびIRC20トークンのテストは以上です。

まとめ

  • IOST はスマートコントラクトが動作するパブリックブロックチェーンとしてローンチされ既に大きなコミュニティを形成している
  • スケーラビリティを達成するために EDS(Efficient Distributed Sharding)という『Sharding』を実装し 100,000 TPS を目指している
  • アカウント操作やコントラクトのデプロイにはiWalletのクライアントが必要となる
  • IOSTでは token.iost として既にトークンコントラクトが実装されている
  • コントラクトはJavascriptで開発できるためJS経験者には学習コストが低いと想定される

--

--

Yuya Sugano
Yuya Sugano

Written by Yuya Sugano

Cloud Architect and Blockchain Enthusiast, techflare.blog, Vinyl DJ, Backpacker. ブロックチェーン・クラウド(AWS/Azure)関連の記事をパブリッシュ。バックパッカーとしてユーラシア大陸を陸路横断するなど旅が趣味。

No responses yet