前回の記事

Cosmos SDKをちゃんと知る その1

前回は、Cosmos SDKとはそもそもどういうものなのか、Cosmos SDKを用いてアプリ専用チェーンを立ち上げるメリットとはなんなのかという話をしました。テックな話は少なかったかと思います。

今回は、前回と少し趣旨が代わりCosmos SDKを用いて作るチェーンはどういう構造になっており、どういう設計であるのかについてお話をしていきます。前回同様、Cosmos の公式ドキュメントを参考文献とさせていただきます。

Cosmos SDK design overview | Cosmos SDK Documentation

最初の方にはステートマシンに関する説明など、ブロックチェーンに詳しい方には耳タコな話にはなっているとは思いますが、参考文献に準拠する形で書かせていただきました。

これを読んでからCosmos チュートリアルに手を出しても、手を出した後にこれを読んでも知識を補完できる内容となっています。個人的には結構面白かったです。では、始めていきましょう。

第3章 SDKを用いたアプリ構造

・ステートマシン

Cosmos SDK の中核をなすブロックチェーンとは、つまるところ複製された決定論的ステートマシンのことです。
ステートマシンとはコンピューターサイエンスの概念のことであり、マシンある事象に対する状態を複数持つことができますが、ある時間の情報に関しては、一つの情報しか持たないものとなっています。つまり、時間ごとに連なった”状態(ステート)”持っていることになります。
“ステート”は、システムの最新の状態を示すものであり、”トランザクション”はそのステートの遷移(ある状態からある状態への変化)を起こすきっかけとなるものです。

以下の図はS(ステート)がT(トランザクション)を適応させることによって、新しいステートS’へと遷移していることを示しています。
図にされなくてもこれくらいわかるよ!と言いたくなるくらい親切です笑

実際には、トランザクションごとにステートを変更するのではなく、トランザクションをブロックという単位にまとめて、より効率よくステートの更新をできるようにしています。
以下の図は、ブロックの中にあるトランザクションを適応させてステートを遷移させる図になります。

ブロックチェーンの文脈では、ステートマシンは決定論的になっています。つまり、特定のステートから、同じトランザクションを適応させて行くと、最終的に常に同じ最終状態になります。(分散台帳として機能するためには、それぞれのノードが同じ台帳を持っていないといけないので、当たり前といえば当たり前です。フォークしないようにできているという意味とほぼ同義であると思います。)

Cosmos SDKでは、アプリケーションが持つステート、トランザクションのタイプ、ステートの遷移を行うための関数を定義するための、最大限の柔軟性を提供します。SDKを用いてステートマシンを構築する方法については、後述します。まずは、Tendermintを用いてどのようにステートを複製するのかをみていきましょう。

・Tendermint

開発者がCosmos-SDKを用いてステートマシンを定義するだけで、Tendermintが開発者のために自動でネットワーク経由で複製を取り扱う過程を行なってくれます。

Tendermintは、上の図のようにブロックチェーンのネットワークレイヤーとコンセンサスレイヤーの処理を担当し、アプリケーションの部分には依存しないエンジンです。これはトランザクションの伝播と順序付けをTendermintが担当していることを意味します。
Tendermint Coreは、同名のTendermint Coreというビザンチン障害耐性(BFT) アルゴリズムを使用して、トランザクションの順序に関するコンセンサス(合意)を得ています。Tendermintについての詳細は、ここに!

Tendermintのコンセンサスアルゴリズムは、バリデータと呼ばれる特別なノード達によって動いており、バリデータ達は、トランザクションをまとめたブロックをチェーンに追加する責任があります。
あるタイミングのブロックに対して、そのブロックに含まれているトランザクション達がチェーンに追加して良いものかを検証するのがバリデータ達であり、そのバリデータ達の中から、そのブロックの中にどのトランザクションを入れるのかを提案するバリデータが存在していることになります。提案されたブロックがバリデータ達の2/3以上によって検証され正しいブロックであると署名されると、そのブロックは妥当なものであるとみなされ、全てのノードが共有するべきブロックとなるのです。
バリデータのセットについては、ステートマシン側で定義したルールによって変更が可能です。(例:Cosmos Hubだとステークされてる量が多い上位100がバリデータになっており、Binance chainでは決められた11のノードがバリデータとなっている。)

Tendermintのアルゴリズム詳細についてはこちらから。

Cosmos SDK アプリケーションの主要部分は、ネットワーク内の各ノードのそれぞれのローカル環境で実行されるブロックチェーンのデーモンになります。悪意のあるバリデータが、バリデータ全体の1/3以下である場合、各ノードはそれぞれ同じステートを持っている必要があります。
(簡単に言うと、それぞれのノードはそれぞれがブロックの情報が伝播されるのを待っていて、そのブロックが伝わってくることによってやっと自分のステートを遷移させる状況にある。その上で、しっかりと正しいブロックの情報をみんなに伝えて、それぞれのノードが持つステートが同じになってないといけないですよね。という話をしています。)

