見出し画像

【Solanaコアコンセプト③】 トランザクション手数料

この記事は、こちらの公式を翻訳・編集したものです。

1 はじめに

1 概要

小額の手数料でSolanaブロックチェーン上での指示を処理することができ、これを「トランザクション手数料」と呼びます。

各トランザクション(一つ以上の指示を含む)がネットワークを通じて送信されると、現在のリーダーバリデーションクライアントによって処理されます。

補足
いつ誰がリーダーかは、『リーダースケジュール』で確認できます。

https://solscan.io/validator#leader

2 経済設計と手数料

トランザクションがグローバルステートとして確認されると、このトランザクション手数料がネットワークに支払われます。

それにより、Solanaブロックチェーンの経済設計を支援します。

3 レント(賃貸料)との違い

トランザクション手数料は、アカウントのレント(賃貸料)とは異なります。

トランザクション手数料はSolanaネットワークでの指示の処理に対して支払われるものです。

一方、レントはブロックチェーン上のデータの保存のために支払われます。

2 トランザクション手数料を支払う理由

トランザクション手数料は、以下に記述されたSolanaの経済設計において多くの利点を提供します。

1 バリデータへの補償

バリデーターネットワークにトランザクションを処理するためのCPU/GPUリソースを補償します。

2 スパムの減少

トランザクションに実際のコストを導入することでネットワークのスパムを減少させます。

補足
悪意のあるものが大量にトランザクションを実行するといったスパム攻撃への予防になります。

3 経済的安定

トランザクションごとの最小手数料額をプロトコルが捕捉することでネットワークに長期的な経済的安定を提供します。

+α 投票にも手数料が発生する

ネットワーク合意の投票通常のシステム転送として送信されます。

そのため、バリデーターは合意への参加のためにトランザクション手数料を支払います。

3 基本的な経済設計

1 概要

多くのブロックチェーンネットワーク(例えばビットコインやイーサリアム)は、短期的なネットワークの安全を確保するためにインフレーションに基づくプロトコル報酬に依存しています。

補足
「インフレーションに基づいた」
という部分は、新たに通貨を発行することで、それによって報酬を支払うシステムという意味です。

長期的には、これらのネットワークはトランザクション手数料にますます依存するようになります。

Solanaにおいても同様であり、具体的には以下の通りです。

各トランザクション手数料の一定割合(初期は50%)バーン(焼却)され、残りはトランザクションを処理する現在のリーダーに渡されます。

スケジュールされたグローバルなインフレ率は、Solanaバリデーターに配布される報酬の源泉を提供します。

2 なぜ一部の手数料を焼却するのか

上述のように、各トランザクション手数料の一定割合がバーン(破壊)されることは、SOLの経済的価値を固定し、ネットワークの安全を維持することを目的としています。

トランザクション手数料が完全に焼却される方式とは異なり、リーダーは依然としてできるだけ多くのトランザクションを自分のスロットに含めるように動機付けられます。

補足
確かに、全部バーンされてしまうのであれば、たくさんのトランザクションを処理するモチベーションは無くなりますね。

焼却された手数料は、分岐選択時に悪意のあるバリデーターによるトランザクションの検閲を防ぐのにも役立ちます。

補足
ここでいう検閲とは、わざとブロックにトランザクションを含めない行為を言います。

3 攻撃の例

悪意のある検閲リーダーによるProof of History (PoH) フォークの場合

検閲によって失われた手数料があるため、正直なフォークに比べて焼却される手数料の総量が少なくなると予想されます。

補足
ブロックに入れるトランザクションを制限している分、制限していない場合に比べて、手数料が少なくなるということですね。

検閲リーダーがこれらの失われたプロトコル手数料を補償する場合、自身のフォークで焼却手数料を自己負担する必要があります。

これにより、最初から検閲する動機が減少する可能性があります

4 トランザクション手数料の計算方法

1 概要

トランザクション手数料は主に2つの部分に基づいて計算されます。

①署名ごとの静的に設定された基本手数料

②トランザクション中に使用される計算リソースの量(「計算ユニット」で測定)

2 計算予算(compute budget)

各トランザクションが異なる量の計算リソースを要求します。

そのため、トランザクションごとに許可される最大の計算ユニット数、つまり「計算予算(compute budget)」が設定されています。

3 計算ユニット超過時の挙動

トランザクション内の各指示の実行は、異なる数の計算ユニットを消費します。

最大の計算ユニット数(つまり計算予算の枯渇)が消費されると、ランタイムはトランザクションを停止、エラーを返します。

これによりトランザクションは失敗します。

+α 手数料見積もりのリクエスト

RPCからの手数料見積もりのリクエストはこちらから。

5 優先料金

1 概要

Solanaトランザクションでは、「優先料金」と呼ばれる任意の追加料金を設定して、他のトランザクションと比較して優先されるようにすることができます。

この追加料金を支払うことで、トランザクションの処理優先度が高まり、実行時間が短縮されます。

2 優先料金の計算方法

トランザクションの優先料金は、使用可能な最大計算ユニット数計算ユニット価格(マイクロ・ランポートで測定)を掛け合わせることで計算されます。

補足
名前が難しいですが、結局普通の価格の計算ですね。
みかんの数が20個、1個100円ですと、20 × 100円ですもんね。

各トランザクションは、『SetComputeUnitLimit』『SetComputeUnitPrice』という計算予算指示を含めることで、許可される最大計算ユニット数計算ユニット価格設定できます。

補足
その名の通り、コンピュートユニットの上限価格セットしているのですね。

3 アカウントについての補足

Solanaトランザクション内の他の命令と異なり、計算予算命令にはアカウントが必要ありません。

