原始文献 / 论坛帖 / Re: [PATCH] Automatic block validation

Re: [PATCH] Automatic block validation

Bitcointalk · 2010-08-16 15:25:54 UTC

AuthorSatoshi Nakamoto
TitleRe: [PATCH] Automatic block validation
Date2010-08-16 15:25:54 UTC
ForumBitcointalk · 原文

这条路不好走。

我们得制造一次 reorg,把那条非法链断开。

这种代码这辈子几乎测不到,又相当 intricate,越简单、越安全越好。

我的想法是这样的(还没测)。它检查主链上所有块。如果发现坏块,就把那条链所有块的 bnChainWork 置 0,让它再也赢不了 best chain,同时把 best chain work 降到分叉点,这样分叉之后任何新块都会触发 reorg。(不实际做一次 reorg 就改不了 pindexBest。)

还不完美。它还得再收到一个合法块才能触发 reorg。

也可能在检查完直接调 AddToBlockIndex 或 Reorganize,但那要小心得多。我大概会把 AddToBlockIndex 里设新 best block 的部分拆出来,用那个办法,而不是下面这段代码。

代码:(以下保留英文原文)

bool CTxDB::LoadBlockIndex()
{
...

// Verify blocks in the main chain
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;
}

英文原文

That's a difficult approach.

We need to cause a reorg, which will disconnect the invalid chain.

This is code that will rarely ever get tested, and is fairly intricate, so something simple and safe is best.

Here's what I was thinking of.  (I haven't tested this yet)  It checks all the blocks in the main chain.  If it finds a bad one, it sets all that chain's bnChainWork to 0 so it can't win best chain again, and it reduces best chain work to the fork level so any new block after the fork will cause a reorg.  (It can't change pindexBest without actually doing a reorg)

This isn't perfect yet.  It still needs to receive one valid block to trigger the reorg.

It would probably be possible to initiate an AddToBlockIndex or Reorganize after the check, but it would require a lot more careful attention.  I probably should break out part of AddToBlockIndex that sets the new best block.  I'll probably end up doing that instead of the code below.

Code:bool CTxDB::LoadBlockIndex()
{
    ...

// Verify blocks in the main chain
    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;
}