# [ERC8002] Bitcoinの取引をEthereumで検証するSPVゲートウェイ提案を理解しよう

> ERC8002は、Bitcoin上の取引をEthereumで検証するためのISPVGatewayインターフェースを定めた提案です。ドラフトのためデプロイ先アドレスはプレースホルダのままです。

- URL: https://cardene.dev/articles/fda1814f9999129ed25e
- 公開日: 2026-04-12
- 更新日: 2026-04-12
- トピック: Blockchain
- タグ: blockchain, ethereum, solidity, smartcontract

## はじめに

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

https://amzn.asia/d/gxvJ0Pw

今回は、BitcoinのブロックヘッダをEthereum上に載せ、Merkle証明で取引の包含を検証する**SPVゲートウェイ**を定めた**ERC8002**についてまとめていきます！

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

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

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

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

https://twitter.com/cardene777

https://zenn.dev/heku

https://cardene.substack.com/

https://mirror.xyz/0xcE77b9fCd390847627c84359fC1Bc02fC78f0e58

## 概要

ERC8002は、Bitcoin上の取引をEthereumで検証するための`ISPVGateway`インターフェースを定めた提案です。
ドラフトのためデプロイ先アドレスはプレースホルダのままです。

#### 要点の整理

提案の骨格は、誰でも有効なBitcoinブロックヘッダをオンチェーンに積み上げ、累積仕事量でメインチェーンを追い、Merkle証明で「この`txId`がそのブロックに含まれたか」を`checkTxInclusion`に問い合わせられる点にあります。
ウォレットやオフチェーンのヘルパがヘッダを送り、消費側のプロトコルが確認数のしきい値を自分で決めます。

| 項目 | 内容 |
|------|------|
| 正式名称 | Simplified Payment Verification Gateway |
| ステータス | Draft |
| コアコントラクト | シングルトン`SPVGateway`（`ISPVGateway`を実装） |
| 入力 | 誰でも有効なBitcoinブロックヘッダ（80バイト）を`addBlockHeader`で追加 |
| メインチェーン | 累積PoWが最大となる枝として先端を更新 |
| 取引の検証 | `txId`・Merkle証明・`blockHash`などから`checkTxInclusion`で包含を確認 |

:::message
**Simplified Payment Verification**（SPV）

フルノードのように全取引を保持せず、ブロックヘッダとMerkle証明だけで支払の存在を確認する、Bitcoinの軽量クライアント向けの考え方です。
**ERC8002**は、その検証ロジックをEthereum上のコントラクトとして共有するためのゲートウェイです。
:::

#### シングルトンとしての狙い

この提案では、Bitcoin上の取引をオンチェーンで検証するシングルトンを導入し、その提出先アドレスは現時点でプレースホルダです。
信頼不要なSPVゲートウェイとして、誰でもBitcoinブロックヘッダを提出でき、メインチェーンを保持しつつMerkle証明で取引の存在を検証できます。

#### 全体像

以下の図は、Bitcoin側からブロックヘッダが提出され、Ethereum上のプロトコルが`checkTxInclusion`などで検証に使う流れを示しています。

![erc8002-spv-overview.png](/images/qiita-e8702977-17fc-4bb3-8e65-a769574eee18.webp)

## 動機

#### 背景

提案の動機では、Ethereumのスマートコントラクトによる分散化・信頼不要・プログラマブルな価値の実現に加え、DeFiの再興、RWAやプライバシー系プロトコルなどの成果が挙がる、と書かれています。
一方、Bitcoinはプログラマビリティが極めて限定的です。
そのため信頼不要な範囲では保有と送受信に留まりやすく、EthereumのDeFiにネイティブなBTCを直接組み込みにくい、という課題が出てきます。

#### 想定されるユースケース

この提案は、その制約を埋め合わせる基盤を置くことを狙いとします。
**ネイティブBTCを担保にステーブルコインを借りる**といったユースケースを既に可能にする、と書いてあります。
さらにBitVMなどの進展と組み合わせると、オーナー不在の二方向ブリッジや、ラップなしのBTC発行をEthereum上で目指せる、といった展望にも触れています。

## 仕様

