Tech と Culture

テクノロジーとカルチャー

翻訳:Satoshi Clientブロック交換

次はこれ。

https://en.bitcoin.it/wiki/Satoshi_Client_Block_Exchange

大事な部分の英語が分からない。。。

誰か偉い人教えて。

Satoshi Clientブロック交換
 
1 概要
2 Inventoryメッセージ
3 ブロックバッチング
4 バッチ継続メカニズム
5 ストールリカバリ
6 ロングオーファンチェイン
7 Flood Limit効果
8 パフォーマンス
9 脚注
 
1 概要
この記事はノード間でどのようにブロックの交換が行われるかを説明します。 どのようにブロックがバリデートされるかについても詳しい情報はProtocol rulesを参照してください。
最初のコネクションで、コネクションが内向きでない場合、言い換えるとコネクションがローカルノードから始まっている場合、versionメッセージがキューイングされ、即座に送信されます。リモートのノードがversionメッセージを受信した時に、リモートのノードは自分のversionメッセージを返信します。
ノードが”version”メッセージを受信した時に、もし下記のいずれかの条件が成り立つ時、”getblocks”リクエストをリモートノードに送ります。
 1 ノードは最初のgetblocksリクエストを他のいかなるノードにも送っていない
 2 もしくは、これが唯一のアクティブなノードコネクションである。おそらくノードはこのコネクション以前にはゼロコネクションであり、おそらく長い間接続できていないと思われる。そこでキャッチアップのためにブロックを要求する。
getblocksメッセージは、リクエストしたノードがすでに所有している複数のブロックハッシュを含み、リモートノードがノード間の最後の共通するブロックを見つけ出すのを助けます。ハッシュのリストは最新のブロックから10そして次にべき上倍にジェネシスブロックに届くまで戻っていきます。両方のノードはジェネシスブロックはハードコードされているため、少なくともそこから始めることができることは保証されています。もしなんらかの理由でそのブロックが一致しない場合、ブロックは一つも交換されません。
 
2 Inventoryメッセージ
ノードはgetblocksリクエストを受信しても返信において完全なブロックを実際に送信するわけではないことに注意しましょう。ノードはリクエストに相当するブロック群のハッシュのみを含んでいる”inv”メッセージを送ります。それによって、リモートノードが持っていない(しかしまだリモートノードが完全なブロックを望んでいるとは仮定しないように)実際のブロックを送ることを検証します。
ローカルのノードが”inv”メッセージを受信した時、”getdata”メッセージによって実際のブロックをリクエストします。下記を参照。
しかし、最初にローカルノードによって送られた”getblocks”リクエストへのレスポンスとしてどのようにリモートノードが”inv”メッセージを送るのか、詳細を見てみましょう。リモートノードはpFrom->PushInventoryをコールします。それはブロックをリクエストしたノード(このウォークスルー中ではローカルノードです)を表しているCNodeインスタンスメソッドです。そして、PushInventoryはCNodeの変数であるvInventoryToSendへブロックハッシュを追加します。main.cpp内のSendMessages関数はvInentoryToSendの中からinvのアイテムを取り出し、vInvの変数に追加していきます。それによって実際の送信の準備ができます。変数を分離させている理由は幾つかのInventoryアイテムは(現在はトランザクションのみです)リモートノードに対して”trickled"されています。それは即座に送信される訳ではないことを意味します。vInv変数が1000エントリ満たされた時、メッセージはこれらの1000個のエントリと共にキューイングされ、ループが続きます。最後に、残ったエントリは最後の”inv”メッセージで送信されます。
ローカルノードが”inv”メッセージを受け取った時、”getdata”メッセージで実際のブロックをリクエストします。正確に言うと、ノードはpfrom->AskForをブロックをリクエストするためにコールし、そのメソッドはmapAskForの中にあるブロックのリクエストをキューイングし、多目的なSendMessage()がmapから1000エントリのバッチの”getdata”リクエストを送信します。
 

The code attempts to limit redundant requests to every 2 minutes for the same block by using a map called mapAlreadyAskedFor to delay the message if necessary.[6]

(コードはmapAlreadyAskedForをコールし必要ならばメッセージを遅らせることで2分毎に冗長に同じブロックをリクエストすることを制限しようとします????)
 
3 ブロックバッチング
“getblocks”リクエストに対応するノードは要求者への応答に対して500ブロックの制限をつけようとします。
しかしながら変わったtwistがあります。もし要求者が、メインのブランチから分岐しているように見える時、ノードは要求者のバッドチェーン、最後の共通ブロックから要求者が持っている最後のブロック(間違ったメインブランチ)、を完全に置き換えることができるように必要な多数のブロックを送ります。これは500個のメインブランチアップデートをキャッチアップするためのものに追加でおこなわれます。
加えて、送信のためにキューイングされるブロックの数に制限があるだけでなく、bitcoindはキューイングされるブロックのサイズにも制限があることに注意しましょう。これは現在のところ、送信バッファサイズ、10MB、の半分に制限されており、5MBとなっています(?)。
 
4 バッチ継続メカニズム
ノードがブロックinventoryのバッチの送信を終了した時、バッチの最後のブロックのハッシュを記録します。
 
