- イーサリアムはビットコインと違って「スマートコントラクト」が実行できる。
- イーサリアムでは通貨だけでなくアプリケーションも作れる
イーサリアムはまだまだ新しいプラットフォームであるので、ビットコインと比較してこのような事実だけ知っている方も多いはずです。しかし、イーサリアムではどのようにしてスマートコントラクトが実行しているのでしょうか。
そこで当記事ではイーサリアムの仕組みに関して、2種類のアカウントや状態遷移のことなどトランザクションレベルで紹介していきます。
また、ここでは基礎的なブロックチェーンの知識を前提とし、ビットコインとの違いに重点を置いて紹介していきますので必要であれば以下の記事も参考にしながらご覧ください。
参考:ビットコインネットワークにおける分散型コンセンサス形成の具体的な流れ
イーサリアムとは
イーサリアムとは2013年にVitalik Buterin氏によりビットコインのアイデアを元に構想が示され、2015年にFrontierというベータ版がローンチされた分散型アプリケーションプラットフォームです。イーサリアムの特徴は自由度の高いスマートコントラクトがイーサリアムネットワーク上で記述できる点です。
これにより、ブロックチェーン技術をベースに中央管理者のいないフラットなP2Pネットワーク上でさまざまなアプリケーションサービスの提供が可能となります。
ビットコインと比較すると、ビットコインネットワークでは通貨というバリューをやり取りすることを提供していましたが、イーサリアムネットワークではアプリケーションを動作させることを提供しているのです。
まずは、ビットコインにはないイーサリアムでの特徴的な概念である「アカウント」「状態(state)」「gas」「EVM」について紹介していきます。
アカウント
イーサリアムにはEOA(Externally Owned Account)とコントラクトアカウント(Contract account)という2つのアカウントがあります。どちらのアカウントも20バイトのアドレスと状態を持っています。
イーサリアムのアドレスの生成までの流れはこちらの記事をご覧ください。
参考:秘密鍵から公開鍵そしてアドレスが生成されるまでの流れ【仮想通貨】
EOAはビットコインのアカウントのように普通のアカウントであるとイメージすると分かりやすいです。EOAは秘密鍵の署名でコントロールされており、コードは持ちません。ユーザーはEOAを通してイーサリアムネットワークとやり取りを行うことができます。
一方、コントラクトアカウントはコードを持っており、このコードがいわゆるスマートコントラクトとして機能する部分となるのです。これにより、通貨の送金だけでなくさまざまなオペレーションをイーサリアムプラットフォーム上で行うことができるのです。コントラクトアカウントはユーザーが持つことはできず、イーサリアムネットワーク上で動作します。
また、EOAは秘密鍵を使って署名することでトランザクションを作ることができます。EOAから他のEOAに対しては、etherなどの通貨(value)をメッセージとして送るトランザクションを作れます。EOAからコントラクトアカウントに対しては、コントラクトアカウントが持っているコードを実行するようなトランザクションを作ることができるのです。
一方、コントラクトアカウントは自分自身でトランザクションを作ることができません。しかし、コントラクトアカウントは、EOAから受け取ったトランザクションの指示に従って、他のコントラクトアカウントに対してインターナルトランザクションを生成することができます。
これにより、さまざまなコントラクトアカウント間で連携し、それぞれが持つコントラクトコードによりオペレーションを実行することができるのです。
状態(state)
イーサリアムのブロックチェーンはトランザクションに基づいた「状態」という概念があります。トランザクションが起きる前は、始まりの状態(genesis state)であり、新たなトランザクションの生成ごとに状態1、状態2、、、と変化していくのです。
(source: ethereum white paper)
また、状態にもアカウント状態(Account state)とワールド状態(World state)という2つの概念があります。
アカウントステート(アカウント状態、Account state)
アカウントはそれぞれ固有の状態を持っているとお伝えしました。その状態のことをアカウントステートと呼びます。EOAとコントラクトアカウントともにアカウントステートは以下の4つのデータから成り立っています。
- ナンス:EOAの場合は、そのアカウントが送ったトランザクションの数。コントラクトアカウントの場合は、そのアカウントが作ったコントラクトの数
- バランス:アドレスが持っている通貨量
- ストレージルート:アカウントが持っているデータのマークル木のルートハッシュ
- コードハッシュ:EOAの場合は、空文字のハッシュ。コントラクトアカウントの場合はそのアカウントが持っているコードのハッシュ。
ワールドステート(ワールド状態、World state)
ワールドステートは、イーサリアムネットワーク全体の状態のことです。上述のアカウントステートを全て考慮することで、ワールドステートが成り立っています。
しかし、イーサリアムネットワークにある全てのアカウントの状態を考えるのはとても複雑であると予想できます。そこで、このワールドステートはマークル・パトリシア木のルートとして成り立っているのです。
マークル木は以下の図のようにツリー上になっており、頂点にあるのがルートであり、ワールドステートになります。そして、一番下に位置するのがそれぞれのアカウントステートで、それらを合計してダブルハッシュ化(2回ハッシュにかける)を繰り返すことでルートまでつながっています。
(source: ethereum white paper)
このようなデータ構造であるマークル木に対し、データの検索挿入コストを減少させるために分岐条件を文字ではなく「文字列」の並びに変更した構造をマークル・パトリシア木と呼びます。
このようにマークル・パトリシア木を用いることで、ひとつのアカウントステートが変更されればワールドステートも変更されるようになり、さらに複雑なワールドステートも少ないデータ量で保存できるようになるのです。ちなみに、このワールドステートはイーサリアムのブロックチェーン上のブロックヘッダーに保存されています。
ビットコインでは、トランザクションのハッシュ木ルートのみがブロックヘッダーに保存されていたのに対し、イーサリアムのブロックヘッダーにはトランザクションルートに加え、ステートルート(上述)とさらにレシートルート(receiptsRoot)が保存されています。レシートとは、それぞれのトランザクションの結果を表しているデータです。
(source: Ethereum Development Tutorial)
Gas
Gasとは、イーサリアムのトランザクションを実行するのにかかる手数料です。ビットコインでも送金するときに手数料がかかるのでイメージしやすいと思います。ビットコイン同様、イーサリアムでも手数料はマイナーが得ることができ、高い手数料ほどマイナーが優先してブロックに含めるのでそのトランザクションが検証されるまでの時間が早くなります。ただし、ビットコインの手数料とは異なる点が多くあるので解説していきます。
まず、トランザクションの送り手はgas limitとgas priceを設定します。これらの値を掛け合わせた値がそのトランザクションで使用されるGasの最大値です。つまり、(gas limit) * (gas price)の値がトランザクションの実行で最大限使える手数料になります。
gas limitが不十分の場合は、トランザクションの実行が途中でガス欠になってしまい中止されてしまいます。この場合、途中までで使用されたgasは送り手に戻ることはありません。一方、十分なgas limitを設定していてトランザクションが正常に行われた場合、余ったgasは送り手に返されます。
EVM(Ethereum Virtual Machine)
EVMとは、イーサリアムネットワーク上で動作する仮想マシンです。トランザクションの処理はこのEVMによって行われるのです。EVMは一時的なデータを保存するメモリや、永久的にデータを保存できるストレージを持っており、コントラクトコードをそれぞれ分別して保存しています。
また、コントラクトコード自体はsolidityという独自のプログラミング言語で記述することができますが、EVMはこのsolidityで書かれたコードをEVMバイトコードに変換することでトランザクションを実行しています。
トランザクション
ここまで解説した「アカウント」「状態(state)」「Gas」「EVM」という概念を整理するためにもイーサリアム上でのトランザクションの流れを見ていきましょう。
全てのトランザクションはEOAによって作られます。そして、ひとつのトランザクションが実行されるとstate3からstate4のようにアカウントの状態が変化し、それに伴いグローバルステートも変化します。
まず、トランザクションを実行するために以下のような必要条件を満たす必要があります。
- トランクザクションに有効な署名やナンスがあるか
- gasが十分な量で設定されているか
- トランザクションはRLP(Recursive Length Prefix)というデータフォーマットになっているか
このような条件が全て満たされていると、トランザクションが実行されます。実行中は中間状態(substate)というトランザクションのログのようなデータが保存されます。トランザクションがエラーなく無事に完了すると、余ったガスは送り手に返され、アカウントの状態が変化します。
ちなみにビットコインではトランザクションはUTXOを介して連鎖的につながっていましたが、イーサリアムではUTXOは存在しません。
参考:ビットコインのトランザクションにおける「UTXO」を分かりやすく解説してみた
イーサリアムにはEOA同士でetherなどの通貨を送り合うトランザクションの他にも以下のような変わった(ビットコインには存在しない)トランザクションも存在します。
- EOAがコントラクトアカウントを生成するトランザクション
- 既存のトランザクション間でメッセージを送るトランザクション
これらのトランザクションについても見ていきましょう。
コントラクトアカウントの生成
このタイプのトランザクションは、他のEOAに送金するのではなく新しいコントラクトアカウントを生成することが目的です。
まず、新しいコントラクトアカウントのアドレスを生成し初期設定を行なったら、トランザクションとしてinitコードを送ることでコントラクトアカウントが生成されます。このときにも十分なgas量が必要になるので注意しなければなりません。
メッセージの送信(トランザクション)
メッセージコールでは新しいアカウントは生成されません。メッセージとは、通貨を送金するトランザクションかもしれませんし、コントラクトコードを実行するためのトランザクションかもしれません。
このメッセージ(トランザクション)を送るときには手数料であるgasが十分に必要であり、もし不十分だとトランザクションは実行されず、アカウントの状態も変化しません。
しかし、ビザンチウムのハードフォークによりrevertコードが実装されました。revertコードを使うと、一連のトランザクションの中である条件下でエラーを出したいときに、トランザクションをストップすることができます。このとき、残っているgasは送り手に返され、アカウントの状態も元に戻されます。
また、イーサリアムについてトランザクションレベルではなくブロックチェーンレベルで以下の記事では解説しています。併せてご覧ください。