はじめに

『DApps開発入門』という本や色々記事を書いているかるでねです。

今回は、Subnet-EVMにACP176の動的手数料を取り込み、オンチェーンで手数料パラメータを変更できる新プリコンパイルを追加して、SAE対応とC-Chain同等の料金制御を可能にする仕組みを提案しているACP224についてまとめていきます!

以下にまとめられているものを翻訳・要約・補足しながらまとめていきます。

他にも様々なEIP・BIP・SLIP・CAIP・ENSIP・RFC・ACPについてまとめています。

概要

ACP224は、Subnet-EVMに対してACP176を実装し、さらに新たなプリコンパイルコントラクトであるACP224FeeManagerPrecompileを導入することを目的としています。 このプリコンパイルは、ACP176の有効化後にオンチェーン上で手数料パラメータを動的に設定・変更できる機能を提供します。 これは、現在FeeManagerPrecompileがACP176導入前の仕組みとして提供している操作性を、ACP176以降の新しい手数料モデルに対応した形で維持するものです。

ACP176については以下の記事を参考にしてください。

つまり、ACP224によってSubnet-EVMでも動的なガス制御と料金管理が可能となり、C-Chainと同様の挙動・メカニズムを持つ統一的な料金システムを利用できるようになります。

動機

背景

ACP176は、EVMにおける動的手数料メカニズムを改良し、ターゲットとなるガス消費量をより正確に達成するための調整機構を導入しました。 さらに、ターゲットガス消費率そのものを動的に更新できる機能も追加されています。

現時点では、このACP176はC-Chainのみに適用されています。 その理由は、多くのL1チェーン(レイヤー1ブロックチェーン)が、ジェネシス設定(genesisファイル)内のFeeManagerPrecompileとFeeConfigを通じて、手数料やガスターゲットを静的に制御する構成を採用しているためです。 しかし、従来のFeeManagerPrecompileは、ACP176で導入された新しい料金調整メカニズムとは互換性がないという制約がありました。

SAEとの関係

ACP194で提案されているStreaming Asynchronous Execution(SAE)を利用するためには、ACP176と整合したガスターゲットとガス容量の管理メカニズムが必要です。

ACP194については以下の記事を参考にしてください。

SAEの前提条件として、以下の2つが明示されています。

  • 秒単位で追加されるガス容量の量(known gas capacity added per second)
  • 最大ガス容量(maximum gas capacity)

これらが明確に定義されていなければ、トランザクションの有効性判定や料金見積りの上限計算が困難になります。 しかし、現在のSubnet-EVMで採用されているWindower Fee Mechanismには、こうした固定的なガス容量レートの概念が存在しません。 そのため、ガス価格の上限を事前に算出することが難しく、静的解析モデルが成立しないという問題があります。

この課題を解決し、SAEをSubnet-EVM上で利用できるようにするには、ACP176で導入された動的ガスキャパシティ管理機構の統合が必須となります。

Subnet-EVMへの統合の意義

ACP176をSubnet-EVMに組み込むことには、以下の2つの大きな利点があります。

  • 将来的なSAE利用に向けた技術的要件を満たす SAEは、効率的で非同期的な実行モデルを実現するために設計されています。 そのためには、ガス供給量やターゲット消費量を正確に追跡できるメカニズムが不可欠です。

  • C-Chainとの一貫性確保とメンテナンス負荷の削減 Subnet-EVMとC-Chainのガス・料金管理メカニズムを統一することで、Avalanche全体としてのコードベースの整合性と保守コストの削減を実現できます。 これにより、複数の料金計算ロジックを個別に維持する必要がなくなり、将来的なアップデートやバグ修正が容易になります。

新プリコンパイルACP224FeeManagerPrecompileの役割

この提案のもう一つの柱は、ACP224FeeManagerPrecompileという新しいプリコンパイルの導入です。 このプリコンパイルは、ACP-176で導入された動的料金モデルに対応したFee Managerとして機能し、オンチェーンで手数料設定を柔軟に更新可能にします。

これまで、料金パラメータの変更は主にジェネシス設定を通じて静的に定義されていましたが、この新プリコンパイルによって次のようなことが可能になります。

  • 管理者(Admin)権限を持つアカウントが、ネットワーク稼働中に料金パラメータを変更できる
  • ガスターゲット値や調整率などを、オンチェーン上で動的に更新できる
  • これにより、需要変動に応じた柔軟な料金制御が可能になる

