Blockchain as a Service「kaleido」の使用感を確認したよ

前回の予告どおり、今回はBaaSの「kaleido」の使用感についてです。 よくあるブロックチェーンのサンプルやチュートリアルのようなことを、kaleidoではどうやるかという観点で確認してみました。 情報源は基本的に公式サイト(英語)ですが、Qiitaで記事を書かれている方が3名ほどいらっしゃいましたのでそちらも参考にしております。

アカウント作成~ノードの作成まで

AWSアカウントの作成

ググれば大丈夫のはずなので本記事では省略。クレジットカード情報が必要。12か月は無料とのこと。

kaleidoアカウントの作成

AWSマーケットプレイスのkaleidoのサイト右上の"Continue to Subscribe"ボタンをクリックすると、kaleidoのサイトに移動するので画面の案内に従ってアカウントを作成します。 f:id:handatec:20200626134217p:plain 今回は1アカウントのみアクセス可能なStarterプラン(無料プラン)としました。

この時点で"Membership ID"と"Organization ID"が付与されるようです。

ネットワーク(コンソーシアム)の作成

ここからネットワーク(コンソーシアム)、環境、ノードの順に作成していきます。 f:id:handatec:20200626134411p:plain

2020年6月現在でのkaleidoの画面は新画面(NEW CONSOLE)が規定になっています。 ネットで調べると出てくる手順では、旧画面(OLD CONSOLE)で記載されているので、言葉が異なっていること注意が必要です。

旧ボタン:Create Consortium

新ボタン:CREATE NETWORK

また、"OLD CONSOLE"でしか表示されない画面がある(例:Ether Poolに関連する画面)ことも注意が必要です。 本記事では、特に注釈がないものは新画面を想定しています。 ちなみに、旧画面へは画面右上にある"BACK TO OLD CONSOLE"ボタンで切り替え可能です。

ネットワーク名を適当に入力してNEXTボタンをクリック。 f:id:handatec:20200626134539p:plain ホームリージョンを設定してNEXTボタンをクリック。 今回はOhio(AWS、US-east-2)を選択。 f:id:handatec:20200626134559p:plain マルチリージョンにもできるけど、Starterプランなので選択できない。 このままFINISHボタンをクリック。 f:id:handatec:20200626134615p:plain この時点で"consortia_id"(コンソーシアムID)が付与されるようです。 kaleidoでは自動付与されるID類は"u0"で始まるみたいです。

環境(Environment)の作成

CREATE ENVIRONMENTボタンをクリック f:id:handatec:20200626134740p:plain プロトコルを選択。2020年6月現在ではEthereum系とCorda(beta)が選択可能。 今回はEthereum系を選択してNEXTボタンをクリック。 f:id:handatec:20200626134817p:plain

環境名を適当に入力。 今回はStarterプランなのでマルチリージョンは選択できません。 NEXTボタンをクリック。 f:id:handatec:20200626134831p:plain プロバイダを選択。 Geth、Quorum、Hyperledger Besuが選択可能。 今回はQuoram、コンセンサスアルゴリズムはRaftを選択してFINISHボタンをクリック。 f:id:handatec:20200626134842p:plain この時点で、"environment_id"(環境ID)が付与されるようです。 また、環境は複数作れるようです。

ノードの作成

CREATE NODEボタンをクリックして環境へノード追加します。 f:id:handatec:20200626135117p:plain メンバシップはprivateしか選べませんでした。プランによるのでしょう。 ノードの名前を適当に付けてNEXTボタンをクリック。 f:id:handatec:20200626135147p:plain

クラウドコンフィグレーションはとりあえず何もせずにNEXTボタンをクリック。 f:id:handatec:20200626135232p:plain ノードサイズはSmallしか選べませんでした。これもプランによるのでしょう。 「コンセンサス上の役割(Role in Consensus)」はあまり理解していませんが、もともと「署名者にする」にチェックが入っていたので、そのまま。 FINISHボタンをクリック。 f:id:handatec:20200626135244p:plain この時点でNode IDが付与されています。 しばらく待つとノードの状態がInitializing(オレンジ)からStarted(グリーン)に変わるはずです。 f:id:handatec:20200626135442p:plain 最初のノードを作成した際に、「System Monitor」というノードも自動で生成されます。 また、ノードはStarterプランでも複数作成できます。今回は3つのノード作成しました。(Node01、Node02、Node03) f:id:handatec:20200626135836p:plain ここまで実施すると、 ネットワーク(コンソーシアム)-環境-ノード-アカウント という構造になっているはずです。

メモ:アカウント、ウォレットについて

ノードを作成した際に、そのノードに紐づくアカウントが1つ生成されます。 画面左のメニュー MANAGE RESOURCES -> Nodes -> Walletの画面でアカウントの追加が可能です。 下の画面ショットでは、自動で生成されたアカウント1つ、手動で追加したアカウント1つが表示されています。 f:id:handatec:20200626140038p:plain WALLETもノードを作成した際に、アカウントと同時に生成されます。 Type(分類)は「Node Wallet」となっています。

スマートコントラクトのデプロイ、関数の利用

ノード情報を表示する画面の右側に2つのボタンが見えます。

  • CONNECT APP
  • IMPORT SMART CONTRACT

f:id:handatec:20200626140443p:plain

CONNECT APP:外部からの接続時における認証情報「App Cred」(旧画面でいう「App Credential」)を作成できます。

画面左のメニューの、MANAGE RESOURCES -> Apps & Integrations->Securityで表示される「App Creds」からも新しいCredの生成や確認が可能です。 f:id:handatec:20200626140814p:plain Credを生成すると、ID、パスワード、JSON/RPC HTTPエンドポイント、REST API Gatewayエンドポイントなどの情報が表示されます。 パスワードはCred生成直後しか表示されないので、メモし忘れた場合は再生成が必要です。

App Credは、IDとパスワードを":"(コロン)で繋げた文字列です。

{App Cred} = {ID}:{password}

truffle等で接続する際のJSON/RPC HTTPエンドポイントは以下のようになるはずです。

https://{App Cred}@{environment_id}-{Node ID}-rpc.{region}.kaleido.io/

また、REST API Gatewayエンドポイントは以下のようになります。(後述します)

https://{App Cred}@{environment_id}-{Node ID}-connect.{region}.kaleido.io/gateways/{API endpoint}/

IMPORT SMART CONTRACT:以下の4つの方法でコントラクトの配置ができます。

  1. Use our Token Factory
  2. Upload file with source code
  3. Paste compilation metadata
  4. Import from Github

f:id:handatec:20200626141111p:plain

本記事では、1.と2.を試しました。

Use our Token Factory(ERC20、ERC721トークンの作成)

Kaleidoが用意しているERC20、ERC721テンプレートからトークンを生成できます。 Kaleido Token Factory テンプレートは OpenZeppelinベースとのことです。 なので、このようなトークンを作る場合はコーディングレスです。

ちなみに、後述する「Upload file with source code」機能で、OpenZeppelinをimportしているソースコード単体をアップロードしてもコンパイルエラーとなります。

Upload file with source code(コントラクトソースコードのアップロード)

手持ちのSolidityコードをアップロードしてコントラクトを作成できます。複数のファイルをZIPでまとめてアップロードもできるようです。 今回は、前回記事で作成していたSimpleStorage.sol(よく見かけるやつ)を利用しました。

pragma solidity ^0.5.0;

contract simplestorage {
  uint public storedData;

  constructor(uint initVal) public {
    storedData = initVal;
  }

  function set(uint x) public {
    storedData = x;
  }

  function get() view public returns (uint retVal) {
    return storedData;
  }
}

アップロードすると、Solidityコードの各関数に対応するAPIが生成されます。

画面左のメニュー MANAGE RESOURCES -> Apps & Integrations -> Gateway API'sに生成したAPI endpointが表示されます。 アップロードした時点ではコンパイルがされるだけでデプロイまではされていないようです。 f:id:handatec:20200626141455p:plain

アップロードしたコントラクトのデプロイ

API endpointの一覧から当該エンドポイントを選択すると次の画面が表示されます。 f:id:handatec:20200626141739p:plain Gateway API Details画面の右上「VIEW GATEWAY API」ボタンをクリック

-> 任意のノードを選択して、「VIEW API」をクリック

-> 表示されたリンクをクリック

するとブラウザの別タブでAPIの一覧が表示されます。 イメージとしてはSwagger Editorのような画面で、API実行機能もついています。 f:id:handatec:20200626142423p:plain 最上行のPOST / はコンストラクタとなっており、これを動かすとコントラクトがデプロイされます。 当該行をクリックして展開し、BODY DATAの欄でEXAMPLEタブをクリックすると以下のような表示がされると思います。

f:id:handatec:20200626161458p:plain

^-?[0-9]+$の部分に適当な数字を上書きしてTRYボタンを押してみましょう。 デプロイのトランザクションが発行され、ブロックが生成されます。 コントラクトのstoredDataには上書きした数値が設定されたはずです。

コントラクトの関数の実行

同画面にget、set、storedDataのメソッドが並んでいました。 get関数で先ほどデプロイしたコントラクトの状態を見てみましょう。

f:id:handatec:20200626161509p:plain

get関数のREST APIアドレスは以下のようになっています。

https://{environment_id}-{Node ID}-connect.{region}.kaleido.io/gateways/{API endpoint}/{address}/get

{address}の部分はコントラクトのアドレスで、同画面上のPATH PARAMETERS項目から設定できます。必須の赤いアスタリスクがついてますね。 コントラクトのアドレスは、先ほどまでのkaleido画面のメニュー、Data Explorer -> Smart Contractsから当該コントラクトを選択、Contract Info画面から確認、クリップボードへコピーできるはずです。 f:id:handatec:20200626143726p:plain コピーしたアドレスを貼り付け、TRYボタンを押すとstoredDataの値が表示されます。

f:id:handatec:20200626161521p:plain

同様の手順でset、storedDataも動かすことができます。

外部からREST APIを使ってコントラクトへアクセスする

上述のgetと同じことをREST APIを使ってローカルから接続して確認してみましょう。今回はお手軽にPostmanを利用しました。curlとかでもよいかと思います。 f:id:handatec:20200626152752p:plain REST APIアドレスは先に書いたものと同じで、以下のようになっています。(画面ショット上は{environment_id}と{Node ID}は伏せています)

https://{environment_id}-{Node ID}-connect.{region}.kaleido.io/gateways/{API endpoint}/{contract address}/get

AuthorizationはTYPEを「Basic Auth」にし、UsernameとPasswordを指定しています。UsernameとPasswordはApp Credで生成したものを使います。

また、以下のURLでも同じようにアクセスできます。この場合、Authorizationは「No Auth」でOKです。

https://{App Cred}@{environment_id}-{Node ID}-connect.{region}.kaleido.io/gateways/{API endpoint}/{contract address}/get

curlだと以下のようなコマンドで同じことができます。

curl -X GET "https://{App Cred}@{environment_id}-{Node ID}-connect.{region}.kaleido.io/gateways/{API endpoint}/{contract addresss}/get?kld-from={account address}" -H "Accept: application/json, application/json"

メモ:gas不足対応について

コントラクトのset関数を実行しているとgas不足で実行できないと言われる場合があるかもしれません。 先人の方によると、アカウントにethを割り当てることで対応可能とのことですが、その割り当て画面、OLD CONSOLEでしか表示されません。 (自分が辿れてないだけなのか、実装漏れなのか。。。)

やり方は以下の通り。

  1. OLD CONSOLEに切り替え
  2. EnvironmentのHOME -> SERVICES -> Ether-Pool -> Fund Account で画面を表示
  3. 以下の例を参考に項目値を設定してFUNDボタンをクリック

f:id:handatec:20200626171130p:plain:w340

  • Token Type:eth
  • RECEIVER ACCOUNT:ethを付与したいアカウントのアドレス
  • AMOUNT:1000とか適当に大きな値
  • Unit (単位):Ether

ちなみに、kaleidoでは環境を作成した際に10億ethがあらかじめプールされているようです。

メモ:その他のAPIについて

kaleidoにはまだまだ多くのAPIが備わっていて、Ledger APIなども試しています。 例えば、以下のようなAPIeth.getBlockコマンドと同じようにブロックの情報を取得することもできます。

https://console.kaleido.io/api/v1/ledger/{consortia_id}/{environment_id}/blocks/{block_number}

やり残しているいこと

  • 作成したERC721トークンをアカウントに配布する方法
  • ERC721トークンとERC20トークンの交換
  • "PrivateFor"でコントラクトの参照を特定ノードに制限する方法
  • TruffleからのJSON/RPC HTTP接続、操作

今回はここまで。

Quorumのサンプル「7nodes」を試す。

前回までどこぞの小宇宙に寄り道していましたが、1週周ってEthereum系に帰ってきました。 実はこれから「Kaleido」(ConsenSys社がAWS上で提供しているBaaS)でQuorumを触ろうと考えているのですが、その前に素のQuorumを触っておこうという趣旨です。 Quorum+Raftコンセンサスアルゴリズムの特徴に惹かれたのがきっかけです。

  • Ethereum互換
  • プライベートチェーン。許可ノードのみでクローズネットワークを構成する。(ビザンチン障害耐性は考慮しない)
  • ノードをグループ化(セグメンテーション)して、指定ノードのみにBC内容を公開する制限が可能
  • ブロック生成タイミングがトランザクション発生時のみ
  • リーダーノードがブロックを生成して伝搬
  • リーダーが倒れたら他のノードからリーダーを選出
  • ブロック生成速度が高速(50ms?)
  • ファイナリティあり
  • ブロックがフォークしない
  • gas代がかからない?

クローズドの仕組みを作りたい場合は魅力的な特徴ですね。

Quorumのサンプルは「7nodes」と名付けられていて、その名の通り7つのQuorumノードを起動させてノード間の動きを確認するような内容になっています。 「7nodesやってみた」系の記事はQiitaを中心にネット上にまあまあありますが、公式サイトの日本語訳+ちょっとだけ補足的な内容にとどまっているようですので、本記事では付加情報も書いていきたいと思います。

それでは始めましょう。

環境

Quorum自体の動作環境はVirtualBox上のUbuntu 16.04.6 LTSになります。

あと、あまり関係ないですがターミナルはWindows Terminalを使っています。

準備

公式サイトはこちら。 github.com

7nodesサンプルファイルの取得、仮想マシンの起動

基本的に公式サイトの記載通りで問題ないかと思います。

gitリポジトリからサンプルをクローン

git clone https://github.com/jpmorganchase/quorum-examples.git

作成されたquorum-examplesフォルダへ移動して仮想マシンの初期化と起動

vagrant up

かなり時間がかかるので気長に待ちましょう。途中で止めるとフォルダごと消して最初からやり直しです。

終わったらssh仮想マシンに入ります。

vagrant ssh

Raftでの初期化、Quorumノードの起動

sshでログインすると、ホームディレクトリ直下に3つのフォルダと1つのファイルが既に存在しています。 tesseraディレクトリ、cakeshopディレクトリには1~2個のjarファイル、warファイルしか格納されていません。

quorum-examples/7nodesディレクトリに移動します。

cd quorum-examples/7nodes

今回はコンセンサスアルゴリズムにRaftを使用するので、Raft用のスクリプトで初期化します。

./raft-init.sh

USBデバイス関連のエラーが出るかもしれませんが、無視しても動きます。

あとは、Quorumノードを起動するだけです。起動には少し時間がかかります。

./raft-start.sh

メモ:raft-init.shが実施している内容

手順だけだと理解が深まらないので、初期化スクリプト、起動スクリプトを覗いてみましょう。

まずはraft-init.shです。ざっと以下のようなことをしているようです。

  1. create-permissioned-nodes.shの実行
  2. 7つのノードの最初のブロックの初期化
  3. tessera-init.shの実行
  4. cakeshop-init.shの実行

1.はpermissioned-nodes-${nodes}.jsonファイルに色々書き込んでいるようです。(大雑把)

2.はQuorumノード単位で

geth --datadir qdata/dd${i} init genesis.json

が実行されています。 ${i}はノード番号で1~7です。 genesis.jsonはカレントディレクトリに用意されているethereumでお馴染みのジェネシスブロック用ファイルです。内容で特徴的な箇所は以下のあたりでしょうか。

"chainId": 10,
"difficulty": "0x0",
"isQuorum": true,
"gasLimit": "0xE0000000",
"alloc": {
    "0xed9d02e382b34818e88b88a309c7fe71e65f419d": {
        "balance": "1000000000000000000000000000"
    },
    ...
},
  • chainIdはEthereumと同様ですね。7つのノードすべてのchainIdが10に設定されます。
  • difficultyはマイニング時のハッシュ計算の難易度ですが、0に設定されています。
  • isQuorum はQuorum独自のパラメータでしょうかね。
  • gasLimitには大きな数値が設定されていますが、この値はなんでもいいのでしょうか(未調査)。ちなみに、後述するコントラクトデプロイ時のgas代は0になってました。
  • allocは特定のアカウントにあらかじめethトークンを割り当てる設定です。大きな数値が設定されています。 アカウントは実際にノードに存在するものですが、どこで生成されているのか詳細を確認できていません。 あらかじめ生成されているように思われます。

