Bitcoin Core 31.99.0
P2P Digital Currency
txdb.cpp
Go to the documentation of this file.
1// Copyright (c) 2009-2010 Satoshi Nakamoto
2// Copyright (c) 2009-present 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 <coins.h>
9#include <dbwrapper.h>
10#include <logging/timer.h>
12#include <random.h>
13#include <serialize.h>
14#include <uint256.h>
15#include <util/byte_units.h>
16#include <util/log.h>
17#include <util/vector.h>
18
19#include <cassert>
20#include <cstdlib>
21#include <iterator>
22#include <utility>
23
24static constexpr uint8_t DB_COIN{'C'};
25static constexpr uint8_t DB_BEST_BLOCK{'B'};
26static constexpr uint8_t DB_HEAD_BLOCKS{'H'};
27// Keys used in previous version that might still be found in the DB:
28static constexpr uint8_t DB_COINS{'c'};
29
30// Threshold for warning when writing this many dirty cache entries to disk.
31static constexpr size_t WARN_FLUSH_COINS_COUNT{10'000'000};
32
34{
35 std::unique_ptr<CDBIterator> cursor{m_db->NewIterator()};
36 // DB_COINS was deprecated in v0.15.0, commit
37 // 1088b02f0ccd7358d2b7076bb9e122d59d502d02
38 cursor->Seek(std::make_pair(DB_COINS, uint256{}));
39 return cursor->Valid();
40}
41
42namespace {
43
44struct CoinEntry {
45 COutPoint* outpoint;
46 uint8_t key{DB_COIN};
47 explicit CoinEntry(const COutPoint* ptr) : outpoint(const_cast<COutPoint*>(ptr)) {}
48
49 SERIALIZE_METHODS(CoinEntry, obj) { READWRITE(obj.key, obj.outpoint->hash, VARINT(obj.outpoint->n)); }
50};
51
52} // namespace
53
55 m_db_params{std::move(db_params)},
56 m_options{std::move(options)},
57 m_db{std::make_unique<CDBWrapper>(m_db_params)} { }
58
59void CCoinsViewDB::ResizeCache(size_t new_cache_size)
60{
61 // We can't do this operation with an in-memory DB since we'll lose all the coins upon
62 // reset.
64 // Have to do a reset first to get the original `m_db` state to release its
65 // filesystem lock.
66 m_db.reset();
67 m_db_params.cache_bytes = new_cache_size;
68 m_db_params.wipe_data = false;
69 m_db = std::make_unique<CDBWrapper>(m_db_params);
70 }
71}
72
73std::optional<Coin> CCoinsViewDB::GetCoin(const COutPoint& outpoint) const
74{
75 if (Coin coin; m_db->Read(CoinEntry(&outpoint), coin)) {
76 Assert(!coin.IsSpent()); // The UTXO database should never contain spent coins
77 return coin;
78 }
79 return std::nullopt;
80}
81
82std::optional<Coin> CCoinsViewDB::PeekCoin(const COutPoint& outpoint) const
83{
84 return GetCoin(outpoint);
85}
86
87bool CCoinsViewDB::HaveCoin(const COutPoint& outpoint) const
88{
89 return m_db->Exists(CoinEntry(&outpoint));
90}
91
93 uint256 hashBestChain;
94 if (!m_db->Read(DB_BEST_BLOCK, hashBestChain))
95 return uint256();
96 return hashBestChain;
97}
98
99std::vector<uint256> CCoinsViewDB::GetHeadBlocks() const {
100 std::vector<uint256> vhashHeadBlocks;
101 if (!m_db->Read(DB_HEAD_BLOCKS, vhashHeadBlocks)) {
102 return std::vector<uint256>();
103 }
104 return vhashHeadBlocks;
105}
106
108{
109 CDBBatch batch(*m_db);
110 size_t count = 0;
111 const size_t dirty_count{cursor.GetDirtyCount()};
112 assert(!block_hash.IsNull());
113
114 uint256 old_tip = GetBestBlock();
115 if (old_tip.IsNull()) {
116 // We may be in the middle of replaying.
117 std::vector<uint256> old_heads = GetHeadBlocks();
118 if (old_heads.size() == 2) {
119 if (old_heads[0] != block_hash) {
120 LogError("The coins database detected an inconsistent state, likely due to a previous crash or shutdown. You will need to restart bitcoind with the -reindex-chainstate or -reindex configuration option.\n");
121 }
122 assert(old_heads[0] == block_hash);
123 old_tip = old_heads[1];
124 }
125 }
126
127 if (dirty_count > WARN_FLUSH_COINS_COUNT) LogWarning("Flushing large (%d entries) UTXO set to disk, it may take several minutes", dirty_count);
128 LOG_TIME_MILLIS_WITH_CATEGORY(strprintf("write coins cache to disk (%d out of %d cached coins)",
129 dirty_count, cursor.GetTotalCount()), BCLog::BENCH);
130
131 // In the first batch, mark the database as being in the middle of a
132 // transition from old_tip to block_hash.
133 // A vector is used for future extensibility, as we may want to support
134 // interrupting after partial writes from multiple independent reorgs.
135 batch.Erase(DB_BEST_BLOCK);
136 batch.Write(DB_HEAD_BLOCKS, Vector(block_hash, old_tip));
137
138 for (auto it{cursor.Begin()}; it != cursor.End();) {
139 if (it->second.IsDirty()) {
140 CoinEntry entry(&it->first);
141 if (it->second.coin.IsSpent()) {
142 batch.Erase(entry);
143 } else {
144 batch.Write(entry, it->second.coin);
145 }
146 }
147 count++;
148 it = cursor.NextAndMaybeErase(*it);
150 LogDebug(BCLog::COINDB, "Writing partial batch of %.2f MiB\n", batch.ApproximateSize() / double(1_MiB));
151
152 m_db->WriteBatch(batch);
153 batch.Clear();
155 static FastRandomContext rng;
157 LogError("Simulating a crash. Goodbye.");
158 _Exit(0);
159 }
160 }
161 }
162 }
163
164 // In the last batch, mark the database as consistent with block_hash again.
165 batch.Erase(DB_HEAD_BLOCKS);
166 batch.Write(DB_BEST_BLOCK, block_hash);
167
168 LogDebug(BCLog::COINDB, "Writing final batch of %.2f MiB\n", batch.ApproximateSize() / double(1_MiB));
169 m_db->WriteBatch(batch);
170 LogDebug(BCLog::COINDB, "Committed %u changed transaction outputs (out of %u) to coin database...", (unsigned int)dirty_count, (unsigned int)count);
171}
172
174{
175 return m_db->EstimateSize(DB_COIN, uint8_t(DB_COIN + 1));
176}
177
180{
181public:
182 // Prefer using CCoinsViewDB::Cursor() since we want to perform some
183 // cache warmup on instantiation.
184 CCoinsViewDBCursor(CDBIterator* pcursorIn, const uint256& in_block_hash):
185 CCoinsViewCursor(in_block_hash), pcursor(pcursorIn) {}
187
188 bool GetKey(COutPoint &key) const override;
189 bool GetValue(Coin &coin) const override;
190
191 bool Valid() const override;
192 void Next() override;
193
194private:
195 std::unique_ptr<CDBIterator> pcursor;
196 std::pair<char, COutPoint> keyTmp;
197
198 friend class CCoinsViewDB;
199};
200
201std::unique_ptr<CCoinsViewCursor> CCoinsViewDB::Cursor() const
202{
203 auto i = std::make_unique<CCoinsViewDBCursor>(
204 const_cast<CDBWrapper&>(*m_db).NewIterator(), GetBestBlock());
205 /* It seems that there are no "const iterators" for LevelDB. Since we
206 only need read operations on it, use a const-cast to get around
207 that restriction. */
208 i->pcursor->Seek(DB_COIN);
209 // Cache key of first record
210 if (i->pcursor->Valid()) {
211 CoinEntry entry(&i->keyTmp.second);
212 i->pcursor->GetKey(entry);
213 i->keyTmp.first = entry.key;
214 } else {
215 i->keyTmp.first = 0; // Make sure Valid() and GetKey() return false
216 }
217 return i;
218}
219
221{
222 // Return cached key
223 if (keyTmp.first == DB_COIN) {
224 key = keyTmp.second;
225 return true;
226 }
227 return false;
228}
229
231{
232 return pcursor->GetValue(coin);
233}
234
236{
237 return keyTmp.first == DB_COIN;
238}
239
241{
242 pcursor->Next();
243 CoinEntry entry(&keyTmp.second);
244 if (!pcursor->Valid() || !pcursor->GetKey(entry)) {
245 keyTmp.first = 0; // Invalidate cached key after last record so that Valid() and GetKey() return false
246 } else {
247 keyTmp.first = entry.key;
248 }
249}
#define Assert(val)
Identity function.
Definition: check.h:116
Cursor for iterating over CoinsView state.
Definition: coins.h:230
Specialization of CCoinsViewCursor to iterate over a CCoinsViewDB.
Definition: txdb.cpp:180
std::unique_ptr< CDBIterator > pcursor
Definition: txdb.cpp:195
bool GetKey(COutPoint &key) const override
Definition: txdb.cpp:220
~CCoinsViewDBCursor()=default
bool GetValue(Coin &coin) const override
Definition: txdb.cpp:230
CCoinsViewDBCursor(CDBIterator *pcursorIn, const uint256 &in_block_hash)
Definition: txdb.cpp:184
bool Valid() const override
Definition: txdb.cpp:235
void Next() override
Definition: txdb.cpp:240
std::pair< char, COutPoint > keyTmp
Definition: txdb.cpp:196
CCoinsView backed by the coin database (chainstate/)
Definition: txdb.h:35
bool HaveCoin(const COutPoint &outpoint) const override
Just check whether a given outpoint is unspent.
Definition: txdb.cpp:87
std::unique_ptr< CDBWrapper > m_db
Definition: txdb.h:39
CCoinsViewDB(DBParams db_params, CoinsViewOptions options)
Definition: txdb.cpp:54
std::optional< Coin > PeekCoin(const COutPoint &outpoint) const override
Retrieve the Coin (unspent transaction output) for a given outpoint, without caching results.
Definition: txdb.cpp:82
uint256 GetBestBlock() const override
Retrieve the block hash whose state this CCoinsView currently represents.
Definition: txdb.cpp:92
std::optional< Coin > GetCoin(const COutPoint &outpoint) const override
Retrieve the Coin (unspent transaction output) for a given outpoint.
Definition: txdb.cpp:73
std::unique_ptr< CCoinsViewCursor > Cursor() const override
Get a cursor to iterate over the whole state. Implementations may return nullptr.
Definition: txdb.cpp:201
void ResizeCache(size_t new_cache_size) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
Dynamically alter the underlying leveldb cache size.
Definition: txdb.cpp:59
CoinsViewOptions m_options
Definition: txdb.h:38
std::vector< uint256 > GetHeadBlocks() const override
Retrieve the range of blocks that may have been only partially written.
Definition: txdb.cpp:99
void BatchWrite(CoinsViewCacheCursor &cursor, const uint256 &block_hash) override
Do a bulk modification (multiple Coin changes + BestBlock change).
Definition: txdb.cpp:107
bool NeedsUpgrade()
Whether an unsupported database format is used.
Definition: txdb.cpp:33
size_t EstimateSize() const override
Estimate database size.
Definition: txdb.cpp:173
DBParams m_db_params
Definition: txdb.h:37
Batch of changes queued to be written to a CDBWrapper.
Definition: dbwrapper.h:73
void Erase(const K &key)
Definition: dbwrapper.h:109
void Write(const K &key, const V &value)
Definition: dbwrapper.h:97
void Clear()
Definition: dbwrapper.cpp:171
size_t ApproximateSize() const
Definition: dbwrapper.cpp:190
CDBIterator * NewIterator()
Definition: dbwrapper.cpp:361
An outpoint - a combination of a transaction hash and an index n into its vout.
Definition: transaction.h:29
A UTXO entry.
Definition: coins.h:35
Fast randomness source.
Definition: random.h:386
I randrange(I range) noexcept
Generate a random integer in the range [0..range), with range > 0.
Definition: random.h:254
constexpr bool IsNull() const
Definition: uint256.h:49
256-bit opaque blob.
Definition: uint256.h:196
#define LogWarning(...)
Definition: log.h:104
#define LogError(...)
Definition: log.h:105
#define LogDebug(category,...)
Definition: log.h:123
@ COINDB
Definition: categories.h:34
@ BENCH
Definition: categories.h:20
Definition: common.h:30
#define VARINT(obj)
Definition: serialize.h:493
#define SERIALIZE_METHODS(cls, obj)
Implement the Serialize and Unserialize methods by delegating to a single templated static method tha...
Definition: serialize.h:231
#define READWRITE(...)
Definition: serialize.h:147
constexpr CoinEntry(const CAmount v, const State s)
Cursor for iterating over the linked list of flagged entries in CCoinsViewCache.
Definition: coins.h:261
CoinsCachePair * NextAndMaybeErase(CoinsCachePair &current) noexcept
Return the next entry after current, possibly erasing current.
Definition: coins.h:279
size_t GetTotalCount() const noexcept
Definition: coins.h:298
size_t GetDirtyCount() const noexcept
Definition: coins.h:297
CoinsCachePair * Begin() const noexcept
Definition: coins.h:275
CoinsCachePair * End() const noexcept
Definition: coins.h:276
User-controlled performance and debug options.
Definition: txdb.h:26
int simulate_crash_ratio
If non-zero, randomly exit when the database is flushed with (1/ratio) probability.
Definition: txdb.h:30
size_t batch_write_bytes
Maximum database write batch size in bytes.
Definition: txdb.h:28
Application-specific storage settings.
Definition: dbwrapper.h:34
bool wipe_data
If true, remove all existing data.
Definition: dbwrapper.h:42
size_t cache_bytes
Configures various leveldb cache settings.
Definition: dbwrapper.h:38
bool memory_only
If true, use leveldb's memory environment.
Definition: dbwrapper.h:40
static int count
#define LOG_TIME_MILLIS_WITH_CATEGORY(end_msg, log_category)
Definition: timer.h:103
#define strprintf
Format arguments and return the string or write to given std::ostream (see tinyformat::format doc for...
Definition: tinyformat.h:1172
static constexpr size_t WARN_FLUSH_COINS_COUNT
Definition: txdb.cpp:31
static constexpr uint8_t DB_HEAD_BLOCKS
Definition: txdb.cpp:26
static constexpr uint8_t DB_BEST_BLOCK
Definition: txdb.cpp:25
static constexpr uint8_t DB_COIN
Definition: txdb.cpp:24
static constexpr uint8_t DB_COINS
Definition: txdb.cpp:28
assert(!tx.IsCoinBase())
std::vector< std::common_type_t< Args... > > Vector(Args &&... args)
Construct a vector with the specified elements.
Definition: vector.h:23