# [EIP8163] Ethereum L1では使わない拡張用オペコードを予約する仕組みを理解しよう！

> EIP8163は、0xaeという1バイトのオペコードをEXTENSIONとして予約する提案です。Ethereum L1では、このEXTENSIONを有効な命令にしません。

- URL: https://cardene.dev/articles/55dee734e8417e03fa3d
- 公開日: 2026-05-26
- 更新日: 2026-05-26
- トピック: Blockchain
- タグ: eip, evm, ブロックチェーン, opcode

## はじめに

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

https://amzn.asia/d/gxvJ0Pw

以下でも情報発信しているので、興味ある記事があればぜひ読んでみてください！

https://cardene.notion.site/EIP-2a03fa3ea33d43baa9ed82288f98d4a9

https://twitter.com/cardene777

https://zenn.dev/heku

https://cardene.substack.com/

https://mirror.xyz/0xcE77b9fCd390847627c84359fC1Bc02fC78f0e58

今回は、Ethereum L1では実行できないままにして、L2や独自EVMチェーンが拡張命令の目印として使える`EXTENSION (0xae)`を予約する「**EIP8163**」についてまとめていきます。

:::message
以下にまとめられているものを解説しながらまとめていきます。
:::

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

**EIP8163**は、Ethereum L1のEVMには新しい実行機能を足さず、他のEVMが独自拡張を入れるための「**ぶつからない目印**」だけを用意する提案です。
要点は、Ethereum L1では`0xae`を`INVALID (0xfe)`と同じように失敗させる一方で、非L1のEVMではその後ろのバイト列を使って独自命令を表現できるようにする点です。

## 概要

**EIP8163**は、`0xae`という1バイトのオペコードを`EXTENSION`として予約する提案です。
Ethereum L1では、この`EXTENSION`を有効な命令にしません。
実行された場合は`INVALID (0xfe)`と同じように例外停止し、現在の実行フレームを終了し、残りのガスを消費します。

一方で、Ethereum L1以外のEVMチェーンでは、`0xae`を「**ここから独自拡張命令が始まる**」というプレフィックスとして使えます。
例えば、あるL2が新しい計算命令を試したい時、既存のEthereum L1オペコードと衝突しない場所として`0xae`から始まる命令空間を使えるようになります。

この提案の狙いは、EVMの互換性を保ちながら、Ethereum L1以外のチェーンがEVM内で実験しやすくすることです。
独自チェーンが勝手に空いているオペコードを使うと、後からEthereum L1が同じ番号を別の意味で採用した時に互換性が崩れます。
**EIP8163**は、Ethereum L1が`0xae`を今後も有効命令として使わないと決めることで、非L1 EVMが安心して拡張用の名前空間として扱えるようにします。

:::message
**オペコードとは**

EVMが実行する命令を表す1バイトの値です。
例えば、`ADD`や`PUSH1`のような命令にも番号が割り当てられており、スマートコントラクトのバイトコードはこの命令列として実行されます。
`EXTENSION (0xae)`は、その命令列の中で拡張命令の始まりを示すために予約される値です。
:::

全体像は以下の図です。

![EIP8163の全体像](/images/qiita-00169836-c324-4192-834c-4d2dd89def31.webp)

図の左側は、同じ`0xae`を含むバイトコードでも実行環境によって扱いが分かれることを示しています。
Ethereum L1では失敗する命令として固定されます。
非L1のEVMでは拡張命令の起点として使えますが、ジャンプ可能な場所の判定はEthereum L1と同じ結果でなければなりません。

## 動機

現在のEVM互換チェーンは、EthereumのEVMと互換性を保つことで、既存のツール、開発者体験、スマートコントラクト資産を利用できます。
しかし、EVM互換性を保とうとすると、新しい命令を自由に追加しにくくなります。