When the node receives a request for that full block, it realizes the remove node is done with the current batch and directly queues a special "inv" message (bypassing the normal SendMessage mechanism) with one block hash entry containing the latest block hash.[12] When the remote node receives that "inv" message, it will see that it does not have that block and it it will ask for that block as described above.
 
(ノードが完全なブロックのリクエストを受信した時、現在のバッチに合わせてノードの削除が行われ最新のブロックハッシュを含む一つのブロックハッシュエントリを持った特別な”inv”メッセージ(通常のSendMessageメカニズムをバイパスして)を直接キューイングします(?)。リモートのノードがそのような”inv”メッセージを受信した時に
?????)
 
 
しかしながら、ブロックを受信して処理する時に、一つ前のブロックを持っていないことに気がつきます。そこで、最後のブロックをオーファンブロックだと記録し、ギャップを埋めるためにオーファンブロックの直前のブロックから始まるブロックをアップデートするリクエストを送ります。その結果”getblocks”リクエストを出し、全体のバッチ処理が繰り返されます。
しかしながら、twistがあります。次のバッチが終了した時に、ブロックを送信しているリモートノードは”inv”を通常は最新のブロックハッシュとともに送信し、ローカルノードはこのブロックはオーファンブロックマップの中にすでに持っていると気がつき、ブロックのリクエストをスキップし、直接ブロックのアップデートを依頼します。
 
This process will continue until the last block prior to the latest block is received. At the end of processing that block, it will notice there is an orphan that pointed to this block and will process the orphan block, (and any other orphans, recursively) thus completing the entire process.[15]
 
 
5 ストールリカバリ
もしバッチング処理がなんらかの理由で中断した場合、例えばリモートノードが"バッチ継続メカニズム”を失敗したり、接続切れが起きたりしたとき、処理を再スタートする方法があります。新しいブロックが発見されアドバタイズされる時に、”inv”の中に新しいブロックがあると気がついたいかなるノードもメッセージを送ったノードに対して”getblock”アップデートをリクエストするトリガーをかけます。それはノードが現在持っているブロックチェーンのいかなる場所からでもブロックを送信させることができます。
 
6 長いオーファンチェイン
多数のテストにおいて、ブロックチェーンの同期が非常に遅れているノードを発見することが頻繁に起きる(十回に一回以上)ということが分かっています。おそらくそれらのノードはキャッチアップの最中です。きちんと接続されたノードは少なくとも8以上のコネクションをもっていますので、新しいノードが他のキャッチアップ中のノードに接続することはしばしば起こります。
キャッチアップ中のノードは自身がメインチェーンとして受け入れたブロックを他の全てのノードに対してアドバタイズします。あるチェックポイント以前に古いブロックをアドバタイズするのを防ぐコードが存在していますが、そのコードはもしブロック高さがリモートノードの現在の最大のブロック高さマイナス2000を超えていればリモートノードに対してアドバタイズするという条項を持っています。これは、両者が古いブロックを処理中であっても、ノードは他のノードのキャッチアップを助けることを許しているということです。
 
These advertisements cause the local node to request those blocks from the remote node, which could be blocks well into the future compared to what has been processed locally.
 
(これらのアドバタイズにより、ローカルノードはこれらのブロックをリモートノードにリクエストします。….????  。)
 
ブロックがリクエストされる方法により、リモートノードは応答として、大きなブロックのバッチを送信します。そして最後までローカルノードに対して続けて送信します。ローカルノードがメインチェーンのブロックを同時にダウンロードしていることが起こり得ることに注意しましょう。その処理は次第にオーファンチェインをキャッチアップし、非常に、非常に長い再評価のオペレーションを生み出し、全てのオーファンブロックとつながります。
一万を超える長さのオーファンチェインでは、一時間を超える処理になることもあり得ます。
それゆえ、二つのキャッチアップ中のノードがお互いにコミュニケーションを取っている時に、Suboptimalなインタラクションに陥ることがあり得ます。特に、片側がひじょうに遅れていて、もう一方が相手よりだいぶ進んでいる場合に。
 
7 Flood Limit Effects
上記のバッチングメカニズムをもってしても、ブロックの交換の際にリモートノードがローカルの受信バッファをオーバーフローさせることが起き得ます。
例えば、リモートノードがキャッチアップ中の時、ある条件では(上記[17]参照)ローカルノードに対して全てのブロックをアドバタイズします。ローカルノードはそれぞれのブロックを即座にリクエストするでしょう。ローカルノードがこれらのブロックを多すぎるリクエストすることを止める手立てはありません。リモートノードはリクエストされたブロックを全て送るでしょう。この状況下では、リモートノードがローカルノードが処理が終わる前にあまりにたくさんのブロックを送ることを防ぐ手立てはありません。
ローカル受信バッファはいっぱいになることがあり得ます。ローカルノードが受信バッファが一杯になったことに木がついた時、ノードのコネクションを切断します。もし、fDisconnectフラグが建てられた場合、一度バッファは空にされソケットは閉じられます。
 
8 パフォーマンス
2011年9月1日現在、circa 2005のサーバークラスのコンピュータで、コムキャストケーブルインターネットに接続したUbuntuにおいて、ブロックチェーンのダウンロード処理に10時間以上かかります。
 

