メインコンテンツへスキップ
Change page

イーサッシュ

イーサッシュは、イーサリアムのプルーフ・オブ・ワーク (PoW) マイニング・アルゴリズムでした。現在、プルーフ・オブ・ワークは完全にオフになっており、イーサリアムは代わりにプルーフ・オブ・ステーク (PoS)を使用して保護されています。詳細については、マージプルーフ・オブ・ステーク (PoS)、およびステーキングをお読みください。このページは歴史的な関心のために残されています!

イーサッシュは、Dagger-Hashimotoアルゴリズムの修正版です。イーサッシュのプルーフ・オブ・ワークはメモリ・ハード (opens in a new tab)であり、これによりアルゴリズムがASIC耐性を持つと考えられていました。最終的にイーサッシュ用のASICは開発されましたが、プルーフ・オブ・ワークがオフになるまで、GPUマイニングは依然として実行可能な選択肢でした。イーサッシュは現在でも、イーサリアム以外の他のプルーフ・オブ・ワーク・ネットワークで他のコインをマイニングするために使用されています。

イーサッシュの仕組み

メモリ・ハードネスは、ナンスとブロック・ヘッダーに依存する固定リソースのサブセットを選択する必要があるプルーフ・オブ・ワーク・アルゴリズムによって実現されます。このリソース(数ギガバイトのサイズ)はDAGと呼ばれます。DAGは30000ブロックごとに変更されます。これはエポックと呼ばれる約125時間のウィンドウ(約5.2日)であり、生成にはしばらく時間がかかります。DAGはブロック高にのみ依存するため、事前に生成しておくことができますが、そうでない場合、クライアントはブロックを生成するためにこのプロセスが終了するまで待つ必要があります。クライアントが事前にDAGを生成してキャッシュしない場合、ネットワークは各エポックの移行時に大規模なブロック遅延を経験する可能性があります。プルーフ・オブ・ワークを検証するためにDAGを生成する必要はないため、本質的に低いCPUと少ないメモリの両方で検証が可能であることに注意してください。

アルゴリズムがたどる一般的な手順は以下の通りです。

  1. その時点までのブロック・ヘッダーをスキャンすることで、各ブロックに対して計算できるシードが存在します。
  2. シードから、16 MBの疑似乱数キャッシュを計算できます。ライト・クライアントはこのキャッシュを保存します。
  3. キャッシュから、1 GBのデータセットを生成できます。このデータセットの各アイテムは、キャッシュからの少数のアイテムにのみ依存するという特性を持っています。フル・クライアントとマイナーはこのデータセットを保存します。データセットは時間とともに線形に増加します。
  4. マイニングでは、データセットのランダムなスライスを取得し、それらを一緒にハッシュ化します。検証は、キャッシュを使用して必要なデータセットの特定の部分を再生成することで、少ないメモリで実行できるため、キャッシュを保存するだけで済みます。

大規模なデータセットは30000ブロックに1回更新されるため、マイナーの労力の大部分はデータセットの読み取りであり、変更を加えることではありません。

定義

以下の定義を採用します。

「SHA3」の使用について

イーサリアムの開発はSHA3標準の開発と同時期に行われました。標準化プロセスの終盤でファイナライズ済みのハッシュ・アルゴリズムのパディングに変更が加えられたため、イーサリアムの「sha3_256」および「sha3_512」ハッシュは標準のsha3ハッシュではなく、他のコンテキストでは「ケチャック・256」および「Keccak-512」とよく呼ばれる変種となっています。議論については、例えばこちら (opens in a new tab)こちら (opens in a new tab)、またはこちら (opens in a new tab)を参照してください。

以下のアルゴリズムの説明で「sha3」ハッシュが言及される際には、この点に留意してください。

パラメータ

イーサッシュのキャッシュとデータセットのパラメータは、ブロック番号に依存します。キャッシュ・サイズとデータセット・サイズはどちらも線形に増加しますが、偶発的な規則性が循環的な動作につながるリスクを減らすために、常に線形に増加するしきい値未満の最大の素数を採用します。

データセットとキャッシュ・サイズの値の表は、付録に記載されています。

