DesignSpark Electrical Logolinkedin
Menu 検索
フォーラムで質問

Raspberry PiでEthereumを探索する - パート3: プライベートブロックチェーンでの取引き

それぞれの資産の移動、イーサリウムのマイニング、スマートコントラクトの動作について

パート1ではEthereumの基本について調査を行った。具体的には、イーサリウムのためのgethクライアントソフトウェアのインストールから、アカウントの作成、基本的なテストの動作確認までを行った。

パート2では、まず簡単にパート1について再度確認、解説し、最初の2つのノードがピアとして独自のプライベートブロックチェーンを作成した。

そしてパート3となる本記事ではプライベートのブロックチェーンにて実際に取引を行う。まず初めに、事前に用意した資産を移動し、イーサリウムをマイニングした後、スマートコントラクトを実行する。これらはイーサリウムにおいて、最も面白い部分だろう。

設定 / gethの更新

まず、今回改めてRaspberry Piを再インストールすることにした。最初にRaspbian Liteが読み込まれてから、sudo apt-get updateとsudo apt-get upgradeコマンドで更新を行う。

gethクライアントの最新ビルドバージョンを実行したい場合は、この執筆時の時点でRaspianに標準でインストールされているgolangのパッケージ版は古すぎると思われたため、インストールされている場合はまずgolangを一度削除しよう。以下のコマンドで削除できる。

$ sudo apt-get remove golang
$ sudo apt-get remove autoremove

もしスクラッチ(何もない状態)から始める場合は、gitツールと、その他の依存関係が必要となる。これらは以下のコマンドでインストールできる。

$ sudo apt-get install git golang libgmp3-dev

また、現在はgethとgolangのバージョンに少し問題があるらしいことを確認した。具体的にはリリースされたgethの1.8のブランチではgolangの1.9.2が動作しているのだが、現在raspbianに標準でインストールされているバージョンでは問題があるようだった。そのため、以下のコマンドを利用してgolangのバージョン1.9.2をインストールする。

$ wget https://dl.google.com/go/go1.9.2.linux-armv6l.tar.gz
$ sudo tar -C /usr/local -xzf go1.9.2.linux-armv6l.tar.gz
$ export PATH=$PATH:/usr/local/go/bin

また、上記コマンドの最後にあるように、exportコマンドを利用して環境パスを~/.profileに追加すると、OSにログインした際に新たにインストールされたgoバイナリが常に利用することが可能になるのだ。

golangをインストールした後に、gethのバージョン1.8を用意、ビルドとインストールが可能になる。以下の通りだ。

$ mkdir src
$ cd src
$ git clone -b release/1.8 https://github.com/ethereum/go-ethereum.git
$ cd go-ethereum
$ make
$ sudo cp build/bin/geth /usr/local/bin/

これらのプロセスはパート1で詳しく解説しているが、最新のgethクライアントツールをインストールしたい場合は、こちらを参考に再度インストールを行ってほしい。

プライベートブロックチェーンの作成

一度環境について振り返っておこう。パート1からここまで、マシン2台を利用して検証と解説を行ってきた。一台はRasberry Pi、もう一台はノートパソコンである。それぞれのマシンはブロックチェーン上の一つのノードとなり、パート2で紹介したプライベートなブロックチェーンには、この2台のノードのみが存在している。詳しくはパート2に目を通してくれると良いだろう。

さて、パート2では主にプライベートなブロックチェーンの作成と、2つのノードを用意して初期化を行うところまで進めた。今回、それらの方法について再度解説はしないので、各自必要に応じでパート2を振り返ってほしい。

パート2までできたのであれば、各ノードにてgethクライアントからadmin.peerseを実行すると上の図のような出力になるはずだ。上の図から2つのノードがピアであることが分かる。

資産の移動とマイニング

では各ノードのアカウントにて、イーサリウムの残高がどれだけ残っているのか確認してみよう。以下のコマンドで確認できる。

> web3.fromWei(eth.getBalance(eth.coinbase), “ether”)

上の図では設定されたアカウントの残高が0であることがわかる。

こちらのノートパソコンに設定されたアカウントには事前に用意しておいたイーサリウムが20だけあることが分かる。

実はパート2まではRaspberry Pi側のアカウントに事前にイーサリウムを用意しており、ノートパソコン側には用意していなかった。これには特に深い意味はないため、もしこちらの記事を読んで進めている方は、各ノードにおいて事前に用意する資産の量などは各自の好きにしてくれて構わない。

今回はノートパソコン上のアカウントからRaspberry Piへと送信を行った。そのためにはアドレスが必要となる。

では、以下のコマンドをノードパソコン側のノードで入力しよう。

> var pi = "0x1a49bcee41bff051b8ffd0a01d4a3be4485fd030";