補足
これは、トランザクション自体の設定であって、アカウントは関係ないからだと考えられます。

4 デフォルト設定について

SetComputeUnitLimit指示が提供されていない場合、リミットはトランザクション内の命令の数デフォルトの命令ごとのユニット数(現在は200k)として計算されます。

補足
ComputeUnitLimitの設定がされていない場合、命令の数✖️200k。
ということは、トランザクション内に3つの命令があれば、3✖️200k = 600kが上限になるようです。

SetComputeUnitPrice指示が提供されていない場合、トランザクションは追加の優先料金なし最低優先度に設定されます。

5 優先料金の設定方法


トランザクションの優先料金は、『SetComputeUnitPrice』指示を含め、必要に応じて『SetComputeUnitLimit』指示を含めることで設定されます。

ランタイムはこれらの値を使用して優先料金を計算し、ブロック内でのトランザクションの優先順位を決定します。

これらの指示は、それぞれのRustまたは@solana/web3.js関数を通じて作成でき、通常通りトランザクションに含めてクラスターに送信されます。

6 複数タイプ設定によるエラー

トランザクションは計算予算指示の各タイプを一つだけ含めることができます。

重複するタイプがある場合は、TransactionError::DuplicateInstructionエラーが発生し、最終的にトランザクションが失敗します。

https://github.com/solana-labs/solana/blob/master/sdk/src/transaction/error.rs#L144-145

7 設定方法について

7ー1 Rust


solana-sdkクレートには、計算ユニットリミット計算ユニット価格の設定のための指示を作成する関数ComputeBudgetInstructionに含まれています。

① 上限

let instruction = ComputeBudgetInstruction::set_compute_unit_limit(300_000);
https://docs.rs/solana-sdk/latest/solana_sdk/compute_budget/enum.ComputeBudgetInstruction.html

② 価格

let instruction = ComputeBudgetInstruction::set_compute_unit_price(1);
https://docs.rs/solana-sdk/latest/solana_sdk/compute_budget/enum.ComputeBudgetInstruction.html

7ー2 Javascript

@solana/web3.jsライブラリには、計算ユニットリミットと計算ユニット価格の設定のための指示を作成するComputeBudgetProgramクラスの関数が含まれています。

① 上限

const instruction = ComputeBudgetProgram.setComputeUnitLimit({
  units: 300_000,
});
https://solana-labs.github.io/solana-web3.js/classes/ComputeBudgetProgram.html#setComputeUnitLimit

② 価格

const instruction = ComputeBudgetProgram.setComputeUnitPrice({
  microLamports: 1,
});
https://solana-labs.github.io/solana-web3.js/classes/ComputeBudgetProgram.html#setComputeUnitPrice


8 優先料金のベストプラクティス

8ー1 最小の計算ユニットを要求する

トランザクションは、実行に必要な最小限の計算ユニットを要求するべきです。

これにより、手数料を最小限に抑えることができます。

また、要求した計算ユニットの数実際にトランザクションの実行に消費された計算ユニットの数超えた場合でも、手数料は調整されない点にも注意が必要です。

補足
ここ、すごく大事だと思います。
つまり、100万の計算ユニットを要求し、実際には10万分しか使わなかった場合も、要求した100万分の手数料が発生します。

8ー2 最近の優先料金を取得する

トランザクションをクラスターに送信する前に、getRecentPrioritizationFees RPCメソッドを使用して、ノードによって処理された最近のブロック内で支払われた最近の優先料金のリストを取得することができます。

https://solana.com/docs/rpc/http/getrecentprioritizationfees

このデータを使用して、トランザクションがクラスターによって処理される可能性を高めるとともに、支払う手数料を最小限に抑えるための適切な優先料金を見積もることができます。

6 手数料収集

1 支払者の特定

トランザクションには、少なくとも1つのアカウントがトランザクションに署名しており、書き込み可能でなければなりません。

書き込み可能な署名者アカウントは、トランザクションアカウントのリストの最初にシリアル化され、このアカウントリストの最初のアカウントは常に「手数料支払者」として使用されます。

https://solana.com/docs/core/transactions

2 支払者残高の確認

トランザクション指示が処理される前に、手数料支払者のアカウント残高からトランザクション手数料が差し引かれます。

手数料支払者の残高がトランザクション手数料をカバーするのに十分でない場合、トランザクションはクラスターによってドロップされます。

残高が十分であれば、トランザクションが成功裏に処理されたかどうかに関わらず、手数料は差し引かれます。

3 エラー時等の処理

実際、トランザクション指示がエラーを返したり、ランタイムの制限に違反したりした場合、トランザクション手数料の差し引きを除くすべてのアカウント変更はロールバックされます。

補足
エラーがあった場合、ロールバックされることにより、アカウントは全く変化しませんが、手数料だけは差し引かれます。

7 手数料分配

1 概要

トランザクション手数料は部分的に焼却され、残りの手数料は該当するトランザクションが含まれるブロックを生成したバリデーターによって収集されます。

トランザクション手数料の焼却率は、2021年初めにインフレ報酬が有効化された際に50%として設定され、これまで変更されていません。

補足
この辺りは第3章で出てきましたね。

2 動機づけへの貢献について

これらの手数料は、バリデーターがリーダースケジュールの自分のスロット中にできるだけ多くのトランザクションを処理するように動機付けます。

3 入金のタイミング

収集された手数料は、現在のスロットのリーダースケジュールに記載されたバリデーターのアカウントに、ブロックに含まれるすべてのトランザクションの処理後に入金されます。

サポートをしていただけたらすごく嬉しいです😄 いただけたサポートを励みに、これからもコツコツ頑張っていきます😊