2012-09-03 16:14:03 -03:00
// Copyright (c) 2009-2010 Satoshi Nakamoto
2021-12-30 14:36:57 -03:00
// Copyright (c) 2009-2021 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>
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_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:
2022-02-02 09:23:02 -03:00
static constexpr uint8_t DB_COINS { ' c ' } ;
2021-08-04 14:55:31 -04:00
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 ) ) {
2022-02-17 08:54:39 -03:00
return _ ( " The -txindex upgrade started by a previous version cannot be completed. Restart with the previous version or run a full -reindex. " ) ;
2021-08-04 14:55:31 -04:00
}
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 ;
}
2022-02-02 09:23:02 -03:00
bool CCoinsViewDB : : NeedsUpgrade ( )
{
std : : unique_ptr < CDBIterator > cursor { m_db - > NewIterator ( ) } ;
// DB_COINS was deprecated in v0.15.0, commit
// 1088b02f0ccd7358d2b7076bb9e122d59d502d02
cursor - > Seek ( std : : make_pair ( DB_COINS , uint256 { } ) ) ;
return cursor - > Valid ( ) ;
}
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
} ;
2022-02-02 09:23:02 -03:00
} // namespace
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 > (
2022-04-02 12:01:40 -03:00
m_ldb_path , new_cache_size , m_is_memory , /*fWipe=*/ false , /*obfuscate=*/ true ) ;
2020-08-25 13:48:21 -04:00
}
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
{
2022-01-28 16:25:50 -03:00
AssertLockHeld ( : : cs_main ) ;
2016-08-30 17:41:56 -03:00
std : : unique_ptr < CDBIterator > pcursor ( NewIterator ( ) ) ;
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 ;
2022-01-28 16:25:50 -03:00
pindexNew - > nFile = diskindex . nFile ;
pindexNew - > nDataPos = diskindex . nDataPos ;
pindexNew - > nUndoPos = diskindex . nUndoPos ;
2012-09-03 16:14:03 -03:00
pindexNew - > nVersion = diskindex . nVersion ;
pindexNew - > hashMerkleRoot = diskindex . hashMerkleRoot ;
pindexNew - > nTime = diskindex . nTime ;
pindexNew - > nBits = diskindex . nBits ;
pindexNew - > nNonce = diskindex . nNonce ;
2022-01-28 16:25:50 -03:00
pindexNew - > nStatus = diskindex . nStatus ;
2012-09-03 16:14:03 -03:00
pindexNew - > nTx = diskindex . nTx ;
2022-01-19 09:42:32 -03:00
if ( ! CheckProofOfWork ( pindexNew - > GetBlockHash ( ) , pindexNew - > nBits , consensusParams ) ) {
2016-11-07 19:31:55 -03:00
return error ( " %s: CheckProofOfWork failed: %s " , __func__ , pindexNew - > ToString ( ) ) ;
2022-01-19 09:42:32 -03:00
}
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 ;
}