@@ -28,11 +28,11 @@ static const char DB_MONEY_SUPPLY = 'M';
2828
2929namespace {
3030
31- struct CoinsEntry
31+ struct CoinEntry
3232{
3333 COutPoint* outpoint;
3434 char key;
35- CoinsEntry (const COutPoint* ptr) : outpoint(const_cast <COutPoint*>(ptr)), key(DB_COIN) {}
35+ explicit CoinEntry (const COutPoint* ptr) : outpoint(const_cast <COutPoint*>(ptr)), key(DB_COIN) {}
3636
3737 template <typename Stream>
3838 void Serialize (Stream &s) const {
@@ -58,12 +58,12 @@ CCoinsViewDB::CCoinsViewDB(size_t nCacheSize, bool fMemory, bool fWipe) : db(Get
5858
5959bool CCoinsViewDB::GetCoins (const COutPoint& outpoint, Coin& coin) const
6060{
61- return db.Read (CoinsEntry (&outpoint), coin);
61+ return db.Read (CoinEntry (&outpoint), coin);
6262}
6363
6464bool CCoinsViewDB::HaveCoins (const COutPoint& outpoint) const
6565{
66- return db.Exists (CoinsEntry (&outpoint));
66+ return db.Exists (CoinEntry (&outpoint));
6767}
6868
6969uint256 CCoinsViewDB::GetBestBlock () const
@@ -81,7 +81,7 @@ bool CCoinsViewDB::BatchWrite(CCoinsMap& mapCoins, const uint256& hashBlock)
8181 size_t changed = 0 ;
8282 for (CCoinsMap::iterator it = mapCoins.begin (); it != mapCoins.end ();) {
8383 if (it->second .flags & CCoinsCacheEntry::DIRTY) {
84- CoinsEntry entry (&it->first );
84+ CoinEntry entry (&it->first );
8585 if (it->second .coins .IsPruned ())
8686 batch.Erase (entry);
8787 else
@@ -148,7 +148,7 @@ CCoinsViewCursor *CCoinsViewDB::Cursor() const
148148 // Cache key of first record
149149 // Cache key of first record
150150 if (i->pcursor ->Valid ()) {
151- CoinsEntry entry (&i->keyTmp .second );
151+ CoinEntry entry (&i->keyTmp .second );
152152 i->pcursor ->GetKey (entry);
153153 i->keyTmp .first = entry.key ;
154154 } else {
@@ -185,7 +185,7 @@ bool CCoinsViewDBCursor::Valid() const
185185void CCoinsViewDBCursor::Next ()
186186{
187187 pcursor->Next ();
188- CoinsEntry entry (&keyTmp.second );
188+ CoinEntry entry (&keyTmp.second );
189189 if (!pcursor->Valid () || !pcursor->GetKey (entry)) {
190190 keyTmp.first = 0 ; // Invalidate cached key after last record so that Valid() and GetKey() return false
191191 } else {
@@ -478,3 +478,49 @@ bool CZerocoinDB::WipeAccChecksums()
478478 LogPrintf (" %s: AccChecksum database removed.\n " , __func__);
479479 return true ;
480480}
481+
482+ /* * Upgrade the database from older formats.
483+ *
484+ * Currently implemented:
485+ * - from the per-tx utxo model (4.2.0) to per-txout (4.2.99)
486+ */
487+ bool CCoinsViewDB::Upgrade () {
488+ std::unique_ptr<CDBIterator> pcursor (db.NewIterator ());
489+ pcursor->Seek (std::make_pair (DB_COINS, uint256 ()));
490+ if (!pcursor->Valid ()) {
491+ return true ;
492+ }
493+
494+ LogPrintf (" Upgrading database...\n " );
495+ size_t batch_size = 1 << 24 ;
496+ CDBBatch batch;
497+ while (pcursor->Valid ()) {
498+ boost::this_thread::interruption_point ();
499+ std::pair<unsigned char , uint256> key;
500+ if (pcursor->GetKey (key) && key.first == DB_COINS) {
501+ CCoins old_coins;
502+ if (!pcursor->GetValue (old_coins)) {
503+ return error (" %s: cannot parse CCoins record" , __func__);
504+ }
505+ COutPoint outpoint (key.second , 0 );
506+ for (size_t i = 0 ; i < old_coins.vout .size (); ++i) {
507+ if (!old_coins.vout [i].IsNull () && !old_coins.vout [i].scriptPubKey .IsUnspendable ()) {
508+ Coin newcoin (std::move (old_coins.vout [i]), old_coins.nHeight , old_coins.fCoinBase , old_coins.fCoinStake );
509+ outpoint.n = i;
510+ CoinEntry entry (&outpoint);
511+ batch.Write (entry, newcoin);
512+ }
513+ }
514+ batch.Erase (key);
515+ if (batch.SizeEstimate () > batch_size) {
516+ db.WriteBatch (batch);
517+ batch.Clear ();
518+ }
519+ pcursor->Next ();
520+ } else {
521+ break ;
522+ }
523+ }
524+ db.WriteBatch (batch);
525+ return true ;
526+ }
0 commit comments