提案では、まず**ビットコインのブロックヘッダ・難易度・検証・Merkle・メインチェーン**といった前提を書き、そのうえで**Ethereum上のシングルトン** `SPVGateway` が実装する`ISPVGateway`のイベント・関数を定めます。
以下はその順に沿った整理です。

#### Bitcoinブロックヘッダの構造

各ブロックのヘッダは固定長80バイトのフィールドで構成され、提案の表では以下のように定めています。

| フィールド名 | サイズ | バイト順 | 説明 |
|-------------|--------|----------|------|
| Version | 4バイト | リトルエンディアン | ブロックのバージョン番号 |
| Previous Block | 32バイト | natural byte order | このブロックが接続する先のブロックのハッシュ |
| Merkle Root | 32バイト | natural byte order | ブロック内に含まれる取引の指紋（Merkle Treeのルート） |
| Time | 4バイト | リトルエンディアン | Unix時刻のタイムスタンプ |
| Bits | 4バイト | リトルエンディアン | 難易度の目標（target）の圧縮表現 |
| Nonce | 4バイト | リトルエンディアン | マイニングで探索する32ビット値 |

フィールドの並びは上表の順序に従います。

バイト境界は以下のように連なります（合計80バイト）。

```mermaid
flowchart LR
  V["Version<br/>4B LE"]
  P["Previous<br/>32B"]
  M["Merkle Root<br/>32B"]
  T["Time<br/>4B LE"]
  B["Bits<br/>4B LE"]
  N["Nonce<br/>4B LE"]
  V --> P --> M --> T --> B --> N
```

:::message
**バイト順**（LEとnatural byte order）

図中の「LE」は**リトルエンディアン**の略です。**Version**・**Time**・**Bits**・**Nonce**のように幅が4バイトのフィールドは、いずれも**数値**として解釈され、そのとき下位バイトから先に並べるのがBitcoinのブロックヘッダの慣習です。

一方、**Previous Block**と**Merkle Root**はそれぞれ32バイトの**ハッシュ値**です。4バイト整数のようにエンディアンを反転して並べるのではなく、SHA256などが出力した**バイト列を先頭からそのまま**ヘッダに載せる扱いになります。表の「natural byte order」は、この「ハッシュの生のバイト順をいじらない」ことを指しています。
:::

#### 難易度調整

BitcoinのPoWは確率的なファイナリティに依拠するため、動的な難易度目標を更新します。
提案では、目標の初期値が`0x00000000ffff0000000000000000000000000000000000000000000000000000`に設定され、これが**最小難易度のしきい値**も兼ねる、と書いてあります。

`target`は約2016ブロックごとに再計算され、この区間は**難易度調整期間**と呼ばれます。
そこで期待される期間の長さは、2016ブロック×10分ブロックとし、秒に換算すると**1,209,600秒**です。
新しい`target`は、現在の`target`に、直前の2016ブロックを採掘するのに実際にかかった時間と、その期待時間（1,209,600秒）の比を掛けた値として求められます。
急激な変動を防ぐため、この比にかかる倍率は**最大で4倍**、**最小で1/4倍**に**クランプ**されます。

以上の流れを以下の図にまとめました。

```mermaid
flowchart TD
  A[約2016ブロック分<br/>難易度調整期間] --> B[実際の経過時間を計測]
  B --> C[期待時間 1,209,600秒との比で<br/>targetを更新]
  C --> D[倍率に上限<br/>最大4倍・最小1/4倍]
```

指数や係数の丸め方など、更新の細部は提案に定めています。

#### ブロックヘッダの検証ルール

有効なヘッダとしてチェーンに採用されるには、**Chain Cohesion**（チェーンの連結）、**Timestamp Rules**（時刻のルール）、**PoW Constraint**（PoWの制約）の3つに合致する必要がある、と提案では整理しています。

その関係を図にすると以下のとおりです。続く番号付きリストで、それぞれのルールの中身を掘り下げます。

![ブロックヘッダが満たす3条件（概念図）](/images/qiita-fd46da5a-da45-4f14-b4c4-403fc94a17bf.webp)

3つの検証はいずれも満たさなければ以降の統合処理に進めません。
以下はその中身です。

1. **Chain Cohesion**
    `Previous Block`のハッシュは、既存のヘッダ集合の中に存在する有効なブロックを指す必要があります。

