他ブロックチェーンからCasperへの移行

このページでは、下記の要素においてCasperとEthereum, Near, AptosやSolanaを比較し、他ブロックチェーンからCasperへ移行する際に考慮するべき観点について説明しています:

  1. スマートコントラクト・プラットフォームについての概要
  2. 変数のストレージと状態管理
  3. コントラクト関数
  4. 引数の渡し方

他のブロックチェーンプロジェクトでは異なる技術を使用しており、それらの技術がご自身のユースケースにいかに影響するかを考慮することは重要です。

ブロックチェーンを選ぶ際にコンセンサスメカニズムやトークノミクス、cross-contractの有効性、コントラクトアップグレードの可否、そしてここにて説明されているソフトウェア開発キット(SDK)を比較することも重要です。

スマートコントラクト・プラットフォーム

CasperのスマートコントラクトはRustにて書かれています。

スマートコントラクト内にて定義された変数は、ブロックチェーンへのデータの読み書きにて説明されている通り、Named KeysもしくはDictionaries(辞書)として格納されます

Call関数はスマートコントラクトのメインエントリーポイントとして機能します。コントラクトの初期設定と他のエントリーポイントの定義済みのスマートコントラクトがインストールされると自動で実行されます。

Casperはコントラクトの公開エントリーポイントのみサポートしていることはご留意ください。また、コントラクトはここで説明しているようにアップグレードの可否を定義できるようになっています。

イーサリアムのスマートコントラクトは主にはこの用途に応じて設計された特殊なプログラミング言語であるSolidityで書かれてあります。これらのコントラクトは、ブロックチェーン上に存在しコントラクトの状態を定義するグローバル変数の集合体によって構成されています。

更には、イーサリアムのスマートコントラクトはブロックチェーン上のデプロイ後の初期状態を指定する構造を機能として持っています。コントラクト内にて定義されているパブリック関数はブロックチェーンの外からの呼び出しも可能となっています。

イミュータブルの可否に関してですがイーサリアムのスマートコントラクトは一度デプロイすると永続的にイミュータブルとなります。ただ、”Proxy” や “Diamond”のような設計パターンは、イーサリアムブロックチェーン上にてコントラクトのバージョン化を対応可能としています。

Solidityのスマートコントラクトはオブジェクト指向のプログラミング原理に則っており、クラスの継承やライブラリのような機能をサポートします。

NearのスマートコントラクトはJavaScriptまたはRustにて書かれており、Near SDKは軽量ランタイムにてコードをまとめることができます。単一のWebAssemblyファイルへのコンパイルとNEARネットワークへのデプロイが可能です。

Nearのエコシステムでは、スマートコントラクトはクラスとして機能します。”init”メソッドとして参照されるコンストラクタは、コントラクトの初期状態を初期化する際に必要とされる属性を受け取ります。

コントラクト内に定義された全てのパブリックメソッドは、機能を共有(露出)するインターフェイスとして扱われます。

Nearスマートコントラクトはイミュータブルですが、彼らのステートはトランザクションが実行されると変更されます。コントラクトは新しいバージョンのコントラクトをデプロイすることでもアップグレードされます。Nearブロックチェーンは、状態のマイグレーション、状態のバージョニングそしてコントラクト自体の更新を含む様々なバージョニング機能を提供しています。

Aptosのプログラミング言語はMoveとして知られています。その主なコンセプトはスクリプトやモジュール周辺に影響します。開発者によるモジュールを用いたブロックチェーン機能の拡張やカスタムスマートコントラクトの作成を可能にしているため、スクリプトにて追加のロジックをトランザクションにインコーポレイトすることも可能です。

Moveの特徴であるResourceコンセプトは、アセット(資産)を表現する特徴的な構造です。このデザインは、Aptosのvectorやstructなど他のデータ型と同様のリソース管理を可能にします。

AptosブロックチェーンにおけるスマートコントラクトはModuleと呼ばれており、常にアカウントアドレスと紐づいています。Module内の関数を呼び出すにはモジュールをコンパイルしなくてはなりません。

Moduleのパブリックメソッドはそのインターフェイスでありブロックチェーン外のコードからの呼び出しが可能です。