While it is debatable what the bottleneck is early in the download process, it is clear from the processing of recent blocks that the network is not the bottleneck for all but the slowest internet connections.

(??????????)
 
ブロックは平均してダウンロードするのに一秒以上かかります。しかしながら、2011年の8月で、平均的なブロックサイズは24KBです。24Kバイトをダウンロードするのに1秒はかかりません。
 
Also, testing reveals very large queues of blocks being processed per message loop, which is not what you would expect if the thread was pulling them out of the queue as they arrive on the sockets.
(???????)
 
ネットワークパフォーマンスが問題であると信じる、幾つかの”false signal”が存在します。
最初のfalse signalは、2011年8月において、最初の60%〜70%のダウンロードされたブロックはひじょうに小さいです。最近の平均ブロックサイズは約100倍も大きい! そのため、突如として、ブロックレートは早い状態から非常に遅い状態になります。何か問題が起きたかのようです。実際のところ、KB単位のブロック処理のレートを計測すると、レートはほぼ定数のままであることが分かります。
 
他のfalse signalは、メッセージキューはノード毎に一つづつ完了するように処理されるという事実に関連します。このことによって、非常に大きな他のノードからのメッセージのバックアップが作成されます。
So, a long period of increasing blocks may freeze for long periods as other nodes are serviced.
(そのため、他のノードがサービスされている時に増加するブロックの時間に合わせて長い時間フリーズします。?)
 
 ブロックのダウンロードが典型的にはただ一つのリモートノードから行われ(少なくともマイナーか他のリレーノードかダウンロードノードが新しいブロックをアドバタイズしてプロセスを止めるまで)、そのため全ての処理が一つのノードで行われることを考えましょう。
また、上記のオーファン効果がオーファンチェインに接続するまで何の証拠もなしに過剰なブロック処理に導く可能性もあります。また、突如として反応の遅いノードにつながることもありえます。おそらくブロックを処理しているか、遅いマシンまたは遅いコネクションであることによります。
上記の全てがブロックダウンロードのプロセスにおいて、大きなジッタに貢献しえます。そしてそれは、一定のダウンロードレートよりもユーザ体験をフラストレーションが多いものにします。

翻訳:Satoshi Client Transaction交換

次はこれ。

Satoshi Client Transaction Exchange - Bitcoin Wiki

分からない部分あり。

Satoshi Client Transaction交換

1 概要 2 walletの送信 3 定期的なアドバタイズメント 4 リレー 5 他の参照 6 脚注

1 概要 Satoshiクライアントはローカルで生成されたトランザクションをアドバタイズし、他のノードからのトランザクションをリレーします。この記事はトランザクションの交換を取り扱う操作について説明します。 トランザクション交換は、トランザクションが標準で有効の場合のみ行われます。

2 walletの送信 クライアントは定期的にmain.cppのSendMessages()を呼び出します。それはResendWalletTransactionsを呼び出し、ローカルに生成されたトランザクションを送信します。 このルーチンは前回から新しいブロックがあるか確認し、もし存在しているならローカルのトランザクションがまだブロックに入ってないか確認し、トランザクションを全てのノードに送信します。これは30分毎に行われます。 トランザクションは最後の受信したブロックより少なくとも5分以上古い場合再ブロードキャストされます。ソートされ古いものから順に送られます。

3 定期的なアドバタイズメント クライアントは定期的にmain.cppのSendMessages()を呼び出します。そこではメッセージがリモートのノードに送られるべきか決定します。それぞれのメッセージの処理の繰り返しにおいて、一つのノードが”trickle node”として選ばれます。このノードは適切であれば”addr"メッセージ受信する唯一つのノードとなります。 inventoryのセクションでは、クライアントはtrickleノードでなければランダムに決められた1/4のトランザクションのinventoryを送信します。この場合、全てのトランザクションを受信します。 ???????

4 リレー クライアントがトランザクションを”tx”メッセージで受け取った時、RelayMessageを呼び出し、それがRelayInventoryを呼び出して、他の全てのノードに送るinventoryをキューにいれます。

5 他の参照 transation broadcasting

翻訳: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
 
インターバル計算の後、もしアドレスがすでにインターバル内にコンタクトされていれば(?)アドレスはスキップされます。
もしアドレスが一日以上古ければ、それをスキップします。もし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()) を検索)
 

翻訳:Satoshiクライアントの初期化とスタートアップ

続けてこちら。
 
Satoshiクライアントの初期化とスタートアップ
 
1 スタートアッププロセス
2  fClientモード
3  net.cppのStartNode()スレッド
4  net.cppのIRCSeedスレッド
5  net.cppのThreadSocketHandlerスレッド
6  net.cppのThreadOpenConnectionsスレッド
7  net.cppのThreadMessageHandlerスレッド
8  rpc.cppのThreadRPCServerスレッド
 
