EthereumのP2P
ethはRLPxトランスポート上のプロトコルを使ってる
基本的な動作
接続が確立されると、Statusメッセージを送信する。
ピアのStatusメッセージの受信後、Ethereumセッションがアクティブになり、他のメッセージを送信することができる。
セッション内では、チェーンの同期、ブロックの伝搬、トランザクションの交換という3つのタスクを実行する
これらのタスクはプロトコルメッセージの分離されたセットを使用し、クライアントは通常、すべてのピア接続で同時アクティビティとして実行する。
RLPxトランスポートでは、1つのメッセージのサイズを16.7MiBに制限しているが、ethプロトコルの実際の制限値は10MiB
受信したメッセージが制限値よりも大きい場合、そのピアは切断されなければなりません。
チェーンの同期
接続時には、双方のピアがステータスメッセージを送信する
このメッセージには、Total Difficulty(TD)と「最も良い」既知のブロックのハッシュが含まれる
最悪のTDを持つクライアントは、GetBlockHeadersメッセージを使ってブロックヘッダのダウンロードを進める
受信したヘッダーに含まれるPoWの値を検証し、GetBlockBodiesメッセージを使用してブロックボディを取得します。
受け取ったブロックはEthereum Virtual Machineを使って実行され、ステートツリーとレシートが再作成されます。
なお、ヘッダーのダウンロード、ブロックボディのダウンロード、ブロックの実行は同時に行われることがある
ステートの同期(別名「Fast sync」)について
Version :eth/63以降では、トランザクションの実行結果(ステートツリーやレシートなど)を同期することも可能
過去のすべてのトランザクションを再実行するよりも速いかもしれないが、いくつかのセキュリティが犠牲になる
ステートの同期は通常、ブロックヘッダのチェーンをダウンロードし、その有効性を確認することで行われる
ブロックボディは「チェーン同期」のセクションと同様に要求されるが、ブロックトランザクションは実行されず、「Data Availability」のみが検証される。
クライアントは、チェーンの先頭付近のブロックを選択し、ツリー全体の同期が完了するまで、GetNodeDataを使用してルートノード、その子、孫...を要求することで、Merkleツリーのノードとコントラクトコードを段階的にダウンロードする。
ブロックの伝搬
新たに採掘されたブロックは、2段階のプロセスでブロック伝搬される。
ピアからNewBlockアナウンスメントメッセージを受信すると、クライアントはまずブロックの基本ヘッダの有効性を確認し、PoWの値が有効かどうかをチェックする。
その後、クライアントはNewBlockメッセージを使って、接続しているピアのごく一部(通常はピアの総数の平方根)にブロックを送信する
ヘッダーの有効性を確認した後、クライアントはブロックに含まれるすべてのトランザクションを実行することでブロックをローカルチェーンにインポートし、ブロックの「ポストステート」を計算する
ブロックのステートルートのハッシュは、計算されたポストステートルートと一致していなければなりません。
ブロックが完全に処理され、有効であると判断されると、クライアントはそのブロックに関するNewBlockHashesメッセージを、先に通知しなかったすべてのピアに送信
これらのピアは、他の誰からもNewBlock経由でブロックを受信できなかった場合、後で完全なブロックを要求することができる。
ノードは、以前に同じブロックを告知したピアに、ブロック告知を送り返してはならない。これは通常、各ピアとの間で最近中継されたブロックハッシュの大規模なセットを記憶することで実現される
トランザクションの交換
すべてのノードは、保留中のトランザクションを交換して、それをマイナーに中継し、マイナーがブロックチェーンに組み込むために選択する必要がある。クライアントの実装では、保留中のトランザクションのセットを「トランザクションプール(mempool)」に記録する
新しいピア接続が確立されると、双方のトランザクション・プールを同期させる必要があります。
最初に、双方は交換を開始するために、ローカルプール内のすべてのトランザクションハッシュを含むNewPooledTransactionHashesメッセージを送信する
NewPooledTransactionHashesのアナウンスを受信すると、クライアントは受信したセットをフィルタリングして、自身のローカルプールにまだないトランザクションハッシュを集める
その後、クライアントは GetPooledTransactions メッセージを使用してトランザクションを要求
クライアントのプールに新しいトランザクションが現れた場合、クライアントは Transactions および NewPooledTransactionHashes メッセージを使用してネットワークにそれらを伝搬する
Transactionsメッセージは、完全なトランザクション・オブジェクトを中継し、通常、接続されたピアの小さなランダムな部分に送信される
他のすべてのピアは、トランザクション・ハッシュの通知を受け取り、完全なトランザクション・オブジェクトが知られていない場合は、それを要求することができる。
一部のピアに完全なトランザクションを配布することで、通常、すべてのノードがトランザクションを受信し、それを要求する必要がないことが保証されます。
ブロックの伝搬と同様に、以前に同じTxを告知したピアに、Txを送り返してはならない
Transaction Encoding and Validity
トランザクションは、ローカルプールへの一時的な保管や他のピアとの交換に許容できるかどうかを検証する必要がある。
*受信時にEVMによって正常に実行できるかどうかではない
トランザクションがタイプされていない場合、そのtx-dataがnonce、gas-price、gas-limitの値を提供し、トランザクションの送信者アカウントがその署名から判断できることを検証する
トランザクションがタイプされている場合、その tx-typeは実装に知られていなければならない。定義されたトランザクションタイプは、ブロックに含めることが許容されるようになる前であっても、有効であるとみなされるかもしれない。実装は、タイプが不明なトランザクションを送信するピアを切断すべきである。
署名は、チェーンでサポートされている署名方式に基づいて有効でなければならない。
型付きトランザクションの場合、署名の取り扱いは、型を導入するEIPによって定義される。
レガシー・トランザクションでは、基本的な「ホームステッド」スキームとEIP-155スキームの2つのスキームが使用されている
ガスリミットは、取引の「本質的なガス」をカバーしなければならない
署名から得られる取引の送信者アカウントは、取引のコスト(gas-limit * gas-price + value)をカバーするのに十分なエーテル残高を持っていなければならない
取引のnonceは、送信者アカウントの現在のnonceと同じかそれ以上でなければならない。
取引をローカルプールに含めることを検討する際、現在のアカウントのnonceよりも大きいnonceを持つ「将来の」取引がいくつ有効か、またどの程度の「nonceギャップ」が許容されるかを決定するのは実装次第である。
特に断りのない限り、実装では無効なトランザクションを送信してもピアを切断してはならず、代わりに単純に破棄する必要があります。これは、ピアがわずかに異なる検証ルールで動作している可能性があるためです。
ブロックヘッダの有効性は、それが使用されるコンテキストに依存する。単一のブロックヘッダの場合、プルーフ・オブ・ワークシール(mix-digest、block-nonce)の有効性のみを検証することができる。ヘッダーがクライアントのローカルチェーンを拡張するために使用される場合、またはチェーン同期中に複数のヘッダーが順番に処理される場合、以下のルールが適用される
ヘッダーは、ブロック番号が連続し、各ヘッダーの親ハッシュが先行するヘッダーのハッシュと一致するチェーンを形成しなければなりません。
ローカルに保存されているチェーンを拡張する際には、難易度、ガスリミット、時間の値がYellow Paperに記載されているプロトコル・ルールの範囲内であることも検証しなければならない。
ブロック・ヘッダのgas-usedフィールドは、gas-limit以下でなければならない。
完全なブロックについては、ブロックのEVMの状態遷移の有効性と、ブロックの(より弱い)「データの有効性」を区別する
状態遷移規則の定義は、この仕様では扱われていない。ブロックのデータの有効性は、ブロックの即時伝搬や状態の同期のために必要
ブロックのデータの有効性を判断するには、以下のルールを使用します。
実装では、無効なブロックを送信するピアを切断する必要があります。
ブロック・ヘッダが有効であること。
ブロックに含まれるトランザクションは、そのブロックの番号のチェーンに含まれるものとして有効でなければならない。つまり、前述のトランザクション検証ルールに加えて、ブロック番号でtx-typeが許可されているかどうかの検証が必要であり、トランザクションのガスの検証にはブロック番号を考慮しなければならないということである。
すべてのトランザクションのガスリミットの合計は、ブロックのガスリミットを超えてはならない。
ブロックのトランザクションは、トランザクション・リストのメルクル・トライ・ハッシュを計算して比較することにより、txs-rootに対して検証されなければならない。
ommers リストには最大で 2 つのヘッダーを含めることができます。
keccak256(omers)は、ブロック・ヘッダのomers-hashと一致しなければならない。
ommers リストに含まれるヘッダは有効なヘッダでなければならない。
ブロック番号は、含まれているブロックの番号より大きくてはいけません。
ommerヘッダの親ハッシュは、含まれるブロックの深さ7以下の祖先を参照していなければならず、この祖先セットに含まれる以前のブロックに含まれていてはならない。