Line | Count | Source | ||||||||||||||||||||||||||||||
1 | // Copyright (c) 2011-present The Bitcoin Core developers | |||||||||||||||||||||||||||||||
2 | // Distributed under the MIT software license, see the accompanying | |||||||||||||||||||||||||||||||
3 | // file COPYING or http://www.opensource.org/licenses/mit-license.php. | |||||||||||||||||||||||||||||||
4 | ||||||||||||||||||||||||||||||||
5 | #ifndef BITCOIN_NODE_BLOCKSTORAGE_H | |||||||||||||||||||||||||||||||
6 | #define BITCOIN_NODE_BLOCKSTORAGE_H | |||||||||||||||||||||||||||||||
7 | ||||||||||||||||||||||||||||||||
8 | #include <attributes.h> | |||||||||||||||||||||||||||||||
9 | #include <chain.h> | |||||||||||||||||||||||||||||||
10 | #include <dbwrapper.h> | |||||||||||||||||||||||||||||||
11 | #include <flatfile.h> | |||||||||||||||||||||||||||||||
12 | #include <kernel/blockmanager_opts.h> | |||||||||||||||||||||||||||||||
13 | #include <kernel/chainparams.h> | |||||||||||||||||||||||||||||||
14 | #include <kernel/cs_main.h> | |||||||||||||||||||||||||||||||
15 | #include <kernel/messagestartchars.h> | |||||||||||||||||||||||||||||||
16 | #include <primitives/block.h> | |||||||||||||||||||||||||||||||
17 | #include <serialize.h> | |||||||||||||||||||||||||||||||
18 | #include <streams.h> | |||||||||||||||||||||||||||||||
19 | #include <sync.h> | |||||||||||||||||||||||||||||||
20 | #include <uint256.h> | |||||||||||||||||||||||||||||||
21 | // IWYU incorrectly suggests removing this header. | |||||||||||||||||||||||||||||||
22 | // See https://github.com/include-what-you-use/include-what-you-use/issues/2014. | |||||||||||||||||||||||||||||||
23 | #include <util/byte_units.h> // IWYU pragma: keep | |||||||||||||||||||||||||||||||
24 | #include <util/expected.h> | |||||||||||||||||||||||||||||||
25 | #include <util/fs.h> | |||||||||||||||||||||||||||||||
26 | #include <util/hasher.h> | |||||||||||||||||||||||||||||||
27 | #include <util/obfuscation.h> | |||||||||||||||||||||||||||||||
28 | ||||||||||||||||||||||||||||||||
29 | #include <algorithm> | |||||||||||||||||||||||||||||||
30 | #include <array> | |||||||||||||||||||||||||||||||
31 | #include <atomic> | |||||||||||||||||||||||||||||||
32 | #include <cstddef> | |||||||||||||||||||||||||||||||
33 | #include <cstdint> | |||||||||||||||||||||||||||||||
34 | #include <functional> | |||||||||||||||||||||||||||||||
35 | #include <iosfwd> | |||||||||||||||||||||||||||||||
36 | #include <limits> | |||||||||||||||||||||||||||||||
37 | #include <map> | |||||||||||||||||||||||||||||||
38 | #include <memory> | |||||||||||||||||||||||||||||||
39 | #include <optional> | |||||||||||||||||||||||||||||||
40 | #include <set> | |||||||||||||||||||||||||||||||
41 | #include <span> | |||||||||||||||||||||||||||||||
42 | #include <string> | |||||||||||||||||||||||||||||||
43 | #include <unordered_map> | |||||||||||||||||||||||||||||||
44 | #include <utility> | |||||||||||||||||||||||||||||||
45 | #include <vector> | |||||||||||||||||||||||||||||||
46 | ||||||||||||||||||||||||||||||||
47 | class BlockValidationState; | |||||||||||||||||||||||||||||||
48 | class CBlockUndo; | |||||||||||||||||||||||||||||||
49 | class Chainstate; | |||||||||||||||||||||||||||||||
50 | class ChainstateManager; | |||||||||||||||||||||||||||||||
51 | namespace Consensus { | |||||||||||||||||||||||||||||||
52 | struct Params; | |||||||||||||||||||||||||||||||
53 | } | |||||||||||||||||||||||||||||||
54 | namespace util { | |||||||||||||||||||||||||||||||
55 | class SignalInterrupt; | |||||||||||||||||||||||||||||||
56 | } // namespace util | |||||||||||||||||||||||||||||||
57 | ||||||||||||||||||||||||||||||||
58 | namespace kernel { | |||||||||||||||||||||||||||||||
59 | class CBlockFileInfo | |||||||||||||||||||||||||||||||
60 | { | |||||||||||||||||||||||||||||||
61 | public: | |||||||||||||||||||||||||||||||
62 | uint32_t nBlocks{}; //!< number of blocks stored in file | |||||||||||||||||||||||||||||||
63 | uint32_t nSize{}; //!< number of used bytes of block file | |||||||||||||||||||||||||||||||
64 | uint32_t nUndoSize{}; //!< number of used bytes in the undo file | |||||||||||||||||||||||||||||||
65 | uint32_t nHeightFirst{}; //!< lowest height of block in file | |||||||||||||||||||||||||||||||
66 | uint32_t nHeightLast{}; //!< highest height of block in file | |||||||||||||||||||||||||||||||
67 | uint64_t nTimeFirst{}; //!< earliest time of block in file | |||||||||||||||||||||||||||||||
68 | uint64_t nTimeLast{}; //!< latest time of block in file | |||||||||||||||||||||||||||||||
69 | ||||||||||||||||||||||||||||||||
70 | SERIALIZE_METHODS(CBlockFileInfo, obj) | |||||||||||||||||||||||||||||||
71 | 153k | { | ||||||||||||||||||||||||||||||
72 | 153k | READWRITE(VARINT(obj.nBlocks)); | ||||||||||||||||||||||||||||||
73 | 153k | READWRITE(VARINT(obj.nSize)); | ||||||||||||||||||||||||||||||
74 | 153k | READWRITE(VARINT(obj.nUndoSize)); | ||||||||||||||||||||||||||||||
75 | 153k | READWRITE(VARINT(obj.nHeightFirst)); | ||||||||||||||||||||||||||||||
76 | 153k | READWRITE(VARINT(obj.nHeightLast)); | ||||||||||||||||||||||||||||||
77 | 153k | READWRITE(VARINT(obj.nTimeFirst)); | ||||||||||||||||||||||||||||||
78 | 153k | READWRITE(VARINT(obj.nTimeLast)); | ||||||||||||||||||||||||||||||
79 | 153k | } Unexecuted instantiation: void kernel::CBlockFileInfo::SerializationOps<SpanReader, kernel::CBlockFileInfo, ActionUnserialize>(kernel::CBlockFileInfo&, SpanReader&, ActionUnserialize)
| ||||||||||||||||||||||||||||||
80 | ||||||||||||||||||||||||||||||||
81 | 54 | CBlockFileInfo() = default; | ||||||||||||||||||||||||||||||
82 | ||||||||||||||||||||||||||||||||
83 | std::string ToString() const; | |||||||||||||||||||||||||||||||
84 | ||||||||||||||||||||||||||||||||
85 | /** update statistics (does not update nSize) */ | |||||||||||||||||||||||||||||||
86 | void AddBlock(unsigned int nHeightIn, uint64_t nTimeIn) | |||||||||||||||||||||||||||||||
87 | 70.9k | { | ||||||||||||||||||||||||||||||
88 | 70.9k | if (nBlocks == 0 || nHeightFirst > nHeightIn) | ||||||||||||||||||||||||||||||
89 | 27 | nHeightFirst = nHeightIn; | ||||||||||||||||||||||||||||||
90 | 70.9k | if (nBlocks == 0 || nTimeFirst > nTimeIn) | ||||||||||||||||||||||||||||||
91 | 27 | nTimeFirst = nTimeIn; | ||||||||||||||||||||||||||||||
92 | 70.9k | nBlocks++; | ||||||||||||||||||||||||||||||
93 | 70.9k | if (nHeightIn > nHeightLast) Branch (93:13): [True: 32.1k, False: 38.8k] | ||||||||||||||||||||||||||||||
94 | 32.1k | nHeightLast = nHeightIn; | ||||||||||||||||||||||||||||||
95 | 70.9k | if (nTimeIn > nTimeLast) Branch (95:13): [True: 21.8k, False: 49.1k] | ||||||||||||||||||||||||||||||
96 | 21.8k | nTimeLast = nTimeIn; | ||||||||||||||||||||||||||||||
97 | 70.9k | } | ||||||||||||||||||||||||||||||
98 | }; | |||||||||||||||||||||||||||||||
99 | ||||||||||||||||||||||||||||||||
100 | /** Access to the block database (blocks/index/) */ | |||||||||||||||||||||||||||||||
101 | class BlockTreeDB : public CDBWrapper | |||||||||||||||||||||||||||||||
102 | { | |||||||||||||||||||||||||||||||
103 | public: | |||||||||||||||||||||||||||||||
104 | using CDBWrapper::CDBWrapper; | |||||||||||||||||||||||||||||||
105 | void WriteBatchSync(const std::vector<std::pair<int, const CBlockFileInfo*>>& fileInfo, int nLastFile, const std::vector<const CBlockIndex*>& blockinfo); | |||||||||||||||||||||||||||||||
106 | bool ReadBlockFileInfo(int nFile, CBlockFileInfo& info); | |||||||||||||||||||||||||||||||
107 | bool ReadLastBlockFile(int& nFile); | |||||||||||||||||||||||||||||||
108 | void WriteReindexing(bool fReindexing); | |||||||||||||||||||||||||||||||
109 | void ReadReindexing(bool& fReindexing); | |||||||||||||||||||||||||||||||
110 | void WriteFlag(const std::string& name, bool fValue); | |||||||||||||||||||||||||||||||
111 | bool ReadFlag(const std::string& name, bool& fValue); | |||||||||||||||||||||||||||||||
112 | bool LoadBlockIndexGuts(const Consensus::Params& consensusParams, std::function<CBlockIndex*(const uint256&)> insertBlockIndex, const util::SignalInterrupt& interrupt) | |||||||||||||||||||||||||||||||
113 | EXCLUSIVE_LOCKS_REQUIRED(::cs_main); | |||||||||||||||||||||||||||||||
114 | }; | |||||||||||||||||||||||||||||||
115 | } // namespace kernel | |||||||||||||||||||||||||||||||
116 | ||||||||||||||||||||||||||||||||
117 | namespace node { | |||||||||||||||||||||||||||||||
118 | using kernel::CBlockFileInfo; | |||||||||||||||||||||||||||||||
119 | using kernel::BlockTreeDB; | |||||||||||||||||||||||||||||||
120 | ||||||||||||||||||||||||||||||||
121 | /** The pre-allocation chunk size for blk?????.dat files (since 0.8) */ | |||||||||||||||||||||||||||||||
122 | static const unsigned int BLOCKFILE_CHUNK_SIZE{16_MiB}; | |||||||||||||||||||||||||||||||
123 | /** The pre-allocation chunk size for rev?????.dat files (since 0.8) */ | |||||||||||||||||||||||||||||||
124 | static const unsigned int UNDOFILE_CHUNK_SIZE{1_MiB}; | |||||||||||||||||||||||||||||||
125 | /** The maximum size of a blk?????.dat file (since 0.8) */ | |||||||||||||||||||||||||||||||
126 | static const unsigned int MAX_BLOCKFILE_SIZE{128_MiB}; | |||||||||||||||||||||||||||||||
127 | ||||||||||||||||||||||||||||||||
128 | /** Size of header written by WriteBlock before a serialized CBlock (8 bytes) */ | |||||||||||||||||||||||||||||||
129 | static constexpr uint32_t STORAGE_HEADER_BYTES{std::tuple_size_v<MessageStartChars> + sizeof(unsigned int)}; | |||||||||||||||||||||||||||||||
130 | ||||||||||||||||||||||||||||||||
131 | /** Total overhead when writing undo data: header (8 bytes) plus checksum (32 bytes) */ | |||||||||||||||||||||||||||||||
132 | static constexpr uint32_t UNDO_DATA_DISK_OVERHEAD{STORAGE_HEADER_BYTES + uint256::size()}; | |||||||||||||||||||||||||||||||
133 | ||||||||||||||||||||||||||||||||
134 | // Because validation code takes pointers to the map's CBlockIndex objects, if | |||||||||||||||||||||||||||||||
135 | // we ever switch to another associative container, we need to either use a | |||||||||||||||||||||||||||||||
136 | // container that has stable addressing (true of all std associative | |||||||||||||||||||||||||||||||
137 | // containers), or make the key a `std::unique_ptr<CBlockIndex>` | |||||||||||||||||||||||||||||||
138 | using BlockMap = std::unordered_map<uint256, CBlockIndex, BlockHasher>; | |||||||||||||||||||||||||||||||
139 | ||||||||||||||||||||||||||||||||
140 | struct CBlockIndexWorkComparator { | |||||||||||||||||||||||||||||||
141 | bool operator()(const CBlockIndex* pa, const CBlockIndex* pb) const; | |||||||||||||||||||||||||||||||
142 | using is_transparent = void; | |||||||||||||||||||||||||||||||
143 | }; | |||||||||||||||||||||||||||||||
144 | ||||||||||||||||||||||||||||||||
145 | struct CBlockIndexHeightOnlyComparator { | |||||||||||||||||||||||||||||||
146 | /* Only compares the height of two block indices, doesn't try to tie-break */ | |||||||||||||||||||||||||||||||
147 | bool operator()(const CBlockIndex* pa, const CBlockIndex* pb) const; | |||||||||||||||||||||||||||||||
148 | }; | |||||||||||||||||||||||||||||||
149 | ||||||||||||||||||||||||||||||||
150 | struct PruneLockInfo { | |||||||||||||||||||||||||||||||
151 | /// Height of earliest block that should be kept and not pruned | |||||||||||||||||||||||||||||||
152 | int height_first{std::numeric_limits<int>::max()}; | |||||||||||||||||||||||||||||||
153 | }; | |||||||||||||||||||||||||||||||
154 | ||||||||||||||||||||||||||||||||
155 | enum BlockfileType { | |||||||||||||||||||||||||||||||
156 | // Values used as array indexes - do not change carelessly. | |||||||||||||||||||||||||||||||
157 | NORMAL = 0, | |||||||||||||||||||||||||||||||
158 | ASSUMED = 1, | |||||||||||||||||||||||||||||||
159 | NUM_TYPES = 2, | |||||||||||||||||||||||||||||||
160 | }; | |||||||||||||||||||||||||||||||
161 | ||||||||||||||||||||||||||||||||
162 | std::ostream& operator<<(std::ostream& os, const BlockfileType& type); | |||||||||||||||||||||||||||||||
163 | ||||||||||||||||||||||||||||||||
164 | struct BlockfileCursor { | |||||||||||||||||||||||||||||||
165 | // The latest blockfile number. | |||||||||||||||||||||||||||||||
166 | int file_num{0}; | |||||||||||||||||||||||||||||||
167 | ||||||||||||||||||||||||||||||||
168 | // Track the height of the highest block in file_num whose undo | |||||||||||||||||||||||||||||||
169 | // data has been written. Block data is written to block files in download | |||||||||||||||||||||||||||||||
170 | // order, but is written to undo files in validation order, which is | |||||||||||||||||||||||||||||||
171 | // usually in order by height. To avoid wasting disk space, undo files will | |||||||||||||||||||||||||||||||
172 | // be trimmed whenever the corresponding block file is finalized and | |||||||||||||||||||||||||||||||
173 | // the height of the highest block written to the block file equals the | |||||||||||||||||||||||||||||||
174 | // height of the highest block written to the undo file. This is a | |||||||||||||||||||||||||||||||
175 | // heuristic and can sometimes preemptively trim undo files that will write | |||||||||||||||||||||||||||||||
176 | // more data later, and sometimes fail to trim undo files that can't have | |||||||||||||||||||||||||||||||
177 | // more data written later. | |||||||||||||||||||||||||||||||
178 | int undo_height{0}; | |||||||||||||||||||||||||||||||
179 | }; | |||||||||||||||||||||||||||||||
180 | ||||||||||||||||||||||||||||||||
181 | std::ostream& operator<<(std::ostream& os, const BlockfileCursor& cursor); | |||||||||||||||||||||||||||||||
182 | ||||||||||||||||||||||||||||||||
183 | enum class ReadRawError { | |||||||||||||||||||||||||||||||
184 | IO, | |||||||||||||||||||||||||||||||
185 | BadPartRange, | |||||||||||||||||||||||||||||||
186 | }; | |||||||||||||||||||||||||||||||
187 | ||||||||||||||||||||||||||||||||
188 | /** | |||||||||||||||||||||||||||||||
189 | * Maintains a tree of blocks (stored in `m_block_index`) which is consulted | |||||||||||||||||||||||||||||||
190 | * to determine where the most-work tip is. | |||||||||||||||||||||||||||||||
191 | * | |||||||||||||||||||||||||||||||
192 | * This data is used mostly in `Chainstate` - information about, e.g., | |||||||||||||||||||||||||||||||
193 | * candidate tips is not maintained here. | |||||||||||||||||||||||||||||||
194 | */ | |||||||||||||||||||||||||||||||
195 | class BlockManager | |||||||||||||||||||||||||||||||
196 | { | |||||||||||||||||||||||||||||||
197 | friend Chainstate; | |||||||||||||||||||||||||||||||
198 | friend ChainstateManager; | |||||||||||||||||||||||||||||||
199 | ||||||||||||||||||||||||||||||||
200 | private: | |||||||||||||||||||||||||||||||
201 | 183k | const CChainParams& GetParams() const { return m_opts.chainparams; } | ||||||||||||||||||||||||||||||
202 | 157k | const Consensus::Params& GetConsensus() const { return m_opts.chainparams.GetConsensus(); } | ||||||||||||||||||||||||||||||
203 | /** | |||||||||||||||||||||||||||||||
204 | * Load the blocktree off disk and into memory. Populate certain metadata | |||||||||||||||||||||||||||||||
205 | * per index entry (nStatus, nChainWork, nTimeMax, etc.) as well as peripheral | |||||||||||||||||||||||||||||||
206 | * collections like m_dirty_blockindex. | |||||||||||||||||||||||||||||||
207 | */ | |||||||||||||||||||||||||||||||
208 | bool LoadBlockIndex(const std::optional<uint256>& snapshot_blockhash) | |||||||||||||||||||||||||||||||
209 | EXCLUSIVE_LOCKS_REQUIRED(cs_main); | |||||||||||||||||||||||||||||||
210 | ||||||||||||||||||||||||||||||||
211 | /** Return false if block file or undo file flushing fails. */ | |||||||||||||||||||||||||||||||
212 | [[nodiscard]] bool FlushBlockFile(int blockfile_num, bool fFinalize, bool finalize_undo) EXCLUSIVE_LOCKS_REQUIRED(::cs_main); | |||||||||||||||||||||||||||||||
213 | ||||||||||||||||||||||||||||||||
214 | /** Return false if undo file flushing fails. */ | |||||||||||||||||||||||||||||||
215 | [[nodiscard]] bool FlushUndoFile(int block_file, bool finalize = false); | |||||||||||||||||||||||||||||||
216 | ||||||||||||||||||||||||||||||||
217 | /** | |||||||||||||||||||||||||||||||
218 | * Helper function performing various preparations before a block can be saved to disk: | |||||||||||||||||||||||||||||||
219 | * Returns the correct position for the block to be saved, which may be in the current or a new | |||||||||||||||||||||||||||||||
220 | * block file depending on nAddSize. May flush the previous blockfile to disk if full, updates | |||||||||||||||||||||||||||||||
221 | * blockfile info, and checks if there is enough disk space to save the block. | |||||||||||||||||||||||||||||||
222 | * | |||||||||||||||||||||||||||||||
223 | * The nAddSize argument passed to this function should include not just the size of the serialized CBlock, but also the size of | |||||||||||||||||||||||||||||||
224 | * separator fields (STORAGE_HEADER_BYTES). | |||||||||||||||||||||||||||||||
225 | */ | |||||||||||||||||||||||||||||||
226 | [[nodiscard]] FlatFilePos FindNextBlockPos(unsigned int nAddSize, unsigned int nHeight, uint64_t nTime) EXCLUSIVE_LOCKS_REQUIRED(::cs_main); | |||||||||||||||||||||||||||||||
227 | [[nodiscard]] bool FlushChainstateBlockFile(int tip_height) EXCLUSIVE_LOCKS_REQUIRED(::cs_main); | |||||||||||||||||||||||||||||||
228 | [[nodiscard]] bool FindUndoPos(BlockValidationState& state, int nFile, FlatFilePos& pos, unsigned int nAddSize) EXCLUSIVE_LOCKS_REQUIRED(::cs_main); | |||||||||||||||||||||||||||||||
229 | ||||||||||||||||||||||||||||||||
230 | AutoFile OpenUndoFile(const FlatFilePos& pos, bool fReadOnly = false) const; | |||||||||||||||||||||||||||||||
231 | ||||||||||||||||||||||||||||||||
232 | /* Calculate the block/rev files to delete based on height specified by user with RPC command pruneblockchain */ | |||||||||||||||||||||||||||||||
233 | void FindFilesToPruneManual( | |||||||||||||||||||||||||||||||
234 | std::set<int>& setFilesToPrune, | |||||||||||||||||||||||||||||||
235 | int nManualPruneHeight, | |||||||||||||||||||||||||||||||
236 | const Chainstate& chain); | |||||||||||||||||||||||||||||||
237 | ||||||||||||||||||||||||||||||||
238 | /** | |||||||||||||||||||||||||||||||
239 | * Prune block and undo files (blk???.dat and rev???.dat) so that the disk space used is less than a user-defined target. | |||||||||||||||||||||||||||||||
240 | * The user sets the target (in MB) on the command line or in config file. This will be run on startup and whenever new | |||||||||||||||||||||||||||||||
241 | * space is allocated in a block or undo file, staying below the target. Changing back to unpruned requires a reindex | |||||||||||||||||||||||||||||||
242 | * (which in this case means the blockchain must be re-downloaded.) | |||||||||||||||||||||||||||||||
243 | * | |||||||||||||||||||||||||||||||
244 | * Pruning functions are called from FlushStateToDisk when the m_check_for_pruning flag has been set. | |||||||||||||||||||||||||||||||
245 | * Block and undo files are deleted in lock-step (when blk00003.dat is deleted, so is rev00003.dat.) | |||||||||||||||||||||||||||||||
246 | * Pruning cannot take place until the longest chain is at least a certain length (CChainParams::nPruneAfterHeight). | |||||||||||||||||||||||||||||||
247 | * Pruning will never delete a block within a defined distance (currently 288) from the active chain's tip. | |||||||||||||||||||||||||||||||
248 | * The block index is updated by unsetting HAVE_DATA and HAVE_UNDO for any blocks that were stored in the deleted files. | |||||||||||||||||||||||||||||||
249 | * A db flag records the fact that at least some block files have been pruned. | |||||||||||||||||||||||||||||||
250 | * | |||||||||||||||||||||||||||||||
251 | * @param[out] setFilesToPrune The set of file indices that can be unlinked will be returned | |||||||||||||||||||||||||||||||
252 | * @param last_prune The last height we're able to prune, according to the prune locks | |||||||||||||||||||||||||||||||
253 | */ | |||||||||||||||||||||||||||||||
254 | void FindFilesToPrune( | |||||||||||||||||||||||||||||||
255 | std::set<int>& setFilesToPrune, | |||||||||||||||||||||||||||||||
256 | int last_prune, | |||||||||||||||||||||||||||||||
257 | const Chainstate& chain, | |||||||||||||||||||||||||||||||
258 | ChainstateManager& chainman); | |||||||||||||||||||||||||||||||
259 | ||||||||||||||||||||||||||||||||
260 | //! Since assumedvalid chainstates may be syncing a range of the chain that is very | |||||||||||||||||||||||||||||||
261 | //! far away from the normal/background validation process, we should segment blockfiles | |||||||||||||||||||||||||||||||
262 | //! for assumed chainstates. Otherwise, we might have wildly different height ranges | |||||||||||||||||||||||||||||||
263 | //! mixed into the same block files, which would impair our ability to prune | |||||||||||||||||||||||||||||||
264 | //! effectively. | |||||||||||||||||||||||||||||||
265 | //! | |||||||||||||||||||||||||||||||
266 | //! This data structure maintains separate blockfile number cursors for each | |||||||||||||||||||||||||||||||
267 | //! BlockfileType. The ASSUMED state is initialized, when necessary, in FindNextBlockPos(). | |||||||||||||||||||||||||||||||
268 | //! | |||||||||||||||||||||||||||||||
269 | //! The first element is the NORMAL cursor, second is ASSUMED. | |||||||||||||||||||||||||||||||
270 | std::array<std::optional<BlockfileCursor>, BlockfileType::NUM_TYPES> | |||||||||||||||||||||||||||||||
271 | m_blockfile_cursors GUARDED_BY(::cs_main) = { | |||||||||||||||||||||||||||||||
272 | BlockfileCursor{}, | |||||||||||||||||||||||||||||||
273 | std::nullopt, | |||||||||||||||||||||||||||||||
274 | }; | |||||||||||||||||||||||||||||||
275 | int MaxBlockfileNum() const EXCLUSIVE_LOCKS_REQUIRED(::cs_main) | |||||||||||||||||||||||||||||||
276 | 305k | { | ||||||||||||||||||||||||||||||
277 | 305k | AssertLockHeld(::cs_main); | ||||||||||||||||||||||||||||||
278 | 305k | static const BlockfileCursor empty_cursor; | ||||||||||||||||||||||||||||||
279 | 305k | const auto& normal = m_blockfile_cursors[BlockfileType::NORMAL].value_or(empty_cursor); | ||||||||||||||||||||||||||||||
280 | 305k | const auto& assumed = m_blockfile_cursors[BlockfileType::ASSUMED].value_or(empty_cursor); | ||||||||||||||||||||||||||||||
281 | 305k | return std::max(normal.file_num, assumed.file_num); | ||||||||||||||||||||||||||||||
282 | 305k | } | ||||||||||||||||||||||||||||||
283 | ||||||||||||||||||||||||||||||||
284 | /** Global flag to indicate we should check to see if there are | |||||||||||||||||||||||||||||||
285 | * block/undo files that should be deleted. Set on startup | |||||||||||||||||||||||||||||||
286 | * or if we allocate more file space when we're in prune mode | |||||||||||||||||||||||||||||||
287 | */ | |||||||||||||||||||||||||||||||
288 | bool m_check_for_pruning = false; | |||||||||||||||||||||||||||||||
289 | ||||||||||||||||||||||||||||||||
290 | const bool m_prune_mode; | |||||||||||||||||||||||||||||||
291 | ||||||||||||||||||||||||||||||||
292 | const Obfuscation m_obfuscation; | |||||||||||||||||||||||||||||||
293 | ||||||||||||||||||||||||||||||||
294 | /** | |||||||||||||||||||||||||||||||
295 | * Map from external index name to oldest block that must not be pruned. | |||||||||||||||||||||||||||||||
296 | * | |||||||||||||||||||||||||||||||
297 | * @note Internally, only blocks at height (height_first - PRUNE_LOCK_BUFFER - 1) and | |||||||||||||||||||||||||||||||
298 | * below will be pruned, but callers should avoid assuming any particular buffer size. | |||||||||||||||||||||||||||||||
299 | */ | |||||||||||||||||||||||||||||||
300 | std::unordered_map<std::string, PruneLockInfo> m_prune_locks GUARDED_BY(::cs_main); | |||||||||||||||||||||||||||||||
301 | ||||||||||||||||||||||||||||||||
302 | BlockfileType BlockfileTypeForHeight(int height); | |||||||||||||||||||||||||||||||
303 | ||||||||||||||||||||||||||||||||
304 | const kernel::BlockManagerOpts m_opts; | |||||||||||||||||||||||||||||||
305 | ||||||||||||||||||||||||||||||||
306 | const FlatFileSeq m_block_file_seq; | |||||||||||||||||||||||||||||||
307 | const FlatFileSeq m_undo_file_seq; | |||||||||||||||||||||||||||||||
308 | ||||||||||||||||||||||||||||||||
309 | protected: | |||||||||||||||||||||||||||||||
310 | std::vector<CBlockFileInfo> m_blockfile_info; | |||||||||||||||||||||||||||||||
311 | ||||||||||||||||||||||||||||||||
312 | /** Dirty block index entries. */ | |||||||||||||||||||||||||||||||
313 | std::set<CBlockIndex*> m_dirty_blockindex; | |||||||||||||||||||||||||||||||
314 | ||||||||||||||||||||||||||||||||
315 | /** Dirty block file entries. */ | |||||||||||||||||||||||||||||||
316 | std::set<int> m_dirty_fileinfo; | |||||||||||||||||||||||||||||||
317 | ||||||||||||||||||||||||||||||||
318 | public: | |||||||||||||||||||||||||||||||
319 | using Options = kernel::BlockManagerOpts; | |||||||||||||||||||||||||||||||
320 | using ReadRawBlockResult = util::Expected<std::vector<std::byte>, ReadRawError>; | |||||||||||||||||||||||||||||||
321 | ||||||||||||||||||||||||||||||||
322 | explicit BlockManager(const util::SignalInterrupt& interrupt, Options opts); | |||||||||||||||||||||||||||||||
323 | ||||||||||||||||||||||||||||||||
324 | const util::SignalInterrupt& m_interrupt; | |||||||||||||||||||||||||||||||
325 | std::atomic<bool> m_importing{false}; | |||||||||||||||||||||||||||||||
326 | ||||||||||||||||||||||||||||||||
327 | /** | |||||||||||||||||||||||||||||||
328 | * Whether all blockfiles have been added to the block tree database. | |||||||||||||||||||||||||||||||
329 | * Normally true, but set to false when a reindex is requested and the | |||||||||||||||||||||||||||||||
330 | * database is wiped. The value is persisted in the database across restarts | |||||||||||||||||||||||||||||||
331 | * and will be false until reindexing completes. | |||||||||||||||||||||||||||||||
332 | */ | |||||||||||||||||||||||||||||||
333 | std::atomic_bool m_blockfiles_indexed{true}; | |||||||||||||||||||||||||||||||
334 | ||||||||||||||||||||||||||||||||
335 | BlockMap m_block_index GUARDED_BY(cs_main); | |||||||||||||||||||||||||||||||
336 | ||||||||||||||||||||||||||||||||
337 | /** | |||||||||||||||||||||||||||||||
338 | * The height of the base block of an assumeutxo snapshot, if one is in use. | |||||||||||||||||||||||||||||||
339 | * | |||||||||||||||||||||||||||||||
340 | * This controls how blockfiles are segmented by chainstate type to avoid | |||||||||||||||||||||||||||||||
341 | * comingling different height regions of the chain when an assumedvalid chainstate | |||||||||||||||||||||||||||||||
342 | * is in use. If heights are drastically different in the same blockfile, pruning | |||||||||||||||||||||||||||||||
343 | * suffers. | |||||||||||||||||||||||||||||||
344 | * | |||||||||||||||||||||||||||||||
345 | * This is set during ActivateSnapshot() or upon LoadBlockIndex() if a snapshot | |||||||||||||||||||||||||||||||
346 | * had been previously loaded. After the snapshot is validated, this is unset to | |||||||||||||||||||||||||||||||
347 | * restore normal LoadBlockIndex behavior. | |||||||||||||||||||||||||||||||
348 | */ | |||||||||||||||||||||||||||||||
349 | std::optional<int> m_snapshot_height; | |||||||||||||||||||||||||||||||
350 | ||||||||||||||||||||||||||||||||
351 | std::vector<CBlockIndex*> GetAllBlockIndices() EXCLUSIVE_LOCKS_REQUIRED(::cs_main); | |||||||||||||||||||||||||||||||
352 | ||||||||||||||||||||||||||||||||
353 | /** | |||||||||||||||||||||||||||||||
354 | * All pairs A->B, where A (or one of its ancestors) misses transactions, but B has transactions. | |||||||||||||||||||||||||||||||
355 | */ | |||||||||||||||||||||||||||||||
356 | std::multimap<CBlockIndex*, CBlockIndex*> m_blocks_unlinked; | |||||||||||||||||||||||||||||||
357 | void AddUnlinkedBlock(CBlockIndex* block) EXCLUSIVE_LOCKS_REQUIRED(cs_main); | |||||||||||||||||||||||||||||||
358 | ||||||||||||||||||||||||||||||||
359 | std::unique_ptr<BlockTreeDB> m_block_tree_db GUARDED_BY(::cs_main); | |||||||||||||||||||||||||||||||
360 | ||||||||||||||||||||||||||||||||
361 | void WriteBlockIndexDB() EXCLUSIVE_LOCKS_REQUIRED(::cs_main); | |||||||||||||||||||||||||||||||
362 | bool LoadBlockIndexDB(const std::optional<uint256>& snapshot_blockhash) | |||||||||||||||||||||||||||||||
363 | EXCLUSIVE_LOCKS_REQUIRED(::cs_main); | |||||||||||||||||||||||||||||||
364 | ||||||||||||||||||||||||||||||||
365 | /** | |||||||||||||||||||||||||||||||
366 | * Remove any pruned block & undo files that are still on disk. | |||||||||||||||||||||||||||||||
367 | * This could happen on some systems if the file was still being read while unlinked, | |||||||||||||||||||||||||||||||
368 | * or if we crash before unlinking. | |||||||||||||||||||||||||||||||
369 | */ | |||||||||||||||||||||||||||||||
370 | void ScanAndUnlinkAlreadyPrunedFiles() EXCLUSIVE_LOCKS_REQUIRED(::cs_main); | |||||||||||||||||||||||||||||||
371 | ||||||||||||||||||||||||||||||||
372 | CBlockIndex* AddToBlockIndex(const CBlockHeader& block, CBlockIndex*& best_header) EXCLUSIVE_LOCKS_REQUIRED(cs_main); | |||||||||||||||||||||||||||||||
373 | /** Create a new block index entry for a given block hash */ | |||||||||||||||||||||||||||||||
374 | CBlockIndex* InsertBlockIndex(const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main); | |||||||||||||||||||||||||||||||
375 | ||||||||||||||||||||||||||||||||
376 | //! Mark one block file as pruned (modify associated database entries) | |||||||||||||||||||||||||||||||
377 | void PruneOneBlockFile(int fileNumber) EXCLUSIVE_LOCKS_REQUIRED(cs_main); | |||||||||||||||||||||||||||||||
378 | ||||||||||||||||||||||||||||||||
379 | CBlockIndex* LookupBlockIndex(const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main); | |||||||||||||||||||||||||||||||
380 | const CBlockIndex* LookupBlockIndex(const uint256& hash) const EXCLUSIVE_LOCKS_REQUIRED(cs_main); | |||||||||||||||||||||||||||||||
381 | ||||||||||||||||||||||||||||||||
382 | /** Get block file info entry for one block file */ | |||||||||||||||||||||||||||||||
383 | CBlockFileInfo* GetBlockFileInfo(size_t n) EXCLUSIVE_LOCKS_REQUIRED(::cs_main); | |||||||||||||||||||||||||||||||
384 | ||||||||||||||||||||||||||||||||
385 | bool WriteBlockUndo(const CBlockUndo& blockundo, BlockValidationState& state, CBlockIndex& block) | |||||||||||||||||||||||||||||||
386 | EXCLUSIVE_LOCKS_REQUIRED(::cs_main); | |||||||||||||||||||||||||||||||
387 | ||||||||||||||||||||||||||||||||
388 | /** Store block on disk and update block file statistics. | |||||||||||||||||||||||||||||||
389 | * | |||||||||||||||||||||||||||||||
390 | * @param[in] block the block to be stored | |||||||||||||||||||||||||||||||
391 | * @param[in] nHeight the height of the block | |||||||||||||||||||||||||||||||
392 | * | |||||||||||||||||||||||||||||||
393 | * @returns in case of success, the position to which the block was written to | |||||||||||||||||||||||||||||||
394 | * in case of an error, an empty FlatFilePos | |||||||||||||||||||||||||||||||
395 | */ | |||||||||||||||||||||||||||||||
396 | FlatFilePos WriteBlock(const CBlock& block, int nHeight) EXCLUSIVE_LOCKS_REQUIRED(::cs_main); | |||||||||||||||||||||||||||||||
397 | ||||||||||||||||||||||||||||||||
398 | /** Update blockfile info while processing a block during reindex. The block must be available on disk. | |||||||||||||||||||||||||||||||
399 | * | |||||||||||||||||||||||||||||||
400 | * @param[in] block the block being processed | |||||||||||||||||||||||||||||||
401 | * @param[in] nHeight the height of the block | |||||||||||||||||||||||||||||||
402 | * @param[in] pos the position of the serialized CBlock on disk | |||||||||||||||||||||||||||||||
403 | */ | |||||||||||||||||||||||||||||||
404 | void UpdateBlockInfo(const CBlock& block, unsigned int nHeight, const FlatFilePos& pos) EXCLUSIVE_LOCKS_REQUIRED(::cs_main); | |||||||||||||||||||||||||||||||
405 | ||||||||||||||||||||||||||||||||
406 | /** Whether running in -prune mode. */ | |||||||||||||||||||||||||||||||
407 | 2.55M | [[nodiscard]] bool IsPruneMode() const { return m_prune_mode; } | ||||||||||||||||||||||||||||||
408 | ||||||||||||||||||||||||||||||||
409 | /** Attempt to stay below this number of bytes of block files. */ | |||||||||||||||||||||||||||||||
410 | 54 | [[nodiscard]] uint64_t GetPruneTarget() const { return m_opts.prune_target; } | ||||||||||||||||||||||||||||||
411 | static constexpr auto PRUNE_TARGET_MANUAL{std::numeric_limits<uint64_t>::max()}; | |||||||||||||||||||||||||||||||
412 | ||||||||||||||||||||||||||||||||
413 | 494k | [[nodiscard]] bool LoadingBlocks() const { return m_importing || !m_blockfiles_indexed; } | ||||||||||||||||||||||||||||||
414 | ||||||||||||||||||||||||||||||||
415 | /** Calculate the amount of disk space the block & undo files currently use */ | |||||||||||||||||||||||||||||||
416 | uint64_t CalculateCurrentUsage() EXCLUSIVE_LOCKS_REQUIRED(::cs_main); | |||||||||||||||||||||||||||||||
417 | ||||||||||||||||||||||||||||||||
418 | //! Check if all blocks in the [upper_block, lower_block] range have data available as | |||||||||||||||||||||||||||||||
419 | //! defined by the status mask. | |||||||||||||||||||||||||||||||
420 | //! The caller is responsible for ensuring that lower_block is an ancestor of upper_block | |||||||||||||||||||||||||||||||
421 | //! (part of the same chain). | |||||||||||||||||||||||||||||||
422 | bool CheckBlockDataAvailability(const CBlockIndex& upper_block, const CBlockIndex& lower_block, BlockStatus block_status = BLOCK_HAVE_DATA) EXCLUSIVE_LOCKS_REQUIRED(::cs_main); | |||||||||||||||||||||||||||||||
423 | ||||||||||||||||||||||||||||||||
424 | /** | |||||||||||||||||||||||||||||||
425 | * @brief Returns the earliest block with specified `status_mask` flags set after | |||||||||||||||||||||||||||||||
426 | * the latest block _not_ having those flags. | |||||||||||||||||||||||||||||||
427 | * | |||||||||||||||||||||||||||||||
428 | * This function starts from `upper_block`, which must have all | |||||||||||||||||||||||||||||||
429 | * `status_mask` flags set, and iterates backwards through its ancestors. It | |||||||||||||||||||||||||||||||
430 | * continues as long as each block has all `status_mask` flags set, until | |||||||||||||||||||||||||||||||
431 | * reaching the oldest ancestor or `lower_block`. | |||||||||||||||||||||||||||||||
432 | * | |||||||||||||||||||||||||||||||
433 | * @pre `upper_block` must have all `status_mask` flags set. | |||||||||||||||||||||||||||||||
434 | * @pre `lower_block` must be null or an ancestor of `upper_block` | |||||||||||||||||||||||||||||||
435 | * | |||||||||||||||||||||||||||||||
436 | * @param upper_block The starting block for the search, which must have all | |||||||||||||||||||||||||||||||
437 | * `status_mask` flags set. | |||||||||||||||||||||||||||||||
438 | * @param status_mask Bitmask specifying required status flags. | |||||||||||||||||||||||||||||||
439 | * @param lower_block The earliest possible block to return. If null, the | |||||||||||||||||||||||||||||||
440 | * search can extend to the genesis block. | |||||||||||||||||||||||||||||||
441 | * | |||||||||||||||||||||||||||||||
442 | * @return A reference to the earliest block between `upper_block` | |||||||||||||||||||||||||||||||
443 | * and `lower_block`, inclusive, such that every block between the | |||||||||||||||||||||||||||||||
444 | * returned block and `upper_block` has `status_mask` flags set. | |||||||||||||||||||||||||||||||
445 | */ | |||||||||||||||||||||||||||||||
446 | const CBlockIndex& GetFirstBlock( | |||||||||||||||||||||||||||||||
447 | const CBlockIndex& upper_block LIFETIMEBOUND, | |||||||||||||||||||||||||||||||
448 | uint32_t status_mask, | |||||||||||||||||||||||||||||||
449 | const CBlockIndex* lower_block LIFETIMEBOUND = nullptr | |||||||||||||||||||||||||||||||
450 | ) const EXCLUSIVE_LOCKS_REQUIRED(::cs_main); | |||||||||||||||||||||||||||||||
451 | ||||||||||||||||||||||||||||||||
452 | /** True if any block files have ever been pruned. */ | |||||||||||||||||||||||||||||||
453 | bool m_have_pruned = false; | |||||||||||||||||||||||||||||||
454 | ||||||||||||||||||||||||||||||||
455 | //! Check whether the block associated with this index entry is pruned or not. | |||||||||||||||||||||||||||||||
456 | bool IsBlockPruned(const CBlockIndex& block) const EXCLUSIVE_LOCKS_REQUIRED(::cs_main); | |||||||||||||||||||||||||||||||
457 | ||||||||||||||||||||||||||||||||
458 | //! Create or update a prune lock identified by its name | |||||||||||||||||||||||||||||||
459 | void UpdatePruneLock(const std::string& name, const PruneLockInfo& lock_info) EXCLUSIVE_LOCKS_REQUIRED(::cs_main); | |||||||||||||||||||||||||||||||
460 | ||||||||||||||||||||||||||||||||
461 | //! Delete a prune lock identified by its name. Returns true if the lock existed. | |||||||||||||||||||||||||||||||
462 | bool DeletePruneLock(const std::string& name) EXCLUSIVE_LOCKS_REQUIRED(::cs_main); | |||||||||||||||||||||||||||||||
463 | ||||||||||||||||||||||||||||||||
464 | /** Open a block file (blk?????.dat) */ | |||||||||||||||||||||||||||||||
465 | AutoFile OpenBlockFile(const FlatFilePos& pos, bool fReadOnly) const; | |||||||||||||||||||||||||||||||
466 | ||||||||||||||||||||||||||||||||
467 | /** Translation to a filesystem path */ | |||||||||||||||||||||||||||||||
468 | fs::path GetBlockPosFilename(const FlatFilePos& pos) const; | |||||||||||||||||||||||||||||||
469 | ||||||||||||||||||||||||||||||||
470 | /** | |||||||||||||||||||||||||||||||
471 | * Actually unlink the specified files | |||||||||||||||||||||||||||||||
472 | */ | |||||||||||||||||||||||||||||||
473 | void UnlinkPrunedFiles(const std::set<int>& setFilesToPrune) const; | |||||||||||||||||||||||||||||||
474 | ||||||||||||||||||||||||||||||||
475 | /** Functions for disk access for blocks */ | |||||||||||||||||||||||||||||||
476 | bool ReadBlock(CBlock& block, const FlatFilePos& pos, const std::optional<uint256>& expected_hash) const; | |||||||||||||||||||||||||||||||
477 | bool ReadBlock(CBlock& block, const CBlockIndex& index) const; | |||||||||||||||||||||||||||||||
478 | ReadRawBlockResult ReadRawBlock(const FlatFilePos& pos, std::optional<std::pair<size_t, size_t>> block_part = std::nullopt) const; | |||||||||||||||||||||||||||||||
479 | ||||||||||||||||||||||||||||||||
480 | bool ReadBlockUndo(CBlockUndo& blockundo, const CBlockIndex& index) const; | |||||||||||||||||||||||||||||||
481 | ||||||||||||||||||||||||||||||||
482 | void CleanupBlockRevFiles() const; | |||||||||||||||||||||||||||||||
483 | }; | |||||||||||||||||||||||||||||||
484 | ||||||||||||||||||||||||||||||||
485 | // Calls ActivateBestChain() even if no blocks are imported. | |||||||||||||||||||||||||||||||
486 | void ImportBlocks(ChainstateManager& chainman, std::span<const fs::path> import_paths); | |||||||||||||||||||||||||||||||
487 | } // namespace node | |||||||||||||||||||||||||||||||
488 | ||||||||||||||||||||||||||||||||
489 | #endif // BITCOIN_NODE_BLOCKSTORAGE_H |