Branch data Line data Source code
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>
11 : : #include <primitives/transaction.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 : :
28 : : static constexpr uint8_t DB_COIN{'C'};
29 : : static constexpr uint8_t DB_BEST_BLOCK{'B'};
30 : : static constexpr uint8_t DB_HEAD_BLOCKS{'H'};
31 : : // Keys used in previous version that might still be found in the DB:
32 : : static constexpr uint8_t DB_COINS{'c'};
33 : :
34 : : // Threshold for warning when writing this many dirty cache entries to disk.
35 : : static constexpr size_t WARN_FLUSH_COINS_COUNT{10'000'000};
36 : :
37 : 3178 : bool CCoinsViewDB::NeedsUpgrade()
38 : : {
39 [ + - ]: 3178 : std::unique_ptr<CDBIterator> cursor{m_db->NewIterator()};
40 : : // DB_COINS was deprecated in v0.15.0, commit
41 : : // 1088b02f0ccd7358d2b7076bb9e122d59d502d02
42 [ + - ]: 3178 : cursor->Seek(std::make_pair(DB_COINS, uint256{}));
43 [ + - ]: 6356 : return cursor->Valid();
44 : 3178 : }
45 : :
46 : : namespace {
47 : :
48 : : struct CoinEntry {
49 : : COutPoint* outpoint;
50 : : uint8_t key{DB_COIN};
51 [ + - ]: 3644012 : explicit CoinEntry(const COutPoint* ptr) : outpoint(const_cast<COutPoint*>(ptr)) {}
52 : :
53 : 21015544 : SERIALIZE_METHODS(CoinEntry, obj) { READWRITE(obj.key, obj.outpoint->hash, VARINT(obj.outpoint->n)); }
54 : : };
55 : :
56 : : } // namespace
57 : :
58 : 12120 : CCoinsViewDB::CCoinsViewDB(DBParams db_params, CoinsViewOptions options) :
59 : 12120 : m_db_params{std::move(db_params)},
60 : 12120 : m_options{std::move(options)},
61 [ + - ]: 12120 : m_db{std::make_unique<CDBWrapper>(m_db_params)} { }
62 : :
63 : 12120 : CCoinsViewDB::~CCoinsViewDB()
64 : : {
65 [ + + ]: 12120 : if (m_compaction.valid()) {
66 [ + + ]: 3219 : if (m_compaction.wait_for(std::chrono::seconds{0}) != std::future_status::ready) {
67 [ - + ]: 3830 : LogInfo("Waiting for background chainstate compaction of %s", fs::PathToString(m_db_params.path));
68 : : }
69 : 3219 : m_compaction.wait();
70 : : }
71 [ + + ]: 15339 : }
72 : :
73 : 4302 : void 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.
77 [ - + ]: 4302 : if (!m_db_params.memory_only) {
78 : 0 : LOCK(m_db_mutex);
79 : : // Have to do a reset first to get the original `m_db` state to release its
80 : : // filesystem lock.
81 [ # # ]: 0 : m_db.reset();
82 : 0 : m_db_params.cache_bytes = new_cache_size;
83 : 0 : m_db_params.wipe_data = false;
84 [ # # # # ]: 0 : m_db = std::make_unique<CDBWrapper>(m_db_params);
85 : 0 : }
86 : 4302 : }
87 : :
88 : 3635312 : std::optional<Coin> CCoinsViewDB::GetCoin(const COutPoint& outpoint) const
89 : : {
90 : 3635312 : Coin coin;
91 [ + - ]: 3635312 : const CDBWrapper::ReadStatus res = m_db->TryRead(CoinEntry(&outpoint), coin);
92 [ - + ]: 3635312 : if (!res) {
93 : : // Propagate errors so CCoinsViewErrorCatcher triggers a clean shutdown.
94 [ # # # ]: 0 : switch (const auto& [err_code, err_msg] = res.error(); err_code) {
95 : 0 : case CDBWrapper::ReadFailure::Code::DeserializationError:
96 [ # # ]: 0 : throw dbwrapper_error{strprintf("Coin deserialization failure: %s", err_msg)};
97 : 0 : case CDBWrapper::ReadFailure::Code::DatabaseError:
98 [ # # ]: 0 : throw dbwrapper_error{strprintf("Coin DB read failure: %s", err_msg)};
99 : : } // no default case, so the compiler can warn about missing cases
100 : 0 : std::abort(); // unreachable
101 : : }
102 : :
103 : : // Check whether the coin exists
104 [ + - + + ]: 3635312 : if (!res.value()) return std::nullopt;
105 : : // Coin found, ensure UTXO database never contains spent coins
106 [ - + ]: 453353 : Assert(!coin.IsSpent());
107 : 453353 : return coin;
108 : 3635312 : }
109 : :
110 : 1924916 : std::optional<Coin> CCoinsViewDB::PeekCoin(const COutPoint& outpoint) const
111 : : {
112 : 1924916 : return GetCoin(outpoint);
113 : : }
114 : :
115 : 8700 : bool CCoinsViewDB::HaveCoin(const COutPoint& outpoint) const
116 : : {
117 : 8700 : return m_db->Exists(CoinEntry(&outpoint));
118 : : }
119 : :
120 : 3304634 : uint256 CCoinsViewDB::GetBestBlock() const {
121 : 3304634 : uint256 hashBestChain;
122 [ + + ]: 3304634 : if (!m_db->Read(DB_BEST_BLOCK, hashBestChain))
123 : 21477 : return uint256();
124 : 3283157 : return hashBestChain;
125 : : }
126 : :
127 : 32801 : std::vector<uint256> CCoinsViewDB::GetHeadBlocks() const {
128 : 32801 : std::vector<uint256> vhashHeadBlocks;
129 [ + - + - ]: 32801 : if (!m_db->Read(DB_HEAD_BLOCKS, vhashHeadBlocks)) {
130 : 32801 : return std::vector<uint256>();
131 : : }
132 : 0 : return vhashHeadBlocks;
133 : 32801 : }
134 : :
135 : 3148214 : void CCoinsViewDB::BatchWrite(CoinsViewCacheCursor& cursor, const uint256& block_hash)
136 : : {
137 : 3148214 : CDBBatch batch(*m_db);
138 : 3148214 : size_t count = 0;
139 : 3148214 : const size_t dirty_count{cursor.GetDirtyCount()};
140 [ - + ]: 6296428 : assert(!block_hash.IsNull());
141 : :
142 [ + - ]: 3148214 : uint256 old_tip = GetBestBlock();
143 [ + + ]: 3148214 : if (old_tip.IsNull()) {
144 : : // We may be in the middle of replaying.
145 [ + - ]: 8282 : std::vector<uint256> old_heads = GetHeadBlocks();
146 [ - + - + ]: 8282 : if (old_heads.size() == 2) {
147 [ # # ]: 0 : if (old_heads[0] != block_hash) {
148 [ # # ]: 0 : 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 [ # # ]: 0 : assert(old_heads[0] == block_hash);
151 : 0 : old_tip = old_heads[1];
152 : : }
153 : 8282 : }
154 : :
155 [ - + - - ]: 3148214 : if (dirty_count > WARN_FLUSH_COINS_COUNT) LogWarning("Flushing large (%d entries) UTXO set to disk, it may take several minutes", dirty_count);
156 [ + - + - : 6296428 : 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 [ + - ]: 3148214 : batch.Erase(DB_BEST_BLOCK);
164 [ + - + - ]: 3148214 : batch.Write(DB_HEAD_BLOCKS, Vector(block_hash, old_tip));
165 : :
166 [ + + ]: 3372530 : for (auto it{cursor.Begin()}; it != cursor.End();) {
167 [ + - ]: 224316 : if (it->second.IsDirty()) {
168 : 224316 : CoinEntry entry(&it->first);
169 [ + + ]: 224316 : if (it->second.coin.IsSpent()) {
170 [ + - ]: 3652 : batch.Erase(entry);
171 : : } else {
172 [ + - ]: 220664 : batch.Write(entry, it->second.coin);
173 : : }
174 : : }
175 : 224316 : count++;
176 : 224316 : it = cursor.NextAndMaybeErase(*it);
177 [ + - - + ]: 224316 : if (batch.ApproximateSize() > m_options.batch_write_bytes) {
178 [ # # # # : 0 : LogDebug(BCLog::COINDB, "Writing partial batch of %.2f MiB\n", batch.ApproximateSize() / double(1_MiB));
# # # # ]
179 : :
180 [ # # ]: 0 : m_db->WriteBatch(batch);
181 [ # # ]: 0 : batch.Clear();
182 [ # # ]: 0 : if (m_options.simulate_crash_ratio) {
183 [ # # # # ]: 0 : static FastRandomContext rng;
184 [ # # ]: 0 : if (rng.randrange(m_options.simulate_crash_ratio) == 0) {
185 [ # # ]: 0 : LogError("Simulating a crash. Goodbye.");
186 : 0 : _Exit(0);
187 : : }
188 : : }
189 : : }
190 : : }
191 : :
192 : : // In the last batch, mark the database as consistent with block_hash again.
193 [ + - ]: 3148214 : batch.Erase(DB_HEAD_BLOCKS);
194 [ + - ]: 3148214 : batch.Write(DB_BEST_BLOCK, block_hash);
195 : :
196 [ + - + + : 3148214 : LogDebug(BCLog::COINDB, "Writing final batch of %.2f MiB\n", batch.ApproximateSize() / double(1_MiB));
+ - + - ]
197 [ + - ]: 3148214 : m_db->WriteBatch(batch);
198 [ + - + + : 3148214 : LogDebug(BCLog::COINDB, "Committed %u changed transaction outputs (out of %u) to coin database...", (unsigned int)dirty_count, (unsigned int)count);
+ - ]
199 : 3148214 : }
200 : :
201 : 150259 : size_t CCoinsViewDB::EstimateSize() const
202 : : {
203 : 150259 : return m_db->EstimateSize(DB_COIN, uint8_t(DB_COIN + 1));
204 : : }
205 : :
206 : 0 : std::optional<std::string> CCoinsViewDB::GetDBProperty(const std::string& property)
207 : : {
208 : 0 : return m_db->GetProperty(property);
209 : : }
210 : :
211 : 422336 : std::shared_future<void> CCoinsViewDB::CompactFullAsync()
212 : : {
213 : 422336 : AssertLockHeld(::cs_main);
214 [ + + + + : 422336 : if (m_compaction.valid() && m_compaction.wait_for(std::chrono::seconds{0}) != std::future_status::ready) return m_compaction;
+ - ]
215 : 25466 : m_compaction = std::async(std::launch::async, [this] {
216 : 25466 : try {
217 [ + - + - ]: 25466 : util::ThreadRename("utxocompact");
218 [ + - ]: 25466 : LOCK(m_db_mutex);
219 : :
220 [ + - + + : 26053 : LogDebug(BCLog::COINDB, "Starting chainstate compaction of %s", fs::PathToString(m_db_params.path));
- + + - ]
221 [ + - ]: 25466 : m_db->CompactFull();
222 [ + - + + : 26053 : LogDebug(BCLog::COINDB, "Finished chainstate compaction of %s", fs::PathToString(m_db_params.path));
- + + - +
- ]
223 [ - - ]: 25466 : } catch (const std::exception& e) {
224 [ - - ]: 0 : LogWarning("Failed chainstate compaction (%s)", e.what());
225 : 0 : }
226 [ - + - + ]: 50932 : }).share();
227 [ + - ]: 25466 : return m_compaction;
228 : : }
229 : :
230 : : /** Specialization of CCoinsViewCursor to iterate over a CCoinsViewDB */
231 : : class CCoinsViewDBCursor: public CCoinsViewCursor
232 : : {
233 : : public:
234 : : // Prefer using CCoinsViewDB::Cursor() since we want to perform some
235 : : // cache warmup on instantiation.
236 : 137620 : CCoinsViewDBCursor(CDBIterator* pcursorIn, const uint256& in_block_hash):
237 : 137620 : CCoinsViewCursor(in_block_hash), pcursor(pcursorIn) {}
238 : 137620 : ~CCoinsViewDBCursor() = default;
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 : :
246 : : private:
247 : : std::unique_ptr<CDBIterator> pcursor;
248 : : std::pair<char, COutPoint> keyTmp;
249 : :
250 : : friend class CCoinsViewDB;
251 : : };
252 : :
253 : 137620 : std::unique_ptr<CCoinsViewCursor> CCoinsViewDB::Cursor() const
254 : : {
255 : 137620 : auto i = std::make_unique<CCoinsViewDBCursor>(
256 : 137620 : 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 [ + - ]: 137620 : i->pcursor->Seek(DB_COIN);
261 : : // Cache key of first record
262 [ + - + + ]: 137620 : if (i->pcursor->Valid()) {
263 [ + - ]: 130492 : CoinEntry entry(&i->keyTmp.second);
264 [ + - ]: 130492 : i->pcursor->GetKey(entry);
265 : 130492 : i->keyTmp.first = entry.key;
266 : : } else {
267 : 7128 : i->keyTmp.first = 0; // Make sure Valid() and GetKey() return false
268 : : }
269 : 137620 : return i;
270 : 137620 : }
271 : :
272 : 6636424 : bool CCoinsViewDBCursor::GetKey(COutPoint &key) const
273 : : {
274 : : // Return cached key
275 [ + - ]: 6636424 : if (keyTmp.first == DB_COIN) {
276 : 6636424 : key = keyTmp.second;
277 : 6636424 : return true;
278 : : }
279 : : return false;
280 : : }
281 : :
282 : 6636424 : bool CCoinsViewDBCursor::GetValue(Coin &coin) const
283 : : {
284 : 6636424 : return pcursor->GetValue(coin);
285 : : }
286 : :
287 : 6765344 : bool CCoinsViewDBCursor::Valid() const
288 : : {
289 : 6765344 : return keyTmp.first == DB_COIN;
290 : : }
291 : :
292 : 6636424 : void CCoinsViewDBCursor::Next()
293 : : {
294 : 6636424 : pcursor->Next();
295 : 6636424 : CoinEntry entry(&keyTmp.second);
296 [ + + - + ]: 6636424 : if (!pcursor->Valid() || !pcursor->GetKey(entry)) {
297 : 127472 : keyTmp.first = 0; // Invalidate cached key after last record so that Valid() and GetKey() return false
298 : : } else {
299 : 6508952 : keyTmp.first = entry.key;
300 : : }
301 : 6636424 : }
|