Line data Source code
1 : // Copyright (c) 2017-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_INDEX_BASE_H 6 : #define BITCOIN_INDEX_BASE_H 7 : 8 : #include <dbwrapper.h> 9 : #include <tinyformat.h> 10 : #include <util/threadinterrupt.h> 11 : #include <validationinterface.h> 12 : 13 : #include <atomic> 14 : 15 : class CBlock; 16 : class CBlockIndex; 17 : class CChainState; 18 : 19 : struct IndexSummary { 20 : std::string name; 21 : bool synced{false}; 22 : int best_block_height{0}; 23 : }; 24 : 25 : /** 26 : * Base class for indices of blockchain data. This implements 27 : * CValidationInterface and ensures blocks are indexed sequentially according 28 : * to their position in the active chain. 29 : */ 30 3629 : class BaseIndex : public CValidationInterface 31 : { 32 : protected: 33 : /** 34 : * The database stores a block locator of the chain the database is synced to 35 : * so that the index can efficiently determine the point it last stopped at. 36 : * A locator is used instead of a simple hash of the chain tip because blocks 37 : * and block index entries may not be flushed to disk until after this database 38 : * is updated. 39 : */ 40 : class DB : public CDBWrapper 41 : { 42 : public: 43 : DB(const fs::path& path, size_t n_cache_size, 44 : bool f_memory = false, bool f_wipe = false, bool f_obfuscate = false); 45 : 46 : /// Read block locator of the chain that the index is in sync with. 47 : bool ReadBestBlock(CBlockLocator& locator) const; 48 : 49 : /// Write block locator of the chain that the index is in sync with. 50 : void WriteBestBlock(CDBBatch& batch, const CBlockLocator& locator); 51 : }; 52 : 53 : private: 54 : /// Whether the index is in sync with the main chain. The flag is flipped 55 : /// from false to true once, after which point this starts processing 56 : /// ValidationInterface notifications to stay in sync. 57 : /// 58 : /// Note that this will latch to true *immediately* upon startup if 59 : /// `m_chainstate->m_chain` is empty, which will be the case upon startup 60 : /// with an empty datadir if, e.g., `-txindex=1` is specified. 61 3629 : std::atomic<bool> m_synced{false}; 62 : 63 : /// The last block in the chain that the index is in sync with. 64 3629 : std::atomic<const CBlockIndex*> m_best_block_index{nullptr}; 65 : 66 : std::thread m_thread_sync; 67 : CThreadInterrupt m_interrupt; 68 : 69 : /// Sync the index with the block index starting from the current best block. 70 : /// Intended to be run in its own thread, m_thread_sync, and can be 71 : /// interrupted with m_interrupt. Once the index gets in sync, the m_synced 72 : /// flag is set and the BlockConnected ValidationInterface callback takes 73 : /// over and the sync thread exits. 74 : void ThreadSync(); 75 : 76 : /// Write the current index state (eg. chain block locator and subclass-specific items) to disk. 77 : /// 78 : /// Recommendations for error handling: 79 : /// If called on a successor of the previous committed best block in the index, the index can 80 : /// continue processing without risk of corruption, though the index state will need to catch up 81 : /// from further behind on reboot. If the new state is not a successor of the previous state (due 82 : /// to a chain reorganization), the index must halt until Commit succeeds or else it could end up 83 : /// getting corrupted. 84 : bool Commit(); 85 : 86 : virtual bool AllowPrune() const = 0; 87 : 88 : protected: 89 3629 : CChainState* m_chainstate{nullptr}; 90 : 91 : void BlockConnected(const std::shared_ptr<const CBlock>& block, const CBlockIndex* pindex) override; 92 : 93 : void BlockDisconnected(const std::shared_ptr<const CBlock>& block, const CBlockIndex* pindex) override; 94 : 95 : void ChainStateFlushed(const CBlockLocator& locator) override; 96 : 97 33 : const CBlockIndex* CurrentIndex() { return m_best_block_index.load(); }; 98 : 99 : /// Initialize internal state from the database and block index. 100 : [[nodiscard]] virtual bool Init(); 101 : 102 : /// Write update index entries for a newly connected block. 103 0 : virtual bool WriteBlock(const CBlock& block, const CBlockIndex* pindex) { return true; } 104 : 105 : /// Virtual method called internally by Commit that can be overridden to atomically 106 : /// commit more index state. 107 : virtual bool CommitInternal(CDBBatch& batch); 108 : 109 : /// Rewind index to an earlier chain tip during a chain reorg. The tip must 110 : /// be an ancestor of the current best block. 111 : virtual bool Rewind(const CBlockIndex* current_tip, const CBlockIndex* new_tip); 112 : 113 : virtual DB& GetDB() const = 0; 114 : 115 : /// Get the name of the index for display in logs. 116 : virtual const char* GetName() const = 0; 117 : 118 : /// Trigger a fatal index error and initiate shutdown. 119 : static void FatalErrorImpl(const std::string& message); 120 : 121 : template <typename... Args> 122 0 : void FatalError(const char* fmt, const Args&... args) const 123 : { 124 0 : FatalErrorImpl(tfm::format(fmt, args...)); 125 0 : } 126 : 127 : /// Update the internal best block index as well as the prune lock. 128 : void SetBestBlockIndex(const CBlockIndex* block); 129 : 130 : public: 131 : /// Destructor interrupts sync thread if running and blocks until it exits. 132 : virtual ~BaseIndex(); 133 : 134 : /// Blocks the current thread until the index is caught up to the current 135 : /// state of the block chain. This only blocks if the index has gotten in 136 : /// sync once and only needs to process blocks in the ValidationInterface 137 : /// queue. If the index is catching up from far behind, this method does 138 : /// not block and immediately returns false. 139 : bool BlockUntilSyncedToCurrentChain() const LOCKS_EXCLUDED(::cs_main); 140 : 141 : void Interrupt(); 142 : 143 : /// Start initializes the sync state and registers the instance as a 144 : /// ValidationInterface so that it stays in sync with blockchain updates. 145 : [[nodiscard]] bool Start(CChainState& active_chainstate); 146 : 147 : /// Stops the instance from staying in sync with blockchain updates. 148 : void Stop(); 149 : 150 : /// Get a summary of the index and its state. 151 : IndexSummary GetSummary() const; 152 : }; 153 : 154 : #endif // BITCOIN_INDEX_BASE_H