通信プロトコル
※Wire Protocolの翻訳です。
Ethereumのクライアントを実行しているノード間でのP2P通信は単純な通信プロトコルによって統御されるよう設計されている。この通信プロトコルはRLPなどの既存のEthereumの技術及び標準を利用できるところではどこでも利用するよう設計されている。
本文書はこの通信プロトコルの仕様を網羅的に記述することを目的としている。
低水準
EthereumのノードはTCPのみを使って互いに接続することができる。ピアは自身が望む任意のポートを自由に他のノードに広く通知することができ、接続を受け入れることができる。しかしながら、特に何も指定しない場合には、接続が待ち受けられ、接続が確立するポートは30303である。
TCPは接続指向(connection-oriented)の通信手段を提供するものの、Ethereumのノードはパケットを単位として通信を行う。パケットはビッグエンディアンの32ビット整数と解釈される4バイトの同期信号(0x22400891)、4バイトの「ペイロード長」を順次に含み、最後にNバイトのRLP形式で直列化されたデータ構造を含む。ここで、Nは前述の「ペイロード長」である。明快に言えば、ペイロード長はパケットの中で最初の8バイトの後に続いているバイト数を表す。
ペイロードの内容
RLP形式で符号化することのできるペイロードの種類には多数の様々なものがある。RLPの最初の項目は常に整数と解釈され、それによってペイロードの「種類」が決まる。
Hello
・[0x00, PROTOCOL_VERSION, NETWORK_ID, CLIENT_ID, CAPABILITIES, LISTEN_PORT, NODE_ID]
・接続が確立したら最初に送信されるパケットである。接続が確立した両側のノードから1回ずつ送信される。Helloが受信されるまでは、如何なる他の通信文も送信されない。
・PROTOCOL_VERSIONは、
・概念実証#1:0x00
・概念実証#2:0x01
・概念実証#3:0x07
の何れかである。
・NETWORK_IDは0であるべきである。
・CLIENT_IDはクライアントソフトウェアを識別する人間が読める文字列である(たとえば、「Ethereum(++)/1.0.0」)。
・LISTEN_PORTはクライアントが(現在の接続が確立されているインターフェイス上で)接続を待ち受けているポート番号である。0である場合は、クライアントが接続を待ち受けていないことを示す。
・CAPABILITIESは一連のフラグとして表されるクライアントの機能である。現在は3つのビットが使用されている。0x01はピアの発見、0x02は取引の中継、0x04はブロック鎖の問い合わせを表す。
・NODE_IDは随意的であり、ノードを識別する512ビットのハッシュ値である(公開鍵として使用される可能性がある)。
Disconnect
・[0x01, REASON]
・接続の切断が差し迫っているということをピアに通知する。本パケットを受信したピアは直ちに接続を切断すべきである。本パケットを送信した、仕様に準拠しているホストは自分自身が接続を切断する前にピアに対して(2秒間待機し)接続を切断する猶予を与える。
・REASONは随意的であり、幾つかある接続の切断の理由の内の1つを示す整数である。
・0x00:接続の切断が要求された。
・0x01:下位にあるTCPのシステムで過誤が発生した。
・0x02:不正なプロトコル。
・0x03:無用なピア。
・0x04:余りにもピアが多過ぎる。
・0x05:既に接続している。
・0x06:起源ブロックが不正である。
・0x07:互換性のないネットワークプロトコルである。
・0x08:クライアントが終了しようとしている。
Ping
・[0x02]
・ピアに対して直ちにPongパケットで応答するよう要求する。
Pong
・[0x03]
・ピアのPingパケットに対する応答である。
GetPeers
・[0x10]
・ピアに対して接続することができる幾つかの既知のピアを列挙するよう要求する。要求を受けたピア自身も既知のピアの列挙に含めるべきである。
Peers
・[0x11, [IP1, Port1, Id1], [IP2, Port2, Id2], ... ]
・幾つかの既知のピアを列挙する。IPは4バイトの配列である。'ABCD'という配列はA.B.C.DというIPアドレスと解釈されるべきである。Portは2バイトの配列であり、16ビットのビッグエンディアンの整数と解釈されるべきである。Idは512ビットのハッシュ値であり、ノードの固有識別子としての役割を果たす。
Transactions
・[0x12, [nonce, receiving_address, value, ... ], ... ]
・ピアが取引の待ち行列に必ず含めるべき取引を表す。(最初の項目である0x12に続いて)一覧の中にある項目はEthereumの主要仕様書で説明されている形式で表現された取引である。
Blocks
・[0x13, [block_header, transaction_list, uncle_list], ... ]
・ピアが知るべきブロックを表す。(最初の項目である0x13に続いて)一覧の中にある項目はEthereumの主要仕様書で説明されている形式で表現されたブロックである。
GetChain
・[0x14, Parent1, Parent2, ..., ParentN, Count]
・ピアに対して現在の正統なブロック鎖の中でParent1(ブロックのSHA3ハッシュ値と解釈される)の子孫であるCount(整数と解釈される)個のブロックを送信するよう要求する。Parent1がブロック鎖の中に含まれない場合には、Parent1の代わりにParent2の子孫であるCount個のブロックを送信する。以下ParentNまで同様である。指定された親が現在のブロック鎖の頭部である場合には、空の応答を送信するべきである。現在の正統なブロック鎖の中に何れの親も含まれていない場合には、ParentN(すなわち、親の一覧における最後のParentである)と共にNotInChainを送信するべきである。親が渡されなかった場合には、応答を行う必要はない。
NotInChain
・[0x15, Hash]
・ピアに対してブロック鎖の中で所与のハッシュ値が見付からなかったことを知らせる。
GetTransactions
・[0x16]
・ピアに対して現在待ち行列に含まれている全ての取引を送信するよう要求する。Transactionsを参照せよ。
パケットの例
0x22400891000000088400000043414243
クライアントの識別子が「ABC」であることを示すHelloパケットである。
ピア1:0x22400891000000028102
ピア2:0x22400891000000028103
Ping及びその応答であるPongである。
セッション管理
接続が確立したら、全てのクライアント(すなわち、接続が確立した両側のノード)はHello通信文を送信しなければならない。Hello通信文を受信し、ネットワークとバージョンの互換性の検証が終わったら、セッションが確立した状態になり、他の任意の通信文を送信することができる。
何時でもDisconnect通信文を送信することができる。