Bitcoin ABC 0.32.5
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 <pow/pow.h>
13#include <random.h>
15#include <util/translation.h>
16#include <util/vector.h>
17#include <version.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
38 CBlockLocator ignored{};
39 if (block_tree_db.Read(DB_TXINDEX_BLOCK, ignored)) {
40 return util::Error{
41 _("The -txindex upgrade started by a previous version can not "
42 "be completed. Restart with the previous version or run a "
43 "full -reindex.")};
44 }
45 bool txindex_legacy_flag{false};
46 block_tree_db.ReadFlag("txindex", txindex_legacy_flag);
47 if (txindex_legacy_flag) {
48 // Disable legacy txindex and warn once about occupied disk space
49 if (!block_tree_db.WriteFlag("txindex", false)) {
51 "Failed to write block index db flag 'txindex'='0'")};
52 }
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
102bool CCoinsViewDB::GetCoin(const COutPoint &outpoint, Coin &coin) const {
103 return m_db->Read(CoinEntry(&outpoint), coin);
104}
105
106bool CCoinsViewDB::HaveCoin(const COutPoint &outpoint) const {
107 return m_db->Exists(CoinEntry(&outpoint));
108}
109
111 BlockHash hashBestChain;
112 if (!m_db->Read(DB_BEST_BLOCK, hashBestChain)) {
113 return BlockHash();
114 }
115 return hashBestChain;
116}
117
118std::vector<BlockHash> CCoinsViewDB::GetHeadBlocks() const {
119 std::vector<BlockHash> vhashHeadBlocks;
120 if (!m_db->Read(DB_HEAD_BLOCKS, vhashHeadBlocks)) {
121 return std::vector<BlockHash>();
122 }
123 return vhashHeadBlocks;
124}
125
127 const BlockHash &hashBlock) {
128 CDBBatch batch(*m_db);
129 size_t count = 0;
130 size_t changed = 0;
131 assert(!hashBlock.IsNull());
132
133 BlockHash old_tip = GetBestBlock();
134 if (old_tip.IsNull()) {
135 // We may be in the middle of replaying.
136 std::vector<BlockHash> old_heads = GetHeadBlocks();
137 if (old_heads.size() == 2) {
138 assert(old_heads[0] == hashBlock);
139 old_tip = old_heads[1];
140 }
141 }
142
143 // In the first batch, mark the database as being in the middle of a
144 // transition from old_tip to hashBlock.
145 // A vector is used for future extensibility, as we may want to support
146 // interrupting after partial writes from multiple independent reorgs.
147 batch.Erase(DB_BEST_BLOCK);
148 batch.Write(DB_HEAD_BLOCKS, Vector(hashBlock, old_tip));
149
150 for (auto it{cursor.Begin()}; it != cursor.End();) {
151 if (it->second.IsDirty()) {
152 CoinEntry entry(&it->first);
153 if (it->second.coin.IsSpent()) {
154 batch.Erase(entry);
155 } else {
156 batch.Write(entry, it->second.coin);
157 }
158 changed++;
159 }
160 count++;
161 it = cursor.NextAndMaybeErase(*it);
163 LogPrint(BCLog::COINDB, "Writing partial batch of %.2f MiB\n",
164 batch.SizeEstimate() * (1.0 / 1048576.0));
165 m_db->WriteBatch(batch);
166 batch.Clear();
168 static FastRandomContext rng;
170 LogPrintf("Simulating a crash. Goodbye.\n");
171 _Exit(0);
172 }
173 }
174 }
175 }
176
177 // In the last batch, mark the database as consistent with hashBlock again.
178 batch.Erase(DB_HEAD_BLOCKS);
179 batch.Write(DB_BEST_BLOCK, hashBlock);
180
181 LogPrint(BCLog::COINDB, "Writing final batch of %.2f MiB\n",
182 batch.SizeEstimate() * (1.0 / 1048576.0));
183 bool ret = m_db->WriteBatch(batch);
185 "Committed %u changed transaction outputs (out of "
186 "%u) to coin database...\n",
187 (unsigned int)changed, (unsigned int)count);
188 return ret;
189}
190
192 return m_db->EstimateSize(DB_COIN, uint8_t(DB_COIN + 1));
193}
194
196 return Read(std::make_pair(DB_BLOCK_FILES, nFile), info);
197}
198
199bool CBlockTreeDB::WriteReindexing(bool fReindexing) {
200 if (fReindexing) {
201 return Write(DB_REINDEX_FLAG, uint8_t{'1'});
202 } else {
203 return Erase(DB_REINDEX_FLAG);
204 }
205}
206
208 return Exists(DB_REINDEX_FLAG);
209}
210
212 return Read(DB_LAST_BLOCK, nFile);
213}
214
217 const_cast<CDBWrapper &>(*m_db).NewIterator(), GetBestBlock());
223 i->pcursor->Seek(DB_COIN);
224 // Cache key of first record
225 if (i->pcursor->Valid()) {
226 CoinEntry entry(&i->keyTmp.second);
227 i->pcursor->GetKey(entry);
228 i->keyTmp.first = entry.key;
229 } else {
230 // Make sure Valid() and GetKey() return false
231 i->keyTmp.first = 0;
232 }
233 return i;
234}
235
236bool CCoinsViewDBCursor::GetKey(COutPoint &key) const {
237 // Return cached key
238 if (keyTmp.first == DB_COIN) {
239 key = keyTmp.second;
240 return true;
241 }
242 return false;
243}
244
246 return pcursor->GetValue(coin);
247}
248
250 return pcursor->GetValueSize();
251}
252
254 return keyTmp.first == DB_COIN;
255}
256
258 pcursor->Next();
259 CoinEntry entry(&keyTmp.second);
260 if (!pcursor->Valid() || !pcursor->GetKey(entry)) {
261 // Invalidate cached key after last record so that Valid() and GetKey()
262 // return false
263 keyTmp.first = 0;
264 } else {
265 keyTmp.first = entry.key;
266 }
267}
268
270 const std::vector<std::pair<int, const CBlockFileInfo *>> &fileInfo,
271 int nLastFile, const std::vector<const CBlockIndex *> &blockinfo) {
272 CDBBatch batch(*this);
273 for (std::vector<std::pair<int, const CBlockFileInfo *>>::const_iterator
274 it = fileInfo.begin();
275 it != fileInfo.end(); it++) {
276 batch.Write(std::make_pair(DB_BLOCK_FILES, it->first), *it->second);
277 }
278 batch.Write(DB_LAST_BLOCK, nLastFile);
279 for (std::vector<const CBlockIndex *>::const_iterator it =
280 blockinfo.begin();
281 it != blockinfo.end(); it++) {
282 batch.Write(std::make_pair(DB_BLOCK_INDEX, (*it)->GetBlockHash()),
283 CDiskBlockIndex(*it));
284 }
285 return WriteBatch(batch, true);
286}
287
288bool CBlockTreeDB::WriteFlag(const std::string &name, bool fValue) {
289 return Write(std::make_pair(DB_FLAG, name),
290 fValue ? uint8_t{'1'} : uint8_t{'0'});
291}
292
293bool CBlockTreeDB::ReadFlag(const std::string &name, bool &fValue) {
294 uint8_t ch;
295 if (!Read(std::make_pair(DB_FLAG, name), ch)) {
296 return false;
297 }
298 fValue = ch == uint8_t{'1'};
299 return true;
300}
301
303 const Consensus::Params &params,
304 std::function<CBlockIndex *(const BlockHash &)> insertBlockIndex,
305 const util::SignalInterrupt &interrupt) {
307 std::unique_ptr<CDBIterator> pcursor(NewIterator());
308
309 uint64_t version = 0;
310 pcursor->Seek("version");
311 if (pcursor->Valid()) {
312 pcursor->GetValue(version);
313 }
314
315 if (version != CLIENT_VERSION) {
316 LogError("%s: Invalid block index database version: %s\n", __func__,
317 version);
318 return false;
319 }
320
321 pcursor->Seek(std::make_pair(DB_BLOCK_INDEX, uint256()));
322
323 // Load m_block_index
324 while (pcursor->Valid()) {
325 if (interrupt) {
326 return false;
327 }
328 std::pair<uint8_t, uint256> key;
329 if (!pcursor->GetKey(key) || key.first != DB_BLOCK_INDEX) {
330 break;
331 }
332
333 CDiskBlockIndex diskindex;
334 if (!pcursor->GetValue(diskindex)) {
335 LogError("%s : failed to read value\n", __func__);
336 return false;
337 }
338
339 // Construct block index object
340 CBlockIndex *pindexNew =
341 insertBlockIndex(diskindex.ConstructBlockHash());
342 pindexNew->pprev = insertBlockIndex(diskindex.hashPrev);
343 pindexNew->nHeight = diskindex.nHeight;
344 pindexNew->nFile = diskindex.nFile;
345 pindexNew->nDataPos = diskindex.nDataPos;
346 pindexNew->nUndoPos = diskindex.nUndoPos;
347 pindexNew->nVersion = diskindex.nVersion;
348 pindexNew->hashMerkleRoot = diskindex.hashMerkleRoot;
349 pindexNew->nTime = diskindex.nTime;
350 pindexNew->nBits = diskindex.nBits;
351 pindexNew->nNonce = diskindex.nNonce;
352 pindexNew->nStatus = diskindex.nStatus;
353 pindexNew->nTx = diskindex.nTx;
354
355 if (!CheckProofOfWork(pindexNew->GetBlockHash(), pindexNew->nBits,
356 params)) {
357 LogError("%s: CheckProofOfWork failed: %s\n", __func__,
358 pindexNew->ToString());
359 return false;
360 }
361
362 pcursor->Next();
363 }
364
365 return true;
366}
367
369 // This method used to add the block size to pre-0.22.8 block index
370 // databases. This is no longer supported as of 0.25.5, but the method is
371 // kept to update the version number in the database.
372 std::unique_ptr<CDBIterator> pcursor(NewIterator());
373
374 uint64_t version = 0;
375 pcursor->Seek("version");
376 if (pcursor->Valid()) {
377 pcursor->GetValue(version);
378 }
379
380 if (version >= CLIENT_VERSION) {
381 // The DB is already up to date.
382 return true;
383 }
384
385 pcursor->Seek(std::make_pair(DB_BLOCK_INDEX, uint256()));
386
387 // The DB is not empty, and the version is either non-existent or too old.
388 // The node requires a reindex.
389 constexpr int TRACK_SIZE_VERSION = 220800;
390 if (pcursor->Valid() && version < TRACK_SIZE_VERSION) {
391 LogPrintf(
392 "\nThe database is too old. The block index cannot be upgraded "
393 "and reindexing is required.\n");
394 return false;
395 }
396
397 // The DB is empty or recent enough.
398 // Just write the new version number and consider the upgrade done.
399 CDBBatch batch(*this);
400 LogPrintf("Updating the block index database version to %d\n",
402 batch.Write("version", uint64_t(CLIENT_VERSION));
403 return WriteBatch(batch);
404}
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
bool ReadBlockFileInfo(int nFile, CBlockFileInfo &info)
Definition: txdb.cpp:195
bool Upgrade()
Attempt to update from an older database format.
Definition: txdb.cpp:368
bool WriteReindexing(bool fReindexing)
Definition: txdb.cpp:199
bool IsReindexing() const
Definition: txdb.cpp:207
bool WriteBatchSync(const std::vector< std::pair< int, const CBlockFileInfo * > > &fileInfo, int nLastFile, const std::vector< const CBlockIndex * > &blockinfo)
Definition: txdb.cpp:269
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:293
bool ReadLastBlockFile(int &nFile)
Definition: txdb.cpp:211
bool WriteFlag(const std::string &name, bool fValue)
Definition: txdb.cpp:288
Cursor for iterating over CoinsView state.
Definition: coins.h:222
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:236
bool GetValue(Coin &coin) const override
Definition: txdb.cpp:245
bool Valid() const override
Definition: txdb.cpp:253
unsigned int GetValueSize() const override
Definition: txdb.cpp:249
void Next() override
Definition: txdb.cpp:257
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:110
std::vector< BlockHash > GetHeadBlocks() const override
Retrieve the range of blocks that may have been only partially written.
Definition: txdb.cpp:118
bool GetCoin(const COutPoint &outpoint, Coin &coin) const override
Retrieve the Coin (unspent transaction output) for a given outpoint.
Definition: txdb.cpp:102
bool HaveCoin(const COutPoint &outpoint) const override
Just check whether a given outpoint is unspent.
Definition: txdb.cpp:106
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:215
CCoinsViewDB(DBParams db_params, CoinsViewOptions options)
Definition: txdb.cpp:85
bool BatchWrite(CoinsViewCacheCursor &cursor, const BlockHash &hashBlock) override
Do a bulk modification (multiple Coin changes + BestBlock change).
Definition: txdb.cpp:126
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:191
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 WriteBatch(CDBBatch &batch, bool fSync=false)
Definition: dbwrapper.cpp:196
bool Read(const K &key, V &value) const
Definition: dbwrapper.h:250
CDBIterator * NewIterator()
Definition: dbwrapper.h:315
bool Erase(const K &key, bool fSync=false)
Definition: dbwrapper.h:304
bool Write(const K &key, const V &value, bool fSync=false)
Definition: dbwrapper.h:274
bool Exists(const K &key) const
Definition: dbwrapper.h:288
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:29
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 LogPrint(category,...)
Definition: logging.h:452
#define LogError(...)
Definition: logging.h:419
#define LogPrintf(...)
Definition: logging.h:424
@ COINDB
Definition: logging.h:87
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:643
#define SERIALIZE_METHODS(cls, obj)
Implement the Serialize and Unserialize methods by delegating to a single templated static method tha...
Definition: serialize.h:289
#define SER_READ(obj, code)
Definition: serialize.h:190
#define READWRITE(...)
Definition: serialize.h:189
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:255
CoinsCachePair * NextAndMaybeErase(CoinsCachePair &current) noexcept
Return the next entry after current, possibly erasing current.
Definition: coins.h:278
CoinsCachePair * Begin() const noexcept
Definition: coins.h:272
CoinsCachePair * End() const noexcept
Definition: coins.h:275
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
Definition: tests.c:31
bilingual_str _(const char *psz)
Translation function.
Definition: translation.h:68
bilingual_str Untranslated(std::string original)
Mark a bilingual_str as untranslated.
Definition: translation.h:36
static constexpr uint8_t DB_TXINDEX_BLOCK
Definition: txdb.cpp:34
static constexpr uint8_t DB_LAST_BLOCK
Definition: txdb.cpp:30
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:37
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