Bitcoin ABC 0.33.6
P2P Digital Currency
txdb.cpp
Go to the documentation of this file.
1// Copyright (c) 2009-2010 Satoshi Nakamoto
2// Copyright (c) 2009-2018 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 <clientversion.h>
10#include <common/system.h>
11#include <logging.h>
12#include <logging/timer.h>
13#include <pow/pow.h>
14#include <random.h>
16#include <util/translation.h>
17#include <util/vector.h>
18
19#include <cstdint>
20#include <memory>
21
22static constexpr uint8_t DB_COIN{'C'};
23static constexpr uint8_t DB_BLOCK_FILES{'f'};
24static constexpr uint8_t DB_BLOCK_INDEX{'b'};
25
26static constexpr uint8_t DB_BEST_BLOCK{'B'};
27static constexpr uint8_t DB_HEAD_BLOCKS{'H'};
28static constexpr uint8_t DB_FLAG{'F'};
29static constexpr uint8_t DB_REINDEX_FLAG{'R'};
30static constexpr uint8_t DB_LAST_BLOCK{'l'};
31
32// Keys used in previous version that might still be found in the DB:
33static constexpr uint8_t DB_COINS{'c'};
34static constexpr uint8_t DB_TXINDEX_BLOCK{'T'};
35// uint8_t DB_TXINDEX{'t'}
36
37// Threshold for warning when writing this many dirty cache entries to disk.
38static constexpr size_t WARN_FLUSH_COINS_COUNT{10'000'000};
39
41 CBlockLocator ignored{};
42 if (block_tree_db.Read(DB_TXINDEX_BLOCK, ignored)) {
43 return util::Error{
44 _("The -txindex upgrade started by a previous version can not "
45 "be completed. Restart with the previous version or run a "
46 "full -reindex.")};
47 }
48 bool txindex_legacy_flag{false};
49 block_tree_db.ReadFlag("txindex", txindex_legacy_flag);
50 if (txindex_legacy_flag) {
51 // Disable legacy txindex and warn once about occupied disk space
52 block_tree_db.WriteFlag("txindex", false);
53 return util::Error{
54 _("The block index db contains a legacy 'txindex'. To clear the "
55 "occupied disk space, run a full -reindex, otherwise ignore "
56 "this error. This error message will not be displayed again.")};
57 }
58 return {};
59}
60
62 std::unique_ptr<CDBIterator> cursor{m_db->NewIterator()};
63 // DB_COINS was deprecated in v0.15.0 (D512)
64 cursor->Seek(std::make_pair(DB_COINS, uint256{}));
65 return cursor->Valid();
66}
67
68namespace {
69
70struct CoinEntry {
71 COutPoint *outpoint;
72 uint8_t key{DB_COIN};
73 explicit CoinEntry(const COutPoint *ptr)
74 : outpoint(const_cast<COutPoint *>(ptr)) {}
75
76 SERIALIZE_METHODS(CoinEntry, obj) {
77 TxId id = obj.outpoint->GetTxId();
78 uint32_t n = obj.outpoint->GetN();
79 READWRITE(obj.key, id, VARINT(n));
80 SER_READ(obj, *obj.outpoint = COutPoint(id, n));
81 }
82};
83} // namespace
84
86 : m_db_params{std::move(db_params)}, m_options{std::move(options)},
87 m_db{std::make_unique<CDBWrapper>(m_db_params)} {}
88
89void CCoinsViewDB::ResizeCache(size_t new_cache_size) {
90 // We can't do this operation with an in-memory DB since we'll lose all the
91 // coins upon reset.
93 // Have to do a reset first to get the original `m_db` state to release
94 // its filesystem lock.
95 m_db.reset();
96 m_db_params.cache_bytes = new_cache_size;
97 m_db_params.wipe_data = false;
98 m_db = std::make_unique<CDBWrapper>(m_db_params);
99 }
100}
101
102std::optional<Coin> CCoinsViewDB::GetCoin(const COutPoint &outpoint) const {
103 if (Coin coin; m_db->Read(CoinEntry(&outpoint), coin)) {
104 // The UTXO database should never contain spent coins
105 Assert(!coin.IsSpent());
106 return coin;
107 }
108 return std::nullopt;
109}
110
111bool CCoinsViewDB::HaveCoin(const COutPoint &outpoint) const {
112 return m_db->Exists(CoinEntry(&outpoint));
113}
114
116 BlockHash hashBestChain;
117 if (!m_db->Read(DB_BEST_BLOCK, hashBestChain)) {
118 return BlockHash();
119 }
120 return hashBestChain;
121}
122
123std::vector<BlockHash> CCoinsViewDB::GetHeadBlocks() const {
124 std::vector<BlockHash> vhashHeadBlocks;
125 if (!m_db->Read(DB_HEAD_BLOCKS, vhashHeadBlocks)) {
126 return std::vector<BlockHash>();
127 }
128 return vhashHeadBlocks;
129}
130
132 const BlockHash &hashBlock) {
133 CDBBatch batch(*m_db);
134 size_t count = 0;
135 const size_t dirty_count{cursor.GetDirtyCount()};
136 assert(!hashBlock.IsNull());
137
138 BlockHash old_tip = GetBestBlock();
139 if (old_tip.IsNull()) {
140 // We may be in the middle of replaying.
141 std::vector<BlockHash> old_heads = GetHeadBlocks();
142 if (old_heads.size() == 2) {
143 assert(old_heads[0] == hashBlock);
144 old_tip = old_heads[1];
145 }
146 }
147
148 if (dirty_count > WARN_FLUSH_COINS_COUNT) {
149 LogWarning("Flushing large (%d entries) UTXO set to disk, it may take "
150 "several minutes\n",
151 dirty_count);
152 }
154 strprintf("write coins cache to disk (%d out of %d cached coins)",
155 dirty_count, cursor.GetTotalCount()),
157
158 // In the first batch, mark the database as being in the middle of a
159 // transition from old_tip to hashBlock.
160 // A vector is used for future extensibility, as we may want to support
161 // interrupting after partial writes from multiple independent reorgs.
162 batch.Erase(DB_BEST_BLOCK);
163 batch.Write(DB_HEAD_BLOCKS, Vector(hashBlock, old_tip));
164
165 for (auto it{cursor.Begin()}; it != cursor.End();) {
166 if (it->second.IsDirty()) {
167 CoinEntry entry(&it->first);
168 if (it->second.coin.IsSpent()) {
169 batch.Erase(entry);
170 } else {
171 batch.Write(entry, it->second.coin);
172 }
173 }
174 count++;
175 it = cursor.NextAndMaybeErase(*it);
177 LogPrint(BCLog::COINDB, "Writing partial batch of %.2f MiB\n",
178 batch.SizeEstimate() * (1.0 / 1048576.0));
179 m_db->WriteBatch(batch);
180 batch.Clear();
182 static FastRandomContext rng;
184 LogPrintf("Simulating a crash. Goodbye.\n");
185 _Exit(0);
186 }
187 }
188 }
189 }
190
191 // In the last batch, mark the database as consistent with hashBlock again.
192 batch.Erase(DB_HEAD_BLOCKS);
193 batch.Write(DB_BEST_BLOCK, hashBlock);
194
195 LogPrint(BCLog::COINDB, "Writing final batch of %.2f MiB\n",
196 batch.SizeEstimate() * (1.0 / 1048576.0));
197 m_db->WriteBatch(batch);
199 "Committed %u changed transaction outputs (out of "
200 "%u) to coin database...\n",
201 (unsigned int)dirty_count, (unsigned int)count);
202}
203
205 return m_db->EstimateSize(DB_COIN, uint8_t(DB_COIN + 1));
206}
207
209 return Read(std::make_pair(DB_BLOCK_FILES, nFile), info);
210}
211
212void CBlockTreeDB::WriteReindexing(bool fReindexing) {
213 if (fReindexing) {
214 Write(DB_REINDEX_FLAG, uint8_t{'1'});
215 } else {
217 }
218}
219
221 return Exists(DB_REINDEX_FLAG);
222}
223
225 return Read(DB_LAST_BLOCK, nFile);
226}
227
230 const_cast<CDBWrapper &>(*m_db).NewIterator(), GetBestBlock());
236 i->pcursor->Seek(DB_COIN);
237 // Cache key of first record
238 if (i->pcursor->Valid()) {
239 CoinEntry entry(&i->keyTmp.second);
240 i->pcursor->GetKey(entry);
241 i->keyTmp.first = entry.key;
242 } else {
243 // Make sure Valid() and GetKey() return false
244 i->keyTmp.first = 0;
245 }
246 return i;
247}
248
249bool CCoinsViewDBCursor::GetKey(COutPoint &key) const {
250 // Return cached key
251 if (keyTmp.first == DB_COIN) {
252 key = keyTmp.second;
253 return true;
254 }
255 return false;
256}
257
259 return pcursor->GetValue(coin);
260}
261
263 return pcursor->GetValueSize();
264}
265
267 return keyTmp.first == DB_COIN;
268}
269
271 pcursor->Next();
272 CoinEntry entry(&keyTmp.second);
273 if (!pcursor->Valid() || !pcursor->GetKey(entry)) {
274 // Invalidate cached key after last record so that Valid() and GetKey()
275 // return false
276 keyTmp.first = 0;
277 } else {
278 keyTmp.first = entry.key;
279 }
280}
281
283 const std::vector<std::pair<int, const CBlockFileInfo *>> &fileInfo,
284 int nLastFile, const std::vector<const CBlockIndex *> &blockinfo) {
285 CDBBatch batch(*this);
286 for (std::vector<std::pair<int, const CBlockFileInfo *>>::const_iterator
287 it = fileInfo.begin();
288 it != fileInfo.end(); it++) {
289 batch.Write(std::make_pair(DB_BLOCK_FILES, it->first), *it->second);
290 }
291 batch.Write(DB_LAST_BLOCK, nLastFile);
292 for (std::vector<const CBlockIndex *>::const_iterator it =
293 blockinfo.begin();
294 it != blockinfo.end(); it++) {
295 batch.Write(std::make_pair(DB_BLOCK_INDEX, (*it)->GetBlockHash()),
296 CDiskBlockIndex(*it));
297 }
298 WriteBatch(batch, true);
299}
300
301void CBlockTreeDB::WriteFlag(const std::string &name, bool fValue) {
302 Write(std::make_pair(DB_FLAG, name), fValue ? uint8_t{'1'} : uint8_t{'0'});
303}
304
305bool CBlockTreeDB::ReadFlag(const std::string &name, bool &fValue) {
306 uint8_t ch;
307 if (!Read(std::make_pair(DB_FLAG, name), ch)) {
308 return false;
309 }
310 fValue = ch == uint8_t{'1'};
311 return true;
312}
313
315 const Consensus::Params &params,
316 std::function<CBlockIndex *(const BlockHash &)> insertBlockIndex,
317 const util::SignalInterrupt &interrupt) {
319 std::unique_ptr<CDBIterator> pcursor(NewIterator());
320
321 uint64_t version = 0;
322 pcursor->Seek("version");
323 if (pcursor->Valid()) {
324 pcursor->GetValue(version);
325 }
326
327 if (version != CLIENT_VERSION) {
328 LogError("%s: Invalid block index database version: %s\n", __func__,
329 version);
330 return false;
331 }
332
333 pcursor->Seek(std::make_pair(DB_BLOCK_INDEX, uint256()));
334
335 // Load m_block_index
336 while (pcursor->Valid()) {
337 if (interrupt) {
338 return false;
339 }
340 std::pair<uint8_t, uint256> key;
341 if (!pcursor->GetKey(key) || key.first != DB_BLOCK_INDEX) {
342 break;
343 }
344
345 CDiskBlockIndex diskindex;
346 if (!pcursor->GetValue(diskindex)) {
347 LogError("%s : failed to read value\n", __func__);
348 return false;
349 }
350
351 // Construct block index object
352 CBlockIndex *pindexNew =
353 insertBlockIndex(diskindex.ConstructBlockHash());
354 pindexNew->pprev = insertBlockIndex(diskindex.hashPrev);
355 pindexNew->nHeight = diskindex.nHeight;
356 pindexNew->nFile = diskindex.nFile;
357 pindexNew->nDataPos = diskindex.nDataPos;
358 pindexNew->nUndoPos = diskindex.nUndoPos;
359 pindexNew->nVersion = diskindex.nVersion;
360 pindexNew->hashMerkleRoot = diskindex.hashMerkleRoot;
361 pindexNew->nTime = diskindex.nTime;
362 pindexNew->nBits = diskindex.nBits;
363 pindexNew->nNonce = diskindex.nNonce;
364 pindexNew->nStatus = diskindex.nStatus;
365 pindexNew->nTx = diskindex.nTx;
366
367 if (!CheckProofOfWork(pindexNew->GetBlockHash(), pindexNew->nBits,
368 params)) {
369 LogError("%s: CheckProofOfWork failed: %s\n", __func__,
370 pindexNew->ToString());
371 return false;
372 }
373
374 pcursor->Next();
375 }
376
377 return true;
378}
379
381 // This method used to add the block size to pre-0.22.8 block index
382 // databases. This is no longer supported as of 0.25.5, but the method is
383 // kept to update the version number in the database.
384 std::unique_ptr<CDBIterator> pcursor(NewIterator());
385
386 uint64_t version = 0;
387 pcursor->Seek("version");
388 if (pcursor->Valid()) {
389 pcursor->GetValue(version);
390 }
391
392 if (version >= CLIENT_VERSION) {
393 // The DB is already up to date.
394 return true;
395 }
396
397 pcursor->Seek(std::make_pair(DB_BLOCK_INDEX, uint256()));
398
399 // The DB is not empty, and the version is either non-existent or too old.
400 // The node requires a reindex.
401 constexpr int TRACK_SIZE_VERSION = 220800;
402 if (pcursor->Valid() && version < TRACK_SIZE_VERSION) {
403 LogPrintf(
404 "\nThe database is too old. The block index cannot be upgraded "
405 "and reindexing is required.\n");
406 return false;
407 }
408
409 // The DB is empty or recent enough.
410 // Just write the new version number and consider the upgrade done.
411 CDBBatch batch(*this);
412 LogPrintf("Updating the block index database version to %d\n",
414 batch.Write("version", uint64_t(CLIENT_VERSION));
415 WriteBatch(batch);
416 return true;
417}
#define Assert(val)
Identity function.
Definition: check.h:84
The block chain is a tree shaped structure starting with the genesis block at the root,...
Definition: blockindex.h:25
uint256 hashMerkleRoot
Definition: blockindex.h:75
std::string ToString() const
Definition: blockindex.cpp:30
CBlockIndex * pprev
pointer to the index of the predecessor of this block
Definition: blockindex.h:32
uint32_t nTime
Definition: blockindex.h:76
uint32_t nNonce
Definition: blockindex.h:78
uint32_t nBits
Definition: blockindex.h:77
unsigned int nTx
Number of transactions in this block.
Definition: blockindex.h:55
int32_t nVersion
block header
Definition: blockindex.h:74
BlockHash GetBlockHash() const
Definition: blockindex.h:130
int nHeight
height of the entry in the chain. The genesis block has height 0
Definition: blockindex.h:38
Access to the block database (blocks/index/)
Definition: txdb.h:100
void WriteFlag(const std::string &name, bool fValue)
Definition: txdb.cpp:301
bool ReadBlockFileInfo(int nFile, CBlockFileInfo &info)
Definition: txdb.cpp:208
bool Upgrade()
Attempt to update from an older database format.
Definition: txdb.cpp:380
bool IsReindexing() const
Definition: txdb.cpp:220
bool LoadBlockIndexGuts(const Consensus::Params &params, std::function< CBlockIndex *(const BlockHash &)> insertBlockIndex, const util::SignalInterrupt &interrupt) EXCLUSIVE_LOCKS_REQUIRED(
Definition: txdb.h:112
bool ReadFlag(const std::string &name, bool &fValue)
Definition: txdb.cpp:305
bool ReadLastBlockFile(int &nFile)
Definition: txdb.cpp:224
void WriteBatchSync(const std::vector< std::pair< int, const CBlockFileInfo * > > &fileInfo, int nLastFile, const std::vector< const CBlockIndex * > &blockinfo)
Definition: txdb.cpp:282
void WriteReindexing(bool fReindexing)
Definition: txdb.cpp:212
Cursor for iterating over CoinsView state.
Definition: coins.h:217
Specialization of CCoinsViewCursor to iterate over a CCoinsViewDB.
Definition: txdb.h:79
std::unique_ptr< CDBIterator > pcursor
Definition: txdb.h:93
bool GetKey(COutPoint &key) const override
Definition: txdb.cpp:249
bool GetValue(Coin &coin) const override
Definition: txdb.cpp:258
bool Valid() const override
Definition: txdb.cpp:266
unsigned int GetValueSize() const override
Definition: txdb.cpp:262
void Next() override
Definition: txdb.cpp:270
std::pair< char, COutPoint > keyTmp
Definition: txdb.h:94
BlockHash GetBestBlock() const override
Retrieve the block hash whose state this CCoinsView currently represents.
Definition: txdb.cpp:115
std::vector< BlockHash > GetHeadBlocks() const override
Retrieve the range of blocks that may have been only partially written.
Definition: txdb.cpp:123
bool HaveCoin(const COutPoint &outpoint) const override
Just check whether a given outpoint is unspent.
Definition: txdb.cpp:111
std::unique_ptr< CDBWrapper > m_db
Definition: txdb.h:53
CCoinsViewCursor * Cursor() const override
Get a cursor to iterate over the whole state.
Definition: txdb.cpp:228
CCoinsViewDB(DBParams db_params, CoinsViewOptions options)
Definition: txdb.cpp:85
std::optional< Coin > GetCoin(const COutPoint &outpoint) const override
Retrieve the Coin (unspent transaction output) for a given outpoint.
Definition: txdb.cpp:102
void BatchWrite(CoinsViewCacheCursor &cursor, const BlockHash &hashBlock) override
Do a bulk modification (multiple Coin changes + BestBlock change).
Definition: txdb.cpp:131
void ResizeCache(size_t new_cache_size) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
Dynamically alter the underlying leveldb cache size.
Definition: txdb.cpp:89
CoinsViewOptions m_options
Definition: txdb.h:52
bool NeedsUpgrade()
Whether an unsupported database format is used.
Definition: txdb.cpp:61
size_t EstimateSize() const override
Estimate database size (0 if not implemented)
Definition: txdb.cpp:204
DBParams m_db_params
Definition: txdb.h:51
Batch of changes queued to be written to a CDBWrapper.
Definition: dbwrapper.h:77
void Erase(const K &key)
Definition: dbwrapper.h:124
size_t SizeEstimate() const
Definition: dbwrapper.h:139
void Write(const K &key, const V &value)
Definition: dbwrapper.h:100
void Clear()
Definition: dbwrapper.h:95
bool Read(const K &key, V &value) const
Definition: dbwrapper.h:250
CDBIterator * NewIterator()
Definition: dbwrapper.h:315
bool Exists(const K &key) const
Definition: dbwrapper.h:288
void Erase(const K &key, bool fSync=false)
Definition: dbwrapper.h:304
void WriteBatch(CDBBatch &batch, bool fSync=false)
Definition: dbwrapper.cpp:196
void Write(const K &key, const V &value, bool fSync=false)
Definition: dbwrapper.h:274
Used to marshal pointers into hashes for db storage.
Definition: chain.h:69
BlockHash hashPrev
Definition: chain.h:80
BlockHash ConstructBlockHash() const
Definition: chain.h:120
A UTXO entry.
Definition: coins.h:31
Fast randomness source.
Definition: random.h:411
I randrange(I range) noexcept
Generate a random integer in the range [0..range), with range > 0.
Definition: random.h:266
bool IsNull() const
Definition: uint256.h:32
256-bit opaque blob.
Definition: uint256.h:129
Helper class that manages an interrupt flag, and allows a thread or signal to interrupt another threa...
static constexpr int CLIENT_VERSION
bitcoind-res.rc includes this file, but it cannot cope with real c++ code.
Definition: clientversion.h:38
RecursiveMutex cs_main
Mutex to guard access to validation specific variables, such as reading or changing the chainstate.
Definition: cs_main.cpp:7
#define LogWarning(...)
Definition: logging.h:416
#define LogPrint(category,...)
Definition: logging.h:452
#define LogError(...)
Definition: logging.h:419
#define LogPrintf(...)
Definition: logging.h:424
@ COINDB
Definition: logging.h:87
@ BENCH
Definition: logging.h:73
Implement std::hash so RCUPtr can be used as a key for maps or sets.
Definition: rcu.h:259
bool CheckProofOfWork(const BlockHash &hash, uint32_t nBits, const Consensus::Params &params)
Check whether a block hash satisfies the proof-of-work requirement specified by nBits.
Definition: pow.cpp:87
const char * name
Definition: rest.cpp:47
#define VARINT(obj)
Definition: serialize.h:635
#define SERIALIZE_METHODS(cls, obj)
Implement the Serialize and Unserialize methods by delegating to a single templated static method tha...
Definition: serialize.h:276
#define SER_READ(obj, code)
Definition: serialize.h:177
#define READWRITE(...)
Definition: serialize.h:176
A BlockHash is a unqiue identifier for a block.
Definition: blockhash.h:13
Describes a place in the block chain to another node such that if the other node doesn't have the sam...
Definition: block.h:108
Cursor for iterating over the linked list of flagged entries in CCoinsViewCache.
Definition: coins.h:250
CoinsCachePair * NextAndMaybeErase(CoinsCachePair &current) noexcept
Return the next entry after current, possibly erasing current.
Definition: coins.h:273
size_t GetTotalCount() const noexcept
Definition: coins.h:294
size_t GetDirtyCount() const noexcept
Definition: coins.h:293
CoinsCachePair * Begin() const noexcept
Definition: coins.h:267
CoinsCachePair * End() const noexcept
Definition: coins.h:270
User-controlled performance and debug options.
Definition: txdb.h:40
int simulate_crash_ratio
If non-zero, randomly exit when the database is flushed with (1/ratio) probability.
Definition: txdb.h:45
size_t batch_write_bytes
Maximum database write batch size in bytes.
Definition: txdb.h:42
Parameters that influence chain consensus.
Definition: params.h:34
Application-specific storage settings.
Definition: dbwrapper.h:31
bool wipe_data
If true, remove all existing data.
Definition: dbwrapper.h:39
size_t cache_bytes
Configures various leveldb cache settings.
Definition: dbwrapper.h:35
bool memory_only
If true, use leveldb's memory environment.
Definition: dbwrapper.h:37
A TxId is the identifier of a transaction.
Definition: txid.h:14
static int count
#define LOG_TIME_MILLIS_WITH_CATEGORY(end_msg, log_category)
Definition: timer.h:97
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
Definition: tinyformat.h:1202
bilingual_str _(const char *psz)
Translation function.
Definition: translation.h:68
static constexpr uint8_t DB_TXINDEX_BLOCK
Definition: txdb.cpp:34
static constexpr uint8_t DB_LAST_BLOCK
Definition: txdb.cpp:30
static constexpr size_t WARN_FLUSH_COINS_COUNT
Definition: txdb.cpp:38
static constexpr uint8_t DB_HEAD_BLOCKS
Definition: txdb.cpp:27
static constexpr uint8_t DB_REINDEX_FLAG
Definition: txdb.cpp:29
static constexpr uint8_t DB_BEST_BLOCK
Definition: txdb.cpp:26
util::Result< void > CheckLegacyTxindex(CBlockTreeDB &block_tree_db)
Definition: txdb.cpp:40
static constexpr uint8_t DB_COIN
Definition: txdb.cpp:22
static constexpr uint8_t DB_FLAG
Definition: txdb.cpp:28
static constexpr uint8_t DB_COINS
Definition: txdb.cpp:33
static constexpr uint8_t DB_BLOCK_FILES
Definition: txdb.cpp:23
static constexpr uint8_t DB_BLOCK_INDEX
Definition: txdb.cpp:24
AssertLockHeld(pool.cs)
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