Moduleコードは、変更されないアカウントアドレスの下でアップグレードと変更が可能です。アップグレードはコードが逆戻り可能な場合のみ受け入れられます。

Solanaのスマートコントラクトは主にRustで書かれています。

他のブロックチェーンプラットフォームとは異なり、Solanaのスマートコントラクトはステートレスかつプログラムのロジックに焦点をあてたものです。コントラクトステートの管理はアカウントレベルにて行われ、アカウント内に保存されたステートとプログラムにて定義されたコントラクトロジックとを切り離したものです。

スマートコントラクトは共通にオンチェーンプログラムとして参照されます。これらプログラムはパブリックエントリーポイントとしてインターフェイスを共有(露出)し外部とのインテラクションを可能にします。

Solanaプログラムの更新は、プログラムへの変更を入れるために必要なパーミッションを持つ “update authority”として知られる権限にて可能とあることはご留意ください。 

様々なストレージとステート管理

ブロックチェーンへのデータの読み書きにて説明しているように、変数は名前付き鍵もしくはディクショナリ(辞書)として格納されます。

更に、ローカル変数はエントリーポイント内で利用可能であり必要なアクションもしくは各エントリーポイントのスコープ内の計算処理を実行する際に使用されます。

コントラクト内の変数は、時間内の特定の瞬間にてコントラクトの状態を保存するために存在しています。ただ、call関数内で使用されるローカル変数はコントラクトのステートに保存されないことは重要です。代わりに、特定の関数内の計算処理を目的とし採用されます。

スマート・コントラクトのコンパイラが型の一貫性を強制し、宣言されたデータ型とストレージ・スペースが一致するように、状態変数は強く型付けされなければなりません。強い型付けはコードの正しさを促進し、コントラクトの状態変数に関連する潜在的なデータ破損やメモリ関連の問題を防ぎます。

コントラクト内の変数はネイティブ型やSDKのコレクションもしくは内部構造として格納されます。SDKコレクションはネイティブの型よりも優位性を持っています。

更に、クラス属性とローカル変数は区別されています。クラス属性はコントラクトの状態を表示し、ローカル変数は関数の呼び出しに指定されコントラクト全体の状態に影響は与えません。

SDKコレクションは状態変数を作成する際の典型となります。なぜなら、リストやマップそしてセットなどの便利なデータ構造を提供するからです。これらのデータ構造はコントラクトのストレージ内の複雑なデータを整理し管理できます。SDKコレクションは効率的なストレージの確証とスマートコントラクト内のアクセス容易性やデータ管理を行ってくれます。

Aptosでは定数やブーリアンそしてアドレスなどのプリミティブ型を採用しており変数を表現しています。これらの要素型が結合されることで構造がつくられるが、その構造定義はModule内でのみ許可されていることは重要です。

Aptosは開発者に効率的なデータ管理と統制用のResourceに関連するデータをクラスターするためにアドバイスします。Resourceはアセットやブロックチェーン上にある特定のデータエンティティを表現します。Resourceにデータをグルーピングすることで、ロジカルコヒーレンスやコードの可読性・保守性の維持が可能となります。

Aptosブロックチェーンは、読み書きのオペレーションを可能にするツリー構造の永続的グローバルストレージを紹介しています。グローバルストレージはアカウントアドレスを元にしたツリーから構成されています。

変数は特定のエントリーポイントの実行コンテキスト内にてローカルに使用可能となっています。それらは、エントリーポイントのスコープに限られておりその外部へのアクセスはできません。この変数はブールや文字列、int等のエレメンタリー型として定義が可能です。

データはアカウント内の構造体に永続します。Binary Object Representation Serializer for Hashing (Borsh / ボーシュ)は、これら構造体のシリアル化とデシリアル化を行います。プロセスは、アカウントからのデータの読み取りやそれ自体が持つ値を取得する為にデシリアル化したり、値のアップデートや修正されたデータをシリアル化しアカウントに新しい値を保存し直すなどに関与しています。

コントラクト関数

Casperのスマートコントラクトでは、パブリック関数が呼び出されるエントリーポイントです。その宣言を行うには、下記フォーマットを使用します:

#[no_mangle]
pub extern "C" fn counter_inc() {
    
    // Entry point body
}

