RubyOnRails/Ethereumとの連携

f:id:AK474747:20190822004601p:plain

プログラミングスクールの課題で個人アプリの作成という課題がある。

個人的にはすごく重きを置いているカリキュラムなんだけれども、とにかく自分の作りたいものを作るというコンセプトで作成をしていくつもり。

で、僕の作りたいものとしてどうしてもスマートコントラクトの機能を使いたい。

スクールの課題ということもあるので、スマートコントラクトを実装したRailsのwebアプリケーションを作るという方針で行こうと思ってます。

ネット上を調べたところ、railsイーサリアムに接続してコントラクトコードを実行するという手法があることがわかったので、簡単にまとめようかなと思います。

動作環境

Rails v5.2.3

・ethereum.rb v2.2

・Ganache v2.1.0

 rails newでプロジェクト作成

いつも通りですね。プロジェクトを作ります。

rails new ethereum-test

gemのthereum.rbをインストール

このgemが今回の肝とも言えるかもしれません。

イーサリアムサーバーに接続し、コントラクトコードの実行を可能にするgemです。

Gemfileにethreum.rbを記述してbundle installします。

// Gemfileに記載
gem 'ethereum.rb'

// ターミナルで実行
bundle install

コントラクトコードの実装

プロジェクトのルートパス配下にcontractsフォルダを作成し、コントラクトファイルを作成して実装します。

ethereumのコントラクトを実装するには、solidityという言語を使用します。

コードの説明は別日に基礎からブログにまとめていこうかと思うのですが、ごく簡単な処理を記述しています。

機能としては、デプロイ時に渡した文字列を呼び出したり、デプロイしたオーナーのアドレス/残高を取得できるだけのものになっています。

contracts/HelloWorld.sol

pragma solidity ^0.4.24;

contract HelloWorld {
    string public greeting;
    address public owner;

    function HelloWorld(string _greeting) {
        greeting = _greeting;
        owner = msg.sender;
    }

    function greet() constant public returns (string) {
        return greeting;
    }

    function getBalance() constant public returns (uint balance) {
        return owner.balance;
    }

    function getAddress() constant public returns (address) {
        return owner;
    }
}

コントラクトコードの実装

コントラクトコードを記述したので、TopControllerというコントローラーファイルを作成します。

ここの記述でethereum.rbを利用したEthereumへの接続を実施を行います。

app/controllers/top_controller.rb

class TopController < ApplicationController
    ETHEREUM_TOKEN_PATH = "#{Dir.pwd}/contracts/HelloWorld.sol"
    GANACHE_URL = 'HTTP://127.0.0.1:7545'
  
    def index
      @client = Ethereum::HttpClient.new(GANACHE_URL) #①
      @contract = Ethereum::Contract.create(file: ETHEREUM_TOKEN_PATH, client: @client) #②
      @contract.deploy_and_wait('Hello, World!') #③
    end
end

①ではGanacheに接続するための@clientオブジェクトを作成します。GANACHE_URLにはGanacheアプリケーションのRPC SEVERに表示されているURLを入力します。

②ではcreateメソッドを使ってcontractインスタンスを生成しています。

③で作成したコントラクトをブロックチェーン上にデプロイします。

ちなみにviewではこんな記述にしています。

app/views/top/index.html.erb

Markup
<! -- index.html.erb -->
<div class="container">
  <h3>Ethereum.rb テストページ</h3>
  <p>アドレス: <%= @contract.call.get_address() %></p>
  <p>残高: <%= @contract.call.get_balance()%></p>
  <p>GreetMethod: <%= @contract.call.greet() %></p>
</div>
Markup
 @contract.call.get_address()

これだけで、HelloWorld.solに記述したfunctionを呼び出すことができます。

Ganacheの起動

アプリと連携させるためにGanacheを起動させます。

Ganacheはイーサリアム開発用のパーソナルブロックチェーンです。

起動するだけでアカウント・残高・契約作成・ガスコストなどを確認できるので、ブロックチェーン関連のアプリケーションを作成した場合に、テストとして有用です。

ブラウザで動作確認

アプリを起動させて、http://localhost:3000/にアクセスします。

bundle exec rails s

こんな感じのサイトにアクセスできればOKです。

f:id:AK474747:20190822004433p:plain

うーん、たったこれだけではあるんだけど、概念理解にすごく時間がかかってしまった。

ほんとはsolidityを使ったコントラクトコードとフロントエンドの連携は、web3.jsっていうjavascriptフレームワークを使ったりするらしいんですが・・。

個人アプリではそこまで新機能もりもりにするのはちょっとつらいので、ethereum.rbを使って連携をして、Railsコントローラの感覚に落とし込んでからコントラクトコードをビューで反映する、という手法で行こうかなと思っています。