2022-12-24 23:49:50 +00:00
|
|
|
// Copyright (c) 2011-2022 The Bitcoin Core developers
|
2021-04-02 19:17:00 +02:00
|
|
|
// Distributed under the MIT software license, see the accompanying
|
|
|
|
// file COPYING or http://www.opensource.org/licenses/mit-license.php.
|
|
|
|
|
|
|
|
#ifndef BITCOIN_NODE_BLOCKSTORAGE_H
|
|
|
|
#define BITCOIN_NODE_BLOCKSTORAGE_H
|
|
|
|
|
2022-05-03 22:20:06 +02:00
|
|
|
#include <attributes.h>
|
2021-01-08 18:56:48 -05:00
|
|
|
#include <chain.h>
|
2021-04-02 19:17:00 +02:00
|
|
|
#include <fs.h>
|
2022-09-15 10:45:07 +01:00
|
|
|
#include <kernel/cs_main.h>
|
2022-05-03 22:20:06 +02:00
|
|
|
#include <protocol.h>
|
2021-10-21 16:56:34 +02:00
|
|
|
#include <sync.h>
|
2022-01-02 17:05:43 +01:00
|
|
|
#include <txdb.h>
|
2021-04-02 19:17:00 +02:00
|
|
|
|
2021-06-14 20:17:39 +02:00
|
|
|
#include <atomic>
|
|
|
|
#include <cstdint>
|
2021-05-13 19:13:08 +02:00
|
|
|
#include <unordered_map>
|
2021-06-14 20:17:39 +02:00
|
|
|
#include <vector>
|
|
|
|
|
2021-04-02 19:17:00 +02:00
|
|
|
class ArgsManager;
|
2021-04-18 17:09:48 +02:00
|
|
|
class BlockValidationState;
|
2021-04-02 20:42:05 +02:00
|
|
|
class CBlock;
|
2021-04-18 17:09:48 +02:00
|
|
|
class CBlockFileInfo;
|
2021-04-02 20:42:05 +02:00
|
|
|
class CBlockUndo;
|
|
|
|
class CChain;
|
|
|
|
class CChainParams;
|
2022-03-09 12:37:19 -05:00
|
|
|
class Chainstate;
|
2021-04-02 19:17:00 +02:00
|
|
|
class ChainstateManager;
|
2022-01-02 17:05:43 +01:00
|
|
|
struct CCheckpointData;
|
2021-04-02 20:42:05 +02:00
|
|
|
struct FlatFilePos;
|
|
|
|
namespace Consensus {
|
|
|
|
struct Params;
|
|
|
|
}
|
2021-04-02 19:17:00 +02:00
|
|
|
|
2021-11-12 10:06:00 -05:00
|
|
|
namespace node {
|
2021-04-02 19:17:00 +02:00
|
|
|
static constexpr bool DEFAULT_STOPAFTERBLOCKIMPORT{false};
|
|
|
|
|
2021-04-18 16:31:53 +02:00
|
|
|
/** The pre-allocation chunk size for blk?????.dat files (since 0.8) */
|
|
|
|
static const unsigned int BLOCKFILE_CHUNK_SIZE = 0x1000000; // 16 MiB
|
|
|
|
/** The pre-allocation chunk size for rev?????.dat files (since 0.8) */
|
|
|
|
static const unsigned int UNDOFILE_CHUNK_SIZE = 0x100000; // 1 MiB
|
|
|
|
/** The maximum size of a blk?????.dat file (since 0.8) */
|
|
|
|
static const unsigned int MAX_BLOCKFILE_SIZE = 0x8000000; // 128 MiB
|
|
|
|
|
2022-04-14 18:44:34 -04:00
|
|
|
/** Size of header written by WriteBlockToDisk before a serialized CBlock */
|
|
|
|
static constexpr size_t BLOCK_SERIALIZATION_HEADER_SIZE = CMessageHeader::MESSAGE_START_SIZE + sizeof(unsigned int);
|
|
|
|
|
2021-04-18 09:46:01 +02:00
|
|
|
extern std::atomic_bool fImporting;
|
|
|
|
extern std::atomic_bool fReindex;
|
|
|
|
/** Pruning-related variables and constants */
|
|
|
|
/** True if we're running in -prune mode. */
|
|
|
|
extern bool fPruneMode;
|
2019-04-23 20:59:02 +02:00
|
|
|
/** Number of bytes of block files that we're trying to stay below. */
|
2021-04-18 09:46:01 +02:00
|
|
|
extern uint64_t nPruneTarget;
|
|
|
|
|
2021-01-08 18:56:48 -05:00
|
|
|
// Because validation code takes pointers to the map's CBlockIndex objects, if
|
|
|
|
// we ever switch to another associative container, we need to either use a
|
|
|
|
// container that has stable addressing (true of all std associative
|
|
|
|
// containers), or make the key a `std::unique_ptr<CBlockIndex>`
|
2022-01-13 12:38:23 -05:00
|
|
|
using BlockMap = std::unordered_map<uint256, CBlockIndex, BlockHasher>;
|
2022-01-02 17:05:43 +01:00
|
|
|
|
2022-01-02 16:59:07 +01:00
|
|
|
struct CBlockIndexWorkComparator {
|
|
|
|
bool operator()(const CBlockIndex* pa, const CBlockIndex* pb) const;
|
2022-01-02 17:05:43 +01:00
|
|
|
};
|
|
|
|
|
2022-03-15 19:19:58 -04:00
|
|
|
struct CBlockIndexHeightOnlyComparator {
|
|
|
|
/* Only compares the height of two block indices, doesn't try to tie-break */
|
|
|
|
bool operator()(const CBlockIndex* pa, const CBlockIndex* pb) const;
|
|
|
|
};
|
|
|
|
|
2021-05-13 19:13:08 +02:00
|
|
|
struct PruneLockInfo {
|
|
|
|
int height_first{std::numeric_limits<int>::max()}; //! Height of earliest block that should be kept and not pruned
|
|
|
|
};
|
|
|
|
|
2022-01-02 17:05:43 +01:00
|
|
|
/**
|
|
|
|
* Maintains a tree of blocks (stored in `m_block_index`) which is consulted
|
|
|
|
* to determine where the most-work tip is.
|
|
|
|
*
|
2022-03-09 12:37:19 -05:00
|
|
|
* This data is used mostly in `Chainstate` - information about, e.g.,
|
2022-01-02 17:05:43 +01:00
|
|
|
* candidate tips is not maintained here.
|
|
|
|
*/
|
|
|
|
class BlockManager
|
|
|
|
{
|
2022-03-09 12:37:19 -05:00
|
|
|
friend Chainstate;
|
2022-01-04 15:00:34 +01:00
|
|
|
friend ChainstateManager;
|
2022-01-02 17:05:43 +01:00
|
|
|
|
|
|
|
private:
|
2022-04-19 11:59:09 +02:00
|
|
|
/**
|
|
|
|
* Load the blocktree off disk and into memory. Populate certain metadata
|
|
|
|
* per index entry (nStatus, nChainWork, nTimeMax, etc.) as well as peripheral
|
|
|
|
* collections like m_dirty_blockindex.
|
|
|
|
*/
|
|
|
|
bool LoadBlockIndex(const Consensus::Params& consensus_params)
|
|
|
|
EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
2022-01-04 14:04:30 +01:00
|
|
|
void FlushBlockFile(bool fFinalize = false, bool finalize_undo = false);
|
|
|
|
void FlushUndoFile(int block_file, bool finalize = false);
|
|
|
|
bool FindBlockPos(FlatFilePos& pos, unsigned int nAddSize, unsigned int nHeight, CChain& active_chain, uint64_t nTime, bool fKnown);
|
|
|
|
bool FindUndoPos(BlockValidationState& state, int nFile, FlatFilePos& pos, unsigned int nAddSize);
|
|
|
|
|
2022-01-02 17:05:43 +01:00
|
|
|
/* Calculate the block/rev files to delete based on height specified by user with RPC command pruneblockchain */
|
|
|
|
void FindFilesToPruneManual(std::set<int>& setFilesToPrune, int nManualPruneHeight, int chain_tip_height);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Prune block and undo files (blk???.dat and rev???.dat) so that the disk space used is less than a user-defined target.
|
|
|
|
* The user sets the target (in MB) on the command line or in config file. This will be run on startup and whenever new
|
|
|
|
* space is allocated in a block or undo file, staying below the target. Changing back to unpruned requires a reindex
|
|
|
|
* (which in this case means the blockchain must be re-downloaded.)
|
|
|
|
*
|
2022-01-05 15:44:16 +01:00
|
|
|
* Pruning functions are called from FlushStateToDisk when the m_check_for_pruning flag has been set.
|
2022-01-02 17:05:43 +01:00
|
|
|
* Block and undo files are deleted in lock-step (when blk00003.dat is deleted, so is rev00003.dat.)
|
2022-01-05 16:26:39 +01:00
|
|
|
* Pruning cannot take place until the longest chain is at least a certain length (CChainParams::nPruneAfterHeight).
|
2022-01-02 17:05:43 +01:00
|
|
|
* Pruning will never delete a block within a defined distance (currently 288) from the active chain's tip.
|
|
|
|
* The block index is updated by unsetting HAVE_DATA and HAVE_UNDO for any blocks that were stored in the deleted files.
|
|
|
|
* A db flag records the fact that at least some block files have been pruned.
|
|
|
|
*
|
|
|
|
* @param[out] setFilesToPrune The set of file indices that can be unlinked will be returned
|
|
|
|
*/
|
|
|
|
void FindFilesToPrune(std::set<int>& setFilesToPrune, uint64_t nPruneAfterHeight, int chain_tip_height, int prune_height, bool is_ibd);
|
|
|
|
|
2022-01-04 15:00:34 +01:00
|
|
|
RecursiveMutex cs_LastBlockFile;
|
2022-01-05 15:44:16 +01:00
|
|
|
std::vector<CBlockFileInfo> m_blockfile_info;
|
|
|
|
int m_last_blockfile = 0;
|
2022-01-04 15:00:34 +01:00
|
|
|
/** Global flag to indicate we should check to see if there are
|
|
|
|
* block/undo files that should be deleted. Set on startup
|
|
|
|
* or if we allocate more file space when we're in prune mode
|
|
|
|
*/
|
2022-01-05 15:44:16 +01:00
|
|
|
bool m_check_for_pruning = false;
|
2022-01-04 15:00:34 +01:00
|
|
|
|
|
|
|
/** Dirty block index entries. */
|
2022-01-05 15:44:16 +01:00
|
|
|
std::set<CBlockIndex*> m_dirty_blockindex;
|
2022-01-04 15:00:34 +01:00
|
|
|
|
|
|
|
/** Dirty block file entries. */
|
2022-01-05 15:44:16 +01:00
|
|
|
std::set<int> m_dirty_fileinfo;
|
2022-01-04 15:00:34 +01:00
|
|
|
|
2021-05-13 19:13:08 +02:00
|
|
|
/**
|
|
|
|
* Map from external index name to oldest block that must not be pruned.
|
|
|
|
*
|
|
|
|
* @note Internally, only blocks at height (height_first - PRUNE_LOCK_BUFFER - 1) and
|
|
|
|
* below will be pruned, but callers should avoid assuming any particular buffer size.
|
|
|
|
*/
|
|
|
|
std::unordered_map<std::string, PruneLockInfo> m_prune_locks GUARDED_BY(::cs_main);
|
|
|
|
|
2022-01-02 17:05:43 +01:00
|
|
|
public:
|
|
|
|
BlockMap m_block_index GUARDED_BY(cs_main);
|
|
|
|
|
2022-03-15 19:28:46 -04:00
|
|
|
std::vector<CBlockIndex*> GetAllBlockIndices() EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
|
|
|
|
|
2022-01-02 17:05:43 +01:00
|
|
|
/**
|
|
|
|
* All pairs A->B, where A (or one of its ancestors) misses transactions, but B has transactions.
|
|
|
|
* Pruned nodes may have entries where B is missing data.
|
|
|
|
*/
|
|
|
|
std::multimap<CBlockIndex*, CBlockIndex*> m_blocks_unlinked;
|
|
|
|
|
|
|
|
std::unique_ptr<CBlockTreeDB> m_block_tree_db GUARDED_BY(::cs_main);
|
|
|
|
|
2022-01-05 15:06:56 +01:00
|
|
|
bool WriteBlockIndexDB() EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
|
2022-06-01 19:10:10 +00:00
|
|
|
bool LoadBlockIndexDB(const Consensus::Params& consensus_params) EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
|
2022-01-02 17:05:43 +01:00
|
|
|
|
2020-12-24 16:18:46 -05:00
|
|
|
CBlockIndex* AddToBlockIndex(const CBlockHeader& block, CBlockIndex*& best_header) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
2022-01-02 17:05:43 +01:00
|
|
|
/** Create a new block index entry for a given block hash */
|
|
|
|
CBlockIndex* InsertBlockIndex(const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
|
|
|
|
|
|
|
//! Mark one block file as pruned (modify associated database entries)
|
|
|
|
void PruneOneBlockFile(const int fileNumber) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
|
|
|
|
2021-01-08 18:56:48 -05:00
|
|
|
CBlockIndex* LookupBlockIndex(const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
|
|
|
const CBlockIndex* LookupBlockIndex(const uint256& hash) const EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
2022-01-02 17:05:43 +01:00
|
|
|
|
2022-01-04 14:04:30 +01:00
|
|
|
/** Get block file info entry for one block file */
|
|
|
|
CBlockFileInfo* GetBlockFileInfo(size_t n);
|
|
|
|
|
2021-10-21 16:56:34 +02:00
|
|
|
bool WriteUndoDataForBlock(const CBlockUndo& blockundo, BlockValidationState& state, CBlockIndex* pindex, const CChainParams& chainparams)
|
|
|
|
EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
|
2022-01-04 14:04:30 +01:00
|
|
|
|
2022-04-14 18:44:34 -04:00
|
|
|
/** Store block on disk. If dbp is not nullptr, then it provides the known position of the block within a block file on disk. */
|
2022-01-04 14:04:30 +01:00
|
|
|
FlatFilePos SaveBlockToDisk(const CBlock& block, int nHeight, CChain& active_chain, const CChainParams& chainparams, const FlatFilePos* dbp);
|
|
|
|
|
2023-01-03 13:03:43 +01:00
|
|
|
[[nodiscard]] bool LoadingBlocks() const
|
|
|
|
{
|
|
|
|
return fImporting || fReindex;
|
|
|
|
}
|
|
|
|
|
2022-01-04 14:04:30 +01:00
|
|
|
/** Calculate the amount of disk space the block & undo files currently use */
|
|
|
|
uint64_t CalculateCurrentUsage();
|
|
|
|
|
2022-01-02 17:05:43 +01:00
|
|
|
//! Returns last CBlockIndex* that is a checkpoint
|
2022-03-02 15:42:57 +10:00
|
|
|
const CBlockIndex* GetLastCheckpoint(const CCheckpointData& data) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
|
2022-01-02 17:05:43 +01:00
|
|
|
|
2022-04-27 12:21:22 +02:00
|
|
|
//! Find the first block that is not pruned
|
2022-05-03 22:20:06 +02:00
|
|
|
const CBlockIndex* GetFirstStoredBlock(const CBlockIndex& start_block LIFETIMEBOUND) EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
|
2022-04-27 12:21:22 +02:00
|
|
|
|
2020-12-24 20:06:34 -05:00
|
|
|
/** True if any block files have ever been pruned. */
|
2022-03-18 12:35:52 -04:00
|
|
|
bool m_have_pruned = false;
|
2020-12-24 20:06:34 -05:00
|
|
|
|
|
|
|
//! Check whether the block associated with this index entry is pruned or not.
|
|
|
|
bool IsBlockPruned(const CBlockIndex* pblockindex) EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
|
|
|
|
|
2021-05-13 19:13:08 +02:00
|
|
|
//! Create or update a prune lock identified by its name
|
|
|
|
void UpdatePruneLock(const std::string& name, const PruneLockInfo& lock_info) EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
|
2022-01-02 17:05:43 +01:00
|
|
|
};
|
|
|
|
|
2021-04-18 09:46:01 +02:00
|
|
|
void CleanupBlockRevFiles();
|
|
|
|
|
2021-04-18 17:09:48 +02:00
|
|
|
/** Open a block file (blk?????.dat) */
|
2021-04-19 08:45:35 +02:00
|
|
|
FILE* OpenBlockFile(const FlatFilePos& pos, bool fReadOnly = false);
|
2021-04-18 17:09:48 +02:00
|
|
|
/** Translation to a filesystem path */
|
2021-04-19 08:45:35 +02:00
|
|
|
fs::path GetBlockPosFilename(const FlatFilePos& pos);
|
2021-04-18 17:09:48 +02:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Actually unlink the specified files
|
|
|
|
*/
|
|
|
|
void UnlinkPrunedFiles(const std::set<int>& setFilesToPrune);
|
|
|
|
|
2021-04-02 20:42:05 +02:00
|
|
|
/** Functions for disk access for blocks */
|
|
|
|
bool ReadBlockFromDisk(CBlock& block, const FlatFilePos& pos, const Consensus::Params& consensusParams);
|
|
|
|
bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex, const Consensus::Params& consensusParams);
|
|
|
|
bool ReadRawBlockFromDisk(std::vector<uint8_t>& block, const FlatFilePos& pos, const CMessageHeader::MessageStartChars& message_start);
|
|
|
|
|
|
|
|
bool UndoReadFromDisk(CBlockUndo& blockundo, const CBlockIndex* pindex);
|
|
|
|
|
2022-07-12 21:42:00 -04:00
|
|
|
void ThreadImport(ChainstateManager& chainman, std::vector<fs::path> vImportFiles, const ArgsManager& args, const fs::path& mempool_path);
|
2021-11-12 10:06:00 -05:00
|
|
|
} // namespace node
|
2021-04-02 19:17:00 +02:00
|
|
|
|
|
|
|
#endif // BITCOIN_NODE_BLOCKSTORAGE_H
|