Ethereumホワイトペーパー略解

はじめに

執筆時点の市場規模は約 2,600 億ドルで,ビットコインに次ぐ第二位となるイーサリアム.

スマートコントラクトという仕組みにより,決済手段としての色が強いビットコインに対し,アプリケーションを実行するプラットフォームという位置づけになっています.拡張性が高く,イーサリアムの規格である ERC20 を使用したトークンが一時期爆発的に流行っていました.

イーサリアムのホワイトペーパーは 2013 年に Vitalik Buterin 氏に公開され,2015 年のイーサリアムプロジェクト開始前に書かれたものでした.しかし,イーサリアムが実現したい世界を正確に伝えるために今もメンテナンスされています.

本記事ではホワイトペーパーに準じてざっくりと以下のような内容を取り上げています.

  • ビットコインの仕組み
  • イーサリアムの仕組み
  • イーサリアムで実現される非中央集権型アプリケーション(DApps)

A Next-Generation Smart Contract and Decentralized Applicaton Platform

ビットコインは価値を保証する裏付けや本質的価値を持たず,中央機関による発行や制御が行われないデジタル資産の最初の例となる通貨です.しかし,もっと重要なのは非中央集権的コンセンサスシステムとしての基礎的なブロックチェーン技術であり,ビットコインの側面にも注目が集まっています.

ブロックチェーンをベースにしたアプリケーションには,例えば以下のようなものがあります.

  • colored coin:ブロックチェーン上にカスタマイズした通貨や金融システムを構築して異なるデジタル資産を扱う (cf. Open Asset Protocol)
  • smart property:物理的な資産の所有権を管理する
  • Namecoin:ドメイン名等の代替不可能な資産を管理する (cf. NFT, ERC721)
  • smart contracts:実装した任意のルールに従って制御されるデジタル資産を扱う
  • DAOs (Decentralized Autonomous Organizations):スマートコントラクトを使用するプロジェクトの一つ

イーサリアムが提供しようとしているのはプログラミングで完全なチューニングを行えるブロックチェーンです.任意の機能をエンコードしたコントラクトによって制御し,様々な機能をブロックチェーンシステムに組み込めます.

Introduction to Bitcoin and Existing Concepts

History

ブロックチェーンの原点,非中央集権的デジタル通貨の概念は数十年間に渡って存在してきました.

  • 1980-1990 年代:データを伏せて利用できる暗号技術 Chaumian blinding1 で匿名性のある電子通貨を実装(中央機関の仲介が必要で流行らず)
  • 1998 年:非中央集権的コンセンサスと同様に計算問題を解いて通貨を発行する b-money の提案(具体的な実装内容に乏しい)
  • 2005 年:b-money, Hashcash を応用した暗号通貨システム構築のための reusable proofs of work の登場(システムを動かすコンピュータへの依存が解決できず)
  • 2009 年:Proof of Work (PoW) を採用したビットコインの実装

PoW をメカニズムに用いることで以下の二つの課題を解決できます.一つ目はシンプルでそこそこ効率的なコンセンサスアルゴリズムを用いることで,ネットワークのノード群がビットコインブロックチェーンの更新に対して集合的に合意すること.二つ目は自由にコンセンサスプロセスに加わることができるため,誰がコンセンサスに影響を与えるかという政治的問題が解決され,それと同時にシビル攻撃(大量の仮 ID 等を使った評価システムの破壊)を防げることです.個々のノードを識別して管理する必要はなく,ノードの影響力(重み)はその演算能力に比例するため,経済的な参入障壁のみが存在します.

その後に考えられたのが Proof of Stake (PoS) です.PoS ではノードの重みは演算能力ではなく通貨保有量に比例します.この双方のメリットについては議論の最中ですが,少なくともどちらも暗号通貨を支えるアプローチとして有用であるといえます.

Bitcoin As A State Transition System

技術的に見ると,ビットコインのような暗号通貨の台帳は状態遷移システムとして解釈できます.状態遷移システムは発行されたすべてのビットコインの保有状況を示す state と,state とトランザクションを入力として新しい state を出力する状態遷移関数から成ります.

例えば,一般的なバンキングシステムでは state はバランスシート,トランザクションは振替依頼にあたり,状態遷移関数は振替元口座から送金金額分を減らして振替先口座の残高に加算することと同じです.

もう少し厳密に定義しようとすると以下のように表現できます.

# S: State, TX: Transaction, S': new State
APPLY(S, TX) -> S' or ERROR

# Banking system defined above
APPLY({ Alice: $50, Bob: $50 }, "send $20 from Alice to Bob") = { Alice: $30, Bob: $70 }

# Wrong case
APPLY({ Alice: $50, Bob: $50 }, "send $70 from Alice to Bob") = ERROR

ビットコインにおける state は送金に使われていないコイン,少し技術的に説明すると未使用トランザクションアウトプット (unspent transaction output: UTXO) のまとまりです.単体あるいは複数の UTXO を入力として UTXO 所有者の秘密鍵による電子署名を作成し,単体あるいは複数の UTXO を出力とします.この出力をブロードキャストすることで state が更新されます.