1 スタートアッププロセス
クライアントはスタートアップ時に一定の数のスレッドを作ります。アクティブなネットワークソケットの全ての読み、書きは一つのスレッドによってハンドルされます。
プログラム中のmain()のエントリポイントはinit.cppにあります。main.cppの中にmain()を探さないようにーその中には見つかりません。
main()が最初に行う事はAppInitをコールすることで、それはAppInit2をコールします。AppInit2はどのようにアプリケーションがエラーをハンドルするかに関する、たくさんの初期化の仕事をします。あるポイントでAppInit2はParseParametersをコールし、基本的な引数の幾つかがハンドリングされます。
さあ、GUIウィンドウがすでに存在しているかチェックし、もし存在していればフォアグラウンドに持ってきます。
次にbitcoinディレクトリのlock fileを生成し、もしすでにbitcoinが実行中であればメッセージを出力してイグジットします。
次にbitcoinのポートをリッスンします。もしポートがすでに使われていたり、他のエラーがあればメッセージを出力してイグジットします。
次にデータベースからIPアドレスをロードし、ブロックインデックスをロードし、それからウォレットをロードします。
次にウォレットからトップのブロックナンバーを取得します。 -rescan引数が指定された時は0になります。
Side Note: printfはutil.hで再定義されています。なのでprintfは実際にはOutputDebugStringFであり、それはもし適切であればファイルへ出力されます(util.hとutil.cppを参照)。“loop”はutil.hでfor(;;)と定義されています。
次に、もう少し初期化処理を行い、パラメータを処理し、最後にGUIのメインウィンドウを開きます。
次に、二つのスレッドを作ります。
  1. StartNode()
  2. サーバーとして動作する場合:ThreadRPCServer()
ここがこれらのスレッドが生成される唯一の場所です。
StartNode()はnet.cppの中にあり、ThreadRPCServer()はrpc.cppの中にあります。
最後に、GUIとしてコンパイルされていなかったら、五秒間のスリープの後、無限ループに入ります。
 
2 fClient Mode
クライアントには、ブロックヘッダーのみをダウンロードするモードを許すコードが存在していることは注目に値する。この実装はlightweightクライアントで使われることを意図しており、そこでは全てのブロックとtransactionを検証やストアする必要がない。これはfClient変数でコントロールでき、現在はfalseにハードコードされている。これは現在はまだコードが完成しているとは想定されていないということです。このモードはfClientモードと知られており、Simplified Payment Verification(SPV)モードという言葉もlightweightクライアントを表現するのに使われています。
 
3 net.cppのStartNode()スレッド
StartNodeはネットワーキングスレッドの一種のマスターのようなものだ。
最初にCNodeを作り、コミュニケーションを取り扱うためにlocalhost 127.0.0.1を内部アドレスとする。
次にローカルのIPアドレスを取得する。Windowsではlocal host nameを使用して見つける。Linuxでは、loopbackインターフェースでない、upされているインターフェースを見つけて最初のIPアドレスとします。
次にThreadGetMyExternalIPスレッドをつくり、ローカルIPアドレスサードパーティの検証を使用して確認します。もしproxyを使用していても、接続しようとしてくるコネクションは無視するので問題ありません。
次に、もしuPnPが使用されている場合は、ThreadMapPortが作られてポートマッピングを行います。
次にThreadIRCSeedスレッドが作られてIPアドレスを交換します。
次にThreadSocketHandlerスレッドが作られて、ソケットで送信、受信を行い、コネクションを受け付けます。
次にThreadOpenConnectionsスレッドによって外向きのコネクションを初期化します。
次にThreadMessageHandlerスレッドをつくり、メッセージを処理します。
最後にもし指定していたなら、マイニングスレッドが始まります。
 
4 net.cppのIRCSeedスレッド
92.243.23.21のポート6667に接続し、チャンネルにジョインし、それからラインを読み、他のユーザを検索します。
 
5 net.cppのThreadSocketHandlerスレッド
必要なサービスを行うサービスソケットの無限ループに入ります。接続が切れたノードをハンドルします。”選択”デスクリプタリストを準備し、”選択”ヲコールシ、カンケイする全てのソケットを50msecのタイムアウトでI/O待ちします。リスニングソケット上の新しい、接続してくるコネクションを処理します。それらにCNodeを作ります。受信と送信をハンドルします。何もしないソケットをディスコネクテッド状態にします。
 
6 net.cppのThreadOpenConnectionsスレッド
パラメータ、シード、IRC等からノードを解決し、ループに入って一つづつ接続していきます。
 
7 net.cppのThreadMessageHandlerスレッド
このスレッドは全てのノードをとおして、main.cppのProcessMessages(pnode)をコールします。そこではノード受信キュー(pFrom->vRecv)に有効なメッセージを探し、もし見つかった場合は、main.cppのProcessMessage(CNode* pfrom, string strCommand, CDataStream& vRecv)
をコールします。
それからスレッドはそれぞれのノードに対しmain.cppのSendMessagesをコールシ、それぞれのノードに対する適切なメッセージを作って送信します。
 
8 rpc.cpp内のThradRPCServerスレッド
このスレッドは少し込み入っていて、HTTP(S)+JSONRPCサーバーをboostクラスで実装しています。おそらく大半の開発者にとってはあまり馴染みのないものです。
以下のような行を見ることができます。
acceptor.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
 
また以下のような行もあります。
boost::thread api_caller(ReadHTTP, boost::ref(stream), boost::ref(mapHeaders), boost::ref(strRequest));
if(!api_caller.timed_join(boost::posix_time::seconds(GetArg(“-rpctimeout”,30))))
 