・ABCI

コンセンサス、ネットワーキングの部分を担当するTendermintの次は、アプリ専用チェーンのアプリの部分を担うインターフェイス、ABCIについてです。

Tendermintは、ABCIを介して、ネットワークから伝播してきたトランザクションをアプリ側に渡します。(下図のようなイメージ)

Tendermintはトランザクションバイトのみを取り扱いますが、このトランザクションバイトの意味を理解しているわけではありません。Tendermintの仕事はこれらのトランザクションバイトの順序を確定することです。
Tendermintは、トランザクションバイトをABCI経由でアプリケーション部分に渡し、トランザクションに含まれる”メッセージ”(アプリへの指示)が正常に処理されたかどうかの情報であるリターンコードが返ってくるのを待ちます。

ABCIがTendermintから渡される重要なメッセージは次の通りです。

CheckTx: Tendermint Coreがトランザクションを受信すると、その”CheckTx”メッセージは、受信したトランザクションが基本的な要件を満たしているかどうかを確認するためにアプリケーション部分に送られます。”CheckTx”はフルノードのmempoolをスパムから保護するために使用されます。(無駄なトランザクションでmempoolがいっぱいになることがないようにする。)
“Ante Handler”と呼ばれる特別なハンドラを使用して、トランザクション手数料が十分か、またそのトランザクションへのバリデータの署名がなされているかなどの一連の検証手順を実行します。そのチェックが妥当な場合に、トランザクションはmempoolに追加され、その後他のノードに中継されます。この段階ではトランザクションはまだブロックにまとめて入れられたわけではないため、トランザクション自体が処理される、つまりステートを遷移させるわけではありません。

DeliverTx:バリデータ達によって検証された有効なブロックがTendermint Coreに受信されると、そのブロックの中の各トランザクションは、”DeliverTx”メッセージを介してアプリケーション部に渡され、処理されます。
この段階では、ステートの遷移が発生し、”CheckTx”の時のように“Ante Handler”が、トランザクション内に含まれているメッセージに対応したハンドラと共に再び実行されます。(再びそのトランザクションが必要な要件を満たしているかを確認しながら、アプリケーションへの指示を実行するということ)

BeginBlock / EndBlock:この二つのメッセージは、ブロック内にトランザクションが含まれているかどうかに関わらず、各ブロックの最初と最後に実行されます。

ABCIのメソッドとタイプの詳細については、ここをクリック。

Tendermintを用いて構築されたアプリ専用チェーンは、Tendermintエンジンと通信するためにABCIが実装されている必要があります。幸いなことに、Cosmos SDKはbaseappという形で、すでにそのABCIの形式のベースの実装を提供しています。

次は、Cosmos SDKに関する高次元での設計原則についてです。

第4章 Cosmos SDKの設計概観

Cosmos SDKは、Tendermintを用いて、安全なステートマシンの開発を簡単にできるようにするフレームワークです。Cosmos SDKの中核となっているのはGo言語で実装されたABCIの実装です。それには、データを保持するための”multistore”と、トランザクションを取り扱う”router”があります。

以下は、TendermintからABCIのDeliverTxを介して、トランザクションがアプリケーション部に送られてきた時に、そのアプリ部分がトランザクションを処理する方法を簡略化した手順です。

  1. Tendermintから受け取ったトランザクションバイトをデコードします。(Tendermintはトランザクションをバイトでしか取り扱わないため)
  2. デコードしたトランザクションからメッセージを見て、そのメッセージがアプリに対して正当なものかをチェックします。
  3. 各メッセージを適切なモジュールにルーティングして、処理できるようにします。
  4. アプリのステートの変更をコミットします。

また、このアプリケーション側は、トランザクションを生成し、エンコードし、それをTendermintエンジンに渡してブロードキャストさせることもできます。

baseapp

baseAppは、何度か説明している通り、Cosmos SDKのABCIに関する定型的なベースとなる実装のことです。トランザクションを必要な機能をもつモジュールにルーティングするルーターが付属しており、アプリのメインであるapp.goファイルには、(baseappの仕様を継承しながら、)これから自分でカスタムして作るアプリについて定義することができます。
つまり、Cosmos SDKを用いて作成するアプリは、baseappの全てのABCIメソッドを自動的に継承してくれます。
もしよければ、Cosmos SDKを用いてアプリ専用チェーンを作るチュートリアルで確認してみてください。

