Casper Networkの概要

はじめに

Casperは、アカウントベースモデルのコンセンサスをとった後に実行するプルーフ・オブ・ステークのブロックチェーンプラットフォームです。Casperネットワークは、グローバルステートとして知られる構造上にデータを格納していきます。ユーザーは、トランザクションにて送信されたセッションコードを介してグローバルステートと疎通します。デプロイには、ネットワークが実行するWasmが含まれており、それにより開発者にとって専用言語ではなく好みのプログラミング言語の使用が可能となっています。

デプロイは、ユーザーアカウントのコンテキスト内にて実行されます。しかし、デプロイ自体のコンテキスト内で実行される格納されたWasmを呼び出すことはできます。アカウント以外のユーザーに関連した情報は、Unforgeable ReferenceもしくはURefとしてグローバルステートに格納されます。ノードが有効なデプロイとして受理した後、デプロイは提案したブロックに置かれ、ネットワークがコンセンサスを満たすまでノード間でゴシップされます。この時点では、ネットワークがデプロイ内のWasmを実行します。

  1. 実行セマンティック
  2. アカウント
  3. Unforgeable Reference (URef)
  4. ブロック構造
  5. トークン

実行セマンティック

Casperネットワークは、分散型計算プラットフォームです。本章では、Casperが使用する計算モデルの側面について説明します。

計算処理の測定

計算は全てWebAssembly (Wasm)インタープリターで行われる為、wasmにコンパイルする任意のプログラミング言語をCasperブロックチェーンのスマートコントラクト言語にすることができます。イーサリウムと同様にGas(ガス)を利用し、Casper Networkのノード間で一貫した方法による計算作業を測定します。各wasmの命令にはGas値が割り当てられ、使用する量は、インタープリターが実行する各命令でランタイムによって追跡されます。

CasperのMainnetネットワーク上のopcodeのコストについては、ここで確認できます。

全ての実行は有限です。これは、ランタイムの計算が終了する前に使用可能なガスの最大量を指定するGasリミットが各々の実行に対して設けられるからです。実行可能なセッションの支払いは、デプロイの支払い方法で決まります。ガスリミットが、デプロイ内にて指定されたペイメントコードを実行することで設定されます。

計算はGasで測定されますが、依然として計算に対する支払いはモーツ(motes)で行われます。従って、Gasとmotes間の変換レートが存在します。

💡NOTE
Casperは、未使用のガスの如何なる額の返金も行いません。

計算資源の効率的な割り当てにより、Casper Runtime Economics にインセンティブを与えるべく、この決定がなされました。consensus-before-execution モデル は、ユーザーサイドからの最適なガス消費量を促し、デプロイ処理の不手際によるブロックスペースの過剰使用を防ぐメカニズムを実装しています。

Casperネットワークランタイム

Wasmモジュールは、独自のリニアメモリからの読み取り/書き込み以外の作用をネイティブに作成することはできません。他の作用(例えば、Casper グローバルステートへの読み取り/書き込み)を有効にするには、wasmモジュールは、実行中のホスト環境から関数をインポートする必要があります。

Casper Network Runtime

すべての機能は、Casper External FFIの関数を介して使用可能となっています。

URefの生成

URefは、ChaCha アルゴリズムを使用した暗号化されたセキュアなランダム数のジェネレーターを使用して生成されます。ランダム数のジェネレーターは、現時点での実行フェーズを表示したインデックスと連結したデプロイハッシュのblake2b256ハッシュを取得することで、分配されます(同じデプロイの異なるフェーズで生成されたURef間の衝突を防ぐため)。

Generating URefs

アカウント

Casperブロックチェーンは、オンチェーンのアカウントベースモデルを使用しており、特定のPublicKeyのAccountHashにてユニークに指定されています。グローバルステートトライの格納は、同じ長さにする為には全ての鍵を要し、AccountHashは、サポートしているどの公開鍵変数の抽象化にも使われている32バイトの導関数です。

