Line data Source code
1 : // Copyright (c) 2018-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 : #include <llmq/options.h> 6 : 7 : #include <spork.h> 8 : #include <util/helpers.h> 9 : #include <util/std23.h> 10 : 11 : #include <chainparams.h> 12 : #include <consensus/params.h> 13 : #include <deploymentstatus.h> 14 : #include <util/system.h> 15 : #include <validation.h> 16 : 17 : #include <algorithm> 18 : #include <ranges> 19 : #include <string> 20 : #include <stdexcept> 21 : #include <thread> 22 : 23 : namespace llmq { 24 146 : int16_t DEFAULT_WORKER_COUNT{std::clamp<int16_t>(std::thread::hardware_concurrency() / 2, 1, 4)}; 25 : 26 0 : static bool EvalSpork(const Consensus::LLMQType llmqType, const int64_t spork_value) 27 : { 28 0 : if (spork_value == 0) { 29 0 : return true; 30 : } 31 0 : if (spork_value == 1 && llmqType != Consensus::LLMQType::LLMQ_100_67 && llmqType != Consensus::LLMQType::LLMQ_400_60 && llmqType != Consensus::LLMQType::LLMQ_400_85) { 32 0 : return true; 33 : } 34 0 : return false; 35 0 : } 36 : 37 0 : bool IsAllMembersConnectedEnabled(const Consensus::LLMQType llmqType, const CSporkManager& sporkman) 38 : { 39 0 : return EvalSpork(llmqType, sporkman.GetSporkValue(SPORK_21_QUORUM_ALL_CONNECTED)); 40 : } 41 : 42 0 : bool IsQuorumDKGEnabled(const CSporkManager& sporkman) { return sporkman.IsSporkActive(SPORK_17_QUORUM_DKG_ENABLED); } 43 : 44 0 : bool IsQuorumPoseEnabled(const Consensus::LLMQType llmqType, const CSporkManager& sporkman) 45 : { 46 0 : return EvalSpork(llmqType, sporkman.GetSporkValue(SPORK_23_QUORUM_POSE)); 47 : } 48 : 49 : 50 377268 : bool IsQuorumRotationEnabled(const Consensus::LLMQParams& llmqParams, gsl::not_null<const CBlockIndex*> pindex) 51 : { 52 377268 : if (!llmqParams.useRotation) { 53 275960 : return false; 54 : } 55 : 56 101308 : int cycleQuorumBaseHeight = pindex->nHeight - (pindex->nHeight % llmqParams.dkgInterval); 57 101308 : if (cycleQuorumBaseHeight < 1) { 58 25 : return false; 59 : } 60 : // It should activate at least 1 block prior to the cycle start 61 101283 : return DeploymentActiveAfter(pindex->GetAncestor(cycleQuorumBaseHeight - 1), Params().GetConsensus(), Consensus::DEPLOYMENT_DIP0024); 62 377268 : } 63 : 64 627 : QvvecSyncModeMap GetEnabledQuorumVvecSyncEntries(const ArgsManager& args) 65 : { 66 627 : QvvecSyncModeMap mapQuorumVvecSyncEntries; 67 627 : for (const auto& strEntry : args.GetArgs("-llmq-qvvec-sync")) { 68 0 : Consensus::LLMQType llmqType = Consensus::LLMQType::LLMQ_NONE; 69 0 : QvvecSyncMode mode{QvvecSyncMode::Invalid}; 70 0 : std::istringstream ssEntry(strEntry); 71 0 : std::string strLLMQType, strMode, strTest; 72 0 : const bool fLLMQTypePresent = std::getline(ssEntry, strLLMQType, ':') && strLLMQType != ""; 73 0 : const bool fModePresent = std::getline(ssEntry, strMode, ':') && strMode != ""; 74 0 : const bool fTooManyEntries = static_cast<bool>(std::getline(ssEntry, strTest, ':')); 75 0 : if (!fLLMQTypePresent || !fModePresent || fTooManyEntries) { 76 0 : throw std::invalid_argument(strprintf("Invalid format in -llmq-qvvec-sync: %s", strEntry)); 77 : } 78 : 79 0 : if (auto optLLMQParams = util::find_if_opt(Params().GetConsensus().llmqs, [&strLLMQType](const auto& params) { 80 0 : return params.name == strLLMQType; 81 : })) { 82 0 : llmqType = optLLMQParams->type; 83 0 : } else { 84 0 : throw std::invalid_argument(strprintf("Invalid llmqType in -llmq-qvvec-sync: %s", strEntry)); 85 : } 86 0 : if (mapQuorumVvecSyncEntries.count(llmqType) > 0) { 87 0 : throw std::invalid_argument(strprintf("Duplicated llmqType in -llmq-qvvec-sync: %s", strEntry)); 88 : } 89 : 90 : int32_t nMode; 91 0 : if (ParseInt32(strMode, &nMode)) { 92 0 : switch (nMode) { 93 : case (int32_t)QvvecSyncMode::Always: 94 0 : mode = QvvecSyncMode::Always; 95 0 : break; 96 : case (int32_t)QvvecSyncMode::OnlyIfTypeMember: 97 0 : mode = QvvecSyncMode::OnlyIfTypeMember; 98 0 : break; 99 : default: 100 0 : mode = QvvecSyncMode::Invalid; 101 0 : break; 102 : } 103 0 : } 104 0 : if (mode == QvvecSyncMode::Invalid) { 105 0 : throw std::invalid_argument(strprintf("Invalid mode in -llmq-qvvec-sync: %s", strEntry)); 106 : } 107 0 : mapQuorumVvecSyncEntries.emplace(llmqType, mode); 108 0 : } 109 627 : return mapQuorumVvecSyncEntries; 110 627 : } 111 : 112 0 : std::vector<Consensus::LLMQType> GetEnabledQuorumTypes(const ChainstateManager& chainman, 113 : gsl::not_null<const CBlockIndex*> pindex) 114 : { 115 0 : std::vector<Consensus::LLMQType> ret; 116 0 : ret.reserve(Params().GetConsensus().llmqs.size()); 117 0 : for (const auto& params : Params().GetConsensus().llmqs) { 118 0 : if (chainman.IsQuorumTypeEnabled(params.type, pindex)) { 119 0 : ret.push_back(params.type); 120 0 : } 121 : } 122 0 : return ret; 123 0 : } 124 : 125 46014 : std::vector<std::reference_wrapper<const Consensus::LLMQParams>> GetEnabledQuorumParams( 126 : const ChainstateManager& chainman, gsl::not_null<const CBlockIndex*> pindex) 127 : { 128 46014 : std::vector<std::reference_wrapper<const Consensus::LLMQParams>> ret; 129 46014 : ret.reserve(Params().GetConsensus().llmqs.size()); 130 : 131 46014 : std::copy_if(Params().GetConsensus().llmqs.begin(), Params().GetConsensus().llmqs.end(), std::back_inserter(ret), 132 276084 : [&pindex, &chainman](const auto& params) { return chainman.IsQuorumTypeEnabled(params.type, pindex); }); 133 : 134 46014 : return ret; 135 46014 : } 136 : } // namespace llmq