[PATCH] ブロックの自動検証
今日プッシュされたもののような検証修正の後に、キャッシュされたブロックを自動的に検証するのを助けるパッチを書いた。以下で見つけられる。
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 の新しいベストブロックを設定する部分を分離すべきだ。おそらく以下のコードの代わりにそうすることになるだろう。
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;
} チェック後に AddToBlockIndex や Reorganize を開始することはおそらく可能だが、はるかに慎重な注意が必要になる。おそらく AddToBlockIndex の新しいベストブロックを設定する部分を分離すべきだ。おそらく以下のコードの代わりにそうすることになるだろう。
最終的に SVN rev 139 でそのようにした。
不正なチェーンを削除する代わりに、ConnectBlock に追加の CheckBlock を加えて、不正なブロックが一度排除された後に最良チェーンに戻れないようにした。