このように、ACP176とACP224FeeManagerPrecompileの組み合わせは、Subnet-EVMの料金設計をより高度かつ柔軟にし、SAEなどの将来提案に対応可能なEVMプラットフォームを構築する上で欠かせないアップグレードとなります。

仕様

ACP176のパラメータ

ACP224では、C-Chainで導入済みのACP176と同じパラメータ体系を使用し、Subnetごと(チェーンごと)に値を設定できるようにします。 各記号の意味は以下です。

Parameter 説明 C-Chainの設定
TT 1秒あたりの目標ガス消費量 dynamic
RR 1秒あたりに追加されるガス容量 2*T
CC 最大ガス容量 10*T
PP 1秒あたりの最小目標ガス消費量 1,000,000
DD 目標ガス消費率の更新定数 2^25
QQ 目標更新の1ブロックあたり変化制限 2^15
MM 最低ガス価格 1×10^-18 AVAX
KK 初期ガス価格更新定数 87*T

「dynamic」はブロック提案やプロトコルにより変化することを意味します。 R=2TR=2T は、ガス価格が上昇する速度と下降する速度を同じに保つための設定です。 つまり、ネットワークの利用量が増えた場合に価格が上がるスピードと、利用量が減った場合に価格が下がるスピードが対称的(バランス良く)になるようにしています。

一方、DDとQQは、それぞれ目標ガス消費量 TT をどれだけ細かく、どれだけの幅で変更できるかを決める値です。 これにより、各ブロックごとのガスターゲットの変動が急すぎず、かつ十分に調整できるようになります。 C-Chainではこの2つの値によって、ガスターゲットの変化が安定しつつも実際のネットワーク負荷にしっかり追随できるよう調整されています。

旧Subnet-EVMの手数料設定パラメータ

ACP176導入以前、Subnet-EVMは以下の設定で手数料(EIP1559系のBaseFeeと「ブロックガスコスト」)を制御していました。用語の要点も併せて説明します。

EIP1559については以下の記事を参考にしてください。

  • GasLimit 各ブロックで消費できる最大ガス量(ブロックガス上限)を直接指定します。
  • TargetBlockRate 手数料調整の基準となる目標ブロック生成間隔(秒)です。 実際の生成がこれより速ければブロックガスコストを上げ、遅ければ下げます。
  • MinBaseFee ブロックのEIP1559のBaseFeeの下限です。 BaseFeeはトランザクションの最低ガス価格でもあるため、ネットワーク全体の最低ガス価格を決めます。
  • TargetGas 10秒間の合計ガス消費量の目標値を設定します(この中にはブロック生成時のガスコストも含まれます)。 ネットワークの実際のガス消費量がこの目標値を上回った場合はBaseFeeを上げ、逆に下回った場合はBaseFeeを下げます。
  • BaseFeeChangeDenominator 「実績−目標」の差をどれくらいの割合でBaseFeeに反映するかを決める分母です。 値が大きいほどBaseFeeの変化はゆっくりになり、値が小さいほど素早く変わります。
  • MinBlockGasCost / MaxBlockGasCost ブロック生成に課すガスコストの下限/上限です(ブロック毎に必ず消費される固定ガスの幅)。
  • BlockGasCostStep ブロック生成間隔のずれに応じて、ブロックガスコストをどの程度増減させるかを決める設定値です。 もしブロックが目標どおりの間隔で生成された場合は、親ブロックと同じガスコストが適用されます。 一方、目標より早く生成された場合は「早かった秒数 × Step」の分だけガスコストを増やし、遅れた場合は「遅れた秒数 × Step」の分だけガスコストを減らします。 なお、この値を非常に大きく設定すると、ブロックを目標間隔より速く生成することが難しくなるため、 実質的に「TargetBlockRateより速い生成」を抑制する働きを持ちます。 (例:目標より2秒速くブロックが生成された場合、ガスコストは「2 × Step」だけ増加します)

Subnet-EVMにおけるACP176のパラメータ

