Author

Topic: [PATCH] Automatic block validation (Read 8262 times)

founder
Activity: 364
Merit: 7248
August 16, 2010, 12:08:02 PM
#4
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.
This is what I ended up doing in SVN rev 139.

Instead of deleting the bad chain, I added an extra CheckBlock to ConnectBlock so bad blocks can't get back into the best chain once they're kicked out.
founder
Activity: 364
Merit: 7248
August 16, 2010, 10:25:54 AM
#3
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 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;
}
full member
Activity: 221
Merit: 102
August 15, 2010, 11:33:10 PM
#2
Hmm, it seems I am missing something important - disconnecting transactions which are no longer part of the accepted block chain. I'm going to have to work on this a bit - the naive approach of simply blasting away all TXNs, then reconnecting things is far too slow, and hits the transaction memory limit.
full member
Activity: 221
Merit: 102
August 15, 2010, 09:57:55 PM
#1
I've written a patch to help automatically validate cached blocks after validation fixes such as the one that was pushed out today. You can find it at

http://fushizen.net/~bd/blockverify.patch

or

http://github.com/bdonlan/bitcoin/commit/b205251959448ca99123f2bc95b088bf06d4ef3b

Upon first run with this patch, all blocks will be verified, and any invalid blocks, as well as blocks orphaned by removal of such blocks, will be removed from the block index. A version stamp
(BLOCK_VERIFY_TOKEN in db.cpp) will be then written to the db; this will cause the next run to skip the verification pass. Any future validation fixes can then simply bump BLOCK_VERIFY_TOKEN to force a revalidation of the block chain.

Note that I may be missing some important steps when deleting the old blocks - in particular, no attempt is made to update the wallet, or to prune stored uncommitted transactions. Review would be helpful.
Jump to: