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.h>
11 : : #include <primitives/transaction.h>
12 : : #include <random.h>
13 : : #include <serialize.h>
14 : : #include <uint256.h>
15 : : #include <util/vector.h>
16 : :
17 : : #include <cassert>
18 : : #include <cstdlib>
19 : : #include <iterator>
20 : : #include <utility>
21 : :
22 : : static constexpr uint8_t DB_COIN{'C'};
23 : : static constexpr uint8_t DB_BEST_BLOCK{'B'};
24 : : static constexpr uint8_t DB_HEAD_BLOCKS{'H'};
25 : : // Keys used in previous version that might still be found in the DB:
26 : : static constexpr uint8_t DB_COINS{'c'};
27 : :
28 : 2210 : bool CCoinsViewDB::NeedsUpgrade()
29 : : {
30 [ + - ]: 2210 : std::unique_ptr<CDBIterator> cursor{m_db->NewIterator()};
31 : : // DB_COINS was deprecated in v0.15.0, commit
32 : : // 1088b02f0ccd7358d2b7076bb9e122d59d502d02
33 [ + - ]: 2210 : cursor->Seek(std::make_pair(DB_COINS, uint256{}));
34 [ + - ]: 4420 : return cursor->Valid();
35 : 2210 : }
36 : :
37 : : namespace {
38 : :
39 : : struct CoinEntry {
40 : : COutPoint* outpoint;
41 : : uint8_t key{DB_COIN};
42 [ + - ]: 1838260 : explicit CoinEntry(const COutPoint* ptr) : outpoint(const_cast<COutPoint*>(ptr)) {}
43 : :
44 : 8085114 : SERIALIZE_METHODS(CoinEntry, obj) { READWRITE(obj.key, obj.outpoint->hash, VARINT(obj.outpoint->n)); }
45 : : };
46 : :
47 : : } // namespace
48 : :
49 : 10503 : CCoinsViewDB::CCoinsViewDB(DBParams db_params, CoinsViewOptions options) :
50 : 10503 : m_db_params{std::move(db_params)},
51 : 10503 : m_options{std::move(options)},
52 [ + - ]: 10503 : m_db{std::make_unique<CDBWrapper>(m_db_params)} { }
53 : :
54 : 5094 : void CCoinsViewDB::ResizeCache(size_t new_cache_size)
55 : : {
56 : : // We can't do this operation with an in-memory DB since we'll lose all the coins upon
57 : : // reset.
58 [ - + ]: 5094 : if (!m_db_params.memory_only) {
59 : : // Have to do a reset first to get the original `m_db` state to release its
60 : : // filesystem lock.
61 [ # # ]: 0 : m_db.reset();
62 : 0 : m_db_params.cache_bytes = new_cache_size;
63 : 0 : m_db_params.wipe_data = false;
64 : 0 : m_db = std::make_unique<CDBWrapper>(m_db_params);
65 : : }
66 : 5094 : }
67 : :
68 : 1832487 : std::optional<Coin> CCoinsViewDB::GetCoin(const COutPoint& outpoint) const
69 : : {
70 [ + - + + ]: 1832487 : if (Coin coin; m_db->Read(CoinEntry(&outpoint), coin)) {
71 [ - + ]: 127319 : Assert(!coin.IsSpent()); // The UTXO database should never contain spent coins
72 : 127319 : return coin;
73 : 127319 : }
74 : 1705168 : return std::nullopt;
75 : : }
76 : :
77 : 5773 : bool CCoinsViewDB::HaveCoin(const COutPoint &outpoint) const {
78 : 5773 : return m_db->Exists(CoinEntry(&outpoint));
79 : : }
80 : :
81 : 283725 : uint256 CCoinsViewDB::GetBestBlock() const {
82 : 283725 : uint256 hashBestChain;
83 [ + + ]: 283725 : if (!m_db->Read(DB_BEST_BLOCK, hashBestChain))
84 : 17930 : return uint256();
85 : 265795 : return hashBestChain;
86 : : }
87 : :
88 : 20700 : std::vector<uint256> CCoinsViewDB::GetHeadBlocks() const {
89 : 20700 : std::vector<uint256> vhashHeadBlocks;
90 [ + - + - ]: 20700 : if (!m_db->Read(DB_HEAD_BLOCKS, vhashHeadBlocks)) {
91 : 20700 : return std::vector<uint256>();
92 : : }
93 : 0 : return vhashHeadBlocks;
94 : 20700 : }
95 : :
96 : 117816 : void CCoinsViewDB::BatchWrite(CoinsViewCacheCursor& cursor, const uint256& hashBlock)
97 : : {
98 : 117816 : CDBBatch batch(*m_db);
99 : 117816 : size_t count = 0;
100 : 117816 : size_t changed = 0;
101 [ - + ]: 235632 : assert(!hashBlock.IsNull());
102 : :
103 [ + - ]: 117816 : uint256 old_tip = GetBestBlock();
104 [ + + ]: 117816 : if (old_tip.IsNull()) {
105 : : // We may be in the middle of replaying.
106 [ + - ]: 6944 : std::vector<uint256> old_heads = GetHeadBlocks();
107 [ - + - + ]: 6944 : if (old_heads.size() == 2) {
108 [ # # ]: 0 : if (old_heads[0] != hashBlock) {
109 [ # # ]: 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");
110 : : }
111 [ # # ]: 0 : assert(old_heads[0] == hashBlock);
112 : 0 : old_tip = old_heads[1];
113 : : }
114 : 6944 : }
115 : :
116 : : // In the first batch, mark the database as being in the middle of a
117 : : // transition from old_tip to hashBlock.
118 : : // A vector is used for future extensibility, as we may want to support
119 : : // interrupting after partial writes from multiple independent reorgs.
120 [ + - ]: 117816 : batch.Erase(DB_BEST_BLOCK);
121 [ + - + - ]: 117816 : batch.Write(DB_HEAD_BLOCKS, Vector(hashBlock, old_tip));
122 : :
123 [ + + ]: 227529 : for (auto it{cursor.Begin()}; it != cursor.End();) {
124 [ + - ]: 109713 : if (it->second.IsDirty()) {
125 : 109713 : CoinEntry entry(&it->first);
126 [ + + ]: 109713 : if (it->second.coin.IsSpent()) {
127 [ + - ]: 695 : batch.Erase(entry);
128 : : } else {
129 [ + - ]: 109018 : batch.Write(entry, it->second.coin);
130 : : }
131 : :
132 : 109713 : changed++;
133 : : }
134 : 109713 : count++;
135 : 109713 : it = cursor.NextAndMaybeErase(*it);
136 [ + - - + ]: 109713 : if (batch.ApproximateSize() > m_options.batch_write_bytes) {
137 [ # # # # : 0 : LogDebug(BCLog::COINDB, "Writing partial batch of %.2f MiB\n", batch.ApproximateSize() * (1.0 / 1048576.0));
# # # # ]
138 : :
139 [ # # ]: 0 : m_db->WriteBatch(batch);
140 [ # # ]: 0 : batch.Clear();
141 [ # # ]: 0 : if (m_options.simulate_crash_ratio) {
142 [ # # # # ]: 0 : static FastRandomContext rng;
143 [ # # ]: 0 : if (rng.randrange(m_options.simulate_crash_ratio) == 0) {
144 [ # # ]: 0 : LogError("Simulating a crash. Goodbye.");
145 : 0 : _Exit(0);
146 : : }
147 : : }
148 : : }
149 : : }
150 : :
151 : : // In the last batch, mark the database as consistent with hashBlock again.
152 [ + - ]: 117816 : batch.Erase(DB_HEAD_BLOCKS);
153 [ + - ]: 117816 : batch.Write(DB_BEST_BLOCK, hashBlock);
154 : :
155 [ + - + + : 117816 : LogDebug(BCLog::COINDB, "Writing final batch of %.2f MiB\n", batch.ApproximateSize() * (1.0 / 1048576.0));
+ - + - ]
156 [ + - ]: 117816 : m_db->WriteBatch(batch);
157 [ + - + + : 117816 : LogDebug(BCLog::COINDB, "Committed %u changed transaction outputs (out of %u) to coin database...\n", (unsigned int)changed, (unsigned int)count);
+ - ]
158 : 117816 : }
159 : :
160 : 85258 : size_t CCoinsViewDB::EstimateSize() const
161 : : {
162 : 85258 : return m_db->EstimateSize(DB_COIN, uint8_t(DB_COIN + 1));
163 : : }
164 : :
165 : : /** Specialization of CCoinsViewCursor to iterate over a CCoinsViewDB */
166 : : class CCoinsViewDBCursor: public CCoinsViewCursor
167 : : {
168 : : public:
169 : : // Prefer using CCoinsViewDB::Cursor() since we want to perform some
170 : : // cache warmup on instantiation.
171 : 79641 : CCoinsViewDBCursor(CDBIterator* pcursorIn, const uint256&hashBlockIn):
172 : 79641 : CCoinsViewCursor(hashBlockIn), pcursor(pcursorIn) {}
173 : 79641 : ~CCoinsViewDBCursor() = default;
174 : :
175 : : bool GetKey(COutPoint &key) const override;
176 : : bool GetValue(Coin &coin) const override;
177 : :
178 : : bool Valid() const override;
179 : : void Next() override;
180 : :
181 : : private:
182 : : std::unique_ptr<CDBIterator> pcursor;
183 : : std::pair<char, COutPoint> keyTmp;
184 : :
185 : : friend class CCoinsViewDB;
186 : : };
187 : :
188 : 79641 : std::unique_ptr<CCoinsViewCursor> CCoinsViewDB::Cursor() const
189 : : {
190 : 79641 : auto i = std::make_unique<CCoinsViewDBCursor>(
191 : 79641 : const_cast<CDBWrapper&>(*m_db).NewIterator(), GetBestBlock());
192 : : /* It seems that there are no "const iterators" for LevelDB. Since we
193 : : only need read operations on it, use a const-cast to get around
194 : : that restriction. */
195 [ + - ]: 79641 : i->pcursor->Seek(DB_COIN);
196 : : // Cache key of first record
197 [ + - + + ]: 79641 : if (i->pcursor->Valid()) {
198 [ + - ]: 72330 : CoinEntry entry(&i->keyTmp.second);
199 [ + - ]: 72330 : i->pcursor->GetKey(entry);
200 : 72330 : i->keyTmp.first = entry.key;
201 : : } else {
202 : 7311 : i->keyTmp.first = 0; // Make sure Valid() and GetKey() return false
203 : : }
204 : 79641 : return i;
205 : 79641 : }
206 : :
207 : 2094514 : bool CCoinsViewDBCursor::GetKey(COutPoint &key) const
208 : : {
209 : : // Return cached key
210 [ + - ]: 2094514 : if (keyTmp.first == DB_COIN) {
211 : 2094514 : key = keyTmp.second;
212 : 2094514 : return true;
213 : : }
214 : : return false;
215 : : }
216 : :
217 : 2094514 : bool CCoinsViewDBCursor::GetValue(Coin &coin) const
218 : : {
219 : 2094514 : return pcursor->GetValue(coin);
220 : : }
221 : :
222 : 2168382 : bool CCoinsViewDBCursor::Valid() const
223 : : {
224 : 2168382 : return keyTmp.first == DB_COIN;
225 : : }
226 : :
227 : 2094514 : void CCoinsViewDBCursor::Next()
228 : : {
229 : 2094514 : pcursor->Next();
230 : 2094514 : CoinEntry entry(&keyTmp.second);
231 [ + + - + ]: 2094514 : if (!pcursor->Valid() || !pcursor->GetKey(entry)) {
232 : 72260 : keyTmp.first = 0; // Invalidate cached key after last record so that Valid() and GetKey() return false
233 : : } else {
234 : 2022254 : keyTmp.first = entry.key;
235 : : }
236 : 2094514 : }
|