(context post by bdonlan)
今日プッシュされたもののような検証修正の後に、キャッシュされたブロックを自動的に検証するのを助けるパッチを書いた。以下で見つけられる。
http://fushizen.net/~bd/blockverify.patch
または
http://github.com/bdonlan/bitcoin/commit/b205251959448ca99123f2bc95b088bf06d4ef3b
このパッチを適用して初めて実行すると、すべてのブロックが検証され、無効なブロックとそのようなブロックの削除によって孤立したブロックがブロックインデックスから削除される。バージョンスタンプ(db.cppのBLOCK_VERIFY_TOKEN)がdbに書き込まれ、次の実行では検証パスがスキップされる。将来の検証修正はBLOCK_VERIFY_TOKENを単にバンプするだけでブロックチェーンの再検証を強制できる。
古いブロックを削除する際に重要なステップを見落としている可能性がある — 特に、ウォレットの更新や保存された未コミットトランザクションの削除は試みていない。レビューをいただけると助かる。
うーん、重要なものを見落としていたようだ — 受け入れられたブロックチェーンの一部ではなくなったトランザクションの切断だ。もう少し作業が必要だ — すべてのTXNを単純に消し去ってから再接続するナイーブなアプローチは非常に遅く、トランザクションメモリの制限に達する。
それは難しいアプローチだ。
再編成(reorg)を起こして、無効なチェーンを切り離す必要がある。
このコードはめったにテストされず、かなり複雑なので、シンプルで安全なものが最善だ。
自分が考えていたのはこうだ。(まだテストしていない)メインチェーンのすべてのブロックをチェックする。不正なブロックが見つかった場合、そのチェーンのbnChainWorkをすべて0に設定して再びベストチェーンになれないようにし、フォークレベルまでベストチェーンワークを下げることで、フォーク後の新しいブロックが再編成を引き起こすようにする。(実際にreorgを行わずにpindexBestを変更することはできない)
これはまだ完璧ではない。reorgをトリガーするために有効なブロックを1つ受信する必要がある。
チェック後にAddToBlockIndexやReorganizeを開始することはおそらく可能だが、はるかに慎重な注意が必要になる。おそらくAddToBlockIndexの新しいベストブロックを設定する部分を分離すべきだ。おそらく以下のコードの代わりにそうすることになるだろう。
Code:bool CTxDB::LoadBlockIndex() { …
// メインチェーンのブロックを検証
vector<CBlockIndex*> vChain;
for (CBlockIndex* pindex = pindexBest; pindex && pindex->pprev; pindex = pindex->pprev)
{
vChain.push_back(pindex);
CBlock block;
if (!block.ReadFromDisk(pindex))
return error("LoadBlockIndex() : block.ReadFromDisk failed");
if (!block.CheckBlock())
{
bnBestChainWork = pindex->pprev->bnChainWork;
foreach(CBlockIndex* pindex2, vChain)
pindex2->bnChainWork = 0;
}
}
return true;
}
Quote from: satoshi on August 16, 2010, 03:25:54 PM
チェック後にAddToBlockIndexまたはReorganizeを開始することはおそらく可能だが、はるかに慎重な注意が必要になる。おそらくAddToBlockIndexの新しい最良ブロックを設定する部分を分離すべきだろう。おそらく以下のコードの代わりにそうすることになるだろう。
最終的にSVN rev 139でそのようにした。
不正なチェーンを削除する代わりに、ConnectBlockに追加のCheckBlockを加えて、不正なブロックが一度排除された後に最良チェーンに戻れないようにした。