未使用のオペコードを独自に使うこと自体はできます。
ただし、その番号が将来Ethereum L1で別の用途に割り当てられると、同じバイトコードがチェーンごとに別の意味を持つようになります。
同じ番号に複数の意味が生まれると、コントラクトの移植性、監査、トレース、デバッグのすべてが難しくなります。

未使用オペコードをそのまま使う場合と、`0xae`を予約する場合の違いは以下の図です。

![未使用オペコード衝突と予約済み0xaeの違い](/images/qiita-296c038b-f52b-40fa-9b35-a84f2dd8148a.webp)

左側は、独自チェーンが空き番号を使った後にEthereum L1が同じ番号を採用し、同じバイトコードが別の意味を持つ流れです。
右側は、Ethereum L1では`0xae`を`INVALID`扱いに固定し、非L1では拡張命令の目印として使う流れです。
この分離によって、非L1 EVMはEthereum L1との衝突を避けながら実験できます。

#### 非L1 EVMの実験余地

Ethereum L1以外のEVMチェーンは、実行環境を特化させることで新しい命令や処理モデルを試せます。
例えば、あるL2が特定の暗号処理を安くしたい場合や、アプリケーション特化チェーンが専用命令を追加したい場合があります。

その時に課題になるのは、どのオペコード番号を使うかです。
空いている番号を自由に使うだけでは、後からEthereum L1や他のEVMチェーンと衝突する可能性があります。
**EIP8163**は、`0xae`をEthereum L1では永久に有効命令にしないことで、非L1 EVMが拡張命令の共通プレフィックスとして使える余地を作ります。

#### Ethereum L1への影響を増やさない設計

**EIP8163**は、Ethereum L1の実行レイヤークライアントにコンセンサス上の変更を求めません。
`0xae`は現在も有効な命令ではないため、実行すると例外停止します。
提案が定めるのは、将来もこの挙動を変えず、拡張命令としてEthereum L1に導入しないという約束です。

この設計により、Ethereum L1の安全性や既存コントラクトの挙動を変えずに、EVMエコシステム全体の実験余地を広げられます。
非L1チェーンで成功した拡張があれば、将来的に別のEIPでEthereum L1へ持ち込むこともできます。
その場合でも、`0xae`をそのままL1の多バイト命令プレフィックスにはせず、別のオペコードとして提案する前提です。

## 仕様

仕様は、Ethereum L1での`EXTENSION`の扱い、非L1 EVMでの扱い、そして`JUMPDEST`解析を変えない制約に分かれます。
`EXTENSION`自体は新しいL1機能ではなく、L1では`INVALID`と同じ失敗動作をする予約済みの値です。

#### `EXTENSION (0xae)`

`EXTENSION`は`0xae`に割り当てられます。
Ethereum Mainnetやテストネットなど、すべてのEthereum L1チェーンでは`INVALID (0xfe)`と同じように動作する必要があります。

**EIP141**は、`INVALID (0xfe)`を実行した時に例外停止する無効命令として定義した提案です。

:::message
[EIP141] INVALIDオペコードの仕組みについて理解しよう！
:::

[\[EIP141\] INVALIDオペコードの仕組みについて理解しよう！](/articles/69c29ecc0e93cc741f05)

Ethereum L1での`EXTENSION`の要件は以下です。

| 項目 | 内容 |
|------|------|
| オペコード | `0xae` |
| 名前 | `EXTENSION` |
| Ethereum L1での実行結果 | `INVALID (0xfe)`と同じく例外停止し、現在の実行フレームを終了して残りのガスを消費する。 |
| `JUMPDEST`解析への影響 | 影響してはならず、`0xae`があってもジャンプ先として有効な位置の判定は変わらない。 |
| 静的解析や事前処理への影響 | `INVALID`と同じ扱いを超えて、追加の影響を与えてはならない。 |

ここで重要なのは、`0xae`を「**将来のL1命令候補として予約する**」のではなく、「**L1では有効命令にしない拡張用の印として予約する**」点です。
そのため、Ethereum L1のスマートコントラクトが`0xae`を実行できるようになるわけではありません。

