Branch data Line data Source code
# 1 : : // Copyright (c) 2009-2010 Satoshi Nakamoto
# 2 : : // Copyright (c) 2009-2020 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 <node/ui_interface.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 const char DB_COIN = 'C';
# 20 : : static const char DB_COINS = 'c';
# 21 : : static const char DB_BLOCK_FILES = 'f';
# 22 : : static const char DB_BLOCK_INDEX = 'b';
# 23 : :
# 24 : : static const char DB_BEST_BLOCK = 'B';
# 25 : : static const char DB_HEAD_BLOCKS = 'H';
# 26 : : static const char DB_FLAG = 'F';
# 27 : : static const char DB_REINDEX_FLAG = 'R';
# 28 : : static const char DB_LAST_BLOCK = 'l';
# 29 : :
# 30 : : namespace {
# 31 : :
# 32 : : struct CoinEntry {
# 33 : : COutPoint* outpoint;
# 34 : : char key;
# 35 : 8162103 : explicit CoinEntry(const COutPoint* ptr) : outpoint(const_cast<COutPoint*>(ptr)), key(DB_COIN) {}
# 36 : :
# 37 : 8162031 : SERIALIZE_METHODS(CoinEntry, obj) { READWRITE(obj.key, obj.outpoint->hash, VARINT(obj.outpoint->n)); }
# 38 : : };
# 39 : :
# 40 : : }
# 41 : :
# 42 : : CCoinsViewDB::CCoinsViewDB(fs::path ldb_path, size_t nCacheSize, bool fMemory, bool fWipe) :
# 43 : : m_db(std::make_unique<CDBWrapper>(ldb_path, nCacheSize, fMemory, fWipe, true)),
# 44 : : m_ldb_path(ldb_path),
# 45 : 796 : m_is_memory(fMemory) { }
# 46 : :
# 47 : : void CCoinsViewDB::ResizeCache(size_t new_cache_size)
# 48 : 20 : {
# 49 : : // We can't do this operation with an in-memory DB since we'll lose all the coins upon
# 50 : : // reset.
# 51 [ - + ]: 20 : if (!m_is_memory) {
# 52 : : // Have to do a reset first to get the original `m_db` state to release its
# 53 : : // filesystem lock.
# 54 : 0 : m_db.reset();
# 55 : 0 : m_db = std::make_unique<CDBWrapper>(
# 56 : 0 : m_ldb_path, new_cache_size, m_is_memory, /*fWipe*/ false, /*obfuscate*/ true);
# 57 : 0 : }
# 58 : 20 : }
# 59 : :
# 60 : 7862528 : bool CCoinsViewDB::GetCoin(const COutPoint &outpoint, Coin &coin) const {
# 61 : 7862528 : return m_db->Read(CoinEntry(&outpoint), coin);
# 62 : 7862528 : }
# 63 : :
# 64 : 0 : bool CCoinsViewDB::HaveCoin(const COutPoint &outpoint) const {
# 65 : 0 : return m_db->Exists(CoinEntry(&outpoint));
# 66 : 0 : }
# 67 : :
# 68 : 4127 : uint256 CCoinsViewDB::GetBestBlock() const {
# 69 : 4127 : uint256 hashBestChain;
# 70 [ + + ]: 4127 : if (!m_db->Read(DB_BEST_BLOCK, hashBestChain))
# 71 : 1133 : return uint256();
# 72 : 2994 : return hashBestChain;
# 73 : 2994 : }
# 74 : :
# 75 : 883 : std::vector<uint256> CCoinsViewDB::GetHeadBlocks() const {
# 76 : 883 : std::vector<uint256> vhashHeadBlocks;
# 77 [ + - ]: 883 : if (!m_db->Read(DB_HEAD_BLOCKS, vhashHeadBlocks)) {
# 78 : 883 : return std::vector<uint256>();
# 79 : 883 : }
# 80 : 0 : return vhashHeadBlocks;
# 81 : 0 : }
# 82 : :
# 83 : 1935 : bool CCoinsViewDB::BatchWrite(CCoinsMap &mapCoins, const uint256 &hashBlock) {
# 84 : 1935 : CDBBatch batch(*m_db);
# 85 : 1935 : size_t count = 0;
# 86 : 1935 : size_t changed = 0;
# 87 : 1935 : size_t batch_size = (size_t)gArgs.GetArg("-dbbatchsize", nDefaultDbBatchSize);
# 88 : 1935 : int crash_simulate = gArgs.GetArg("-dbcrashratio", 0);
# 89 : 1935 : assert(!hashBlock.IsNull());
# 90 : :
# 91 : 1935 : uint256 old_tip = GetBestBlock();
# 92 [ + + ]: 1935 : if (old_tip.IsNull()) {
# 93 : : // We may be in the middle of replaying.
# 94 : 257 : std::vector<uint256> old_heads = GetHeadBlocks();
# 95 [ - + ]: 257 : if (old_heads.size() == 2) {
# 96 : 0 : assert(old_heads[0] == hashBlock);
# 97 : 0 : old_tip = old_heads[1];
# 98 : 0 : }
# 99 : 257 : }
# 100 : :
# 101 : : // In the first batch, mark the database as being in the middle of a
# 102 : : // transition from old_tip to hashBlock.
# 103 : : // A vector is used for future extensibility, as we may want to support
# 104 : : // interrupting after partial writes from multiple independent reorgs.
# 105 : 1935 : batch.Erase(DB_BEST_BLOCK);
# 106 : 1935 : batch.Write(DB_HEAD_BLOCKS, Vector(hashBlock, old_tip));
# 107 : :
# 108 [ + + ]: 399016 : for (CCoinsMap::iterator it = mapCoins.begin(); it != mapCoins.end();) {
# 109 [ + + ]: 397081 : if (it->second.flags & CCoinsCacheEntry::DIRTY) {
# 110 : 286088 : CoinEntry entry(&it->first);
# 111 [ + + ]: 286088 : if (it->second.coin.IsSpent())
# 112 : 38210 : batch.Erase(entry);
# 113 : 247878 : else
# 114 : 247878 : batch.Write(entry, it->second.coin);
# 115 : 286088 : changed++;
# 116 : 286088 : }
# 117 : 397081 : count++;
# 118 : 397081 : CCoinsMap::iterator itOld = it++;
# 119 : 397081 : mapCoins.erase(itOld);
# 120 [ - + ]: 397081 : if (batch.SizeEstimate() > batch_size) {
# 121 [ # # ]: 0 : LogPrint(BCLog::COINDB, "Writing partial batch of %.2f MiB\n", batch.SizeEstimate() * (1.0 / 1048576.0));
# 122 : 0 : m_db->WriteBatch(batch);
# 123 : 0 : batch.Clear();
# 124 [ # # ]: 0 : if (crash_simulate) {
# 125 : 0 : static FastRandomContext rng;
# 126 [ # # ]: 0 : if (rng.randrange(crash_simulate) == 0) {
# 127 : 0 : LogPrintf("Simulating a crash. Goodbye.\n");
# 128 : 0 : _Exit(0);
# 129 : 0 : }
# 130 : 0 : }
# 131 : 0 : }
# 132 : 397081 : }
# 133 : :
# 134 : : // In the last batch, mark the database as consistent with hashBlock again.
# 135 : 1935 : batch.Erase(DB_HEAD_BLOCKS);
# 136 : 1935 : batch.Write(DB_BEST_BLOCK, hashBlock);
# 137 : :
# 138 [ + - ]: 1935 : LogPrint(BCLog::COINDB, "Writing final batch of %.2f MiB\n", batch.SizeEstimate() * (1.0 / 1048576.0));
# 139 : 1935 : bool ret = m_db->WriteBatch(batch);
# 140 [ + - ]: 1935 : LogPrint(BCLog::COINDB, "Committed %u changed transaction outputs (out of %u) to coin database...\n", (unsigned int)changed, (unsigned int)count);
# 141 : 1935 : return ret;
# 142 : 1935 : }
# 143 : :
# 144 : : size_t CCoinsViewDB::EstimateSize() const
# 145 : 26 : {
# 146 : 26 : return m_db->EstimateSize(DB_COIN, (char)(DB_COIN+1));
# 147 : 26 : }
# 148 : :
# 149 : 783 : CBlockTreeDB::CBlockTreeDB(size_t nCacheSize, bool fMemory, bool fWipe) : CDBWrapper(gArgs.GetDataDirNet() / "blocks" / "index", nCacheSize, fMemory, fWipe) {
# 150 : 783 : }
# 151 : :
# 152 : 1240 : bool CBlockTreeDB::ReadBlockFileInfo(int nFile, CBlockFileInfo &info) {
# 153 : 1240 : return Read(std::make_pair(DB_BLOCK_FILES, nFile), info);
# 154 : 1240 : }
# 155 : :
# 156 : 20 : bool CBlockTreeDB::WriteReindexing(bool fReindexing) {
# 157 [ + + ]: 20 : if (fReindexing)
# 158 : 10 : return Write(DB_REINDEX_FLAG, '1');
# 159 : 10 : else
# 160 : 10 : return Erase(DB_REINDEX_FLAG);
# 161 : 20 : }
# 162 : :
# 163 : 616 : void CBlockTreeDB::ReadReindexing(bool &fReindexing) {
# 164 : 616 : fReindexing = Exists(DB_REINDEX_FLAG);
# 165 : 616 : }
# 166 : :
# 167 : 616 : bool CBlockTreeDB::ReadLastBlockFile(int &nFile) {
# 168 : 616 : return Read(DB_LAST_BLOCK, nFile);
# 169 : 616 : }
# 170 : :
# 171 : : CCoinsViewCursor *CCoinsViewDB::Cursor() const
# 172 : 344 : {
# 173 : 344 : CCoinsViewDBCursor *i = new CCoinsViewDBCursor(const_cast<CDBWrapper&>(*m_db).NewIterator(), GetBestBlock());
# 174 : : /* It seems that there are no "const iterators" for LevelDB. Since we
# 175 : : only need read operations on it, use a const-cast to get around
# 176 : : that restriction. */
# 177 : 344 : i->pcursor->Seek(DB_COIN);
# 178 : : // Cache key of first record
# 179 [ + + ]: 344 : if (i->pcursor->Valid()) {
# 180 : 343 : CoinEntry entry(&i->keyTmp.second);
# 181 : 343 : i->pcursor->GetKey(entry);
# 182 : 343 : i->keyTmp.first = entry.key;
# 183 : 343 : } else {
# 184 : 1 : i->keyTmp.first = 0; // Make sure Valid() and GetKey() return false
# 185 : 1 : }
# 186 : 344 : return i;
# 187 : 344 : }
# 188 : :
# 189 : : bool CCoinsViewDBCursor::GetKey(COutPoint &key) const
# 190 : 13144 : {
# 191 : : // Return cached key
# 192 [ + - ]: 13144 : if (keyTmp.first == DB_COIN) {
# 193 : 13144 : key = keyTmp.second;
# 194 : 13144 : return true;
# 195 : 13144 : }
# 196 : 0 : return false;
# 197 : 0 : }
# 198 : :
# 199 : : bool CCoinsViewDBCursor::GetValue(Coin &coin) const
# 200 : 13144 : {
# 201 : 13144 : return pcursor->GetValue(coin);
# 202 : 13144 : }
# 203 : :
# 204 : : unsigned int CCoinsViewDBCursor::GetValueSize() const
# 205 : 0 : {
# 206 : 0 : return pcursor->GetValueSize();
# 207 : 0 : }
# 208 : :
# 209 : : bool CCoinsViewDBCursor::Valid() const
# 210 : 13217 : {
# 211 : 13217 : return keyTmp.first == DB_COIN;
# 212 : 13217 : }
# 213 : :
# 214 : : void CCoinsViewDBCursor::Next()
# 215 : 13144 : {
# 216 : 13144 : pcursor->Next();
# 217 : 13144 : CoinEntry entry(&keyTmp.second);
# 218 [ + + ][ - + ]: 13144 : if (!pcursor->Valid() || !pcursor->GetKey(entry)) {
# 219 : 72 : keyTmp.first = 0; // Invalidate cached key after last record so that Valid() and GetKey() return false
# 220 : 13072 : } else {
# 221 : 13072 : keyTmp.first = entry.key;
# 222 : 13072 : }
# 223 : 13144 : }
# 224 : :
# 225 : 1588 : bool CBlockTreeDB::WriteBatchSync(const std::vector<std::pair<int, const CBlockFileInfo*> >& fileInfo, int nLastFile, const std::vector<const CBlockIndex*>& blockinfo) {
# 226 : 1588 : CDBBatch batch(*this);
# 227 [ + + ]: 2071 : for (std::vector<std::pair<int, const CBlockFileInfo*> >::const_iterator it=fileInfo.begin(); it != fileInfo.end(); it++) {
# 228 : 483 : batch.Write(std::make_pair(DB_BLOCK_FILES, it->first), *it->second);
# 229 : 483 : }
# 230 : 1588 : batch.Write(DB_LAST_BLOCK, nLastFile);
# 231 [ + + ]: 69979 : for (std::vector<const CBlockIndex*>::const_iterator it=blockinfo.begin(); it != blockinfo.end(); it++) {
# 232 : 68391 : batch.Write(std::make_pair(DB_BLOCK_INDEX, (*it)->GetBlockHash()), CDiskBlockIndex(*it));
# 233 : 68391 : }
# 234 : 1588 : return WriteBatch(batch, true);
# 235 : 1588 : }
# 236 : :
# 237 : 1 : bool CBlockTreeDB::WriteFlag(const std::string &name, bool fValue) {
# 238 [ + - ]: 1 : return Write(std::make_pair(DB_FLAG, name), fValue ? '1' : '0');
# 239 : 1 : }
# 240 : :
# 241 : 627 : bool CBlockTreeDB::ReadFlag(const std::string &name, bool &fValue) {
# 242 : 627 : char ch;
# 243 [ + + ]: 627 : if (!Read(std::make_pair(DB_FLAG, name), ch))
# 244 : 625 : return false;
# 245 : 2 : fValue = ch == '1';
# 246 : 2 : return true;
# 247 : 2 : }
# 248 : :
# 249 : : bool CBlockTreeDB::LoadBlockIndexGuts(const Consensus::Params& consensusParams, std::function<CBlockIndex*(const uint256&)> insertBlockIndex)
# 250 : 616 : {
# 251 : 616 : std::unique_ptr<CDBIterator> pcursor(NewIterator());
# 252 : :
# 253 : 616 : pcursor->Seek(std::make_pair(DB_BLOCK_INDEX, uint256()));
# 254 : :
# 255 : : // Load m_block_index
# 256 [ + + ]: 62976 : while (pcursor->Valid()) {
# 257 [ - + ]: 62740 : if (ShutdownRequested()) return false;
# 258 : 62740 : std::pair<char, uint256> key;
# 259 [ + + ][ + - ]: 62740 : if (pcursor->GetKey(key) && key.first == DB_BLOCK_INDEX) {
# 260 : 62360 : CDiskBlockIndex diskindex;
# 261 [ + - ]: 62360 : if (pcursor->GetValue(diskindex)) {
# 262 : : // Construct block index object
# 263 : 62360 : CBlockIndex* pindexNew = insertBlockIndex(diskindex.GetBlockHash());
# 264 : 62360 : pindexNew->pprev = insertBlockIndex(diskindex.hashPrev);
# 265 : 62360 : pindexNew->nHeight = diskindex.nHeight;
# 266 : 62360 : pindexNew->nFile = diskindex.nFile;
# 267 : 62360 : pindexNew->nDataPos = diskindex.nDataPos;
# 268 : 62360 : pindexNew->nUndoPos = diskindex.nUndoPos;
# 269 : 62360 : pindexNew->nVersion = diskindex.nVersion;
# 270 : 62360 : pindexNew->hashMerkleRoot = diskindex.hashMerkleRoot;
# 271 : 62360 : pindexNew->nTime = diskindex.nTime;
# 272 : 62360 : pindexNew->nBits = diskindex.nBits;
# 273 : 62360 : pindexNew->nNonce = diskindex.nNonce;
# 274 : 62360 : pindexNew->nStatus = diskindex.nStatus;
# 275 : 62360 : pindexNew->nTx = diskindex.nTx;
# 276 : :
# 277 [ - + ]: 62360 : if (!CheckProofOfWork(pindexNew->GetBlockHash(), pindexNew->nBits, consensusParams))
# 278 : 0 : return error("%s: CheckProofOfWork failed: %s", __func__, pindexNew->ToString());
# 279 : :
# 280 : 62360 : pcursor->Next();
# 281 : 62360 : } else {
# 282 : 0 : return error("%s: failed to read value", __func__);
# 283 : 0 : }
# 284 : 380 : } else {
# 285 : 380 : break;
# 286 : 380 : }
# 287 : 62740 : }
# 288 : :
# 289 : 616 : return true;
# 290 : 616 : }
# 291 : :
# 292 : : namespace {
# 293 : :
# 294 : : //! Legacy class to deserialize pre-pertxout database entries without reindex.
# 295 : : class CCoins
# 296 : : {
# 297 : : public:
# 298 : : //! whether transaction is a coinbase
# 299 : : bool fCoinBase;
# 300 : :
# 301 : : //! unspent transaction outputs; spent outputs are .IsNull(); spent outputs at the end of the array are dropped
# 302 : : std::vector<CTxOut> vout;
# 303 : :
# 304 : : //! at which height this transaction was included in the active block chain
# 305 : : int nHeight;
# 306 : :
# 307 : : //! empty constructor
# 308 : 0 : CCoins() : fCoinBase(false), vout(0), nHeight(0) { }
# 309 : :
# 310 : : template<typename Stream>
# 311 : 0 : void Unserialize(Stream &s) {
# 312 : 0 : unsigned int nCode = 0;
# 313 : : // version
# 314 : 0 : unsigned int nVersionDummy;
# 315 : 0 : ::Unserialize(s, VARINT(nVersionDummy));
# 316 : : // header code
# 317 : 0 : ::Unserialize(s, VARINT(nCode));
# 318 : 0 : fCoinBase = nCode & 1;
# 319 : 0 : std::vector<bool> vAvail(2, false);
# 320 : 0 : vAvail[0] = (nCode & 2) != 0;
# 321 : 0 : vAvail[1] = (nCode & 4) != 0;
# 322 [ # # ]: 0 : unsigned int nMaskCode = (nCode / 8) + ((nCode & 6) != 0 ? 0 : 1);
# 323 : : // spentness bitmask
# 324 [ # # ]: 0 : while (nMaskCode > 0) {
# 325 : 0 : unsigned char chAvail = 0;
# 326 : 0 : ::Unserialize(s, chAvail);
# 327 [ # # ]: 0 : for (unsigned int p = 0; p < 8; p++) {
# 328 : 0 : bool f = (chAvail & (1 << p)) != 0;
# 329 : 0 : vAvail.push_back(f);
# 330 : 0 : }
# 331 [ # # ]: 0 : if (chAvail != 0)
# 332 : 0 : nMaskCode--;
# 333 : 0 : }
# 334 : : // txouts themself
# 335 : 0 : vout.assign(vAvail.size(), CTxOut());
# 336 [ # # ]: 0 : for (unsigned int i = 0; i < vAvail.size(); i++) {
# 337 [ # # ]: 0 : if (vAvail[i])
# 338 : 0 : ::Unserialize(s, Using<TxOutCompression>(vout[i]));
# 339 : 0 : }
# 340 : : // coinbase height
# 341 : 0 : ::Unserialize(s, VARINT_MODE(nHeight, VarIntMode::NONNEGATIVE_SIGNED));
# 342 : 0 : }
# 343 : : };
# 344 : :
# 345 : : }
# 346 : :
# 347 : : /** Upgrade the database from older formats.
# 348 : : *
# 349 : : * Currently implemented: from the per-tx utxo model (0.8..0.14.x) to per-txout.
# 350 : : */
# 351 : 626 : bool CCoinsViewDB::Upgrade() {
# 352 : 626 : std::unique_ptr<CDBIterator> pcursor(m_db->NewIterator());
# 353 : 626 : pcursor->Seek(std::make_pair(DB_COINS, uint256()));
# 354 [ + - ]: 626 : if (!pcursor->Valid()) {
# 355 : 626 : return true;
# 356 : 626 : }
# 357 : :
# 358 : 0 : int64_t count = 0;
# 359 : 0 : LogPrintf("Upgrading utxo-set database...\n");
# 360 : 0 : LogPrintf("[0%%]..."); /* Continued */
# 361 : 0 : uiInterface.ShowProgress(_("Upgrading UTXO database").translated, 0, true);
# 362 : 0 : size_t batch_size = 1 << 24;
# 363 : 0 : CDBBatch batch(*m_db);
# 364 : 0 : int reportDone = 0;
# 365 : 0 : std::pair<unsigned char, uint256> key;
# 366 : 0 : std::pair<unsigned char, uint256> prev_key = {DB_COINS, uint256()};
# 367 [ # # ]: 0 : while (pcursor->Valid()) {
# 368 [ # # ]: 0 : if (ShutdownRequested()) {
# 369 : 0 : break;
# 370 : 0 : }
# 371 [ # # ][ # # ]: 0 : if (pcursor->GetKey(key) && key.first == DB_COINS) {
# 372 [ # # ]: 0 : if (count++ % 256 == 0) {
# 373 : 0 : uint32_t high = 0x100 * *key.second.begin() + *(key.second.begin() + 1);
# 374 : 0 : int percentageDone = (int)(high * 100.0 / 65536.0 + 0.5);
# 375 : 0 : uiInterface.ShowProgress(_("Upgrading UTXO database").translated, percentageDone, true);
# 376 [ # # ]: 0 : if (reportDone < percentageDone/10) {
# 377 : : // report max. every 10% step
# 378 : 0 : LogPrintf("[%d%%]...", percentageDone); /* Continued */
# 379 : 0 : reportDone = percentageDone/10;
# 380 : 0 : }
# 381 : 0 : }
# 382 : 0 : CCoins old_coins;
# 383 [ # # ]: 0 : if (!pcursor->GetValue(old_coins)) {
# 384 : 0 : return error("%s: cannot parse CCoins record", __func__);
# 385 : 0 : }
# 386 : 0 : COutPoint outpoint(key.second, 0);
# 387 [ # # ]: 0 : for (size_t i = 0; i < old_coins.vout.size(); ++i) {
# 388 [ # # ][ # # ]: 0 : if (!old_coins.vout[i].IsNull() && !old_coins.vout[i].scriptPubKey.IsUnspendable()) {
# 389 : 0 : Coin newcoin(std::move(old_coins.vout[i]), old_coins.nHeight, old_coins.fCoinBase);
# 390 : 0 : outpoint.n = i;
# 391 : 0 : CoinEntry entry(&outpoint);
# 392 : 0 : batch.Write(entry, newcoin);
# 393 : 0 : }
# 394 : 0 : }
# 395 : 0 : batch.Erase(key);
# 396 [ # # ]: 0 : if (batch.SizeEstimate() > batch_size) {
# 397 : 0 : m_db->WriteBatch(batch);
# 398 : 0 : batch.Clear();
# 399 : 0 : m_db->CompactRange(prev_key, key);
# 400 : 0 : prev_key = key;
# 401 : 0 : }
# 402 : 0 : pcursor->Next();
# 403 : 0 : } else {
# 404 : 0 : break;
# 405 : 0 : }
# 406 : 0 : }
# 407 : 0 : m_db->WriteBatch(batch);
# 408 : 0 : m_db->CompactRange({DB_COINS, uint256()}, key);
# 409 : 0 : uiInterface.ShowProgress("", 100, false);
# 410 [ # # ]: 0 : LogPrintf("[%s].\n", ShutdownRequested() ? "CANCELLED" : "DONE");
# 411 : 0 : return !ShutdownRequested();
# 412 : 0 : }
|