上記のコードは30秒タイムアウトをHTTPrequestを読むときに設定するためのスレッドを作ることが見て取れます。HTTPリクエストが読まれたとき、パースされ、リクエストコマンド名に対応するルーチンが呼ばれてリクエストがハンドルされます。これはシャットダウンされるまでループします。

翻訳: Network

続けてこっちも。

同じく適当なので自己責任で。

 

Network - Bitcoin Wiki

Network
 
Bitcoinトランザクションとブロックを伝達するために単純なブロードキャストネットワークを使用します。全てのコミュニケーションはTCP上で行われます。Bitcoinはポートパラメーターによって、8333以外の全てのポートを使用可能です。IpV6は Bitcoind/Bitcoin-Qt v0.7からサポートされています。
 
1 メッセージ
2 コネクション
3 標準リレー
4 最初のブロックダウンロード
5 SPVクライアント
6 ブートストラッピング
    6.1 Addr
    6.2 DNS
    6.3 IRC
7 ハートビート
8 他の参照
 
1 メッセージ
・version - プログラムのバージョンとブロック数の情報。最初に接続するときに交換される
・verack  - バージョンメッセージの応答として送られ、接続しようとしていることを知らせる
・addr     -  一つ以上のIPアドレスとポートのリスト
・inv        -  “私はこれらのブロック/トランザクションを持っています:…...” 通常は、新しいブロックもしくはトランザクションがリレーされる時のみ送られ雨r。これはリストのみであり、実データは含まれない
・getdata - 一つのブロックもしくはトランザクションのハッシュによるリクエスト
・getblocks - 一定範囲内の全てのブロックのinvのリクエスト
・getheaders - 一定範囲内の全てのブロックヘッダを含むheadersメッセージのリクエスト
・tx        - トランザクションの送信。getdataリクエストに対する応答としてのみ送られる
・headers   -  2000ブロックヘッダーまでの送信。Non-generators ブロック全体の代わりにブロックのヘッダーをダウンロードできる
・getaddr   -  (ブートストラッピングのための)アクティブピアのかたまりを含むaddrメッセージのリクエスト
・submitorder, checkorder, reply IP transactionで使用  ※現在は使用されていない
・aleart  - network alertを送る
ping - 何もしない。コネクションがまだ生きているかのチェックに使われる。コネクションが死んでいる場合、TCPエラーが発生する。
もっと詳細な技術情報はプロトコル仕様を参照のこと。
 
2 コネクション
ピアに接続するためには、自分のバージョン番号とブロック数、現在時刻を含むversionメッセージを送る。リモートのピアは、もしあなたのバージョンをによる接続を受け付ける場合は、verackメッセージを返答し、そしてリモートピア自身のversionメッセージを送ってくる。もしあなたが彼のバージョンからの接続を受け付ける場合は自分のverackメッセージを返す。
あなたの全てのピアからの時刻データは集められ、median値が(versionメッセージ以外の)Bitcoin内で時刻を使用する際に使われます。
その後、”getaddr”と”addr”メッセージを交換し、全ての知らないアドレスをストアします。 “addr”メッセージはしばしば一つのアドレスのみを含みますが、時々1000個以内のアドレスを含みます。これは交換の初期では普通のことです。
 
3 標準リレー
 誰かがトランザクションを送る時、それを含むinvメッセージを全てのピアに送ります。それらのピアはgetdataで完全なtransactionデータを要求します。それを受け取った後、もしtransactionが有効であると考えれば、彼らは彼らの全てのピアにinvメッセージでtransactionをブロードキャストします。それが続いていきます。ピアはtransactionの要求やリレーは、すでにそのtransactionを持っていない場合のみ行います。transactionはしばらくしてブロックに含まれていくとともに忘れられていくのですが、ピアは決してすでに知っているtransacctionを再ブロードキャストしません。ただしtransactionの送付者と受信者は再ブロードキャストを行います。
generatingしている(?)ものは誰でも、受信した正当なtransactinを収集し、それをブロックに含めようと働きます。誰かがブロックを発見した時、上記と同じようにそれを含むinvを全てのピアに送付します。transactionsの時と同じように働きます。
全ての人は24時間毎に、自分のIPアドレスを含む”addr”メッセージをブロードキャストします。ノードはこれらのメッセージを2つのピアにリレーし、もしそれが新しいものであるあるならばストアされます。このシステムを通して、全ての人が、ある瞬間にどのIPアドレスが接続しているかクリアな概要を持つことんいなります。ネットワークに接続したのち、あなたの最初の”addr”メッセージで全ての人のアドレスデータベースにほとんど瞬時に加えられます。
ネットワークalertは”alert”メッセージによってブロードキャストされます。”inv”のようなシステムは使われていません;これらは全てのalertを含んでいます。もし、受信したalertが有効な場合(誰かのprivate keyで署名されています)、全てのピアにリレーされます。alertが有効であるかぎり、全ての新しいコネクションに対して再ブロードキャストされます。
 
4 最初のブロックダウンロード
コネクションの最初に、あなたが知っている最新のブロックのハッシュを含む”getblocks”メッセージを送付します。もしピアがそれが最新ブロックではないと考えた場合、あなたがリストした先の500個のブロックを含む”inv”メッセージを送付します。そこで、あなたはこれら全てのブロックを”getdata”でリクエストします、ピアは”block”メッセージでそれらをあなたに送付します。あなたが、これらのブロック全てをダウンロードして処理したのち、全てのブロックを得るまで、あなたは次の”getblocks”メッセージを送付します。
 
