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 {
72 READWRITE(VARINT(obj.nBlocks));
73 READWRITE(VARINT(obj.nSize));
74 READWRITE(VARINT(obj.nUndoSize));
75 READWRITE(VARINT(obj.nHeightFirst));
76 READWRITE(VARINT(obj.nHeightLast));
77 READWRITE(VARINT(obj.nTimeFirst));
78 READWRITE(VARINT(obj.nTimeLast));
79 }
80 81 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 {
88 if (nBlocks == 0 || nHeightFirst > nHeightIn)
89 nHeightFirst = nHeightIn;
90 if (nBlocks == 0 || nTimeFirst > nTimeIn)
91 nTimeFirst = nTimeIn;
92 nBlocks++;
93 if (nHeightIn > nHeightLast)
94 nHeightLast = nHeightIn;
95 if (nTimeIn > nTimeLast)
96 nTimeLast = nTimeIn;
97 }
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 const CChainParams& GetParams() const { return m_opts.chainparams; }
202 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 {
277 AssertLockHeld(::cs_main);
278 static const BlockfileCursor empty_cursor;
279 const auto& normal = m_blockfile_cursors[BlockfileType::NORMAL].value_or(empty_cursor);
280 const auto& assumed = m_blockfile_cursors[BlockfileType::ASSUMED].value_or(empty_cursor);
281 return std::max(normal.file_num, assumed.file_num);
282 }
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 [[nodiscard]] bool IsPruneMode() const { return m_prune_mode; }
408 409 /** Attempt to stay below this number of bytes of block files. */
410 [[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 [[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
490