ACP176の導入により、Subnet-EVMの以下の設定は不要になります。 GasLimitとBaseFeeChangeDenominatorはACP176の枠組みに置き換わります。 さらにTargetBlockRate、MinBlockGasCost、MaxBlockGasCost、BlockGasCostStepはACP226(動的最小ブロック時間)により削除されます。

一方で、既存設定とACP176の対応は以下のとおりです。

  • MinGasPriceはACP176のMMに相当し、最低ガス価格を設定します。 従来のMinBaseFeeに近い効果です。 現在のデフォルトは25 * 10^-18(25nAVAX)ですが、C-Chainに合わせて1Weiに変更されます。
  • TargetGasはACP176のTT(1秒あたりの目標ガス消費量)です。
  • MaxCapacityFactorはCCの係数に相当し、最大ガス容量(=ブロックガス上限)を決めます。 C=MaxCapacityFactor×TC = MaxCapacityFactor \times Tで計算され、デフォルトは10(C-Chainと同じ)です。
  • TimeToDoubleは価格応答定数KKの調整に使います。 K=(RMult×TimeToDouble)/ln⁡2K = (RMult \times TimeToDouble) / \ln 2で求め、RMult=2RMult=2とします。 デフォルトTimeToDouble=60秒ならK≈87TK\approx 87T(C-Chainと同じ)です。

最終的な既定値と可変性は以下の表のとおりです。

Parameter 説明 既定値 変更可否
TT 1秒あたりの目標ガス消費量 1,000,000 ✅
RR 1秒あたりに追加されるガス容量 2*T ❌
CC 最大ガス容量 10*T ✅(MaxCapacityFactor、既定10)
PP 最小目標ガス消費量/秒 1,000,000 ❌
DD 目標更新の定数 2^25 ❌
QQ 目標更新の変化制限 2^15 ❌
MM 最低ガス価格 1Wei ✅
KK 価格応答定数 約87*T ✅(TimeToDouble、既定60s)

R=2TR=2Tの固定は、ガス価格が「上がる速度」と「下がる速度」を同じに保つためです。 DDとQQは各ブロックでTTをどれだけ動かせるか(およびその刻み)を決めます。 C-Chainと同一の既定値により、1ブロックあたり約1/10241/1024の相対変更が可能です。 P=1,000,000P=1{,}000{,}000gas/秒はどのEVM L1にとっても十分低い下限で、TTは上方向に上限なく動的に増やせます。

ジェネシス設定(Genesis Configuration)

新しいチェーンでは、プリコンパイルを有効化しなくてもジェネシスのチェーン設定でパラメータを与えられます。 未指定の場合はC-Chainの既定が使われます。 設定例は以下のとおりです。

json
{
  "...": "...",
  "acp224Timestamp": 0,
  "acp224FeeConfig": {
    "minGasPrice": 0,
    "maxCapacityFactor": 10,
    "timeToDouble": 60
  }
}

acp224TimestampはACP224を有効化する時刻(エポック秒を表す64bit整数)です。 acp224FeeConfigでMM、CC(係数)、KK(を決める時間)を定義できます。

バリデータ設定による動的ガスターゲット

C-ChainのACP176と同様に、各バリデータはノード設定でgas-targetを設定できます。 ブロックビルダーは、許容される更新幅に従いこの設定を用いて提案ブロックの targetExcess を計算して反映します。 これにより、オンチェーンのガスターゲットはバリデータの設定値に合わせて段階的に更新されます。

ACP224FeeManagerPrecompileによる動的ガスターゲットと手数料設定

管理者アカウントでガスターゲットや手数料関連パラメータをオンチェーンで動的に変更したいL1向けに、任意で有効化できる新プリコンパイルACP224FeeManagerPrecompileを追加します。 操作体系は、Subnet-EVMに存在する既存のFeeManagerPrecompileに類似します(アクセス制御はIAllowList準拠)。

solidity
//SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
import "./IAllowList.sol";

/// @title ACP-224 Fee Manager Interface
/// @notice Interface for managing dynamic gas limit and fee parameters
/// @dev Inherits from IAllowList for access control
interface IACP224FeeManager is IAllowList {
    /// @notice Configuration parameters for the dynamic fee mechanism
    struct FeeConfig {
        uint256 targetGas;           // Target gas consumption per second
        uint256 minGasPrice;         // Minimum gas price in wei
        uint256 maxCapacityFactor;   // Maximum capacity factor (C = factor * T)
        uint256 timeToDouble;        // Time in seconds for gas price to double at max capacity
    }