2. **Timestamp Rules**
    `Time`は直前11ブロックのMedian Time Past（MTP、中央時刻）より大きくなければなりません。
    また`Time`は、検証ノードのネットワーク調整時刻から見て**2時間より未来**を示してはなりません。

3. **PoW Constraint**
    ヘッダに対してSHA256を2回適用した結果が、難易度調整から得られる現在の`target`以下である必要があります。

#### 取引のMerkle Treeと包含検証

各ブロックヘッダの`Merkle Root`は、そのブロックに含まれる取引のMerkle Treeのルートです。
葉は生の取引バイト列の二重SHA256、隣接ノードがない場合は自分自身とペアにして再帰的にハッシュ化する、という構築方法が提案に書いてあります。

取引の包含を検証するには、Merkle証明と`txId`などからMerkle Treeのルートを再構築し、ヘッダに保存された`Merkle Root`と一致するか比較する必要があります。Merkleパスとハッシュ方向のビットは、Bitcoinフルノードへの問い合わせで取得できる、と書かれています。

実際のTreeは取引数に応じて深さが変わり、奇数のときは葉が自分自身とペアになる、といった提案上のルールがあります。
葉からルートへハッシュが集約される様子は以下の図のとおりです。

```mermaid
flowchart BT
  R[Merkleルート]
  H12[H12]
  H34[H34]
  T1[tx1 hash]
  T2[tx2 hash]
  T3[tx3 hash]
  T4[tx4 hash]
  T1 --> H12
  T2 --> H12
  T3 --> H34
  T4 --> H34
  H12 --> R
  H34 --> R
```

#### メインチェーンと累積PoW

Bitcoinのメインチェーンは、単に長いチェーンではなく、**累積PoWが最大となる枝**です。

1ブロックの仕事量は`target`に反比例し、提案では`(2**256 - 1) / (target + 1)`として表されます。
`target`は`Bits`フィールドから導かれ、先頭1バイトが左シフト量、残り3バイトが実際の`target`値を表す、と書いてあります。

数値のイメージを掴むと分かりやすいので、Bitcoinと同様の圧縮表現として以下のように整理できます。

- `Bits`は4バイト（リトルエンディアン）。これを32ビット整数として読むと、**上位1バイトが指数（左シフト量に相当）、下位3バイトが係数**（実際の`target`を組み立てる値）を表す、という対応です。
- 例として、ワイヤ上の4バイトが `ff ff 00 1d`（LE）のとき、整数としては `0x1d00ffff` と解釈され、指数 `0x1d`、係数 `0x00ffff` から `target = 0x00ffff × 2^(8×(0x1d−3))` のように256ビットの`target`へ展開される、というイメージです。

チェーン全体の累積仕事量は、チェーン上の各ブロックの仕事量の和であり、累積PoWが最大となる枝に属するブロックがメインチェーン上にあります。

分岐があったときに「長さ」ではなく累積PoWで枝を比べるイメージです。

![メインチェーンの選び方（累積PoW）](/images/qiita-57007bac-3e8c-4052-91a9-9e237f532086.webp)

実際のノードはより多くの分岐を扱いますが、選ぶ基準は「累積PoWが最大の枝」である点がポイントです。

#### `SPVGateway`の初期化に関する必須要件

`SPVGateway`は、**パーミッションレスな初期化**を提供しなければなりません。
この仕組みは、**有効なBitcoinブロックヘッダ**、**対応するブロック高さ**、**そのブロックまでの累積PoW**を、特別な権限なしに提出できることを許可しなければなりません。

誰でも起点となる状態を載せられる、という関係を図示します。

```mermaid
flowchart LR
  U[任意のアクター]
  U --> X[有効ヘッダ・高さ・<br/>累積PoWを提出]
  X --> G[SPVGateway<br/>初期状態の確立]
```

管理者キーでロックするのではなく、誰でも起点データを載せられる設計であることが、この提案の前提です。

#### `ISPVGateway`インターフェース

以下は提案に掲載されている`ISPVGateway`の各要素です。
**シグネチャ**の直後に、構造体・イベント・関数ごとに**表**で引数・戻り値（またはフィールド）を示します。