> personal.unlockAccount(eth.coinbase, "")

> eth.sendTransaction({from: eth.coinbase, to: pi, value: web3.toWei(0.1, "ether")})

最初のコマンドではpiという変数名にRaspberry Pi側のアカウントを設定している。2番目のコマンドではアカウントのロックを解除し、3番目のコマンドではRaspberry Piへとイーサリウムを送信している。

この時点では、Raspberry Pi側とノートパソコン側の両方とも変化はないはずだ。これは「同期」が行われていないためだ。そこで、実際に取引をすすめるために、ノードパソコン側のノードでマイナー(マイニングするツール)を動作させる。

> miner.start()

最初に目につく“DAG”は、作業を行ったことを記録するための有効グラフデータ構造だ。これを生成した後に、マイニングと同期を開始する必要がある。

一度同期が開始すると、上の図のような出力となるはずだ。

では今度こそRaspberry Piで現在の残高を確認してみよう。上の図のように資産を受け取れていたら成功だ。

今回の検証では2つのノードしか存在しないため、マイニングの難易度(difficulty)も低いため、ノートパソコン側で動作するマイナーが事前に割り当てた20をすぐに超えるだろう。

マイナーを停止したいときは以下のコマンドから停止できる。

> miner.stop()

新しいブロックのストリームを生成するためにはマイナーを一つだけ動作させればいいことに注意してほしい。ここではマイニングに必要なリソースに制限がないマシンにおいて実行できる。

最初のスマートコントラクト

次に、グリーター(Greeter)をビルドしてイーサリウムでのHello worldスマートコントラクトを行ってみよう。このグリーターは「ブロックチェーン上に存在し、その入力に基づいて相互に通信できる誰とでも会話できるインテリジェントな存在」と表現されている。

“Solidity”と呼ばれる言語で書かれたスマートコントラクトについてはパート1に戻って確認してほしい。この言語はJavaに似ており、コンパイルすると実行のためのバイトコードへと変換される。もちろん、今回もノートパソコン側で動作させるために、そのコンパイラのインストールが必要となる。

$ sudo add-apt-repository ppa:ethereum/ethereum
$ sudo apt-get update
$ sudo apt-get install solc

PPAは既に設定されており、gethはインストールされているため、上記の最初のコマンドは今回のケースでは本当は必要ないものだ。

では実際にSolidityを利用してみよう。以下のSlidityコードを用意し、Greeter.solといファイル名で保存しよう。

contract Mortal {
    /* Define variable owner of the type address */
    address owner;

    /* This function is executed at initialization and sets the owner of the contract */
    function Mortal() { owner = msg.sender; }

    /* Function to recover the funds on the contract */
    function kill() { if (msg.sender == owner) selfdestruct(owner); }
}

contract Greeter is Mortal {
    /* Define variable greeting of the type string */
    string greeting;

    /* This runs when the contract is executed */
    function Greeter(string _greeting) public {
        greeting = _greeting;
    }

    /* Main function */
    function greet() constant returns (string) {
        return greeting;
    }
}

これを以下のコマンドでコンパイルする。

$ solc -o target --bin --abi Greeter.sol

上記の実行結果にはいくつかの警告が表示されているものの、指定したディレクトリにGreeter、Mortal、コントラクト用のabiファイルの4つのファイルが生成されている。

これをgethへと読み込むための最も簡単な方法はスクリプトを作成することだ。今回はこれをgreeter.jsとする。以下が完成したファイルだ。

