Bitcoin Core  27.99.0
P2P Digital Currency
txdb.cpp
Go to the documentation of this file.
1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2022 The Bitcoin Core developers
3 // Distributed under the MIT software license, see the accompanying
4 // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5 
6 #include <txdb.h>
7 
8 #include <coins.h>
9 #include <dbwrapper.h>
10 #include <logging.h>
11 #include <primitives/transaction.h>
12 #include <random.h>
13 #include <serialize.h>
14 #include <uint256.h>
15 #include <util/vector.h>
16 
17 #include <cassert>
18 #include <cstdlib>
19 #include <iterator>
20 #include <utility>
21 
22 static constexpr uint8_t DB_COIN{'C'};
23 static constexpr uint8_t DB_BEST_BLOCK{'B'};
24 static constexpr uint8_t DB_HEAD_BLOCKS{'H'};
25 // Keys used in previous version that might still be found in the DB:
26 static constexpr uint8_t DB_COINS{'c'};
27 
29 {
30  std::unique_ptr<CDBIterator> cursor{m_db->NewIterator()};
31  // DB_COINS was deprecated in v0.15.0, commit
32  // 1088b02f0ccd7358d2b7076bb9e122d59d502d02
33  cursor->Seek(std::make_pair(DB_COINS, uint256{}));
34  return cursor->Valid();
35 }
36 
37 namespace {
38 
39 struct CoinEntry {
40  COutPoint* outpoint;
41  uint8_t key;
42  explicit CoinEntry(const COutPoint* ptr) : outpoint(const_cast<COutPoint*>(ptr)), key(DB_COIN) {}
43 
44  SERIALIZE_METHODS(CoinEntry, obj) { READWRITE(obj.key, obj.outpoint->hash, VARINT(obj.outpoint->n)); }
45 };
46 
47 } // namespace
48 
50  m_db_params{std::move(db_params)},
51  m_options{std::move(options)},
52  m_db{std::make_unique<CDBWrapper>(m_db_params)} { }
53 
54 void CCoinsViewDB::ResizeCache(size_t new_cache_size)
55 {
56  // We can't do this operation with an in-memory DB since we'll lose all the coins upon
57  // reset.
58  if (!m_db_params.memory_only) {
59  // Have to do a reset first to get the original `m_db` state to release its
60  // filesystem lock.
61  m_db.reset();
62  m_db_params.cache_bytes = new_cache_size;
63  m_db_params.wipe_data = false;
64  m_db = std::make_unique<CDBWrapper>(m_db_params);
65  }
66 }
67 
68 bool CCoinsViewDB::GetCoin(const COutPoint &outpoint, Coin &coin) const {
69  return m_db->Read(CoinEntry(&outpoint), coin);
70 }
71 
72 bool CCoinsViewDB::HaveCoin(const COutPoint &outpoint) const {
73  return m_db->Exists(CoinEntry(&outpoint));
74 }
75 
77  uint256 hashBestChain;
78  if (!m_db->Read(DB_BEST_BLOCK, hashBestChain))
79  return uint256();
80  return hashBestChain;
81 }
82 
83 std::vector<uint256> CCoinsViewDB::GetHeadBlocks() const {
84  std::vector<uint256> vhashHeadBlocks;
85  if (!m_db->Read(DB_HEAD_BLOCKS, vhashHeadBlocks)) {
86  return std::vector<uint256>();
87  }
88  return vhashHeadBlocks;
89 }
90 
91 bool CCoinsViewDB::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock, bool erase) {
92  CDBBatch batch(*m_db);
93  size_t count = 0;
94  size_t changed = 0;
95  assert(!hashBlock.IsNull());
96 
97  uint256 old_tip = GetBestBlock();
98  if (old_tip.IsNull()) {
99  // We may be in the middle of replaying.
100  std::vector<uint256> old_heads = GetHeadBlocks();
101  if (old_heads.size() == 2) {
102  if (old_heads[0] != hashBlock) {
103  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");
104  }
105  assert(old_heads[0] == hashBlock);
106  old_tip = old_heads[1];
107  }
108  }
109 
110  // In the first batch, mark the database as being in the middle of a
111  // transition from old_tip to hashBlock.
112  // A vector is used for future extensibility, as we may want to support
113  // interrupting after partial writes from multiple independent reorgs.
114  batch.Erase(DB_BEST_BLOCK);
115  batch.Write(DB_HEAD_BLOCKS, Vector(hashBlock, old_tip));
116 
117  for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end();) {
118  if (it->second.flags & CCoinsCacheEntry::DIRTY) {
119  CoinEntry entry(&it->first);
120  if (it->second.coin.IsSpent())
121  batch.Erase(entry);
122  else
123  batch.Write(entry, it->second.coin);
124  changed++;
125  }
126  count++;
127  it = erase ? mapCoins.erase(it) : std::next(it);
128  if (batch.SizeEstimate() > m_options.batch_write_bytes) {
129  LogPrint(BCLog::COINDB, "Writing partial batch of %.2f MiB\n", batch.SizeEstimate() * (1.0 / 1048576.0));
130  m_db->WriteBatch(batch);
131  batch.Clear();
133  static FastRandomContext rng;
134  if (rng.randrange(m_options.simulate_crash_ratio) == 0) {
135  LogPrintf("Simulating a crash. Goodbye.\n");
136  _Exit(0);
137  }
138  }
139  }
140  }
141 
142  // In the last batch, mark the database as consistent with hashBlock again.
143  batch.Erase(DB_HEAD_BLOCKS);
144  batch.Write(DB_BEST_BLOCK, hashBlock);
145 
146  LogPrint(BCLog::COINDB, "Writing final batch of %.2f MiB\n", batch.SizeEstimate() * (1.0 / 1048576.0));
147  bool ret = m_db->WriteBatch(batch);
148  LogPrint(BCLog::COINDB, "Committed %u changed transaction outputs (out of %u) to coin database...\n", (unsigned int)changed, (unsigned int)count);
149  return ret;
150 }
151 
153 {
154  return m_db->EstimateSize(DB_COIN, uint8_t(DB_COIN + 1));
155 }
156 
159 {
160 public:
161  // Prefer using CCoinsViewDB::Cursor() since we want to perform some
162  // cache warmup on instantiation.
163  CCoinsViewDBCursor(CDBIterator* pcursorIn, const uint256&hashBlockIn):
164  CCoinsViewCursor(hashBlockIn), pcursor(pcursorIn) {}
165  ~CCoinsViewDBCursor() = default;
166 
167  bool GetKey(COutPoint &key) const override;
168  bool GetValue(Coin &coin) const override;
169 
170  bool Valid() const override;
171  void Next() override;
172 
173 private:
174  std::unique_ptr<CDBIterator> pcursor;
175  std::pair<char, COutPoint> keyTmp;
176 
177  friend class CCoinsViewDB;
178 };
179 
180 std::unique_ptr<CCoinsViewCursor> CCoinsViewDB::Cursor() const
181 {
182  auto i = std::make_unique<CCoinsViewDBCursor>(
183  const_cast<CDBWrapper&>(*m_db).NewIterator(), GetBestBlock());
184  /* It seems that there are no "const iterators" for LevelDB. Since we
185  only need read operations on it, use a const-cast to get around
186  that restriction. */
187  i->pcursor->Seek(DB_COIN);
188  // Cache key of first record
189  if (i->pcursor->Valid()) {
190  CoinEntry entry(&i->keyTmp.second);
191  i->pcursor->GetKey(entry);
192  i->keyTmp.first = entry.key;
193  } else {
194  i->keyTmp.first = 0; // Make sure Valid() and GetKey() return false
195  }
196  return i;
197 }
198 
200 {
201  // Return cached key
202  if (keyTmp.first == DB_COIN) {
203  key = keyTmp.second;
204  return true;
205  }
206  return false;
207 }
208 
210 {
211  return pcursor->GetValue(coin);
212 }
213 
215 {
216  return keyTmp.first == DB_COIN;
217 }
218 
220 {
221  pcursor->Next();
222  CoinEntry entry(&keyTmp.second);
223  if (!pcursor->Valid() || !pcursor->GetKey(entry)) {
224  keyTmp.first = 0; // Invalidate cached key after last record so that Valid() and GetKey() return false
225  } else {
226  keyTmp.first = entry.key;
227  }
228 }
int ret
Cursor for iterating over CoinsView state.
Definition: coins.h:154
Specialization of CCoinsViewCursor to iterate over a CCoinsViewDB.
Definition: txdb.cpp:159
std::unique_ptr< CDBIterator > pcursor
Definition: txdb.cpp:174
bool GetKey(COutPoint &key) const override
Definition: txdb.cpp:199
~CCoinsViewDBCursor()=default
bool GetValue(Coin &coin) const override
Definition: txdb.cpp:209
CCoinsViewDBCursor(CDBIterator *pcursorIn, const uint256 &hashBlockIn)
Definition: txdb.cpp:163
bool Valid() const override
Definition: txdb.cpp:214
void Next() override
Definition: txdb.cpp:219
std::pair< char, COutPoint > keyTmp
Definition: txdb.cpp:175
CCoinsView backed by the coin database (chainstate/)
Definition: txdb.h:54
bool GetCoin(const COutPoint &outpoint, Coin &coin) const override
Retrieve the Coin (unspent transaction output) for a given outpoint.
Definition: txdb.cpp:68
bool HaveCoin(const COutPoint &outpoint) const override
Just check whether a given outpoint is unspent.
Definition: txdb.cpp:72
std::unique_ptr< CDBWrapper > m_db
Definition: txdb.h:58
bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock, bool erase=true) override
Do a bulk modification (multiple Coin changes + BestBlock change).
Definition: txdb.cpp:91
CCoinsViewDB(DBParams db_params, CoinsViewOptions options)
Definition: txdb.cpp:49
uint256 GetBestBlock() const override
Retrieve the block hash whose state this CCoinsView currently represents.
Definition: txdb.cpp:76
std::unique_ptr< CCoinsViewCursor > Cursor() const override
Get a cursor to iterate over the whole state.
Definition: txdb.cpp:180
void ResizeCache(size_t new_cache_size) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
Dynamically alter the underlying leveldb cache size.
Definition: txdb.cpp:54
CoinsViewOptions m_options
Definition: txdb.h:57
std::vector< uint256 > GetHeadBlocks() const override
Retrieve the range of blocks that may have been only partially written.
Definition: txdb.cpp:83
bool NeedsUpgrade()
Whether an unsupported database format is used.
Definition: txdb.cpp:28
size_t EstimateSize() const override
Estimate database size (0 if not implemented)
Definition: txdb.cpp:152
DBParams m_db_params
Definition: txdb.h:56
Batch of changes queued to be written to a CDBWrapper.
Definition: dbwrapper.h:73
void Erase(const K &key)
Definition: dbwrapper.h:111
size_t SizeEstimate() const
Definition: dbwrapper.h:119
void Write(const K &key, const V &value)
Definition: dbwrapper.h:99
void Clear()
Definition: dbwrapper.cpp:164
CDBIterator * NewIterator()
Definition: dbwrapper.cpp:393
An outpoint - a combination of a transaction hash and an index n into its vout.
Definition: transaction.h:29
A UTXO entry.
Definition: coins.h:32
Fast randomness source.
Definition: random.h:145
uint64_t randrange(uint64_t range) noexcept
Generate a random integer in the range [0..range).
Definition: random.h:203
constexpr bool IsNull() const
Definition: uint256.h:42
256-bit opaque blob.
Definition: uint256.h:106
std::unordered_map< COutPoint, CCoinsCacheEntry, SaltedOutpointHasher, std::equal_to< COutPoint >, PoolAllocator< std::pair< const COutPoint, CCoinsCacheEntry >, sizeof(std::pair< const COutPoint, CCoinsCacheEntry >)+sizeof(void *) *4 > > CCoinsMap
PoolAllocator's MAX_BLOCK_SIZE_BYTES parameter here uses sizeof the data, and adds the size of 4 poin...
Definition: coins.h:148
#define LogPrintLevel(category, level,...)
Definition: logging.h:251
#define LogPrint(category,...)
Definition: logging.h:263
#define LogPrintf(...)
Definition: logging.h:244
@ COINDB
Definition: logging.h:59
#define VARINT(obj)
Definition: serialize.h:498
#define SERIALIZE_METHODS(cls, obj)
Implement the Serialize and Unserialize methods by delegating to a single templated static method tha...
Definition: serialize.h:240
#define READWRITE(...)
Definition: serialize.h:156
@ DIRTY
DIRTY means the CCoinsCacheEntry is potentially different from the version in the parent cache.
Definition: coins.h:117
User-controlled performance and debug options.
Definition: txdb.h:44
int simulate_crash_ratio
If non-zero, randomly exit when the database is flushed with (1/ratio) probability.
Definition: txdb.h:49
size_t batch_write_bytes
Maximum database write batch size in bytes.
Definition: txdb.h:46
Application-specific storage settings.
Definition: dbwrapper.h:33
bool wipe_data
If true, remove all existing data.
Definition: dbwrapper.h:41
size_t cache_bytes
Configures various leveldb cache settings.
Definition: dbwrapper.h:37
bool memory_only
If true, use leveldb's memory environment.
Definition: dbwrapper.h:39
static int count
static constexpr uint8_t DB_HEAD_BLOCKS
Definition: txdb.cpp:24
static constexpr uint8_t DB_BEST_BLOCK
Definition: txdb.cpp:23
static constexpr uint8_t DB_COIN
Definition: txdb.cpp:22
static constexpr uint8_t DB_COINS
Definition: txdb.cpp:26
assert(!tx.IsCoinBase())
std::vector< typename std::common_type< Args... >::type > Vector(Args &&... args)
Construct a vector with the specified elements.
Definition: vector.h:23