翻訳:Satoshiクライアントのノード接続性
次はこれ。
Satoshi Client Node Connectivity - Bitcoin Wiki
同じく適当。
Satoshiクライアントのノード接続性
1 概要
2 接続ルール
2.1 外向きのスタティックアドレス
2.2 外向きの制限
2.3 シードノード
2.4 外向きのランダムな選択
2.5 内向きの受け入れと切断
1 概要
Satoshiビットコインクライアントは他のノードとの接続生成をマネージメントするスレッドをつくります。net.cppの中のThreadOpenConnections2と呼ばれる関数の中にそのスレッドのコードがあります。
クライアントはnet.cppの中にある、ThreadSocketHandler2と呼ばれるスレッドで、新しい内向きのコネクションと切断を適切なタイミングでハンドルします。
コネクションを生成するスレッドは他のノードのアドレス発見は行いません。
その情報は様々な方法で集められます(Node Discoveryの記事を参照)
コネクションスレッドは有効なアドレスの中からアドレスを選択し、適切なタイミングでコネクションを生成したり切断したりします。これが全てです。
ノードアドレスは以下のようなルール群に従って選ばれます。
2 接続ルール
2.1外向きのスタティックアドレス
-connect引数でユーザがアドレスを指定した場合、ノードはそのアドレスだけを使います。それぞれのノードに対してコネクションを成立させようとしたのち0.5秒スリープします。それからシャットダウンまでループを繰り返します。コードはOpenNetworkConnection(addr)をコールすることによってコネクションを成立させます。すでにコネクションがオープンしている場合、OpenNetworkConnectionは何もしません。
もしユーザーが -node引数によってアドレスを指定した場合、スタートアップ時は(それぞれ0.5秒の遅延をもって)これらのノードに対してコネクションを作ります。これらのコネクションが試された後、コードは標準的なコネクションをハンドルするコードを処理します。
2.2外向きの制限
コネクションをハンドリングするコードはシャットダウンまで様々な関数を実行する一つのループです。ループが最初に行うことは外向きの接続の数を数えることです。次に(8または、-maxconnectionで与えられた数)に到達していたら、数がmax以下になるまで2秒の遅延ループに入ります。
コネクションの数が制限以下である場合、ノードは他のノードに接続をこころみます。次の説を参照してください。
2.3 シードノード
もしノードが他のアドレスを得ることができなかった場合、おそらくこれらの方法が失敗しているのだが、ノードはソフトウェアにハードコードされている320のアドレスのリストを使用します。
可能な場合、シードノードを取り除くコードが存在しています。おそらくこれはシードノードへの過負荷を避けるためです。一度ローカルノードが十分な数のアドレスを得たら(おそらくシードノードから得た)、コネクションスレッドはシードノードのコネクションをクローズします。
2.4 外向きのランダムな選択
最初にコードはアドレスをa.b.c.*バケット(?)に 一つのコネクションのみがそれぞれの24bitのnetmaskされたネットワークを作ります。
次に全てのアドレスに対してループし、”ready”状態かどうか決定します。そして、複雑な計算式でそれぞれのアドレスに対してスコアを計算します。もっとも高いスコアを持つアドレスが勝利し、OpenNetworkConnectionが呼び出されます。そして、コードはスレッドのメインのループを完了し、繰り返します。
readinessを決定するために、コードはIPと他のエントロピーをハッシュし、1〜3600の乱数を決定します。もしアドレスが標準でないポートを指定していた場合、2時間のペナルティが与えられます。これはリトライ間隔を調整するための数字です。
メインのリトライ間隔は基本的に最後につながった時間の平方根に前パラグラフの乱数調整値を足したものです。しかしながら、もしノードが最後につながったのが一時間以内の場合は、リトライ間隔は10分となります。以下のテーブルがコードの中にあります。
// Last seen Base retry frequency
// <1 hour 10 min
// 1 hour 1 hour
// 4 hours 2 hours
// 24 hours 5 hours
// 48 hours 7 hours
// 7 days 13 hours
// 30 days 27 hours
// 90 days 46 hours
// 365 days 93 hours
// <1 hour 10 min
// 1 hour 1 hour
// 4 hours 2 hours
// 24 hours 5 hours
// 48 hours 7 hours
// 7 days 13 hours
// 30 days 27 hours
// 90 days 46 hours
// 365 days 93 hours
インターバル計算の後、もしアドレスがすでにインターバル内にコンタクトされていれば(?)アドレスはスキップされます。
もしアドレスが一日以上古ければ、それをスキップします。もしIRCアドレスを取得でき、ノード接続ができれば、もしそれが本当にアクティブであれば、アドレスのアドバタイズを見ることができるという仮定のもとにそれをスキップします。
最後にリトライの準備ができていると思われる全てのアドレスに対して、最大24時間で最も長い間コンタクトできていないアドレスが選ばれます。しかしながらそこには少しひねりがあります。スコアの計算式は以下です。
int64 nScore = min(nSinceLastTry, (int64)24 * 60 * 60) - nSinceLastSeen - nRandomizer;
アドレスは最後に見られたのちに毎秒ペナルティがあります(そして乱数による調整も)
2.5 内向きの受け入れと切断
クライアントはnet.cppにある、ThreadSocketHanler2と呼ばれるスレッドの中で適切なタイミングで内向きの接続と切断をハンドリングします。
ソケットスレッドは、単純なループで、fDisconnectフラグが立っている(そしてバッファが空である)ソケットを切断し、全てのソケットに”select”の準備をし、”select”をコールします。”select”はシステムコールで、ソケットのアクティビティを待ちます。
そのコールが帰ってきたとき、ノードはいかなる新しいコネクションも受け入れ、ready状態のいかなるソケットの送受信を行い、アクティブでないいかなるソケットもfDisconnectフラグを立てて切断します。
ソケットは、もし60秒間の過去のもので、データが送受信されていない場合切断されます。
ソケットは過去90分に渡ってデータの送受信が過去90分間データの送受信がない場合切断されます。
ソケットは現在の内向きのデータがバッファリミットを超えていたら切断します。
(net.cppの中で if (nPos > ReceiveBufferSize())を検索)
ソケットは現在の外向きのデータがバッファリミットを超えていたら切断されます。
(net.cppの中で if (vSend.size() > SendBufferSize()) を検索)