# [EIP2] ホームステッド・ハードフォークについて理解しよう！

> Ethereumのホームステッドアップデートには、以下のような変更点が含まれています。

- URL: https://cardene.dev/articles/2c81484c7469233fa4ee
- 公開日: 2024-01-17
- 更新日: 2024-01-17
- トピック: Blockchain
- タグ: ethereum, solidity, smartcontract, ブロックチェーン

## はじめに

初めまして。
**CryptoGames**というブロックチェーンゲーム企業でエンジニアをしている **cardene（かるでね）** です！
スマートコントラクトを書いたり、フロントエンド・バックエンド・インフラと幅広く触れています。

https://cryptogames.co.jp/

代表的なゲームは**クリプトスペルズ**というブロックチェーンゲームです。

https://cryptospells.jp/

今回は、ホームステッド・ハードフォークの仕組みについて説明している**EIP2**についてまとめていきます！

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

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

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

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

## パラメーター

| FORK_BLKNUM | CHAIN_NAME |
| :---------: | :--------: |
| `1,150,000` | **Main net** |
| `494,000` | **Morden** |
| `0` | **Future testnets** |


## 仕様

Ethereumのホームステッドアップデートには、以下のような変更点が含まれています。

### トランザクションによるコントラクト作成のガスコスト増加
このアップデートでは、トランザクションによるコントラクト作成の初期ガス料金が`21,000`ガスから`53,000`ガスへと増加します。
これは、トランザクションを送信して宛先アドレスが空の文字列（つまり新しいコントラクトを作成する場合）の時に適用されます。
トランザクションデータのガスコストに加え、初期ガスとして`53,000`ガスが引かれることになります。
ただし、`CREATE`オペコードを用いたコントラクト内からのコントラクト作成は、この変更の影響を受けません。

:::message
**CREATE**オペコードについては以下の記事を参考にしてください。
:::

https://zenn.dev/heku/books/aef33b86ded3c0/viewer/27cd5d#create

### トランザクション署名のs値の制限
**secp256k1n**の半分以上の**s**値を持つトランザクション署名は無効とされるようになります。
一方で、ECDSAリカバリープリコンパイルドコントラクトは変更されず、大きい**s**値の署名も受け入れ続けます。
これは、例えば古いBitcoinの署名を回復する時にコントラクトで利用されることがあります。

:::message
#### secp256k1n

**secp256k1nとは？**
**secp256k1n**は、EthereumやBitcoinなどのブロックチェーン技術で使用される特定の楕円曲線（**secp256k1**）に関連する数値です。
この楕円曲線は、暗号学的に安全なデジタル署名を生成するために使用されます。

**楕円曲線の基本**
楕円曲線暗号では、楕円曲線上の点の集まりを使用します。
これらの点は特定の数学的な規則に従っています。
楕円曲線上の点は、公開鍵や秘密鍵などの暗号通貨の鍵生成に重要な役割を果たします。

**nの意味**
**secp256k1n**は、**secp256k1**楕円曲線の「**オーダー**」と呼ばれるものです。
このオーダーは楕円曲線上の異なる点の総数です。
この数値は非常に大きく、約`10^77`の範囲にあります。
これにより、楕円曲線暗号は非常に多くの異なる鍵の組み合わせを提供することができます。

**具体例**
例えば、秘密鍵は`1`から**secp256k1n**までの間の任意の数値にすることができます。
秘密鍵として選ばれたこの数値を使って、楕円曲線上の特定の点（これが公開鍵になります）を計算します。
このプロセスは非常に複雑で、逆算するのは事実上不可能です。
つまり、誰かが公開鍵を持っていても、元の秘密鍵を特定するのは非常に困難です。

Aliceが自分の秘密鍵を使ってメッセージに署名を行い、Bobに送信したとしましょう。
BobはAliceの公開鍵を使って、その署名が本当にAliceによって行われたものであることを確認します。
このプロセスの中で、**secp256k1**楕円曲線の特性と**secp256k1n**の値が暗号学的な検証に使われています。