var greeterFactory = eth.contract([{"constant":false,"inputs":[],"name":"kill","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[],"name":"greet","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[{"name":"_greeting","type":"string"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"}])

var greeterCompiled = "0x" + "608060405234801561001057600080fd5b5060405161039b38038061039b83398101806040528101908080518201929190505050336000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508060019080519060200190610089929190610090565b5050610135565b828054600181600116156101000203166002900490600052602060002090601f016020900481019282601f106100d157805160ff19168380011785556100ff565b828001600101855582156100ff579182015b828111156100fe5782518255916020019190600101906100e3565b5b50905061010c9190610110565b5090565b61013291905b8082111561012e576000816000905550600101610116565b5090565b90565b610257806101446000396000f30060806040526004361061004c576000357c0100000000000000000000000000000000000000000000000000000000900463ffffffff16806341c0e1b514610051578063cfae321714610068575b600080fd5b34801561005d57600080fd5b506100666100f8565b005b34801561007457600080fd5b5061007d610189565b6040518080602001828103825283818151815260200191508051906020019080838360005b838110156100bd5780820151818401526020810190506100a2565b50505050905090810190601f1680156100ea5780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b6000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff161415610187576000809054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff16ff5b565b606060018054600181600116156101000203166002900480601f0160208091040260200160405190810160405280929190818152602001828054600181600116156101000203166002900480156102215780601f106101f657610100808354040283529160200191610221565b820191906000526020600020905b81548152906001019060200180831161020457829003601f168201915b50505050509050905600a165627a7a72305820467ac32dfa208b06ba97f3a7f72d039f2f912938b54b9881c603d80f6b004df40029"

var _greeting = "Hello DesignSpark!"

var greeter = greeterFactory.new(_greeting,{from:eth.accounts[0],data:greeterCompiled,gas:1000000}, function(e, contract){
    if(e) {
      console.error(e); // If something goes wrong, at least we'll know.
      return;
    }

    if(!contract.address) {
      console.log("Contract transaction send: TransactionHash: " + contract.transactionHash + " waiting to be mined...");

    } else {
      console.log("Contract mined! Address: " + contract.address);
      console.log(contract);
    }
})

最初の2行には生成されたabiファイルとbinファイルの内容が含まれている。実際には、これらはコントラクトの機能について記述しており、greeterCompiledという変数はコンパイルされたバイトコードだ。

var greeterFactory = eth.contract(<contents of the file Greeter.abi>)

var greeterCompiled = "0x" + "<contents of the file Greeter.bin>"

_greetingという変数はその名の通り挨拶のメッセージのために定義されている。これはコントラクトが実行されると返されるものだ。

次に適したノードにおいてマイナーが動作できるか確認しよう。コントラクトをデプロイしたいマシンにおいてアカウントをアンロックする。今回の私たちの場合だと、ノートパソコン側のgethコンソールからminer.start()を再度実行し、Raspberry Piからコントラクトをデプロイする。

以下のコマンドをRaspberry Piにて入力しよう。なお、先ほど紹介したスクリプトをgreeter.jsとして保存しておこう。

> personal.unlockAccount(eth.coinbase, "")

> loadScript("greeter.js")

成功した!同期を行っているメッセージの中にコントラクトの取引が行われ、それがマイニングされるのを待っている通知と、マイニングが完了した通知を確認できる。

以下のコマンドで検証できる。

> eth.getCode(greeter.address)

Raspberry Piにて残高を確認すると、わずかだが減っていることが分かる。

資産は適切なマイナーへと移動した。この場合はノートパソコン側となるだろう。

最後に、次のコマンドでコントラクトを実行しよう。

> greeter.greet();

イーサリウムのwebサイトによると返信は即座に返ってくるだろう。これはブロックチェーン上に何も影響がなく、手数料であるgasコストもないためだ。

ドキュメント作成とデバッグ

イーサリウムのドキュメントは既に時代遅れであることに注意した方が良い。さまざまなWebサイトやウィキに情報が拡散されているため、統一した手順が見つからず、場合によってはうまくいかずに混乱するだろう。例えばgethのウィキにあるコントラクトのチュートリアルだ。これはgethからにSolidityのコンパイルを提案しているが、これは既にサポートされていないのだ。

多くのブロックチェーン技術と同様に、イーサリウムは攻撃と効率に対して耐性を持つように作られている、高速で開発が進む技術だ。しかし、開発よりもドキュメント作成のほうが遅れており、イーサリウムやその他ツールのバージョンについて気を付けrw正しいドキュメントを利用しなければうまく動作しないだろう。今回紹介したようなプライベートなネットワークにおいて、将来的に古いバージョンのソフトウェアなどが利用されることとなるが、これはあまりお勧めではないだろう。

もし現在なにも取引していない状態であるならば、以下のコマンドを利用してブロックチェーンをリセットできる。

$ geth removedb --datadir .designspark

しかし、再度実行する際には.jsonファイルにてネットワークの初期化を行わなければいけないことに注意しよう。

まとめ

ではここまでやってきてことについてまとめてみよう。

    1. Raspberry Piのような小さなノードが理論的にどのように大きなブロックチェーンに参加するのか、について紹介した。
    2. どのようにプライベートネットワークを設定するのかについてのデモを行った
    3. プライベートなブロックチェーンにてアカウント間でイーサリウムを送信し、スマートコントラクトのコンパイルからデプロイまでRaspberry Piにて行った。

ここまで紹介したことを参考に、さらにノードを増やし、スマートコントラクトを作成していくつかの便利な機能を実現することができるだろう。イーサリウムのブロックチェーン技術によって提供される機能の利点を有効的に利用していこう。

  — Andrew Back

Open source (hardware and software!) advocate, Treasurer and Director of the Free and Open Source Silicon Foundation, organiser of Wuthering Bytes technology festival and founder of the Open Source Hardware User Group.

7 Feb 2019, 9:15