Line data Source code
1 : // Copyright (c) 2011-2021 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 <chainparams.h> 11 : #include <fs.h> 12 : #include <kernel/blockmanager_opts.h> 13 : #include <protocol.h> 14 : #include <sync.h> 15 : #include <txdb.h> 16 : 17 : #include <cstdint> 18 : #include <optional> 19 : #include <unordered_map> 20 : #include <vector> 21 : 22 : extern RecursiveMutex cs_main; // NOLINT(readability-redundant-declaration) 23 : 24 : class ArgsManager; 25 : class BlockValidationState; 26 : class CBlock; 27 : class CBlockUndo; 28 : class CChain; 29 : class CChainParams; 30 : class CChainState; 31 : class ChainstateManager; 32 : struct CCheckpointData; 33 : struct FlatFilePos; 34 : namespace Consensus { 35 : struct Params; 36 : } 37 : 38 : namespace node { 39 : static constexpr bool DEFAULT_STOPAFTERBLOCKIMPORT{false}; 40 : 41 : /** The pre-allocation chunk size for blk?????.dat files (since 0.8) */ 42 : static const unsigned int BLOCKFILE_CHUNK_SIZE = 0x1000000; // 16 MiB 43 : /** The pre-allocation chunk size for rev?????.dat files (since 0.8) */ 44 : static const unsigned int UNDOFILE_CHUNK_SIZE = 0x100000; // 1 MiB 45 : /** The maximum size of a blk?????.dat file (since 0.8) */ 46 : static const unsigned int MAX_BLOCKFILE_SIZE = 0x8000000; // 128 MiB 47 : 48 : /** Size of header written by WriteBlockToDisk before a serialized CBlock */ 49 : static constexpr size_t BLOCK_SERIALIZATION_HEADER_SIZE = CMessageHeader::MESSAGE_START_SIZE + sizeof(unsigned int); 50 : 51 : extern std::atomic_bool fImporting; 52 : extern std::atomic_bool fReindex; 53 : /** Pruning-related variables and constants */ 54 : /** True if we're running in -prune mode. */ 55 : extern bool fPruneMode; 56 : /** Number of bytes of block files that we're trying to stay below. */ 57 : extern uint64_t nPruneTarget; 58 : 59 : // Because validation code takes pointers to the map's CBlockIndex objects, if 60 : // we ever switch to another associative container, we need to either use a 61 : // container that has stable addressing (true of all std associative 62 : // containers), or make the key a `std::unique_ptr<CBlockIndex>` 63 : using BlockMap = std::unordered_map<uint256, CBlockIndex, BlockHasher>; 64 : using PrevBlockMap = std::unordered_multimap<uint256, CBlockIndex*, BlockHasher>; 65 : 66 : struct CBlockIndexWorkComparator { 67 : bool operator()(const CBlockIndex* pa, const CBlockIndex* pb) const; 68 : }; 69 : 70 : struct CBlockIndexHeightOnlyComparator { 71 : /* Only compares the height of two block indices, doesn't try to tie-break */ 72 : bool operator()(const CBlockIndex* pa, const CBlockIndex* pb) const; 73 : }; 74 : 75 26 : struct PruneLockInfo { 76 26 : int height_first{std::numeric_limits<int>::max()}; //! Height of earliest block that should be kept and not pruned 77 : }; 78 : 79 : /** 80 : * Maintains a tree of blocks (stored in `m_block_index`) which is consulted 81 : * to determine where the most-work tip is. 82 : * 83 : * This data is used mostly in `CChainState` - information about, e.g., 84 : * candidate tips is not maintained here. 85 : */ 86 : class BlockManager 87 : { 88 : friend CChainState; 89 : friend ChainstateManager; 90 : 91 : private: 92 : const kernel::BlockManagerOpts m_opts; 93 : 94 49195 : const CChainParams& GetParams() const { return m_opts.chainparams; } 95 180 : const Consensus::Params& GetConsensus() const { return m_opts.chainparams.GetConsensus(); } 96 : /** 97 : * Load the blocktree off disk and into memory. Populate certain metadata 98 : * per index entry (nStatus, nChainWork, nTimeMax, etc.) as well as peripheral 99 : * collections like m_dirty_blockindex. 100 : */ 101 : bool LoadBlockIndex() 102 : EXCLUSIVE_LOCKS_REQUIRED(cs_main); 103 : void FlushBlockFile(bool fFinalize = false, bool finalize_undo = false); 104 : void FlushUndoFile(int block_file, bool finalize = false); 105 : bool FindBlockPos(FlatFilePos& pos, unsigned int nAddSize, unsigned int nHeight, CChain& active_chain, uint64_t nTime, bool fKnown); 106 : bool FindUndoPos(BlockValidationState& state, int nFile, FlatFilePos& pos, unsigned int nAddSize); 107 : 108 : /* Calculate the block/rev files to delete based on height specified by user with RPC command pruneblockchain */ 109 : void FindFilesToPruneManual(std::set<int>& setFilesToPrune, int nManualPruneHeight, int chain_tip_height); 110 : 111 : /** 112 : * Prune block and undo files (blk???.dat and rev???.dat) so that the disk space used is less than a user-defined target. 113 : * The user sets the target (in MB) on the command line or in config file. This will be run on startup and whenever new 114 : * space is allocated in a block or undo file, staying below the target. Changing back to unpruned requires a reindex 115 : * (which in this case means the blockchain must be re-downloaded.) 116 : * 117 : * Pruning functions are called from FlushStateToDisk when the m_check_for_pruning flag has been set. 118 : * Block and undo files are deleted in lock-step (when blk00003.dat is deleted, so is rev00003.dat.) 119 : * Pruning cannot take place until the longest chain is at least a certain length (CChainParams::nPruneAfterHeight). 120 : * Pruning will never delete a block within a defined distance (currently 288) from the active chain's tip. 121 : * The block index is updated by unsetting HAVE_DATA and HAVE_UNDO for any blocks that were stored in the deleted files. 122 : * A db flag records the fact that at least some block files have been pruned. 123 : * 124 : * @param[out] setFilesToPrune The set of file indices that can be unlinked will be returned 125 : */ 126 : void FindFilesToPrune(std::set<int>& setFilesToPrune, uint64_t nPruneAfterHeight, int chain_tip_height, int prune_height, bool is_ibd); 127 : 128 : RecursiveMutex cs_LastBlockFile; 129 : std::vector<CBlockFileInfo> m_blockfile_info; 130 185 : int m_last_blockfile = 0; 131 : /** Global flag to indicate we should check to see if there are 132 : * block/undo files that should be deleted. Set on startup 133 : * or if we allocate more file space when we're in prune mode 134 : */ 135 185 : bool m_check_for_pruning = false; 136 : 137 : /** Dirty block index entries. */ 138 : std::set<CBlockIndex*> m_dirty_blockindex; 139 : 140 : /** Dirty block file entries. */ 141 : std::set<int> m_dirty_fileinfo; 142 : 143 : /** 144 : * Map from external index name to oldest block that must not be pruned. 145 : * 146 : * @note Internally, only blocks at height (height_first - PRUNE_LOCK_BUFFER - 1) and 147 : * below will be pruned, but callers should avoid assuming any particular buffer size. 148 : */ 149 : std::unordered_map<std::string, PruneLockInfo> m_prune_locks GUARDED_BY(::cs_main); 150 : 151 : public: 152 : using Options = kernel::BlockManagerOpts; 153 : 154 740 : explicit BlockManager(Options opts) : m_opts{opts} {} 155 : 156 : BlockMap m_block_index GUARDED_BY(cs_main); 157 : PrevBlockMap m_prev_block_index GUARDED_BY(cs_main); 158 : 159 : std::vector<CBlockIndex*> GetAllBlockIndices() EXCLUSIVE_LOCKS_REQUIRED(::cs_main); 160 : 161 : /** 162 : * All pairs A->B, where A (or one of its ancestors) misses transactions, but B has transactions. 163 : * Pruned nodes may have entries where B is missing data. 164 : */ 165 : std::multimap<CBlockIndex*, CBlockIndex*> m_blocks_unlinked; 166 : 167 : std::unique_ptr<CBlockTreeDB> m_block_tree_db GUARDED_BY(::cs_main); 168 : 169 : bool WriteBlockIndexDB() EXCLUSIVE_LOCKS_REQUIRED(::cs_main); 170 : bool LoadBlockIndexDB() EXCLUSIVE_LOCKS_REQUIRED(::cs_main); 171 : 172 : CBlockIndex* AddToBlockIndex(const CBlockHeader& block, const uint256& hash, CBlockIndex*& best_header, 173 : enum BlockStatus nStatus = BLOCK_VALID_TREE) 174 : EXCLUSIVE_LOCKS_REQUIRED(cs_main); 175 : /** Create a new block index entry for a given block hash */ 176 : CBlockIndex* InsertBlockIndex(const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main); 177 : 178 : //! Mark one block file as pruned (modify associated database entries) 179 : void PruneOneBlockFile(const int fileNumber) EXCLUSIVE_LOCKS_REQUIRED(cs_main); 180 : 181 : CBlockIndex* LookupBlockIndex(const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main); 182 : const CBlockIndex* LookupBlockIndex(const uint256& hash) const EXCLUSIVE_LOCKS_REQUIRED(cs_main); 183 : 184 : /** Get block file info entry for one block file */ 185 : CBlockFileInfo* GetBlockFileInfo(size_t n); 186 : 187 : bool WriteUndoDataForBlock(const CBlockUndo& blockundo, BlockValidationState& state, CBlockIndex& block) 188 : EXCLUSIVE_LOCKS_REQUIRED(::cs_main); 189 : 190 : /** Store block on disk. If dbp is not nullptr, then it provides the known position of the block within a block file on disk. */ 191 : FlatFilePos SaveBlockToDisk(const CBlock& block, int nHeight, CChain& active_chain, const FlatFilePos* dbp); 192 : 193 : /** Calculate the amount of disk space the block & undo files currently use */ 194 : uint64_t CalculateCurrentUsage(); 195 : 196 : //! Returns last CBlockIndex* that is a checkpoint 197 : const CBlockIndex* GetLastCheckpoint(const CCheckpointData& data) EXCLUSIVE_LOCKS_REQUIRED(cs_main); 198 : 199 : //! Find the first block that is not pruned 200 : const CBlockIndex* GetFirstStoredBlock(const CBlockIndex& start_block LIFETIMEBOUND) EXCLUSIVE_LOCKS_REQUIRED(::cs_main); 201 : 202 : /** True if any block files have ever been pruned. */ 203 185 : bool m_have_pruned = false; 204 : 205 : //! Check whether the block associated with this index entry is pruned or not. 206 : bool IsBlockPruned(const CBlockIndex* pblockindex) EXCLUSIVE_LOCKS_REQUIRED(::cs_main); 207 : 208 : //! Create or update a prune lock identified by its name 209 : void UpdatePruneLock(const std::string& name, const PruneLockInfo& lock_info) EXCLUSIVE_LOCKS_REQUIRED(::cs_main); 210 : }; 211 : 212 : void CleanupBlockRevFiles(); 213 : 214 : /** Open a block file (blk?????.dat) */ 215 : FILE* OpenBlockFile(const FlatFilePos& pos, bool fReadOnly = false); 216 : /** Translation to a filesystem path */ 217 : fs::path GetBlockPosFilename(const FlatFilePos& pos); 218 : 219 : /** 220 : * Actually unlink the specified files 221 : */ 222 : void UnlinkPrunedFiles(const std::set<int>& setFilesToPrune); 223 : 224 : /** Functions for disk access for blocks */ 225 : std::optional<uint256> ReadBlockFromDisk(CBlock& block, const FlatFilePos& pos, const Consensus::Params& consensusParams); 226 : bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex, const Consensus::Params& consensusParams); 227 : 228 : bool UndoReadFromDisk(CBlockUndo& blockundo, const CBlockIndex* pindex); 229 : 230 : void ThreadImport(ChainstateManager& chainman, std::vector<fs::path> vImportFiles, const ArgsManager& args); 231 : } // namespace node 232 : 233 : #endif // BITCOIN_NODE_BLOCKSTORAGE_H