    /// @notice Emitted when fee configuration is updated
    /// @param sender Address that triggered the update
    /// @param oldFeeConfig Previous configuration
    /// @param newFeeConfig New configuration
    event FeeConfigUpdated(address indexed sender, FeeConfig oldFeeConfig, FeeConfig newFeeConfig);

    /// @notice Set the fee configuration
    /// @param config New fee configuration parameters
    function setFeeConfig(FeeConfig calldata config) external;

    /// @notice Get the current fee configuration
    /// @return config Current fee configuration
    function getFeeConfig() external view returns (FeeConfig memory config);

    /// @notice Get the block number when fee config was last changed
    /// @return blockNumber Block number of last configuration change
    function getFeeConfigLastChangedAt() external view returns (uint256 blockNumber);
}

重要な挙動として、setFeeConfigでの更新はトランザクションのAccept/Execute時ではなく、Settlement時に発効します(ACP194の実行ライフサイクルに準拠)。 これにより、トランザクションを受け入れる時の検証条件が、すべてのノードで常に同じ基準で維持されます。 手数料パラメータが途中で変更されても、ノード間で検証条件が不一致になることはありません。

またプリコンパイルは、最新のFeeConfigに加えて、導出済みの qq (targetExcess計算で使う係数)と KK をステートに保持します。 qqはCorethのdesired target excess計算と同じ手順でtargetGasから決定します。 KKは本来K=targetGas⋅timeToDoubleln⁡2K = \frac{targetGas \cdot timeToDouble}{\ln 2}で計算できますが、浮動小数点の誤差を避けるため2分探索で最も近い整数値を求めます。

targetExcessの決定フローは以下の図の通りです。

flowchart TD
    A[ACP-224 activated] --> B{Is ACP224FeeManager precompile active?}

    B -- Yes --> C[Use targetExcess from precompile storage at latest settled root]

    B -- No --> D{Is gas-target set in node chain config file?}
    D -- Yes --> E[Calculate targetExcess from configured preference and allowed update bounds]

    D -- No --> F{Does parent block have ACP176 fields?}
    F -- Yes --> G[Use parent block ACP176 gas target]
    F -- No --> H[Use MinTargetPerSecond]

価格発見に関するACP176計算の調整

ACP176では、ブロックのガス価格は以下のように定義されています。

gasprice;=;M⋅e,x/Kgas_price ;=; M \cdot e^{,x/K}

ここで、Mは最低ガス価格(下限)、Kは価格がどれくらいの速さで変化できるかを決める定数、xは現在のexcess(目標ガス量に対して実際の利用がどれだけ多い/少ないかを表す内部指標)です。 需要が高いほどxは大きくなり、低いほど小さくなります。 価格はこのxを使って指数関数で計算されます。

ACP224FeeManagerPrecompileから MM(minGasPrice)や KK(timeToDouble から導出)を変更する場合、xx も同時に更新して変更前後で現在のガス価格が急に変わらないように調整します。

MMを変更した場合

MMを M0M_0 から M1M_1 に変更する場合、理論上は以下の式で xx を補正すれば変更前と同じガス価格を維持できます。

x1=ln⁡(M0M1)⋅K+x0x_1 = \ln\left(\frac{M_0}{M_1}\right) \cdot K + x_0

ただし、この計算には浮動小数点演算が必要となり、EVM上では誤差が生じる可能性があります。 そのため実装上は、2分探索を用いて「M1M_1 を使って計算したガス価格が、変更前の価格以上となる最小の非負整数 x1x_1」を求めます。

この手法により、以下のような挙動が保証されます。

  • 最低ガス価格を下げる、または現行価格以下に設定する場合 ガス価格は即座に変化しません。
  • 最低ガス価格を現行価格より高く設定する場合 ガス価格はその新しい下限まで即座に引き上げられます。

つまり、MM の変更は「価格の下限を調整する操作」であり、現行のガス価格がその下限より高い場合は維持され、下限より低い場合は新しい最低価格に合わせて引き上げられます。

KKを変更した場合

KKを K0K_0 から K1K_1 に変更する場合は、以下の式で xx を再計算します。