**secp256k1nの重要性**
このように、**secp256k1n**は暗号通貨のセキュリティの基礎となる数値です。
非常に大きな範囲を持つため、攻撃者が正しい秘密鍵を推測することは実質的に不可能となります。
この堅牢なセキュリティが、EthereumやBitcoinのようなブロックチェーン技術の信頼性の高さにつながっています。

**secp256k1n**はブロックチェーン技術における重要な基盤であり、トランザクションの安全性とデジタルアイデンティティの保証に不可欠な役割を果たしています。
:::

:::message
#### s値

**ECDSAとは？**
**ECDSA**は、公開鍵暗号の一種で、特にブロックチェーン技術（例：Bitcoin、Ethereum）で広く使用されています。
このアルゴリズムは、楕円曲線暗号を利用して、デジタル署名を生成し検証します。
デジタル署名は、メッセージが特定の個人（プライベートキーの所有者）から送信されたことを証明するために使用されます。

**ECDSAの署名プロセス**
1. **キー生成**
    - 秘密鍵と公開鍵（楕円曲線上の点）が生成されます。

2. **署名生成**
    - メッセージ（例えばトランザクション）に対して、秘密鍵を使って署名が生成されます。
    - この署名は、**r**値と**s**値という2つの数値から構成されます。

3. **署名の検証**
    - 他の人（例えばトランザクションを受け取る者）は、公開鍵を使用して、メッセージに付加された署名が有効であることを検証します。

**r値とs値とは？**
- **r値**
    - 署名の一部であり、署名プロセス中に使用されるランダムな数値から計算されます。
    - 具体的には、メッセージをハッシュ化（一意の固定長の値に変換）し、そのハッシュに基づいて楕円曲線上の点を特定し、その点のx座標が**r**値となります。
- **s値**
    - **r**値と同様に、署名の重要な部分です。
    - **s**値は、メッセージのハッシュ、秘密鍵、そして署名プロセスで使われたランダムな数値を基に計算されます。

**重要性**
- **r**値と**s**値の組み合わせが、署名の唯一性を保証します。
- 署名は、トランザクションやメッセージが改ざんされていないこと、または特定の秘密鍵の所有者によって承認されたことを証明するために重要です。
- **ECDSA**署名の検証は、トランザクションが正当な発行者から来ていることを確認するのに使用され、ブロックチェーン

ネットワークにおけるセキュリティと信頼性の根幹を成します。

**ECDSA**における**r**値と**s**値は、デジタル署名を形成するために不可欠な要素です。
これらの値を用いることで、ブロックチェーン技術はメッセージの真正性と送信者の正当性を保証し、ネットワークの安全性を高めています。
これは、ブロックチェーンが信頼できる分散型台帳を提供する上で極めて重要な機能です。
:::

:::message
#### secp256k1n/2より大きいs値の無効化
Ethereumでは、トランザクション署名の**s**値が**secp256k1n**の半分より大きい場合、その署名は無効と見なされます。
これは、トランザクションの変更可能性（malleability）の問題を防ぐためです。
トランザクションの変更可能性とは、署名を変更しても有効なトランザクションが生成できることを意味します。
:::

:::message
#### ECDSA recover precompiled contract

**ECDSA recover precompiled contract**は、既にコンパイルされた特別なコントラクトで、署名から公開鍵をリカバリーするのに使用されます。
このコントラクトは、引き続き大きい**s**値の署名を受け入れます。
これは、たとえば過去のBitcoin署名をEthereumのコントラクトがリカバリーする場合に便利です。
:::

### コントラクト作成のガス不足時の失敗処理
コントラクト作成時に最終的なガス料金を支払うためのガスが不足している場合、そのコントラクト作成は失敗（ガス不足）となります。
この場合、空のコントラクトが残されるのではなく、コントラクト作成自体が完全に失敗します。

### 難易度調整アルゴリズムの変更
難易度調整アルゴリズムが更新され、新しい式は`block_diff = parent_diff + parent_diff // 2048 * max(1 - (block_timestamp - parent_timestamp) // 10, -99) + int(2**((block.number // 100000) - 2))`となります。
ここで、`//`は整数除算を意味します。
また、`minDifficulty`は最小難易度を定義し続け、難易度の調整はこの値以下にはならないようにされます。

