「Satoshi Client Block Exchange」の版間の差分
細 (1版 をインポートしました) |
(→バッチ継続メカニズム) |
||
(4人の利用者による、間の14版が非表示) | |||
1行目: | 1行目: | ||
− | + | この記事では、ノード間でどのようにブロックが交換されるかについて説明します。ブロックの検証方法の詳細については、「プロトコルルール」を参照してください。 | |
− | |||
− | |||
− | + | 初期接続時に、接続がインバウンド[1]でなかった場合、つまり接続がローカルノードによって開始された場合、バージョンメッセージはすぐに送信するためにキューに入れられます。リモートノードがバージョンメッセージを受信すると、それはそれ自身のバージョンメッセージで応答する[2] | |
− | |||
− | |||
− | |||
− | + | ノードが「バージョン」メッセージを受信すると、ノードは「getblocks」要求をリモートノードに送信することができる。 | |
− | |||
− | + | ノードは、まだどのノードにも初期getblocks要求を送信していません。 | |
− | + | または、これは唯一のアクティブノード接続です。おそらく、ノードはこの接続に先立って接続がゼロであったため、おそらく長時間切断されていた可能性があります。それで、それはブロックが追いつくように求めるでしょう。 | |
+ | getblocksメッセージは、遠隔ノートがノード間の最新の共通ブロックを見つけるのを助けるために、要求側ノードが既に所有している複数のブロックハッシュを含む。ハッシュのリストは、最新のブロックから始まり、10に戻り、起点ブロックに達するまで指数関数的に2倍になります。[3]両方のノードは起源ブロックでハードコードされているので、そこでの開始が最も少ないことが保証されています。そのブロックが何らかの理由で一致しない場合、ブロックは交換されません。 | ||
− | + | Hello my family member! I want to say that this article is amazing, great written and come with almost all significant infos. Id like to peer extra posts like this . ckbafbbefakakffd | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | + | Hello! | |
− | + | Hello! | |
− | |||
− | |||
− | |||
− | |||
− | + | ==失速の回復 == | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | + | リモートノードが「バッチ継続メカニズム」を守らないなどの何らかの理由でバッチ処理が中断された場合、または切断が発生した場合は、プロセスを再起動する方法があります。 新しいブロックが解決され、[16]の周りに宣伝されると、後ろにあるノードは "inv"の新しいブロックに気づき、メッセージを送信したノードから "getblocks"更新を要求するようトリガーします。 これは、後ろにあるノードが現在あるブロックチェーンのどこからでもブロックが送信されるようにします。 | |
− | |||
− | |||
− | |||
− | |||
− | + | == ロングオーファンチェーン == | |
− | |||
− | |||
− | + | さまざまなテストでは、ブロックチェーン上でかなり遅れているノードを検出することが比較的一般的であると分かっています(おそらく10人に1人以上)。これはおそらくキャッチアップの過程にあるためです。うまく接続されたノードには少なくとも8つの接続と最大で十数の接続があるため、新しいノードが追いついている別のノードに接続する可能性は非常に高いです。 | |
− | + | 追いついているノードは、メイン・チェーン内のブロックを他のすべてのノードに受け入れるので、処理中のブロックをアドバタイズします。[16]特定のチェックポイントの前に古いブロックを広告するのを防ぐコードがありますが、ブロックの高さがリモートノードの現在の最高の高さから2000ブロックを差し引いたものであれば、ブロックにはリモートノードにブロックを広告する節もあります。これは、たとえ両方が古いブロックを処理していても、ノードが他のノードに追いつくのを助けることを可能にするように見える。 | |
− | |||
− | + | これらの広告により、ローカル・ノードはリモート・ノードからこれらのブロックを要求します。これは、ローカルで処理されたものと比較して将来的にブロックされる可能性があります。ブロックが要求される方法のため、リモートノードは応答して大きなブロックのバッチを送信し、ブロックが最後に達するまでブロックをローカルノードに送信し続けます。これは、ローカルノードが別のノードからメインチェーン上の以前のブロックをダウンロードしているときに発生する可能性が高いことに注意してください。そのプロセスは最終的に孤立チェーンに追いつき、すべての孤立ブロックを再検証して接続する非常に長い操作を生成する可能性があります。 1万ブロック以上の孤立した鎖が処理に1時間以上かかる。 | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | + | したがって、両方のノードが互いに話し合っている2つのノードは、特にどちらか一方が遠く、もう一方が他方よりはるかに遠い場合に、最適ではない対話につながる可能性があります。 | |
− | |||
− | |||
− | |||
− | == | + | ==洪水制限効果 == |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | + | 上述のバッチ処理メカニズムがあっても、ブロックが交換されている間にリモートノードがローカル受信バッファをオーバーフローさせるというシナリオが発生します。 | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
+ | 例えば、リモートノードが「追いついている」場合、特定の状況でローカルノードに処理する各ブロックをアドバタイズします(上記[17]を参照)。 ローカルノードは、それらのブロックのそれぞれを直ちに要求する。 これらのブロックをあまりにも多く要求しているローカルノードに対する保護はありません。 リモート・ノードは、要求されたすべてのブロックを送信します。 この状況では、ローカル・ノードが処理する時間が過ぎる前に、リモート・ノードが過度に多くのブロックを送信することに対する保護はありません。 | ||
− | + | ローカル受信バッファがいっぱいになる可能性があります。 ローカルノードが受信バッファがいっぱいであることに気付くと、そのノード接続は切断されます。[18] fDisconnectフラグをセットすると、バッファが空になったら[19]、ソケットは閉じます。 | |
− | + | ==パフォーマンス == | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
+ | パフォーマンス | ||
+ | 2011年9月1日現在、Comcastケーブルインターネット接続を使用してUbuntuを実行しているサーバークラスのコンピュータでは、ブロックチェーンをダウンロードして処理するのに10時間以上かかります。ダウンロードプロセスの初期段階でボトルネックがどのようなものかは議論の余地がありますが、最近のブロックの処理からは、ネットワークが最も遅いインターネット接続以外のボトルネックではないことは明らかです。 | ||
− | + | ブロックは、一度ダウンロードされると処理に平均して1秒以上かかる[20]しかし、ブロックの平均サイズは2011年8月にわずか24キロバイトです.24Kをダウンロードするのに1秒かかることはありません。また、テストでは、メッセージループごとに処理されるブロックの非常に大きなキューが明らかになります。スレッドがソケットに到着したときにキューからスレッドを引き出していた場合に期待されるものではありません。 | |
− | + | 問題がネットワークのパフォーマンスであると信じさせる多くの「偽の信号」があります。最初の誤った信号は、2011年8月現在、ダウンロードされたブロックの最初の60〜70%のほぼすべてが非常に小さいことです。最近の平均ブロックサイズは約100倍です!だから、突然、ほぼすべてのブロックレートは非常に高速から非常に遅くになります。何かが間違っているように見えます。現実には、ブロック処理の速度をキロバイト単位で測定すると、速度は比較的一定です。 | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | + | もう1つの誤った信号は、ノードごとに1つずつメッセージキューが完了するまで処理されるという事実に関連しています。これは、他のノードからのメッセージの大きなバックアップをもたらす可能性があります。したがって、他のノードがサービスされるにつれて、長期間にわたるブロックの増加が長時間にわたってフリーズする可能性があります。ブロックダウンロードは、通常、1つのリモートノードから(少なくとも、鉱山者または他の中継またはダウンロードノードが遅延ブロックを宣伝してプロセスを中断するまで)、すべての作業が1つのノード上にあることを考えてください。ノードからブロックを処理することが速くなり、 "addr"メッセージが他のノードから処理され、他の作業が完了すると停止するように見えます。しかし何かが間違っているように見えます。 | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | + | また、上記の孤立効果は、孤立チェーンが接続されるまで、何も表示せずに過剰なブロック処理につながる可能性があります。また、おそらく処理ブロックであるか、マシンや接続が遅いために、応答が遅いノードに陥ることもあります。 | |
− | |||
− | |||
+ | 上記のすべてが、ブロックダウンロードプロセスでの「ジッタ」に大きく寄与します。これは、一定のダウンロード速度よりもユーザーの不満を感じます。 | ||
− | == | + | ==脚注== |
− | + | 脚注 | |
− | + | 1. pfrom-> fInboundを参照してください。ここで、pfromはCNodeです。 | |
− | |||
− | + | 2. main.cppのProcessMessage()を参照してください。strCommand == "version"となります。 | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | + | 3. main.hのCBlockLocatorを参照してください。 | |
− | |||
− | |||
− | |||
+ | 4.メッセージ:main.cppのSendMessageのinventoryを参照してください。 | ||
− | + | 5. main.cppのSendMessageの最後にあるMessage:getdataを参照してください。 | |
− | + | 6. net.hのCNode :: AskForを参照してください。 | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | + | 7. main.cppのProcessMessage()を参照してください。strCommand == "getblocks"となります。 | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | + | 8.参照 | |
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
int nLimit = 500 + locator.GetDistanceBack(); | int nLimit = 500 + locator.GetDistanceBack(); | ||
in ProcessMessage in main.cpp where strCommand =="getblocks". | in ProcessMessage in main.cpp where strCommand =="getblocks". | ||
− | 9. | + | 9. 参照 |
if (--nLimit <= 0 || nBytes >= SendBufferSize()/2) | if (--nLimit <= 0 || nBytes >= SendBufferSize()/2) | ||
in ProcessMessage() in main.cpp where strCommand =="getblocks". | in ProcessMessage() in main.cpp where strCommand =="getblocks". | ||
− | 10. | + | 10. 参照 |
inline unsigned int SendBufferSize() { | inline unsigned int SendBufferSize() { | ||
return 1000*GetArg("-maxsendbuffer", 10*1000); } | return 1000*GetArg("-maxsendbuffer", 10*1000); } | ||
in net.h. | in net.h. | ||
− | 11. | + | 11.参照 pfrom->hashContinue = pindex->GetBlockHash(); |
in ProcessMessage() in main.cpp where strCommand =="getblocks". | in ProcessMessage() in main.cpp where strCommand =="getblocks". | ||
− | 12. | + | 12. 参照: if (inv.hash == pfrom->hashContinue) |
in ProcessMessage() in main.cpp where strCommand =="getdata". | in ProcessMessage() in main.cpp where strCommand =="getdata". | ||
− | 13. | + | 13. 参照: |
// Ask this guy to fill in what we're missing | // Ask this guy to fill in what we're missing | ||
if (pfrom) | if (pfrom) | ||
253行目: | 97行目: | ||
in ProcessBlock() in main.cpp. | in ProcessBlock() in main.cpp. | ||
− | 14. | + | 14. 参照: |
else if (inv.type == MSG_BLOCK && mapOrphanBlocks.count(inv.hash)) | else if (inv.type == MSG_BLOCK && mapOrphanBlocks.count(inv.hash)) | ||
pfrom->PushGetBlocks(pindexBest, GetOrphanRoot(mapOrphanBlocks[inv.hash])); | pfrom->PushGetBlocks(pindexBest, GetOrphanRoot(mapOrphanBlocks[inv.hash])); | ||
in ProcessMessage() in main.cpp where strCommand =="inv". | in ProcessMessage() in main.cpp where strCommand =="inv". | ||
− | 15. | + | 15. 参照: |
// Recursively process any orphan blocks that depended on this one | // Recursively process any orphan blocks that depended on this one | ||
in ProcessBlock() in main.cpp. | in ProcessBlock() in main.cpp. | ||
− | 16. | + | 16. 参照the last block of code in AcceptBlock in main.cpp. |
− | 17. | + | 17. 参照: |
if (nBestHeight > (pnode->nStartingHeight != -1 ? pnode->nStartingHeight - 2000 : 134444)) | if (nBestHeight > (pnode->nStartingHeight != -1 ? pnode->nStartingHeight - 2000 : 134444)) | ||
in AcceptBlock() in main.cpp. | in AcceptBlock() in main.cpp. | ||
− | 18. | + | 18. 参照: |
if (nPos > ReceiveBufferSize()) { | if (nPos > ReceiveBufferSize()) { | ||
in ThreadSocketHandler2() in net.cpp. | in ThreadSocketHandler2() in net.cpp. | ||
− | 19. | + | 19. 参照: |
if (pnode->fDisconnect || | if (pnode->fDisconnect || | ||
(pnode->GetRefCount() <= 0 && pnode->vRecv.empty() && pnode->vSend.empty())) | (pnode->GetRefCount() <= 0 && pnode->vRecv.empty() && pnode->vSend.empty())) |
2018年10月12日 (金) 13:30時点における最新版
この記事では、ノード間でどのようにブロックが交換されるかについて説明します。ブロックの検証方法の詳細については、「プロトコルルール」を参照してください。
初期接続時に、接続がインバウンド[1]でなかった場合、つまり接続がローカルノードによって開始された場合、バージョンメッセージはすぐに送信するためにキューに入れられます。リモートノードがバージョンメッセージを受信すると、それはそれ自身のバージョンメッセージで応答する[2]
ノードが「バージョン」メッセージを受信すると、ノードは「getblocks」要求をリモートノードに送信することができる。
ノードは、まだどのノードにも初期getblocks要求を送信していません。 または、これは唯一のアクティブノード接続です。おそらく、ノードはこの接続に先立って接続がゼロであったため、おそらく長時間切断されていた可能性があります。それで、それはブロックが追いつくように求めるでしょう。 getblocksメッセージは、遠隔ノートがノード間の最新の共通ブロックを見つけるのを助けるために、要求側ノードが既に所有している複数のブロックハッシュを含む。ハッシュのリストは、最新のブロックから始まり、10に戻り、起点ブロックに達するまで指数関数的に2倍になります。[3]両方のノードは起源ブロックでハードコードされているので、そこでの開始が最も少ないことが保証されています。そのブロックが何らかの理由で一致しない場合、ブロックは交換されません。
Hello my family member! I want to say that this article is amazing, great written and come with almost all significant infos. Id like to peer extra posts like this . ckbafbbefakakffd
Hello!
Hello!
失速の回復[編集]
リモートノードが「バッチ継続メカニズム」を守らないなどの何らかの理由でバッチ処理が中断された場合、または切断が発生した場合は、プロセスを再起動する方法があります。 新しいブロックが解決され、[16]の周りに宣伝されると、後ろにあるノードは "inv"の新しいブロックに気づき、メッセージを送信したノードから "getblocks"更新を要求するようトリガーします。 これは、後ろにあるノードが現在あるブロックチェーンのどこからでもブロックが送信されるようにします。
ロングオーファンチェーン[編集]
さまざまなテストでは、ブロックチェーン上でかなり遅れているノードを検出することが比較的一般的であると分かっています(おそらく10人に1人以上)。これはおそらくキャッチアップの過程にあるためです。うまく接続されたノードには少なくとも8つの接続と最大で十数の接続があるため、新しいノードが追いついている別のノードに接続する可能性は非常に高いです。
追いついているノードは、メイン・チェーン内のブロックを他のすべてのノードに受け入れるので、処理中のブロックをアドバタイズします。[16]特定のチェックポイントの前に古いブロックを広告するのを防ぐコードがありますが、ブロックの高さがリモートノードの現在の最高の高さから2000ブロックを差し引いたものであれば、ブロックにはリモートノードにブロックを広告する節もあります。これは、たとえ両方が古いブロックを処理していても、ノードが他のノードに追いつくのを助けることを可能にするように見える。
これらの広告により、ローカル・ノードはリモート・ノードからこれらのブロックを要求します。これは、ローカルで処理されたものと比較して将来的にブロックされる可能性があります。ブロックが要求される方法のため、リモートノードは応答して大きなブロックのバッチを送信し、ブロックが最後に達するまでブロックをローカルノードに送信し続けます。これは、ローカルノードが別のノードからメインチェーン上の以前のブロックをダウンロードしているときに発生する可能性が高いことに注意してください。そのプロセスは最終的に孤立チェーンに追いつき、すべての孤立ブロックを再検証して接続する非常に長い操作を生成する可能性があります。 1万ブロック以上の孤立した鎖が処理に1時間以上かかる。
したがって、両方のノードが互いに話し合っている2つのノードは、特にどちらか一方が遠く、もう一方が他方よりはるかに遠い場合に、最適ではない対話につながる可能性があります。
洪水制限効果[編集]
上述のバッチ処理メカニズムがあっても、ブロックが交換されている間にリモートノードがローカル受信バッファをオーバーフローさせるというシナリオが発生します。
例えば、リモートノードが「追いついている」場合、特定の状況でローカルノードに処理する各ブロックをアドバタイズします(上記[17]を参照)。 ローカルノードは、それらのブロックのそれぞれを直ちに要求する。 これらのブロックをあまりにも多く要求しているローカルノードに対する保護はありません。 リモート・ノードは、要求されたすべてのブロックを送信します。 この状況では、ローカル・ノードが処理する時間が過ぎる前に、リモート・ノードが過度に多くのブロックを送信することに対する保護はありません。
ローカル受信バッファがいっぱいになる可能性があります。 ローカルノードが受信バッファがいっぱいであることに気付くと、そのノード接続は切断されます。[18] fDisconnectフラグをセットすると、バッファが空になったら[19]、ソケットは閉じます。
パフォーマンス[編集]
パフォーマンス 2011年9月1日現在、Comcastケーブルインターネット接続を使用してUbuntuを実行しているサーバークラスのコンピュータでは、ブロックチェーンをダウンロードして処理するのに10時間以上かかります。ダウンロードプロセスの初期段階でボトルネックがどのようなものかは議論の余地がありますが、最近のブロックの処理からは、ネットワークが最も遅いインターネット接続以外のボトルネックではないことは明らかです。
ブロックは、一度ダウンロードされると処理に平均して1秒以上かかる[20]しかし、ブロックの平均サイズは2011年8月にわずか24キロバイトです.24Kをダウンロードするのに1秒かかることはありません。また、テストでは、メッセージループごとに処理されるブロックの非常に大きなキューが明らかになります。スレッドがソケットに到着したときにキューからスレッドを引き出していた場合に期待されるものではありません。
問題がネットワークのパフォーマンスであると信じさせる多くの「偽の信号」があります。最初の誤った信号は、2011年8月現在、ダウンロードされたブロックの最初の60〜70%のほぼすべてが非常に小さいことです。最近の平均ブロックサイズは約100倍です!だから、突然、ほぼすべてのブロックレートは非常に高速から非常に遅くになります。何かが間違っているように見えます。現実には、ブロック処理の速度をキロバイト単位で測定すると、速度は比較的一定です。
もう1つの誤った信号は、ノードごとに1つずつメッセージキューが完了するまで処理されるという事実に関連しています。これは、他のノードからのメッセージの大きなバックアップをもたらす可能性があります。したがって、他のノードがサービスされるにつれて、長期間にわたるブロックの増加が長時間にわたってフリーズする可能性があります。ブロックダウンロードは、通常、1つのリモートノードから(少なくとも、鉱山者または他の中継またはダウンロードノードが遅延ブロックを宣伝してプロセスを中断するまで)、すべての作業が1つのノード上にあることを考えてください。ノードからブロックを処理することが速くなり、 "addr"メッセージが他のノードから処理され、他の作業が完了すると停止するように見えます。しかし何かが間違っているように見えます。
また、上記の孤立効果は、孤立チェーンが接続されるまで、何も表示せずに過剰なブロック処理につながる可能性があります。また、おそらく処理ブロックであるか、マシンや接続が遅いために、応答が遅いノードに陥ることもあります。
上記のすべてが、ブロックダウンロードプロセスでの「ジッタ」に大きく寄与します。これは、一定のダウンロード速度よりもユーザーの不満を感じます。
脚注[編集]
脚注 1. pfrom-> fInboundを参照してください。ここで、pfromはCNodeです。
2. main.cppのProcessMessage()を参照してください。strCommand == "version"となります。
3. main.hのCBlockLocatorを参照してください。
4.メッセージ:main.cppのSendMessageのinventoryを参照してください。
5. main.cppのSendMessageの最後にあるMessage:getdataを参照してください。
6. net.hのCNode :: AskForを参照してください。
7. main.cppのProcessMessage()を参照してください。strCommand == "getblocks"となります。
8.参照
int nLimit = 500 + locator.GetDistanceBack();
in ProcessMessage in main.cpp where strCommand =="getblocks".
9. 参照
if (--nLimit <= 0 || nBytes >= SendBufferSize()/2)
in ProcessMessage() in main.cpp where strCommand =="getblocks".
10. 参照
inline unsigned int SendBufferSize() { return 1000*GetArg("-maxsendbuffer", 10*1000); }
in net.h.
11.参照 pfrom->hashContinue = pindex->GetBlockHash();
in ProcessMessage() in main.cpp where strCommand =="getblocks".
12. 参照: if (inv.hash == pfrom->hashContinue)
in ProcessMessage() in main.cpp where strCommand =="getdata".
13. 参照:
// Ask this guy to fill in what we're missing if (pfrom) pfrom->PushGetBlocks(pindexBest, GetOrphanRoot(pblock2));
in ProcessBlock() in main.cpp.
14. 参照:
else if (inv.type == MSG_BLOCK && mapOrphanBlocks.count(inv.hash)) pfrom->PushGetBlocks(pindexBest, GetOrphanRoot(mapOrphanBlocks[inv.hash]));
in ProcessMessage() in main.cpp where strCommand =="inv".
15. 参照:
// Recursively process any orphan blocks that depended on this one
in ProcessBlock() in main.cpp.
16. 参照the last block of code in AcceptBlock in main.cpp.
17. 参照:
if (nBestHeight > (pnode->nStartingHeight != -1 ? pnode->nStartingHeight - 2000 : 134444)) in AcceptBlock() in main.cpp.
18. 参照:
if (nPos > ReceiveBufferSize()) {
in ThreadSocketHandler2() in net.cpp.
19. 参照:
if (pnode->fDisconnect || (pnode->GetRefCount() <= 0 && pnode->vRecv.empty() && pnode->vSend.empty()))
in ThreadSocketHandler2() in net.cpp.
20. This is from the authors experience and also
see https://bitcointalk.org/index.php?topic=31376.0.