Skip to content

Commit 4538e45

Browse files
committed
Add -checklevel and improve -checkblocks
-checkblocks now takes a numeric argument: the number of blocks that must be verified at the end of the chain. Default is 2500, and 0 means all blocks. -checklevel specifies how thorough the verification must be: 0: only check whether the block exists on disk 1: verify block validity (default) 2: verify transaction index validity 3: check transaction hashes 4: check whether spent txouts were spent within the main chain 5: check whether all prevouts are marked spent 6: check whether spent txouts were spent by a valid transaction that consumes them
1 parent 100da73 commit 4538e45

File tree

2 files changed

+100
-3
lines changed

2 files changed

+100
-3
lines changed

src/db.cpp

Lines changed: 97 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -580,19 +580,114 @@ bool CTxDB::LoadBlockIndex()
580580
ReadBestInvalidWork(bnBestInvalidWork);
581581

582582
// Verify blocks in the best chain
583+
int nCheckLevel = GetArg("-checklevel", 1);
584+
int nCheckDepth = GetArg( "-checkblocks", 2500);
585+
if (nCheckDepth == 0)
586+
nCheckDepth = 1000000000; // suffices until the year 19000
587+
if (nCheckDepth > nBestHeight)
588+
nCheckDepth = nBestHeight;
589+
printf("Verifying last %i blocks at level %i\n", nCheckDepth, nCheckLevel);
583590
CBlockIndex* pindexFork = NULL;
591+
map<pair<unsigned int, unsigned int>, CBlockIndex*> mapBlockPos;
584592
for (CBlockIndex* pindex = pindexBest; pindex && pindex->pprev; pindex = pindex->pprev)
585593
{
586-
if (pindex->nHeight < nBestHeight-2500 && !mapArgs.count("-checkblocks"))
594+
if (pindex->nHeight < nBestHeight-nCheckDepth)
587595
break;
588596
CBlock block;
589597
if (!block.ReadFromDisk(pindex))
590598
return error("LoadBlockIndex() : block.ReadFromDisk failed");
591-
if (!block.CheckBlock())
599+
// check level 1: verify block validity
600+
if (nCheckLevel>0 && !block.CheckBlock())
592601
{
593602
printf("LoadBlockIndex() : *** found bad block at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString().c_str());
594603
pindexFork = pindex->pprev;
595604
}
605+
// check level 2: verify transaction index validity
606+
if (nCheckLevel>1)
607+
{
608+
pair<unsigned int, unsigned int> pos = make_pair(pindex->nFile, pindex->nBlockPos);
609+
mapBlockPos[pos] = pindex;
610+
BOOST_FOREACH(const CTransaction &tx, block.vtx)
611+
{
612+
uint256 hashTx = tx.GetHash();
613+
CTxIndex txindex;
614+
if (ReadTxIndex(hashTx, txindex))
615+
{
616+
// check level 3: checker transaction hashes
617+
if (nCheckLevel>2 || pindex->nFile != txindex.pos.nFile || pindex->nBlockPos != txindex.pos.nBlockPos)
618+
{
619+
// either an error or a duplicate transaction
620+
CTransaction txFound;
621+
if (!txFound.ReadFromDisk(txindex.pos))
622+
{
623+
printf("LoadBlockIndex() : *** cannot read mislocated transaction %s\n", hashTx.ToString().c_str());
624+
pindexFork = pindex->pprev;
625+
}
626+
else
627+
if (txFound.GetHash() != hashTx) // not a duplicate tx
628+
{
629+
printf("LoadBlockIndex(): *** invalid tx position for %s\n", hashTx.ToString().c_str());
630+
pindexFork = pindex->pprev;
631+
}
632+
}
633+
// check level 4: check whether spent txouts were spent within the main chain
634+
int nOutput = 0;
635+
if (nCheckLevel>3)
636+
BOOST_FOREACH(const CDiskTxPos &txpos, txindex.vSpent)
637+
{
638+
if (!txpos.IsNull())
639+
{
640+
pair<unsigned int, unsigned int> posFind = make_pair(txpos.nFile, txpos.nBlockPos);
641+
if (!mapBlockPos.count(posFind))
642+
{
643+
printf("LoadBlockIndex(): *** found bad spend at %d, hashBlock=%s, hashTx=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString().c_str(), hashTx.ToString().c_str());
644+
pindexFork = pindex->pprev;
645+
}
646+
// check level 6: check whether spent txouts were spent by a valid transaction that consume them
647+
if (nCheckLevel>5)
648+
{
649+
CTransaction txSpend;
650+
if (!txSpend.ReadFromDisk(txpos))
651+
{
652+
printf("LoadBlockIndex(): *** cannot read spending transaction of %s:%i from disk\n", hashTx.ToString().c_str(), nOutput);
653+
pindexFork = pindex->pprev;
654+
}
655+
else if (!txSpend.CheckTransaction())
656+
{
657+
printf("LoadBlockIndex(): *** spending transaction of %s:%i is invalid\n", hashTx.ToString().c_str(), nOutput);
658+
pindexFork = pindex->pprev;
659+
}
660+
else
661+
{
662+
bool fFound = false;
663+
BOOST_FOREACH(const CTxIn &txin, txSpend.vin)
664+
if (txin.prevout.hash == hashTx && txin.prevout.n == nOutput)
665+
fFound = true;
666+
if (!fFound)
667+
{
668+
printf("LoadBlockIndex(): *** spending transaction of %s:%i does not spend it\n", hashTx.ToString().c_str(), nOutput);
669+
pindexFork = pindex->pprev;
670+
}
671+
}
672+
}
673+
}
674+
nOutput++;
675+
}
676+
}
677+
// check level 5: check whether all prevouts are marked spent
678+
if (nCheckLevel>4)
679+
BOOST_FOREACH(const CTxIn &txin, tx.vin)
680+
{
681+
CTxIndex txindex;
682+
if (ReadTxIndex(txin.prevout.hash, txindex))
683+
if (txindex.vSpent.size()-1 < txin.prevout.n || txindex.vSpent[txin.prevout.n].IsNull())
684+
{
685+
printf("LoadBlockIndex(): *** found unspent prevout %s:%i in %s\n", txin.prevout.hash.ToString().c_str(), txin.prevout.n, hashTx.ToString().c_str());
686+
pindexFork = pindex->pprev;
687+
}
688+
}
689+
}
690+
}
596691
}
597692
if (pindexFork)
598693
{

src/init.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,9 @@ bool AppInit2(int argc, char* argv[])
222222
" -rpcconnect=<ip> \t " + _("Send commands to node running on <ip> (default: 127.0.0.1)") + "\n" +
223223
" -blocknotify=<cmd> " + _("Execute command when the best block changes (%s in cmd is replaced by block hash)") + "\n" +
224224
" -keypool=<n> \t " + _("Set key pool size to <n> (default: 100)") + "\n" +
225-
" -rescan \t " + _("Rescan the block chain for missing wallet transactions") + "\n";
225+
" -rescan \t " + _("Rescan the block chain for missing wallet transactions") + "\n" +
226+
" -checkblocks=<n> \t\t " + _("How many blocks to check at startup (default: 2500, 0 = all)") + "\n" +
227+
" -checklevel=<n> \t\t " + _("How thorough the block verification is (0-6, default: 1)") + "\n";
226228

227229
#ifdef USE_SSL
228230
strUsage += string() +

0 commit comments

Comments
 (0)