3.はTesseraノードの初期化です。 QuorumにはTesseraと呼ばれるPrivacy Managerがあります。 TesseraはJavaで実装されていて、Jarファイルが前述のホームディレクトリ直下、~/tesseraディレクトリに格納されています。 スクリプト内では、Tessera用のConfigファイルを元にjavaコマンドでkeyが生成されています。

java -jar $tesseraJar -configfile keygenconfig.json -keygen -filename tm < /dev/null

Quorumノードと対になっているようで、Tesseraノードも7つのノードとなっています。

4.は別のサンプル「cakeshop」関連のスクリプトのようです。

メモ:raft-start.shが実施している内容

  1. Tesseraノードの起動
  2. Quorumノードの起動

1.は同ディレクトリにあるtessera-start.shが実行され、そのなかでJavaコマンドによりTesseraノードが起動されています。

java $jvmParams $DEBUG $MEMORY -jar ${tesseraJar} -configfile $DDIR/tessera-config$TESSERA_CONFIG_TYPE$i.json

Tesseraノードは前述の通り、7つあるようです。 なお、上述のraft-start.sh実行時は引数が省略されていますが、規定値としてPrivacy ManagerにTesseraが使用される設定になっています。

2.は、Tesseraノード起動の後に、gethコマンドにより7つのQuorumノードが起動されています。

geth --datadir qdata/dd${i} ${ARGS} ${permissioned} --raftport ${raftPort} --rpcport ${rpcPort} --port ${port} 2

メモ:7nodesのファイル、ディレクトリ構成(抜粋)

ここでサンプルに登場する7nodes配下のファイル類、ディレクトリをまとめておきましょう。

ファイル類

  • raft-init.sh:Raftによる初期化処理のスクリプト
  • tessera-init.sh:Tesseraの初期化スクリプト
  • create-permissioned-nodes.sh:permissioned-nodes.jsonの設定?
  • permissioned-nodes.json:ネットワークへの参加が許可されているQuorumノードのリスト。各ノードのID(enode)、IP、ポート等の情報を保持
  • raft-start.sh:ノード起動スクリプト
  • tessera-start.sh: Tesseraノード起動スクリプト
  • genesis.json:Quorumノードのジェネシスブロックの情報
  • runscript.shJavascript実行用スクリプト(後述)
  • private-contract.js:サンプルのコントラクトデプロイ用スクリプト(後述)
  • simplestorage.sol:サンプルのコントラクトのSolidityコード(後述)

permissioned-nodes.jsonには、7つのノード分のenodeと呼ばれるノード固有のIDが記載されていますが、 各ノードにおいてadmin.peersコマンドで自ノード以外の6つのenodeが確認できます。

ディレクト

  • qdata:ノード毎のデータ類の格納先
  • keys:ノード毎のキー情報の格納先。おそらくTesseraで生成、利用されている。

7nodesの動作確認

公式サイトはこちら。 github.com

プライベートコントラクトのデプロイ

以下のスクリプト実行によりコントラクトをノードにデプロイします。

./runscript.sh private-contract.js

実行するとトランザクションハッシュ値が表示されます。この値は後で使います。

また、このとき、1番目のブロック(ジェネシスブロックの次のブロック)が生成されます。 eth.getBlock(1)トランザクションハッシュ値が一致することを確認できます。 この時点でブロックはジェネシスブロック1つ、コントラクトデプロイのトランザクション分1つ、計2つのブロックの状態になっています。

ちなみにデプロイ時のgasUsedは0になっています。

メモ:runscript.shの内容

ノード1にてgethコマンドで引数のスクリプトprivate-contract.jsを実行しています。

geth --exec "loadScript(\"$1\")" attach ipc:qdata/dd1/geth.ipc

メモ:private-contract.jsの内容

  1. 使用するアカウントとして0番目のアカウントを指定
  2. abiとbytecodeを記載
  3. コントラクトをデプロイ

1.の0番目のアカウントは、0xed9d02e382b34818e88b88a309c7fe71e65f419dでした。 このアカウントは初期化の際のgenesis.jsonのallocにてethトークンが割り当たっていたものです。ノード1上でコマンドeth.accountsでも存在を確認できます。 なお、各ノードにはアカウントは1つしか存在していませんでした。

2.は、あらかじめsimplestorage.solコンパイルされた結果のabiとbytecodeが記載されています。 simplestorage.solの内容は単純なもので、storedDataという値と、コンストラクタ、setter/getter関数を備えたコントラクトです。

3.はQuorumで特徴的な記載があります。

