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