66#include < txdb.h>
77
88#include < chain.h>
9- #include < node/interface_ui.h>
109#include < pow.h>
1110#include < random.h>
1211#include < shutdown.h>
1817#include < stdint.h>
1918
2019static constexpr uint8_t DB_COIN{' C' };
21- static constexpr uint8_t DB_COINS{' c' };
2220static constexpr uint8_t DB_BLOCK_FILES{' f' };
2321static constexpr uint8_t DB_ADDRESSINDEX{' a' };
2422static constexpr uint8_t DB_ADDRESSUNSPENTINDEX{' u' };
@@ -33,6 +31,7 @@ static constexpr uint8_t DB_REINDEX_FLAG{'R'};
3331static constexpr uint8_t DB_LAST_BLOCK{' l' };
3432
3533// Keys used in previous version that might still be found in the DB:
34+ static constexpr uint8_t DB_COINS{' c' };
3635static constexpr uint8_t DB_TXINDEX_BLOCK{' T' };
3736// uint8_t DB_TXINDEX{'t'}
3837
@@ -54,6 +53,15 @@ std::optional<bilingual_str> CheckLegacyTxindex(CBlockTreeDB& block_tree_db)
5453 return std::nullopt ;
5554}
5655
56+ bool CCoinsViewDB::NeedsUpgrade ()
57+ {
58+ std::unique_ptr<CDBIterator> cursor{m_db->NewIterator ()};
59+ // DB_COINS was deprecated in v0.15.0, commit
60+ // 1088b02f0ccd7358d2b7076bb9e122d59d502d02
61+ cursor->Seek (std::make_pair (DB_COINS, uint256{}));
62+ return cursor->Valid ();
63+ }
64+
5765namespace {
5866
5967struct CoinEntry {
@@ -64,7 +72,7 @@ struct CoinEntry {
6472 SERIALIZE_METHODS (CoinEntry, obj) { READWRITE (obj.key , obj.outpoint ->hash , VARINT (obj.outpoint ->n )); }
6573};
6674
67- }
75+ } // namespace
6876
6977CCoinsViewDB::CCoinsViewDB (fs::path ldb_path, size_t nCacheSize, bool fMemory , bool fWipe ) :
7078 m_db(std::make_unique<CDBWrapper>(ldb_path, nCacheSize, fMemory , fWipe , true )),
@@ -473,125 +481,3 @@ bool CBlockTreeDB::LoadBlockIndexGuts(const Consensus::Params& consensusParams,
473481
474482 return true ;
475483}
476-
477- namespace {
478-
479- // ! Legacy class to deserialize pre-pertxout database entries without reindex.
480- class CCoins
481- {
482- public:
483- // ! whether transaction is a coinbase
484- bool fCoinBase ;
485-
486- // ! unspent transaction outputs; spent outputs are .IsNull(); spent outputs at the end of the array are dropped
487- std::vector<CTxOut> vout;
488-
489- // ! at which height this transaction was included in the active block chain
490- int nHeight;
491-
492- // ! empty constructor
493- CCoins () : fCoinBase (false ), vout(0 ), nHeight(0 ) { }
494-
495- template <typename Stream>
496- void Unserialize (Stream &s) {
497- unsigned int nCode = 0 ;
498- // version
499- unsigned int nVersionDummy;
500- ::Unserialize (s, VARINT(nVersionDummy));
501- // header code
502- ::Unserialize (s, VARINT(nCode));
503- fCoinBase = nCode & 1 ;
504- std::vector<bool > vAvail (2 , false );
505- vAvail[0 ] = (nCode & 2 ) != 0 ;
506- vAvail[1 ] = (nCode & 4 ) != 0 ;
507- unsigned int nMaskCode = (nCode / 8 ) + ((nCode & 6 ) != 0 ? 0 : 1 );
508- // spentness bitmask
509- while (nMaskCode > 0 ) {
510- unsigned char chAvail = 0 ;
511- ::Unserialize (s, chAvail);
512- for (unsigned int p = 0 ; p < 8 ; p++) {
513- bool f = (chAvail & (1 << p)) != 0 ;
514- vAvail.push_back (f);
515- }
516- if (chAvail != 0 )
517- nMaskCode--;
518- }
519- // txouts themself
520- vout.assign (vAvail.size (), CTxOut ());
521- for (unsigned int i = 0 ; i < vAvail.size (); i++) {
522- if (vAvail[i])
523- ::Unserialize (s, Using<TxOutCompression>(vout[i]));
524- }
525- // coinbase height
526- ::Unserialize (s, VARINT_MODE(nHeight, VarIntMode::NONNEGATIVE_SIGNED));
527- }
528- };
529-
530- }
531-
532- /* * Upgrade the database from older formats.
533- *
534- * Currently implemented: from the per-tx utxo model (0.8..0.14.x) to per-txout.
535- */
536- bool CCoinsViewDB::Upgrade () {
537- std::unique_ptr<CDBIterator> pcursor (m_db->NewIterator ());
538- pcursor->Seek (std::make_pair (DB_COINS, uint256 ()));
539- if (!pcursor->Valid ()) {
540- return true ;
541- }
542-
543- int64_t count = 0 ;
544- LogPrintf (" Upgrading utxo-set database...\n " );
545- LogPrintf (" [0%%]..." ); /* Continued */
546- uiInterface.ShowProgress (_ (" Upgrading UTXO database" ).translated , 0 , true );
547- size_t batch_size = 1 << 24 ;
548- CDBBatch batch (*m_db);
549- int reportDone = 0 ;
550- std::pair<unsigned char , uint256> key;
551- std::pair<unsigned char , uint256> prev_key = {DB_COINS, uint256 ()};
552- while (pcursor->Valid ()) {
553- if (ShutdownRequested ()) {
554- break ;
555- }
556- if (pcursor->GetKey (key) && key.first == DB_COINS) {
557- if (count++ % 256 == 0 ) {
558- uint32_t high = 0x100 * *key.second .begin () + *(key.second .begin () + 1 );
559- int percentageDone = (int )(high * 100.0 / 65536.0 + 0.5 );
560- uiInterface.ShowProgress (_ (" Upgrading UTXO database" ).translated , percentageDone, true );
561- if (reportDone < percentageDone/10 ) {
562- // report max. every 10% step
563- LogPrintf (" [%d%%]..." , percentageDone); /* Continued */
564- reportDone = percentageDone/10 ;
565- }
566- }
567- CCoins old_coins;
568- if (!pcursor->GetValue (old_coins)) {
569- return error (" %s: cannot parse CCoins record" , __func__);
570- }
571- COutPoint outpoint (key.second , 0 );
572- for (size_t i = 0 ; i < old_coins.vout .size (); ++i) {
573- if (!old_coins.vout [i].IsNull () && !old_coins.vout [i].scriptPubKey .IsUnspendable ()) {
574- Coin newcoin (std::move (old_coins.vout [i]), old_coins.nHeight , old_coins.fCoinBase );
575- outpoint.n = i;
576- CoinEntry entry (&outpoint);
577- batch.Write (entry, newcoin);
578- }
579- }
580- batch.Erase (key);
581- if (batch.SizeEstimate () > batch_size) {
582- m_db->WriteBatch (batch);
583- batch.Clear ();
584- m_db->CompactRange (prev_key, key);
585- prev_key = key;
586- }
587- pcursor->Next ();
588- } else {
589- break ;
590- }
591- }
592- m_db->WriteBatch (batch);
593- m_db->CompactRange ({DB_COINS, uint256 ()}, key);
594- uiInterface.ShowProgress (" " , 100 , false );
595- LogPrintf (" [%s].\n " , ShutdownRequested () ? " CANCELLED" : " DONE" );
596- return !ShutdownRequested ();
597- }
0 commit comments