Hyperledger Fabric で Ethereum のスマートコントラクトが動くらしい。
先日、以下の記事を見つけました。
Ethereum のスマートコントラクト教材を Hyperledger Fabric 上でやってみる
Hyperledger Fabric に EVM 載せようというプロジェクト Hyperledger Burrow がありますがもう動くようになっていたのですね!Hyperledger 1.3 あたりからですかね?
Hyperledger Fabricでイーサリアム・スマートコントラクトが実装可能に―BC基盤競争が加速
ちなみに Hyperledger Burrow プロジェクトのリポジトリはこちら。
サンプルでの動かし方もチュートリアルがありました。
最新バージョンではどうなんだろう?ということでやってみました。
環境構築
なにはともあれ、Ubuntu16:04+GoでのHyperledgerの開発環境を整えましょうか。
いつものようにDocker on LXDでまいります。
開発環境の構築
まずこちらのでご紹介した手順にて lxc の docker プロファイルを利用して Ubuntu16.04 のコンテナを作成します。
$ lxc launch -p docker ubuntu:xenial hyperledger-go
$ lxc exec hyperledger-go bash
~#
ここに go-lang と docker をインストールしていきます。米国のarchive.ubuntu.com サーバーはレスポンス遅いので理研のftpサーバーをaptのリポジトリとします。
# sed -i.bak -e "s%http://[^ ]\+%http://ftp.riken.go.jp/Linux/ubuntu/%g" /etc/apt/sources.list
# apt update && apt upgrade -y
# cd /tmp && wget https://dl.google.com/go/go1.11.linux-amd64.tar.gz
# tar -xvf go1.11.linux-amd64.tar.gz
# mv go /usr/local
# rm go1.11.linux-amd64.tar.gz
# cd ~/
# mkdir go
# vi~/.bashrc
以下の環境変数を追加してGO言語の準備は完了です。
export GOROOT=/usr/local/go
export GOPATH=$HOME/go
export PATH=$GOPATH/bin:$GOROOT/bin:$PATH
引き続き以下の手順で Docker & docker-compose をインストールしていきます。
# apt-get install -y \
apt-transport-https \
ca-certificates \
curl \
gnupg-agent \
software-properties-common
# curl -fsSL https://download.docker.com/linux/ubuntu/gpg | apt-key add -
# add-apt-repository \
"deb [arch=amd64] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) \
stable"
# apt-get update
# apt-get install -y docker-ce docker-ce-cli containerd.io
# docker -v
# docker run hello-world
# curl -L https://github.com/docker/compose/releases/download/1.23.2/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose
# chmod +x /usr/local/bin/docker-compose
でDockerの動作確認とdocker-composeのインストール OK です。
Hyperledger のダウンロード
Hyperledger Burrow プロジェクトのリポジトリからソースを cloneします。
また今回はHyperledgerそのものは EVM の動作確認用として使用するだけなのでFabric本体のダウンロードはせず、さくっとテストネットワークだけ立ち上げられるサンプルのプロジェクトのほうを使います。
# apt install -y make
# go get github.com/hyperledger/fabric-chaincode-evm
# cd $GOPATH/src/github.com/hyperledger/fabric-chaincode-evm
# make fab3
# cd $GOPATH/src/github.com/hyperledger
# git clone https://github.com/hyperledger/fabric-samples.git -b release-1.4
# cd fabric-samples
# ./scripts/bootstrap.sh
# export PATH=$PWD/bin:$PATH
# cd first-network
# ./byfn.sh up
で、テストネットが起動できれば OK です。
スマートコントラクトの環境構築
EVM チェインコードのインストール
Fabric上でスマートコントラクトを実行するモジュール"チェインコード"に対してEVMサポートを追加します。
いったん、テストネットワークを止めます。
# ./byfn.sh down
# vi docker-compose-cli.yaml
以下のボリュームを追加します。
- ./../../fabric-chaincode-evm:/opt/gopath/src/github.com/hyperledger/fabric-chaincode-evm
テストネットを再度、起動します。
# ./byfn.sh up
以下のインストールスクリプトを作成します。
# vi scripts/installevm.sh
#!/bin/bash
export CORE_PEER_MSPCONFIGPATH=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
export CORE_PEER_ADDRESS=peer0.org1.example.com:7051
export CORE_PEER_LOCALMSPID="Org1MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=/opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
peer chaincode install -n evmcc -l golang -v 0 -p github.com/hyperledger/fabric-chaincode-evm/evmcc
peer chaincode instantiate -n evmcc -v 0 -C mychannel -c '{"Args":[]}' -o orderer.example.com:7050 --tls --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
コンテナ内部で実行いたします。
# chmod a+x scripts/installevm.sh
# docker exec -it cli scripts/installevm.sh
これで Ethereumのスマートコントラクトを動かす準備が整いました。
サンプルの実行
本家サイトのチュートリアルにある通り、試しにバイナリのチェインコードを実行してみます。
# docker exec -it cli peer chaincode invoke -n evmcc -C mychannel -c '{"Args":["0000000000000000000000000000000000000000","608060405234801561001057600080fd5b5060df8061001f6000396000f3006080604052600436106049576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806360fe47b114604e5780636d4ce63c146078575b600080fd5b348015605957600080fd5b5060766004803603810190808035906020019092919050505060a0565b005b348015608357600080fd5b50608a60aa565b6040518082815260200191505060405180910390f35b8060008190555050565b600080549050905600a165627a7a723058203dbaed52da8059a841ed6d7b484bf6fa6f61a7e975a803fdedf076a121a8c4010029"]}' -o orderer.example.com:7050 --tls --cafile /opt/gopath/src/github.com/hyperledger/fabric/peer/crypto/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem
以下のような OK メッセージが表示されれば OKです。
2019-03-20 08:29:08.382 UTC [chaincodeCmd] chaincodeInvokeOrQuery -> INFO 001 Chaincode invoke successful. result: status:200 payload:"5bf7e5ecd6e75cce05552c6cbd628d9616e4e09b"
Ethereum スマートコントラクトの開発と動作確認
Fab3 の準備
Hyperledger ネットワークを Ethereum のネットワークとして web3.js と対話させるためのサービスとして、Hyperledger Burrow プロジェクトでは Fab3 が提供されています。
以下のコマンドで Fab3 を起動します。
# cd $GOPATH/src/github.com/hyperledger/fabric-chaincode-evm
# vi fab3_env.sh
以下の環境設定ファイルを作成
# Environment Variables for Fab3:
export FAB3_CONFIG=${GOPATH}/src/github.com/hyperledger/fabric-chaincode-evm/examples/first-network-sdk-config.yaml
export FAB3_USER=User1
export FAB3_ORG=Org1
export FAB3_CHANNEL=mychannel
export FAB3_CCID=evmcc
export FAB3_PORT=5000
source して fab3 を起動します。
# source fab3_env.sh
# ./bin/fab3
{"level":"info","ts":1553072051.4909546,"logger":"fab3","caller":"cmd/main.go:149","msg":"Starting Fab3","port":5000}
無事に起動出来たようなのでバックグラウンドに持っていくか別ターミナルを立ち上げましょう。
Web3.js のインストール
Burrow プロジェクトのチュートリアルにもありますが、web3.jsのバージョンは"0.20.2"が宜しいようです。(最新版入れたらダメでした。)
# npm install -g web3@0.20.2
# node
>
でnodeのREPLモードに入ります。さっそくweb3.jsからHyperledgerネットワークにアクセスしてみましょう。
> Web3 = require('web3')
{ [Function: Web3]
providers:
{ HttpProvider: [Function: HttpProvider],
IpcProvider: [Function: IpcProvider] } }
> web3 = new Web3(new Web3.providers.HttpProvider('http://localhost:5000'))
Web3 {
_requestManager:
RequestManager {
provider:
...
> web3.eth.accounts
[ '0x955b022fdbe8f163d53e8bfd9aaddd3c8377553f' ]
> web3.eth.defaultAccount = web3.eth.accounts[0]
'0x955b022fdbe8f163d53e8bfd9aaddd3c8377553f'
これで準備完了です。HyperledgerのネットワークはバッチリEthereumネットワークとして認識されていますね!
Remix でバイナリの生成
ローカルにSolidity環境を構築するのはちょっと大変、というか今どきの推奨でもないので、ささっとオンラインの Remix を使ってしまいます。
まずはSolidityの本家マニュアルに掲載されているSimpleStrageSampleを動かしてみましょう。
pragma solidity >=0.4.0 <0.7.0;
contract SimpleStorage {
uint storedData;
function set(uint x) public {
storedData = x;
}
function get() public view returns (uint) {
return storedData;
}
}
このコードをコピーして Remixのエディタで貼り付け、コンパイラを "0.4.25" にセットします。
コンパイラのロードができたら Ctrl+S
で保存するとコンパイラが走ります。
エラーがあった場合はコンパイラのバージョンを確認しましょう。0.5.x以上ではコンパイルできません。
エラーなどがなければABI
とBytecode
のボタンをクリックしてそれぞれ適当なエディタに貼り付けておきます。
実は上記で最初にEVMの動作確認したバイナリがこのSimpleStorageのバイナリです。
peerコマンドではなく、web3経由でアクセスしてみたいと思います。
まずはABIから行きましょう。以下のようにSimpleStorageABI
を定義します。
> simpleStorageABI = [
... {
... "constant": false,
... "inputs": [
...
つづいてバイナリコードを変数に入れておきます。
> simpleStorageBytecode = '608060405234801561001057600... '
これらを合わせてスマートコントラクトとし、ネットワーク上にデプロイします。
> SimpleStorage = web3.eth.contract(simpleStorageABI)
ContractFactory {
eth:
Eth {
_requestManager: RequestManager { provider: [Object], polls: {}, timeout: null },
...
> deployedContract = SimpleStorage.new([], {data: simpleStorageBytecode})
Contract {
_eth:
Eth {
_requestManager: RequestManager { provider: [Object], polls: {}, timeout: null },
こちらでデプロイされたスマートコントラクトにアクセスするインタフェースのdeployedContract
が取得できました。
また、今回は新規作成ですがデプロイ済みのスマートコントラクトには以下のメソッドでもアクセス可能です。
> myContract = SimpleStorage.at(web3.eth.getTransactionReceipt(deployedContract.transactionHash).contractAddress)
Contract {
_eth:...
アドレスがわかっている場合はもっと簡単に
> myContract = SimpleStorage.at('0x127d9f8f199e363f2aa57dd125abb7b2d4f1c19a')
Contract {
_eth:
Eth {
_requestManager: RequestManager { provider: [Object], polls: {}, timeout: null },
...
と直接、指定でもOKです。
それではこのスマートコントラクトのset
とget
メソッドを呼び出してみましょう。
> myContract.set(10)
'6e049d491457e1c2862a83183ced3be8ac841c0bc83e2ed079127a805a2fbdfb'
> myContract.get().toNumber()
10
Hyperledger FabricのブロックチェーンへのEthereumコントラクトからの書き込みと読み込み、ばっちりできていますね!
このようにABI
とBytecode
からSmartContract
を生成し、デプロイするか既存のアドレスを指定してインスタンスを取得し、メソッドを呼び出す、という一連の流れが確認できました。
もう少しだけ複雑なスマートコントラクト
以下のサイトのチュートリアルのスマートコントラクトを試してみます。
上記サイトの後半にあるスマートコントラクトの完全版のコードをコピーしてRemixに貼り付け、ABIとBytecodeを取得します。例によってコンパイラは0.40.2x
を指定して下さい。
準備が整ったらweb3.jsでの作業を開始します。
> gradeABI = [
{
"constant": true,
"inputs": [
{
"name": "",
"type": "bytes32"
}
],
...
> gradeBytecode = '6060604052341561000f57600080fd5b60405161069f38 ...`
> GradeContract = web3.eth.contract(gradeABI)
> myGrade = GradeContract.new(['John','James'], {data: gradeBytecode})
GradeContract.new
で第一引数にコンストラクタに渡す値を指定しますが、ちゃんと動いていますね!
それではメソッドを叩いてみます。
> myGrade.giveGradeToStudent('John', 'A+')
'5ddbf87d76b011339d02128d1c6889c0fade7dad667af43f835e5841724c9e84'
> myGrade.getGradeForStudent("John")
'A+'
ばっちり良好です!
まとめ
Solidity0.40.25
でコンパイルしたバイナリはばっちり動作することがわかりました。
ローカルのHyperledgerでEVMのスマートコントラクト開発、アリじゃないかな?!ガス代かからないしコミット早いし。
というわけで引き続きSolidity0.5.x
やもうちょっと複雑なスマートコントラクトなどにも挑戦してみたいと思います。
本日は以上です。