simpleContract.new(42, {from:web3.eth.accounts[0], data: bytecode, gas: 0x47b760, privateFor: ["ROAZBWtSacxXQrOe3FGAqJDyJjFePR5ce4TSIzmJ0Bc="]}

コントラクトをデプロイして、その際にstoredDataを42で初期化するという内容ですが、privateForというパラメータでこのコントラクトがどのノードから参照可能かを指定しています。 この場合、"ROAZBWtSacxXQrOe3FGAqJDyJjFePR5ce4TSIzmJ0Bc="というキー値のノード、すなわちノード7と、自ノード(ノード1)で参照可能ということです。 他のノードからはこのコントラクトの存在すら確認することはできません。

ちなみに、ノード7のキー値はkeys/tm7.pubファイルで確認できます。他のノードのキー値も同様に番号違いのファイルにて確認できます。

あとgasに値が入っているのですが、ここは詳細未調査です。(gas値は必要なの?)

コントラクトの動作確認

ノード1のipcファイルを指定してgethのコンソールを開きます。

geth attach ipc:qdata/dd1/geth.ipc

コントラクトをデプロイした際に表示されたトランザクションを確認してみます。

eth.getTransaction("0xd07344932b92dbeabd46aa288e0a11ada1c95c9e711cf7047476b5e82978a481")

確認できる値として特徴的なのは、v: "0x26"でしょうかね。 QuorumのPrivate Transactionの場合はvの値が10進数で37か38(16進数で"0x25"か"0x26")とのこと。ethereumの場合この値は27か28になるとのことです。

ここから、ノード1、ノード4、ノード7でコントラクトが保持している値を確認していきます。 ノード1と同じ要領で、ノード4、ノード7でgethコンソールをそれぞれ別画面で開きます。

ノード4

vagrant ssh
cd quorum-examples/7nodes
geth attach ipc:qdata/dd4/geth.ipc

ノード7

vagrant ssh
cd quorum-examples/7nodes
geth attach ipc:qdata/dd7/geth.ipc

3つのコンソールで以下の同じ操作を実施します。

var address = "0x1932c48b2bf8102ba33b4a6b545c32236e342f34";
var abi = [{"constant":true,"inputs":[],"name":"storedData","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"x","type":"uint256"}],"name":"set","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"get","outputs":[{"name":"retVal","type":"uint256"}],"payable":false,"type":"function"},{"inputs":[{"name":"initVal","type":"uint256"}],"type":"constructor"}];
var private = eth.contract(abi).at(address)
private.get()

結果、ノード1とノード7では初期値の42、ノード4では0という結果が返ってきます。 これは、デプロイしたコントラクトの参照権限がノード1とノード7にしかないためです。

ところで、addressに指定している値(コントラクトのアドレス)ですが、ノード1のログから取得しました。

cat qdata/logs/1.log

Submitted contract creationのログのto=以下がaddressになります。

次に、ノード1上でコントラクトの状態を変更してみます。

private.set(4,{from:eth.accounts[0],privateFor:["ROAZBWtSacxXQrOe3FGAqJDyJjFePR5ce4TSIzmJ0Bc="]});

初期値42だったstoredDataをset関数で4へ変更しています。またしてもprivateForでノード7を指定しています。実行結果としてはトランザクションハッシュ値が表示されます。 この時点で2番目のブロックが生成され、合計3つのブロックとなります。ちなみにこの時のトランザクションでもgasUsed: 0です。

再度、ノード1、4、7のコンソールでコントラクトの状態を確認してみます。

private.get()

結果、ノード1とノード7では4、ノード4では0という結果が返ってきます。うまく動いてますね。

この後、公式サイトでは他のサンプルの説明や、「Cakeshop」という7nodesの状態を確認するダッシュボード画面の説明があります。本記事では公式サイトの紹介だけ。。。 docs.goquorum.com github.com

今回はここまで。次回は多分Kaleido+Quorum(+Truffle?)です。

Tendermint、Cosmos SDK、LotionJSをちょっとだけ試す。

前回までにEthereum、HyperLedger Fabricと試してきましたが、ネットでブロックチェーン関連を調べているとTendermint、Cosmosに辿り着きました。 というわけで、今回はTendermint関連です。とはいってもTendermintはほぼ意識しないですが。

Cosmos scaffloldツールを使用したチュートリアル

結論から言うと、途中断念しています。

scaffloldツールで生成されるソースコード雛型とチュートリアルの内容に差異が結構あり、萎えました。 一応、確認したところまでメモしておきますが、ただの環境構築です。。。

公式はこちら。

tutorials.cosmos.network

Go-lang、Git、makeのほか、Github CLI、Cosmos scaffold tool、そして「自分のブロックチェーンを作りたいという気持ち」が必要とのこと。

OSは毎度お馴染みのUbuntu18.04LTS。Git、makeはすでに入っていたので、Goをいつも通りsnapでインストール。 PATH関連はちゃんと設定していないと動かないです。以下は.profileに追記した設定例です。記載したらsourceコマンドか再起動で反映。

export GOPATH=$HOME/go
export GOBIN=$GOPATH/bin
export PATH=$PATH:$GOBIN

Github CLIのインストール

以下でOK。でも、どこで使ってるのか分からない。。。

wget https://github.com/cli/cli/releases/download/v0.9.0/gh_0.9.0_linux_amd64.deb
sudo apt install ./gh_0.9.0_linux_amd64.deb

Cosmos scaffloldツールのインストール

公式には、git clone git@github.com:cosmos/scaffold.gitと記載されていますが、リポジトリが無いと怒られてしまいました。 以下のようにするとちゃんと通ります。

git clone https://github.com/cosmos/scaffold.git

scaffoldという名前のディレクトリが作成され、ソースコードがクローンされいるはず。この後、ツールをmakeするのですが、ここで前述のGo関連のPATHがちゃんと設定されていないと、go-bindataが見つからないと怒られてしまいます。(go-bindataが必要なのも、何だかなぁと思いつつ)

cd scaffold
make

エラーが出なければCosmos scaffloldツールが使えるようになったはずです。このツールを使ってブロックチェーンアプリの雛型を生成していきます。

nameserviceブロックチェーンの作成

まずはアプリの大枠を生成。

scaffold app lvl-1 <ユーザ名> <リポジトリ名> 

公式には、Githubの<ユーザ名>と<リポジトリ名>をとの記載がありますが、たぶん適当で大丈夫なんじゃないかと。 <リポジトリ名> は今回はcosmossdk-tutorialとしました。コマンド実行後、<リポジトリ名> のディレクトリが生成されます。 コマンド実行直後のcosmossdk-tutorialの状態は以下の通りです。

cosmossdk-tutorial
├── app
│   ├── app.go
│   └── export.go
├── cmd
│   ├── appcli
│   │   └── main.go
│   └── appd
│       ├── genaccounts.go
│       └── main.go
├── go.mod
├── Makefile
└── x

次に、xディレクトリに移動して、scaffloldツールでnameserviceという名前のモジュールを生成します。(xって名前もどうなのと思いつつ)

scaffold module <ユーザ名> <リポジトリ名>  nameservice

コマンド実行するとnameservice配下に以下のようなファイルやディレクトリが生成されます。

x
└── nameservice
       ├── abci.go
       ├── alias.go
       ├── client
       │       ├── cli
       │       │     ├── query.go
       │       │     └── tx.go
       │       └── rest
       │             ├── query.go
       │             ├── rest.go
       │             └── tx.go
       ├── genesis.go
       ├── handler.go
       ├── keeper
       │      ├── keeper.go
       │      ├── params.go
       │      └── querier.go
       ├── module.go
       ├── README.md
       ├── spec
       │      └── README.md
       └── types
              ├── codec.go
              ├── errors.go
              ├── events.go
              ├── expected_keepers.go
              ├── genesis.go
              ├── key.go
              ├── msg.go
              ├── params.go
              └── querier.go

ここで断念。

ここから公式サイトに沿って確認、コード追記等していくのですが、ここで断念。 公式通りに修正する気力が湧きませんでした。。。。

公式は、types/types.goのコード追加、keeper、codec等の説明が続きます。

完成済みのチュートリアルを試す。

気を取り直して、動きだけでも確認しようと思い、完成済みのチュートリアルをインストールしてみます。 以下のサイト様を参考に進めました。公式サイトは探せておらず不明です。

goblockchain.network

www.blockchainengineer.tokyo

gccがないとmakeできないようですので、インストールしておきましょう。

sudo apt install build-essential

チュートリアルリポジトリをクローンしてビルドします。

git clone https://github.com/cosmos/sdk-application-tutorial.git
cd sdk-application-tutorial/nameservice
make install

これで、Goのソースコードコンパイルされnsdnscliという名前の実行ファイルが$GOPATH/binディレクトリに生成されたはず。 コマンドはspf13/cobraで作られているようです。

あとは参考サイトそのままです。

nsd init cosmos --chain-id namechain

jackとaliceという名前のアカウントを追加して、それぞれに1,000nametoken、100,000,000stakeの初期値割り当て

nscli keys add jack
nscli keys add alice
nsd add-genesis-account $(nscli keys show jack -a) 1000nametoken,100000000stake
nsd add-genesis-account $(nscli keys show alice -a) 1000nametoken,100000000stake

初期値の設定ファイルgenesis.json確認(目視)

cat ~/.nsd/config/genesis.json

nscliの設定

nscli config chain-id namechain
nscli config output json
nscli config indent true
nscli config trust-node true

nscli設定値の確認(目視)

cat ~/.nscli/config/config.toml

ノード起動

nsd gentx --name jack
nsd collect-gentxs
nsd validate-genesis
nsd start

ちなみに、nsdサブコマンドは以下の説明になっています。

  • init : Initialize private validator, p2p, genesis, and application configuration files
  • add-genesis-account : Add a genesis account to genesis.json
  • gentx : Generate a genesis tx carrying a self delegation
  • collect-gentxs : Collect genesis txs and output a genesis.json file
  • validate-genesis : Validates the genesis file at the default location or at the location passed as an arg
  • start : Run the full node

ここから別コンソール。

jackの初期値確認

nscli query account $(nscli keys show jack -a)

jack.idという名前を5tokenで買ってみる。

nscli tx nameservice buy-name jack.id 5nametoken --from jack

jackのアカウントからtokenが減ってるか確認。

nscli query account $(nscli keys show jack -a)

jack.idの名前に8.8.8.8というIPアドレスを設定してみる。(8.8.8.8はGoogleDNSのアドレスですが)

nscli tx nameservice set-name jack.id 8.8.8.8 --from jack

jack.idという名前からIPアドレスを引いてみる。(結果は8.8.8.8が表示される)

nscli query nameservice resolve jack.id

aliceがjack.idを買うところは面倒なので省略。

LotionJSを試す。

Cosmos-SDKチュートリアルで辟易としたので、Tendermint関連で別のものがないか調べていると、Javascriptフレームワークらしきものがありました。 公式サイト通りにやってみましたが簡単でした。簡単すぎて味気ないというか、歯ごたえがまるでないです。

lotionjs.com

Node.js、npmが必要です。使用したバージョンは以下の通りです。

  • Node 12.16.3
  • npm 6.14.5

Lotion、Lotion-CLIをインストール。-gオプションは不要かもしれませんが、念のため。一緒にTendermintとかもインストールされるようです。

npm install lotion
npm install -g lotion-cli

インストールされたバージョンはこんな感じでした。

  • lotion 0.4.27
  • tendermint 0.31.5
  • tendermint-node 5.1.5

適当なディレクトリ内にapp.jsファイルを作成して、以下のようなコードを記述(公式からのコピペ)。

let lotion = require('lotion')

let app = lotion({
    initialState: {
        count: 0
    }
})

function transactionHandler(state, transaction) {
    if (state.count === transaction.nonce) {
        state.count++
    }
}

app.use(transactionHandler)

app.start().then(appInfo => console.log(appInfo.GCI))

そして実行。

node app.js

実行すると、Global Chain Identifier (GCI)と呼ばれる超長い文字列が表示されます。この文字列はこの後のlotion動作確認で使用します。

ここから別ターミナルを開いて動作を確認。

lotion state <GCI>

<GCI>の箇所には、先ほどのnodeコマンドで表示された超長い文字列を指定します。 結果、countの初期値は0になっています。

{
    "count": 0
}

トランザクションを発行?してcountを変更してみます。

lotion send <GCI> '{ "nonce" : 0 }'

(nonceが0って何だかなぁと思いつつ)以下のような値が表示されます。

{
    "check_tx": {},
    "deliver_tx": {},
    "hash": "E11E0D22061B3359D4A331E76BDC2DB2F95ECCE19E969EB1780CC671D5AF52C9",
    "height": "65"
}

生成ブロックの情報でしょうか。hash値とheightがはまってますね。

countの値を再度確認してみます。

lotion state <GCI>

結果

{
    "count": 1
}

countが+1されています。

感想

個人的にブロックチェーンでやりたいことは、デジタルコンテンツ(Non-Fungibleトークン的なもの)とFungibleトークンの価値交換とか、参加者限定の分散台帳なのですが、今回のTendermint関連でやれるかと考えると、情報が足りない(私自身の勉強も足りませんが)、ナレッジベースが洗練されていない感触でした。 アプリケーション開発者目線での「なんかできそう」感は、現時点ではEthereumの方がありますね。 CosmosはLino Network/D-Liveが採用してサービスインしていたり、Cosmos Hubがローンチされているという記事を読んだので期待していたのですが。。。ウワモノを作る人にとっては敷居が高いかもしれません。

雑記:デジタル円検討会のニュースについて

2020/06/03付で、デジタル円(CDBC:Central Bank Digital Currency)検討会発足のニュースがでていました。参加企業はメガバンク、大手の情報通信、キャッシュレス決済サービスを運用している運輸、流通・小売、そして法律事務所と納得のラインナップになっていました。 FacebookのLibraや中国の動きから検討せざるを得ない状況になっているのだろうと思います(そういえば、ブロックチェーンやってる人って中華系の人が多いような印象があります)。 これまでの検討状況では、「現時点の技術水準では困難」の見解のようですね。これから先、日銀他がどのようなインフラ技術をベースにしようとするのか興味があります。

Hyperledger FabricのSample「fabcar」を試してみる。

前回のEthereumのTruffle、Vue-boxに続いて、今回はコンソーシアム型ブロックチェーンHyperledger Fabricのサンプルについてです。

公式は以下のサイトですが、英語で文章量が結構多めであること、日本語でそのままずばりの情報がないようなので、とりあえずサンプルを動かすところまでをまとめてみました。

hyperledger-fabric.readthedocs.io

ざっくりした手順は以下の通りです。

  1. 必要なツール類のインストール
  2. fabric-samplesのインストール
  3. テストネットワークの起動、チャネル生成、chaincodeのデプロイ
  4. chaincodeの実行

それではいってみましょう。

環境

  • Ubuntu 18.04 LTS
  • Git 2.17.1
  • cURL 7.58.0
  • Docker 19.03.9 / docker-compose 1.25.4
  • Go 1.14.3
  • Node.js 12.16.3 / NPM 0.35.3
  • Python 2.7.17

UbuntuVirtualBox上で動作させています。VirtualBox仮想マシン上でDockerの仮想環境を動かしている感じです。 VirtualBox仮想マシンのCPU数、メモリは多めに設定しています。

ツール類のインストール

事前に入れておきなさいと言われているものはこちら。上述の環境にも記載しましたが、必要なものがちょっと多めですね。

hyperledger-fabric.readthedocs.io

Git、cURLPythonは元々入っていたのでとりあえず作業なし。 node/npmの手順はググれば出てくるので割愛。 本記事ではDockerとGoのメモだけ。

Dockerのインストール

Docker公式の通りaptでのインストールで特に問題なし。

docs.docker.com

日本語だとこちらのサイトがよいと思いました。

qiita.com

docker-composeのインストール

こちらも公式に従って1.25.4をインストール。 権限の関係でsudoを付けています。

sudo curl -L https://github.com/docker/compose/releases/download/1.25.4/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose
sudo chmod +x /usr/local/bin/docker-compose

github.com

Goのインストール

snapを使ってインストール。snapはUbuntu16.04以上であればプレインストールされているはず。こちらもsudoを付けて実行。

sudo snap install go --classic

fabric-samplesのインストール

Hyperledger Fabricのサンプル一式をダウンロードして配置します。

公式はこちら。

hyperledger-fabric.readthedocs.io

長々と説明が書かれていますが、以下のコマンドでインストールされます。

curl -sSL https://bit.ly/2ysbOFE | bash -s

パーミッション関連のエラーが出るかもしれません。 ツール類をインストールしたらOS(Ubuntu)を一旦リブートしておくのが吉です。 curlの実行が終わると、fabric-samplesという名前のディレクトリができており、サンプルファイル一式が格納されています。

メモ:fabric-samplesの構造

主なものだけ。

  • chaincode/fabcar : (かっこよく言うと)自動車の所有権等管理のサンプル。各言語別にfabcar用ソースコードが格納されています。
  • test-network : テスト用ネットワークのファイル一式(fabcar専用?)
  • test-network/script : スクリプトファイル一式。手順を進める上では意識しなくてよいです。
  • bin : Hyperledger Fabricのツール群(実行ファイル)。

binには以下のようなツールが格納されています。

configtxgen
configtxlator
cryptogen
discover
fabric-ca-client
fabric-ca-server
idemixgen
orderer
peer

メモ:Docker Imageの確認

この時点でDockerのイメージ(コンテナ)を確認すると、hyperledger fabricノード用のイメージが複数登録されれいます。

sudo docker images

登録されるのは以下の11個。

hyperledger/fabric-ca
hyperledger/fabric-tools
hyperledger/fabric-peer
hyperledger/fabric-orderer
hyperledger/fabric-ccenv
hyperledger/fabric-baseos
hyperledger/fabric-nodeenv
hyperledger/fabric-javaenv
hyperledger/fabric-zookeeper
hyperledger/fabric-kafka
hyperledger/fabric-couchdb

テストネットワークの起動~chaincodeのデプロイ

テストネットワーク

test-networkディレクトリの下にnetwork.shというスクリプトファイルがあります。 test-networkディレクトリに移動して、コマンド

./network.sh up

を実行すると、ログがたくさん出た後、3つのノード(Dockerコンテナ)が立ち上がります。

  • orderer.example.comという名前のordererノード
  • peer0.org1.example.comという名前のpeerノード(以下、Org1)
  • peer0.org2.example.comという名前のpeerノード(以下、Org2)

Dockerのコマンドでも同様の情報を確認できます。

docker ps -a

チャネル生成

以下のコマンドでチャネルを生成します。

./network.sh createChannel

mychannelという名前のチャネルが生成され、PeerノードであるOrg1とOrg2がmychannelにJOINされます。 ちゃんと理解できていませんが、おそらく複数のPeerを1つのチャネルでグルーピングしているのだと思われます。

「fabcar」chaincodeのデプロイ

「fabcar」のchaincode(スマートコントラクト)を以下のコマンドでmychannelにデプロイします。

./network.sh deployCC

こちらもたくさんのログが出力された後、最終的に自動車10台分の車種や色、所有者のデータが登録されます。 こんなデータです。

[{"Key":"CAR0","Record":{"make":"Toyota","model":"Prius","colour":"blue","owner":"Tomoko"}},
{"Key":"CAR1","Record":{"make":"Ford","model":"Mustang","colour":"red","owner":"Brad"}},
{"Key":"CAR2","Record":{"make":"Hyundai","model":"Tucson","colour":"green","owner":"Jin Soo"}},
{"Key":"CAR3","Record":{"make":"Volkswagen","model":"Passat","colour":"yellow","owner":"Max"}},
{"Key":"CAR4","Record":{"make":"Tesla","model":"S","colour":"black","owner":"Adriana"}},
{"Key":"CAR5","Record":{"make":"Peugeot","model":"205","colour":"purple","owner":"Michel"}},
{"Key":"CAR6","Record":{"make":"Chery","model":"S22L","colour":"white","owner":"Aarav"}},
{"Key":"CAR7","Record":{"make":"Fiat","model":"Punto","colour":"violet","owner":"Pari"}},
{"Key":"CAR8","Record":{"make":"Tata","model":"Nano","colour":"indigo","owner":"Valeria"}},
{"Key":"CAR9","Record":{"make":"Holden","model":"Barina","colour":"brown","owner":"Shotaro"}}]

chaincodeの実行

実行前の準備

これから実行する作業のために環境変数を2つ設定します。絶対パスじゃないのでなんだかいまいちなのですが。。。公式に従います。 カレントディレクトリはfabric-samples/test-networkです。

export PATH=${PWD}/../bin:$PATH
export FABRIC_CFG_PATH=$PWD/../config/

また、トランザクションの受付ノードをOrg1ににするため?に環境変数を5つ設定します。(多い。。。)

export CORE_PEER_TLS_ENABLED=true
export CORE_PEER_LOCALMSPID="Org1MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org1.example.com/users/Admin@org1.example.com/msp
export CORE_PEER_ADDRESS=localhost:7051

chaincode実行:自動車一覧の取得

で、やっとchaincodeの実行。データ一覧を取得するクエリです。fabric-samples/bin/peerに引数をいくつか付けてますね。

peer chaincode query -C mychannel -n fabcar -c '{"Args":["queryAllCars"]}'

結果としては前述の自動車の車種や色、所有者のデータ一覧が表示されます。(省略)

chaincode実行:オーナーの変更

Car9のオーナーをデーブさんに変更してみます。この時点でのトランザクション受付ノードはOrg1です。

peer chaincode invoke -o localhost:7050 --ordererTLSHostnameOverride orderer.example.com --tls true --cafile ${PWD}/organizations/ordererOrganizations/example.com/orderers/orderer.example.com/msp/tlscacerts/tlsca.example.com-cert.pem -C mychannel -n fabcar --peerAddresses localhost:7051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org1.example.com/peers/peer0.org1.example.com/tls/ca.crt --peerAddresses localhost:9051 --tlsRootCertFiles ${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt -c '{"function":"changeCarOwner","Args":["CAR9","Dave"]}'

な、長い。。。長すぎる。実行結果としては簡単なログが出るだけです。

2020-05-20 08:44:53.732 UTC [chaincodeCmd] chaincodeInvokeOrQuery -> INFO 001 Chaincode invoke successful. result: status:200

トランザクションの受付ノードをOrg2ににするため?に環境変数を変更して、データが変更されていることを確認します。

export CORE_PEER_TLS_ENABLED=true
export CORE_PEER_LOCALMSPID="Org2MSP"
export CORE_PEER_TLS_ROOTCERT_FILE=${PWD}/organizations/peerOrganizations/org2.example.com/peers/peer0.org2.example.com/tls/ca.crt
export CORE_PEER_MSPCONFIGPATH=${PWD}/organizations/peerOrganizations/org2.example.com/users/Admin@org2.example.com/msp
export CORE_PEER_ADDRESS=localhost:9051

で、やっと確認。

peer chaincode query -C mychannel -n fabcar -c '{"Args":["queryCar","CAR9"]}'

実行結果はこんな感じ。ちゃんとオーナーが変更されていますね。オーストラリアの自動車メーカーなんてマニアックな。

{"make":"Holden","model":"Barina","colour":"brown","owner":"Dave"}

ここまでの感想

実行しているシェルスクリプトを読まないと何をしているか分からず、ただ手順に沿ってコマンドたたいているだけになってしまいます。 スクリプトも幾重にもなっており、末端はbinディレクトリに格納されているツール類を実行しているようです。 また、CA(認証局)やユーザが明示的に登場していないので物足りないです。 サンプルを動かせたとしても、応用は効かないかも。

公式ではこれから先は自分でスマートコントラクトを書いて実行してみる手順に続くようです。気が向いたらやってみて追記します。

本日はここまで。

TruffleのVue-boxを試してみる。

Ethereumのフレームワーク(開発ツール?)「Truffle」ですが、様々なサンプルがboxという形でパッケージされており、利用可能になっています。 そのなかでDRIZZLE-VUE-BOXについて試してみました。ネット上にあまり解説等がないため、まとめておきます。

最終的にはこんな画面が動かせるようになります。

f:id:handatec:20200514161848p:plain:w480
vue-boxの画面

公式は下記のサイトですが、本記事ではGanache CLIを使用しているため、手順を少々追加、変更しています。 www.trufflesuite.com

環境

  • Truffle v5.1.25
  • Ganache CLI v6.9.1 (ganache-core: 2.10.2)
  • Node v12.16.3
  • npm v6.14.4
  • Utuntu 18.04 LTS
  • Firefox + MetaMask(Extension)

ブラウザ(Firefox + MetaMask)以外はVirtualBox仮想マシンubuntu上で動作させています。仮想マシンのCPUは2個、メモリ4GBの構成にしています。

ツール類のインストール

当たり前ですが、node/npmををインストールしてからTruffle、Ganache CLIをインストールします。 node/npmはnvmからインストールしました。

#npm/nodeインストール(nodeバージョン指定)
$ nvm install v12.16.3
#Truffleインストール
$ npm install -g truffle
#Ganache CLIインストール
$ sudo npm install -g ganache-cli

ganache-cliについて、sudoを付けずに実施するとビルドエラーっぽいのがでて気持ち悪かったので、念のためsudoを付けています。 sudo付けても微妙にエラーが出ていますが、なんとか動いています。細かく調べていませんが、nodeのバージョンがよくないのかもしれません。

仮想通貨ウォレットのMetaMaskも必要です。ChromeFirefoxにエクステンションがありますので、そちらをインストールしておきます。 本記事ではFirefox版を使用しました。 手順はいろんなサイトで紹介されているので省略します。

boxの開梱~コントラクトのデプロイまで

vue-boxのunbox

unboxは公式の通りです。適当に作成したディレクトリ(フォルダ)内でコマンドを実行。通信状況のせいなのかよく失敗しますが、2回ぐらい実行するとだいたい成功します。

$ truffle unbox vue-box

truffle-config.jsの編集

ここからは公式と異なり、本記事ではtruffle developは使いません。

Ganacheに向けてコントラクトをデプロイするため、truffle-config.jsに追記を施します。ファイルはunboxしたディレクトリ直下に展開されています。 追記箇所は、module.exportsの内側、contracts_build_directory:の下です。

const path = require('path')
module.exports = {
  // See <http://truffleframework.com/docs/advanced/configuration>
  // to customize your Truffle configuration!
  contracts_build_directory: path.join(__dirname, "vapp/src/contracts"),

  //ここから追記
  networks: {
     development: {
      host: "127.0.0.1", 
      port: 8545,
      network_id: "*",
     },
  },  
};

truffle developの場合は port: 7545ですが、Ganacheの場合は8545です。

コンパイル

unbox直後の状態でコンパイルせずとも動くと思います。私はComplexStorage.solに気に入らない箇所があった(笑)ので修正してコンパイルしました。(後述)

$ truffle compile

コンパイルすると、vapp/src/contracts配下にいくつかのjsonファイルが生成、または更新されます。

Ganache CLIの起動

さて、マイグレーションする前に、別のターミナルを開いて Ganache CLIを起動しておきます。私の環境ではブラウザとGanacheが動いているマシンが異なるため、-hオプション(ホストの指定)を付けて接続元の縛りをなくしています。環境によってはオプション付けなくても動くと思います。規定値はlocalhostです。

$ ganache-cli -h 0.0.0.0

Ganacheを起動すると100ETHを保持したアカウント10個と、それに対応するPrivate Keys10個が表示されます。Private Keysは後ほどMetaMaskの設定に使用するのでメモしておきます。起動する度に変わるので注意です。

ちなみに、Ganache CLIのオプションの種類はこちら。 github.com

マイグレーション

普通にコマンド実行です。Ganacheの方(別で開いたターミナル)にもデプロイ関連のトランザクションのログが流れるはずです。

$ truffle migrate

MetaMaskの設定

Ganacheへの接続設定と、アカウントのインポートを行います。

  • Ganacheへの接続設定

MetaMaskのネットワーク選択リストから"カスタムRPC"を選択すると、「設定」->「ネットワーク」の画面になります。

"Network Name"に分かりやすい名前を適当に入力し、"New RPC URL"には自分の環境に合わせてhttp://x.x.x.x:8545を記載。x.x.x.xはIPアドレスなので適宜読み替えてください。8545は前述の通りGanacheのポートです。 設定を保存すると、うまくいっていれば接続されるはずです。

  • アカウントのインポート

MetaMaskがGanacheに接続された状態で、MetaMaskのアカウントインポート機能でインポートを行っておきます。Ganacheを起動したときに表示されたPrivate Keysから0番目のアカウントの秘密鍵の入力欄にコピペし、「追加」ボタンをクリックするとインポートされます。

マイグレーション後にこの手順を実施すると、元々保持していた100ETHから少し減っている(99.9418ETHぐらい)と思います。 これはマイグレーションの際のコントラクト配置のトランザクション手数料分のはずです。

動作確認

開発サーバの起動

vappディレクトリ配下で以下のコマンドを実行すると開発用サーバが起動します。これはvueで普通に開発する場合と同じです。

$ npm run serve

画面の表示

ブラウザから以下のアドレスにアクセスすると、冒頭で紹介した画面が表示されるはずです。x.x.x.xはIPアドレスなので適宜読み替えてください。 一番最初の表示の際にMetaMaskの小さな画面が開くと思います。画面下部に"connect"ボタンがありますので、それを押しましょう。

http://x.x.x.x:8080/

f:id:handatec:20200514161848p:plain
vue-boxの画面

画面上には大きく4つの内容が表示されています。

Show the Accounts

Ganacheが生成した0番目のアカウントのアドレスと、保持しているETHが表示されています。

Tutorial Token

vue-boxには「Tutorial Token」という名前のERC20ベースのトークンが実装されています。 シンボルは"TT"です(通貨記号、単位みたいなもの)。 初期供給値が12,000(120TT)になっており、0番目のアカウントが保持しています。

Address欄にGanacheが生成したアカウント(0番目以外)を記載し、Amount欄に12,000以下の数値を入力してSubmitボタンを押すと、MetaMaskの小さな画面が開きます。確認ボタンと押すと、TTが移動(送金)され、0番目アカウントが保持しているTTが12,000から減額されます。GAS FEEはトランザクション手数料です。

f:id:handatec:20200514193134p:plain:w200
TT移送画面

Simple Storage

Simple Storageは、ステート(状態)として1つの数値を保持するようなコントラクトとして実装されています。

Value入力欄に適当に数値を入力してSubmitボタンを押すと、やはりMetaMaskの小さな画面が開きます。確認ボタンと押すと、その数値がSimple Storageコントラクトのステートに保存され、Value表示欄に表示されるようになっています。

f:id:handatec:20200514194824p:plain:w200
数値設定時の子画面

Complex Storage

Complex Storageは様々な数値、文字列、配列等をステートとして保持するコントラクトとして実装されています。保持する値はコントラクトに直書きされており、変更する機能は実装されていません。 画面上には保持している内容のうち4種類の情報(string1、string2、singleDD、uintarray)が表示されています。

(string2の初期値が「你好」になっていたので「こんにちは」に書き換えてコンパイルしなおしました)

VUE-BOXの構造

contracts配下

主に3つのコントラクトが実装されています。

  • TutorialToken.sol
  • SimpleStorage.sol
  • ComplexStorage.sol

これらはそれぞれ前述の画面の表示に対応しています。 TutorialToken.solにはOpenZeppelinが利用されているようです。(詳細要調査)

OpenZeppelinのライブラリはnode_modules/openzeppelin-solidityに格納されています。

migrations配下

unboxした時点で既に以下の2ファイルが格納されています。Truffleのマイグレーション/デプロイ用のファイルですね。 そのまま動かすだけなら修正する必要はありません。

  • 1_initial_migration.js
  • 2_deploy_contracts.js

vapp/src/contracts配下

コントラクト(Solidityファイル)をコンパイルした結果のjsonファイルが格納されます。

vapp/src配下

Vue関連でお馴染みのファイルが格納されています。

  • main.js
  • App.vue

main.jsにVuexとDrizzleの利用が定義されています。ストア関連ですね。

App.vueには以下の3つのVueコンポーネントが配置されています。

  • TutorialToken.vue
  • SimpleStorage.vue
  • ComplexStorage.vue

あとは、Drizzle関連ファイル。各Vueコンポーネント内でdrizzleが利用されていますが、まだ動きを理解していないのでこれから勉強します。 なんとなく、各contractsとvueコンポーネントマッピングしているだけのように見えます。

  • drizzleOptions.js

VUE-BOXにたどり着くまでにやってきたこと

つい数週間前まではブロックチェーンの知識0でしたが、以下を実施することにより概要は分かったような気でいます。

書籍2冊を読了

ブロックチェーンの仕組みが分かりやすく書かれているのと、Web3.0時代の未来が書かれています。 こんな世の中になればいいなと思いますが、既得権益者や縦社会組織からの抵抗が予想されるので、トップダウンでやるか、こっそりと始めて気づいたらインフラになってたというやり方がよさそうですね。社会へ価値を提供せずにお給金を頂いている方は職を失いますね。

ブロックチェーン システム設計

ブロックチェーン システム設計

正直なところ、文章や図が分かりにくかったり、冗長だったりしますが、後半の内容がシステム設計思想のベースになりそうなことと、巻末付録の「Ethereumの手順」が多少参考になりました。

「Ethereum入門」の実施

book.ethereum-jp.net いろんなところで紹介されているEthereum入門のサイトです。 「スマートコントラクトを作成し実行する」までの流れと、Appendix「Ethereum ウォレットの使い方(Metamask)」を実施しました。 2018年時点の記載であること、Metamaskは画面ショットが現在のものと微妙に異なりますが、だいたい分かります。 Ethereumネットワークに種類があること(プライベート、テスト、本番)は頭に入れておきましょう。

gethを使った複数ノードの連動実験

VirtualBoxで2つのノードを立ち上げ、ブロック等が同期されることを確認しました。 上記2つ目の書籍「ブロックチェーンシステム設計」巻末付録と、こちらのサイトを参考にさせていただきました。 blockchain-jp.com

TruffleのHelloWorld

こちらのサイトを参考にさせていただきました。 noumenon-th.net

Truffleのその他のbox

vueの前にmetacoin、drizzle、react、pet-shopを試しました。 metacoinはちゃんと動きましたが、reactは何か変なエラーが出て動いていません。どうも自分にはReactと縁がないようです。 drizzleはloading...のまま動かず、pet-shopはチュートリアルが面倒くさい割に最後のコントラクト実行のところがうまくいかず辟易しています。。。

本日はここまで。

Raspberry PiをRoon Bridge(ついでにネットラジオ)にしてみる。

手持ちの音楽CD(5,000曲ぐらい)を2019年春ごろにすべてFLAC Uncompressedにし、メディアサーバーとしてServiioを立ててAVレシーバーやネットワークプレーヤー(Marantz NA6005)に付いている再生機能で聴いていたのですが、再生中に切れたりして不安定だったこと、また、ネットラジオの機能(vTuner?)で海外のラジオをよく聴いていたのですが、たまに音がブチブチ切れることがあり、こちらも再生品質が悪く不満でした。

Raspberry Piでなんとかなる?

ネットオーディオについては、かねてからRoonに興味があったので、Roon Readyのネットワークプレーヤー TEAC NT-505を検討していたのですが、少々お高いので二の足を踏んでいました。

そんなとき、ふと部屋の隅をみると昔いじっていたRaspberry Piが目に入り、これを使って何かできないかとググってみるとなんとかできそうな雰囲気だったのでやってみました。

やりたかったことは2つ。

  • ラズパイにRoon Bridgeを入れて、AVレシーバーとS/PDIFでつなげたい。
  • ついでにネットラジオもラズパイで受信したい。

いろいろ試した結果、最終的には、

  •  光/同軸出力のサウンドカードを買ってラズパイに装着
  • ラズパイのOSとしてVolumioを入れ、管理画面からRoonを有効化

で落ち着きました。

iPhoneのRoon RemoteからVolumioのRoon Bridgeを操作している画面はこんな感じです。Volumioはホスト名を初期値から変更していないので「volumio」と表示されています。Roonがネットワーク上のBridgeを認識して自動的に表示されるので、何の設定も不要です。今のところ何の問題もなく、快適に動いています。

f:id:handatec:20200424131404p:plain:w250f:id:handatec:20200424131446p:plain:w250
Roonの再生画面、ゾーン選択の様子

そしてこちらはVolumioのインターネットラジオ周辺の画面。WebアプリなのでSafari等のブラウザからのアクセスになりますが、IPアドレスはmDNSが効いているのでDHCP環境でも意識する必要なく、volumio.localでアクセスできます。また、iPhoneの場合はブラウザから「ホーム画面に追加」をしてやると普通のアプリっぽく使うことができます。

f:id:handatec:20200424134021p:plain:w250f:id:handatec:20200424134044p:plain:w250
Volumioの画面

追加で買ったもの

サウンドカード

サウンドカードは、ネット上に情報が多かった「HiFiBerry Digi+ Pro」を購入。ラズパイのGPIOに差し込むだけでVolumioは認識してくれるはずです。BNC端子のはんだ付けはしてません。

HiFiBerry Digi + Pro

HiFiBerry Digi + Pro

  • メディア: Personal Computers
 

ケース

裸のラズパイをAVラック裏にずっと置いておくのもなんなので、AVIOTのケースとDigi +用の交換パネルを購入。ラズパイのLEDランプが見えなくなるのが玉に瑕。

  サウンドカード、ケース合わせて17,000円ぐらい。 裸のままが気にならないならもう少し安くあがりますが、ケースにいれると安心感があります。

Roonライセンス

Roonは14日間のトライアル期間で気に入ったのでひとまず年間ライセンスを購入。こちらは119.88USD(現在の為替レートで13,000円弱)。ちょっと高い気はしますが、払う価値はあると思います。アプリ全般の出来が素晴らしいです。ちなみに、Lifetimeライセンスは699.99USD(約75,000円)です。6年以上使い続けるならお得ですね。 roonlabs.com

トライアル登録の際にクレジットカードの入力まで求められるのですが、ここでちょっとつまづき、先方(Roon Labs)と稚拙な英語でやり取りしました。 最初の問い合わせメールを送って返信まで2週間ぐらいかかりましたが、その間にごちゃごちゃやってたら登録できてしまい、結果OKとしました。 以下のメールのやり取りの2.のところで、ドロップダウンリストからクレジットカード情報を選択するのではなく、その画面のカード情報入力欄に直接入力するとうまく登録できます。 暗にサイトの不具合を報告をしたつもりでしたが、もしかしたら修正されているかもしれません。

Thank you for your reply. I tried to register by another operation, then I was able to do it.

Sorry for the confusion. It looks like you were able to figure this out and you have a free trial that converts to a yearly subscription.

How do I become Trial Membership? I did the following operations on your sites, but I cannot be Trial Membership. Please tell me what to do.

  1. I registered my account informations (name, email address etc.) and credit card informations on the following site. https://roonlabs.com/account#tab_account And I clicked "Try it Free" button.

  2. I selected "Use Card Ending in xxxx, Exp. mm/yyyy" on drop-down list, and clicked "PURCHASE USING THIS CARD" button on the following site. https://roonlabs.com/buy

Then, The following message was displayed. "Purchase failed: CCRequired. Please try again." I don't understand this message.

ライセンス認証は、最初にRoonのクライアントを立ち上げた際にアカウント情報を入力し、ネット経由で認証される仕組みになっています。

ちなみに、Roon Serverはラズパイには入れておらず、別のUbuntuマシンにインストールしています。 インストールの仕方については、公式に書かれている通りにすれば詰まるところはないかと思います。 自分は「The Easy Installer (Recommended)」に書かれているshでのインストールを行いました。 kb.roonlabs.com

Volumioが良い!

当初はRaspbian Busterでなんとかしようとして、ネットラジオ機能をMPD/MPC+自作プログラムやMopidy/Irisで解決しようと1日半ほど回り道をしてしまいましたが、ラズパイのOSをVolumioにすることでやりたかったことが1時間程度であっさり実現できてしまいました。インストールはラズパイに挿すmicroSDカードにVolumioイメージを焼くだけです。 volumio.org

Raspbian+Mopidyを没にした理由は、とりあえずTuneIn Radioは聞けるけどラジオ局選択ができないこと、Roonとオーディオデバイスが競合するため、Mopidyを常時起動できないことです(ここが致命的でした)。

VolumioだとRoonをわざわざ手動でインストールする必要もなく、プラグインの管理画面からボタン1つで機能追加できます。また、前述のとおりネットラジオの機能も付いてます。デバイス競合云々も考えなくてよいです。

f:id:handatec:20200424140725p:plain
VolumioのRoon Bridgeインストール画面

使用感

Roonの使用感としては、スマホタブレットからRoon Remoteで再生曲選択などの操作をしたり、直接スマホで聴けたり(←ここも重要)で快適ですし、音源のデータがAVレシーバーまで無劣化で転送できているようで、音質的にも満足しています。

ネットラジオの操作性に関しては、TuneInやvTunerと同様に聴きたい局が選択できますし、「お好みの放送局」に登録しておくこともできます。

当初問題となっていた音の途切れについても、アプリの安定性やメモリ容量のおかげなのか問題なく再生できており、快適です。

しかしこれでNA6005が置物になってしまった。。。

 

2020年4月現在のオーディオ周りの構成

Roon Server

Ubuntu18.04 LTS 物理マシン(Core i3-8100、メモリ8GB)にインストール

 常時起動。FLACファイルもここに格納。

Roon Bridge

Raspberry Pi 3 Model B v1.2 (2015)

 + HiFiBerry Digi+ Pro

 + Volumio 2.729

AVレシーバー

YAMAHA CX-A5100

 Raspberry Piとは同軸デジタルケーブルで接続

アンプ

NuPrime STA-9

 レシーバーとはXLRケーブルで接続

スピーカー

KEF Q900

ネットワークは、Roon Serverを置いてある部屋とRoon Bridgeが置いてある部屋の間は11acで無線化しています。

余談

STA-9は正直あまり気に入っていません。調子が悪くなったSONY DA-7100ESから今の構成に変えたのですが、無音時のホワイトノイズと、低音のルーズな感じがスピーカーとの相性もあっていまいちです。

 

在宅勤務は意外としんどいという話

コロナ禍の影響により在宅勤務が推奨されていますね。

幸いにも現在所属している会社ではリモートワークの仕組みが辛うじて整備されており、家庭の事情もあって2020年2月下旬より在宅勤務を主にしてきました。 在宅を始める前は、さぞ快適だろうと想像していたのですが、しばらく続けていると「こいつは案外しんどいぞ」と感じてくるようになりました。今回の記事はそこら辺のことを書きたいと思います。

 

会議、打合せ準備が結構面倒

前の記事でも書きましたが、現在所属している会社はシステム屋のはずなのですが、自分の仕事はほぼ9割が人と話すという謎の役割でしたので、同僚やお客様とのコミュニケーション、定例会議・打ち合わせの類をどうするかは在宅勤務実施前から課題に感じていました。 2020年2月時点ではそれほど在宅在宅と言われていなかったこと、それまで在宅勤務実施者がプロジェクト内に約1名いらっしゃいましたが、なんとなく休み扱いみたいな雰囲気が漂っていたため、リモート間で積極的に会話するということの前例がなかったのです。

コミュニケーションの手段としては、社内ではSkype、お客様とはJIRA、Webex、某電話会議システム、某メッセージアプリが整備されています。電話は個人携帯しかもっていないので、こちらからかける場合は自腹になってしまいます(公私分計の仕組みは導入されていません)。自分の場合、かけ放題プランではなく従量課金なので電話会議でかけようものなら残業代ぐらいは軽く吹っ飛び死活問題です。 個々の会話はSkype、JIRA、メッセージアプリでなんとかなるのですが、会議・打合せとなるとWebexや電話会議システムの出番になります。問題は、これらシステムの予約と参加者の日程調整です。特にWebexは契約しているアカウント数が少ないため、社内で利用時間枠の取り合いになり、打合せ参加者の日程・時間調整が難しくなります。そして在宅の場合、同僚に会議の段取りをちょっと口頭でお願いするといったことが心理的に難しいと感じました(これは単に組織の問題かもしれません)。 このような準備、段取りに時間がかかり、本来の仕事にかける時間が圧迫されるという状況に陥り、これがストレスになります。 また、社内の会議はSkypeで対応しましたが、参加者各自がSkypeを起動して会議実施する文化がなく、2月あたりでは会議主催者が「勝手に在宅しているのだからSkype等の段取りはそっちでやるのが当たり前」みたいな雰囲気を醸し出されて配慮がなかったのも辛かったですね(これは愚痴)。結局、1年目社員にSkypeで繋いてもらってカメラでスクリーンを撮りながら会話するといった酷く面倒なことをしていました。

よかったことといえば、同僚への作業のお願い等は文字にして送るので、やってほしいことの内容がより具体的になったというメリットはありました。

ちなみに、個人携帯から2回ほど電話会議してしましました。6,000円ほど自腹になりましたが、まぁ諦めてます。

気分転換、切り替えがしづらい

業務逼迫時に在宅勤務へ移行したため、朝起きてパン食べてAM7:00より業務開始、お昼までは数回のトイレ休憩、昼食を休憩も兼ねて30分で食べて午後からPM7:00あたりまでまた数回のトイレ休憩といった生活になりました。トイレも5~6歩で到達する狭い家なので、ほぼ半日PC画面の前にいる状態になります。 ずっと家の中にいるので仕事とプライベートの時間の境目が曖昧になり、毎日起床~仕事~ご飯~就寝の繰り返し、これでストレスが蓄積されていきます。通勤していた場合は自宅から駅、駅から会社まで合計25分ほど歩くのですが、これが意外と気分の切り替えになっていたことに気が付きました。

マンション住まいですが、最近では中庭などにPCを持ち出して在宅勤務されている方もみられます(Web会議までやっているのはビビりました)。おそらく皆さん同じような悩みがあり、工夫されているるのではないかと思っています。屋外でネットが繋がる状態であれば庭やカフェでの作業もいいかもしれませんね。

ちなみに、通勤していた時もAM5:00起き、AM7:00までに出社していました。フレックス制度が導入されており、コアタイムは10:00-15:00、標準勤務時間が7.5時間なので、7:00出社で定時帰宅する場合は15:30までです。

運動不足になる

これまでに書いた通りですが、唯一といっていい運動である通勤の徒歩25分がなくなってしましました。意識的に運動しないと足腰が弱るかも?です。しょうがないので定期的にランニングと筋トレしてます。

お昼ご飯に悩む

通勤していた時はビル内に食堂と売店がありましたので、いろいろメニューが選べましたが、在宅では近所のコンビニ食になってしまい、選ぶものも個人の嗜好により同じものになりがちだと思います。自分の場合は、パスタ、ささみの加工されたやつ、野菜ジュースの3点セットですが、正直飽きます。

 

ということで、在宅勤務は通勤が楽になるというようないいことばかりじゃなくてマイナス面もあり、この局面を工夫して乗り切る必要があると思います。心と体の健康にはくれぐれも気を付けましょう。