Casperのプラットフォームは、アカウントの作成とトランザクションの署名用の2つのタイプの鍵が使用可能となっています。

  • ed25519鍵:エドワーズ曲線デジタル署名アルゴリズム (EdDSA)を使用している、66バイトの長さのものです。
  • Secp256k1鍵:イーサリアム鍵とよく知られており、68バイトの長さのものです。

デフォルトでは、トランザクションがブロックチェーンとの連携に、アカウント作成時に使用した公開鍵のkey-pairによる暗号署名を施したDeploy形式をとっています。全てのユーザーのCasperブロックチェーン上のアクティビティ(”deploy”にあたる)は、アカウントから発生しているはずです。各アカウントは、それぞれのコンテキストを保持しており、ローカルに情報を格納することができます(例:使用可能なコントラクトやメトリックス、ブロックチェーンの他部分から収集したデータ参照)。各アカウントは、”main purse(メインのお財布)”も持っており、Casperのトークン(詳細は、トークンをご確認ください)を保有できます。

このチャプターでは、アカウントのパーミッションモデルやローカルストレージの利用について、そしてアカウント連携のランタイム関数について簡単に述べています。

アカウント作成

アカウント作成は、未使用の公開鍵にトークンが転送されることで自動生成されます。アカウント作成時は、そのメインパースの残高が作成処理中に転送されたトークン数と同等となります。そのアクション閾値は1であり、アソシエイトキーが1つ存在します。アソシエイトキーは、アカウントの作成に使用された公開鍵(PublicKey)です。この方法では、アカウントは、トランザクションの支払いに使われるメインパースを隠す必須のコンテキストオブジェクトとなります。ただ、アカウントがメインパースとは別に追加のお財布を持つこともあります。

Image showing the account data structure

Accountは、以下のデータを保持しています。

  • URef:アカウントの”main purse(メインパース)”を表示
  • 名前付き鍵のコレクション(格納されたコントラクトの名前付き鍵のように同じロールにて対応)
  • アソシエイトキーのコレクション(下記参照)
  • アクション閾値(下記参照)

パーミッションモデル

アクションと閾値

アカウントが実行できるアクションには、デプロイとKey management(鍵の管理)の2種類があります。デプロイは、単にブロックチェーン上でコードを実行することを意味しますが、Key management(鍵の管理)は、関連鍵の変更も含まれてます(詳細は後述します)。ブロックチェーンへの書き込みなどの全てのアクションは、デプロイを通して実施される必要がある為、鍵の管理は独立して実行されることはありません。従って、Key management(鍵の管理)のアクションは、デプロイアクションも同時に実行されているという裏付けがあって初めて動作します。

Accountデータ構造に含まれるActionThresholdsは、そのアクションを実行するために必要なWeight(ウェイト・重み)の閾値を設定します。これらの閾値をどのように満たすかについては、次節にて説明します。Key management(鍵の管理)のアクションはデプロイのアクションを必要とする為、Key management(鍵の管理)の閾値は常にデプロイの閾値以上である必要があります。

アソシエイトキーとWeight(ウェイト)

Casperネットワーク上のアカウントは、トランザクションの送信スキーマであるマルチシグを行うことで他の鍵ペアと紐づくことが可能です。アカウントのアソシエイトキー(紐づいた鍵)は、そのアカウントによるデプロイに署名を施すことが可能な公開鍵のセットとなります。各アソシエイトキーにはウェイトが設定されており、そのウェイトは前の項にて説明したアクション閾値を満たすべく合算されます。各デプロイは、デプロイ用のアカウントの1つ以上のアソシエイトキーによって署名されていなくてはならない上に、これらの鍵のウエイトの合計値は、そのアカウントのデプロイ閾値のウエイト以上である必要があります。デプロイに署名をした鍵のことを”authorizing keys(認証鍵)”と呼びます。同様に、デプロイにKey management(鍵の管理)アクション(詳細は以下参照)が含まれている場合は、認証鍵の合計ウェイトがアカウントのKey managementアクション閾値以上でなければなりません。

💡NOTE
どの鍵がどのアクションの認証を助けるか分からないように、”special keys(特別な鍵)”は存在しないのです。全ての鍵のウェイトは全く同じ方法で扱われます。

Key management(鍵管理)アクション

