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