提出系の関数が状態を更新し、参照系の関数と`checkTxInclusion`がその状態を読む、という役割分担を以下に示します。

![ISPVGatewayの役割（書き込みと読み取り）](/images/qiita-264a2487-cda4-4fe0-98b1-db3c338c1d42.webp)

イベントの発火条件は、各関数の節で書いてあるとおりです。
読み取り系は状態を変えず、`checkTxInclusion`だけが包含検証という重い読み取りを担います。

##### `BlockHeaderData`

Bitcoinブロックヘッダをコントラクト内で扱うための構造体です。
提案では、すべてのフィールドを**ビッグエンディアン**に変換して内部表現とし、EVMの効率を優先します（Bitcoinの整数フィールドのリトルエンディアンとは向きが異なります）。

```javascript
struct BlockHeaderData {
    bytes32 prevBlockHash;
    bytes32 merkleRoot;
    uint32 version;
    uint32 time;
    uint32 nonce;
    bytes4 bits;
}
```

| フィールド | 型 | 説明 |
|------------|-----|------|
| `prevBlockHash` | `bytes32` | 前ブロックのハッシュ。 |
| `merkleRoot` | `bytes32` | ブロック内取引のMerkleルート。 |
| `version` | `uint32` | ブロックバージョン。 |
| `time` | `uint32` | タイムスタンプ。 |
| `nonce` | `uint32` | マイニング用のnonce。 |
| `bits` | `bytes4` | 難易度の圧縮表現。 |

##### `MainchainHeadUpdated`

メインチェーンの先端が変わった時に発火するイベントです。
`addBlockHeader`や`addBlockHeaderBatch`などで更新が起きる場合に必ずemitする、と定めています。

```javascript
event MainchainHeadUpdated(
    uint64 indexed newMainchainHeight,
    bytes32 indexed newMainchainHead
);
```

| 引数 | 説明 |
|------|------|
| `newMainchainHeight` | 新しいメインチェーン先端の高さ。 |
| `newMainchainHead` | 新しいメインチェーン先端のブロックハッシュ。 |

##### `BlockHeaderAdded`

新しいブロックヘッダがコントラクト上の状態に追加された時に発火するイベントです。
`addBlockHeader`や`addBlockHeaderBatch`などで追加が発生した場合に必ずemitする、と定めています。

```javascript
event BlockHeaderAdded(uint64 indexed blockHeight, bytes32 blockHash);
```

| 引数 | 説明 |
|------|------|
| `blockHeight` | 追加されたブロックの高さ。 |
| `blockHash` | 追加されたブロックのハッシュ。 |

##### `addBlockHeader`

生の80バイトのブロックヘッダを1つ追加する関数です。
追加前に検証が行われます。

```javascript
function addBlockHeader(bytes calldata blockHeaderRaw) external
```

| 区分 | 名前 | 型 | 説明 |
|------|------|-----|------|
| 引数 | `blockHeaderRaw` | `bytes calldata` | 生のブロックヘッダバイト列（80バイトであること）。 |
| 戻り値 | — | — | 提案のインターフェース上、戻り値の明示はありません。 |

提案では、`addBlockHeader`は以下の処理を**必ず**実行しなければなりません（提案本文の列挙順に合わせています）。

1. **PoW Constraint**: ヘッダに対してSHA256を2回適用した結果が、難易度調整から得られる現在の`target`以下であることを検証する（「ブロックヘッダの検証ルール」の**3. PoW Constraint**と同じ内容）。
2. 提出された生ヘッダの長さが**80バイト**であることを検証する。
3. 「ブロックヘッダの検証ルール」に書かれた**Chain Cohesion**と**Timestamp Rules**を検証する。
4. 新しいヘッダを既知のチェーンに統合する際に、累積PoWを計算し、「メインチェーンと累積PoW」に従ってリオーガナイゼーションを含めて管理する。
5. 追加に成功したら`BlockHeaderAdded`をemitする。
6. メインチェーンが更新されたら`MainchainHeadUpdated`をemitする。

上記の手順の流れを図にしたものです。

