Coverage Report

Created: 2026-06-16 16:41

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/tmp/bitcoin/src/node/blockstorage.h
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
2.40k
    {
72
2.40k
        READWRITE(VARINT(obj.nBlocks));
73
2.40k
        READWRITE(VARINT(obj.nSize));
74
2.40k
        READWRITE(VARINT(obj.nUndoSize));
75
2.40k
        READWRITE(VARINT(obj.nHeightFirst));
76
2.40k
        READWRITE(VARINT(obj.nHeightLast));
77
2.40k
        READWRITE(VARINT(obj.nTimeFirst));
78
2.40k
        READWRITE(VARINT(obj.nTimeLast));
79
2.40k
    }
void kernel::CBlockFileInfo::SerializationOps<SpanReader, kernel::CBlockFileInfo, ActionUnserialize>(kernel::CBlockFileInfo&, SpanReader&, ActionUnserialize)
Line
Count
Source
71
760
    {
72
760
        READWRITE(VARINT(obj.nBlocks));
73
760
        READWRITE(VARINT(obj.nSize));
74
760
        READWRITE(VARINT(obj.nUndoSize));
75
760
        READWRITE(VARINT(obj.nHeightFirst));
76
760
        READWRITE(VARINT(obj.nHeightLast));
77
760
        READWRITE(VARINT(obj.nTimeFirst));
78
760
        READWRITE(VARINT(obj.nTimeLast));
79
760
    }
void kernel::CBlockFileInfo::SerializationOps<DataStream, kernel::CBlockFileInfo const, ActionSerialize>(kernel::CBlockFileInfo const&, DataStream&, ActionSerialize)
Line
Count
Source
71
1.64k
    {
72
1.64k
        READWRITE(VARINT(obj.nBlocks));
73
1.64k
        READWRITE(VARINT(obj.nSize));
74
1.64k
        READWRITE(VARINT(obj.nUndoSize));
75
1.64k
        READWRITE(VARINT(obj.nHeightFirst));
76
1.64k
        READWRITE(VARINT(obj.nHeightLast));
77
1.64k
        READWRITE(VARINT(obj.nTimeFirst));
78
1.64k
        READWRITE(VARINT(obj.nTimeLast));
79
1.64k
    }
80
81
2.46k
    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
107k
    {
88
107k
        if (nBlocks == 0 || nHeightFirst > nHeightIn)
89
517
            nHeightFirst = nHeightIn;
90
107k
        if (nBlocks == 0 || nTimeFirst > nTimeIn)
91
510
            nTimeFirst = nTimeIn;
92
107k
        nBlocks++;
93
107k
        if (nHeightIn > nHeightLast)
94
91.7k
            nHeightLast = nHeightIn;
95
107k
        if (nTimeIn > nTimeLast)
96
33.0k
            nTimeLast = nTimeIn;
97
107k
    }
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
365k
    const CChainParams& GetParams() const { return m_opts.chainparams; }
202
255k
    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
4.69k
    {
277
4.69k
        AssertLockHeld(::cs_main);
278
4.69k
        static const BlockfileCursor empty_cursor;
279
4.69k
        const auto& normal = m_blockfile_cursors[BlockfileType::NORMAL].value_or(empty_cursor);
280
4.69k
        const auto& assumed = m_blockfile_cursors[BlockfileType::ASSUMED].value_or(empty_cursor);
281
4.69k
        return std::max(normal.file_num, assumed.file_num);
282
4.69k
    }
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
     * Pruned nodes may have entries where B is missing data.
356
     */
357
    std::multimap<CBlockIndex*, CBlockIndex*> m_blocks_unlinked;
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
420k
    [[nodiscard]] bool IsPruneMode() const { return m_prune_mode; }
408
409
    /** Attempt to stay below this number of bytes of block files. */
410
2.60k
    [[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
93.1k
    [[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