# [EIP7736] Verkleツリーでステートデータを期限切れ管理する仕組みを理解しよう！

> EIP7736では、Verkleツリーの各拡張ノード（共通の鍵接頭部をまとめる中間ノード）に「更新エポック」を導入する提案をしています。

- URL: https://cardene.dev/articles/f8edd33c1a35f593be5f
- 公開日: 2025-07-07
- 更新日: 2025-07-07
- トピック: Blockchain
- タグ: ethereum, solidity, smartcontract, ブロックチェーン

## はじめに

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

https://amzn.asia/d/gxvJ0Pw

今回は、EthereumノードにVerkleツリーの拡張ノードにエポック管理を導入して、古いステートデータを自動的に期限切れ削除し、必要な時に簡易な証明で再度データにアクセスする仕組みを提案している**EIP7736**についてまとめていきます！

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

https://eips.ethereum.org/EIPS/eip-7736

他にも様々なEIPについてまとめています。

https://cardene.notion.site/ERC-EIP-2a03fa3ea33d43baa9ed82288f98d4a9?pvs=4

## 概要

**EIP7736**では、Verkleツリーの各拡張ノード（共通の鍵接頭部をまとめる中間ノード）に「**更新エポック**」を導入する提案をしています。
エポックとは一定期間を示す単位で、エポックが期限切れになると、その拡張ノードとその配下にある接尾ノード（実際の鍵と値を格納する末端ノード）をツリーから削除できるようになります。
削除された状態から再びアクセスが必要になった場合には、新しい取引タイプを用いてシンプルなVerkle証明（ツリー構造の正当性を示す証跡）を提出し、その証明に基づいて拡張ノードと接尾ノードを再活性化すると同時に、エポックカウンタを更新します。

## 動機

従来の状態データの期限切れ（state expiry）実装は、アドレス空間の拡張や多層ツリーの導入など、Ethereumの基本構造に大きな変更を伴うため非常に複雑化しがちでした。
**EIP7736**では、葉（リーフ）ノードのみを削除し、ツリーの他の部分はそのまま維持することで、ユーザーや開発者の体験を損なうことなくステートデータの一部を効率的に消去する仕組みを実現します。
これにより、既存のノード構造を大きく変えずに、必要な部分だけを期限切れ管理の対象とするシンプルかつ非破壊的なアプローチを提供します。

## 仕様

### 定数の定義

この仕様では、ツリーのエポック管理と復活トランザクションを制御するためにいくつかの定数を定義しています。
まずフォーク時刻を示す `FORK_TIME` は後日決定され、エポックの長さ `EPOCH_LENGTH` は約6か月（15,778,800秒）に設定されます。
フォーク直前のエポック番号を `INITIAL_EPOCH_COUNTER` として0に初期化し、同時に保持する有効エポック数 `NUM_ACTIVE_EPOCHS` は2とします。
ステートを復活させる専用のトランザクション種別ID `RESURRECT_TX_TYPE` も後日決定されます。
これらの定数が、エポックの進行、期限切れ判定、復活処理の制御に用いられます。

### Verkleツリーへの変更

ツリー全体に `current_epoch` という整数変数を追加し、フォーク前は `INITIAL_EPOCH_COUNTER` で初期化します。
拡張ノード（extension node）には新たに `last_epoch` というフィールドを設け、初期化時や更新時にそのノードが最後に更新されたエポック番号を保持します。
ノードをコミットする `extension_and_suffix_tree` 関数では、既存のステム（stem）と値集合（values）に加えて `last_epoch` をコミットメント要素として組み込み、ツリーの整合性証明に用います。

さらに、ツリーへの読み書き操作時には常に「**現在のエポック番号が `last_epoch` + `NUM_ACTIVE_EPOCHS` より小さい**」ことを確認し、この条件を満たさなければ処理を中断（revert）します。
書き込みが正常に行われた場合は当該拡張ノードの `last_epoch` を `current_epoch` に更新し、以後の有効期限チェックに備えます。

### エポックのチェックと期限切れ処理

各ブロックの処理開始時点で `check_epoch_end` 関数を実行し、ブロックタイムスタンプが `FORK_TIME` + `current_epoch` × `EPOCH_LENGTH` 以上であれば `current_epoch` をインクリメントします。
その際、古いエポックのデータを削除するために `schedule_expiry` 関数を呼び出し、 `current_epoch` − `NUM_ACTIVE_EPOCHS` に対応する拡張ノードのキープセイク（stem とコミットメントC）を使って後続の削除作業をクライアント側で実装します。
実際の削除は、ブロックのファイナライズ後に行われることが想定されます。

:::message
#### キープセイクとは

キープセイクとは、期限切れ処理の対象となった拡張ノードとその接尾ノードを後から復活させるために、クライアント側で保持しておく必要がある二つのデータのことです。
具体的には「`stem`」と「**コミットメントC**」を指します。

##### stem（ステム）

stem は、拡張ノードが表す鍵空間の共通接頭部を示す `31` バイトの値です。
Verkle ツリーでは、鍵を枝分かれさせるために各拡張ノードにこの `stem` を割り当てており、ツリーのどの位置にどのサブツリーがあったかを特定する情報になります。
キープセイクとして `stem` を保持しておくことで、削除後に同じ場所へ正しくノードを復元できます。

##### コミットメントC

