/Users/eugenesiegel/btc/bitcoin/src/index/base.h
| Line | Count | Source (jump to first uncovered line) | 
| 1 |  | // Copyright (c) 2017-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_INDEX_BASE_H | 
| 6 |  | #define BITCOIN_INDEX_BASE_H | 
| 7 |  |  | 
| 8 |  | #include <dbwrapper.h> | 
| 9 |  | #include <interfaces/chain.h> | 
| 10 |  | #include <interfaces/types.h> | 
| 11 |  | #include <util/string.h> | 
| 12 |  | #include <util/threadinterrupt.h> | 
| 13 |  | #include <validationinterface.h> | 
| 14 |  |  | 
| 15 |  | #include <string> | 
| 16 |  |  | 
| 17 |  | class CBlock; | 
| 18 |  | class CBlockIndex; | 
| 19 |  | class Chainstate; | 
| 20 |  | class ChainstateManager; | 
| 21 |  | namespace interfaces { | 
| 22 |  | class Chain; | 
| 23 |  | } // namespace interfaces | 
| 24 |  |  | 
| 25 |  | struct IndexSummary { | 
| 26 |  |     std::string name; | 
| 27 |  |     bool synced{false}; | 
| 28 |  |     int best_block_height{0}; | 
| 29 |  |     uint256 best_block_hash; | 
| 30 |  | }; | 
| 31 |  |  | 
| 32 |  | /** | 
| 33 |  |  * Base class for indices of blockchain data. This implements | 
| 34 |  |  * CValidationInterface and ensures blocks are indexed sequentially according | 
| 35 |  |  * to their position in the active chain. | 
| 36 |  |  * | 
| 37 |  |  * In the presence of multiple chainstates (i.e. if a UTXO snapshot is loaded), | 
| 38 |  |  * only the background "IBD" chainstate will be indexed to avoid building the | 
| 39 |  |  * index out of order. When the background chainstate completes validation, the | 
| 40 |  |  * index will be reinitialized and indexing will continue. | 
| 41 |  |  */ | 
| 42 |  | class BaseIndex : public CValidationInterface | 
| 43 |  | { | 
| 44 |  | protected: | 
| 45 |  |     /** | 
| 46 |  |      * The database stores a block locator of the chain the database is synced to | 
| 47 |  |      * so that the index can efficiently determine the point it last stopped at. | 
| 48 |  |      * A locator is used instead of a simple hash of the chain tip because blocks | 
| 49 |  |      * and block index entries may not be flushed to disk until after this database | 
| 50 |  |      * is updated. | 
| 51 |  |     */ | 
| 52 |  |     class DB : public CDBWrapper | 
| 53 |  |     { | 
| 54 |  |     public: | 
| 55 |  |         DB(const fs::path& path, size_t n_cache_size, | 
| 56 |  |            bool f_memory = false, bool f_wipe = false, bool f_obfuscate = false); | 
| 57 |  |  | 
| 58 |  |         /// Read block locator of the chain that the index is in sync with. | 
| 59 |  |         bool ReadBestBlock(CBlockLocator& locator) const; | 
| 60 |  |  | 
| 61 |  |         /// Write block locator of the chain that the index is in sync with. | 
| 62 |  |         void WriteBestBlock(CDBBatch& batch, const CBlockLocator& locator); | 
| 63 |  |     }; | 
| 64 |  |  | 
| 65 |  | private: | 
| 66 |  |     /// Whether the index has been initialized or not. | 
| 67 |  |     std::atomic<bool> m_init{false}; | 
| 68 |  |     /// Whether the index is in sync with the main chain. The flag is flipped | 
| 69 |  |     /// from false to true once, after which point this starts processing | 
| 70 |  |     /// ValidationInterface notifications to stay in sync. | 
| 71 |  |     /// | 
| 72 |  |     /// Note that this will latch to true *immediately* upon startup if | 
| 73 |  |     /// `m_chainstate->m_chain` is empty, which will be the case upon startup | 
| 74 |  |     /// with an empty datadir if, e.g., `-txindex=1` is specified. | 
| 75 |  |     std::atomic<bool> m_synced{false}; | 
| 76 |  |  | 
| 77 |  |     /// The last block in the chain that the index is in sync with. | 
| 78 |  |     std::atomic<const CBlockIndex*> m_best_block_index{nullptr}; | 
| 79 |  |  | 
| 80 |  |     std::thread m_thread_sync; | 
| 81 |  |     CThreadInterrupt m_interrupt; | 
| 82 |  |  | 
| 83 |  |     /// Write the current index state (eg. chain block locator and subclass-specific items) to disk. | 
| 84 |  |     /// | 
| 85 |  |     /// Recommendations for error handling: | 
| 86 |  |     /// If called on a successor of the previous committed best block in the index, the index can | 
| 87 |  |     /// continue processing without risk of corruption, though the index state will need to catch up | 
| 88 |  |     /// from further behind on reboot. If the new state is not a successor of the previous state (due | 
| 89 |  |     /// to a chain reorganization), the index must halt until Commit succeeds or else it could end up | 
| 90 |  |     /// getting corrupted. | 
| 91 |  |     bool Commit(); | 
| 92 |  |  | 
| 93 |  |     /// Loop over disconnected blocks and call CustomRemove. | 
| 94 |  |     bool Rewind(const CBlockIndex* current_tip, const CBlockIndex* new_tip); | 
| 95 |  |  | 
| 96 |  |     bool ProcessBlock(const CBlockIndex* pindex, const CBlock* block_data = nullptr); | 
| 97 |  |  | 
| 98 |  |     virtual bool AllowPrune() const = 0; | 
| 99 |  |  | 
| 100 |  |     template <typename... Args> | 
| 101 |  |     void FatalErrorf(util::ConstevalFormatString<sizeof...(Args)> fmt, const Args&... args); | 
| 102 |  |  | 
| 103 |  | protected: | 
| 104 |  |     std::unique_ptr<interfaces::Chain> m_chain; | 
| 105 |  |     Chainstate* m_chainstate{nullptr}; | 
| 106 |  |     const std::string m_name; | 
| 107 |  |  | 
| 108 |  |     void BlockConnected(ChainstateRole role, const std::shared_ptr<const CBlock>& block, const CBlockIndex* pindex) override; | 
| 109 |  |  | 
| 110 |  |     void ChainStateFlushed(ChainstateRole role, const CBlockLocator& locator) override; | 
| 111 |  |  | 
| 112 |  |     /// Return custom notification options for index. | 
| 113 | 0 |     [[nodiscard]] virtual interfaces::Chain::NotifyOptions CustomOptions() { return {}; } | 
| 114 |  |  | 
| 115 |  |     /// Initialize internal state from the database and block index. | 
| 116 | 0 |     [[nodiscard]] virtual bool CustomInit(const std::optional<interfaces::BlockRef>& block) { return true; } | 
| 117 |  |  | 
| 118 |  |     /// Write update index entries for a newly connected block. | 
| 119 | 0 |     [[nodiscard]] virtual bool CustomAppend(const interfaces::BlockInfo& block) { return true; } | 
| 120 |  |  | 
| 121 |  |     /// Virtual method called internally by Commit that can be overridden to atomically | 
| 122 |  |     /// commit more index state. | 
| 123 | 0 |     virtual bool CustomCommit(CDBBatch& batch) { return true; } | 
| 124 |  |  | 
| 125 |  |     /// Rewind index by one block during a chain reorg. | 
| 126 | 0 |     [[nodiscard]] virtual bool CustomRemove(const interfaces::BlockInfo& block) { return true; } | 
| 127 |  |  | 
| 128 |  |     virtual DB& GetDB() const = 0; | 
| 129 |  |  | 
| 130 |  |     /// Update the internal best block index as well as the prune lock. | 
| 131 |  |     void SetBestBlockIndex(const CBlockIndex* block); | 
| 132 |  |  | 
| 133 |  | public: | 
| 134 |  |     BaseIndex(std::unique_ptr<interfaces::Chain> chain, std::string name); | 
| 135 |  |     /// Destructor interrupts sync thread if running and blocks until it exits. | 
| 136 |  |     virtual ~BaseIndex(); | 
| 137 |  |  | 
| 138 |  |     /// Get the name of the index for display in logs. | 
| 139 | 0 |     const std::string& GetName() const LIFETIMEBOUND { return m_name; } | 
| 140 |  |  | 
| 141 |  |     /// Blocks the current thread until the index is caught up to the current | 
| 142 |  |     /// state of the block chain. This only blocks if the index has gotten in | 
| 143 |  |     /// sync once and only needs to process blocks in the ValidationInterface | 
| 144 |  |     /// queue. If the index is catching up from far behind, this method does | 
| 145 |  |     /// not block and immediately returns false. | 
| 146 |  |     bool BlockUntilSyncedToCurrentChain() const LOCKS_EXCLUDED(::cs_main); | 
| 147 |  |  | 
| 148 |  |     void Interrupt(); | 
| 149 |  |  | 
| 150 |  |     /// Initializes the sync state and registers the instance to the | 
| 151 |  |     /// validation interface so that it stays in sync with blockchain updates. | 
| 152 |  |     [[nodiscard]] bool Init(); | 
| 153 |  |  | 
| 154 |  |     /// Starts the initial sync process on a background thread. | 
| 155 |  |     [[nodiscard]] bool StartBackgroundSync(); | 
| 156 |  |  | 
| 157 |  |     /// Sync the index with the block index starting from the current best block. | 
| 158 |  |     /// Intended to be run in its own thread, m_thread_sync, and can be | 
| 159 |  |     /// interrupted with m_interrupt. Once the index gets in sync, the m_synced | 
| 160 |  |     /// flag is set and the BlockConnected ValidationInterface callback takes | 
| 161 |  |     /// over and the sync thread exits. | 
| 162 |  |     void Sync(); | 
| 163 |  |  | 
| 164 |  |     /// Stops the instance from staying in sync with blockchain updates. | 
| 165 |  |     void Stop(); | 
| 166 |  |  | 
| 167 |  |     /// Get a summary of the index and its state. | 
| 168 |  |     IndexSummary GetSummary() const; | 
| 169 |  | }; | 
| 170 |  |  | 
| 171 |  | #endif // BITCOIN_INDEX_BASE_H |