Key management(鍵管理)アクションは、アカウントの何らかの許可パラメーターに対する任意の変更です。これには以下のものが含まれます。:

  • 関連鍵(アソシエイトキー)の追加または削除
  • 各関連キーのWeightの変更
  • アクション閾値の変更

Key management(鍵管理)アクションには、ユーザーが自分のアカウントのロックアウトを防ぐルールが設けられています。例えば、全ての関連キーのWeightの合計より大きい値を閾値として設定することはできません。

Key management(鍵管理)を使用したアカウントセキュリティとリカバリー

この許可モデルは、現代のモバイルデバイス機能を利用可能にしつつ、アカウントの鍵の紛失または盗難から保護しています。例えば、日常的に使用する際、スマートフォンからのデプロイ署名も、携帯を紛失した際の心配をすることなく行えたりします。推奨される設定としては、デプロイ閾値以上かつKey management(鍵管理)の閾値を満たさない程の低いWeightの関連鍵を携帯に設定することです。そうすれば、その携帯を紛失したり盗難に遭ったりした場合には、他のデバイス(例えば自宅のコンピューターなど)から他の関連鍵を使用したKey management(鍵管理)アクションを使用でき、紛失した関連鍵を削除した上で代わりの携帯に配置した鍵をAccountに追加することができます。

💡NOTE
Key management(鍵管理)アクションを実行するために、十分な数の鍵へのアクセスを常に可能な状態にしておくことは非常に重要です。その場合、今後のリカバリーが不可能な状態になってしまいます。(現在、「非アクティブの回復」についてはサポートしておりません。)

アカウントコンテキスト

デプロイは、ブロックチェーン上の何らかの実行を行う為のユーザーリクエストです。(詳細については実行セマンティクスの項を参照。)これには、「ペイメントコード」と「セッションコード」が含まれており、それらはチェーン上に格納されたコントラクトや実行可能なWasmを参照します。実行可能なWasmは、デプロイを署名するアカウントのコンテキスト内にて、そのロジックに基いた実行が行われます。すなわち、実行中のWasmは名前付き鍵とアカウントのコンテキストが持つメインパースへのアクセス権を保持していることになります。

💡NOTE
オンチェーンに格納されたWasm(スマートコントラクト)へのリファレンスがある場合は、オンチェーンWasmの実行は他の所有しているランタイムコンテキスト内にて行われます。結果的には、格納されたWasmは名前付き鍵へのアクセスもしくは呼び出し元のアカウントのメインパースへのアクセスをもつことはないです。

偽造困難参照 Unforgeable Reference(URef)

このキータイプは、Account以外のあらゆるタイプの値を格納できます。さらに、Wasm内のURefには、キー配下に格納されている値の不正使用防止の権限情報が含まれています。この権限情報はランタイムによってトラッキングされます。つまり、悪意のあるWasmが、実際には保持していない権限でURefを生成しようとした場合、Wasmが偽造困難参照を「偽造(forge)」しようとしたとみなし、ランタイムは偽造URefエラーと判断します。URefのアクセス許可は、全体へのコントラクトの呼び出しで付与できるため、URef配下に保存されているデータを制御された状態で共有できます。キーを表す32バイトの識別子は、ランタイムによってランダムに生成されます(詳細については、実行セマンティクスを参照してください)。URefのパーミッションを定義するアクセス権限(AccessRights)のシリアライゼーションについては、CLValuesセクションに詳細が書かれています。

URefの権限

ランタイムでは、URefはAccessRightsと呼ばれる独自のアクセス権限を持っています。さらに、ランタイムは、各コンテキストの各URefが持つ有効なAccessRightsをトラッキングします。システムは、宣言されたAccessRightに関わらず、送信されたURefが無効であると想定し、各用途においてコンテキストの実行が正当であるかを判断します。ホストのロジックは、以下の方法にてURefの追加が可能です。

  • 「既知の」URefセット内の場合
  •  new_uref関数を介してランタイムにて新たに生成
  •  呼び出されたコントラクトの場合、呼び出し元がcall_contractへの引数を介して渡す
  •  ret関数を介してcall_contractから呼び出し元に返す