コミットメントC は、`extension_and_suffixtree` 関数で計算されるノードのまとめ上げたハッシュ値（コミットメント）です。
具体的には、サブリーフの値から二つの部分ツリーのコミットメント C1, C2 を導出し、そこに `stem` と `last_epoch` を組み合わせて最終的なコミットメントを生成します。
キープセイクとしてこのCを保持することで、復活トランザクション時に提出された値がもともとそのノードにあったデータであることを検証できます。
:::

### 復活用トランザクションの仕組み

期限切れで削除されたノードを再構築するため、`RESURRECT_TX_TYPE` として定義されたトランザクションを用います。
ペイロードはSSZ形式で「ステム、`last_epoch`、`values`」を含むベクトルです。
検証開始時に**EIP4762**で定義されたガスコスト関数 `resurrect_gas_cost` を適用し、証明に必要なブランチやチャンク編集のコストを合算して徴収します。

検証ロジックではまずSSZを逆シリアライズし、各サブツリーについて `validate_subtree` を呼び出します。
ここでは保存しておいたキープセイクコミットメントと、ペイロード内のステム・値集合・`last_epoch` から再計算したコミットメントが一致することを確認し、問題なければ新しい `current_epoch` を使って拡張ノードと接尾ノードを再コミットします。
最後に `tree.resurrect_subtree` を呼び出してツリーに復活させ、成功すれば処理が完了します。

:::message
#### SSZとは？

SSZ（SimpleSerialize）は、Ethereumのコンセンサス層で用いられるデータシリアライズ方式です。
Beacon Chainやシャーディングのプロトコル仕様で標準採用されており、高速かつ軽量にデータをバイト列に変換・復元できる点が特徴です。

SSZは主に以下の目的で設計されました。

- ノード間で大量の状態データをやり取りする際に処理速度を最適化する。
- シリアライズ結果が容易にMerkle化できる構造を持たせ、部分データの真偽検証や省略（プリング）を効率的に行えるようにする。

##### データ型の構成

SSZではデータ型を大きく「**基本型**」と「**コンテナ型**」に分類します。
基本型には符号なし整数やブール値、固定長バイト列などが含まれ、常に決まったバイト長で表現されます。
一方、コンテナ型は複数の要素をまとめた構造体に相当し、要素の並びや可変長配列などを扱います。

##### シリアライズのルール

シリアライズ時にはまず基本型の値をリトルエンディアンで固定長にエンコードし、可変長データは末尾にまとめて配置します。
コンテナ型は要素を定義順に並べ、固定長部分と可変長部分を分離してから連結します。
これにより、各要素の開始位置を計算しやすくなるとともに、効率的なパーシングが可能になります。

##### Merkle化との連携

SSZのもう1つの大きな特徴は、シリアライズ結果を32バイト単位に分割し、それぞれをリーフとしてMerkleツリーを構築できる点です。
これにより、あるフィールドだけの存在証明（Merkleプルーフ）が容易に生成でき、検証時にはツリー構造を辿るだけでデータの真偽を確かめられます。

### Ethereumでの利用例

Beacon Chainではブロックヘッダーやステートルート、クロスリンク情報などをSSZ形式でネットワーク伝播し、各ノードが同一のバイナリ表現を用いて整合性を保ちます。
また、シャーディング計画でもセグメントごとのデータをSSZでやり取りし、効率的なデータブロックの取得と検証を実現しています。
:::

## 補足

この手法は、従来の状態期限切れ提案と比べて構造の単純さを追求しています。
アドレス空間の拡張を必要とせず、エポックごとに複数のツリーを用意することもなく、1つのツリー構造のまま古いデータだけを削除します。
削除対象となるのはコールドデータのみで、アクセス頻度の高いホットデータは常時保持されるため、ユーザー体験を損なわずに運用できます。
復活証明も、削除されたノードのデータをそのまま提出するだけで済み、証明サイズが小さくガスコストが明確になる点も大きなメリットです。
エポックカウンタの増分処理は各エポック開始時に一度だけ実行されるため、その費用は短期間で十分に平準化されます。

## 互換性

**EIP7736**は既存のVerkleツリー仕様との互換性を損なわないよう設計されています。
**EIP6800**で定められた評価点のデフォルト値（第四評価点）が初期エポックカウンタと同じ0となっているため、フォーク前後にかかわらず従来のクライアントは特別な対応なしに動作します。
フォーク後は段階的に更新エポック機能を取り込むことで、ノードソフトウェアの改修を最小限に抑えつつ新機能を利用できるようになっています。

:::message
**EIP6800**については以下の記事を参考にしてください。
:::

[\[EIP6800\] Verkleツリーで証明サイズを削減する仕組みを理解しよう！](/articles/1d12fe71f82f7d8dbd67)

## 引用

Guillaume Ballet (@gballet), Wei Han Ng (@weiihann), "EIP-7736: Leaf-level state expiry in verkle trees [DRAFT]," Ethereum Improvement Proposals, no. 7736, July 2024. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-7736.

## 最後に

今回は「EthereumノードにVerkleツリーの拡張ノードにエポック管理を導入して、古いステートデータを自動的に期限切れ削除し、必要な時に簡易な証明で再度データにアクセスする仕組みを提案している**EIP7736**」についてまとめてきました！
いかがだったでしょうか？

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

[Twitter @cardene777](https://twitter.com/cardene777)

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

https://chaldene.net/

https://zenn.dev/heku

https://cardene.substack.com/

https://mirror.xyz/0xcE77b9fCd390847627c84359fC1Bc02fC78f0e58

https://cardene.notion.site/ERC-EIP-2a03fa3ea33d43baa9ed82288f98d4a9?pvs=4
