Bitcoin Core  24.1.0
P2P Digital Currency
txdb.cpp
Go to the documentation of this file.
1 // Copyright (c) 2009-2010 Satoshi Nakamoto
2 // Copyright (c) 2009-2021 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 <chain.h>
9 #include <pow.h>
10 #include <random.h>
11 #include <shutdown.h>
12 #include <uint256.h>
13 #include <util/system.h>
14 #include <util/translation.h>
15 #include <util/vector.h>
16 
17 #include <stdint.h>
18 
19 static constexpr uint8_t DB_COIN{'C'};
20 static constexpr uint8_t DB_BLOCK_FILES{'f'};
21 static constexpr uint8_t DB_BLOCK_INDEX{'b'};
22 
23 static constexpr uint8_t DB_BEST_BLOCK{'B'};
24 static constexpr uint8_t DB_HEAD_BLOCKS{'H'};
25 static constexpr uint8_t DB_FLAG{'F'};
26 static constexpr uint8_t DB_REINDEX_FLAG{'R'};
27 static constexpr uint8_t DB_LAST_BLOCK{'l'};
28 
29 // Keys used in previous version that might still be found in the DB:
30 static constexpr uint8_t DB_COINS{'c'};
31 static constexpr uint8_t DB_TXINDEX_BLOCK{'T'};
32 // uint8_t DB_TXINDEX{'t'}
33 
34 std::optional<bilingual_str> CheckLegacyTxindex(CBlockTreeDB& block_tree_db)
35 {
36  CBlockLocator ignored{};
37  if (block_tree_db.Read(DB_TXINDEX_BLOCK, ignored)) {
38  return _("The -txindex upgrade started by a previous version cannot be completed. Restart with the previous version or run a full -reindex.");
39  }
40  bool txindex_legacy_flag{false};
41  block_tree_db.ReadFlag("txindex", txindex_legacy_flag);
42  if (txindex_legacy_flag) {
43  // Disable legacy txindex and warn once about occupied disk space
44  if (!block_tree_db.WriteFlag("txindex", false)) {
45  return Untranslated("Failed to write block index db flag 'txindex'='0'");
46  }
47  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.");
48  }
49  return std::nullopt;
50 }
51 
53 {
54  std::unique_ptr<CDBIterator> cursor{m_db->NewIterator()};
55  // DB_COINS was deprecated in v0.15.0, commit
56  // 1088b02f0ccd7358d2b7076bb9e122d59d502d02
57  cursor->Seek(std::make_pair(DB_COINS, uint256{}));
58  return cursor->Valid();
59 }
60 
61 namespace {
62 
63 struct CoinEntry {
64  COutPoint* outpoint;
65  uint8_t key;
66  explicit CoinEntry(const COutPoint* ptr) : outpoint(const_cast<COutPoint*>(ptr)), key(DB_COIN) {}
67 
68  SERIALIZE_METHODS(CoinEntry, obj) { READWRITE(obj.key, obj.outpoint->hash, VARINT(obj.outpoint->n)); }
69 };
70 
71 } // namespace
72 
73 CCoinsViewDB::CCoinsViewDB(fs::path ldb_path, size_t nCacheSize, bool fMemory, bool fWipe) :
74  m_db(std::make_unique<CDBWrapper>(ldb_path, nCacheSize, fMemory, fWipe, true)),
75  m_ldb_path(ldb_path),
76  m_is_memory(fMemory) { }
77 
78 void CCoinsViewDB::ResizeCache(size_t new_cache_size)
79 {
80  // We can't do this operation with an in-memory DB since we'll lose all the coins upon
81  // reset.
82  if (!m_is_memory) {
83  // Have to do a reset first to get the original `m_db` state to release its
84  // filesystem lock.
85  m_db.reset();
86  m_db = std::make_unique<CDBWrapper>(
87  m_ldb_path, new_cache_size, m_is_memory, /*fWipe=*/false, /*obfuscate=*/true);
88  }
89 }
90 
91 bool CCoinsViewDB::GetCoin(const COutPoint &outpoint, Coin &coin) const {
92  return m_db->Read(CoinEntry(&outpoint), coin);
93 }
94 
95 bool CCoinsViewDB::HaveCoin(const COutPoint &outpoint) const {
96  return m_db->Exists(CoinEntry(&outpoint));
97 }
98 
100  uint256 hashBestChain;
101  if (!m_db->Read(DB_BEST_BLOCK, hashBestChain))
102  return uint256();
103  return hashBestChain;
104 }
105 
106 std::vector<uint256> CCoinsViewDB::GetHeadBlocks() const {
107  std::vector<uint256> vhashHeadBlocks;
108  if (!m_db->Read(DB_HEAD_BLOCKS, vhashHeadBlocks)) {
109  return std::vector<uint256>();
110  }
111  return vhashHeadBlocks;
112 }
113 
114 bool CCoinsViewDB::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) {
115  CDBBatch batch(*m_db);
116  size_t count = 0;
117  size_t changed = 0;
118  size_t batch_size = (size_t)gArgs.GetIntArg("-dbbatchsize", nDefaultDbBatchSize);
119  int crash_simulate = gArgs.GetIntArg("-dbcrashratio", 0);
120  assert(!hashBlock.IsNull());
121 
122  uint256 old_tip = GetBestBlock();
123  if (old_tip.IsNull()) {
124  // We may be in the middle of replaying.
125  std::vector<uint256> old_heads = GetHeadBlocks();
126  if (old_heads.size() == 2) {
127  assert(old_heads[0] == hashBlock);
128  old_tip = old_heads[1];
129  }
130  }
131 
132  // In the first batch, mark the database as being in the middle of a
133  // transition from old_tip to hashBlock.
134  // A vector is used for future extensibility, as we may want to support
135  // interrupting after partial writes from multiple independent reorgs.
136  batch.Erase(DB_BEST_BLOCK);
137  batch.Write(DB_HEAD_BLOCKS, Vector(hashBlock, old_tip));
138 
139  for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end();) {
140  if (it->second.flags & CCoinsCacheEntry::DIRTY) {
141  CoinEntry entry(&it->first);
142  if (it->second.coin.IsSpent())
143  batch.Erase(entry);
144  else
145  batch.Write(entry, it->second.coin);
146  changed++;
147  }
148  count++;
149  CCoinsMap::iterator itOld = it++;
150  mapCoins.erase(itOld);
151  if (batch.SizeEstimate() > batch_size) {
152  LogPrint(BCLog::COINDB, "Writing partial batch of %.2f MiB\n", batch.SizeEstimate() * (1.0 / 1048576.0));
153  m_db->WriteBatch(batch);
154  batch.Clear();
155  if (crash_simulate) {
156  static FastRandomContext rng;
157  if (rng.randrange(crash_simulate) == 0) {
158  LogPrintf("Simulating a crash. Goodbye.\n");
159  _Exit(0);
160  }
161  }
162  }
163  }
164 
165  // In the last batch, mark the database as consistent with hashBlock again.
166  batch.Erase(DB_HEAD_BLOCKS);
167  batch.Write(DB_BEST_BLOCK, hashBlock);
168 
169  LogPrint(BCLog::COINDB, "Writing final batch of %.2f MiB\n", batch.SizeEstimate() * (1.0 / 1048576.0));
170  bool ret = m_db->WriteBatch(batch);
171  LogPrint(BCLog::COINDB, "Committed %u changed transaction outputs (out of %u) to coin database...\n", (unsigned int)changed, (unsigned int)count);
172  return ret;
173 }
174 
176 {
177  return m_db->EstimateSize(DB_COIN, uint8_t(DB_COIN + 1));
178 }
179 
180 CBlockTreeDB::CBlockTreeDB(size_t nCacheSize, bool fMemory, bool fWipe) : CDBWrapper(gArgs.GetDataDirNet() / "blocks" / "index", nCacheSize, fMemory, fWipe) {
181 }
182 
184  return Read(std::make_pair(DB_BLOCK_FILES, nFile), info);
185 }
186 
187 bool CBlockTreeDB::WriteReindexing(bool fReindexing) {
188  if (fReindexing)
189  return Write(DB_REINDEX_FLAG, uint8_t{'1'});
190  else
191  return Erase(DB_REINDEX_FLAG);
192 }
193 
194 void CBlockTreeDB::ReadReindexing(bool &fReindexing) {
195  fReindexing = Exists(DB_REINDEX_FLAG);
196 }
197 
199  return Read(DB_LAST_BLOCK, nFile);
200 }
201 
204 {
205 public:
206  // Prefer using CCoinsViewDB::Cursor() since we want to perform some
207  // cache warmup on instantiation.
208  CCoinsViewDBCursor(CDBIterator* pcursorIn, const uint256&hashBlockIn):
209  CCoinsViewCursor(hashBlockIn), pcursor(pcursorIn) {}
210  ~CCoinsViewDBCursor() = default;
211 
212  bool GetKey(COutPoint &key) const override;
213  bool GetValue(Coin &coin) const override;
214 
215  bool Valid() const override;
216  void Next() override;
217 
218 private:
219  std::unique_ptr<CDBIterator> pcursor;
220  std::pair<char, COutPoint> keyTmp;
221 
222  friend class CCoinsViewDB;
223 };
224 
225 std::unique_ptr<CCoinsViewCursor> CCoinsViewDB::Cursor() const
226 {
227  auto i = std::make_unique<CCoinsViewDBCursor>(
228  const_cast<CDBWrapper&>(*m_db).NewIterator(), GetBestBlock());
229  /* It seems that there are no "const iterators" for LevelDB. Since we
230  only need read operations on it, use a const-cast to get around
231  that restriction. */
232  i->pcursor->Seek(DB_COIN);
233  // Cache key of first record
234  if (i->pcursor->Valid()) {
235  CoinEntry entry(&i->keyTmp.second);
236  i->pcursor->GetKey(entry);
237  i->keyTmp.first = entry.key;
238  } else {
239  i->keyTmp.first = 0; // Make sure Valid() and GetKey() return false
240  }
241  return i;
242 }
243 
245 {
246  // Return cached key
247  if (keyTmp.first == DB_COIN) {
248  key = keyTmp.second;
249  return true;
250  }
251  return false;
252 }
253 
255 {
256  return pcursor->GetValue(coin);
257 }
258 
260 {
261  return keyTmp.first == DB_COIN;
262 }
263 
265 {
266  pcursor->Next();
267  CoinEntry entry(&keyTmp.second);
268  if (!pcursor->Valid() || !pcursor->GetKey(entry)) {
269  keyTmp.first = 0; // Invalidate cached key after last record so that Valid() and GetKey() return false
270  } else {
271  keyTmp.first = entry.key;
272  }
273 }
274 
275 bool CBlockTreeDB::WriteBatchSync(const std::vector<std::pair<int, const CBlockFileInfo*> >& fileInfo, int nLastFile, const std::vector<const CBlockIndex*>& blockinfo) {
276  CDBBatch batch(*this);
277  for (std::vector<std::pair<int, const CBlockFileInfo*> >::const_iterator it=fileInfo.begin(); it != fileInfo.end(); it++) {
278  batch.Write(std::make_pair(DB_BLOCK_FILES, it->first), *it->second);
279  }
280  batch.Write(DB_LAST_BLOCK, nLastFile);
281  for (std::vector<const CBlockIndex*>::const_iterator it=blockinfo.begin(); it != blockinfo.end(); it++) {
282  batch.Write(std::make_pair(DB_BLOCK_INDEX, (*it)->GetBlockHash()), CDiskBlockIndex(*it));
283  }
284  return WriteBatch(batch, true);
285 }
286 
287 bool CBlockTreeDB::WriteFlag(const std::string &name, bool fValue) {
288  return Write(std::make_pair(DB_FLAG, name), fValue ? uint8_t{'1'} : uint8_t{'0'});
289 }
290 
291 bool CBlockTreeDB::ReadFlag(const std::string &name, bool &fValue) {
292  uint8_t ch;
293  if (!Read(std::make_pair(DB_FLAG, name), ch))
294  return false;
295  fValue = ch == uint8_t{'1'};
296  return true;
297 }
298 
299 bool CBlockTreeDB::LoadBlockIndexGuts(const Consensus::Params& consensusParams, std::function<CBlockIndex*(const uint256&)> insertBlockIndex)
300 {
302  std::unique_ptr<CDBIterator> pcursor(NewIterator());
303  pcursor->Seek(std::make_pair(DB_BLOCK_INDEX, uint256()));
304 
305  // Load m_block_index
306  while (pcursor->Valid()) {
307  if (ShutdownRequested()) return false;
308  std::pair<uint8_t, uint256> key;
309  if (pcursor->GetKey(key) && key.first == DB_BLOCK_INDEX) {
310  CDiskBlockIndex diskindex;
311  if (pcursor->GetValue(diskindex)) {
312  // Construct block index object
313  CBlockIndex* pindexNew = insertBlockIndex(diskindex.ConstructBlockHash());
314  pindexNew->pprev = insertBlockIndex(diskindex.hashPrev);
315  pindexNew->nHeight = diskindex.nHeight;
316  pindexNew->nFile = diskindex.nFile;
317  pindexNew->nDataPos = diskindex.nDataPos;
318  pindexNew->nUndoPos = diskindex.nUndoPos;
319  pindexNew->nVersion = diskindex.nVersion;
320  pindexNew->hashMerkleRoot = diskindex.hashMerkleRoot;
321  pindexNew->nTime = diskindex.nTime;
322  pindexNew->nBits = diskindex.nBits;
323  pindexNew->nNonce = diskindex.nNonce;
324  pindexNew->nStatus = diskindex.nStatus;
325  pindexNew->nTx = diskindex.nTx;
326 
327  if (!CheckProofOfWork(pindexNew->GetBlockHash(), pindexNew->nBits, consensusParams)) {
328  return error("%s: CheckProofOfWork failed: %s", __func__, pindexNew->ToString());
329  }
330 
331  pcursor->Next();
332  } else {
333  return error("%s: failed to read value", __func__);
334  }
335  } else {
336  break;
337  }
338  }
339 
340  return true;
341 }
bool Exists(const K &key) const
Definition: dbwrapper.h:272
bool GetValue(Coin &coin) const override
Definition: txdb.cpp:254
bool GetCoin(const COutPoint &outpoint, Coin &coin) const override
Retrieve the Coin (unspent transaction output) for a given outpoint.
Definition: txdb.cpp:91
#define VARINT(obj)
Definition: serialize.h:436
int ret
std::string ToString() const
Definition: chain.cpp:15
void Clear()
Definition: dbwrapper.h:78
bool ShutdownRequested()
Returns true if a shutdown is requested, false otherwise.
Definition: shutdown.cpp:89
ArgsManager gArgs
Definition: system.cpp:86
AssertLockHeld(pool.cs)
std::unique_ptr< CCoinsViewCursor > Cursor() const override
Get a cursor to iterate over the whole state.
Definition: txdb.cpp:225
#define LogPrint(category,...)
Definition: logging.h:243
Specialization of CCoinsViewCursor to iterate over a CCoinsViewDB.
Definition: txdb.cpp:203
assert(!tx.IsCoinBase())
Describes a place in the block chain to another node such that if the other node doesn&#39;t have the sam...
Definition: block.h:120
CBlockIndex * pprev
pointer to the index of the predecessor of this block
Definition: chain.h:158
Batch of changes queued to be written to a CDBWrapper.
Definition: dbwrapper.h:59
A UTXO entry.
Definition: coins.h:30
static constexpr uint8_t DB_BLOCK_INDEX
Definition: txdb.cpp:21
bool ReadLastBlockFile(int &nFile)
Definition: txdb.cpp:198
CCoinsViewDB(fs::path ldb_path, size_t nCacheSize, bool fMemory, bool fWipe)
Definition: txdb.cpp:73
bilingual_str Untranslated(std::string original)
Mark a bilingual_str as untranslated.
Definition: translation.h:48
void Erase(const K &key)
Definition: dbwrapper.h:110
std::unique_ptr< CDBIterator > pcursor
Definition: txdb.cpp:219
void ReadReindexing(bool &fReindexing)
Definition: txdb.cpp:194
void ResizeCache(size_t new_cache_size) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
Dynamically alter the underlying leveldb cache size.
Definition: txdb.cpp:78
uint32_t nTime
Definition: chain.h:206
static constexpr uint8_t DB_BEST_BLOCK
Definition: txdb.cpp:23
static constexpr uint8_t DB_HEAD_BLOCKS
Definition: txdb.cpp:24
bool GetKey(COutPoint &key) const override
Definition: txdb.cpp:244
static constexpr uint8_t DB_LAST_BLOCK
Definition: txdb.cpp:27
bool IsNull() const
Definition: uint256.h:34
bool WriteReindexing(bool fReindexing)
Definition: txdb.cpp:187
bool NeedsUpgrade()
Whether an unsupported database format is used.
Definition: txdb.cpp:52
CDBIterator * NewIterator()
Definition: dbwrapper.h:303
DIRTY means the CCoinsCacheEntry is potentially different from the version in the parent cache...
Definition: coins.h:116
std::vector< typename std::common_type< Args... >::type > Vector(Args &&... args)
Construct a vector with the specified elements.
Definition: vector.h:21
uint256 GetBlockHash() const
Definition: chain.h:264
static constexpr uint8_t DB_FLAG
Definition: txdb.cpp:25
Access to the block database (blocks/index/)
Definition: txdb.h:78
bool Erase(const K &key, bool fSync=false)
Definition: dbwrapper.h:291
uint32_t nNonce
Definition: chain.h:208
std::optional< bilingual_str > CheckLegacyTxindex(CBlockTreeDB &block_tree_db)
Definition: txdb.cpp:34
static constexpr uint8_t DB_TXINDEX_BLOCK
Definition: txdb.cpp:31
static constexpr uint8_t DB_REINDEX_FLAG
Definition: txdb.cpp:26
const char * name
Definition: rest.cpp:46
bilingual_str _(const char *psz)
Translation function.
Definition: translation.h:65
Fast randomness source.
Definition: random.h:142
std::unordered_map< COutPoint, CCoinsCacheEntry, SaltedOutpointHasher > CCoinsMap
Definition: coins.h:134
uint256 hashMerkleRoot
Definition: chain.h:205
static constexpr uint8_t DB_COINS
Definition: txdb.cpp:30
void Write(const K &key, const V &value)
Definition: dbwrapper.h:85
size_t SizeEstimate() const
Definition: dbwrapper.h:126
CCoinsViewDBCursor(CDBIterator *pcursorIn, const uint256 &hashBlockIn)
Definition: txdb.cpp:208
Used to marshal pointers into hashes for db storage.
Definition: chain.h:368
static const int64_t nDefaultDbBatchSize
-dbbatchsize default (bytes)
Definition: txdb.h:30
size_t EstimateSize() const override
Estimate database size (0 if not implemented)
Definition: txdb.cpp:175
Parameters that influence chain consensus.
Definition: params.h:73
bool CheckProofOfWork(uint256 hash, unsigned int nBits, const Consensus::Params &params)
Check whether a block hash satisfies the proof-of-work requirement specified by nBits.
Definition: pow.cpp:125
An outpoint - a combination of a transaction hash and an index n into its vout.
Definition: transaction.h:34
std::pair< char, COutPoint > keyTmp
Definition: txdb.cpp:220
bool Read(const K &key, V &value) const
Definition: dbwrapper.h:238
bool m_is_memory
Definition: txdb.h:55
bool HaveCoin(const COutPoint &outpoint) const override
Just check whether a given outpoint is unspent.
Definition: txdb.cpp:95
bool ReadFlag(const std::string &name, bool &fValue)
Definition: txdb.cpp:291
CBlockTreeDB(size_t nCacheSize, bool fMemory=false, bool fWipe=false)
Definition: txdb.cpp:180
bool WriteBatchSync(const std::vector< std::pair< int, const CBlockFileInfo *> > &fileInfo, int nLastFile, const std::vector< const CBlockIndex *> &blockinfo)
Definition: txdb.cpp:275
bool ReadBlockFileInfo(int nFile, CBlockFileInfo &info)
Definition: txdb.cpp:183
~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:176
uint256 GetBestBlock() const override
Retrieve the block hash whose state this CCoinsView currently represents.
Definition: txdb.cpp:99
int32_t nVersion
block header
Definition: chain.h:204
256-bit opaque blob.
Definition: uint256.h:119
uint256 ConstructBlockHash() const
Definition: chain.h:405
uint256 hashPrev
Definition: chain.h:371
bool Write(const K &key, const V &value, bool fSync=false)
Definition: dbwrapper.h:264
static constexpr uint8_t DB_COIN
Definition: txdb.cpp:19
The block chain is a tree shaped structure starting with the genesis block at the root...
Definition: chain.h:151
CCoinsView backed by the coin database (chainstate/)
Definition: txdb.h:50
int64_t GetIntArg(const std::string &strArg, int64_t nDefault) const
Return integer argument or default value.
Definition: system.cpp:629
RecursiveMutex cs_main
Mutex to guard access to validation specific variables, such as reading or changing the chainstate...
Definition: validation.cpp:121
static int count
Definition: tests.c:33
bool WriteFlag(const std::string &name, bool fValue)
Definition: txdb.cpp:287
bool BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) override
Do a bulk modification (multiple Coin changes + BestBlock change).
Definition: txdb.cpp:114
void Next() override
Definition: txdb.cpp:264
bool WriteBatch(CDBBatch &batch, bool fSync=false)
Definition: dbwrapper.cpp:200
static constexpr uint8_t DB_BLOCK_FILES
Definition: txdb.cpp:20
fs::path m_ldb_path
Definition: txdb.h:54
bool Valid() const override
Definition: txdb.cpp:259
int nHeight
height of the entry in the chain. The genesis block has height 0
Definition: chain.h:164
#define READWRITE(...)
Definition: serialize.h:140
#define LogPrintf(...)
Definition: logging.h:234
Path class wrapper to block calls to the fs::path(std::string) implicit constructor and the fs::path:...
Definition: fs.h:30
bool error(const char *fmt, const Args &... args)
Definition: system.h:48
std::vector< uint256 > GetHeadBlocks() const override
Retrieve the range of blocks that may have been only partially written.
Definition: txdb.cpp:106
uint32_t nBits
Definition: chain.h:207
uint64_t randrange(uint64_t range) noexcept
Generate a random integer in the range [0..range).
Definition: random.h:213
unsigned int nTx
Number of transactions in this block.
Definition: chain.h:183
std::unique_ptr< CDBWrapper > m_db
Definition: txdb.h:53
Cursor for iterating over CoinsView state.
Definition: coins.h:137