エントリーポイントがその定義内にインプット引数を持っていないことは重要ですのでご留意いただきたいが、引数はコントラクトに渡されたRuntimeArgsを用いてアクセス可能となっています。エントリーポイントはcallエントリーポイント内にてインスタンス化されます。戻り値が必要な場合は、Runtime Return Valueとの受け渡しにて説明されているようにシンタックスを使用して宣言されるはずです。

runtime::ret(value);

それぞれのエントリーポイントへの呼び出しは、ネットワークへのDeployとして扱われるため呼び出し毎にモーツ(moteはネットワークのネイティブアカウントの単位)での支払いが発生します。

イーサリアム上では、パブリックメソッドは二つの目的を持っており、コントラクトロジックの実行とコントラクトのステート修正もしくはコントラクトのステート内に保存されているデータの取得に使用されます。

イーサリアムにおけるパブリックメソッドの宣言は以下フォーマットとなっています:

function update_name(string value) public {
    dapp_name = value;
}

パブリックメソッドが状態を変更することなく値の返却のみを行う場合、下記の通りの定義となるはずです:

function balanceOf(address _owner) public view returns (uint256 return_parameter) { }

イーサリアム上の状態変更なくデータを単独で取得可能なパブリックビューメソッドはガスを消費しないことは覚えておいてください。

Nearブロックチェーンでは、3種類のパブリック関数があります:

  • Init Methods – コントラクトのステートを初期化する際に使用されるクラス構造化
  • View Methods – コントラクトの変数状態を読み取る際に使用される関数
  • Call Methods – コントラクトの状態変更や他のコントラクトの呼び出しといった特定のアクションを実行できます。

Nearにおけるパブリックメソッドの定義は以下のとおりです:

pub fn add_message(&mut self, ...) { }

変数を返すパブリックメソッドの場合の定義は以下となります:

pub fn get_messages(&self, from_index: Option, limit: Option) -> Vec { }

実際の関数実装には必要なパラメータとコントラクトの特定の必須条件に基いたロジックが含まれます。

Aptosにおけるパブリック関数はパブリックメソッドもしくは他のブロックチェーンネットワークに見られる関数に似ています。Aptosにおけるパブリック関数は以下のように表現します:

public fun start_collection(account: &signer) {}

変数を返すパブリック関数の場合、定義は以下のようになります:

public fun max(a: u8, b: u8): (u8, bool) {}

Aptos ブロックチェーンでは、関数から1つ以上の戻り値を取得できます。

Solanaでは関数がネットワークに見える状態のインターフェイスとしてふるまうパブリックエントリーポイントとして定義されます。エントリーポイントの定義はこのフォーマットに従っています:

entrypoint!(process_instruction);

エントリーポイントの実装は下記と同様です:

pub fn process_instruction(
    program_id: &Pubkey,
    accounts: &[AccountInfo],
    _instruction_data: &[u8],
) -> ProgramResult {}

エントリーポイント関数内では、必要なパラメータ(プログラムの識別子やアカウント、アカウントの詳細を提供するAccountInfoの配列を表示するprogram_id、そして受け取ったインストラクションデータを表示する_instruction_data 等)が指定されています。関数は、インストラクション実行時に成功または失敗を表示するProgramResultを返します。

引数を渡し方

名前付き引数は型指定のある文字列として渡されます。Deploy時にエントリーポイントへセッション引数を提供するには下記手法を用います:

casper-client put-deploy \
  --node-address http://65.21.235.219:7777 \
  --chain-name casper-test \
  --secret-key [KEY_PATH]/secret_key.pem \
  --payment-amount 2500000000 \
  --session-hash hash-93d923e336b20a4c4ca14d592b60e5bd3fe330775618290104f9beb326db7ae2 \
  --session-entry-point "delegate" \
  --session-arg "validator:public_key='0145fb72c75e1b459839555d70356a5e6172e706efa204d86c86050e2f7878960f'" \
  --session-arg "amount:u512='500000000000'" \
  --session-arg "delegator:public_key='0154d828baafa6858b92919c4d78f26747430dcbecb9aa03e8b44077dc6266cabf'"