x1=x0⋅K1K0x_1 = x_0 \cdot \frac{K_1}{K_0}

この補正により、変更後もガス価格そのものは変わりません。 KK は「ガス価格が変化する速度」を決める定数のため、値を変えてもその瞬間の価格には影響せず、以降の価格変動のスピードだけが変わるという挙動になります。

パラメータ計算と整合性

qq(targetExcess の導出に用いる係数)および KK は、targetGas と timeToDouble の値から算出されます。 この計算手順は C-Chainと同一であり、EVMの整数演算の制約を踏まえて、実際には 2分探索(二分法)により最も近い整数値を求めます。

すべての setFeeConfig による設定変更は、トランザクションのSettlement(確定)時に有効化されます。 これにより、トランザクションを受け入れる段階での検証基準が、すべてのノードで統一され、手数料パラメータの変更によってノード間で整合性が崩れることはありません。 これは SAE(ACP194) におけるトランザクションキューの一貫性を確保する上で重要な要素です。

これらの設計により、Subnet-EVMはC-Chainと同様のACP176ベースの動的手数料モデルを採用し、ACP224FeeManagerPrecompile を利用してネットワーク稼働中でも安全かつ精密に手数料設定を調整できるようになります。

互換性

ACP224を有効化するには、まず新しい手数料メカニズム(ACP224のフィーロジック)をネットワークアップグレードで有効化する必要があります。 新しい手数料マネージャプリコンパイル(ACP224FeeManagerPrecompile)を使う場合は、これとは別に追加のアクティベーションが必要です。 プリコンパイルのアクティベーションは、必ずACP224(フィーメカニズム)のアクティベーション後に行ってください。 プリコンパイルはACP224の手数料更新ロジックに依存して動作するためです。

ACP224のメカニズムを有効化すると、従来の手数料メカニズムと従来のFeeManagerプリコンパイルは無効化されます。 旧ロジックと新ロジックが同時に有効になって挙動が曖昧になることを防ぐためです。 すでに稼働中のネットワーク向けには、アクティベーション時刻とACP176の構成パラメータを上書き指定できるネットワークアップグレード用オーバーライドが導入されます。

これらのアップグレードは現時点では任意です。 ただしACP194(SAE)の導入に伴い、SAEを利用するにはACP224の有効化が必須になります。 ACP224を有効化しないネットワークはACP194を利用できません。

flowchart TD
    A[Step1:ACP224の手数料メカニズムを有効化] --> B[旧フィー機構と旧FeeManagerを無効化]
    B --> C{新FeeManagerを使うか}
    C -- はい --> D[Step2:ACP224FeeManagerPrecompileを有効化]
    C -- いいえ --> E[プリコンパイルなしで運用継続]
    %% 注意: DはAの後でのみ有効化可

セキュリティ

基本的なセキュリティ前提はACP176と同じです。 一方で、ACP224FeeManagerPrecompileで動的に変更可能なパラメータが公開されるため、設定ミスのリスクが追加されます。 設定を誤ると、ネットワークがDoS攻撃に弱くなる、あるいは不必要に高い手数料が発生するといった問題につながり得ます。 したがって、どの値をいつ反映するかの運用管理や、反映順序(Settlementで有効化されること)を含む手順管理が重要です。

未解決の論点

下記の点は未確定です。

質問
ACP224FeeManagerプリコンパイルを有効化したときに旧プリコンパイルを自動で無効化すべきか、それとも別のアップグレードで手動無効化を求めるべきか。
ジェネシス/チェーン設定にtargetGasを任意項目として持たせ、チェーン設定がバリデータ設定より優先されることを示すシグナルとして使うべきか。
上記に関連し、ACP224FeeManagerプリコンパイル側にtargetGasの制御をバリデータに委ねるトグルを用意すべきか。

最後に

今回は「Subnet-EVMにACP176の動的手数料を取り込み、オンチェーンで手数料パラメータを変更できる新プリコンパイルを追加して、SAE対応とC-Chain同等の料金制御を可能にする仕組みを提案しているACP224」についてまとめてきました! いかがだったでしょうか?

質問などがある方は以下のTwitterのDMなどからお気軽に質問してください!

他の媒体でも情報発信しているのでぜひ他も見ていってください!