2012-09-03 16:14:03 -03:00
// Copyright (c) 2009-2010 Satoshi Nakamoto
2020-04-16 13:14:08 -04:00
// Copyright (c) 2009-2020 The Bitcoin Core developers
2014-12-13 01:09:33 -03:00
// Distributed under the MIT software license, see the accompanying
2012-09-03 16:14:03 -03:00
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
2017-11-09 21:57:53 -03:00
# include <txdb.h>
2021-08-04 14:55:31 -04:00
# include <chain.h>
2020-06-19 18:14:17 -04:00
# include <node/ui_interface.h>
2017-11-09 21:57:53 -03:00
# include <pow.h>
2019-06-17 03:56:52 -04:00
# include <random.h>
2018-05-16 15:17:40 -04:00
# include <shutdown.h>
2017-11-09 21:57:53 -03:00
# include <uint256.h>
2018-10-22 19:51:11 -03:00
# include <util/system.h>
2019-06-17 03:56:52 -04:00
# include <util/translation.h>
2019-08-28 18:12:51 -04:00
# include <util/vector.h>
2013-04-13 02:13:08 -03:00
# include <stdint.h>
2012-09-03 16:14:03 -03:00
2021-05-31 08:57:32 -04:00
static constexpr uint8_t DB_COIN { ' C ' } ;
static constexpr uint8_t DB_COINS { ' c ' } ;
static constexpr uint8_t DB_BLOCK_FILES { ' f ' } ;
static constexpr uint8_t DB_BLOCK_INDEX { ' b ' } ;
2015-01-25 12:27:54 -03:00
2021-05-31 08:57:32 -04:00
static constexpr uint8_t DB_BEST_BLOCK { ' B ' } ;
static constexpr uint8_t DB_HEAD_BLOCKS { ' H ' } ;
static constexpr uint8_t DB_FLAG { ' F ' } ;
static constexpr uint8_t DB_REINDEX_FLAG { ' R ' } ;
static constexpr uint8_t DB_LAST_BLOCK { ' l ' } ;
2015-01-25 12:27:54 -03:00
2021-08-04 14:55:31 -04:00
// Keys used in previous version that might still be found in the DB:
static constexpr uint8_t DB_TXINDEX_BLOCK { ' T ' } ;
// uint8_t DB_TXINDEX{'t'}
std : : optional < bilingual_str > CheckLegacyTxindex ( CBlockTreeDB & block_tree_db )
{
CBlockLocator ignored { } ;
if ( block_tree_db . Read ( DB_TXINDEX_BLOCK , ignored ) ) {
return _ ( " The -txindex upgrade started by a previous version can not be completed. Restart with the previous version or run a full -reindex. " ) ;
}
bool txindex_legacy_flag { false } ;
block_tree_db . ReadFlag ( " txindex " , txindex_legacy_flag ) ;
if ( txindex_legacy_flag ) {
// Disable legacy txindex and warn once about occupied disk space
if ( ! block_tree_db . WriteFlag ( " txindex " , false ) ) {
return Untranslated ( " Failed to write block index db flag 'txindex'='0' " ) ;
}
return _ ( " The block index db contains a legacy 'txindex'. To clear the occupied disk space, run a full -reindex, otherwise ignore this error. This error message will not be displayed again. " ) ;
}
return std : : nullopt ;
}
2017-04-25 15:29:39 -03:00
namespace {
2017-05-30 20:58:54 -04:00
struct CoinEntry {
2017-04-25 15:29:39 -03:00
COutPoint * outpoint ;
2021-05-31 08:57:32 -04:00
uint8_t key ;
2017-08-01 06:22:41 -04:00
explicit CoinEntry ( const COutPoint * ptr ) : outpoint ( const_cast < COutPoint * > ( ptr ) ) , key ( DB_COIN ) { }
2017-04-25 15:29:39 -03:00
2020-03-11 13:35:50 -03:00
SERIALIZE_METHODS ( CoinEntry , obj ) { READWRITE ( obj . key , obj . outpoint - > hash , VARINT ( obj . outpoint - > n ) ) ; }
2017-04-25 15:29:39 -03:00
} ;
}
2015-01-25 12:27:54 -03:00
2019-04-17 10:07:15 -04:00
CCoinsViewDB : : CCoinsViewDB ( fs : : path ldb_path , size_t nCacheSize , bool fMemory , bool fWipe ) :
2021-03-10 06:28:08 -03:00
m_db ( std : : make_unique < CDBWrapper > ( ldb_path , nCacheSize , fMemory , fWipe , true ) ) ,
2019-04-17 10:07:15 -04:00
m_ldb_path ( ldb_path ) ,
m_is_memory ( fMemory ) { }
void CCoinsViewDB : : ResizeCache ( size_t new_cache_size )
2015-09-07 19:22:23 -03:00
{
2020-08-25 13:48:21 -04:00
// We can't do this operation with an in-memory DB since we'll lose all the coins upon
// reset.
if ( ! m_is_memory ) {
// Have to do a reset first to get the original `m_db` state to release its
// filesystem lock.
m_db . reset ( ) ;
2021-03-10 06:28:08 -03:00
m_db = std : : make_unique < CDBWrapper > (
2020-08-25 13:48:21 -04:00
m_ldb_path , new_cache_size , m_is_memory , /*fWipe*/ false , /*obfuscate*/ true ) ;
}
2012-09-03 16:14:03 -03:00
}
2017-05-30 20:58:54 -04:00
bool CCoinsViewDB : : GetCoin ( const COutPoint & outpoint , Coin & coin ) const {
2019-04-17 10:07:15 -04:00
return m_db - > Read ( CoinEntry ( & outpoint ) , coin ) ;
2012-09-03 16:14:03 -03:00
}
2017-05-30 20:58:54 -04:00
bool CCoinsViewDB : : HaveCoin ( const COutPoint & outpoint ) const {
2019-04-17 10:07:15 -04:00
return m_db - > Exists ( CoinEntry ( & outpoint ) ) ;
2012-09-03 16:14:03 -03:00
}
2014-07-19 10:42:48 -04:00
uint256 CCoinsViewDB : : GetBestBlock ( ) const {
2012-09-03 16:14:03 -03:00
uint256 hashBestChain ;
2019-04-17 10:07:15 -04:00
if ( ! m_db - > Read ( DB_BEST_BLOCK , hashBestChain ) )
2014-12-15 05:11:16 -03:00
return uint256 ( ) ;
2013-11-04 22:27:39 -03:00
return hashBestChain ;
2012-09-03 16:14:03 -03:00
}
2017-04-19 13:34:30 -03:00
std : : vector < uint256 > CCoinsViewDB : : GetHeadBlocks ( ) const {
std : : vector < uint256 > vhashHeadBlocks ;
2019-04-17 10:07:15 -04:00
if ( ! m_db - > Read ( DB_HEAD_BLOCKS , vhashHeadBlocks ) ) {
2017-04-19 13:34:30 -03:00
return std : : vector < uint256 > ( ) ;
}
return vhashHeadBlocks ;
}
2014-08-23 20:08:05 -04:00
bool CCoinsViewDB : : BatchWrite ( CCoinsMap & mapCoins , const uint256 & hashBlock ) {
2019-04-17 10:07:15 -04:00
CDBBatch batch ( * m_db ) ;
2014-09-03 03:37:47 -04:00
size_t count = 0 ;
size_t changed = 0 ;
2019-08-22 21:40:41 -04:00
size_t batch_size = ( size_t ) gArgs . GetIntArg ( " -dbbatchsize " , nDefaultDbBatchSize ) ;
int crash_simulate = gArgs . GetIntArg ( " -dbcrashratio " , 0 ) ;
2017-04-17 12:41:10 -03:00
assert ( ! hashBlock . IsNull ( ) ) ;
2017-04-19 13:34:30 -03:00
uint256 old_tip = GetBestBlock ( ) ;
if ( old_tip . IsNull ( ) ) {
// We may be in the middle of replaying.
std : : vector < uint256 > old_heads = GetHeadBlocks ( ) ;
if ( old_heads . size ( ) = = 2 ) {
assert ( old_heads [ 0 ] = = hashBlock ) ;
old_tip = old_heads [ 1 ] ;
}
}
// In the first batch, mark the database as being in the middle of a
// transition from old_tip to hashBlock.
// A vector is used for future extensibility, as we may want to support
// interrupting after partial writes from multiple independent reorgs.
batch . Erase ( DB_BEST_BLOCK ) ;
2019-08-28 18:12:51 -04:00
batch . Write ( DB_HEAD_BLOCKS , Vector ( hashBlock , old_tip ) ) ;
2017-04-19 13:34:30 -03:00
2014-08-23 20:08:05 -04:00
for ( CCoinsMap : : iterator it = mapCoins . begin ( ) ; it ! = mapCoins . end ( ) ; ) {
2014-09-03 03:37:47 -04:00
if ( it - > second . flags & CCoinsCacheEntry : : DIRTY ) {
2017-05-30 20:58:54 -04:00
CoinEntry entry ( & it - > first ) ;
if ( it - > second . coin . IsSpent ( ) )
2017-04-25 15:29:39 -03:00
batch . Erase ( entry ) ;
2015-09-07 19:22:23 -03:00
else
2017-05-04 04:15:36 -03:00
batch . Write ( entry , it - > second . coin ) ;
2014-09-03 03:37:47 -04:00
changed + + ;
}
count + + ;
2014-08-23 20:08:05 -04:00
CCoinsMap : : iterator itOld = it + + ;
mapCoins . erase ( itOld ) ;
2017-04-19 13:34:30 -03:00
if ( batch . SizeEstimate ( ) > batch_size ) {
LogPrint ( BCLog : : COINDB , " Writing partial batch of %.2f MiB \n " , batch . SizeEstimate ( ) * ( 1.0 / 1048576.0 ) ) ;
2019-04-17 10:07:15 -04:00
m_db - > WriteBatch ( batch ) ;
2017-04-19 13:34:30 -03:00
batch . Clear ( ) ;
2017-04-05 05:37:09 -03:00
if ( crash_simulate ) {
static FastRandomContext rng ;
if ( rng . randrange ( crash_simulate ) = = 0 ) {
LogPrintf ( " Simulating a crash. Goodbye. \n " ) ;
2017-06-15 17:08:48 -04:00
_Exit ( 0 ) ;
2017-04-05 05:37:09 -03:00
}
}
2017-04-19 13:34:30 -03:00
}
2014-08-23 20:08:05 -04:00
}
2012-09-03 16:14:03 -03:00
2017-04-19 13:34:30 -03:00
// In the last batch, mark the database as consistent with hashBlock again.
batch . Erase ( DB_HEAD_BLOCKS ) ;
batch . Write ( DB_BEST_BLOCK , hashBlock ) ;
LogPrint ( BCLog : : COINDB , " Writing final batch of %.2f MiB \n " , batch . SizeEstimate ( ) * ( 1.0 / 1048576.0 ) ) ;
2019-04-17 10:07:15 -04:00
bool ret = m_db - > WriteBatch ( batch ) ;
2017-04-25 15:29:39 -03:00
LogPrint ( BCLog : : COINDB , " Committed %u changed transaction outputs (out of %u) to coin database... \n " , ( unsigned int ) changed , ( unsigned int ) count ) ;
return ret ;
2012-09-03 16:14:03 -03:00
}
2017-05-12 19:19:19 -03:00
size_t CCoinsViewDB : : EstimateSize ( ) const
{
2021-05-31 08:57:32 -04:00
return m_db - > EstimateSize ( DB_COIN , uint8_t ( DB_COIN + 1 ) ) ;
2017-05-12 19:19:19 -03:00
}
2021-05-04 07:00:25 -04:00
CBlockTreeDB : : CBlockTreeDB ( size_t nCacheSize , bool fMemory , bool fWipe ) : CDBWrapper ( gArgs . GetDataDirNet ( ) / " blocks " / " index " , nCacheSize , fMemory , fWipe ) {
2012-09-04 13:12:00 -03:00
}
2012-09-03 16:14:03 -03:00
bool CBlockTreeDB : : ReadBlockFileInfo ( int nFile , CBlockFileInfo & info ) {
2017-01-27 05:43:41 -03:00
return Read ( std : : make_pair ( DB_BLOCK_FILES , nFile ) , info ) ;
2012-09-03 16:14:03 -03:00
}
2012-10-21 16:23:13 -03:00
bool CBlockTreeDB : : WriteReindexing ( bool fReindexing ) {
if ( fReindexing )
2021-05-31 08:57:32 -04:00
return Write ( DB_REINDEX_FLAG , uint8_t { ' 1 ' } ) ;
2012-10-21 16:23:13 -03:00
else
2015-01-25 12:27:54 -03:00
return Erase ( DB_REINDEX_FLAG ) ;
2012-10-21 16:23:13 -03:00
}
2018-07-27 02:22:42 -04:00
void CBlockTreeDB : : ReadReindexing ( bool & fReindexing ) {
2015-01-25 12:27:54 -03:00
fReindexing = Exists ( DB_REINDEX_FLAG ) ;
2012-10-21 16:23:13 -03:00
}
2012-09-03 16:14:03 -03:00
bool CBlockTreeDB : : ReadLastBlockFile ( int & nFile ) {
2015-01-25 12:27:54 -03:00
return Read ( DB_LAST_BLOCK , nFile ) ;
2012-09-03 16:14:03 -03:00
}
2021-06-18 14:14:15 -04:00
/** Specialization of CCoinsViewCursor to iterate over a CCoinsViewDB */
class CCoinsViewDBCursor : public CCoinsViewCursor
{
public :
2021-06-18 14:15:39 -04:00
// Prefer using CCoinsViewDB::Cursor() since we want to perform some
// cache warmup on instantiation.
2021-06-18 14:14:15 -04:00
CCoinsViewDBCursor ( CDBIterator * pcursorIn , const uint256 & hashBlockIn ) :
CCoinsViewCursor ( hashBlockIn ) , pcursor ( pcursorIn ) { }
~ CCoinsViewDBCursor ( ) { }
bool GetKey ( COutPoint & key ) const override ;
bool GetValue ( Coin & coin ) const override ;
unsigned int GetValueSize ( ) const override ;
bool Valid ( ) const override ;
void Next ( ) override ;
private :
std : : unique_ptr < CDBIterator > pcursor ;
std : : pair < char , COutPoint > keyTmp ;
friend class CCoinsViewDB ;
} ;
2021-06-16 16:27:20 -04:00
std : : unique_ptr < CCoinsViewCursor > CCoinsViewDB : : Cursor ( ) const
2016-03-28 13:18:30 -03:00
{
2021-06-16 16:27:20 -04:00
auto i = std : : make_unique < CCoinsViewDBCursor > (
const_cast < CDBWrapper & > ( * m_db ) . NewIterator ( ) , GetBestBlock ( ) ) ;
2014-07-19 10:42:48 -04:00
/* It seems that there are no "const iterators" for LevelDB. Since we
only need read operations on it , use a const - cast to get around
that restriction . */
2017-04-25 15:29:39 -03:00
i - > pcursor - > Seek ( DB_COIN ) ;
2016-03-28 13:18:30 -03:00
// Cache key of first record
2017-05-23 13:04:14 -04:00
if ( i - > pcursor - > Valid ( ) ) {
2017-05-30 20:58:54 -04:00
CoinEntry entry ( & i - > keyTmp . second ) ;
2017-04-25 15:29:39 -03:00
i - > pcursor - > GetKey ( entry ) ;
i - > keyTmp . first = entry . key ;
2017-05-23 13:04:14 -04:00
} else {
i - > keyTmp . first = 0 ; // Make sure Valid() and GetKey() return false
}
2016-03-28 13:18:30 -03:00
return i ;
}
2017-04-25 15:29:39 -03:00
bool CCoinsViewDBCursor : : GetKey ( COutPoint & key ) const
2016-03-28 13:18:30 -03:00
{
// Return cached key
2017-04-25 15:29:39 -03:00
if ( keyTmp . first = = DB_COIN ) {
2016-03-28 13:18:30 -03:00
key = keyTmp . second ;
return true ;
2012-09-25 18:04:54 -03:00
}
2016-03-28 13:18:30 -03:00
return false ;
}
2017-04-25 15:29:39 -03:00
bool CCoinsViewDBCursor : : GetValue ( Coin & coin ) const
2016-03-28 13:18:30 -03:00
{
2017-04-25 15:29:39 -03:00
return pcursor - > GetValue ( coin ) ;
2016-03-28 13:18:30 -03:00
}
unsigned int CCoinsViewDBCursor : : GetValueSize ( ) const
{
return pcursor - > GetValueSize ( ) ;
}
bool CCoinsViewDBCursor : : Valid ( ) const
{
2017-04-25 15:29:39 -03:00
return keyTmp . first = = DB_COIN ;
2016-03-28 13:18:30 -03:00
}
void CCoinsViewDBCursor : : Next ( )
{
pcursor - > Next ( ) ;
2017-05-30 20:58:54 -04:00
CoinEntry entry ( & keyTmp . second ) ;
2017-04-25 15:29:39 -03:00
if ( ! pcursor - > Valid ( ) | | ! pcursor - > GetKey ( entry ) ) {
2016-03-28 13:18:30 -03:00
keyTmp . first = 0 ; // Invalidate cached key after last record so that Valid() and GetKey() return false
2017-04-25 15:29:39 -03:00
} else {
keyTmp . first = entry . key ;
}
2012-09-25 18:04:54 -03:00
}
2014-11-25 12:26:20 -03:00
bool CBlockTreeDB : : WriteBatchSync ( const std : : vector < std : : pair < int , const CBlockFileInfo * > > & fileInfo , int nLastFile , const std : : vector < const CBlockIndex * > & blockinfo ) {
2016-04-20 06:46:01 -03:00
CDBBatch batch ( * this ) ;
2014-11-25 12:26:20 -03:00
for ( std : : vector < std : : pair < int , const CBlockFileInfo * > > : : const_iterator it = fileInfo . begin ( ) ; it ! = fileInfo . end ( ) ; it + + ) {
2017-01-27 05:43:41 -03:00
batch . Write ( std : : make_pair ( DB_BLOCK_FILES , it - > first ) , * it - > second ) ;
2014-11-25 12:26:20 -03:00
}
2015-01-25 12:27:54 -03:00
batch . Write ( DB_LAST_BLOCK , nLastFile ) ;
2014-11-25 12:26:20 -03:00
for ( std : : vector < const CBlockIndex * > : : const_iterator it = blockinfo . begin ( ) ; it ! = blockinfo . end ( ) ; it + + ) {
2017-01-27 05:43:41 -03:00
batch . Write ( std : : make_pair ( DB_BLOCK_INDEX , ( * it ) - > GetBlockHash ( ) ) , CDiskBlockIndex ( * it ) ) ;
2014-11-25 12:26:20 -03:00
}
return WriteBatch ( batch , true ) ;
}
2013-01-10 21:47:57 -03:00
bool CBlockTreeDB : : WriteFlag ( const std : : string & name , bool fValue ) {
2021-05-31 08:57:32 -04:00
return Write ( std : : make_pair ( DB_FLAG , name ) , fValue ? uint8_t { ' 1 ' } : uint8_t { ' 0 ' } ) ;
2013-01-10 21:47:57 -03:00
}
bool CBlockTreeDB : : ReadFlag ( const std : : string & name , bool & fValue ) {
2021-05-31 08:57:32 -04:00
uint8_t ch ;
2015-01-25 12:27:54 -03:00
if ( ! Read ( std : : make_pair ( DB_FLAG , name ) , ch ) )
2013-01-10 21:47:57 -03:00
return false ;
2021-05-31 08:57:32 -04:00
fValue = ch = = uint8_t { ' 1 ' } ;
2013-01-10 21:47:57 -03:00
return true ;
}
2016-11-07 19:31:55 -03:00
bool CBlockTreeDB : : LoadBlockIndexGuts ( const Consensus : : Params & consensusParams , std : : function < CBlockIndex * ( const uint256 & ) > insertBlockIndex )
2012-09-03 16:14:03 -03:00
{
2016-08-30 17:41:56 -03:00
std : : unique_ptr < CDBIterator > pcursor ( NewIterator ( ) ) ;
2012-09-03 16:14:03 -03:00
2017-01-27 05:43:41 -03:00
pcursor - > Seek ( std : : make_pair ( DB_BLOCK_INDEX , uint256 ( ) ) ) ;
2012-09-03 16:14:03 -03:00
2019-04-10 14:34:46 -04:00
// Load m_block_index
2012-09-03 16:14:03 -03:00
while ( pcursor - > Valid ( ) ) {
2018-04-13 16:20:29 -03:00
if ( ShutdownRequested ( ) ) return false ;
2021-05-31 08:57:32 -04:00
std : : pair < uint8_t , uint256 > key ;
2015-10-13 15:25:57 -03:00
if ( pcursor - > GetKey ( key ) & & key . first = = DB_BLOCK_INDEX ) {
2015-10-07 21:12:24 -03:00
CDiskBlockIndex diskindex ;
if ( pcursor - > GetValue ( diskindex ) ) {
2012-09-03 16:14:03 -03:00
// Construct block index object
2016-04-05 10:14:48 -03:00
CBlockIndex * pindexNew = insertBlockIndex ( diskindex . GetBlockHash ( ) ) ;
pindexNew - > pprev = insertBlockIndex ( diskindex . hashPrev ) ;
2012-09-03 16:14:03 -03:00
pindexNew - > nHeight = diskindex . nHeight ;
pindexNew - > nFile = diskindex . nFile ;
pindexNew - > nDataPos = diskindex . nDataPos ;
pindexNew - > nUndoPos = diskindex . nUndoPos ;
pindexNew - > nVersion = diskindex . nVersion ;
pindexNew - > hashMerkleRoot = diskindex . hashMerkleRoot ;
pindexNew - > nTime = diskindex . nTime ;
pindexNew - > nBits = diskindex . nBits ;
pindexNew - > nNonce = diskindex . nNonce ;
pindexNew - > nStatus = diskindex . nStatus ;
pindexNew - > nTx = diskindex . nTx ;
2016-11-07 19:31:55 -03:00
if ( ! CheckProofOfWork ( pindexNew - > GetBlockHash ( ) , pindexNew - > nBits , consensusParams ) )
return error ( " %s: CheckProofOfWork failed: %s " , __func__ , pindexNew - > ToString ( ) ) ;
2012-09-03 16:14:03 -03:00
pcursor - > Next ( ) ;
} else {
2016-11-07 19:31:55 -03:00
return error ( " %s: failed to read value " , __func__ ) ;
2012-09-03 16:14:03 -03:00
}
2015-10-07 21:12:24 -03:00
} else {
break ;
2012-09-03 16:14:03 -03:00
}
}
return true ;
}
2017-04-25 15:29:46 -03:00
2017-04-25 15:29:48 -03:00
namespace {
//! Legacy class to deserialize pre-pertxout database entries without reindex.
class CCoins
{
public :
//! whether transaction is a coinbase
bool fCoinBase ;
//! unspent transaction outputs; spent outputs are .IsNull(); spent outputs at the end of the array are dropped
std : : vector < CTxOut > vout ;
//! at which height this transaction was included in the active block chain
int nHeight ;
//! empty constructor
CCoins ( ) : fCoinBase ( false ) , vout ( 0 ) , nHeight ( 0 ) { }
template < typename Stream >
void Unserialize ( Stream & s ) {
unsigned int nCode = 0 ;
// version
2017-02-13 15:41:02 -03:00
unsigned int nVersionDummy ;
2017-04-25 15:29:48 -03:00
: : Unserialize ( s , VARINT ( nVersionDummy ) ) ;
// header code
: : Unserialize ( s , VARINT ( nCode ) ) ;
fCoinBase = nCode & 1 ;
std : : vector < bool > vAvail ( 2 , false ) ;
vAvail [ 0 ] = ( nCode & 2 ) ! = 0 ;
vAvail [ 1 ] = ( nCode & 4 ) ! = 0 ;
unsigned int nMaskCode = ( nCode / 8 ) + ( ( nCode & 6 ) ! = 0 ? 0 : 1 ) ;
// spentness bitmask
while ( nMaskCode > 0 ) {
unsigned char chAvail = 0 ;
: : Unserialize ( s , chAvail ) ;
for ( unsigned int p = 0 ; p < 8 ; p + + ) {
bool f = ( chAvail & ( 1 < < p ) ) ! = 0 ;
vAvail . push_back ( f ) ;
}
if ( chAvail ! = 0 )
nMaskCode - - ;
}
// txouts themself
vout . assign ( vAvail . size ( ) , CTxOut ( ) ) ;
for ( unsigned int i = 0 ; i < vAvail . size ( ) ; i + + ) {
if ( vAvail [ i ] )
2020-01-18 12:32:58 -03:00
: : Unserialize ( s , Using < TxOutCompression > ( vout [ i ] ) ) ;
2017-04-25 15:29:48 -03:00
}
// coinbase height
2020-02-07 00:57:32 -03:00
: : Unserialize ( s , VARINT_MODE ( nHeight , VarIntMode : : NONNEGATIVE_SIGNED ) ) ;
2017-04-25 15:29:48 -03:00
}
} ;
}
2017-04-25 15:29:46 -03:00
/** Upgrade the database from older formats.
*
* Currently implemented : from the per - tx utxo model ( 0.8 . .0 .14 . x ) to per - txout .
*/
bool CCoinsViewDB : : Upgrade ( ) {
2019-04-17 10:07:15 -04:00
std : : unique_ptr < CDBIterator > pcursor ( m_db - > NewIterator ( ) ) ;
2017-04-25 15:29:46 -03:00
pcursor - > Seek ( std : : make_pair ( DB_COINS , uint256 ( ) ) ) ;
if ( ! pcursor - > Valid ( ) ) {
return true ;
}
2017-06-23 03:35:24 -04:00
int64_t count = 0 ;
2017-06-23 03:51:59 -04:00
LogPrintf ( " Upgrading utxo-set database... \n " ) ;
2018-04-05 11:17:32 -03:00
LogPrintf ( " [0%%]... " ) ; /* Continued */
2019-06-28 14:09:58 -04:00
uiInterface . ShowProgress ( _ ( " Upgrading UTXO database " ) . translated , 0 , true ) ;
2017-04-25 15:29:46 -03:00
size_t batch_size = 1 < < 24 ;
2019-04-17 10:07:15 -04:00
CDBBatch batch ( * m_db ) ;
2017-06-28 15:05:39 -04:00
int reportDone = 0 ;
2017-06-02 20:52:37 -04:00
std : : pair < unsigned char , uint256 > key ;
std : : pair < unsigned char , uint256 > prev_key = { DB_COINS , uint256 ( ) } ;
2017-04-25 15:29:46 -03:00
while ( pcursor - > Valid ( ) ) {
2017-06-23 03:33:31 -04:00
if ( ShutdownRequested ( ) ) {
break ;
}
2017-04-25 15:29:46 -03:00
if ( pcursor - > GetKey ( key ) & & key . first = = DB_COINS ) {
2017-06-23 03:35:24 -04:00
if ( count + + % 256 = = 0 ) {
uint32_t high = 0x100 * * key . second . begin ( ) + * ( key . second . begin ( ) + 1 ) ;
2017-06-28 15:05:39 -04:00
int percentageDone = ( int ) ( high * 100.0 / 65536.0 + 0.5 ) ;
2019-06-28 14:09:58 -04:00
uiInterface . ShowProgress ( _ ( " Upgrading UTXO database " ) . translated , percentageDone , true ) ;
2017-06-28 15:05:39 -04:00
if ( reportDone < percentageDone / 10 ) {
// report max. every 10% step
2018-04-05 11:17:32 -03:00
LogPrintf ( " [%d%%]... " , percentageDone ) ; /* Continued */
2017-06-28 15:05:39 -04:00
reportDone = percentageDone / 10 ;
}
2017-06-23 03:35:24 -04:00
}
2017-04-25 15:29:46 -03:00
CCoins old_coins ;
if ( ! pcursor - > GetValue ( old_coins ) ) {
return error ( " %s: cannot parse CCoins record " , __func__ ) ;
}
COutPoint outpoint ( key . second , 0 ) ;
for ( size_t i = 0 ; i < old_coins . vout . size ( ) ; + + i ) {
if ( ! old_coins . vout [ i ] . IsNull ( ) & & ! old_coins . vout [ i ] . scriptPubKey . IsUnspendable ( ) ) {
Coin newcoin ( std : : move ( old_coins . vout [ i ] ) , old_coins . nHeight , old_coins . fCoinBase ) ;
outpoint . n = i ;
CoinEntry entry ( & outpoint ) ;
batch . Write ( entry , newcoin ) ;
}
}
batch . Erase ( key ) ;
if ( batch . SizeEstimate ( ) > batch_size ) {
2019-04-17 10:07:15 -04:00
m_db - > WriteBatch ( batch ) ;
2017-04-25 15:29:46 -03:00
batch . Clear ( ) ;
2019-04-17 10:07:15 -04:00
m_db - > CompactRange ( prev_key , key ) ;
2017-06-02 20:52:37 -04:00
prev_key = key ;
2017-04-25 15:29:46 -03:00
}
pcursor - > Next ( ) ;
} else {
break ;
}
}
2019-04-17 10:07:15 -04:00
m_db - > WriteBatch ( batch ) ;
m_db - > CompactRange ( { DB_COINS , uint256 ( ) } , key ) ;
2017-07-07 17:09:55 -04:00
uiInterface . ShowProgress ( " " , 100 , false ) ;
2017-06-28 15:28:11 -04:00
LogPrintf ( " [%s]. \n " , ShutdownRequested ( ) ? " CANCELLED " : " DONE " ) ;
2017-08-06 21:25:04 -04:00
return ! ShutdownRequested ( ) ;
2017-04-25 15:29:46 -03:00
}