💡NOTE
既知のURefまたは境界を跨いだ呼び出しに対して、有効なURefのみ追加可能です。つまり、システムは、コントラクトの抜け道や既知のURefの隠し場所などに騙されて、偽造URefを受け入れてしまうことはないです。 

call_contract / retを介してコンテキスト間でURefを渡すことは、他グループには非公式のまま一定数のグループ間でのステート共有を可能にします。

URefとお財布

お財布は、Casperネットワークにおけるアカウントの基準としてURefのユニークな型を使用しています。URefは、トップレベルのエンティティであり、それは個別アカウントが’URef’を保有していないことを意味しています。上述した通り、アカウントとコントラクトは特定のURefとの連携を可能とする適切なAccess Rights(アクセス権)を所有しています。アカウントはメインパースに関連したURefを保有しているため、URefはUnit(単位)として存在しCasper mintbalance(残高)キーに対応しています。Casper mintの個別残高キーは、関連付けのあるURefと付与されたアクセス権にて単体で認証されたtransferを持つアカウントのお財布です。

このロジックを介して、Casper mintはネットワーク上の全てのmote(モーツ)と送信元アカウントのバランスキーと必要となったコントラクトの間の転送を持っています。

ブロック構造

ブロックは、Casperネットワーク上でのノード間による情報通信に必要な主要データ構造です。ここでは、このデータ構造のフォーマットについて簡単に説明します。

データフィールド

ブロックは、以下のもので構成されています。

  • block_hash(1)
  • ヘッダ(1)
  • Body(本体)(1)

これら各々についての詳細は以降の節で説明します。

block_hash

block_hashはヘッダのblake2b256ハッシュです。

block_headerには、以下のフィールドが含まれています。

  • parent_hash(親ブロックのハッシュ値)
    • 親ブロックを表すblock_hashリスト
  • state_root_hash
    • ブロックバディ(本体)の実行にて提供されるグローバルステートルートハッシュ
  • body_hash
    • ブロックバディ(本体)のハッシュ
  • random_bit
    • 以降のeraの初期化に必要なboolean
  • accumulated_seed
    • 以降のeraの初期化に必要なシード
  • era_end
    • エクイヴォケーションとファイナライズブロックのターミナルに含まれる報酬情報をもつ。これは、オプショナルフィールドです。
  • timestamp
    • ブロックが提案された時点でのタイムスタンプ
  • era_id
    • ブロックが生成されたEra ID
  • height
    • ブロックの高さ(つまり、祖先の数)
  • protocol_version
    • ブロックが提案された時点でのCasperネットワークのバージョン

Body

ブロック本体には、デプロイを参照するDeployHashが順に並んだリストと、ネイティブ転送(アカウント間のトークン転送のみの特殊なデプロイ)のDeployHashが順に並んだリストが含まれます。ネイティブトランスファーのような特殊なデプロイも含めて、すべてのデプロイは、実行やコミットという動作ごとに大きく分類され、グローバルステートに書き込まれます。有効なブロックには、デプロイやネイティブ転送が含まれていない場合もあることもあります。

ブロックボディには、そのブロックを提案したバリデータの公開鍵も含まれています。

デプロイとそのシリアル化についての詳細は、シリアライゼーション規格のブロックとデプロイのシリアル化方法の項目を参照ください。

トークン

Casperネットワークは、 Highwayと呼ばれているプルーフ・オブ・ステークのコンセンサスアルゴリズムに基づく分散型計算プラットフォームです。ユーザーは計算に対する支払いを行う必要があり、バリデーターは担保する為のステーク(資産保有量)を所有している必要がある為、このシステムを機能させるには価値の単位が必要です。ブロックチェーン界隈では、この価値の単位を、トークンといいます。

本章では、トークンの定義の仕方、更にはCasperプラットフォームにおけるトークンの使用方法について説明します。

トークンの生成と配布

ブロックチェーンシステムでは、計算処理に対してや、ネットワーク上でのトランザクションデータ処理に対するバリデーターへの報酬の支払いといった、目的に応じたトークンが供給可能である必要があります。Mainnet(メインネット)立ち上げ時の初期供給量は、100億CSPRでした。現在の供給量は、こちらで確認できます。初期供給量に加えて、システムには低いインフレ率が設定され、その結果はシニョリッジ(通貨発行益)という形でバリデータに支払われます。