キャッシュの生成

次に、キャッシュを生成するための関数を指定します。

キャッシュ生成プロセスでは、まず32 MBのメモリを順次埋め、次にStrict Memory Hard Hashing Functions (2014) (opens in a new tab)のSergio Demian Lernerによる_RandMemoHash_アルゴリズムを2パス実行します。出力は、524288個の64バイト値のセットになります。

データ集約関数

XORの非結合的な代替として、場合によってはFNVハッシュ (opens in a new tab)に触発されたアルゴリズムを使用します。素数と1バイト(オクテット)を順番に乗算するFNV-1の仕様とは対照的に、素数と完全な32ビット入力を乗算することに注意してください。

FNV_PRIME = 0x01000193

def fnv(v1, v2):
    return ((v1 * FNV_PRIME) ^ v2) % 2**32

イエロー・ペーパーではfnvをv1*(FNV_PRIME ^ v2)と指定していますが、現在のすべての実装は一貫して上記の定義を使用していることに注意してください。

完全なデータセットの計算

完全な1 GBのデータセット内の各64バイトのアイテムは、次のように計算されます。

基本的には、疑似ランダムに選択された256個のキャッシュ・ノードからのデータを結合し、それをハッシュ化してデータセット・ノードを計算します。その後、データセット全体は次のように生成されます。

def calc_dataset(full_size, cache):
    return [calc_dataset_item(cache, i) for i in range(full_size // HASH_BYTES)]

メイン・ループ

次に、特定のヘッダーとナンスの最終値を生成するために、完全なデータセットからデータを集約するメインの「hashimoto」風ループを指定します。以下のコードでは、headerは、_切り詰められた_ブロック・ヘッダー(つまり、mixHashnonceフィールドを除外したヘッダー)のRLP表現のSHA3-256_ハッシュ_を表します。nonceは、ビッグ・エンディアン順の64ビット符号なし整数の8バイトです。したがって、nonce[::-1]はその値の8バイトのリトル・エンディアン表現になります。

基本的には、128バイト幅の「mix」を維持し、完全なデータセットから128バイトを繰り返し順次フェッチして、fnv関数を使用してmixと結合します。アルゴリズムの各ラウンドが常にRAMからフル・ページをフェッチするように128バイトのシーケンシャル・アクセスが使用され、ASICが理論的に回避できるトランスレーション・ルックアサイド・バッファのミスを最小限に抑えます。

このアルゴリズムの出力が目的のターゲットを下回る場合、ナンスは有効です。最後にsha3_256を追加で適用することで、少なくとも少量の作業が行われたことを証明するために提供できる中間ナンスが存在することが保証されることに注意してください。この迅速な外部PoW検証は、DDoS対策の目的で使用できます。また、結果が偏りのない256ビットの数値であるという統計的な保証を提供する役割も果たします。

マイニング

マイニング・アルゴリズムは次のように定義されます。

def mine(full_size, dataset, header, difficulty):
    # 同じ桁でハッシュと比較するためにターゲットをゼロパディングする
    target = zpad(encode_int(2**256 // difficulty), 64)[::-1]
    from random import randint
    nonce = randint(0, 2**64)
    while hashimoto_full(full_size, dataset, header, nonce) > target:
        nonce = (nonce + 1) % 2**64
    return nonce

シード・ハッシュの定義

特定のブロックの上でマイニングするために使用されるシード・ハッシュを計算するために、以下のアルゴリズムを使用します。

 def get_seedhash(block):
     s = '\x00' * 32
     for i in range(block.number // EPOCH_LENGTH):
         s = serialize_hash(sha3_256(s))
     return s

スムーズなマイニングと検証のために、将来のシード・ハッシュとデータセットを別のスレッドで事前に計算しておくことをお勧めします。

参考文献

役に立つコミュニティ・リソースをご存知ですか?このページを編集して追加してください!

付録

上記のPython仕様をコードとして実行することに関心がある場合は、以下のコードを先頭に追加する必要があります。

データ・サイズ

以下のルックアップ・テーブルは、データ・サイズとキャッシュ・サイズの約2048エポック分を表にしたものです。