Ethereumのライブラリとして有名なのはおそらくweb3.jsでしょう。
しかし、Rubyist(のはしくれ)としては、Ethereumを使ったアプリもRubyで開発したいな〜
そう、思ってました。
そこで、EthereumのRuby実装のライブラリであるethereum.rbを使って、Ethereumに接続し、スマートコントラクトを実行するところまで試してみました。
(その後、その勢いで、具体的なアプリケーションまで作ってみました)
##1.事前準備
1. gethのインストール
今回はローカル環境でブロックチェーンを動かすので、gethをインストールする。
手順は以下を参照↓
https://github.com/ethereum/go-ethereum/wiki/Installation-Instructions-for-Mac
2. プライベートネットでgethを起動
genesisファイルを作成して、プライベートネットでgethを起動する。
genesisファイルは以下の通り。
{
"nonce": "0x0000000000000042",
"timestamp": "0x0",
"parentHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"extraData": "0x0",
"gasLimit": "0xffffffff",
"difficulty": "0x4000",
"mixhash": "0x0000000000000000000000000000000000000000000000000000000000000000",
"coinbase": "0x0000000000000000000000000000000000000000",
"alloc": {}
}
gethの起動コマンドは以下の通り。
今回はHTTP-RPCサーバーを有効にして起動する。
geth --networkid 10 --nodiscover --maxpeers 0 --datadir /Users/user1/eth/data_testnet
--mine --minerthreads 1 --rpc --rpcaddr "0.0.0.0" --rpcport 8545 --rpccorsdomain "*" --rpcapi "admin, db, eth,
debug, miner, net, shh, txpool, personal, web3" 2>> /Users/user1/eth/data_testnet/geth.log
その後、gethコンソール上でアカウントを作成して、マイニングを開始します。マイニングが開始されれば、hashrateが0より大きくなっているはずです。
geth attach rpc:http://localhost:8545
> personal.newAccount("pass0")
> personal.unlockAccount(eth.accounts[0], 'pass0', 1000000)
true
> miner.start(1)
> eth.hashrate
140956
##2.Smart Contractの準備
今回は毎度おなじみのコントラクトを使って、試してみます。
pragma solidity ^0.4.15;
contract HelloWorld {
string public greeting;
function HelloWorld(string _greeting) {
greeting = _greeting;
}
function setGreeting(string _greeting) {
greeting = _greeting;
}
function say() constant returns (string) {
return greeting;
}
}
##3. Smart Contractの実行
1. ethereum.rbのインストール
gem install ethereum.rb
2. コントラクトをデプロイする
今回はirbを使って、進めます。
> require 'ethereum'
=> true
geth.ipcとコントラクトのパスを定義します。
> ETHEREUM_ADDRESS = "/Users/user1/eth/data_testnet/geth.ipc"
=> "/Users/user1/eth/data_testnet/geth.ipc"
> CONTRACT_PATH="/Users/user1/eth/HelloWorld.sol"
=> "/Users/user1/eth/HelloWorld.sol"
IPC Clientを作成して、gethに接続して、コントラクトをデプロイします。
> client = Ethereum::IpcClient.new(ETHEREUM_ADDRESS)
=> #<Ethereum::IpcClient:0x007fb7c79fa458 @id=0, @log=true, @batch=nil, @formatter=#<Ethereum::Formatter:0x007fb7c79fa3b8>, @gas_price=22000000000, @gas_limit=4000000, @logger=#<Logger:0x007fb7c79fa368 @progname=nil, @level=0, @default_formatter=#<Logger::Formatter:0x007fb7c79fa2f0 @datetime_format=nil>, @formatter=nil, @logdev=#<Logger::LogDevice:0x007fb7c79fa2a0 @shift_size=1048576, @shift_age=0, @filename="/tmp/ethereum_ruby_http.log", @dev=#<File:/tmp/ethereum_ruby_http.log>, @mon_owner=nil, @mon_count=0, @mon_mutex=#<Thread::Mutex:0x007fb7c79fa228>>>, @ipcpath="/Users/user1/eth/data_testnet/geth.ipc"
いよいよ、コントラクトをデプロイします。
createメソッドはオブジェクト指向で言うところのインスタンスの生成のようなものです。
contractというインスタンスを生成し、deploy_and_waitメソッドでデプロイします。
> contract = Ethereum::Contract.create(file: CONTRACT_PATH, client: client)
=> #<HelloWorld:0x007fb7c71dedc8>
> address = contract.deploy_and_wait("Hello, World!")
=> "0x3f2033e41c80647bf3bdeb9b08128bec5972ff46"
このcontractを使って、デプロイしたコントラクトのメソッドを実行します。
まず、sayメソッドを呼び出してみます。
> contract.call.say()
=> "Hello, World!"
コンストラクタで指定した"Hello, World!"が返ってきました!
次にsetGreetingメソッドを実行してみます。
> contract.transact_and_wait.set_greeting("Hello, Ruby Ethereum!")
=> #<Ethereum::Transaction:0x007fb7c7b706e8 @mined=true, @connection=#<Ethereum::IpcClient:0x007fb7c79fa458 @id=0, @log=true, @batch=nil, @formatter=#<Ethereum::Formatter:0x007fb7c79fa3b8>, @gas_price=22000000000, @gas_limit=4000000, @logger=#<Logger:0x007fb7c79fa368 @progname=nil, @level=0, @default_formatter=#<Logger::Formatter:0x007fb7c79fa2f0 @datetime_format=nil>, @formatter=nil, @logdev=#<Logger::LogDevice:0x007fb7c79fa2a0 @shift_size=1048576, @shift_age=0, @filename="/tmp/ethereum_ruby_http.log", @dev=#<File:/tmp/ethereum_ruby_http.log>, @mon_owner=nil, @mon_count=0, @mon_mutex=#<Thread::Mutex:0x007fb7c79fa228>>>, @ipcpath="/Users/user1/eth/data_testnet/geth.ipc", @default_account="0x394083a0212f7781a31d774df1f3e0b9610e8eef">, @id="0x57546d8bb1c593bab10eb71ab4babcae337db4d71b76eed1f8425499efe2e5af", @input="0xa41368620000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000001548656c6c6f2c205275627920457468657265756d210000000000000000000000", @input_parameters=["Hello, Ruby Ethereum!"]
sayメソッドをもう一度呼び出すと、
> contract.call.say()
=> "Hello, Ruby Ethereum!"
変数の値が更新されていることが分かります。
##4. まとめ
以上の手順で、ethereum.rbを使って、ブロックチェーンに接続し、コントラクトを実行できることが確認できました。Webアプリの世界ではまだまだ、Ruby(on Rails)での開発も盛んなので、RubyによるEthereumのアプリ開発も候補に入れてみてはいかがでしょうか?
ちなみに、その後、トークンを発行し、それをトレードに出すというデモ用のアプリをRuby on Railsで作ってみました。まだまだ、課題も多いですが、ご参考までにどうぞ。
https://github.com/shiki-tak/token-trader-app