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/threadnames.h>
18#include <util/vector.h>
19
20#include <cassert>
21#include <chrono>
22#include <cstdlib>
23#include <exception>
24#include <future>
25#include <iterator>
26#include <utility>
27
28static constexpr uint8_t DB_COIN{'C'};
29static constexpr uint8_t DB_BEST_BLOCK{'B'};
30static constexpr uint8_t DB_HEAD_BLOCKS{'H'};
31// Keys used in previous version that might still be found in the DB:
32static constexpr uint8_t DB_COINS{'c'};
33
34// Threshold for warning when writing this many dirty cache entries to disk.
35static constexpr size_t WARN_FLUSH_COINS_COUNT{10'000'000};
36
38{
39 std::unique_ptr<CDBIterator> cursor{m_db->NewIterator()};
40 // DB_COINS was deprecated in v0.15.0, commit
41 // 1088b02f0ccd7358d2b7076bb9e122d59d502d02
42 cursor->Seek(std::make_pair(DB_COINS, uint256{}));
43 return cursor->Valid();
44}
45
46namespace {
47
48struct CoinEntry {
49 COutPoint* outpoint;
50 uint8_t key{DB_COIN};
51 explicit CoinEntry(const COutPoint* ptr) : outpoint(const_cast<COutPoint*>(ptr)) {}
52
53 SERIALIZE_METHODS(CoinEntry, obj) { READWRITE(obj.key, obj.outpoint->hash, VARINT(obj.outpoint->n)); }
54};
55
56} // namespace
57
59 m_db_params{std::move(db_params)},
60 m_options{std::move(options)},
61 m_db{std::make_unique<CDBWrapper>(m_db_params)} { }
62
64{
65 if (m_compaction.valid()) {
66 if (m_compaction.wait_for(std::chrono::seconds{0}) != std::future_status::ready) {
67 LogInfo("Waiting for background chainstate compaction of %s", fs::PathToString(m_db_params.path));
68 }
69 m_compaction.wait();
70 }
71}
72
73void CCoinsViewDB::ResizeCache(size_t new_cache_size)
74{
75 // We can't do this operation with an in-memory DB since we'll lose all the coins upon
76 // reset.
79 // Have to do a reset first to get the original `m_db` state to release its
80 // filesystem lock.
81 m_db.reset();
82 m_db_params.cache_bytes = new_cache_size;
83 m_db_params.wipe_data = false;
84 m_db = std::make_unique<CDBWrapper>(m_db_params);
85 }
86}
87
88std::optional<Coin> CCoinsViewDB::GetCoin(const COutPoint& outpoint) const
89{
90 Coin coin;
91 const CDBWrapper::ReadStatus res = m_db->TryRead(CoinEntry(&outpoint), coin);
92 if (!res) {
93 // Propagate errors so CCoinsViewErrorCatcher triggers a clean shutdown.
94 switch (const auto& [err_code, err_msg] = res.error(); err_code) {
96 throw dbwrapper_error{strprintf("Coin deserialization failure: %s", err_msg)};
98 throw dbwrapper_error{strprintf("Coin DB read failure: %s", err_msg)};
99 } // no default case, so the compiler can warn about missing cases
100 std::abort(); // unreachable
101 }
102
103 // Check whether the coin exists
104 if (!res.value()) return std::nullopt;
105 // Coin found, ensure UTXO database never contains spent coins
106 Assert(!coin.IsSpent());
107 return coin;
108}
109
110std::optional<Coin> CCoinsViewDB::PeekCoin(const COutPoint& outpoint) const
111{
112 return GetCoin(outpoint);
113}
114
115bool CCoinsViewDB::HaveCoin(const COutPoint& outpoint) const
116{
117 return m_db->Exists(CoinEntry(&outpoint));
118}
119
121 uint256 hashBestChain;
122 if (!m_db->Read(DB_BEST_BLOCK, hashBestChain))
123 return uint256();
124 return hashBestChain;
125}
126
127std::vector<uint256> CCoinsViewDB::GetHeadBlocks() const {
128 std::vector<uint256> vhashHeadBlocks;
129 if (!m_db->Read(DB_HEAD_BLOCKS, vhashHeadBlocks)) {
130 return std::vector<uint256>();
131 }
132 return vhashHeadBlocks;
133}
134
136{
137 CDBBatch batch(*m_db);
138 size_t count = 0;
139 const size_t dirty_count{cursor.GetDirtyCount()};
140 assert(!block_hash.IsNull());
141
142 uint256 old_tip = GetBestBlock();
143 if (old_tip.IsNull()) {
144 // We may be in the middle of replaying.
145 std::vector<uint256> old_heads = GetHeadBlocks();
146 if (old_heads.size() == 2) {
147 if (old_heads[0] != block_hash) {
148 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");
149 }
150 assert(old_heads[0] == block_hash);
151 old_tip = old_heads[1];
152 }
153 }
154
155 if (dirty_count > WARN_FLUSH_COINS_COUNT) LogWarning("Flushing large (%d entries) UTXO set to disk, it may take several minutes", dirty_count);
156 LOG_TIME_MILLIS_WITH_CATEGORY(strprintf("write coins cache to disk (%d out of %d cached coins)",
157 dirty_count, cursor.GetTotalCount()), BCLog::BENCH);
158
159 // In the first batch, mark the database as being in the middle of a
160 // transition from old_tip to block_hash.
161 // A vector is used for future extensibility, as we may want to support
162 // interrupting after partial writes from multiple independent reorgs.
163 batch.Erase(DB_BEST_BLOCK);
164 batch.Write(DB_HEAD_BLOCKS, Vector(block_hash, old_tip));
165
166 for (auto it{cursor.Begin()}; it != cursor.End();) {
167 if (it->second.IsDirty()) {
168 CoinEntry entry(&it->first);
169 if (it->second.coin.IsSpent()) {
170 batch.Erase(entry);
171 } else {
172 batch.Write(entry, it->second.coin);
173 }
174 }
175 count++;
176 it = cursor.NextAndMaybeErase(*it);
178 LogDebug(BCLog::COINDB, "Writing partial batch of %.2f MiB\n", batch.ApproximateSize() / double(1_MiB));
179
180 m_db->WriteBatch(batch);
181 batch.Clear();
183 static FastRandomContext rng;
185 LogError("Simulating a crash. Goodbye.");
186 _Exit(0);
187 }
188 }
189 }
190 }
191
192 // In the last batch, mark the database as consistent with block_hash again.
193 batch.Erase(DB_HEAD_BLOCKS);
194 batch.Write(DB_BEST_BLOCK, block_hash);
195
196 LogDebug(BCLog::COINDB, "Writing final batch of %.2f MiB\n", batch.ApproximateSize() / double(1_MiB));
197 m_db->WriteBatch(batch);
198 LogDebug(BCLog::COINDB, "Committed %u changed transaction outputs (out of %u) to coin database...", (unsigned int)dirty_count, (unsigned int)count);
199}
200
202{
203 return m_db->EstimateSize(DB_COIN, uint8_t(DB_COIN + 1));
204}
205
206std::optional<std::string> CCoinsViewDB::GetDBProperty(const std::string& property)
207{
208 return m_db->GetProperty(property);
209}
210
211std::shared_future<void> CCoinsViewDB::CompactFullAsync()
212{
214 if (m_compaction.valid() && m_compaction.wait_for(std::chrono::seconds{0}) != std::future_status::ready) return m_compaction;
215 m_compaction = std::async(std::launch::async, [this] {
216 try {
217 util::ThreadRename("utxocompact");
219
220 LogDebug(BCLog::COINDB, "Starting chainstate compaction of %s", fs::PathToString(m_db_params.path));
221 m_db->CompactFull();
222 LogDebug(BCLog::COINDB, "Finished chainstate compaction of %s", fs::PathToString(m_db_params.path));
223 } catch (const std::exception& e) {
224 LogWarning("Failed chainstate compaction (%s)", e.what());
225 }
226 }).share();
227 return m_compaction;
228}
229
232{
233public:
234 // Prefer using CCoinsViewDB::Cursor() since we want to perform some
235 // cache warmup on instantiation.
236 CCoinsViewDBCursor(CDBIterator* pcursorIn, const uint256& in_block_hash):
237 CCoinsViewCursor(in_block_hash), pcursor(pcursorIn) {}
239
240 bool GetKey(COutPoint &key) const override;
241 bool GetValue(Coin &coin) const override;
242
243 bool Valid() const override;
244 void Next() override;
245
246private:
247 std::unique_ptr<CDBIterator> pcursor;
248 std::pair<char, COutPoint> keyTmp;
249
250 friend class CCoinsViewDB;
251};
252
253std::unique_ptr<CCoinsViewCursor> CCoinsViewDB::Cursor() const
254{
255 auto i = std::make_unique<CCoinsViewDBCursor>(
256 const_cast<CDBWrapper&>(*m_db).NewIterator(), GetBestBlock());
257 /* It seems that there are no "const iterators" for LevelDB. Since we
258 only need read operations on it, use a const-cast to get around
259 that restriction. */
260 i->pcursor->Seek(DB_COIN);
261 // Cache key of first record
262 if (i->pcursor->Valid()) {
263 CoinEntry entry(&i->keyTmp.second);
264 i->pcursor->GetKey(entry);
265 i->keyTmp.first = entry.key;
266 } else {
267 i->keyTmp.first = 0; // Make sure Valid() and GetKey() return false
268 }
269 return i;
270}
271
273{
274 // Return cached key
275 if (keyTmp.first == DB_COIN) {
276 key = keyTmp.second;
277 return true;
278 }
279 return false;
280}
281
283{
284 return pcursor->GetValue(coin);
285}
286
288{
289 return keyTmp.first == DB_COIN;
290}
291
293{
294 pcursor->Next();
295 CoinEntry entry(&keyTmp.second);
296 if (!pcursor->Valid() || !pcursor->GetKey(entry)) {
297 keyTmp.first = 0; // Invalidate cached key after last record so that Valid() and GetKey() return false
298 } else {
299 keyTmp.first = entry.key;
300 }
301}
#define Assert(val)
Identity function.
Definition: check.h:116
Cursor for iterating over CoinsView state.
Definition: coins.h:278
Specialization of CCoinsViewCursor to iterate over a CCoinsViewDB.
Definition: txdb.cpp:232
std::unique_ptr< CDBIterator > pcursor
Definition: txdb.cpp:247
bool GetKey(COutPoint &key) const override
Definition: txdb.cpp:272
~CCoinsViewDBCursor()=default
bool GetValue(Coin &coin) const override
Definition: txdb.cpp:282
CCoinsViewDBCursor(CDBIterator *pcursorIn, const uint256 &in_block_hash)
Definition: txdb.cpp:236
bool Valid() const override
Definition: txdb.cpp:287
void Next() override
Definition: txdb.cpp:292
std::pair< char, COutPoint > keyTmp
Definition: txdb.cpp:248
CCoinsView backed by the coin database (chainstate/)
Definition: txdb.h:37
std::unique_ptr< CCoinsViewCursor > Cursor() const
Get a cursor to iterate over the whole state.
Definition: txdb.cpp:253
Mutex m_db_mutex
Prevents CompactFull() from using m_db while ResizeCache() replaces it.
Definition: txdb.h:42
std::shared_future< void > CompactFullAsync() EXCLUSIVE_LOCKS_REQUIRED(cs_main
Perform a full compaction of the underlying LevelDB on a one-shot background thread.
Definition: txdb.cpp:211
std::shared_future< void > m_compaction
Definition: txdb.h:44
bool HaveCoin(const COutPoint &outpoint) const override
Just check whether a given outpoint is unspent.
Definition: txdb.cpp:115
std::unique_ptr< CDBWrapper > m_db
Definition: txdb.h:43
~CCoinsViewDB() override
Definition: txdb.cpp:63
CCoinsViewDB(DBParams db_params, CoinsViewOptions options)
Definition: txdb.cpp:58
std::optional< std::string > GetDBProperty(const std::string &property)
Return an underlying LevelDB property value, if available.
Definition: txdb.cpp:206
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:110
uint256 GetBestBlock() const override
Retrieve the block hash whose state this CCoinsView currently represents.
Definition: txdb.cpp:120
std::optional< Coin > GetCoin(const COutPoint &outpoint) const override
Retrieve the Coin (unspent transaction output) for a given outpoint.
Definition: txdb.cpp:88
void ResizeCache(size_t new_cache_size) EXCLUSIVE_LOCKS_REQUIRED(cs_main
Dynamically alter the underlying leveldb cache size.
Definition: txdb.cpp:73
CoinsViewOptions m_options
Definition: txdb.h:40
std::vector< uint256 > GetHeadBlocks() const override
Retrieve the range of blocks that may have been only partially written.
Definition: txdb.cpp:127
void BatchWrite(CoinsViewCacheCursor &cursor, const uint256 &block_hash) override
Do a bulk modification (multiple Coin changes + BestBlock change).
Definition: txdb.cpp:135
bool NeedsUpgrade()
Whether an unsupported database format is used.
Definition: txdb.cpp:37
size_t EstimateSize() const override
Estimate database size.
Definition: txdb.cpp:201
DBParams m_db_params
Definition: txdb.h:39
Batch of changes queued to be written to a CDBWrapper.
Definition: dbwrapper.h:89
void Erase(const K &key)
Definition: dbwrapper.h:122
void Write(const K &key, const V &value)
Definition: dbwrapper.h:113
void Clear()
Definition: dbwrapper.cpp:195
size_t ApproximateSize() const
Definition: dbwrapper.cpp:216
CDBIterator * NewIterator()
Definition: dbwrapper.cpp:404
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:46
bool IsSpent() const
Either this coin never existed (see e.g.
Definition: coins.h:94
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:50
256-bit opaque blob.
Definition: uint256.h:196
The util::Expected class provides a standard way for low-level functions to return either error value...
Definition: expected.h:44
constexpr const T & value() const &LIFETIMEBOUND
Definition: expected.h:59
constexpr const E & error() const &noexcept LIFETIMEBOUND
Definition: expected.h:86
RecursiveMutex cs_main
Mutex to guard access to validation specific variables, such as reading or changing the chainstate.
Definition: cs_main.cpp:8
static std::string PathToString(const path &path)
Convert path object to a byte string.
Definition: fs.h:160
#define LogWarning(...)
Definition: log.h:126
#define LogInfo(...)
Definition: log.h:125
#define LogError(...)
Definition: log.h:127
#define LogDebug(category,...)
Definition: log.h:143
@ COINDB
Definition: categories.h:33
@ BENCH
Definition: categories.h:20
void ThreadRename(const std::string &)
Rename a thread both in terms of an internal (in-memory) name as well as its system thread name.
Definition: threadnames.cpp:66
#define VARINT(obj)
Definition: serialize.h:494
#define SERIALIZE_METHODS(cls, obj)
Implement the Serialize and Unserialize methods by delegating to a single templated static method tha...
Definition: serialize.h:232
#define READWRITE(...)
Definition: serialize.h:148
@ DeserializationError
Key exists but value could not be deserialized.
@ DatabaseError
Unexpected internal DB error.
constexpr CoinEntry(const CAmount v, const State s)
Cursor for iterating over the linked list of flagged entries in CCoinsViewCache.
Definition: coins.h:309
CoinsCachePair * NextAndMaybeErase(CoinsCachePair &current) noexcept
Return the next entry after current, possibly erasing current.
Definition: coins.h:327
size_t GetTotalCount() const noexcept
Definition: coins.h:346
size_t GetDirtyCount() const noexcept
Definition: coins.h:345
CoinsCachePair * Begin() const noexcept
Definition: coins.h:323
CoinsCachePair * End() const noexcept
Definition: coins.h:324
User-controlled performance and debug options.
Definition: txdb.h:28
uint64_t batch_write_bytes
Maximum database write batch size in bytes.
Definition: txdb.h:30
int simulate_crash_ratio
If non-zero, randomly exit when the database is flushed with (1/ratio) probability.
Definition: txdb.h:32
Application-specific storage settings.
Definition: dbwrapper.h:42
bool wipe_data
If true, remove all existing data.
Definition: dbwrapper.h:50
uint64_t cache_bytes
Configures various leveldb cache settings.
Definition: dbwrapper.h:46
fs::path path
Location in the filesystem where leveldb data will be stored.
Definition: dbwrapper.h:44
bool memory_only
If true, use leveldb's memory environment.
Definition: dbwrapper.h:48
#define LOCK(cs)
Definition: sync.h:268
FastRandomContext rng
Definition: dbwrapper.cpp:413
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:35
static constexpr uint8_t DB_HEAD_BLOCKS
Definition: txdb.cpp:30
static constexpr uint8_t DB_BEST_BLOCK
Definition: txdb.cpp:29
static constexpr uint8_t DB_COIN
Definition: txdb.cpp:28
static constexpr uint8_t DB_COINS
Definition: txdb.cpp:32
AssertLockHeld(pool.cs)
assert(!tx.IsCoinBase())
std::vector< std::common_type_t< Args... > > Vector(Args &&... args)
Construct a vector with the specified elements.
Definition: vector.h:23