ある日、ブロックチェーンでサービスを作ることになったら

これは、[SREアドベントカレンダー](https://qiita.com/advent-calendar/2018/sre)23日目の記事です。

# はじめに
昨年、暗号資産（仮想通貨とは呼ばないそうです）は投機性から非常に盛り上がりました。
対日本円への価値の下降や様々な事件から暗号資産自体の注目は下がりましたが、
ブロックチェーン技術自体の改善やブロックチェーンの投機以外での利用は依然とし盛り上がっています。

ブロックチェーンを使ったサービスなどは、Web3と呼ばれたり、[限られた巨人たちからインターネットを取り戻そう](http://www.itmedia.co.jp/news/articles/1810/01/news062.html)という流れの後押しもあり注目が集まっています。

多くのブロックチェーンでは、、**分散システム**で**改ざん困難**であり、**非中央集権**であることが利点であり、未来のインターネットと感じて投資をしている人がいます。

私は現在、double jump.tokyoという会社で「[My Crypto Heroes](mch.gg/abgQrwC)」というEthereumを利用したブロックチェーンゲームの開発をしています。

以前はインフラエンジニア/SREのようなことをやっていましたが、2018年7月からブロックチェーンエンジニアに転身しました。
世界でも数少ないブロックチェーン開発事例かつSRE視点から、つらつらとブロックチェーンとSREについて書いてみたいと思います。

この記事は、ある程度ブロックチェーンビジネスに関わっている人よりも、ブロックチェーンが気になっているけど既存技術と何が違うかよくわかってない人やある日突然「ブロックチェーンでXやるから！あとはよろしく！！」みたいなことを言われてしまった人を対象としています。
従って、ブロックチェーン関連の用語の正確性よりも既存のWeb/SRE文脈での伝わりやすさを優先するため、用語が正確でない場合があります。

ブロックチェーンの概要から、ブロックチェーン技術を使ったEthereumの実践的な説明をし、現実のサービスを作成したときに感じたブロックチェーンの所感を書いていきます。

# ブロックチェーンとは
ブロックチェーンとは、分散台帳機能を実現する技術です。

「最新のブロック情報」と「実行したトランザクション情報」とある条件を満たす**Nonce**を付け加え、**ブロック**を生成します。

```
Hash(「最新のブロック情報」+「実行したトランザクション」+ Nonce) < 条件X
```

計算内容に「最新のブロック情報」が入っており、システム稼働時からの「最新のブロック情報」を**鎖のように**つなげているため、ある点から改ざんすることは非常に困難となっています。

このNonceの値を見つけ、ブロックを作成することを**Minning**といい、Minningを行う事業者/個人を**Miner**、Minningを行う計算機/プログラムを**Node**と呼びます。

**分散**台帳であるため、Nodeは複数存在します。
分散システムの中で、確定するブロックを一意にするための取り決めを**コンセンサスアルゴリズム**と呼びます。

Hashの性質から、Nonceの値を見つけるのは計算量的に大変ですが、Nonceから条件を満たしていることを検証するのは簡単です。

この計算量的に大変なものを確定するブロックの根拠にするコンセンサスアルゴリズムを**Proof of Work （PoW）**と呼びます。
BitcoinはこのPoWやNonceを発見したNodeへの報酬によるエコシステムが提案されたシステムです。

ブロックチェーンには公開されている範囲によって言い換える事が多く、広く知られているBitcoinやEthereumのようにインターネット上で誰でもNodeになれるし、トランザクションを発行することができるものを**パブリックチェーン**、特定の団体や組合で運用するものを**コンソーシアムチェーン**、1企業が内部で運用するものを**プライベートチェーン**と呼びます。

エンタープライズ文脈では、コンソーシアムチェーンやプライベートチェーンを使った**改ざん不可能な分散台帳**としての価値がもてはやされています。
一方、コンシューマー向け文脈では、パブリックチェーンを用いたトランザクションや決済の透明性、運営者でも手の出せなくなる非中央集権性がもてはやされています。

〇〇社がブロックチェーンを採用！となった場合は、何を目的としているのかを見極めるのが第一歩となります。

以降この記事では、ブロックチェーンといった場合にパブリックチェーンを前提としています。

# ブロックチェーンのスケーラビリティ
前述の通り、分散システムによる高い可用性を得られるものの、PoWという計算量によって担保されたコンセンサスのため、スケーラビリティは非常に低くなります。

具体的には、Bitcoinではブロック生成に期待値として約10分間ほどかかる条件を計算するようにネットワーク内で合意されています。
また、ブロックの同時生成による競合をさけるために6ブロックが後に続くことで承認をするようになっています。
1ブロックに含ませることのできるトランザクションも1MBと決められており、1つのトランザクションが実行され、確定するまで1時間ほど待つことになります。

PoWでコンセンサスを行うブロックチェーンは遅かれ早かれスケーラビリティの問題に当たることとなります。
また、ブロックという**全ての処理をシリアルに実行**することでリソース競合をさけ整合性を担保しているため、並列性がありません。

計算処理をブロックチェーン外に任せ結果だけを記録する**State channel**という考え方や、サービスごとやある程度の単位で別のブロックチェーンを利用する**サイドチェーン**といったスケーラビリティに対する解決策が提案されています。

現実的には、一部の処理はブロックチェーンに託し、それ以外のサービスに関わる部分を従来どおりWebサービスとして実装する場合は、その部分のことを**オフチェーン**と呼びます。

# 公開鍵暗号とアドレス
主なブロックチェーンでは、あるTransactionやリクエストが自分のものである、という証明に公開鍵暗号を使った電子署名が使われます。
ユーザーは秘密鍵を使い自分のTransactionに署名、公開鍵を使って誰もがそのユーザーが署名したものであるということが確認できます。

BitcoinやEthereumでは、楕円曲線署名ECDSAを使っていますが、ブロックチェーンによっては違う署名方式のようです。

また、送金などに使われている**アドレス**は公開鍵から一方向性ハッシュを使って作成することが多いようです。
基本的には、公開鍵から一意に求まる、という理解で問題ありません。

ブロックチェーン技術の敷居の高さには暗号技術がいたるところに出てくることが少なからず理由にあると考えています。
ある日突然ブロックチェーンをやることになったらとりあえず[暗号技術入門](http://amzn.asia/d/2dzSAnq)を買って用語だけでも頭に入れておくと理解がしやすくなるでしょう。

# Ethereumとは
Ethereumとは数あるブロックチェーンネットワークのうちの1つで、**任意のプログラム**が実行できるため注目を集めました。
任意のプログラムは**Smart Contract**と呼ばれ、**Solidity**という言語で記述することができます。
現在、Ethereumでは、15秒に1ブロック生成され、1ブロックに含まれるTransactionの数は、そのSmart Contractの計算量によってきまります。

Transactionの実行には**Gas**と呼ばれる計算量の単位に任意の手数料（**Gas Price**）をかけた手数料がかかります。
このGasがEthereum Minerへの報酬の一部となります。
詳しくは後述します。

ブロックに含ませるTransactionの数は、ネットワーク内で合意された**Block Gas limit**を上限として、NodeがSmart Contractによる計算量Gasによって決まります

こういったGasやTransactionはパブリックに公開されており誰でも確認することができます。
先人により、検索や可視化されているサイトがあるため、サービス運営者は日々次のようなサイトを眺めることになります。

- [Etherscan](https://etherscan.io) Transactionを見たりContractを見たりできる
- [ETH Gas station](https://ethgasstation.info) Gas状況を確認できる

前述のスケーラビリティに対して、Ethereumでは**Plasma**と呼ばれる解決策が提案され研究が進んでいますが、まだ決め手となる実装は出てきていません。
Plasmaという言葉はEthereumを調べていくと必ず耳にする単語なので、予め構えておくと良さそうですが、本記事では特に言及しません。

Ethereumというのは仕様の名前であり、各プログラミング言語で実装されています。
有名なものとして、Go言語による実装である[geth](https://github.com/ethereum/go-ethereum)とRustによる実装である[Parity](https://github.com/paritytech/parity-ethereum)があります。

プライベートチェーンでEthereumを利用する場合は前述のgethもしくはPrityで行うことが多くなります。

パブリックブチェーン上でサービスを行ないたい場合、いずれかの実装でNodeを運営する機会もあるかと思いますが、
現在の主流は[INFURA](https://www.infura.io)というサービスを使ってネットワークに接続するケースが多いかと思います。
INFURAやその他、Ethereumの開発エコシステムは[ConsenSys](https://consensys.net/)という団体が開発しているものを利用することが主流です。
いくつかの公開資料[1](https://crypto.watch.impress.co.jp/docs/event/1127478.html),[2](https://d1.awsstatic.com/events/jp/2017/summit/devday/D3T7-4.pdf)からINFURAはAWS上で動いていることが確認できます。

一時はテンプレートを用意する程度で、そこまでブロックチェーンに力を入れていないように見えたAWSも[Amazon Managed Blockchain](https://aws.amazon.com/jp/blockchain/)を発表するなど、SREにとって身近な存在となってきました。
このAmazon Managed BlockchainではEthereumが採用されています。

ブロックチェーンを利用したサービスを開発する場合、第一の選択肢としてEthereumが挙がるのは間違いないでしょう。


# 通貨としてのEthereum
Minningの報酬や計算実行手数料は、通貨としてのEthereumを使うことになります。
仮想通貨取引所での略称はETHです。
これ以降、**ETHといった場合は通貨としての説明**、**Ethereumといった場合はパブリックネットワークを指す**ように説明します。
この辺の用語の乱立も混乱の元と考えていますので、一口にEthereumと言った場合でも何について議論しているのかきちんと整理できることが重要になります。

基本単位は**ether**で、執筆時点において`1 ether = 13,000日本円前後`で取引されています。
最小単位は**wei**で `1 wei = 0.000000000000000001 ether`です。

よく使われる単位として**gwei**があり、`1 gwei = 0.000000001 ether`となります。

# SmartContractとSolidity
Ethereumでは[Solidity](https://github.com/ethereum/solidity)というプログラミング言語を用いて任意のプログラムを実行することができます。

雑感で言えば、全体としてはJavaScriptのような形の言語です。
**浮動小数点型はなく、型のサイズの基本が256bit**なので大きな桁数を扱うことができます。
ほぼClassのような存在として、**Contract**という要素があり多重継承ができます。

Solidityで書かれたコードは、コンパイラを通して**[ABI](https://solidity.readthedocs.io/en/develop/abi-spec.html)**とバイトコードに変換されます。

このバイトコードをEthereum上にデプロイすることで、任意のプログラムSmartContractとして動作します。
このEthereumへのデプロイにも、Gasがかかるため事前にETHを手に入れて置く必要があります。
SmartContractは、単純にContract（コントラクト）と呼ばれたり、日本語ではスマコンと略されたりしています。

[CryptoZombies](https://cryptozombies.io)という学習プログラムがあり、Solidityおよび後述のERC721を学ぶのに最適なプログラムがあります。
ある程度実力のあるエンジニアであれば1日程度で終わりますので、SmartContract開発の取っ掛かりには非常にオススメできます。

より実践的なツールとして、[Remix IDE](https://remix.ethereum.org/)というWeb IDEがあり、コーディングからコンパイル、デプロイ、簡単な動作確認が行えます。
また、フレームワークとしてConsenSysが開発している[Truffle](https://truffleframework.com/)が現在のデファクトスタンダードとなっています。

Web開発の文脈でいうとこのContractが1つのマイクロサービスとして見なすのが一番理解しやすいと感じています。

# Smart Contractを実行するには
JavaScriptライブラリであるweb3.jsが一番有名です。

基本的に、コンパイル時に生成されたABIを解釈して、各言語のライブラリに落とし込むことでSmart Contractのクライアントとして動作します。

個人的には、Go言語で利用することが多く[go-ethereumの提供している変換ツール](https://github.com/ethereum/go-ethereum/wiki/Native-DApps:-Go-bindings-to-Ethereum-contracts)でABIからGoライブラリに変換し利用しています。

Smart ContractをロジックとしてEthereum上で実行し、そのフロントエンドをJavaScript web3.jsを用いて実行できるものを**Decentralized Apps (DApps)**と呼びます。

# EIP/ERC
[EIP](https://eips.ethereum.org/)は、Ethereumの仕様です。
[GitHubリポジトリ](https://github.com/ethereum/EIPs)で管理され、Issue番号によって採番されているようです。

EIPとついているものは、Ethereum本体の改善や更新などが決められています。
ERCは、SolidityであったりEthereumを利用する上での標準仕様がまとめられているという理解で問題はなさそうです。

サービス展開する上で、特に有名なERC20とERC721を紹介します。

## ERC20
[ERC20](https://eips.ethereum.org/EIPS/eip-20)とはEthereum上で独自のTokenを発行するための標準仕様とインタフェースです。

独自のToken、つまり自分だけの仮想通貨、CoinをContractで作成できます。
発行上限も渡す先も思いのままですが、一般的に人に渡ったCoinは持ち主にしか利用できないようになります。
もちろんContractで書いた通りにしか動かないので不正をできるようにも書けますが、そこは透明性と非中央集権性を是とするブロックチェーンにおいて、不正のできるCoinは信頼できず価値がつかないでしょう。

参考実装として、Zeppelinという会社が開発しているOSSである[OpenZppelin](https://github.com/OpenZeppelin/openzeppelin-solidity)があります。
このOpenZeppelinによるERC20実装を時前のContractに継承して独自機能を追加することがあります。

当然ですが、独自のTokenはEthreum上でしかやりとりできず、ある程度価値が出たとしてもETHの価値に連動しがちです。

## ERC721
[ERC721](https://eips.ethereum.org/EIPS/eip-721)とはEthereum上で独自の**Non-Fungible Token(NFT)**を発行するための標準仕様とインタフェースです。

Non-Fungible Tokenとは日本語で**代替不可トークン**と呼ばれています。
代替不可能とは、あるTokenAとTokenBは等価値ではなく交換がし難いという理解になります。
よくあるたとえでは、うちのワンちゃんとお隣のワンちゃんは同じ犬であるが、交換はできないというのが代替不可の意味です。

ゲームでいうとアイテムがそれに当たります。
[CryptoKittes](https://www.cryptokitties.co/)や[Etheremon](https://www.etheremon.com/)、MyCryptoHeroesでは、ゲームのアイテムやキャラクターをこのERC721で扱っています。

ブロックチェーン上、かつ標準仕様であるERC721を使うことで、ユーザー間での流通が可能になります。
実際、Ethreum上のERC721をやりとりするマーケットの[OpenSea](https://opensea.io/)では、毎日数多くのトークンがやりとりされています。

そのトークンの所有権が明確にユーザーのものであるというのはブロックチェーン上でサービスを行う上で大きな魅力です。

# Gas
ここまで何度か出てきたGasですが、非常に分かりづらいです。
まず、言葉を整理すると、

- **Gas**
    - トランザクション実行するための計算量の単位、同じ処理であれば同じGasになる
- **Gas Price**
    - 実行するユーザーが指定する1Gasあたりの実行手数量、単位はgwei単位であると割り切ってもよい
- **Transaction cost**
    - あまり明確に名前がついていないが、トランザクションを実行した場合にかかったコスト、普通は`Gas * GasPrice`
- **Gas Limit**
    - Contract上に無限ループがあった場合多額のコストがかかるため予め払う上限を決めることができる
- **Block Gas Limit**
    - あるブロックに入れることのできるGasの総和
    - Gas Limitと勘違いしやすい

があります。

基本的に、Minerは**高いGas Priceを払ってくれる処理を実行したい**かつ、**Block Gas Limit上限いっぱいまで処理を詰め込む**という戦略が手数料を得られる最適解です。

ユーザー視点では、Gas Priceを高くすれば処理が行われやすく優先的にブロックに取り込まれやすい、
サービス開発者視点では、Gasの小さい処理の方がユーザーにコストの負担が少なく、ブロックに取り込まれやすいということになります。

エンジニアでもちゃんと理解できていないケースもあり、初見では難解ですが理解しなければユーザー対応などもままならない状況になるので、腰を据えて理解するようにしましょう。
また、これを理解すると前述のGas Stationなどを楽しくみることができます。

# Wallet
Walletという概念があります。
ブロックチェーン全般におけるWalletとは、ユーザーが資産を預けるアドレスとその秘密鍵をセキュアに保存してくれる存在を指します。

Ethereum界隈においてWalletとは、

- ECDSAを行うための秘密鍵を管理する
- JSライブラリであるweb3.jsに秘密鍵情報を含ませた状態で、`window.web3`を提供するWebブラウザ

のことを指します。

PCブラウザでは、[Metamask](https://metamask.io)、モバイルでは[Trust](https://trustwallet.com/ja/)が先行者として有名です。
Ethreum上のDAppsがにわかに流行り始めたため、[tokenPocket](https://tokenpocket.jp/)、[GO! WALLET](https://www.go-wallet.app/)、[Qurage](https://qurage.app/)と言った国産DAppsブラウザも増えてきています。

# ブロックチェーンとSRE
さてここまでが、前提知識になります。

ここから、実際にサービスを提供してきた~~愚痴~~知見を共有します。

モバイルアプリの大御所であるAppleやGoogleでは自社プラットフォーム決済を利用しないETH払いでのアプリを許容しておらず、必然的にWebで作成することになります。
**Walletブラウザが必須**というのは非常に高いハードルで、広くユーザーを集めるにはこのハードルを超える必要があります。
解決策は特にありません。
また、Walletが接続するEthereumのNodeはサービス提供者側が指定できるものではなく、その通信状況やNode状況によって不具合が発生します。

現在、ブロックチェーンを利用するということは、**自分たちのコントロール不可能な構成要素**がいくつも増えることになります。

EthereumはTransactionの実行に15秒ほどかかるため、**全ての処理をEthereum上で実行する**というのはUX的に最悪なものになります。
サービスの設計で、**待ち時間も楽しめるものにする**もしくは思い切って**重要な部分以外はオフチェーンを利用する**というのが現実解なのかなと想っています。
また、ブロック内のTransactionであってもTransactionはシリアルにしか実行されません。
この制約がある以上、ブロックチェーンで通常のRDBMSのような処理速度を期待するのはかなり厳しいのではないかと思っています。

Ethereum上にロジックをデプロイする場合、Solidityは一度デプロイしたら変更できません。
一応[UpgradableなContract](https://zoom-blc.com/how-to-develop-upgradable-contracts)を作成する方法はあるのですが、一度動き出したContractを変更するのは容易おではありません。
昨今の**継続的デプロイといった概念は一度忘れましょう**。
Admin権限で行う一つ一つが緊張感のあふれるものになります。
細かい運用TipsはEIPとOpenZeppelinを読み込むことで知見を得られるでしょう。

# おわりに
Ethereumを用いたブロックチェーンサービスを行う上で、必要となりそうな知識を順を追って説明しました。

もともとは、エンジニアの友人たちに私のやっている領域を説明するつもりで書き始めた文章でしたが、実際に書いてて辛くなるくらい情報が多くなってしまいました。

用語が正確でない場合や、初学者向けに分かりづらい部分がありましたら、Twitter（[@rmanzoku](https://twitter.com/rmanzoku)）かコメント欄にぜひフィードバックいただければと思います！

随時、加筆修正を行うつもりですので、気になるかたはストックかいいねを頂けると幸いです。