5 SPVクライアント
BIP0037はSimple Payment Verificationによる軽量クライアントを紹介しています。SPVクライアントは残金の存在を検証するのに、完全なブロックの内容をダウンロードする必要がなく、そのかわりにブロックヘッダのチェインをリレーし、他のノードから必要なデータを得るためにbloom filterを設定します。これらのクライアントの方法は、フルノードと非常にセキュリティの高いtrustlessなコミュニケーションを可能にしますが、SPVクライアントが探している情報はどのアドレスなのかをピアが推論することに対して少し高価なプライバシーを必要とします。
MultibitやBitcoin Walletは基礎にbitcoinjライブラリを使用した、このような方法で動くwalletです。
 
6 ブートストラッピング
あなたはどのピアに接続するかを、あなたのアドレスデータベースを最後にアドレスを見た時刻によってソートし、すこしだけランダマイズして選びます。
Bitcoinはピアを見つけるのに3つの方法があります。
 6.1 Addr
上で説明されている“addr”メッセージは、IRCブートストラッピング方法とにたような効果を作り出します。ピアが参加したら必ず、早い時間に知ることができます。ただし、ピアが離脱した時はしばらくの間知ることができません。
Bitcoinは”seed nodes”として知られているアドレスリストからも立ち上げられます。もしあなたが、IRCに接続できず、一度もネットワークにつなげていない場合、クライアントはアドレスデータベースをこのリストのノードの一つにつなぐことによって更新します。
-addnodeコマンドラインオプションをマニュアルでノードを追加することに使用できる。 -connectオプションはbitcoinを特定のノードに接続することを強制する。
6.2 DNS
Bitcoinは幾つかのホスト名のIPアドレスDNSに問い合わせ、これらをアドレスのリストに追加する。これはv0.6x以降のデフォルトのseedingメカニズムである。
6.3 IRC
v0.6xのBitcoinクライアントはIRCブートストラッピングはもはやデフォルトでは有効になっていない。以下の情報は古いバージョンのために記す。
Bitcoinirc.Ifnet.orgの#bitcoin00から#bitcoin99の間のチャンネルにランダムに参加する。あなたのニックネームはあなたのIPアドレスからエンコードされている。チャンネルにいる全てのユーザのニックネームをデコードすることによって現在Bitcoinに接続しているIPアドレスのリストを得ることができる。
ポート6667で外部に接続できないサーバーのため、Ifnetサーバはポート7777でもリッスンしている。
 
7 HeartBeat
クライアントがなんらかのメッセージを発してから、もし30分以上過ぎていれば、ピアノードへのコネクションをキープするためメッセージを送信する。
もし、ピアノードと何らかのメッセージでコミュニケートしてから90分以上過ぎていれば、クライアントはコネクションが閉じたと判断する。
 

翻訳:Satoshiクライアントのノード発見

Bitcoindのノード発見の部分を勉強したいと思ったので、以下のページを翻訳してみた。少し情報が古いような気がするけど、各自自己責任でお願いします。
Satoshiクライアントのノード発見
 
1 概要
2 "getaddr"メッセージの取り扱い
3 発見方法
  3.1 ローカルクライアントの外部アドレス
  3.2 コールバックアドレスへの接続
  3.3 IRC アドレス
  3.4 DNS アドレス
  3.5 ハードコードされた "seed""アドレス
  3.6 "addr"アドバタイズメント
       3.6.1  アドレスリレー
       3.6.2   セルフブロードキャスト
       3.6.3   古いアドレスのクリーンアップ
  3.7 データベースに保持されたアドレス
  3.8 コマンドラインで与えられるアドレス
  3.9 テキストファイルで与えられるアドレス
4 他の情報
5 リファレンス
 
1 概要
Satoshiクライアントは数種類の異なる方法で、IPアドレスとノードのポートの発見を行います
1 ノードは様々な方法で自身の外部アドレスを発見する
2 ノードは接続する外部ノードのコールバックアドレスを受信する
3 ノードはIPアドレスを受信するためDNSリクエストを作る
4 ノードはソフトウェアにハードコードされたアドレスを使うことができる
5 ノードは他のノードとアドレス交換をする
6 ノードはデータベースにアドレスをストアし、スタートアップ時にそのデータベースを読む
7 ノードはコマンドラインの引数でアドレスを与えることができる
8 ノードはスタートアップ時にユーザーが与えるテキストファイルからアドレスを読む
 
Timestampはそれぞれのアドレスに対していつそのノードアドレスが最後に確認されたかを記録するために保持される。net.cpp中のAddressCurrentlyConnectedはメッセージをノードから受信した時に必ずTimestampをアップデートする。Timestampは20分以上古くなった時にアップデートされデータベースに保持される
実際にノードに接続する時にどのタイプのアドレスが上位に来るのかについてはNode Connectivityの項目を参照。
最初の項では、”getaddr”メッセージを通して、ノードがどのようにアドレスのリクエストを取り扱うのかについて記す。Timestampの役割を理解することによって、アドレスが発見された方法によってTimestampがなぜそれぞれの方法で保持されるのかがよりクリアになる。
 