シニョリッジ(通貨発行益)を計算する基準として使用されるトークン数は100億となります。

Image showing the token lifecycle

トークンの可分性

通常、「トークン」はいくつかの部分に分割できます。私たちのトークンを構成するこうした分割不可能な単位をmotes(モーツ)と呼びます。各CSPRは10のモーツに分割できます。丸め誤差の発生を回避する為、トークンの残高を常にモーツで表すことが重要です。対照的に、Etherは1018のパーツ(Wei/ウェイと呼ぶ)に分割できます。

CSPRの概念は、人間が読める状態である便利さとCasperネットワークの実際のインフラ内に存在しないことです。その代わりに、全てのトランザクションは単体としてmotesにてやり取りされます。

パース(財布)とアカウント

Casperシステム上の全てのアカウントには、CasperシステムのMintと紐付いた「財布(パース)」があり、これを「メインパース」と呼びます。ただし、セキュリティ上の理由から、メインパースのURefは、そのアカウントを使って実行されるコード(つまり、ペイメントコードまたはセッションコード)でのみ使用可能です。従って、URefを受け取るMintのtransfer(転送)方法は、アカウントのメインパース間での転送方法として最も使い勝手が良いとは言えません。こうした理由から、Casperは transfer_to_account 関数を提供しています。この関数は、アカウントのIDを導くのに使用する公開鍵を取得します。この関数は、source(送信者)として現時点でのアカウントのメインパースを使用し、提供された鍵のアカウントが持つメインパースをtarget(受信者)として使用します。

Casper Mint(鋳造)コントラクト

Casper mintは、Casperネットワーク内にてmotes(モーツ)の残高を管理するシステムコントラクトです。このモーツは、ネットワーク上での計算処理やボンディングに対する支払いに使用されます。Mintシステムコントラクトは、Casperネットワーク上に全てのモーツを保有しているが、各アカウントのメインパースにて残高用のレジャーを維持しています。URefは、お財布がmintの外となる外部への参照を行う方法です。

URefのパーミッションモデルであるAccessRightsは、パース(お財布)に関連づけられたURefを使用する際に実行可能なアクションを決定します。

全てのURefは偽造不可能であるので、パースとデータを交換する唯一の方法は、適切なAccessRightsを伴うURefを有効な方法で現在のコンテキストに与えることです。

基本的なグローバルステートのオプションは、以下の表に従ってより標準的な通貨操作にマップされます。

グローバルステートアクション通貨アクション
Add(追加)預入 (~への送金)
Write(書き込み)引き出し (~からの送金)残高確認の参照

Mint(鋳造)コントラクトインターフェイス

Mintシステムコントラクトは、下記方法をとります。

  • transfer(source: URef, target: URef, amount: Motes) -> TransferResult

    source(送信者)には、少なくともWriteアクセス権が必要であり、target(受信者)には、少なくともAddアクセス権が必要です。

    TransferResultは成功を返し、無効なsourceもしくはtargetである場合、または送信者のお財布にある残高が不十分である場合にエラーとなります。 
  • mint(amount: Motes) -> MintResult

    MintResultは、作成されたURef(全てのアクセス権を保持)を与え、それにより、指定されたamountに等しい残高を得るか、または、許可されていない新たなmotesをMintしたことに起因するエラーを与えるかのいずれかを行います。

    CasperのMintは、システムアカウントだけがmintを呼び出すことができ、有効な暗号化署名を生成する秘密鍵はありません。つまり、ソフトウェア自体のみがシステムアカウントのコンテキストにおいてコントラクトを実行できます。
  • create() -> URef

    常に空のパース(財布)を作成可能な為、エラーになることはないmint(0)の簡易関数です。
  • balance(purse: URef) -> Option<Motes>

    purseには、少なくともReadアクセス権が必要です。

    BalanceResultは、purseが保持しているmotes数を返すか、URefが有効でない場合に何も返さないかのいずれかです。