ビットコインの仕組みを先ほどの定義に則して考えると,状態遷移は以下のように表されます.

  1. 各入力トランザクションについて UTXO が S に含まれない,もしくは UTXO の所有者による電子署名でない場合は ERROR を返す
  2. 出力 UTXO の総額が入力 UTXO の総額を上回っている場合は ERROR を返す
  3. すべての入力 UTXO を削除し,出力 UTXO を追加する

支払う金額ちょうどになるように UTXO を集めるのは難しいため,現実的には複数の UTXO を集めておつりの UTXO を発行することで対応します.例えば,Alice から Bob へ 11.7BTC を送るとき,Alice の所有する UTXO (6BTC, 4BTC, 2BTC) を入力トランザクションとして,Bob 宛てに 11.7BTC.Alice 自信宛てに 0.3BTC の UTXO を作成します.

Mining

信頼性が保証される中央機関が存在すれば簡単に実装できますが,ビットコインは非中央集権的な暗号通貨システムを構築するため,すべてのノードがトランザクションに合意するためのコンセンサスシステムが求められます.ビットコインのコンセンサスプロセスでは複数のトランザクションをパッケージングする,すなわちブロック生成を継続的に行うノードが必要です.ブロックは約 10 分ごとに生成され,各ブロックにはタイムスタンプ,ナンス,前ブロックのハッシュ,前ブロック生成以降の取引に対応するトランザクションのリストが含まれています.これを繰り返すことでブロックチェーンは恒久的に伸び,最新の state を更新していくことができます.

ブロックの検証アルゴリズムは以下のようになります.

  1. 前ブロックが存在していて,その内容には問題がないことを検証する
  2. 前ブロックのタイムスタンプ以降2時間以内の生成となることを確認する
  3. PoW を実行する
  4. 前ブロックの最後尾の state を S[0] とする
  5. n 個の TXS[i+1] = APPLY(S[i], TX[i]) (i=0, ..., n-1) のように連結させる(途中でエラーが起これば false を返す)
  6. true が返れば S[n] を state としてブロックの最後尾に登録する

検証に PoW の実行を必要とする点は他のシステムには見られない特徴です.そこで検証する内容は,SHA-256 の二重処理を通して得られる 256bit のブロックのハッシュが閾値よりも小さいか否かというものです.閾値は難易度調整アルゴリズムによってその時々で変化していて,現在(ホワイトペーパー更新時)は 2187 になっています.この難易度調整という仕組みでブロックチェーンをシビル攻撃から守っているのです.また,SHA-256 は出力が予想できないランダム関数として用いており,あるナンスとそれに対するハッシュの照合を反復する方法でしか検証できません.

現在の条件となっている 2187 であれば平均 269 回の反復計算で正しいナンスを見つけ,ブロックが生成されます.この条件は 10 分に一度のペースでブロックを生成できるよう, 2016 ブロックごとに再設定しています.

PoW の計算を行うノードであるマイナーには現在 12.5BTC が支払われています.これがビットコイン発行の唯一の手段です.加えて,トランザクションの出金額は入金額よりも必ず大きくなっており,その差額がトランザクション手数料としてマイナーに支払われています.

マイニングを必要とする理由は,攻撃例を考えると理解できます.例えば,ビットコインに対する攻撃シナリオが考えられます.

  1. 商品購入の対価として販売者宛てに 100BTC 送金する
  2. 商品が届くのを待つ
  3. 自分宛てに 100BTC 送金する
  4. 自分宛てのトランザクションが先に来たものだとビットコインネットワークに誤認させる

ステップ1の送金トランザクションが含まれるブロック(ここではブロック 270 とする)が承認されてから一時間ほど経つと,5ブロック以上がその先に繋がっている状態になり,1の送金は正式に承認された状態 (confirming) になります.これによって支払い状況が確定 (finalize) し,販売者は商品を発送します(デジタル商品であれば瞬時に).攻撃者はこれと同時期に販売者への送金額を相殺する自分宛ての送金トランザクションを別に作成します.また,ブロックチェーンを分岐 (fork) させ,元のブロックチェーンのブロック 269 に対して異なるバージョンのブロック 270 を作成し,元のブロック 270 の代わりにこれを使用します.この時点で善意のノードはブロック 275,攻撃者はブロック 270 を生成しており,攻撃者のブロックチェーンを正しいものと認識させるためには圧倒的な演算性能を以て最長のブロックチェーンにしなければなりません.

この攻撃は 51% 攻撃と呼ばれています.全ノードの演算能力の過半数が攻撃者によるものであれば攻撃者のブロックチェーンのほうが長くなるからです.演算能力を高めるためにはコストがかかるため,51% 攻撃で得られるリターンよりもマイニング報酬のほうが多い場合,合理的に判断すれば攻撃の判断を下すことはないと考えられます.

Merkle Trees