#### 非L1 EVMでの扱い

Ethereum L1以外のEVMでは、`EXTENSION`に意味のある実行動作を与えられます。
ただし、どのような動作にするかは各EVM実装が決めます。
**EIP8163**は、拡張命令そのもののエンコード方式や命令一覧までは定義しません。

非L1 EVMが`EXTENSION`を実行する場合、後続のバイト列を即値引数として使い、拡張命令の意味を決める必要があります。
例えば、`0xae 0x01`をある拡張命令、`0xae 0x02`を別の拡張命令として解釈するような設計が考えられます。

ただし、後続の即値引数に`JUMPDEST (0x5b)`が含まれ、それがジャンプ先として有効なまま残る場合は、実行は例外停止する必要があります。
これは、Ethereum L1と非L1 EVMで`JUMPDEST`解析の結果がずれないようにするためです。

#### `JUMPDEST`解析

EVMでは、`JUMP`や`JUMPI`で移動できる先が`JUMPDEST (0x5b)`の位置に限定されています。
そのため、バイトコード中のどの`0x5b`が有効なジャンプ先かを事前に解析する必要があります。

もし非L1 EVMが`EXTENSION`の後続バイトを自由に隠してしまうと、同じバイトコードでもEthereum L1と非L1 EVMで有効なジャンプ先が変わる可能性があります。
これが起きると、コードの移植性が失われます。
そこで**EIP8163**は、`EXTENSION`があっても`JUMPDEST`解析の結果をEthereum L1と一致させることを強く求めています。

処理の考え方は以下です。

1. **Ethereum L1では`0xae`を`INVALID`として読む**
    `0xae`の後ろにあるバイトは、通常のEVMバイトコードとして解析されます。
2. **非L1 EVMでは`0xae`を拡張命令の始まりとして読める**
    ただし、後続バイトの扱いによって有効な`JUMPDEST`の集合を変えてはいけません。
3. **有効な`JUMPDEST`が即値引数に残る場合は例外停止する**
    拡張命令として実行するとジャンプ解析がずれるバイト列は、拡張命令として成立しません。

`0x5b`が命令として読まれる場合と、`PUSH`命令のデータとして読まれる場合の違いは以下の図です。

![JUMPDEST解析とPUSHデータの違い](/images/qiita-dcc33282-94a2-43cd-8a43-71ae492fa5d3.webp)

上段の`0xae 5b`では、`5b`が命令としての`JUMPDEST`です。
この場合、拡張命令の即値引数に有効なジャンプ先が残るため、拡張命令としては無効です。
一方、`0xae 60 5b`や`0xae 61 60 5b`では、`5b`が`PUSH1`または`PUSH2`のデータとして扱われます。
この場合、`5b`はジャンプ先ではないため、Ethereum L1と同じ解析結果を保てます。

#### バイト列の例

提案では、`0xae`の後ろに来るバイト列と`JUMPDEST`解析の関係を例で示しています。
日本語で整理すると以下です。

| バイト列 | `JUMPDEST`の扱い | 拡張命令としての扱い |
|----------|------------------|----------------------|
| `0xae5b...` | `0x5b`は有効な`JUMPDEST`です。 | 即値引数に有効な`JUMPDEST`が残るため、拡張命令としては無効です。 |
| `0xae015b...` | `0x5b`は有効な`JUMPDEST`です。 | `0x01`を引数とする拡張命令として有効にできます。 |
| `0xae60` | 判定対象になる後続データが足りません。 | `PUSH1`の即値が足りないため無効です。 |
| `0xae605b...` | `0x5b`は`PUSH1`のデータで、ジャンプ先ではありません。 | `PUSH1`のデータとして`0x5b`を渡す拡張命令として有効にできます。 |
| `0xae60605b...` | 最後の`0x5b`は有効な`JUMPDEST`です。 | `PUSH1`で`0x60`を引数にする拡張命令として有効にできます。 |
| `0xae61605b...` | `0x5b`は`PUSH2`のデータで、ジャンプ先ではありません。 | `PUSH2`で`0x605b`を引数にする拡張命令として有効にできます。 |
| `0xae615b` | `PUSH2`のデータが足りません。 | 命令が途中で切れているため無効です。 |