2 "getaddr"メッセージの取り扱い"
ノードが”getaddr”リクエストを受信した時に、最初に過去3時間のTimestampを持つアドレスをいくつもっているかをはっきりさせる。次に、それらのアドレスを送信する。しかし、もし3時間以内に2500以上のアドレスがあった場合は、ランダムな選択で約2500個のアドレスを選択する。
 
さあ、ノードがノードアドレスを見つける方法について見てみよう
 
3 発見方法
 3.1 ローカルクライアントの外部アドレス
クライアントは自身のルーティング可能なIPアドレス情報を返すパブリックなWEBサービスを使用する
クライアントはnet.cpp中のThreadGetMyExternalIPと呼ばれるスレッドを走らせる。そこでは外部世界から見えるクライアントのIPアドレスを決定する。
最初に91.198.22.70のポート80(checkip.dyndns.org)に接続を試みる。もし接続が失敗した場合、checkip.dyndns.orgへのDNSリクエストが行われ、そのアドレスへの接続を試みる。次に74.208.43.192のポート80(www.showmyip.com)に接続を試みる。接続に失敗した場合、www.showmyip.comへのDNSリクエストが行われ、そのアドレスへの接続を試みる。
上記で試みられたそれぞれのアドレスに対して、クライアントは接続を試み、HTTPリクエストを送り、適切なレスポンスをリードし、そこからIPアドレスをパースする。もしこれが成功した場合、IPアドレスが返ってくる。IPアドレスは接続しているどれかのノードにアドバタイズされ、スレッドは終了する(???)
 3.2 コールバックアドレスへの接続
ノードが最初の”version”メッセージを受信して、コネクションを開始した時に、ノードは自分のアドレスをリモートにアドバタイズし、リモートが望んだ時にローカルのノードに接続することができるようにします。
もしリモートのバージョンが最新のものであったり、ローカルのノードが1000個のアドレスをまだ持っていない場合、自分のアドレスを送信したのちに、”getaddr”リクエストメッセージをリモートノードに送り、多数のアドレスを得ます。
 3.3 IRCアドレス
バージョン0.6.xからBitcoinクライアントはデフォルトではIRCブートストラッピングは使わなくなっているし、バージョン0.8.2からはIRCブートストラッピングは完全に取り除かれている。以下のドキュメントは過去のバージョンに対する正確性のために記されている
自身のアドレスを知ったりシェアするために、ノードはたのノードをIRCチャンネルを通して他のノードアドレスを知ることができる。 irc.cpp参照。
自分自身のアドレスを知ったのち、ノードは自身のアドレスをニックネームとして使用するための文字列にエンコードします。そして、#bitcoin00と#bitcoin99の間のIRCチャンネルにランダムに参加します。そして、WHOコマンドを発行します。それらが現れたチャンネルのスレッドはラインを読むとチャンネル内の他のノードのIPアドレスをデコードします。ノードがシャットダウンされるまでそれは繰り返します。
クライアントはIRCからアドレスを発見した時に、現在時刻をTimestampとしてアドレスにセットします。ただし、その時にペナルティとして51分が課されます。それはあたかも一時間前に発見されたかのように見えます。
 3.4 DNS Address
スタートアップにおいて、ピアノードの発見が必要な場合、クライアントは他のピアノードのアドレスを知るためにDNSリクエストを発行します。クライアントはDNSサービスのためのシードとなるホストネームを含んでいます。2012,5月17日現在、リストは以下のものを含んでいます(chainparams.cppより)
 
DNS応答は要求された名前に対して複数IPアドレスを含むことができます。
DNSによって発見されたアドレスは最初にTimestampゼロが与えられています。ですので、getaddrリクエストに対する応答でアドバタイズはされません。
 
3.5 ハードコードされたSeedアドレス
クライアントはBitcoinのノードを示すハードコードされたIPアドレスを含んでいます。
これらのアドレスは、他の方法によってアドレスが全く得られなかった時にラストリゾートとしてのみ使われます。接続をハンドリングするThreadOpenConnection2()のスレッドのループでアドレスマップが空だった時、”seed”IPアドレスがバックアップとして使用されます。
可能な時にシードノードを取り除くコードがあります。これらのノードの負荷を下げるためです。ひとたびローカルノードが十分なアドレスを得た時(おそらくシードノードから情報を得た)、シードノードとのコネクションは閉じられます。
シードアドレスは最初はゼロのTimestampが与えられます、それゆえ、”getaddr”リクエストに対する応答ではアドバタイズされません。
 
3.6 addr"アドバタイズメント
getaddrリクエストを送った後にやってくるaddrメッセージによってノードはアドレスを受け取ります。または、ノードが無償でアドレスをリレーするときに要求なしにやってくるaddrメッセージによってノードはアドレスを受け取ります。
もし、アドレスが古いバージョンのリレーからのものであった場合は無視します。もし、そこまで古いバージョンでない場合、もし1000個のアドレスをすでに持っていたら無視します。
または、1000以上のアドレスが送られてきた時も全て無視されます。
addrメッセージで受信したアドレスはTimestampを持っていますが、Timestampを直接使用はしません。
 