ビットコインの拡張性を考える上で重要なことは,ブロックのデータを階層構造で保存することです.ブロックのハッシュは実際には約 200 バイトほどのブロックヘッダのハッシュで,タイムスタンプ,ナンス,前ブロックのハッシュ,ブロックに含まれるすべてのトランザクションを保存するマークルツリーのルートハッシュを含んでいます.マークルツリーは二分木構造を持つハッシュ木で,データを持つ大量の葉のノードを反覆的に二つずつ文字列結合してハッシュ化し,親のノードを生成します.マークルツリーを使用することで断片的な少ない情報からデータの正しさを検証できます.攻撃者が異なるトランザクションに更新しようとした場合には最下層のノードが変更されるため,再帰的に一つ上のノードが変更され,最終的にブロックのハッシュが元と異なるものになります.

マークルツリーのプロトコルは長期間の持続可能性を実現するために必要なものです.ビットコインネットワークのフルノードはすべてのブロックのデータを保存・処理するため,2014 年春の時点でデータ容量は 15GB,毎月数 GB 単位で増えており,今後ネットワークへの参加者は増えていくと考えられます.simplified payment verification (SPV) プロトコルはフルノードと別の,ブロックヘッダーのみを持ついわゆるライトノード向けに用意されています.トランザクションに関連するブランチのハッシュのみを持ち,軽量のデータで支払いを検証できます.

Alternative Blockchain Applications

ブロックチェーンベースのアプリケーションは様々なものが考えられてきました.1998 年に Nick Szabo 氏が公表した secure property titles with owner authority では,複製されたデータベース技術の利点としてブロックチェーンベースのシステムを使った不動産登記簿が提案されました.しかし,あまり影響力はなく,プロトコルが実装されることはありませんでした.その後,ビットコインの非中央集権コンセンサスプロトコルが開発されて以来,異なる多くのアプリケーションが生まれています.

  • Namecoin (2010):非中央集権型の名前登録のデータベースとして説明できます.Tor, Bitcoin, BitMessage 等の非中央集権型プロトコル上でアカウントを識別し,相互にやり取りできるようにするものです.問題は同じ手順を踏めば複数人が同じ名前を使用できてしまうため,なりすましの可能性があることで,その解決方法としては先着順で名前を利用する他ありません.最初に到着したものが正しいとする考え方はビットコインブロックチェーンにおけるコンセンサスプロトコルととても相性がよいといえます.
  • Colored coins:ビットコインブロックチェーン上で誰でもデジタル通貨が作れるようにするプロトコルを提供することを目的に作られました.UTXO に「色」をつける(=プロトコルに応じたデータを追加する)ことで通貨を発行し,その通貨を使用する際には入力と同様に他の UTXO の色を定義します (cf. Open Asset, CoinSpark, Colu, EPOBC).この特定の色がついた UTXO のみをウォレットで追うことでビットコインと同様に利用できます.
  • Metacoins:Metacoin はビットコインのトランザクションを使って Metacoin のトランザクションを保存しますが,ビットコインとは異なる状態遷移関数を持っています.Metacoin のプロトコルでは誤りのあるトランザクションを防げないため,もし状態遷移関数がエラーを返した場合には state は更新されません.この方法では任意の通貨のプロトコルを簡単に作ることができ,ビットコインに含まれない機能を実装することはできないものの,自分で実装せずともビットコインのネットワークやマイニングの仕組みを利用できるため,開発コストは低くなります.

以上より,コンセンサスプロトコルを実現するには,独立したネットワークを作る方法とビットコインシステムの上に作る方法の二つのアプローチがあります.前者は Namecoin のようにアプリケーションに適用しやすいものの実装は難しくなります.後者のビットコインベースでは実装しやすいものの SPV は利用できません.SPV は自ら支払いの検証を行わなくてもブロックの深さを一つの基準として安全性を保証する仕組みですが,ビットコインはその上に載っている別の通貨のトランザクションの検証結果の影響を受けずに state を更新していくため,ブロックの深さだけでは別の通貨の state を正しく更新し続けているか保証できないからです.したがって,このようなメタプロトコルで SPV を実装するためにはトランザクションが正しいかビットコインブロックチェーンの開始時点まで遡ってスキャンする必要があります.現状では,すべての「軽量な」ビットコインベースのメタプロトコルは信用できるサーバによるデータ提供に依存しており,暗号通貨の第一の目的である信頼の必要性の排除を考えれば,まだ最適とは言えません,

Scripting

実際のところ,ビットコインプロトコルは少しスマートコントラクトの概念をもたらしています.UTXO を公開鍵で所有するのみならず,スタックベースのプログラミング言語を用いたより複雑なスクリプトで表現できます.公開鍵の所有者証明メカニズムはスクリプトで実装されています.楕円曲線暗号を用いた電子署名を入力とし,トランザクションと UTXO を所有するアドレスで検証します.検証が成功すればスクリプトは1を返し,失敗すれば0を返します.他にも,更に複雑なケースが存在します.例えば,「マルチシグ」では三つあるうちの二つの秘密鍵を用いた電子署名を必要とするといったスクリプトを実装してます.ビットコインの支払いに複数の秘密鍵が必要になることから,企業のアカウント利用,セキュリティの向上,エスクローでの運用などに利用しやすくなります.