この表のポイントは、`0x5b`が「**命令としてのJUMPDEST**」なのか、「**PUSH命令のデータの一部**」なのかで扱いが変わることです。
EVMの既存ルールでは、`PUSH1`から`PUSH32`の直後にあるデータは命令として解釈されません。
そのため、`0xae605b...`の`0x5b`は`PUSH1`の即値データとして扱われ、ジャンプ先にはなりません。

## 設計根拠

#### `JUMPDEST`解析を変えない理由

別案として、`EXTENSION`の後ろにある`0x5b`をジャンプ先として無効化したり、`PUSHx`命令を飛ばして即値引数のサイズを決めたりする設計も考えられました。
しかし、この方法では`EXTENSION`の即値引数のサイズを**EIP8163**側で決める必要があります。

また、将来別のEIPで即値引数を持つオペコードが導入された場合に、解析ルールが衝突する可能性もあります。
さらに、同じバイトコードをEthereum L1と非L1 EVMで解析した時、有効なジャンプ先が異なると、コードの移植性が下がります。

そのため、この提案では`EXTENSION`が`JUMPDEST`解析に影響しない設計を採用しています。
`0xae5b`のように`0x5b`が有効なジャンプ先として残るバイト列は、拡張命令としては無効です。
一方、`0xae605b`のように`0x5b`が`PUSH1`のデータとして扱われる場合は、ジャンプ解析を変えずに即値引数として使えます。

#### エンコード方式を定義しない理由

**EIP8163**は、`EXTENSION`の後ろをどうエンコードするかまでは定めません。
この提案の範囲は、拡張命令のための安全なプレフィックスを予約することに絞られています。

もし具体的なエンコード方式まで決めると、非L1 EVMの実験余地が狭くなります。
また、拡張命令の形式や命令一覧は、それ自体が独立した議論になります。
そのため、必要であれば別の提案で議論する形になっています。

#### Ethereum L1で多バイト命令を使わない理由

`EXTENSION`は、Ethereum L1で多バイト命令を作るための仕組みではありません。
提案では、Ethereum L1 EVMが`EXTENSION`を使って多バイト命令をサポートすることを明確に禁止しています。

将来Ethereum L1に同じ機能を取り込みたい場合は、`0xae`プレフィックスをそのまま使うのではなく、別のEIPで別のオペコードを選ぶ形になります。
これにより、非L1 EVMでの実験とEthereum L1の仕様進化を切り分けられます。

#### L1への取り込み方

非L1 EVMで`EXTENSION`を使った機能が成功し、Ethereum L1にも取り込みたい場合があります。
その時は、別のEIPで専用のオペコードを選び、L1向けの仕様として提案します。

元の非L1 EVMがそのL1向けEIPも採用した場合、そのEVMでは同じ機能にアクセスする方法が2つ残ります。
1つは`EXTENSION`を使った独自拡張命令で、もう1つはEthereum L1と共通の新しいオペコードです。
この二重経路を許容することで、既存の非L1向けコードを壊さずに、L1側へ機能を持ち込めます。

非L1で成功した拡張機能をEthereum L1へ取り込む時の流れは以下です。

![非L1拡張からEthereum L1採用までの流れ](/images/qiita-ec8cf3ee-be8c-4da4-ad13-326fa8e828e2.webp)

`EXTENSION`は非L1での実験用の経路です。
成功した機能をEthereum L1へ持ち込む時は、別EIPでL1向けに議論し、L1では別オペコードとして採用します。
元の非L1 EVMがL1側の新オペコードも採用すると、`0xae`経由とL1共通オペコード経由の2つが残ります。

## 互換性

`EXTENSION (0xae)`は、現在のEthereumでは有効な命令ではありません。
そのため、既存のEthereum L1コントラクトが`0xae`を実行しても、今までどおり無効命令として失敗します。

また、`0xae`は`JUMPDEST`解析に影響しないため、既存バイトコードのジャンプ先判定も変わりません。
この提案は、Ethereum L1に新しい実行動作を追加するのではなく、将来も`0xae`をL1の有効命令にしないことを決めるものです。

## テストケース

提案では、テストケースはEthereum Execution Layer Specs形式で提供予定とされています。
現時点で具体的なテストコードは含まれていません。

テストで確認すべき中心は、Ethereum L1で`0xae`が`INVALID`と同じように例外停止することと、`0xae`を含むバイトコードでも`JUMPDEST`解析の結果が変わらないことです。
非L1 EVMで`EXTENSION`を実装する場合は、即値引数に有効な`JUMPDEST`が残るバイト列を拡張命令として認めないことも確認対象になります。

## 参考実装

提案では、参考実装はありません。
Ethereum L1の実行レイヤークライアントのコンセンサス動作は変わらないためです。

実装上の変更があるとしても、トレースや表示など、コンセンサスに関係しない見せ方の部分に限られます。
例えば、ディスアセンブラやデバッグツールが`0xae`を`EXTENSION`という名前で表示するかどうかは、実行結果には影響しません。

## セキュリティ

Ethereum L1では、`EXTENSION`は`INVALID`と同じ扱いです。
そのため、Ethereum L1の実行レイヤークライアントに新しいコンセンサス上のリスクは追加されません。

一方で、非L1 EVMが`EXTENSION`を実装する場合は注意が必要です。
特に、拡張命令の即値引数によって`JUMPDEST`解析がEthereum L1とずれると、同じバイトコードの制御フローがチェーンごとに変わります。
このずれは、監査や移植、ツールによる解析を難しくします。

解析がずれる時のリスクは以下の図です。

![JUMPDEST解析がずれる時のリスク](/images/qiita-8e85b6a1-4d50-424d-bf6b-5bb7a1641ebe.webp)

同じバイトコードでも、Ethereum L1と非L1 EVMで有効な`JUMPDEST`の集合が変わると、ジャンプできる場所が変わります。
ジャンプできる場所が変わると、実行される経路も変わるため、監査結果や移植時の前提が合わなくなります。
そのため、非L1 EVMで`EXTENSION`を実装する場合でも、`JUMPDEST`解析はEthereum L1と同じ結果に保つ必要があります。

また、各EVM実装が独自に拡張命令を増やしすぎると、EVM互換と呼ばれる範囲が読みにくくなります。
提案では、非L1 EVMの実装者がEIPの議論スレッドで具体的な`EXTENSION`の使い方を調整することを推奨しています。
同じ`0xae`プレフィックスを使う以上、命令空間の衝突を避けるための調整が重要です。

## 引用

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

https://ethereum-magicians.org/t/eip-8163-reserve-0xae-extension-opcode/27756

## 最後に

今回は「**EIP8163**」についてまとめてきました。

**EIP8163**は、Ethereum L1で新しい命令を増やす提案ではありません。
むしろ、`0xae`をL1では使わない値として固定し、L2や独自EVMチェーンが安全に拡張命令を試せる場所を作る提案です。

重要なのは、Ethereum L1の挙動を変えないことと、`JUMPDEST`解析を変えないことです。
この2つを守ることで、非L1 EVMは実験しやすくなり、同時にEVMバイトコードの移植性や解析可能性も保ちやすくなります。

他でも色々記事を書いているのでぜひよろしければ読んでいってください！

https://amzn.asia/d/gxvJ0Pw

https://cardene.notion.site/EIP-2a03fa3ea33d43baa9ed82288f98d4a9

https://zenn.dev/heku

https://mirror.xyz/0xcE77b9fCd390847627c84359fC1Bc02fC78f0e58

https://twitter.com/cardene777

https://cardene.substack.com/