```mermaid
flowchart TD
  IN[生ヘッダ] --> V[PoW・80バイト・<br/>Chain/Timeの検証]
  V -->|失敗| X[拒否]
  V -->|成功| P[累積PoW更新と<br/>リオーグ処理]
  P --> E1[BlockHeaderAddedをemit]
  P --> H{先端が変わったか}
  H -->|はい| E2[MainchainHeadUpdatedをemit]
  H -->|いいえ| OK[完了]
  E2 --> OK
```

検証のどこかで失敗した場合は、以降の統合処理に進みません。
先端が変わらない追従だけなら`MainchainHeadUpdated`は不要、という整理です。

##### `addBlockHeaderBatch`

複数のブロックヘッダを順に追加する**オプション**の関数です。
各ヘッダは検証と追加が順番に行われます。

```javascript
function addBlockHeaderBatch(bytes[] calldata blockHeaderRawArray) external
```

| 区分 | 名前 | 型 | 説明 |
|------|------|-----|------|
| 引数 | `blockHeaderRawArray` | `bytes[] calldata` | 生ヘッダの配列。 |
| 戻り値 | — | — | 提案のインターフェース上、戻り値の明示はありません。 |

提案の**Rationale**（設計根拠）では、**11ブロックを超えるバッチ**では、MTP（中央時刻）の計算に`calldata`上のタイムスタンプを使えるため、ストレージ読み込みが減り、ガスとトランザクションコストを大きく下げられる、と書いてあります。

##### `checkTxInclusion`

指定した`txId`が、指定したブロックのMerkle Treeに含まれ、かつそのブロックがメインチェーン上にあり、かつ十分な確認数があるかを検査するview関数です。

```javascript
function checkTxInclusion(
    bytes32[] memory merkleProof,
    bytes32 blockHash,
    bytes32 txId,
    uint256 txIndex,
    uint256 minConfirmationsCount
) external view returns (bool)
```

| 名前 | 型 | 説明 |
|------|-----|------|
| `merkleProof` | `bytes32[] memory` | Merkleルートに到達するまでに使うハッシュの配列。 |
| `blockHash` | `bytes32` | 検証対象のブロックのハッシュ。 |
| `txId` | `bytes32` | 検証したい取引ID。 |
| `txIndex` | `uint256` | ブロック内のMerkle Treeにおける取引のインデックス。 |
| `minConfirmationsCount` | `uint256` | 要求する最小確認数。 |

| 戻り値の型 | 説明 |
|------------|------|
| `bool` | 条件を満たせば`true`、満たせなければ`false`。 |

提案では、`checkTxInclusion`は以下の手順を**必ず**実行しなければなりません。

1. `blockHash`がメインチェーンの一部であること、およびそのブロックの確認数が`minConfirmationsCount`以上であることを確認する。いずれかに失敗したら`false`を返す。
2. `merkleProof`、`txId`、`txIndex`を用いてMerkleルートを計算する。
3. 計算したMerkleルートを、`blockHash`で識別されるブロックヘッダに保存された`Merkle Root`と比較する。
4. 一致すれば`true`、一致しなければ`false`を返す。

以下は上記の流れを図示したものです。

```mermaid
flowchart TD
  A[入力のblockHashとminConfirmations] --> B{メインチェーン上かつ確認数は足りるか}
  B -->|いいえ| Z[falseを返す]
  B -->|はい| C[Merkle証明とtxIdとtxIndexから<br/>Merkleルートを計算]
  C --> D{Merkleルートがヘッダの<br/>Merkle Rootと一致するか}
  D -->|いいえ| Z
  D -->|はい| E[trueを返す]
```

図の分岐は、提案が必須とする順序と対応しています。
まずメインチェーン上の位置と確認数で早期に失敗し、その後Merkle再計算でルートの一致を見ます。

##### 参照系のview関数

状態を読むだけのview関数は、メインチェーンの先端や各ブロックのメタデータを取得するためのものです。
いずれも状態を変更しません。

###### メインチェーン先端

`getMainchainHead`は、累積PoWが最大となる枝の**先端ブロックのハッシュ**を返します。
`getMainchainHeight`は、その**高さ**を返します。
`getBlockHash`は、指定した**高さ**にあるメインチェーン上のブロックのハッシュを返します。

###### ブロック単体の参照