しかし,ビットコインのスクリプト言語にはいくつか制限があります.

  • チューリング不完全:ビットコインにおけるスクリプト言語には基本的なものの中で欠けている機能があります.その主たるものがループ処理です.これはトランザクション検証中に無限ループに陥るのを防ぐためで,理論的には何度も同じコードを書けば実装できますが,効率的ではありません.例えば,別の楕円曲線の署名アルゴリズムを実装しようとすれば 256 回処理を繰り返す必要があるのです.
  • Value-blindness:UTXO のスクリプトでは引き出す金額を細かく制御する方法がありません.一例としてヘッジ契約を考えます.A さんと B さんが $1000 相当の BTC を購入し,30 日後にスクリプトが $1000 相当の BTC を A さんに送金,残りを B さんに送金することとします.UTXO は all-or-nothing であるため,複数の UTXO の組み合わせで送金するという非効率的な方法しかありません.
  • state の欠如:UTXO の状態は未使用か使用済みかの二種類で,それを超える多段階のコントラクトやスクリプトは実装できません.
  • Blockchain-blindness:UTXO はナンス,タイムスタンプ,前ブロックのハッシュ等のデータが確認できず,スクリプト言語から潜在的に価値のあるランダム性を奪っているため,ギャンブルやその他のアプリケーションを制限しています.

以上より,暗号通貨システムの上にアプリケーションを構築するアプローチは,新しいブロックチェーンの構築,ビットコインシステム上でのスクリプト実装,ビットコイン上でのメタプロトコル実装の三つになります.新しいブロックチェーンの構築は最も自由度が高いものの,自らセキュリティ等を考えねばならず開発コストが高くなります.スクリプト言語を使う方法は実装しやすく標準化されていますが容量制限があり,メタプロトコルでは拡張性に欠けています.

Ethereum

イーサリアムは非中央集権型アプリケーションを構築するためのプロトコルとして作られました.

Philosophy

  • Sinplicity:イーサリアムのプロトコルはストレージや時間の非効率性を犠牲にしたとしても,できるだけシンプルにします.暗号通貨によって前例のない民主化を実現し,イーサリアムがすべての人に開かれたプロトコルとなるように,平均的なプログラマーがすべての仕様を理解して実装できようにあるべきです.多大な利益を得られない限り,複雑性を増すような最適化は含んではなりません.
  • Universality:基礎的な設計思想として,イーサリアムは機能を持ちません.その代わりにチューリング完全なスクリプト言語を提供し,プログラマーは数学的に定義したコントラクトやトランザクションを使うことができます.これによって,デリバティブ(金融派生商品)や独自の通貨を作ることもできます.
  • Modularity:イーサリアムプロトコルはモジュラーとして分割可能なように設計されています.一箇所でプロトコルを修正すればアプリケーションに手を加えなくても動き続けることができるシステムを目指しています.個別に機能が完全なライブラリを実装すれば,イーサリアムの特定の機能を必要とせずに動かすことが可能です.イーサリアムはそれ自体だけでなく暗号通貨のエコシステム全体に多大な利益を生むように開発するべきでしょう.
  • Agility:イーサリアムプロトコルの詳細は不変なものではありません.ただ,高レベルのコントラクトの変更は非常に慎重に行います.開発テスト中,プロトコルアーキテクチャや Ethereum Virtual Machine (EVM) 等の修正で大幅にスケーラビリティやセキュリティを向上させられるとわかるかもしれないので,その場合は修正していきます.
  • Non-discrimination and non-censorship:プロトコルで特定の利用方法を制限するべきではありません.プロトコルは直接的な害をもたらすことを規制するべきで,特定の望ましくないアプリケーションを規制するものであってはなりません.プログラマーはステップ数に応じたトランザクション手数料を払っている限り,無限ループすら実行できます.

Ethereum Accounts

イーサリアムにおいて state は 20bytes のアドレスを持つアカウントというオブジェクトで構成されており,状態遷移はアカウント間での値と情報の直接のやり取りとなります.イーサリアムアカウントは以下の4種のフィールドを持ちます.

  • ナンス:各トランザクションが一回のみ処理されるように使用するカウンター
  • 現在の Ether 残高
  • コントラクトコード
  • ストレージ

Ether はイーサリアムのトランザクション手数料の支払いに用いられます.アカウントのタイプは2種類に分けられ,秘密鍵で制御する外部所有アカウント (externally owned account: EOA) とコントラクトのコードで制御するコントラクトアカウントがあります.EOA はコードを持たず,トランザクションを作成・署名することでメッセージを送信します.コントラクトアカウントは内部ストレージへの読み書きを許可するメッセージを受け取り,メッセージを送信したりコントラクトを作成したりします.イーサリアムにおけるコントラクトはその実行環境の中で活動できる自律的なエージェントのようなもので,メッセージやトランザクションをきっかけに特定のコードを実行し,Ether 残高や永続的な変数を管理する key/value store を直接操作します.