この例の文脈を理解するには、Casperクライアントでのデリゲート(委任)を参照ください: 

コントラクト内では下記のようにセッション引数へアクセス可能です:

let uref: URef = runtime::get_key(Key_Name)

鍵の名前を指定することで期待するセッション引数を取得するためにget_key関数を使用します。

特定のセッション引数を取得するget_key関数の使用方法が不明な場合は、基本的なスマートコントラクトをRustで書く方法にてご確認いただけます。

イーサリアムでは厳密に型定義された関数引数を使用しており、開発者は明示的に入力値と返す変数を定義しなくてはなりません。コンパイラは実行中に関数に渡された引数の正確性を確認します。結果的に、開発者は明示的に引数を指定し関数の署名にて型を返します。コンパイラが、型に関連したエラー取得と型の安全性の確証を行う特定の型に渡された引数が紐づいていることを確証します。

厳密に型定義を強要することで、コンパイラは潜在するランタイムエラーを防ぎ、コードの信頼度を渡された引数と期待する戻り値の型の互換性を検証することで強化してくれます。

厳密に型定義された関数の引数は明示的に入力値と返す変数の定義が必要です。厳密な型を強要することで、プログラミング言語は関数に渡された引数が期待する型と合致し型に関連したエラー発生を防ぎコードの正確性を向上することを確証します。厳密な型定義は追加の明確性と安全性を関数の入力値と戻り値のデータ型を明示的に定めることで提供します。

Nearのように、Aptosは厳密に型定義された関数の引数を必要とするため、型に関連したエラーを防ぎコードの正確性を向上します。

NearとAptosのように、Solanaも厳密に型定義された関数引数が必要となっているため型に関連したエラーを防ぎコードの正確性を向上します。

補足事項

ブロックチェーン選定時は、ネットワークのコンセンサスメカニズムやトークノミクスやエコノミックモデル、コントラクトを跨いだコミュニケーション、スマートコントラクトのアップグレードそして利用可能なソフトウェア開発キット(SDK)も確認した方がよいでしょう。

  1. Consensus mechanism(コンセンサスメカニズム):ブロックチェーンネットワークが検証時の合意形成やトランザクションのシークエンスのために使用するアルゴリズムです。異なるブロックチェーンでは、Proof-of-Work (PoW)やProof-of-Stake (PoS)はたまたデリゲートされたProof-of-Stake (DPoS)等、様々なコンセンサスメカニズムを採用しています。コンセンサスメカニズムの選択は、セキュリティや拡張性そしてエネルギーの効率性のような要素に影響します。
  2. Tokenomics(トークノミクス/経済圏):ブロックチェーンネットワークの経済圏モデルやそのネイティブトークン、トークン分配への関与、インフレーション、活用方法そしてガバナンスに関連しています。ネットワークのトークノミクス(経済圏)を理解することはエコシステムの長期的な成功と潜在的な価値を評価するためには必須となります。
  3. Cross-contract capabilities(コントラクトを跨いだ有効性):ブロックチェーンネットワーク内にて疎通やコミュニケーションを行うスマートコントラクトの有効性です。この機能は、複雑な分散型アプリケーション(dApps)のビルドやコントラクト内の機能実装には必須となります。
  4. Contract upgradability(コントラクトのアップグレード可否):ネットワーク上にインストールされたスマートコントラクトのインストール後の修正もしくは更新可否を決定します。選択したブロックチェーンの柔軟性を査定することは、コントラクトの保守やバグ修正、そして現存のエコシステムを壊すことなく新しい機能の導入もしくは改善の観点にて必須となります。
  5. SDK availability(利用可能なSDK):開発過程で重要な役割を担っています。SDKはツールやライブラリ、そしてアプリケーションやブロックチェーン上のスマートコントラクトの作成をシンプルにするためのドキュメントを提供してくれます。成熟度やコミュニティのサポートそして利用可能なSDKの互換性の評価は開発者に必須となります。

これらの要素を考慮することにより、プロジェクトもしくはアプリケーションの特定条件や目的に沿ったブロックチェーンの選定を手助けします。

Casperのエコシステムはエンタープライズ仕様のプロジェクトのサポートを踏まえた上で、これらの要素を満たすことを目的としています。