Bitcoin ABC 0.32.4
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 <common/system.h>
10#include <logging.h>
11#include <pow/pow.h>
12#include <random.h>
14#include <util/translation.h>
15#include <util/vector.h>
16#include <version.h>
17
18#include <cstdint>
19#include <memory>
20
21static constexpr uint8_t DB_COIN{'C'};
22static constexpr uint8_t DB_BLOCK_FILES{'f'};
23static constexpr uint8_t DB_BLOCK_INDEX{'b'};
24
25static constexpr uint8_t DB_BEST_BLOCK{'B'};
26static constexpr uint8_t DB_HEAD_BLOCKS{'H'};
27static constexpr uint8_t DB_FLAG{'F'};
28static constexpr uint8_t DB_REINDEX_FLAG{'R'};
29static constexpr uint8_t DB_LAST_BLOCK{'l'};
30
31// Keys used in previous version that might still be found in the DB:
32static constexpr uint8_t DB_COINS{'c'};
33static constexpr uint8_t DB_TXINDEX_BLOCK{'T'};
34// uint8_t DB_TXINDEX{'t'}
35
37 CBlockLocator ignored{};
38 if (block_tree_db.Read(DB_TXINDEX_BLOCK, ignored)) {
39 return util::Error{
40 _("The -txindex upgrade started by a previous version can not "
41 "be completed. Restart with the previous version or run a "
42 "full -reindex.")};
43 }
44 bool txindex_legacy_flag{false};
45 block_tree_db.ReadFlag("txindex", txindex_legacy_flag);
46 if (txindex_legacy_flag) {
47 // Disable legacy txindex and warn once about occupied disk space
48 if (!block_tree_db.WriteFlag("txindex", false)) {
50 "Failed to write block index db flag 'txindex'='0'")};
51 }
52 return util::Error{
53 _("The block index db contains a legacy 'txindex'. To clear the "
54 "occupied disk space, run a full -reindex, otherwise ignore "
55 "this error. This error message will not be displayed again.")};
56 }
57 return {};
58}
59
61 std::unique_ptr<CDBIterator> cursor{m_db->NewIterator()};
62 // DB_COINS was deprecated in v0.15.0 (D512)
63 cursor->Seek(std::make_pair(DB_COINS, uint256{}));
64 return cursor->Valid();
65}
66
67namespace {
68
69struct CoinEntry {
70 COutPoint *outpoint;
71 uint8_t key;
72 explicit CoinEntry(const COutPoint *ptr)
73 : outpoint(const_cast<COutPoint *>(ptr)), key(DB_COIN) {}
74
75 SERIALIZE_METHODS(CoinEntry, obj) {
76 TxId id = obj.outpoint->GetTxId();
77 uint32_t n = obj.outpoint->GetN();
78 READWRITE(obj.key, id, VARINT(n));
79 SER_READ(obj, *obj.outpoint = COutPoint(id, n));
80 }
81};
82} // namespace
83
85 : m_db_params{std::move(db_params)}, m_options{std::move(options)},
86 m_db{std::make_unique<CDBWrapper>(m_db_params)} {}
87
88void CCoinsViewDB::ResizeCache(size_t new_cache_size) {
89 // We can't do this operation with an in-memory DB since we'll lose all the
90 // coins upon reset.
92 // Have to do a reset first to get the original `m_db` state to release
93 // its filesystem lock.
94 m_db.reset();
95 m_db_params.cache_bytes = new_cache_size;
96 m_db_params.wipe_data = false;
97 m_db = std::make_unique<CDBWrapper>(m_db_params);
98 }
99}
100
101bool CCoinsViewDB::GetCoin(const COutPoint &outpoint, Coin &coin) const {
102 return m_db->Read(CoinEntry(&outpoint), coin);
103}
104
105bool CCoinsViewDB::HaveCoin(const COutPoint &outpoint) const {
106 return m_db->Exists(CoinEntry(&outpoint));
107}
108
110 BlockHash hashBestChain;
111 if (!m_db->Read(DB_BEST_BLOCK, hashBestChain)) {
112 return BlockHash();
113 }
114 return hashBestChain;
115}
116
117std::vector<BlockHash> CCoinsViewDB::GetHeadBlocks() const {
118 std::vector<BlockHash> vhashHeadBlocks;
119 if (!m_db->Read(DB_HEAD_BLOCKS, vhashHeadBlocks)) {
120 return std::vector<BlockHash>();
121 }
122 return vhashHeadBlocks;
123}
124
126 const BlockHash &hashBlock) {
127 CDBBatch batch(*m_db);
128 size_t count = 0;
129 size_t changed = 0;
130 assert(!hashBlock.IsNull());
131
132 BlockHash old_tip = GetBestBlock();
133 if (old_tip.IsNull()) {
134 // We may be in the middle of replaying.
135 std::vector<BlockHash> old_heads = GetHeadBlocks();
136 if (old_heads.size() == 2) {
137 assert(old_heads[0] == hashBlock);
138 old_tip = old_heads[1];
139 }
140 }
141
142 // In the first batch, mark the database as being in the middle of a
143 // transition from old_tip to hashBlock.
144 // A vector is used for future extensibility, as we may want to support
145 // interrupting after partial writes from multiple independent reorgs.
146 batch.Erase(DB_BEST_BLOCK);
147 batch.Write(DB_HEAD_BLOCKS, Vector(hashBlock, old_tip));
148
149 for (auto it{cursor.Begin()}; it != cursor.End();) {
150 if (it->second.IsDirty()) {
151 CoinEntry entry(&it->first);
152 if (it->second.coin.IsSpent()) {
153 batch.Erase(entry);
154 } else {
155 batch.Write(entry, it->second.coin);
156 }
157 changed++;
158 }
159 count++;
160 it = cursor.NextAndMaybeErase(*it);
162 LogPrint(BCLog::COINDB, "Writing partial batch of %.2f MiB\n",
163 batch.SizeEstimate() * (1.0 / 1048576.0));
164 m_db->WriteBatch(batch);
165 batch.Clear();
167 static FastRandomContext rng;
169 LogPrintf("Simulating a crash. Goodbye.\n");
170 _Exit(0);
171 }
172 }
173 }
174 }
175
176 // In the last batch, mark the database as consistent with hashBlock again.
177 batch.Erase(DB_HEAD_BLOCKS);
178 batch.Write(DB_BEST_BLOCK, hashBlock);
179
180 LogPrint(BCLog::COINDB, "Writing final batch of %.2f MiB\n",
181 batch.SizeEstimate() * (1.0 / 1048576.0));
182 bool ret = m_db->WriteBatch(batch);
184 "Committed %u changed transaction outputs (out of "
185 "%u) to coin database...\n",
186 (unsigned int)changed, (unsigned int)count);
187 return ret;
188}
189
191 return m_db->EstimateSize(DB_COIN, uint8_t(DB_COIN + 1));
192}
193
195 return Read(std::make_pair(DB_BLOCK_FILES, nFile), info);
196}
197
198bool CBlockTreeDB::WriteReindexing(bool fReindexing) {
199 if (fReindexing) {
200 return Write(DB_REINDEX_FLAG, uint8_t{'1'});
201 } else {
202 return Erase(DB_REINDEX_FLAG);
203 }
204}
205
207 return Exists(DB_REINDEX_FLAG);
208}
209
211 return Read(DB_LAST_BLOCK, nFile);
212}
213
216 const_cast<CDBWrapper &>(*m_db).NewIterator(), GetBestBlock());
222 i->pcursor->Seek(DB_COIN);
223 // Cache key of first record
224 if (i->pcursor->Valid()) {
225 CoinEntry entry(&i->keyTmp.second);
226 i->pcursor->GetKey(entry);
227 i->keyTmp.first = entry.key;
228 } else {
229 // Make sure Valid() and GetKey() return false
230 i->keyTmp.first = 0;
231 }
232 return i;
233}
234
235bool CCoinsViewDBCursor::GetKey(COutPoint &key) const {
236 // Return cached key
237 if (keyTmp.first == DB_COIN) {
238 key = keyTmp.second;
239 return true;
240 }
241 return false;
242}
243
245 return pcursor->GetValue(coin);
246}
247
249 return pcursor->GetValueSize();
250}
251
253 return keyTmp.first == DB_COIN;
254}
255
257 pcursor->Next();
258 CoinEntry entry(&keyTmp.second);
259 if (!pcursor->Valid() || !pcursor->GetKey(entry)) {
260 // Invalidate cached key after last record so that Valid() and GetKey()
261 // return false
262 keyTmp.first = 0;
263 } else {
264 keyTmp.first = entry.key;
265 }
266}
267
269 const std::vector<std::pair<int, const CBlockFileInfo *>> &fileInfo,
270 int nLastFile, const std::vector<const CBlockIndex *> &blockinfo) {
271 CDBBatch batch(*this);
272 for (std::vector<std::pair<int, const CBlockFileInfo *>>::const_iterator
273 it = fileInfo.begin();
274 it != fileInfo.end(); it++) {
275 batch.Write(std::make_pair(DB_BLOCK_FILES, it->first), *it->second);
276 }
277 batch.Write(DB_LAST_BLOCK, nLastFile);
278 for (std::vector<const CBlockIndex *>::const_iterator it =
279 blockinfo.begin();
280 it != blockinfo.end(); it++) {
281 batch.Write(std::make_pair(DB_BLOCK_INDEX, (*it)->GetBlockHash()),
282 CDiskBlockIndex(*it));
283 }
284 return WriteBatch(batch, true);
285}
286
287bool CBlockTreeDB::WriteFlag(const std::string &name, bool fValue) {
288 return Write(std::make_pair(DB_FLAG, name),
289 fValue ? uint8_t{'1'} : uint8_t{'0'});
290}
291
292bool CBlockTreeDB::ReadFlag(const std::string &name, bool &fValue) {
293 uint8_t ch;
294 if (!Read(std::make_pair(DB_FLAG, name), ch)) {
295 return false;
296 }
297 fValue = ch == uint8_t{'1'};
298 return true;
299}
300
302 const Consensus::Params &params,
303 std::function<CBlockIndex *(const BlockHash &)> insertBlockIndex,
304 const util::SignalInterrupt &interrupt) {
306 std::unique_ptr<CDBIterator> pcursor(NewIterator());
307
308 uint64_t version = 0;
309 pcursor->Seek("version");
310 if (pcursor->Valid()) {
311 pcursor->GetValue(version);
312 }
313
314 if (version != CLIENT_VERSION) {
315 LogError("%s: Invalid block index database version: %s\n", __func__,
316 version);
317 return false;
318 }
319
320 pcursor->Seek(std::make_pair(DB_BLOCK_INDEX, uint256()));
321
322 // Load m_block_index
323 while (pcursor->Valid()) {
324 if (interrupt) {
325 return false;
326 }
327 std::pair<uint8_t, uint256> key;
328 if (!pcursor->GetKey(key) || key.first != DB_BLOCK_INDEX) {
329 break;
330 }
331
332 CDiskBlockIndex diskindex;
333 if (!pcursor->GetValue(diskindex)) {
334 LogError("%s : failed to read value\n", __func__);
335 return false;
336 }
337
338 // Construct block index object
339 CBlockIndex *pindexNew =
340 insertBlockIndex(diskindex.ConstructBlockHash());
341 pindexNew->pprev = insertBlockIndex(diskindex.hashPrev);
342 pindexNew->nHeight = diskindex.nHeight;
343 pindexNew->nFile = diskindex.nFile;
344 pindexNew->nDataPos = diskindex.nDataPos;
345 pindexNew->nUndoPos = diskindex.nUndoPos;
346 pindexNew->nVersion = diskindex.nVersion;
347 pindexNew->hashMerkleRoot = diskindex.hashMerkleRoot;
348 pindexNew->nTime = diskindex.nTime;
349 pindexNew->nBits = diskindex.nBits;
350 pindexNew->nNonce = diskindex.nNonce;
351 pindexNew->nStatus = diskindex.nStatus;
352 pindexNew->nTx = diskindex.nTx;
353
354 if (!CheckProofOfWork(pindexNew->GetBlockHash(), pindexNew->nBits,
355 params)) {
356 LogError("%s: CheckProofOfWork failed: %s\n", __func__,
357 pindexNew->ToString());
358 return false;
359 }
360
361 pcursor->Next();
362 }
363
364 return true;
365}
366
368 // This method used to add the block size to pre-0.22.8 block index
369 // databases. This is no longer supported as of 0.25.5, but the method is
370 // kept to update the version number in the database.
371 std::unique_ptr<CDBIterator> pcursor(NewIterator());
372
373 uint64_t version = 0;
374 pcursor->Seek("version");
375 if (pcursor->Valid()) {
376 pcursor->GetValue(version);
377 }
378
379 if (version >= CLIENT_VERSION) {
380 // The DB is already up to date.
381 return true;
382 }
383
384 pcursor->Seek(std::make_pair(DB_BLOCK_INDEX, uint256()));
385
386 // The DB is not empty, and the version is either non-existent or too old.
387 // The node requires a reindex.
388 if (pcursor->Valid() && version < CDiskBlockIndex::TRACK_SIZE_VERSION) {
389 LogPrintf(
390 "\nThe database is too old. The block index cannot be upgraded "
391 "and reindexing is required.\n");
392 return false;
393 }
394
395 // The DB is empty or recent enough.
396 // Just write the new version number and consider the upgrade done.
397 CDBBatch batch(*this);
398 LogPrintf("Updating the block index database version to %d\n",
400 batch.Write("version", uint64_t(CLIENT_VERSION));
401 return WriteBatch(batch);
402}
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:194
bool Upgrade()
Attempt to update from an older database format.
Definition: txdb.cpp:367
bool WriteReindexing(bool fReindexing)
Definition: txdb.cpp:198
bool IsReindexing() const
Definition: txdb.cpp:206
bool WriteBatchSync(const std::vector< std::pair< int, const CBlockFileInfo * > > &fileInfo, int nLastFile, const std::vector< const CBlockIndex * > &blockinfo)
Definition: txdb.cpp:268
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:292
bool ReadLastBlockFile(int &nFile)
Definition: txdb.cpp:210
bool WriteFlag(const std::string &name, bool fValue)
Definition: txdb.cpp:287
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:235
bool GetValue(Coin &coin) const override
Definition: txdb.cpp:244
bool Valid() const override
Definition: txdb.cpp:252
unsigned int GetValueSize() const override
Definition: txdb.cpp:248
void Next() override
Definition: txdb.cpp:256
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:109
std::vector< BlockHash > GetHeadBlocks() const override
Retrieve the range of blocks that may have been only partially written.
Definition: txdb.cpp:117
bool GetCoin(const COutPoint &outpoint, Coin &coin) const override
Retrieve the Coin (unspent transaction output) for a given outpoint.
Definition: txdb.cpp:101
bool HaveCoin(const COutPoint &outpoint) const override
Just check whether a given outpoint is unspent.
Definition: txdb.cpp:105
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:214
CCoinsViewDB(DBParams db_params, CoinsViewOptions options)
Definition: txdb.cpp:84
bool BatchWrite(CoinsViewCacheCursor &cursor, const BlockHash &hashBlock) override
Do a bulk modification (multiple Coin changes + BestBlock change).
Definition: txdb.cpp:125
void ResizeCache(size_t new_cache_size) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
Dynamically alter the underlying leveldb cache size.
Definition: txdb.cpp:88
CoinsViewOptions m_options
Definition: txdb.h:52
bool NeedsUpgrade()
Whether an unsupported database format is used.
Definition: txdb.cpp:60
size_t EstimateSize() const override
Estimate database size (0 if not implemented)
Definition: txdb.cpp:190
DBParams m_db_params
Definition: txdb.h:51
Batch of changes queued to be written to a CDBWrapper.
Definition: dbwrapper.h:78
void Erase(const K &key)
Definition: dbwrapper.h:127
size_t SizeEstimate() const
Definition: dbwrapper.h:142
void Write(const K &key, const V &value)
Definition: dbwrapper.h:103
void Clear()
Definition: dbwrapper.h:98
bool WriteBatch(CDBBatch &batch, bool fSync=false)
Definition: dbwrapper.cpp:196
bool Read(const K &key, V &value) const
Definition: dbwrapper.h:254
CDBIterator * NewIterator()
Definition: dbwrapper.h:320
bool Erase(const K &key, bool fSync=false)
Definition: dbwrapper.h:309
bool Write(const K &key, const V &value, bool fSync=false)
Definition: dbwrapper.h:279
bool Exists(const K &key) const
Definition: dbwrapper.h:293
Used to marshal pointers into hashes for db storage.
Definition: chain.h:69
BlockHash hashPrev
Definition: chain.h:73
static constexpr int TRACK_SIZE_VERSION
Definition: chain.h:71
BlockHash ConstructBlockHash() const
Definition: chain.h:116
A UTXO entry.
Definition: coins.h:29
Fast randomness source.
Definition: random.h:156
uint64_t randrange(uint64_t range) noexcept
Generate a random integer in the range [0..range).
Definition: random.h:220
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:569
#define SERIALIZE_METHODS(cls, obj)
Implement the Serialize and Unserialize methods by delegating to a single templated static method tha...
Definition: serialize.h:215
#define SER_READ(obj, code)
Definition: serialize.h:171
#define READWRITE(...)
Definition: serialize.h:168
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:109
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:32
bool wipe_data
If true, remove all existing data.
Definition: dbwrapper.h:40
size_t cache_bytes
Configures various leveldb cache settings.
Definition: dbwrapper.h:36
bool memory_only
If true, use leveldb's memory environment.
Definition: dbwrapper.h:38
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:33
static constexpr uint8_t DB_LAST_BLOCK
Definition: txdb.cpp:29
static constexpr uint8_t DB_HEAD_BLOCKS
Definition: txdb.cpp:26
static constexpr uint8_t DB_REINDEX_FLAG
Definition: txdb.cpp:28
static constexpr uint8_t DB_BEST_BLOCK
Definition: txdb.cpp:25
util::Result< void > CheckLegacyTxindex(CBlockTreeDB &block_tree_db)
Definition: txdb.cpp:36
static constexpr uint8_t DB_COIN
Definition: txdb.cpp:21
static constexpr uint8_t DB_FLAG
Definition: txdb.cpp:27
static constexpr uint8_t DB_COINS
Definition: txdb.cpp:32
static constexpr uint8_t DB_BLOCK_FILES
Definition: txdb.cpp:22
static constexpr uint8_t DB_BLOCK_INDEX
Definition: txdb.cpp:23
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