Messages and Transactions

トランザクションという用語は EOA から送られたメッセージを保存する署名済みデータパッケージを指しています.トランザクションに含まれるものは以下の通りです.

  • メッセージの受信者
  • 送信者を識別する電子署名
  • メッセージ送信に使用する Ether の金額
  • オプションのデータ領域
  • トランザクション実行時に許可されるステップ数の最大値である STARTGAS の値
  • 送信者が負担する1ステップあたりの手数料である GASPRICE の値

最初の三つはどの暗号通貨であっても見られる標準的なものです.デフォルトではデータ領域は空ですが,EVM はコントラクトがデータにアクセスする opcode(特定の処理を実行する命令)を備えています.

STARTGASGASPRICE はイーサリアムの理念の実現に重要な存在です.偶発的あるいは敵意による無限ループや無駄な計算を防ぐために,各トランザクションにはコードを何ステップ実行するか制限を設ける必要があります.その制限の単位を「ガス」とし,ステップ数,各ステップでの計算コスト,保存するデータ量に応じて必要なガスの量を増やします.また,トランザクションデータ1バイトにつき 5gas かかります.このシステムは攻撃者にリソース(計算量,使用帯域,容量)に応じた手数料を求めることで,ネットワークのリソースを使用するほど比例して手数料も高くなるため,攻撃コストも高くなるのです.

Messages

コントラクトは他のコントラクトにメッセージを送る機能があります.メッセージはシリアル化されない仮想オブジェクトでイーサリアム実行環境にのみ存在し,以下の内容を含んでいます.

  • メッセージの送信者(暗示)
  • メッセージの受信者
  • メッセージの送信にかかる Ether
  • オプションのデータ領域
  • STARTGAS

ユーザではなくコントラクトが生成することを除けば,本質的にはメッセージはトランザクションのようなものです.メッセージは実行中のコントラクトが CALL opcode を実行すると生成されます.

トランザクション或いはコントラクトによるガスの割り当ては,トランザクションとすべてのコード実行で消費する合計が適用されます.例えば,A から B に 1000gas でトランザクションを送信し,B が C へメッセージを送信する前の処理で 600gas,C が内部処理で 300gas 使用するとき,B はあと 100gas 使用できます.

Ethereum State Transition Function

イーサリアムの状態遷移関数 APPLY(S, TX) -> S' は以下のように定義されています.

  1. トランザクションの値が正しいか,署名が正しいか,ナンスが送信者アカウントのナンスとマッチするかを確認し,どこかで引っかかったらエラーを返す.
  2. STARTGAS * GASPRICE でトランザクション手数料を計算し,署名から送信先アドレスを判断する.送信者の残高から手数料を引き,送信者のナンスを1加算する.残高不足の場合はエラーを返す.
  3. GAS = STARTGAS とし,バイトあたり一定量のガスを除いていく.
  4. 送信者アカウントから受信者アカウントにトランザクションの値が転送される.もし受信者アカウントが存在しなければ作成される.また,受信アカウントがコントラクトの場合はコードが終了するかガスが尽きるまで実行する.
  5. もし送信者の残高不足,或いはガス不足による実行終了となった場合は変更された state を元に戻し,手数料をマイナーのアカウントに付加する(支払い済み手数料は戻らない)
  6. 何もなければ,消費されなかった手数料は送信者に返金し,支払われた手数料はマイナーに送金される

コントラクトコードは低級の EVM コードで書かれています.高級言語である Serpent で書いたものが EVM コードにコンパイルされるといった感じです. ここで一つ例を考えてみます.空のコントラクトにトランザクションで 10ETH と 64bytes のデータ送り,そのときの条件を STARTGAS = 2000gasGASPRICE = 0.001 とします.ここで,データの前半 32bytes は数値 2 を表し,後半 32bytes は CHARLIE という文字を表すものとします.このとき,状態遷移のプロセスは以下のようになります.

  1. トランザクションを検証する.
  2. 送信者が最低 2000 * 0.001ETH 保有しているか確認し,保有していれば 2ETH 引く.
  3. gas = 2000 とし,トランザクションサイズが 170bytes と仮定すると,残るガスは 2000 - 170 * 5 = 1150 となる.
  4. 送信者から 10ETH 引き,コントラクトに 10ETH 足す.
  5. インデックス 2 が空であれば,これに対して CHARLIE を格納するコードを実行する.187gas 消費すると仮定すると,残るガスは 1150 - 187 = 963 となる.
  6. 送信者に未使用のガス 963 * 0.001 = 0.963 を返金し,処理した state を返す.

トランザクションの受け手がコントラクトでない場合はコントラクトのコード実行にガスを消費しないので,GASPRICE にトランザクションを乗じた値がトランザクション手数料になります.

ガス欠の場合はメッセージの実行とそれがトリガーになった実行が巻き戻されますが,その親の実行は巻き戻りません.すなわち,A が G gas で B を呼んだとき,A の実行で消費されるガスは高々 G gas であることが保証されるということです.

