mirror of
https://github.com/twisterarmy/twister-core.git
synced 2025-01-11 07:17:53 +00:00
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
This commit is contained in:
parent
100da73677
commit
4538e45c46
99
src/db.cpp
99
src/db.cpp
@ -580,19 +580,114 @@ bool CTxDB::LoadBlockIndex()
|
|||||||
ReadBestInvalidWork(bnBestInvalidWork);
|
ReadBestInvalidWork(bnBestInvalidWork);
|
||||||
|
|
||||||
// Verify blocks in the best chain
|
// Verify blocks in the best chain
|
||||||
|
int nCheckLevel = GetArg("-checklevel", 1);
|
||||||
|
int nCheckDepth = GetArg( "-checkblocks", 2500);
|
||||||
|
if (nCheckDepth == 0)
|
||||||
|
nCheckDepth = 1000000000; // suffices until the year 19000
|
||||||
|
if (nCheckDepth > nBestHeight)
|
||||||
|
nCheckDepth = nBestHeight;
|
||||||
|
printf("Verifying last %i blocks at level %i\n", nCheckDepth, nCheckLevel);
|
||||||
CBlockIndex* pindexFork = NULL;
|
CBlockIndex* pindexFork = NULL;
|
||||||
|
map<pair<unsigned int, unsigned int>, CBlockIndex*> mapBlockPos;
|
||||||
for (CBlockIndex* pindex = pindexBest; pindex && pindex->pprev; pindex = pindex->pprev)
|
for (CBlockIndex* pindex = pindexBest; pindex && pindex->pprev; pindex = pindex->pprev)
|
||||||
{
|
{
|
||||||
if (pindex->nHeight < nBestHeight-2500 && !mapArgs.count("-checkblocks"))
|
if (pindex->nHeight < nBestHeight-nCheckDepth)
|
||||||
break;
|
break;
|
||||||
CBlock block;
|
CBlock block;
|
||||||
if (!block.ReadFromDisk(pindex))
|
if (!block.ReadFromDisk(pindex))
|
||||||
return error("LoadBlockIndex() : block.ReadFromDisk failed");
|
return error("LoadBlockIndex() : block.ReadFromDisk failed");
|
||||||
if (!block.CheckBlock())
|
// check level 1: verify block validity
|
||||||
|
if (nCheckLevel>0 && !block.CheckBlock())
|
||||||
{
|
{
|
||||||
printf("LoadBlockIndex() : *** found bad block at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString().c_str());
|
printf("LoadBlockIndex() : *** found bad block at %d, hash=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString().c_str());
|
||||||
pindexFork = pindex->pprev;
|
pindexFork = pindex->pprev;
|
||||||
}
|
}
|
||||||
|
// check level 2: verify transaction index validity
|
||||||
|
if (nCheckLevel>1)
|
||||||
|
{
|
||||||
|
pair<unsigned int, unsigned int> pos = make_pair(pindex->nFile, pindex->nBlockPos);
|
||||||
|
mapBlockPos[pos] = pindex;
|
||||||
|
BOOST_FOREACH(const CTransaction &tx, block.vtx)
|
||||||
|
{
|
||||||
|
uint256 hashTx = tx.GetHash();
|
||||||
|
CTxIndex txindex;
|
||||||
|
if (ReadTxIndex(hashTx, txindex))
|
||||||
|
{
|
||||||
|
// check level 3: checker transaction hashes
|
||||||
|
if (nCheckLevel>2 || pindex->nFile != txindex.pos.nFile || pindex->nBlockPos != txindex.pos.nBlockPos)
|
||||||
|
{
|
||||||
|
// either an error or a duplicate transaction
|
||||||
|
CTransaction txFound;
|
||||||
|
if (!txFound.ReadFromDisk(txindex.pos))
|
||||||
|
{
|
||||||
|
printf("LoadBlockIndex() : *** cannot read mislocated transaction %s\n", hashTx.ToString().c_str());
|
||||||
|
pindexFork = pindex->pprev;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if (txFound.GetHash() != hashTx) // not a duplicate tx
|
||||||
|
{
|
||||||
|
printf("LoadBlockIndex(): *** invalid tx position for %s\n", hashTx.ToString().c_str());
|
||||||
|
pindexFork = pindex->pprev;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// check level 4: check whether spent txouts were spent within the main chain
|
||||||
|
int nOutput = 0;
|
||||||
|
if (nCheckLevel>3)
|
||||||
|
BOOST_FOREACH(const CDiskTxPos &txpos, txindex.vSpent)
|
||||||
|
{
|
||||||
|
if (!txpos.IsNull())
|
||||||
|
{
|
||||||
|
pair<unsigned int, unsigned int> posFind = make_pair(txpos.nFile, txpos.nBlockPos);
|
||||||
|
if (!mapBlockPos.count(posFind))
|
||||||
|
{
|
||||||
|
printf("LoadBlockIndex(): *** found bad spend at %d, hashBlock=%s, hashTx=%s\n", pindex->nHeight, pindex->GetBlockHash().ToString().c_str(), hashTx.ToString().c_str());
|
||||||
|
pindexFork = pindex->pprev;
|
||||||
|
}
|
||||||
|
// check level 6: check whether spent txouts were spent by a valid transaction that consume them
|
||||||
|
if (nCheckLevel>5)
|
||||||
|
{
|
||||||
|
CTransaction txSpend;
|
||||||
|
if (!txSpend.ReadFromDisk(txpos))
|
||||||
|
{
|
||||||
|
printf("LoadBlockIndex(): *** cannot read spending transaction of %s:%i from disk\n", hashTx.ToString().c_str(), nOutput);
|
||||||
|
pindexFork = pindex->pprev;
|
||||||
|
}
|
||||||
|
else if (!txSpend.CheckTransaction())
|
||||||
|
{
|
||||||
|
printf("LoadBlockIndex(): *** spending transaction of %s:%i is invalid\n", hashTx.ToString().c_str(), nOutput);
|
||||||
|
pindexFork = pindex->pprev;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bool fFound = false;
|
||||||
|
BOOST_FOREACH(const CTxIn &txin, txSpend.vin)
|
||||||
|
if (txin.prevout.hash == hashTx && txin.prevout.n == nOutput)
|
||||||
|
fFound = true;
|
||||||
|
if (!fFound)
|
||||||
|
{
|
||||||
|
printf("LoadBlockIndex(): *** spending transaction of %s:%i does not spend it\n", hashTx.ToString().c_str(), nOutput);
|
||||||
|
pindexFork = pindex->pprev;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
nOutput++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// check level 5: check whether all prevouts are marked spent
|
||||||
|
if (nCheckLevel>4)
|
||||||
|
BOOST_FOREACH(const CTxIn &txin, tx.vin)
|
||||||
|
{
|
||||||
|
CTxIndex txindex;
|
||||||
|
if (ReadTxIndex(txin.prevout.hash, txindex))
|
||||||
|
if (txindex.vSpent.size()-1 < txin.prevout.n || txindex.vSpent[txin.prevout.n].IsNull())
|
||||||
|
{
|
||||||
|
printf("LoadBlockIndex(): *** found unspent prevout %s:%i in %s\n", txin.prevout.hash.ToString().c_str(), txin.prevout.n, hashTx.ToString().c_str());
|
||||||
|
pindexFork = pindex->pprev;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (pindexFork)
|
if (pindexFork)
|
||||||
{
|
{
|
||||||
|
@ -222,7 +222,9 @@ bool AppInit2(int argc, char* argv[])
|
|||||||
" -rpcconnect=<ip> \t " + _("Send commands to node running on <ip> (default: 127.0.0.1)") + "\n" +
|
" -rpcconnect=<ip> \t " + _("Send commands to node running on <ip> (default: 127.0.0.1)") + "\n" +
|
||||||
" -blocknotify=<cmd> " + _("Execute command when the best block changes (%s in cmd is replaced by block hash)") + "\n" +
|
" -blocknotify=<cmd> " + _("Execute command when the best block changes (%s in cmd is replaced by block hash)") + "\n" +
|
||||||
" -keypool=<n> \t " + _("Set key pool size to <n> (default: 100)") + "\n" +
|
" -keypool=<n> \t " + _("Set key pool size to <n> (default: 100)") + "\n" +
|
||||||
" -rescan \t " + _("Rescan the block chain for missing wallet transactions") + "\n";
|
" -rescan \t " + _("Rescan the block chain for missing wallet transactions") + "\n" +
|
||||||
|
" -checkblocks=<n> \t\t " + _("How many blocks to check at startup (default: 2500, 0 = all)") + "\n" +
|
||||||
|
" -checklevel=<n> \t\t " + _("How thorough the block verification is (0-6, default: 1)") + "\n";
|
||||||
|
|
||||||
#ifdef USE_SSL
|
#ifdef USE_SSL
|
||||||
strUsage += string() +
|
strUsage += string() +
|
||||||
|
Loading…
Reference in New Issue
Block a user