`getBlockHeader`は、保存済みの`BlockHeaderData`を返します。
`getBlockHeight`は、`blockHash`から**高さ**を引きます。
`getBlockMerkleRoot`は、ヘッダに保存されたMerkleルートを返します。
`blockExists`は、コントラクトがその`blockHash`を保持しているかを返します。

###### `getBlockStatus`

`getBlockStatus`は、メインチェーン上かどうか（`isInMainchain`）と、そのブロックの上に積まれたブロック数に相当する**確認数**（`confirmationsCount`）を一度に返します。
`checkTxInclusion`を呼ぶ前に、同じ前提を自前で確認したいときの入口になります。

以下の表に、主な関数と返す情報をまとめました。

| 関数 | 返す情報 |
|------|----------|
| `getMainchainHead` | 累積PoWが最大のメインチェーン先端のブロックハッシュ |
| `getMainchainHeight` | 累積PoWが最大のメインチェーンにおける先端のブロック高さ |
| `getBlockHeader` | 指定`blockHash`に対応する`BlockHeaderData` |
| `getBlockStatus` | メインチェーン上か（`isInMainchain`）と、その上に積まれたブロック数に相当する確認数 |
| `getBlockMerkleRoot` | ヘッダに保存されたMerkleルート |
| `getBlockHeight` | 既知の`blockHash`のブロック高さ |
| `getBlockHash` | 指定高さのメインチェーン上のブロックハッシュ |
| `blockExists` | ストレージに当該`blockHash`が登録されているか |

シグネチャの一覧は提案本文のインターフェース定義に従います。
個別の引数・戻り値の意味は上表と対応しています。

```javascript
function getMainchainHead() external view returns (bytes32);
function getMainchainHeight() external view returns (uint64);
function getBlockHeader(bytes32 blockHash) external view returns (BlockHeaderData memory);
function getBlockStatus(bytes32 blockHash) external view returns (bool isInMainchain, uint64 confirmationsCount);
function getBlockMerkleRoot(bytes32 blockHash) external view returns (bytes32);
function getBlockHeight(bytes32 blockHash) external view returns (uint64);
function getBlockHash(uint64 blockHeight) external view returns (bytes32);
function blockExists(bytes32 blockHash) external view returns (bool);
```

#### 参照実装

提案は、同じEIPページに`SPVGateway.sol`の参照実装と、難易度の`Bits`と`target`の相互変換などを扱う`TargetsHelper.sol`へのリンクを載せています。
依存するライブラリのバージョンも提案に書かれています。

## 設計根拠（Rationale）

EIP/ERCでは、採用した設計の**理由やトレードオフ**をまとめた節を **Rationale**（ラシオナーレ）と呼びます。ここではその内容の要約です。

#### 初期化の比較

設計時に、初期化の取り方として以下の3案が並んでいます。

以下の図は、この節で並べられる3案の位置づけと、提案が②を採用形としている点をまとめたものです。

![erc8002-init-options.png](/images/qiita-b765c305-8c29-4113-a83b-8d3d03e87114.webp)

1. **Bitcoinジェネシスをハードコードする**
    デプロイの起点は最も信頼不要だが、フル同期のコストが大きく、提案の例では**ガス単価1 gweiのとき約100 ETH**規模のフル同期に相当する、と試算しています。

2. **任意の高さからのブートストラップ**
    初期の累積仕事量と高さを信頼する必要があるが、ライトクライアントの起動で一般的な方法であり、コミュニティ検証済みチェックポイントなどでオフチェーン補強が可能。

3. **歴史の正しさをゼロ知識証明で保証する**
    高度だが、特定ブロックまでの歴史を一括で証明できる。

現行の提案では、初期化の採用形は**2**です。

#### エンディアン

生ヘッダを提出した後、`BlockHeaderData`の各フィールドはビッグエンディアンに正規化されます。
EVMの効率を優先するためであり、Bitcoinの整数のリトルエンディアンとは逆の扱いになります。

ワイヤ上のBitcoinヘッダと、コントラクト内の構造体の向きの違いを図示します。

```mermaid
flowchart LR
  B[Bitcoin 生80バイト<br/>整数フィールドはLE]
  B --> P[パースと正規化]
  P --> D[BlockHeaderData<br/>EVM向けにBE]
```

