Bitcoin Core  31.0.0
P2P Digital Currency
txdb.cpp
Go to the documentation of this file.
1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2009-present 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/timer.h>
11 #include <primitives/transaction.h>
12 #include <random.h>
13 #include <serialize.h>
14 #include <uint256.h>
15 #include <util/log.h>
16 #include <util/vector.h>
17 
18 #include <cassert>
19 #include <cstdlib>
20 #include <iterator>
21 #include <utility>
22 
23 static constexpr uint8_t DB_COIN{'C'};
24 static constexpr uint8_t DB_BEST_BLOCK{'B'};
25 static constexpr uint8_t DB_HEAD_BLOCKS{'H'};
26 // Keys used in previous version that might still be found in the DB:
27 static constexpr uint8_t DB_COINS{'c'};
28 
29 // Threshold for warning when writing this many dirty cache entries to disk.
30 static constexpr size_t WARN_FLUSH_COINS_COUNT{10'000'000};
31 
33 {
34  std::unique_ptr<CDBIterator> cursor{m_db->NewIterator()};
35  // DB_COINS was deprecated in v0.15.0, commit
36  // 1088b02f0ccd7358d2b7076bb9e122d59d502d02
37  cursor->Seek(std::make_pair(DB_COINS, uint256{}));
38  return cursor->Valid();
39 }
40 
41 namespace {
42 
43 struct CoinEntry {
44  COutPoint* outpoint;
45  uint8_t key{DB_COIN};
46  explicit CoinEntry(const COutPoint* ptr) : outpoint(const_cast<COutPoint*>(ptr)) {}
47 
48  SERIALIZE_METHODS(CoinEntry, obj) { READWRITE(obj.key, obj.outpoint->hash, VARINT(obj.outpoint->n)); }
49 };
50 
51 } // namespace
52 
54  m_db_params{std::move(db_params)},
55  m_options{std::move(options)},
56  m_db{std::make_unique<CDBWrapper>(m_db_params)} { }
57 
58 void CCoinsViewDB::ResizeCache(size_t new_cache_size)
59 {
60  // We can't do this operation with an in-memory DB since we'll lose all the coins upon
61  // reset.
62  if (!m_db_params.memory_only) {
63  // Have to do a reset first to get the original `m_db` state to release its
64  // filesystem lock.
65  m_db.reset();
66  m_db_params.cache_bytes = new_cache_size;
67  m_db_params.wipe_data = false;
68  m_db = std::make_unique<CDBWrapper>(m_db_params);
69  }
70 }
71 
72 std::optional<Coin> CCoinsViewDB::GetCoin(const COutPoint& outpoint) const
73 {
74  if (Coin coin; m_db->Read(CoinEntry(&outpoint), coin)) {
75  Assert(!coin.IsSpent()); // The UTXO database should never contain spent coins
76  return coin;
77  }
78  return std::nullopt;
79 }
80 
81 bool CCoinsViewDB::HaveCoin(const COutPoint &outpoint) const {
82  return m_db->Exists(CoinEntry(&outpoint));
83 }
84 
86  uint256 hashBestChain;
87  if (!m_db->Read(DB_BEST_BLOCK, hashBestChain))
88  return uint256();
89  return hashBestChain;
90 }
91 
92 std::vector<uint256> CCoinsViewDB::GetHeadBlocks() const {
93  std::vector<uint256> vhashHeadBlocks;
94  if (!m_db->Read(DB_HEAD_BLOCKS, vhashHeadBlocks)) {
95  return std::vector<uint256>();
96  }
97  return vhashHeadBlocks;
98 }
99 
101 {
102  CDBBatch batch(*m_db);
103  size_t count = 0;
104  const size_t dirty_count{cursor.GetDirtyCount()};
105  assert(!hashBlock.IsNull());
106 
107  uint256 old_tip = GetBestBlock();
108  if (old_tip.IsNull()) {
109  // We may be in the middle of replaying.
110  std::vector<uint256> old_heads = GetHeadBlocks();
111  if (old_heads.size() == 2) {
112  if (old_heads[0] != hashBlock) {
113  LogError("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");
114  }
115  assert(old_heads[0] == hashBlock);
116  old_tip = old_heads[1];
117  }
118  }
119 
120  if (dirty_count > WARN_FLUSH_COINS_COUNT) LogWarning("Flushing large (%d entries) UTXO set to disk, it may take several minutes", dirty_count);
121  LOG_TIME_MILLIS_WITH_CATEGORY(strprintf("write coins cache to disk (%d out of %d cached coins)",
122  dirty_count, cursor.GetTotalCount()), BCLog::BENCH);
123 
124  // In the first batch, mark the database as being in the middle of a
125  // transition from old_tip to hashBlock.
126  // A vector is used for future extensibility, as we may want to support
127  // interrupting after partial writes from multiple independent reorgs.
128  batch.Erase(DB_BEST_BLOCK);
129  batch.Write(DB_HEAD_BLOCKS, Vector(hashBlock, old_tip));
130 
131  for (auto it{cursor.Begin()}; it != cursor.End();) {
132  if (it->second.IsDirty()) {
133  CoinEntry entry(&it->first);
134  if (it->second.coin.IsSpent()) {
135  batch.Erase(entry);
136  } else {
137  batch.Write(entry, it->second.coin);
138  }
139  }
140  count++;
141  it = cursor.NextAndMaybeErase(*it);
143  LogDebug(BCLog::COINDB, "Writing partial batch of %.2f MiB\n", batch.ApproximateSize() * (1.0 / 1048576.0));
144 
145  m_db->WriteBatch(batch);
146  batch.Clear();
148  static FastRandomContext rng;
149  if (rng.randrange(m_options.simulate_crash_ratio) == 0) {
150  LogError("Simulating a crash. Goodbye.");
151  _Exit(0);
152  }
153  }
154  }
155  }
156 
157  // In the last batch, mark the database as consistent with hashBlock again.
158  batch.Erase(DB_HEAD_BLOCKS);
159  batch.Write(DB_BEST_BLOCK, hashBlock);
160 
161  LogDebug(BCLog::COINDB, "Writing final batch of %.2f MiB\n", batch.ApproximateSize() * (1.0 / 1048576.0));
162  m_db->WriteBatch(batch);
163  LogDebug(BCLog::COINDB, "Committed %u changed transaction outputs (out of %u) to coin database...", (unsigned int)dirty_count, (unsigned int)count);
164 }
165 
167 {
168  return m_db->EstimateSize(DB_COIN, uint8_t(DB_COIN + 1));
169 }
170 
173 {
174 public:
175  // Prefer using CCoinsViewDB::Cursor() since we want to perform some
176  // cache warmup on instantiation.
177  CCoinsViewDBCursor(CDBIterator* pcursorIn, const uint256&hashBlockIn):
178  CCoinsViewCursor(hashBlockIn), pcursor(pcursorIn) {}
179  ~CCoinsViewDBCursor() = default;
180 
181  bool GetKey(COutPoint &key) const override;
182  bool GetValue(Coin &coin) const override;
183 
184  bool Valid() const override;
185  void Next() override;
186 
187 private:
188  std::unique_ptr<CDBIterator> pcursor;
189  std::pair<char, COutPoint> keyTmp;
190 
191  friend class CCoinsViewDB;
192 };
193 
194 std::unique_ptr<CCoinsViewCursor> CCoinsViewDB::Cursor() const
195 {
196  auto i = std::make_unique<CCoinsViewDBCursor>(
197  const_cast<CDBWrapper&>(*m_db).NewIterator(), GetBestBlock());
198  /* It seems that there are no "const iterators" for LevelDB. Since we
199  only need read operations on it, use a const-cast to get around
200  that restriction. */
201  i->pcursor->Seek(DB_COIN);
202  // Cache key of first record
203  if (i->pcursor->Valid()) {
204  CoinEntry entry(&i->keyTmp.second);
205  i->pcursor->GetKey(entry);
206  i->keyTmp.first = entry.key;
207  } else {
208  i->keyTmp.first = 0; // Make sure Valid() and GetKey() return false
209  }
210  return i;
211 }
212 
214 {
215  // Return cached key
216  if (keyTmp.first == DB_COIN) {
217  key = keyTmp.second;
218  return true;
219  }
220  return false;
221 }
222 
224 {
225  return pcursor->GetValue(coin);
226 }
227 
229 {
230  return keyTmp.first == DB_COIN;
231 }
232 
234 {
235  pcursor->Next();
236  CoinEntry entry(&keyTmp.second);
237  if (!pcursor->Valid() || !pcursor->GetKey(entry)) {
238  keyTmp.first = 0; // Invalidate cached key after last record so that Valid() and GetKey() return false
239  } else {
240  keyTmp.first = entry.key;
241  }
242 }
CoinsCachePair * NextAndMaybeErase(CoinsCachePair &current) noexcept
Return the next entry after current, possibly erasing current.
Definition: coins.h:279
bool GetValue(Coin &coin) const override
Definition: txdb.cpp:223
#define VARINT(obj)
Definition: serialize.h:491
void Clear()
Definition: dbwrapper.cpp:170
std::unique_ptr< CCoinsViewCursor > Cursor() const override
Get a cursor to iterate over the whole state.
Definition: txdb.cpp:194
Specialization of CCoinsViewCursor to iterate over a CCoinsViewDB.
Definition: txdb.cpp:172
assert(!tx.IsCoinBase())
size_t ApproximateSize() const
Definition: dbwrapper.cpp:189
Batch of changes queued to be written to a CDBWrapper.
Definition: dbwrapper.h:71
A UTXO entry.
Definition: coins.h:34
#define LogWarning(...)
Definition: log.h:96
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
Definition: tinyformat.h:1172
CoinsCachePair * End() const noexcept
Definition: coins.h:276
size_t GetDirtyCount() const noexcept
Definition: coins.h:297
void Erase(const K &key)
Definition: dbwrapper.h:108
std::unique_ptr< CDBIterator > pcursor
Definition: txdb.cpp:188
void ResizeCache(size_t new_cache_size) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
Dynamically alter the underlying leveldb cache size.
Definition: txdb.cpp:58
User-controlled performance and debug options.
Definition: txdb.h:26
CoinsViewOptions m_options
Definition: txdb.h:38
static constexpr uint8_t DB_BEST_BLOCK
Definition: txdb.cpp:24
static constexpr uint8_t DB_HEAD_BLOCKS
Definition: txdb.cpp:25
bool GetKey(COutPoint &key) const override
Definition: txdb.cpp:213
DBParams m_db_params
Definition: txdb.h:37
bool NeedsUpgrade()
Whether an unsupported database format is used.
Definition: txdb.cpp:32
CCoinsViewDB(DBParams db_params, CoinsViewOptions options)
Definition: txdb.cpp:53
size_t batch_write_bytes
Maximum database write batch size in bytes.
Definition: txdb.h:28
Cursor for iterating over the linked list of flagged entries in CCoinsViewCache.
Definition: coins.h:260
Fast randomness source.
Definition: random.h:385
CDBIterator * NewIterator()
Definition: dbwrapper.cpp:360
std::vector< std::common_type_t< Args... > > Vector(Args &&... args)
Construct a vector with the specified elements.
Definition: vector.h:23
static constexpr uint8_t DB_COINS
Definition: txdb.cpp:27
void Write(const K &key, const V &value)
Definition: dbwrapper.h:96
CCoinsViewDBCursor(CDBIterator *pcursorIn, const uint256 &hashBlockIn)
Definition: txdb.cpp:177
size_t EstimateSize() const override
Estimate database size (0 if not implemented)
Definition: txdb.cpp:166
An outpoint - a combination of a transaction hash and an index n into its vout.
Definition: transaction.h:28
bool wipe_data
If true, remove all existing data.
Definition: dbwrapper.h:41
std::pair< char, COutPoint > keyTmp
Definition: txdb.cpp:189
constexpr bool IsNull() const
Definition: uint256.h:48
bool HaveCoin(const COutPoint &outpoint) const override
Just check whether a given outpoint is unspent.
Definition: txdb.cpp:81
~CCoinsViewDBCursor()=default
#define SERIALIZE_METHODS(cls, obj)
Implement the Serialize and Unserialize methods by delegating to a single templated static method tha...
Definition: serialize.h:229
CoinsCachePair * Begin() const noexcept
Definition: coins.h:275
uint256 GetBestBlock() const override
Retrieve the block hash whose state this CCoinsView currently represents.
Definition: txdb.cpp:85
size_t GetTotalCount() const noexcept
Definition: coins.h:298
#define LogDebug(category,...)
Definition: log.h:115
256-bit opaque blob.
Definition: uint256.h:195
void BatchWrite(CoinsViewCacheCursor &cursor, const uint256 &hashBlock) override
Do a bulk modification (multiple Coin changes + BestBlock change).
Definition: txdb.cpp:100
constexpr CoinEntry(const CAmount v, const State s)
static constexpr uint8_t DB_COIN
Definition: txdb.cpp:23
CCoinsView backed by the coin database (chainstate/)
Definition: txdb.h:34
static constexpr size_t WARN_FLUSH_COINS_COUNT
Definition: txdb.cpp:30
Application-specific storage settings.
Definition: dbwrapper.h:33
I randrange(I range) noexcept
Generate a random integer in the range [0..range), with range > 0.
Definition: random.h:254
std::optional< Coin > GetCoin(const COutPoint &outpoint) const override
Retrieve the Coin (unspent transaction output) for a given outpoint.
Definition: txdb.cpp:72
static int count
void Next() override
Definition: txdb.cpp:233
bool Valid() const override
Definition: txdb.cpp:228
int simulate_crash_ratio
If non-zero, randomly exit when the database is flushed with (1/ratio) probability.
Definition: txdb.h:30
size_t cache_bytes
Configures various leveldb cache settings.
Definition: dbwrapper.h:37
#define LOG_TIME_MILLIS_WITH_CATEGORY(end_msg, log_category)
Definition: timer.h:103
#define READWRITE(...)
Definition: serialize.h:145
std::vector< uint256 > GetHeadBlocks() const override
Retrieve the range of blocks that may have been only partially written.
Definition: txdb.cpp:92
bool memory_only
If true, use leveldb&#39;s memory environment.
Definition: dbwrapper.h:39
std::unique_ptr< CDBWrapper > m_db
Definition: txdb.h:39
#define Assert(val)
Identity function.
Definition: check.h:113
#define LogError(...)
Definition: log.h:97
Cursor for iterating over CoinsView state.
Definition: coins.h:229