ちなみに,CALL によく似た opcode に CREATE がありますが,前者は既に存在するコントラクトを呼ぶのに対し,後者は新たなコントラクトを作成するという点のみ異なっています.

Code Execution

イーサリアムのコントラクトはスタックベースのバイトコードによる低級言語で書かれています.コードはバイトの連続で構成され,それぞれのコードは処理内容を示しています.3種類の方法で保存されているデータにアクセス可能です.

  • スタック:LIFO 方式のコンテナ
  • メモリ:無限に拡張できるバイト列
  • 長期ストレージ:key/value 方式のストレージで,計算終了時にリセットされる上記二つと異なり,長い期間値を保存する

コードはブロックヘッダと同様に受信したメッセージの値や送信者,データにもアクセス可能で,データのバイト列を出力として返します.

EVM の実行モデルはとてもシンプルです.state は以下のタプル (block_state, transaction, message, code, memory, stack, pc, gas) で定義されています.block_state はすべてのアカウントを含むグローバルな state で,残高やストレージも含まれています.実行のすべてのラウンドの開始時に pc 番目のコードを取得して現在の命令を検出します.それぞれの命令にはタプルの変更に関する内容が定義されています.例えば,ADD 命令はスタックから上2個の要素を取り出してその合計をスタックに挿入し,gas を1減らして pc を1増やします.また,SSTORE 命令は上2個の要素を取り出し,2番目の要素をコントラクトのストレージに保存します.このときのインデックスは1番目の要素で示されています.just-in-time コンパイラで EVM 実行を最適化する方法はありますが,基本的な実装では数百行のコードを実行可能です.

Blockchain and Mining

イーサリアムブロックチェーンはビットコインブロックチェーンと似ている点が多いですが,ビットコインブロックチェーンはトランザクションリストのみを持つのに対し,イーサリアムブロックチェーンはトランザクションリストと最新の state を持つという違いがあります.また,ブロック番号と難易度もブロックに保存されています.

イーサリアムでは以下のようなブロック検証アルゴリズムが用いられています.

  1. 一つ前のブロックが存在していて,その内容が正しいか確認する.
  2. タイムスタンプが前ブロックのものより後かつ 15 分以内に収まっているか確認する.
  3. ブロック番号,難易度,トランザクションルート,uncle ルート(uncle ブロックのルートハッシュ?),ガスリミットが正しいか確認する.
  4. PoW の結果が正しいか確認する.
  5. 前ブロックの最後の状態を S[0] にする
  6. For i = 0, ..., n-1, S[i+1] = APPLY(S[i], TX[i]) のようにして再帰的に state を求める.途中でエラーが発生するか,全体でガス使用量が GASLIMIT を上回る場合はエラーを返す.
  7. S[n]S_FINAL とし,マイナーへの報酬を支払うブロックを追加する.
  8. state のマークルツリーのルートハッシュである S_FINAL がブロックヘッダに含まれる最終的な state のルートハッシュと一致するか確認し,True/False を判断する.

各ブロックに全体の state を保存する必要があるため一見効率の悪い方法にも思えますが,ビットコインブロックチェーンと比較して実際には効率的なアプローチになっています.なぜならば,state はツリー構造で保存されており,ブロックが追加されたときの変更点が少ないからです.したがって,二つの隣り合うブロック間ではツリーの大部分は同じでなければなりません.この仕組みを作るために Patricia tree として知られる特殊な種類のハッシュツリーを使っています.これはノードを変更するだけでなく,効率的に挿入や削除もできるようにマークルツリーを修正したものです.ブロックチェーンの履歴のすべてを保存する必要がないため,ビットコインで考えればストレージを 5-20 倍節約できます.

よくある質問としてコントラクトコードはハードウェア的にどこで実行されているのかというものがあります.コントラクトコードの実行プロセスは状態遷移関数の一部であり,これはブロック検証アルゴリズムの一部です.つまり,トランザクションがブロックに追加されるタイミングでそのブロックを検証するすべてのノードが実行することになります.

Applications

イーサリアム上で動かすアプリケーションは大きく分けて3種類あります.一つ目は金融アプリケーションで,ユーザがお金を管理するツールを提供するものです.例えば,サブ通貨や金融派生商品,ヘッジ契約,ウォレット等があります.二つ目は準金融アプリケーションで,お金は絡みますが直接金融に関連しないようなものです.まさに,演算上の問題を解決するために報酬を支払う仕組みもその一種と捉えられます.三つ目は完全に金融に関連していない,オンライン投票や非中央集権型ガバナンス等のアプリケーションです.

Token Systems

ブロックチェーン上のトークンシステムには様々なアプリケーションがあります.例えば,企業が貯蓄する米ドルや金といった資産を表現できるサブ通貨,スマートプロパティ(不動産管理等)を表現できる独立トークン,偽造不可能なクーポン,報酬制度に使われる実在するモノの価値に結びついていないトークンなどが挙げられます.トークンシステムはイーサリアムで簡単に実装できます.ここでのポイントは,通貨やトークンシステムは本質的に二者間の通貨やトークンの足し引きを操作するデータベースであるということです.Serpent で書くと基本的なコードは以下のように表現できます.

