Line data Source code
1 : // Copyright (c) 2021-2025 The Dash 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_EVO_MNHFTX_H 6 : #define BITCOIN_EVO_MNHFTX_H 7 : 8 : #include <saltedhasher.h> 9 : #include <sync.h> 10 : #include <threadsafety.h> 11 : #include <versionbits.h> 12 : 13 : #include <bls/bls.h> 14 : #include <unordered_lru_cache.h> 15 : 16 : #include <gsl/pointers.h> 17 : #include <univalue.h> 18 : 19 : #include <optional> 20 : 21 : class BlockValidationState; 22 : class CBlock; 23 : class CBlockIndex; 24 : class CEvoDB; 25 : class CTransaction; 26 : class ChainstateManager; 27 : class TxValidationState; 28 : struct RPCResult; 29 : namespace llmq { 30 : class CQuorumManager; 31 : } 32 : 33 : // mnhf signal special transaction 34 : class MNHFTx 35 : { 36 : public: 37 4 : uint8_t versionBit{0}; 38 4 : uint256 quorumHash{0}; 39 4 : CBLSSignature sig{}; 40 : 41 12 : MNHFTx() = default; 42 : bool Verify(const llmq::CQuorumManager& qman, const uint256& quorumHash, const uint256& requestId, const uint256& msgHash, 43 : TxValidationState& state) const; 44 : 45 12 : SERIALIZE_METHODS(MNHFTx, obj) 46 : { 47 4 : READWRITE(obj.versionBit, obj.quorumHash); 48 4 : READWRITE(CBLSSignatureVersionWrapper(const_cast<CBLSSignature&>(obj.sig), /*legacy=*/false)); 49 4 : } 50 : 51 : std::string ToString() const; 52 : 53 : [[nodiscard]] static RPCResult GetJsonHelp(const std::string& key, bool optional); 54 : [[nodiscard]] UniValue ToJson() const; 55 : }; 56 : 57 4 : class MNHFTxPayload 58 : { 59 : public: 60 : static constexpr auto SPECIALTX_TYPE = TRANSACTION_MNHF_SIGNAL; 61 : static constexpr uint16_t CURRENT_VERSION = 1; 62 : 63 4 : uint8_t nVersion{CURRENT_VERSION}; 64 : MNHFTx signal; 65 : 66 : public: 67 : /** 68 : * helper function to calculate Request ID used for signing 69 : */ 70 : uint256 GetRequestId() const; 71 : 72 : /** 73 : * helper function to prepare special transaction for signing 74 : */ 75 : CMutableTransaction PrepareTx() const; 76 : 77 12 : SERIALIZE_METHODS(MNHFTxPayload, obj) 78 : { 79 4 : READWRITE(obj.nVersion, obj.signal); 80 4 : } 81 : 82 : std::string ToString() const; 83 : 84 : [[nodiscard]] static RPCResult GetJsonHelp(const std::string& key, bool optional); 85 : [[nodiscard]] UniValue ToJson() const; 86 : }; 87 : 88 : class CMNHFManager : public AbstractEHFManager 89 : { 90 : private: 91 : CEvoDB& m_evoDb; 92 : // TODO: move its functionallity of ProcessBlock, UndoBlock to specialtxman; 93 : // it will help to drop dependency on m_chainman, m_qman here (and validation.h) 94 : // Secondly, store in database active EHF signals not for each block; 95 : // but quite opposite: keep only hash of block where signal is added. 96 : // TODO: implement migration to a new format 97 : const ChainstateManager& m_chainman; 98 : const llmq::CQuorumManager& m_qman; 99 : 100 : static constexpr size_t MNHFCacheSize = 1000; 101 : Mutex cs_cache; 102 : // versionBit <-> height 103 : Uint256LruHashMap<Signals> mnhfCache GUARDED_BY(cs_cache){MNHFCacheSize}; 104 : 105 : public: 106 : CMNHFManager() = delete; 107 : CMNHFManager(const CMNHFManager&) = delete; 108 : CMNHFManager& operator=(const CMNHFManager&) = delete; 109 : explicit CMNHFManager(CEvoDB& evoDb, const ChainstateManager& chainman, const llmq::CQuorumManager& qman); 110 : ~CMNHFManager(); 111 : 112 : /** 113 : * Every new block should be processed when Tip() is updated by calling of CMNHFManager::ProcessBlock. 114 : * This function actually does only validate EHF transaction for this block and update internal caches/evodb state 115 : */ 116 : std::optional<Signals> ProcessBlock(const CBlock& block, const CBlockIndex* const pindex, bool fJustCheck, 117 : BlockValidationState& state) EXCLUSIVE_LOCKS_REQUIRED(!cs_cache); 118 : 119 : /** 120 : * Every undo block should be processed when Tip() is updated by calling of CMNHFManager::UndoBlock 121 : * This function actually does nothing at the moment, because status of ancestor block is already known. 122 : * Although it should be still called to do some sanity checks 123 : */ 124 : bool UndoBlock(const CBlock& block, const CBlockIndex* const pindex) EXCLUSIVE_LOCKS_REQUIRED(!cs_cache); 125 : 126 : // Implements interface 127 : Signals GetSignalsStage(const CBlockIndex* const pindexPrev) override EXCLUSIVE_LOCKS_REQUIRED(!cs_cache); 128 : 129 : /** 130 : * Helper that used in Unit Test to forcely setup EHF signal for specific block 131 : */ 132 : void AddSignal(const CBlockIndex* const pindex, int bit) EXCLUSIVE_LOCKS_REQUIRED(!cs_cache); 133 : 134 : bool ForceSignalDBUpdate() EXCLUSIVE_LOCKS_REQUIRED(::cs_main, !cs_cache); 135 : 136 : private: 137 : void AddToCache(const Signals& signals, const CBlockIndex* const pindex) EXCLUSIVE_LOCKS_REQUIRED(!cs_cache); 138 : 139 : /** 140 : * This function returns list of signals available on previous block. 141 : * if the signals for previous block is not available in cache it would read blocks from disk 142 : * until state won't be recovered. 143 : * NOTE: that some signals could expired between blocks. 144 : */ 145 : Signals GetForBlock(const CBlockIndex* const pindex) EXCLUSIVE_LOCKS_REQUIRED(!cs_cache); 146 : 147 : /** 148 : * This function access to in-memory cache or to evo db but does not calculate anything 149 : * NOTE: that some signals could expired between blocks. 150 : */ 151 : std::optional<Signals> GetFromCache(const CBlockIndex* const pindex) EXCLUSIVE_LOCKS_REQUIRED(!cs_cache); 152 : }; 153 : 154 : std::optional<uint8_t> extractEHFSignal(const CTransaction& tx); 155 : bool CheckMNHFTx(const ChainstateManager& chainman, const llmq::CQuorumManager& qman, const CTransaction& tx, const CBlockIndex* pindexPrev, TxValidationState& state); 156 : 157 : #endif // BITCOIN_EVO_MNHFTX_H