From: Gavin Andresen Date: Thu, 22 Mar 2012 16:18:56 +0000 (-0400) Subject: Merge branch 'checklevel' of https://github.com/sipa/bitcoin X-Git-Tag: v0.4.0-unstable~129^2~137 X-Git-Url: https://git.novaco.in/?a=commitdiff_plain;h=958fe01c327a5a758b432d768685e77304b737bc;hp=-c;p=novacoin.git Merge branch 'checklevel' of https://github.com/sipa/bitcoin --- 958fe01c327a5a758b432d768685e77304b737bc diff --combined src/db.cpp index 4e1b959,0ee5185..56c59cb --- a/src/db.cpp +++ b/src/db.cpp @@@ -84,11 -84,8 +84,11 @@@ CDB::CDB(const char* pszFile, const cha string strErrorFile = strDataDir + "/db.log"; printf("dbenv.open strLogDir=%s strErrorFile=%s\n", strLogDir.c_str(), strErrorFile.c_str()); + int nDbCache = GetArg("-dbcache", 25); dbenv.set_lg_dir(strLogDir.c_str()); - dbenv.set_lg_max(10000000); + dbenv.set_cachesize(nDbCache / 1024, (nDbCache % 1024)*1048576, 1); + dbenv.set_lg_bsize(10485760); + dbenv.set_lg_max(104857600); dbenv.set_lk_max_locks(10000); dbenv.set_lk_max_objects(10000); dbenv.set_errfile(fopen(strErrorFile.c_str(), "a")); /// debug @@@ -159,7 -156,7 +159,7 @@@ void CDB::Close( nMinutes = 1; if (strFile == "addr.dat") nMinutes = 2; - if (strFile == "blkindex.dat" && IsInitialBlockDownload() && nBestHeight % 500 != 0) + if (strFile == "blkindex.dat" && IsInitialBlockDownload() && nBestHeight % 5000 != 0) nMinutes = 1; dbenv.txn_checkpoint(0, nMinutes, 0); @@@ -583,19 -580,114 +583,114 @@@ bool CTxDB::LoadBlockIndex( ReadBestInvalidWork(bnBestInvalidWork); // 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; + map, CBlockIndex*> mapBlockPos; for (CBlockIndex* pindex = pindexBest; pindex && pindex->pprev; pindex = pindex->pprev) { - if (pindex->nHeight < nBestHeight-2500 && !mapArgs.count("-checkblocks")) + if (pindex->nHeight < nBestHeight-nCheckDepth) break; CBlock block; if (!block.ReadFromDisk(pindex)) 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()); pindexFork = pindex->pprev; } + // check level 2: verify transaction index validity + if (nCheckLevel>1) + { + pair 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 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) { @@@ -624,65 -716,44 +719,65 @@@ bool CAddrDB::WriteAddress(const CAddre return Write(make_pair(string("addr"), addr.GetKey()), addr); } +bool CAddrDB::WriteAddrman(const CAddrMan& addrman) +{ + return Write(string("addrman"), addrman); +} + bool CAddrDB::EraseAddress(const CAddress& addr) { return Erase(make_pair(string("addr"), addr.GetKey())); } -bool CAddrDB::LoadAddresses() +bool CAddrDB::LoadAddresses(bool &fUpdate) { - CRITICAL_BLOCK(cs_mapAddresses) + bool fAddrMan = false; + if (Read(string("addrman"), addrman)) { - // Get cursor - Dbc* pcursor = GetCursor(); - if (!pcursor) + printf("Loaded %i addresses\n", addrman.size()); + fAddrMan = true; + } + + vector vAddr; + + // Get cursor + Dbc* pcursor = GetCursor(); + if (!pcursor) + return false; + + loop + { + // Read next record + CDataStream ssKey; + CDataStream ssValue; + int ret = ReadAtCursor(pcursor, ssKey, ssValue); + if (ret == DB_NOTFOUND) + break; + else if (ret != 0) return false; - loop + // Unserialize + string strType; + ssKey >> strType; + if (strType == "addr") { - // Read next record - CDataStream ssKey; - CDataStream ssValue; - int ret = ReadAtCursor(pcursor, ssKey, ssValue); - if (ret == DB_NOTFOUND) - break; - else if (ret != 0) - return false; - - // Unserialize - string strType; - ssKey >> strType; - if (strType == "addr") + if (fAddrMan) + fUpdate = true; + else { CAddress addr; ssValue >> addr; - mapAddresses.insert(make_pair(addr.GetKey(), addr)); + vAddr.push_back(addr); } + } - pcursor->close(); + } + pcursor->close(); - printf("Loaded %d addresses\n", mapAddresses.size()); + if (!fAddrMan) + { + addrman.Add(vAddr, CNetAddr("0.0.0.0")); + printf("Loaded %i addresses\n", addrman.size()); } return true; @@@ -690,11 -761,7 +785,11 @@@ bool LoadAddresses() { - return CAddrDB("cr+").LoadAddresses(); + bool fUpdate = false; + bool fRet = CAddrDB("cr+").LoadAddresses(fUpdate); + if (fUpdate) + CDB::Rewrite("addr.dat", "\004addr"); + return fRet; } @@@ -799,14 -866,6 +894,14 @@@ int CWalletDB::LoadWallet(CWallet* pwal //// todo: shouldn't we catch exceptions and try to recover and continue? CRITICAL_BLOCK(pwallet->cs_wallet) { + int nMinVersion = 0; + if (Read((string)"minversion", nMinVersion)) + { + if (nMinVersion > CLIENT_VERSION) + return DB_TOO_NEW; + pwallet->LoadMinVersion(nMinVersion); + } + // Get cursor Dbc* pcursor = GetCursor(); if (!pcursor) @@@ -976,6 -1035,14 +1071,6 @@@ if (nFileVersion == 10300) nFileVersion = 300; } - else if (strType == "minversion") - { - int nMinVersion = 0; - ssValue >> nMinVersion; - if (nMinVersion > CLIENT_VERSION) - return DB_TOO_NEW; - pwallet->LoadMinVersion(nMinVersion); - } else if (strType == "cscript") { uint160 hash; diff --combined src/init.cpp index b00a6be,647bf44..603022e --- a/src/init.cpp +++ b/src/init.cpp @@@ -177,7 -177,6 +177,7 @@@ bool AppInit2(int argc, char* argv[] " -min \t\t " + _("Start minimized") + "\n" + " -splash \t\t " + _("Show splash screen on startup (default: 1)") + "\n" + " -datadir= \t\t " + _("Specify data directory") + "\n" + + " -dbcache= \t\t " + _("Set database cache size in megabytes (default: 25)") + "\n" + " -timeout= \t " + _("Specify connection timeout (in milliseconds)") + "\n" + " -proxy= \t " + _("Connect through socks4 proxy") + "\n" + " -dns \t " + _("Allow DNS lookups for addnode and connect") + "\n" + @@@ -223,7 -222,9 +223,9 @@@ " -rpcconnect= \t " + _("Send commands to node running on (default: 127.0.0.1)") + "\n" + " -blocknotify= " + _("Execute command when the best block changes (%s in cmd is replaced by block hash)") + "\n" + " -keypool= \t " + _("Set key pool size to (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= \t\t " + _("How many blocks to check at startup (default: 2500, 0 = all)") + "\n" + + " -checklevel= \t\t " + _("How thorough the block verification is (0-6, default: 1)") + "\n"; #ifdef USE_SSL strUsage += string() + @@@ -490,11 -491,24 +492,11 @@@ fAllowDNS = GetBoolArg("-dns"); fNoListen = !GetBoolArg("-listen", true); - // This code can be removed once a super-majority of the network has upgraded. - if (GetBoolArg("-bip16", true)) - { - if (fTestNet) - SoftSetArg("-paytoscripthashtime", "1329264000"); // Feb 15 - else - SoftSetArg("-paytoscripthashtime", "1333238400"); // April 1 2012 - - // Put "/P2SH/" in the coinbase so everybody can tell when - // a majority of miners support it - const char* pszP2SH = "/P2SH/"; - COINBASE_FLAGS << std::vector(pszP2SH, pszP2SH+strlen(pszP2SH)); - } - else - { - const char* pszP2SH = "NOP2SH"; - COINBASE_FLAGS << std::vector(pszP2SH, pszP2SH+strlen(pszP2SH)); - } + // Continue to put "/P2SH/" in the coinbase to monitor + // BIP16 support. + // This can be removed eventually... + const char* pszP2SH = "/P2SH/"; + COINBASE_FLAGS << std::vector(pszP2SH, pszP2SH+strlen(pszP2SH)); if (!fNoListen) { @@@ -513,7 -527,7 +515,7 @@@ CAddress addr(CService(strAddr, GetDefaultPort(), fAllowDNS)); addr.nTime = 0; // so it won't relay unless successfully connected if (addr.IsValid()) - AddAddress(addr); + addrman.Add(addr, CNetAddr("127.0.0.1")); } }