これらの変更は、Ethereumネットワークのセキュリティと効率を向上させるためのもので、特にガスコストの増加や難易度調整アルゴリズムの変更は、ネットワークの安定性と耐久性を向上させる目的があります。コントラクト作成のガスコスト増加は、ネットワークの過負荷を防ぎ、適切なトランザクション処理を促進するために導入されました。また、トランザクション署名のs値制限はセキュリティを高めるため、そしてコントラクト作成の失敗処理変更は、不完全なコントラクトの生成を防ぐために行われました。

難易度調整アルゴリズムの変更は、ブロック生成時間をより安定させるために重要です。これにより、マイニングの難易度が適切に調整され、ネットワークの健全な運営が保たれます。

:::message
#### 難易度調整アルゴリズム

```math
block_diff = parent_diff + parent_diff // 2048 * max(1 - (block_timestamp - parent_timestamp) // 10, -99) + int(2**((block.number // 100000) - 2))
```

この式は、ブロックチェーン（例えばEthereum）における難易度調整アルゴリズムを示しています。
ブロックチェーンでは、各ブロックの難易度を調整することで、ブロックの生成速度を一定に保ちます。
この式を分解して、具体例を用いて説明します。

**式の構成要素**
- `block_diff`
    - 新しいブロックの難易度。
- `parent_diff`
    - 直前のブロックの難易度。
- `block_timestamp`
    - 新しいブロックのタイムスタンプ。
- `parent_timestamp`
    - 直前のブロックのタイムスタンプ。
- `block.number`
    - 新しいブロックの番号。

**式の説明**

```math
parent_diff + parent_diff // 2048 * max(1 - (block_timestamp - parent_timestamp) // 10, -99)
```

この部分は、直前のブロックと新しいブロックの生成時間の差に基づいて難易度を調整します。

```math
parent_diff // 2048
```

直前のブロックの難易度を`2048`で割った値。
難易度調整の基本単位となります。

```math
(block_timestamp - parent_timestamp) // 10
```

新しいブロックと直前のブロックの生成時間差を`10`で割った値。

```math
max(1 - (block_timestamp - parent_timestamp) // 10, -99)
```

生成時間差に基づいた調整値。
この値は`1`から`-99`の範囲に制限されます。

```math
int(2**((block.number // 100000) - 2))
```

この部分は、ブロックの番号に基づいて、定期的な難易度の調整を行います。

```math
block.number // 100000
```

ブロック番号を`100,000`で割った値。

```math
2**((block.number // 100000) - 2)
```

難易度爆弾の調整値。
ブロック番号が`100,000`ごとに増加すると、この値は急激に増加します。

**難易度爆弾**

難易度爆弾（Difficulty Bomb）は、Ethereumなどの一部のブロックチェーンネットワークにおいて、意図的に設計されたメカニズムです。
これは、一定の時間が経過すると、ブロックの難易度を人工的に急速に増加させることで、ブロックの生成時間を長引かせることを目的としています。

**難易度爆弾の目的**
- **Proof of WorkからProof of Stakeへの移行を促進する**
    - Ethereumの場合、難易度爆弾はネットワークをProof of Work（PoW）からProof of Stake（PoS）に移行するためのインセンティブとして設計されました。
    - これは、マイナーが新しいコンセンサスメカニズムに移行するよう促すための一つの方法です。

- **ネットワークのアップグレードを促進する**
    - 難易度爆弾は、ネットワークのアップグレードやプロトコルの変更を加速するためにも使用されます。
    - これにより、全ての参加者が最新のプロトコルに迅速に適応するよう促されます。

**難易度爆弾の影響**
- **ブロック生成時間の増加**
    - 難易度爆弾が発動すると、ブロック生成時間が大幅に増加します。
    - これは、トランザクションの処理速度が低下し、ネットワークの遅延が生じることを意味します。

- **「氷河期」への導入**
    - 極端な場合、難易度爆弾はネットワークを「氷河期（Ice Age）」と呼ばれる状態に導くことがあります。
    - これは、ブロック生成が非常に困難または不可能になり、ネットワークが事実上停止する状態を指します。