def send(to, value):
    if self.storage[msg.sender] >= value:
        self.storage[msg.sender] = self.storage[msg.sender] - value
        self.storage[to] = self.storage[to] + value

これはバンキングシステムの状態遷移関数と見ることができます.上記のコードに加えて,通貨の配布やアドレスの残高取得があれば完全形です.理論的にはサブ通貨として機能するイーサリアムベースのトークンシステムはビットコインのメタ通貨にはない別の重要な機能を持っています.それはトランザクション手数料を直接サブ通貨で支払えることです.この仕組みは以下のように実装できます.

  1. 送信者が ether でトランザクション手数料を支払う
  2. コントラクトがトランザクション手数料に見合うサブ通貨を受け取る
  3. 常に開いているオークションでサブ通貨と ether を交換する
  4. 送信者にトランザクション手数料分の ether を渡す

送信者からトランザクション手数料分のサブ通貨を受け取り,コントラクトの残高を使ってトランザクション送信時に消費された ether を補填することで実質的にはサブ通貨でトランザクション手数料を支払う仕組みを作ることができます.

Financial derivatives and Stable-Value Currencies

デリバティブはスマートコントラクトのよくある利用方法で,実装方法もとてもシンプルといえます.実装が難しいのはコントラクトが外部価格の参照が必要な点です.例えば,最も望ましいアプリケーションは米ドルに対する ether 等の暗号通貨の変動に関してヘッジ取引を行うスマートコントラクトですが,これを実現するにはコントラクトが ETH/USD レートを知らなければなりません.レートを取得する最も簡単な方法は,NASDAQ 等特定の機関が必要に応じて更新する「データフィード」となるコントラクトを通し,メッセージを送信したコントラクトに対して価格を返すというものです.

ヘッジ取引を行うコントラクトの原理は以下のようになります.

  1. A さん,B さんがそれぞれ 1000ETH の入金を待機させておく
  2. データフィードコントラクトを通じて取得したレートを元に 1000ETH に相当する米ドル額 $x を記録する
  3. 30 日後,A さんと B さんのコントラクト実行を再開し,$x 分の ether を A さんに,残りを B さんに送る

(この場合,ether の価値が上がると A さんは損失を被ります.)

このようなコントラクトは商取引において重要な可能性を秘めています.暗号通貨に関する主な問題の一つに変動性の高さが挙げられます.多くのユーザ,販売者は暗号通貨による取引の安全性と利便性を求めていますが,一日で資産の 23% を失う見通しに直面したくはないでしょう.今まで最も提案されてきた解決策は発行者が資産を裏付けるというものです.発行者が発行・失効の権限を持ち,担保の資産となる実世界の金やドル1単位に対して1単位のサブ通貨を発行します.そしてサブ通貨1単位が返金されたときには担保の資産を返すと約束しておきます.この仕組みによって発行者が信用できれば非暗号資産を暗号資産として「持ち上げる」ことができます.

しかし,実際には発行者が常に信用できるわけではありません.デリバティブはこのような場合に代替策となり得ます.資産を担保とする単体の発行者の代わりに,暗号資産の価格上昇に賭ける投機家の非中央集権型市場がその役割を果たします.発行者と異なり,ヘッジコントラクトは投機家のお金をエスクローに保持しているため,投資家には交渉の場で取引に応じないという選択肢はありません.このアプローチでは外部価格が信用できる情報源に依存するので完全な非中央集権型市場にはなっていませんが,発行者等のインフラをなくし,不正の可能性を排除するという点においては著しい向上が望めます.

Identity and Reputation Systems

早期に立ち上げられたプロジェクトである Namecoin ではビットコインのようなブロックチェーンを用いてパブリックデータベースに名前を登録できるシステムを作ろうとしました.ユースケースとしては bitcoin.org のようなドメイン(Namecoin においては bitcoin.bit 等)と IP アドレスを紐付ける DNS が挙げられます.その他にはメール認証や評価システムなども考えられます.イーサリアムで Namecoin のような登録システムを実装するためのコントラクトは以下のようになります.

def register(name, value):
    if !self.storage[name]:
        self.storage[name] = value

イーサリアムネットワーク内のデータベースであり,追加はできますが変更や削除はできません.いくらかの支払いで誰でも名前を登録でき,ずっと紐付けたままになります.より洗練されたコントラクトであれば他のコントラクトがクエリを実行できる関数,名前の所有者がデータを変更したり所有権を譲渡したりする仕組みを持たせられます.

Decentralized File Storage