メッセージの中のそれぞれのアドレスに対して
      1.もしTimestampが非常に小さかったり、大きかったりした場合、5日前に設定されます
      2.Timestampから2時間を差し引いて、アドレスを追加します。
いかなるアドレスが追加される時でも、いかなる理由によっても、コードはAddAddress()をコールして、すでにアドレスが存在しているかどうかはチェックしません。net.cpp内のAddAddress()関数がそれを実行します。すでにアドレスが存在していても、アドレスのレコードをアップデートします。もし、アドレスのアドバタイズされたサービスが変わっていても(?)、それがアップデートされストアされます。
もしアドレスが過去24時間以内に見られて、Timestampが60分以上古い場合、60分過去にアップデートされます。
もしアドレスが過去24時間以内に見られておらず、Timestampが24時間以上古い場合、24時間過去にアップデートされます。
 
 3.6.1 アドレスリレー
一度アドレスが”addr”メッセージ(上記参照)によって加えられたら、それらは他のノードにリレーされます。最初に以下のような基準が設定されます。
     1.処理が行われた後、アドレスTimestampが現在時刻から60分以内である
  1.       “addr”メッセージは10個、もしくはそれ以下のアドレスを含む
  2. fGetAddrがノードにセットされていない。fGetAddrはfalseからスタートし、ノードにアドレスをリクエストした時にtrueにセットされます。そして、1000以下のアドレスをノードから受け取ったときにクリアされます
  3. アドレスはルーティング可能でないといけない
上記の基準にマッチする全てのアドレスに対して、ノードはアドレスと現在の日にち(Integerで表される)と256bitの乱数(クライアントのスタートアップ時に生成される)をハッシュする。ノードは最もハッシュの小さい値のアドレスを二つ選び、”addr”メッセージをそれらにリレーする。これはそれぞれのノードが”addr”メッセージを与えられたタイミングで二つの他のノードのみにリレーすることを保証する。そしてその二つはランダムに選択されており、ランダムな選択は少なくとも24時間毎に行われることが保証される。
 3.6.2 セルフブロードキャスト
24時間毎に、ノードは自分自身のアドレスを接続している全てのノードにアドバタイズする。
これはまた、リモートノードが持っていると思われるアドレスのリストをクリアーし、ノードのリフレッシュのトリガーとなる(?)。このコードはmain.cppのSendMessages()の中にある。
 3.6.3 古いアドレスのクリーンアップ
main.cppの中のSendMessages()において、古いアドレスをリムーブするコードが存在している。
これは3つのアクティブなコネクションがある限り、10分毎に行われる。
ノードは1000アドレスがマップされ、20秒以上消去プロセスが行われていない限り、14日以上使われていないメッセージを消去する(?)。
 
3.7 データベースに保持されたアドレス
アドレスはAddAddress()がコールされた時にデータベースに保持される。
アドレスははスタートアップの時、AppInit2()がdb.cppに存在するLoadAddresses()をコールした際に読み出される。
現在は、どれか一つのアドレスがストアされるかアップデートされる時は必ず、全てのアドレスが一度に同時にストアされるようになっています。実際のところ、AddAddressはは様々なテストで、0.01秒ほど使用することが分かっており、クライアント実行の最初の12時間で典型的には数万回呼び出されます。
 
3.8 コマンドラインで与えられるアドレス
ユーザーは接続するノードを
-addnode <ip>
のようにコマンドラインの引数で与えることができます。複数のノードが指定できます。
コマンドラインで与えられるアドレスは当初はTimestampゼロが与えられます。それゆえ、”getaddr”リクエストに対する応答でアドバタイズされません。
ユーザは、-connect <ip>コマンドライン引数でも接続するアドレスを与えることができる。複数のノードが指定できます。
-connect引数と -addnode引数の違いは、-connectが指定されたとき、アドレスはアドレスデータベースへ追加されず、ただ単に使用されます。
 
3.9 テキストファイルで与えられるアドレス
クライアントは自動的に bitcoinデータディレクトリにある“addr.txt”という名前のファイルを読み、その中にある、ノードアドレスを追加します。これらのノードは他のアドレスと比較して何の特権もありません。ただ単にプールに追加されます。
テキストファイルからロードされるアドレスは最初にTimestampゼロが与えられます。それゆえ、”getaddr”リクエストに対する応答でアドバタイズされません。
 
  1. 他の参照
Network - Bootstrapping
 
 

EthereumのRelease

いよいよ今週、Ethereumのgenesis blockが生成されて動き始めます。

https://blog.ethereum.org/2015/07/22/frontier-is-coming-what-to-expect-and-how-to-prepare/

安定稼働して商用に使用できるようになるまでには、まだまだ色々起きると思いますが、Decentralizedなコンピュータが動き始める時ということで、もしかしたらITの歴史に残るタイミングになるかもしれません。

Decentralizedなコンピュータが存在し続けることが可能なのか、可能だとしたらそれがEthereumになるのか、誰にも分かりませんが、最初の一歩が動き始めたという感じです。

Ethereumが何かについてはこちらの記事参照。

Ethereum(3) Bitcoin2.0の本命 Ethereumとは何か - Tech と Culture