ハッシュ系の`bytes32`は向きの問題が出にくく、主に`version`や`time`などの整数フィールドでエンディアン変換の話になります。

#### ファイナリティ

`SPVGateway`は、**消費側プロトコル**が必要とする確定の基準を決める「ファイナリティのルール」を持ちません。
しきい値は利用側が個別に定めます。

#### バッチ追加とガス

オプションの`addBlockHeaderBatch`はガス最適化のために含まれ、**11ブロック超**のバッチではMTP計算に`calldata`のタイムスタンプを使えるため、ストレージ読み込みとコストを大きく下げられる、と書いてあります。

複数ヘッダを順に処理するイメージです。各要素は個別に検証・追加されます。

```mermaid
flowchart LR
  H1[ヘッダ1] --> H2[ヘッダ2]
  H2 --> H3[ヘッダn]
  H3 --> V[各ステップで<br/>検証して追加]
```

長い同期を一度のトランザクションにまとめる用途を想定した関数であり、中身は単一追加の繰り返しです。

## セキュリティ

#### BitcoinのPoWへの依存

ゲートウェイの安全性はBitcoinのPoWコンセンサスに直結します。
51%攻撃が成功すると、攻撃者が提出する不正なヘッダが受け入れられ、状態が破綻する可能性があります。

#### 2時間先の時刻チェックの省略

ノード実装ではネットワーク調整時刻に対する「2時間先まで許容しない」チェックがありますが、`SPVGateway`ではネットワーク調整時刻が取れないため、このチェックは実装しません。

#### 確率的ファイナリティとリオーグ

Bitcoinは確率的なファイナリティであり、`SPVGateway`は任意の深さのリオーガナイゼーションに対応するよう設計されるべきですが、リオーグの発生を防ぐことはできません。
ブロックに含まれた取引が恒久的に確定するとは限らないため、利用するdAppとプロトコルは、自前のセキュリティ方針で十分な確認数を決めなければなりません。

#### 初期状態の信頼点

`addBlockHeader`はパーミッションレスで各ヘッダを暗号学的に検証しますが、開始時のブロックヘッダ・高さ・累積PoWは信頼の起点になります。
設計上の柔軟なブートストラップを許容する一方、初期状態の検証責任はコミュニティと、当該デプロイを使うdAppの選択にあります。

## リファレンス実装

Solidityの参考実装はethereum/ERCsリポジトリに含まれています。

https://github.com/ethereum/ERCs/tree/master/assets/erc-8002/contracts

`TargetsHelper`は、Bitcoinの難易度`target`と`Bits`の相互変換や、難易度調整期間における新しい`target`の計算などを提供する補助ライブラリです。

依存関係として、提案では`@openzeppelin/contracts v5.2.0`、`@solarity/solidity-lib v3.2.0`、`solady v0.1.23`が列挙されています。

## 議論とステータス

Ethereum Magicians上のスレッドは以下のURLです。

https://ethereum-magicians.org/t/eip-8002-simplified-payment-verification-gateway/25038

本提案はドラフトであり、デプロイアドレス・テストケース・**デプロイ手順**などは未確定のプレースホルダが残っています。
互換性について提案本文に「後方互換」とある場合でも、**何に対する互換性か**（例: 既存のEthereumアップグレードや他規格との関係）は原文の該当節で確認してください。
本番利用の前に、常に最新の原文と実装を確認してください。

## 最後に

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

Bitcoinヘッダのバイトレイアウトから難易度調整、Chain CohesionとMTPとPoWの3条件、累積PoWでのメインチェーン選定までを押さえたうえで、`addBlockHeader`の必須ステップと`checkTxInclusion`の分岐、Rationaleの初期化トレードオフ、セキュリティ上の前提（PoW依存・2時間ルール省略・ブートストラップの信頼点）までを、提案の順に整理しました。
参照系のviewは、メインチェーン先端・ブロック単体・`getBlockStatus`のように小見出しでまとめ、表とシグネチャでAPI全体の地図を掴めるようにしています。

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

https://amzn.asia/d/gxvJ0Pw

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

https://zenn.dev/heku

https://mirror.xyz/0xcE77b9fCd390847627c84359fC1Bc02fC78f0e58

https://twitter.com/cardene777

https://cardene.substack.com/