baseappの目的は、できる限りステートマシンに関して必要な定義を少なくしながらも、アプリのデータを保持しているストアと、拡張可能なステートマシンとの間に、安全なインターフェイスを(ABCIに忠実なまま)提供することです。

Multistore

Cosmos SDKは、ステートを保持するための”Multistore”を提供しています。このMultistoreのおかげで、開発者はいくつものKVStoreを宣言することができます。これらのKVStoreはValueを[]byteの型でしか受け付けないため、保存する前にgo-amminoを使って、マーシャリングする必要があります。

Multistoreの抽象化は、ステートを個別の区分に分割するために使用され、各区分は独自のモジュールによって管理されることになっています。(これは、アプリが持つ、ステートを必要とするモジュールごとにKVstoreが存在しているということだと思われます。違ったら教えてください!)

Modules

Cosmos SDKの強みというのは、そのモジュール性にあります。Cosmos SDKを用いたアプリケーションは、相互運用が可能なモジュールをつなぎ合わせることにより構築することができます。(この相互運用可能というのは、ブロックチェーン間のインターオペラビリティ とは別の話です。)

各モジュールは、ステートのステートを定義し、モジュール固有のメッセージ、トランザクションプロセッサの種類を持つのに対し、Cosmos SDK側はその固有のメッセージをモジュールにルーティングしてくれます。
(モジュール側は受け取ったメッセージをもとに、然るべき関数を実行します。)

検証された有効なブロックがTendermintが受信した場合、その中のトランザクションがどのように処理されるのかを以下に簡単に示します。

各モジュールは、小さなステートマシンとして考えることができます。開発者側は、モジュールによって処理されるステートのサブセットと、ステートを変更するためのメッセージのタイプを定義する必要があります。(メッセージは、先ほどABCIの説明でしたように、Cosmos SDKベースの場合は、baseappがデコードしてトランザクションから抽出してくれます。)

一般に、各モジュールは”Multistore”の中で、そのモジュール自身が持つKVStoreを宣言して、定義するステートのサブセットを永続化します。

ほとんどの開発者は、独自のモジュールを作成する時に、サードパーティのモジュールにアクセスする必要があります。Cosmos SDKはオープンフレームワークであるため、一部のモジュールには悪意のあるものがあるおそれがあります。つまり、モジュール間の相互作用を推めるためのセキュリティに関する原則が必要となります。これらの原則は、Object-capabilityに基づいて作られており、これは実際には、各モジュールが他のモジュールに関するアクセス制御のリストを持つ代わりに、それぞれのモジュールにKeeperと呼ばれる、他のモジュールに対して、事前に決められた関数を使わせることを許可する特別なオブジェクトを実装することを意味しています。

Cosmos SDKの各モジュールは、”x”フォルダー(xというフォルダー名)以下に定義されています。いくつかの代表的なモジュールを紹介します。

x / auth : アカウントと署名の管理に使用されます。
x / bank :トークンとトークン転送を有効にするために使用されます。
x / staking & x / slashing : Proof-Of-Stakeブロックチェーンの構築に使用されます。

x フォルダ以下に既存のモジュールに加えたり、独自のカスタムモジュールを構築することによって、誰もがアプリケーションを作ることができます。

おわりに

今回は、主に、TendermintとABCIの関係、またABCIを介してアプリに渡されるトランザクションが、その先のモジュールでどう扱われるのかについて確認しました。

文章だけの説明となってしまったので、なかなか理解しずらい部分もあったかもしれませんが、これを読んだ上で”nameservice”アプリチェーンのチュートリアルをやってみると、理解が早いと思います。ぜひ、そちらもやってみてください。
ではまた!

fressetsお知らせ

fressetsは積極的に採用を行っています!詳細は下記のリンクからご確認下さい。
Link: https://fressets.com/careers/careers-416/
Link: https://fressets.com/careers/careers-0/

HashHubお知らせ

■HashHubでは下記のポジションを積極採用中です!
・コミュニティマネージャー
・ブロックチェーン技術者・開発者
・ビジネスディベロップメント
詳細は下記Wantedlyのページをご覧ください。

Wantedly:https://www.wantedly.com/companies/hashhub/projects

■HashHubでは入居者募集中です!
HashHubは、ブロックチェーン業界で働いている人のためのコワーキングスペースを運営しています。ご利用をご検討の方は、下記のWEBサイトからお問い合わせください。また、最新情報はTwitterで発信中です。

HashHub:https://hashhub.tokyo/
Twitter:https://twitter.com/HashHub_Tokyo


Cosmos SDKをちゃんと知る その2 was originally published in Blockchain Engineer Blog on Medium, where people are continuing the conversation by highlighting and responding to this story.

  • このエントリーをはてなブックマークに追加
 
Recommend article