LCOV - code coverage report
Current view: top level - src - txdb.cpp (source / functions) Hit Total Coverage
Test: total_coverage.info Lines: 198 298 66.4 %
Date: 2025-02-23 09:33:43 Functions: 31 45 68.9 %

          Line data    Source code
       1             : // Copyright (c) 2009-2010 Satoshi Nakamoto
       2             : // Copyright (c) 2009-2014 The Bitcoin developers
       3             : // Copyright (c) 2016-2022 The PIVX Core developers
       4             : // Distributed under the MIT/X11 software license, see the accompanying
       5             : // file COPYING or http://www.opensource.org/licenses/mit-license.php.
       6             : 
       7             : #include "txdb.h"
       8             : 
       9             : #include "clientversion.h"
      10             : #include "pow.h"
      11             : #include "random.h"
      12             : #include "uint256.h"
      13             : #include "util/system.h"
      14             : #include "util/vector.h"
      15             : 
      16             : #include <stdint.h>
      17             : 
      18             : #include <boost/thread.hpp>
      19             : 
      20             : static const char DB_COIN = 'C';
      21             : static const char DB_COINS = 'c';
      22             : static const char DB_BLOCK_FILES = 'f';
      23             : static const char DB_TXINDEX = 't';
      24             : static const char DB_BLOCK_INDEX = 'b';
      25             : 
      26             : static const char DB_BEST_BLOCK = 'B';
      27             : static const char DB_HEAD_BLOCKS = 'H';
      28             : static const char DB_FLAG = 'F';
      29             : static const char DB_REINDEX_FLAG = 'R';
      30             : static const char DB_LAST_BLOCK = 'l';
      31             : // static const char DB_MONEY_SUPPLY = 'M';
      32             : 
      33             : namespace {
      34             : 
      35             : struct CoinEntry
      36             : {
      37             :     COutPoint* outpoint;
      38             :     char key;
      39     8869026 :     explicit CoinEntry(const COutPoint* ptr) : outpoint(const_cast<COutPoint*>(ptr)), key(DB_COIN)  {}
      40             : 
      41    17738052 :     SERIALIZE_METHODS(CoinEntry, obj) { READWRITE(obj.key, obj.outpoint->hash, VARINT(obj.outpoint->n)); }
      42             : };
      43             : 
      44             : }
      45             : 
      46             : 
      47         950 : CCoinsViewDB::CCoinsViewDB(size_t nCacheSize, bool fMemory, bool fWipe) : db(GetDataDir() / "chainstate", nCacheSize, fMemory, fWipe)
      48             : {
      49         475 : }
      50             : 
      51     1473886 : bool CCoinsViewDB::GetCoin(const COutPoint& outpoint, Coin& coin) const
      52             : {
      53     1473886 :     return db.Read(CoinEntry(&outpoint), coin);
      54             : }
      55             : 
      56           0 : bool CCoinsViewDB::HaveCoin(const COutPoint& outpoint) const
      57             : {
      58           0 :     return db.Exists(CoinEntry(&outpoint));
      59             : }
      60             : 
      61        2450 : uint256 CCoinsViewDB::GetBestBlock() const
      62             : {
      63        2450 :     uint256 hashBestChain;
      64        2450 :     if (!db.Read(DB_BEST_BLOCK, hashBestChain))
      65        1227 :         return UINT256_ZERO;
      66        1223 :     return hashBestChain;
      67             : }
      68             : 
      69         562 : std::vector<uint256> CCoinsViewDB::GetHeadBlocks() const {
      70        1124 :     std::vector<uint256> vhashHeadBlocks;
      71         562 :     if (!db.Read(DB_HEAD_BLOCKS, vhashHeadBlocks)) {
      72         556 :         return std::vector<uint256>();
      73             :     }
      74         562 :     return vhashHeadBlocks;
      75             : }
      76             : 
      77         810 : bool CCoinsViewDB::BatchWrite(CCoinsMap& mapCoins,
      78             :                               const uint256& hashBlock,
      79             :                               const uint256& hashSaplingAnchor,
      80             :                               CAnchorsSaplingMap& mapSaplingAnchors,
      81             :                               CNullifiersMap& mapSaplingNullifiers)
      82             : {
      83         810 :     CDBBatch batch(CLIENT_VERSION);
      84         810 :     size_t count = 0;
      85         810 :     size_t changed = 0;
      86         810 :     size_t batch_size = (size_t) gArgs.GetArg("-dbbatchsize", nDefaultDbBatchSize);
      87         810 :     int crash_simulate = gArgs.GetArg("-dbcrashratio", 0);
      88        1620 :     assert(!hashBlock.IsNull());
      89             : 
      90         810 :     uint256 old_tip = GetBestBlock();
      91        7975 :     if (old_tip.IsNull()) {
      92             :         // We may be in the middle of replaying.
      93         410 :         std::vector<uint256> old_heads = GetHeadBlocks();
      94         205 :         if (old_heads.size() == 2) {
      95           3 :             assert(old_heads[0] == hashBlock);
      96           3 :             old_tip = old_heads[1];
      97             :         }
      98             :     }
      99             : 
     100             :     // In the first batch, mark the database as being in the middle of a
     101             :     // transition from old_tip to hashBlock.
     102             :     // A vector is used for future extensibility, as we may want to support
     103             :     // interrupting after partial writes from multiple independent reorgs.
     104         810 :     batch.Erase(DB_BEST_BLOCK);
     105         810 :     batch.Write(DB_HEAD_BLOCKS, Vector(hashBlock, old_tip));
     106             : 
     107     1025186 :     for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end();) {
     108     1024373 :         if (it->second.flags & CCoinsCacheEntry::DIRTY) {
     109     1023753 :             CoinEntry entry(&it->first);
     110     1023753 :             if (it->second.coin.IsSpent())
     111      328616 :                 batch.Erase(entry);
     112             :             else
     113      695135 :                 batch.Write(entry, it->second.coin);
     114     1023753 :             changed++;
     115             :         }
     116     1024373 :         count++;
     117     1024373 :         CCoinsMap::iterator itOld = it++;
     118     1024373 :         mapCoins.erase(itOld);
     119     1024373 :         if (batch.SizeEstimate() > batch_size) {
     120          75 :             LogPrint(BCLog::COINDB, "Writing partial batch of %.2f MiB\n", batch.SizeEstimate() * (1.0 / 1048576.0));
     121          75 :             db.WriteBatch(batch);
     122          75 :             batch.Clear();
     123          75 :             if (crash_simulate) {
     124          75 :                 static FastRandomContext rng;
     125         150 :                 if (rng.randrange(crash_simulate) == 0) {
     126           0 :                     LogPrintf("Simulating a crash. Goodbye.\n");
     127           0 :                     _Exit(0);
     128             :                 }
     129             :             }
     130             :         }
     131             :     }
     132             : 
     133             :     // Write Sapling
     134         810 :     BatchWriteSapling(hashSaplingAnchor, mapSaplingAnchors, mapSaplingNullifiers, batch);
     135             : 
     136             :     // In the last batch, mark the database as consistent with hashBlock again.
     137         810 :     batch.Erase(DB_HEAD_BLOCKS);
     138         810 :     batch.Write(DB_BEST_BLOCK, hashBlock);
     139             : 
     140         810 :     LogPrint(BCLog::COINDB, "Writing final batch of %.2f MiB\n", batch.SizeEstimate() * (1.0 / 1048576.0));
     141         810 :     bool ret = db.WriteBatch(batch);
     142         810 :     LogPrint(BCLog::COINDB, "Committed %u changed transaction outputs (out of %u) to coin database...\n", (unsigned int)changed, (unsigned int)count);
     143         810 :     return ret;
     144             : }
     145             : 
     146          49 : size_t CCoinsViewDB::EstimateSize() const
     147             : {
     148          49 :     return db.EstimateSize(DB_COIN, (char)(DB_COIN+1));
     149             : }
     150             : 
     151        1425 : CBlockTreeDB::CBlockTreeDB(size_t nCacheSize, bool fMemory, bool fWipe) : CDBWrapper(GetDataDir() / "blocks" / "index", nCacheSize, fMemory, fWipe)
     152             : {
     153         475 : }
     154             : 
     155           0 : bool CBlockTreeDB::WriteBlockIndex(const CDiskBlockIndex& blockindex)
     156             : {
     157           0 :     return Write(std::make_pair(DB_BLOCK_INDEX, blockindex.GetBlockHash()), blockindex);
     158             : }
     159             : 
     160         704 : bool CBlockTreeDB::ReadBlockFileInfo(int nFile, CBlockFileInfo& info)
     161             : {
     162         704 :     return Read(std::make_pair(DB_BLOCK_FILES, nFile), info);
     163             : }
     164             : 
     165          10 : bool CBlockTreeDB::WriteReindexing(bool fReindexing)
     166             : {
     167          10 :     if (fReindexing)
     168           5 :         return Write(DB_REINDEX_FLAG, '1');
     169             :     else
     170           5 :         return Erase(DB_REINDEX_FLAG);
     171             : }
     172             : 
     173         352 : bool CBlockTreeDB::ReadReindexing(bool& fReindexing)
     174             : {
     175         352 :     fReindexing = Exists(DB_REINDEX_FLAG);
     176         352 :     return true;
     177             : }
     178             : 
     179         352 : bool CBlockTreeDB::ReadLastBlockFile(int& nFile)
     180             : {
     181         352 :     return Read(DB_LAST_BLOCK, nFile);
     182             : }
     183             : 
     184         518 : CCoinsViewCursor *CCoinsViewDB::Cursor() const
     185             : {
     186         518 :     CCoinsViewDBCursor *i = new CCoinsViewDBCursor(const_cast<CDBWrapper&>(db).NewIterator(), GetBestBlock());
     187             :     /* It seems that there are no "const iterators" for LevelDB.  Since we
     188             :        only need read operations on it, use a const-cast to get around
     189             :        that restriction.  */
     190         518 :     i->pcursor->Seek(DB_COIN);
     191             :     // Cache key of first record
     192             :     // Cache key of first record
     193         518 :     if (i->pcursor->Valid()) {
     194         306 :         CoinEntry entry(&i->keyTmp.second);
     195         306 :         i->pcursor->GetKey(entry);
     196         306 :         i->keyTmp.first = entry.key;
     197             :     } else {
     198         212 :         i->keyTmp.first = 0; // Make sure Valid() and GetKey() return false
     199             :     }
     200         518 :     return i;
     201             : }
     202             : 
     203     2791730 : bool CCoinsViewDBCursor::GetKey(COutPoint &key) const
     204             : {
     205             :     // Return cached key
     206     2791730 :     if (keyTmp.first == DB_COIN) {
     207     2791730 :         key = keyTmp.second;
     208     2791730 :         return true;
     209             :     }
     210             :     return false;
     211             : }
     212             : 
     213     6371084 : bool CCoinsViewDBCursor::GetValue(Coin& coin) const
     214             : {
     215     6371084 :     return pcursor->GetValue(coin);
     216             : }
     217             : 
     218           0 : unsigned int CCoinsViewDBCursor::GetValueSize() const
     219             : {
     220           0 :     return pcursor->GetValueSize();
     221             : }
     222             : 
     223     6371597 : bool CCoinsViewDBCursor::Valid() const
     224             : {
     225     6371597 :     return keyTmp.first == DB_COIN;
     226             : }
     227             : 
     228     6371084 : void CCoinsViewDBCursor::Next()
     229             : {
     230     6371084 :     pcursor->Next();
     231     6371084 :     CoinEntry entry(&keyTmp.second);
     232     6371084 :     if (!pcursor->Valid() || !pcursor->GetKey(entry)) {
     233         306 :         keyTmp.first = 0; // Invalidate cached key after last record so that Valid() and GetKey() return false
     234             :     } else {
     235     6370771 :         keyTmp.first = entry.key;
     236             :     }
     237     6371084 : }
     238             : 
     239         807 : bool CBlockTreeDB::WriteBatchSync(const std::vector<std::pair<int, const CBlockFileInfo*> >& fileInfo, int nLastFile, const std::vector<const CBlockIndex*>& blockinfo) {
     240        1614 :     CDBBatch batch(CLIENT_VERSION);
     241        1136 :     for (std::vector<std::pair<int, const CBlockFileInfo*> >::const_iterator it=fileInfo.begin(); it != fileInfo.end(); it++) {
     242         329 :         batch.Write(std::make_pair(DB_BLOCK_FILES, it->first), *it->second);
     243             :     }
     244         807 :     batch.Write(DB_LAST_BLOCK, nLastFile);
     245       40043 :     for (std::vector<const CBlockIndex*>::const_iterator it=blockinfo.begin(); it != blockinfo.end(); it++) {
     246       78272 :         batch.Write(std::make_pair(DB_BLOCK_INDEX, (*it)->GetBlockHash()), CDiskBlockIndex(*it));
     247             :     }
     248        1614 :     return WriteBatch(batch, true);
     249             : }
     250             : 
     251      204081 : bool CBlockTreeDB::ReadTxIndex(const uint256& txid, CDiskTxPos& pos)
     252             : {
     253      204081 :     return Read(std::make_pair(DB_TXINDEX, txid), pos);
     254             : }
     255             : 
     256       41250 : bool CBlockTreeDB::WriteTxIndex(const std::vector<std::pair<uint256, CDiskTxPos> >& vect)
     257             : {
     258       82500 :     CDBBatch batch(CLIENT_VERSION);
     259      341502 :     for (std::vector<std::pair<uint256, CDiskTxPos> >::const_iterator it = vect.begin(); it != vect.end(); it++)
     260      300252 :         batch.Write(std::make_pair(DB_TXINDEX, it->first), it->second);
     261       82500 :     return WriteBatch(batch);
     262             : }
     263             : 
     264         907 : bool CBlockTreeDB::WriteFlag(const std::string& name, bool fValue)
     265             : {
     266        1259 :     return Write(std::make_pair(DB_FLAG, name), fValue ? '1' : '0');
     267             : }
     268             : 
     269         704 : bool CBlockTreeDB::ReadFlag(const std::string& name, bool& fValue)
     270             : {
     271         704 :     char ch;
     272         704 :     if (!Read(std::make_pair(DB_FLAG, name), ch))
     273             :         return false;
     274         318 :     fValue = ch == '1';
     275         318 :     return true;
     276             : }
     277             : 
     278           0 : bool CBlockTreeDB::WriteInt(const std::string& name, int nValue)
     279             : {
     280           0 :     return Write(std::make_pair('I', name), nValue);
     281             : }
     282             : 
     283           0 : bool CBlockTreeDB::ReadInt(const std::string& name, int& nValue)
     284             : {
     285           0 :     return Read(std::make_pair('I', name), nValue);
     286             : }
     287             : 
     288         352 : bool CBlockTreeDB::LoadBlockIndexGuts(std::function<CBlockIndex*(const uint256&)> insertBlockIndex)
     289             : {
     290         704 :     std::unique_ptr<CDBIterator> pcursor(NewIterator());
     291             : 
     292         352 :     pcursor->Seek(std::make_pair(DB_BLOCK_INDEX, UINT256_ZERO));
     293             : 
     294             :     // Load mapBlockIndex
     295       33158 :     while (pcursor->Valid()) {
     296       32965 :         boost::this_thread::interruption_point();
     297       32965 :         std::pair<char, uint256> key;
     298       32965 :         if (pcursor->GetKey(key) && key.first == DB_BLOCK_INDEX) {
     299       65612 :             CDiskBlockIndex diskindex;
     300       32806 :             if (pcursor->GetValue(diskindex)) {
     301             :                 // Construct block index object
     302       32806 :                 CBlockIndex* pindexNew = insertBlockIndex(diskindex.GetBlockHash());
     303       32806 :                 pindexNew->pprev = insertBlockIndex(diskindex.hashPrev);
     304       32806 :                 pindexNew->nHeight = diskindex.nHeight;
     305       32806 :                 pindexNew->nFile = diskindex.nFile;
     306       32806 :                 pindexNew->nDataPos = diskindex.nDataPos;
     307       32806 :                 pindexNew->nUndoPos = diskindex.nUndoPos;
     308       32806 :                 pindexNew->nVersion = diskindex.nVersion;
     309       32806 :                 pindexNew->hashMerkleRoot = diskindex.hashMerkleRoot;
     310       32806 :                 pindexNew->nTime = diskindex.nTime;
     311       32806 :                 pindexNew->nBits = diskindex.nBits;
     312       32806 :                 pindexNew->nNonce = diskindex.nNonce;
     313       32806 :                 pindexNew->nStatus = diskindex.nStatus;
     314       32806 :                 pindexNew->nTx = diskindex.nTx;
     315             : 
     316             :                 // sapling
     317       32806 :                 pindexNew->nSaplingValue  = diskindex.nSaplingValue;
     318       32806 :                 pindexNew->hashFinalSaplingRoot = diskindex.hashFinalSaplingRoot;
     319             : 
     320             :                 //zerocoin
     321       32806 :                 pindexNew->nAccumulatorCheckpoint = diskindex.nAccumulatorCheckpoint;
     322             : 
     323             :                 //Proof Of Stake
     324       32806 :                 pindexNew->nFlags = diskindex.nFlags;
     325       32806 :                 pindexNew->vStakeModifier = diskindex.vStakeModifier;
     326             : 
     327       32806 :                 if (!Params().GetConsensus().NetworkUpgradeActive(pindexNew->nHeight, Consensus::UPGRADE_POS)) {
     328       32651 :                     if (!CheckProofOfWork(pindexNew->GetBlockHash(), pindexNew->nBits))
     329           0 :                         return error("%s : CheckProofOfWork failed: %s", __func__, pindexNew->ToString());
     330             :                 }
     331             : 
     332       32806 :                 pcursor->Next();
     333             :             } else {
     334           0 :                 return error("%s : failed to read value", __func__);
     335             :             }
     336             :         } else {
     337             :             break;
     338             :         }
     339             :     }
     340             : 
     341             :     return true;
     342             : }
     343             : 
     344         950 : CZerocoinDB::CZerocoinDB(size_t nCacheSize, bool fMemory, bool fWipe) : CDBWrapper(GetDataDir() / "zerocoin", nCacheSize, fMemory, fWipe)
     345             : {
     346         475 : }
     347             : 
     348           0 : bool CZerocoinDB::WriteCoinSpendBatch(const std::vector<std::pair<CBigNum, uint256> >& spendInfo)
     349             : {
     350           0 :     CDBBatch batch(CLIENT_VERSION);
     351           0 :     size_t count = 0;
     352           0 :     for (std::vector<std::pair<CBigNum, uint256> >::const_iterator it=spendInfo.begin(); it != spendInfo.end(); it++) {
     353           0 :         CBigNum bnSerial = it->first;
     354           0 :         CDataStream ss(SER_GETHASH, 0);
     355           0 :         ss << bnSerial;
     356           0 :         uint256 hash = Hash(ss.begin(), ss.end());
     357           0 :         batch.Write(std::make_pair('s', hash), it->second);
     358           0 :         ++count;
     359             :     }
     360             : 
     361           0 :     LogPrint(BCLog::COINDB, "Writing %u coin spends to db.\n", (unsigned int)count);
     362           0 :     return WriteBatch(batch, true);
     363             : }
     364             : 
     365           0 : bool CZerocoinDB::ReadCoinSpend(const CBigNum& bnSerial, uint256& txHash)
     366             : {
     367           0 :     CDataStream ss(SER_GETHASH, 0);
     368           0 :     ss << bnSerial;
     369           0 :     uint256 hash = Hash(ss.begin(), ss.end());
     370             : 
     371           0 :     return Read(std::make_pair('s', hash), txHash);
     372             : }
     373             : 
     374           0 : bool CZerocoinDB::EraseCoinSpend(const CBigNum& bnSerial)
     375             : {
     376           0 :     CDataStream ss(SER_GETHASH, 0);
     377           0 :     ss << bnSerial;
     378           0 :     uint256 hash = Hash(ss.begin(), ss.end());
     379             : 
     380           0 :     return Erase(std::make_pair('s', hash));
     381             : }
     382             : 
     383             : // Legacy Zerocoin Database
     384             : static const char LZC_ACCUMCS = 'A';
     385             : //static const char LZC_MAPSUPPLY = 'M'; // TODO: add removal for LZC_MAPSUPPLY key-value if is found in db
     386             : 
     387         160 : bool CZerocoinDB::WriteAccChecksum(const uint32_t nChecksum, const libzerocoin::CoinDenomination denom, const int nHeight)
     388             : {
     389         160 :     return Write(std::make_pair(LZC_ACCUMCS, std::make_pair(nChecksum, denom)), nHeight);
     390             : }
     391             : 
     392           0 : bool CZerocoinDB::ReadAccChecksum(const uint32_t nChecksum, const libzerocoin::CoinDenomination denom, int& nHeightRet)
     393             : {
     394           0 :     return Read(std::make_pair(LZC_ACCUMCS, std::make_pair(nChecksum, denom)), nHeightRet);
     395             : }
     396             : 
     397           0 : bool CZerocoinDB::EraseAccChecksum(const uint32_t nChecksum, const libzerocoin::CoinDenomination denom)
     398             : {
     399           0 :     return Erase(std::make_pair(LZC_ACCUMCS, std::make_pair(nChecksum, denom)));
     400             : }
     401             : 
     402         359 : bool CZerocoinDB::ReadAll(std::map<std::pair<uint32_t, libzerocoin::CoinDenomination>, int>& mapCheckpoints)
     403             : {
     404         718 :     std::unique_ptr<CDBIterator> pcursor(NewIterator());
     405         359 :     pcursor->Seek(std::make_pair(LZC_ACCUMCS, std::make_pair((uint32_t) 0, libzerocoin::CoinDenomination::ZQ_ERROR)));
     406         519 :     while (pcursor->Valid()) {
     407         160 :         boost::this_thread::interruption_point();
     408         160 :         std::pair<char, std::pair<uint32_t, libzerocoin::CoinDenomination>> key;
     409         160 :         if (pcursor->GetKey(key) && key.first == LZC_ACCUMCS) {
     410         160 :             int height;
     411         160 :             if (pcursor->GetValue(height)) {
     412         160 :                 mapCheckpoints[key.second] = height;
     413         160 :                 pcursor->Next();
     414             :             } else {
     415           0 :                 return error("%s : failed to read value", __func__);
     416             :             }
     417             :         } else {
     418             :             break;
     419             :         }
     420             :     }
     421             : 
     422         359 :     LogPrintf("%s: Total acc checksum records: %d\n", __func__, mapCheckpoints.size());
     423         359 :     return true;
     424             : }
     425             : 
     426          20 : void CZerocoinDB::WipeAccChecksums()
     427             : {
     428          20 :     std::unique_ptr<CDBIterator> pcursor(NewIterator());
     429          20 :     pcursor->Seek(std::make_pair(LZC_ACCUMCS, std::make_pair((uint32_t) 0, libzerocoin::CoinDenomination::ZQ_ERROR)));
     430          40 :     std::set<std::pair<char, std::pair<uint32_t, libzerocoin::CoinDenomination>>> setDelete;
     431         180 :     while (pcursor->Valid()) {
     432         160 :         boost::this_thread::interruption_point();
     433         160 :         std::pair<char, std::pair<uint32_t, libzerocoin::CoinDenomination>> key;
     434         160 :         if (pcursor->GetKey(key) && key.first == LZC_ACCUMCS) {
     435         160 :             setDelete.insert(key);
     436             :         } else {
     437             :             break;
     438             :         }
     439         160 :         pcursor->Next();
     440             :     }
     441             : 
     442          20 :     int deleted = 0;
     443         180 :     for (const auto& k : setDelete) {
     444         160 :         if (!Erase(k)) {
     445           0 :             LogPrintf("%s: failed to delete acc checksum %d-%d\n", __func__, k.second.first, k.second.second);
     446             :         } else {
     447         160 :             deleted++;
     448             :         }
     449             :     }
     450             : 
     451          20 :     LogPrintf("%s: %d entries to delete. %d entries deleted\n", __func__, setDelete.size(), deleted);
     452          20 : }
     453             : 
     454             : namespace {
     455             : 
     456             : //! Legacy class to deserialize pre-pertxout database entries without reindex.
     457           0 : class CCoins
     458             : {
     459             : public:
     460             :     //! whether transaction is a coinbase
     461             :     bool fCoinBase;
     462             :     bool fCoinStake;
     463             : 
     464             :     //! unspent transaction outputs; spent outputs are .IsNull(); spent outputs at the end of the array are dropped
     465             :     std::vector<CTxOut> vout;
     466             : 
     467             :     //! at which height this transaction was included in the active block chain
     468             :     int nHeight;
     469             : 
     470             :     template <typename Stream>
     471           0 :     void Unserialize(Stream& s)
     472             :     {
     473           0 :         unsigned int nCode = 0;
     474             :         // version
     475             :         unsigned int nVersionDummy;
     476           0 :         ::Unserialize(s, VARINT(nVersionDummy));
     477             :         // header code
     478           0 :         ::Unserialize(s, VARINT(nCode));
     479           0 :         fCoinBase = nCode & 1;         //0001 - means coinbase
     480           0 :         fCoinStake = (nCode & 2) != 0; //0010 coinstake
     481           0 :         std::vector<bool> vAvail(2, false);
     482           0 :         vAvail[0] = (nCode & 4) != 0; // 0100
     483           0 :         vAvail[1] = (nCode & 8) != 0; // 1000
     484           0 :         unsigned int nMaskCode = (nCode / 16) + ((nCode & 12) != 0 ? 0 : 1);
     485             :         // spentness bitmask
     486           0 :         while (nMaskCode > 0) {
     487           0 :             unsigned char chAvail = 0;
     488           0 :             ::Unserialize(s, chAvail);
     489           0 :             for (unsigned int p = 0; p < 8; p++) {
     490           0 :                 bool f = (chAvail & (1 << p)) != 0;
     491           0 :                 vAvail.push_back(f);
     492             :             }
     493           0 :             if (chAvail != 0)
     494           0 :                 nMaskCode--;
     495             :         }
     496             :         // txouts themself
     497           0 :         vout.assign(vAvail.size(), CTxOut());
     498           0 :         for (unsigned int i = 0; i < vAvail.size(); i++) {
     499           0 :             if (vAvail[i])
     500           0 :                 ::Unserialize(s, Using<TxOutCompression>(vout[i]));
     501             :         }
     502             :         // coinbase height
     503           0 :         ::Unserialize(s, VARINT_MODE(nHeight, VarIntMode::NONNEGATIVE_SIGNED));
     504           0 :     }
     505             : };
     506             : 
     507             : }
     508             : 
     509             : /** Upgrade the database from older formats.
     510             :  *
     511             :  * Currently implemented:
     512             :  * - from the per-tx utxo model (4.2.0) to per-txout (4.2.99)
     513             :  */
     514         357 : bool CCoinsViewDB::Upgrade() {
     515         714 :     std::unique_ptr<CDBIterator> pcursor(db.NewIterator());
     516         714 :     pcursor->Seek(std::make_pair(DB_COINS, uint256()));
     517         357 :     if (!pcursor->Valid()) {
     518             :         return true;
     519             :     }
     520             : 
     521         137 :     LogPrintf("Upgrading database...\n");
     522         137 :     size_t batch_size = 1 << 24;
     523         274 :     CDBBatch batch(CLIENT_VERSION);
     524         137 :     while (pcursor->Valid()) {
     525         137 :         boost::this_thread::interruption_point();
     526         137 :         std::pair<unsigned char, uint256> key;
     527         137 :         if (pcursor->GetKey(key) && key.first == DB_COINS) {
     528           0 :             CCoins old_coins;
     529           0 :             if (!pcursor->GetValue(old_coins)) {
     530           0 :                 return error("%s: cannot parse CCoins record", __func__);
     531             :             }
     532           0 :             COutPoint outpoint(key.second, 0);
     533           0 :             for (size_t i = 0; i < old_coins.vout.size(); ++i) {
     534           0 :                 if (!old_coins.vout[i].IsNull() && !old_coins.vout[i].scriptPubKey.IsUnspendable()) {
     535           0 :                     Coin newcoin(std::move(old_coins.vout[i]), old_coins.nHeight, old_coins.fCoinBase, old_coins.fCoinStake);
     536           0 :                     outpoint.n = i;
     537           0 :                     CoinEntry entry(&outpoint);
     538           0 :                     batch.Write(entry, newcoin);
     539             :                 }
     540             :             }
     541           0 :             batch.Erase(key);
     542           0 :             if (batch.SizeEstimate() > batch_size) {
     543           0 :                 db.WriteBatch(batch);
     544           0 :                 batch.Clear();
     545             :             }
     546           0 :             pcursor->Next();
     547             :         } else {
     548             :             break;
     549             :         }
     550             :     }
     551         137 :     db.WriteBatch(batch);
     552             :     return true;
     553             : }
     554             : 
     555           0 : Optional<int> AccumulatorCache::Get(uint32_t checksum, libzerocoin::CoinDenomination denom)
     556             : {
     557           0 :     const auto& p = std::make_pair(checksum, denom);
     558             : 
     559             :     // First check the map in-memory.
     560           0 :     const auto it = mapCheckpoints.find(p);
     561           0 :     if (it != mapCheckpoints.end()) {
     562           0 :         return Optional<int>(it->second);
     563             :     }
     564             : 
     565             :     // Not found. Check disk.
     566           0 :     int checksum_height = 0;
     567           0 :     if (db->ReadAccChecksum(checksum, denom, checksum_height)) {
     568             :         // save in memory and return
     569           0 :         mapCheckpoints[p] = checksum_height;
     570           0 :         return Optional<int>(checksum_height);
     571             :     }
     572             : 
     573             :     // Not found. Scan the chain.
     574           0 :     return nullopt;
     575             : }
     576             : 
     577           0 : void AccumulatorCache::Set(uint32_t checksum, libzerocoin::CoinDenomination denom, int height)
     578             : {
     579             :     // Update memory cache
     580           0 :     mapCheckpoints[std::make_pair(checksum, denom)] = height;
     581           0 : }
     582             : 
     583           0 : void AccumulatorCache::Erase(uint32_t checksum, libzerocoin::CoinDenomination denom)
     584             : {
     585             :     // Update memory cache and database
     586           0 :     mapCheckpoints.erase(std::make_pair(checksum, denom));
     587           0 :     db->EraseAccChecksum(checksum, denom);
     588           0 : }
     589             : 
     590         718 : void AccumulatorCache::Flush()
     591             : {
     592         718 :     for (const auto& it : mapCheckpoints) {
     593             :         // Write to disk
     594           0 :         db->WriteAccChecksum(it.first.first, it.first.second, it.second);
     595             :     }
     596         718 : }
     597             : 
     598          19 : void AccumulatorCache::Wipe()
     599             : {
     600          19 :     mapCheckpoints.clear();
     601          19 :     db->WipeAccChecksums();
     602          19 : }

Generated by: LCOV version 1.14