**対応策**
- **ハードフォークによる延期または除去**
    - Ethereumでは、過去に難易度爆弾の影響を緩和または除去するためにハードフォーク（大きなアップデート）が実施されています。
    - これにより、ネットワークの正常な運用が保たれています。

難易度爆弾は、ブロックチェーンネットワークにおける重要な政策的ツールであり、その運用と管理はネットワークの将来に大きな影響を与えます。

**具体例**
- 直前のブロックの難易度（`parent_diff`）が`2,000,000`、直前のブロックのタイムスタンプが`100,000`、新しいブロックのタイムスタンプが`100,010`、新しいブロックの番号が`200,000`だと仮定します。

- 難易度調整基本単位
    - `2,000,000 // 2048 = 976`
- 生成時間差
    - `(100,010 - 100,000) // 10 = 1`
- 調整値
    - `max(1 - 1, -99) = 0`
- 難易度調整
    - `976 * 0 = 0`
- 難易度爆弾調整
    - `int(2**((200,000 // 100000) - 2)) = int(2**(2 - 2)) = int(2**0) = 1`

したがって、新しいブロックの難易度（`block_diff`）は以下のように計算されます。
- `block_diff = 2,000,000 + 0 + 1 = 2,000,001`

この例では、直前のブロックと新しいブロックの生成時間がほぼ同じ（10秒差）であるため、難易度調整基本単位と生成時間差による調整はゼロとなります。
ただし、難易度爆弾の影響により、新しいブロックの難易度は僅かに増加します。

このように、このアルゴリズムは、ブロックの生成速度が既定の目標（例えばEthereumでは約14秒ごと）から大きく外れないように、難易度を動的に調整する役割を果たしています。
これにより、ネットワークの安定性とセキュリティが保たれ、ブロックチェーンの健全な機能が維持されます。
:::

これらの変更は、Ethereumネットワークをより堅牢で効率的にするために非常に重要です。ユーザーと開発者はこれらの変更に適応し、ネットワークの新しい動作に対応する必要があります。

## 補足

現在のEthereumネットワークでは、トランザクションを介してコントラクトを作成する場合のガスコストが`21,000`ガスとなっています。
これは、直接コントラクトを作成する場合の`32,000`ガスよりも低いため、トランザクションを介したコントラクト作成に対するインセンティブが過剰になっています。
さらに、自殺返金（suicide refund）を利用することにより、`11,664`ガスを使用して単純なイーサ送金が可能となります。以下のコードがその例です。

```python
from ethereum import tester as t
from ethereum import utils
s = t.state()
c = s.abi_contract('def init():\n suicide(0x47e25df8822538a8596b28c637896b4d143c351e)', endowment=10**15)
s.block.get_receipts()[-1].gas_used
# 出力: 11664
s.block.get_balance(utils.normalize_address(0x47e25df8822538a8596b28c637896b4d143c351e))
# 出力: 1000000000000000
```

この状況は特に深刻な問題ではありませんが、バグと見なすことができます。

また、現在のルールでは`0 < s < secp256k1n`である任意の**s**値を持つトランザクションが許容されていますが、これによりトランザクションの変更可能性（malleability）の問題が生じています。
]この問題では、トランザクションを取り、**s**値を`secp256k1n - s`に変更し、**v**値 （`27 -> 28`, `28 -> 27`）を反転させると、結果として得られる署名が依然として有効になります。
これはEthereumがイーサ送金や他のトランザクションの入力としてアドレスを使用し、トランザクションハッシュを使用しないため、重大なセキュリティ上の欠陥ではありませんが、攻撃者がブロックで確認されるトランザクションを変更し、ユーザーが送信したトランザクションと異なるハッシュを持たせることにより、トランザクションハッシュを追跡IDとして使用するユーザーインターフェースに干渉する可能性があります。
大きい**s**値の使用を防止することにより、この問題は解決されます。

:::message
Ethereumネットワークにおけるこれらの特性は、一部のユーザーにとっては利便性をもたらすものの、全体的なネットワークのセキュリティや効率には影響を及ぼす可能性があります。
特に、トランザクションの変更可能性に関する問題は、セキュリティの観点から重要な検討事項となります。
Ethereumは、これらの問題を解決するための措置を講じ、より安全で効率的なブロックチェーンネットワークを目指しています。
:::

Ethereumネットワークにおけるコントラクト作成プロセスとブロック生成の難易度調整に関する改善点について、それぞれポイントを説明します。

#### コントラクト作成のガス不足による失敗処理の改善
- (i) 以前は、コントラクト作成が「**成功**」、「**失敗**」、または「**空のコントラクト**」という三つの結果を持ち得ました。
    - 改善後は、コントラクト作成が「**成功するか失敗するか**」の二つの結果のみになります。
    - これにより、結果がより直感的に理解できるようになります。
- (ii) 改善により、コントラクト作成が完全に成功しない限りコントラクトアカウントは作成されません。
    - そのため、失敗がより簡単に検出できます。
- (iii) 寄付（endowment）を伴うコントラクト作成がより安全になります。
    - この改善により、コントラクトの初期化プロセスが完全に成功するか、トランザクションが失敗して寄付が返金されることが保証されます。

#### 難易度調整の変更
Ethereumは以前、多くのマイナーがほぼ同じタイムスタンプ（`parent_timestamp + 1`）を持つブロックを採掘することにより、ブロック時間の分布に偏りが生じていました。
これにより、ブロック生成の平均時間が増加する問題がありました。
新しい難易度調整の式は、平均ブロック時間をターゲットにしており、長期的には平均ブロック時間が24秒を超えることが数学的に不可能になります。

#### 難易度調整アルゴリズムの主要な入力変数
`(block_timestamp - parent_timestamp) // 10`を使用することで、アルゴリズムが過度に反応しない性質を生かして、マイナーがタイムスタンプの差を`1`に設定するインセンティブを防ぎます。
これにより、やや難易度が高いブロックが生成され、可能なフォークよりも優位に立つことができます。
`-99`の上限は、極端なケース（例えばセキュリティバグや予期せぬ問題）により2つのブロックが時間的に非常に離れている場合に、難易度が過度に低下するのを防ぐために設定されています。

これらの改善は、Ethereumネットワークの効率性と安全性を向上させるために重要です。
コントラクト作成が直感的かつ安全に行われ、ブロック生成の難易度調整が適切に行われることで、ネットワークの安定性と予測可能性が向上します。
これらの変更により、Ethereumユーザーはより信頼性の高いブロックチェーン体験を享受できるようになります。

## 実装

以下に実装されています。

- [https://github.com/ethereum/pyethereum/blob/d117c8f3fd93359fc641fd850fa799436f7c43b5/ethereum/processblock.py#L130](https://github.com/ethereum/pyethereum/blob/d117c8f3fd93359fc641fd850fa799436f7c43b5/ethereum/processblock.py#L130)

- [https://github.com/ethereum/pyethereum/blob/d117c8f3fd93359fc641fd850fa799436f7c43b5/ethereum/processblock.py#L129](https://github.com/ethereum/pyethereum/blob/d117c8f3fd93359fc641fd850fa799436f7c43b5/ethereum/processblock.py#L129)

- [https://github.com/ethereum/pyethereum/blob/d117c8f3fd93359fc641fd850fa799436f7c43b5/ethereum/processblock.py#L304](https://github.com/ethereum/pyethereum/blob/d117c8f3fd93359fc641fd850fa799436f7c43b5/ethereum/processblock.py#L304)
- [https://github.com/ethereum/pyethereum/blob/d117c8f3fd93359fc641fd850fa799436f7c43b5/ethereum/blocks.py#L42](https://github.com/ethereum/pyethereum/blob/d117c8f3fd93359fc641fd850fa799436f7c43b5/ethereum/blocks.py#L42)

## 引用

Vitalik Buterin (@vbuterin), "EIP-2: Homestead Hard-fork Changes," Ethereum Improvement Proposals, no. 2, November 2015. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-2.

## 最後に

今回は「ホームステッド・ハードフォークの仕組みについて説明している**ERC2**」についてまとめてきました！
いかがだったでしょうか？

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

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

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

https://chaldene.net/

https://zenn.dev/heku

https://mirror.xyz/0xcE77b9fCd390847627c84359fC1Bc02fC78f0e58

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