過去数年に渡り,オンラインストレージを提供するスタートアップが大量に生まれ,月単位の契約でユーザがハードドライブのバックアップ等に使用できるよう目指してきました.しかし,現状のファイルストレージ市場は非効率的で,無料割当も企業向け割引もない 20-200GB の範囲における主流の月額料金はハードディスク全体を使用するコストよりも高くなる場合があります.イーサリアムコントラクトによって非中央集権型ファイルストレージエコシステムの開発が可能であり,個人のユーザがハードディスクを貸すことで少額の利益を得られ,未使用領域の活用によりファイルストレージのコストが下がります.

非中央集権型ファイルストレージを実現するコントラクトは以下のような仕組みになっています.まず,データをブロックに分けて暗号化し,マークルツリーを構築します.そして,N ブロックごとにツリーのインデックスをランダムに抽出し,ブロックの所有権の SPV-like な証明をトランザクションに提供する最初のエンティティに X ether を与えるというルールに従ってコントラクトを作成します.

ユーザがファイルを再度ダウンロードしたいときは,マイクロペイメントチャネルを使用(32KB につき 1 szabo = 10-6 ether 支払う等)してファイルを復元します.手数料の面で最も効率のよいアプローチは処理終了までトランザクションを公開せず,32KB ごとに同じナンスを持つトランザクションで置き換える方法です.

ファイルを消失しないように多くのランダムなノードを信頼しているように見えるかもしれませんが,このプロトコルの重要な機能は秘密共有を介してファイルを幾つものピースに分割することでリスクを低減することにあり,コントラクトを監視することでそれぞれのピースがノードに所有されているかを確認できます.コントラクトが支払いを行っている間はファイルを保存していることが暗号学的に証明されます.

Decentralized Autonomous Organizations

「自律分散型組織」(Decentralized autonomous organization: DAO) という概念は,全体の 67% 程度をメンバーや株式保有者が占める仮想的なエンティティを指しており,所属している人はエンティティの資金を使用したり,コードを変更したりする権利を持っています.メンバー達で組織がどのように資金を配分すべきかを決めています.配分を決める方法は報奨金や給与から,作業に対する内部通貨の報酬など一風変わったものまで多岐に渡ることもあり得ます.本質的には従来の企業や非営利団体に見られる法的な制度を複製したようなものですが,これを暗号学的なブロックチェーン技術のみを用いて実現しています.これまで DAO に関する話題は配当を受け取る株式保有者と取引可能な株を持つ「自律分散型企業」(Decentralized autonomous corporation) という「資本主義」モデルに集中していました.また,別の言い方をすれば「自律分散型コミュニティ」(Decentralized autonomous community) として説明されます.全メンバーが等しい価値の株式を保有して意思決定を行い,メンバーの追加や除名には全体の 67% の賛成が必要というようなコミュニティです.これには一人のメンバーは必ず一つのメンバーシップしか持てないという要件が必要になります.

以下に DAO をコードベースでどのように実現するか,アウトラインを示します.最もシンプルなのはメンバーの 2/3 が賛同したときにコードを自ら変更するような設計にすることです.理論的にはコードは不変なように思えますが,いくつかのコントラクトにコードを分割して実装し,それぞれのコントラクトを呼ぶためにアドレスを可変な保存領域に格納しておくことで事実上可変な処理を実現できます.そのような DAO のコントラクトをシンプルに実装するにあたり,三つのトランザクションタイプがあり,それぞれのトランザクションのデータによって区別されます.

  • [0, i, K, V]:アドレス変更時にキー K と値 V を用いてストレージに格納するためのインデックス i のプロポーザルを登録
  • [1, i]:プロポーザル i に対する賛成票を投票
  • [2, i]:投票数が十分であればプロポーザル i を確定

コントラクトには上記のそれぞれについて条項が記述されています.コントラクトはオープンなストレージの全ての変更とそれに対応する投票者リストのレコードを保管しており,全メンバーのリストも保持しています.メンバーの 2/3 に対応するストレージが変更されると,ファイナライズするトランザクションで変更を実行できます.より高尚な枠組みを考えれば,トランザクションの送信やメンバーの追加,除名,その他 Liquid Democracy で提供されるような機能を持つ投票の仕組みを組み込むこともできます.このような設計は分散型コミュニティとしての DAO の成長に繋がり,最終的に誰がメンバーであるかをフィルタリングするタスクをスペシャリストに委託できるようになります.ただし,現在のシステムとは異なり,それぞれのコミュニティメンバーが自身のアラインメントを変更することで,スペシャリストは容易に存在を現したり消えたりできます.

それに代わるモデルは分散型企業に対するもので,どのアカウントもゼロ以上の株を保有し,2/3 の株が意思決定に必要です.完全形としては資産管理機能,株の売買オファーの作成機能,そのオファーを受ける機能を持ちます.コントラクト内部にオーダーマッチングメカニズムを持つのが望ましいと考えられます.デリゲーションも Liquid Democrary スタイルで存在し,「取締役会」の概念を一般化するでしょう.

参考

https://ethereum.org/en/whitepaper

Footnotes

  1. Chaum, D. (1983). Blind signatures for untraceable payments. In Advances in cryptology (pp. 199-203). Springer, Boston, MA.