2012-09-03 21:14:03 +02:00
// Copyright (c) 2009-2010 Satoshi Nakamoto
2022-12-24 23:49:50 +00:00
// Copyright (c) 2009-2022 The Bitcoin Core developers
2014-12-13 12:09:33 +08:00
// Distributed under the MIT software license, see the accompanying
2012-09-03 21:14:03 +02:00
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
2017-11-10 13:57:53 +13:00
# include <txdb.h>
2023-08-01 11:01:48 +02:00
# include <coins.h>
# include <dbwrapper.h>
2023-03-06 22:01:13 +01:00
# include <logging.h>
2023-08-01 11:01:48 +02:00
# include <primitives/transaction.h>
2019-06-17 10:56:52 +03:00
# include <random.h>
2023-08-01 11:01:48 +02:00
# include <serialize.h>
2017-11-10 13:57:53 +13:00
# include <uint256.h>
2019-08-28 15:12:51 -07:00
# include <util/vector.h>
2013-04-13 00:13:08 -05:00
2023-08-01 11:01:48 +02:00
# include <cassert>
# include <cstdlib>
# include <iterator>
2023-08-01 12:01:02 +02:00
# include <utility>
2012-09-03 21:14:03 +02:00
2021-05-31 14:57:32 +02:00
static constexpr uint8_t DB_COIN { ' C ' } ;
static constexpr uint8_t DB_BEST_BLOCK { ' B ' } ;
static constexpr uint8_t DB_HEAD_BLOCKS { ' H ' } ;
2021-08-04 20:55:31 +02:00
// Keys used in previous version that might still be found in the DB:
2022-02-02 13:23:02 +01:00
static constexpr uint8_t DB_COINS { ' c ' } ;
2021-08-04 20:55:31 +02:00
2022-02-02 13:23:02 +01: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 11:29:39 -07:00
namespace {
2017-05-30 17:58:54 -07:00
struct CoinEntry {
2017-04-25 11:29:39 -07:00
COutPoint * outpoint ;
2021-05-31 14:57:32 +02:00
uint8_t key ;
2017-08-01 12:22:41 +02:00
explicit CoinEntry ( const COutPoint * ptr ) : outpoint ( const_cast < COutPoint * > ( ptr ) ) , key ( DB_COIN ) { }
2017-04-25 11:29:39 -07:00
2020-03-11 09:35:50 -07:00
SERIALIZE_METHODS ( CoinEntry , obj ) { READWRITE ( obj . key , obj . outpoint - > hash , VARINT ( obj . outpoint - > n ) ) ; }
2017-04-25 11:29:39 -07:00
} ;
2022-02-02 13:23:02 +01:00
} // namespace
2015-01-25 10:27:54 -05:00
2022-08-16 23:32:55 -04:00
CCoinsViewDB : : CCoinsViewDB ( DBParams db_params , CoinsViewOptions options ) :
m_db_params { std : : move ( db_params ) } ,
m_options { std : : move ( options ) } ,
m_db { std : : make_unique < CDBWrapper > ( m_db_params ) } { }
2019-04-17 10:07:15 -04:00
void CCoinsViewDB : : ResizeCache ( size_t new_cache_size )
2015-09-07 15:22:23 -07: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.
2022-08-16 23:32:55 -04:00
if ( ! m_db_params . memory_only ) {
2020-08-25 13:48:21 -04:00
// Have to do a reset first to get the original `m_db` state to release its
// filesystem lock.
m_db . reset ( ) ;
2022-08-16 23:32:55 -04:00
m_db_params . cache_bytes = new_cache_size ;
m_db_params . wipe_data = false ;
m_db = std : : make_unique < CDBWrapper > ( m_db_params ) ;
2020-08-25 13:48:21 -04:00
}
2012-09-03 21:14:03 +02:00
}
2017-05-30 17:58:54 -07: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 21:14:03 +02:00
}
2017-05-30 17:58:54 -07: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 21:14:03 +02:00
}
2014-07-19 16:42:48 +02:00
uint256 CCoinsViewDB : : GetBestBlock ( ) const {
2012-09-03 21:14:03 +02:00
uint256 hashBestChain ;
2019-04-17 10:07:15 -04:00
if ( ! m_db - > Read ( DB_BEST_BLOCK , hashBestChain ) )
2014-12-15 09:11:16 +01:00
return uint256 ( ) ;
2013-11-05 02:27:39 +01:00
return hashBestChain ;
2012-09-03 21:14:03 +02:00
}
2017-04-19 09:34:30 -07: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 09:34:30 -07:00
return std : : vector < uint256 > ( ) ;
}
return vhashHeadBlocks ;
}
2019-12-03 13:25:35 -05:00
bool CCoinsViewDB : : BatchWrite ( CCoinsMap & mapCoins , const uint256 & hashBlock , bool erase ) {
2019-04-17 10:07:15 -04:00
CDBBatch batch ( * m_db ) ;
2014-09-03 09:37:47 +02:00
size_t count = 0 ;
size_t changed = 0 ;
2017-04-17 11:41:10 -04:00
assert ( ! hashBlock . IsNull ( ) ) ;
2017-04-19 09:34:30 -07: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 ) {
2023-08-27 13:14:56 +02:00
if ( old_heads [ 0 ] ! = hashBlock ) {
LogPrintLevel ( BCLog : : COINDB , BCLog : : Level : : Error , " The coins database detected an inconsistent state, likely due to a previous crash or shutdown. You will need to restart bitcoind with the -reindex-chainstate or -reindex configuration option. \n " ) ;
}
2017-04-19 09:34:30 -07:00
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 15:12:51 -07:00
batch . Write ( DB_HEAD_BLOCKS , Vector ( hashBlock , old_tip ) ) ;
2017-04-19 09:34:30 -07:00
2014-08-24 02:08:05 +02:00
for ( CCoinsMap : : iterator it = mapCoins . begin ( ) ; it ! = mapCoins . end ( ) ; ) {
2014-09-03 09:37:47 +02:00
if ( it - > second . flags & CCoinsCacheEntry : : DIRTY ) {
2017-05-30 17:58:54 -07:00
CoinEntry entry ( & it - > first ) ;
if ( it - > second . coin . IsSpent ( ) )
2017-04-25 11:29:39 -07:00
batch . Erase ( entry ) ;
2015-09-07 15:22:23 -07:00
else
2017-05-04 00:15:36 -07:00
batch . Write ( entry , it - > second . coin ) ;
2014-09-03 09:37:47 +02:00
changed + + ;
}
count + + ;
2019-12-03 13:25:35 -05:00
it = erase ? mapCoins . erase ( it ) : std : : next ( it ) ;
2022-08-16 23:32:55 -04:00
if ( batch . SizeEstimate ( ) > m_options . batch_write_bytes ) {
2017-04-19 09:34:30 -07:00
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 09:34:30 -07:00
batch . Clear ( ) ;
2022-08-16 23:32:55 -04:00
if ( m_options . simulate_crash_ratio ) {
2017-04-05 01:37:09 -07:00
static FastRandomContext rng ;
2022-08-16 23:32:55 -04:00
if ( rng . randrange ( m_options . simulate_crash_ratio ) = = 0 ) {
2017-04-05 01:37:09 -07:00
LogPrintf ( " Simulating a crash. Goodbye. \n " ) ;
2017-06-15 17:08:48 -04:00
_Exit ( 0 ) ;
2017-04-05 01:37:09 -07:00
}
}
2017-04-19 09:34:30 -07:00
}
2014-08-24 02:08:05 +02:00
}
2012-09-03 21:14:03 +02:00
2017-04-19 09:34:30 -07: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 11:29:39 -07: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 21:14:03 +02:00
}
2017-05-12 15:19:19 -07:00
size_t CCoinsViewDB : : EstimateSize ( ) const
{
2021-05-31 14:57:32 +02:00
return m_db - > EstimateSize ( DB_COIN , uint8_t ( DB_COIN + 1 ) ) ;
2017-05-12 15:19:19 -07: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 ) { }
2022-05-11 16:02:15 +01:00
~ CCoinsViewDBCursor ( ) = default ;
2021-06-18 14:14:15 -04:00
bool GetKey ( COutPoint & key ) const override ;
bool GetValue ( Coin & coin ) 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 18:18:30 +02: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 16:42:48 +02: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 11:29:39 -07:00
i - > pcursor - > Seek ( DB_COIN ) ;
2016-03-28 18:18:30 +02:00
// Cache key of first record
2017-05-23 10:04:14 -07:00
if ( i - > pcursor - > Valid ( ) ) {
2017-05-30 17:58:54 -07:00
CoinEntry entry ( & i - > keyTmp . second ) ;
2017-04-25 11:29:39 -07:00
i - > pcursor - > GetKey ( entry ) ;
i - > keyTmp . first = entry . key ;
2017-05-23 10:04:14 -07:00
} else {
i - > keyTmp . first = 0 ; // Make sure Valid() and GetKey() return false
}
2016-03-28 18:18:30 +02:00
return i ;
}
2017-04-25 11:29:39 -07:00
bool CCoinsViewDBCursor : : GetKey ( COutPoint & key ) const
2016-03-28 18:18:30 +02:00
{
// Return cached key
2017-04-25 11:29:39 -07:00
if ( keyTmp . first = = DB_COIN ) {
2016-03-28 18:18:30 +02:00
key = keyTmp . second ;
return true ;
2012-09-25 23:04:54 +02:00
}
2016-03-28 18:18:30 +02:00
return false ;
}
2017-04-25 11:29:39 -07:00
bool CCoinsViewDBCursor : : GetValue ( Coin & coin ) const
2016-03-28 18:18:30 +02:00
{
2017-04-25 11:29:39 -07:00
return pcursor - > GetValue ( coin ) ;
2016-03-28 18:18:30 +02:00
}
bool CCoinsViewDBCursor : : Valid ( ) const
{
2017-04-25 11:29:39 -07:00
return keyTmp . first = = DB_COIN ;
2016-03-28 18:18:30 +02:00
}
void CCoinsViewDBCursor : : Next ( )
{
pcursor - > Next ( ) ;
2017-05-30 17:58:54 -07:00
CoinEntry entry ( & keyTmp . second ) ;
2017-04-25 11:29:39 -07:00
if ( ! pcursor - > Valid ( ) | | ! pcursor - > GetKey ( entry ) ) {
2016-03-28 18:18:30 +02:00
keyTmp . first = 0 ; // Invalidate cached key after last record so that Valid() and GetKey() return false
2017-04-25 11:29:39 -07:00
} else {
keyTmp . first = entry . key ;
}
2012-09-25 23:04:54 +02:00
}