diff --git a/src/Makefile.am b/src/Makefile.am index 792c884f0850..75e4a5efc2da 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -232,6 +232,7 @@ BITCOIN_CORE_H = \ llmq/ehf_signals.cpp \ llmq/ehf_signals.h \ llmq/instantsend.h \ + llmq/options.h \ llmq/params.h \ llmq/quorums.h \ llmq/signing.h \ @@ -452,6 +453,7 @@ libbitcoin_server_a_SOURCES = \ llmq/dkgsession.cpp \ llmq/context.cpp \ llmq/instantsend.cpp \ + llmq/options.cpp \ llmq/snapshot.cpp \ llmq/signing.cpp \ llmq/signing_shares.cpp \ diff --git a/src/chainparams.h b/src/chainparams.h index e665b6aaf5f0..0b6535eecc42 100644 --- a/src/chainparams.h +++ b/src/chainparams.h @@ -152,7 +152,7 @@ class CChainParams int FulfilledRequestExpireTime() const { return nFulfilledRequestExpireTime; } const std::vector& SporkAddresses() const { return vSporkAddresses; } int MinSporkKeys() const { return nMinSporkKeys; } - std::optional GetLLMQ(Consensus::LLMQType llmqType) const; + [[nodiscard]] std::optional GetLLMQ(Consensus::LLMQType llmqType) const; protected: CChainParams() {} diff --git a/src/coinjoin/coinjoin.cpp b/src/coinjoin/coinjoin.cpp index 9bb932da05b3..0440f48fef6b 100644 --- a/src/coinjoin/coinjoin.cpp +++ b/src/coinjoin/coinjoin.cpp @@ -11,7 +11,6 @@ #include #include #include -#include #include #include #include diff --git a/src/evo/assetlocktx.cpp b/src/evo/assetlocktx.cpp index d96c97e38ecd..748b7e48309d 100644 --- a/src/evo/assetlocktx.cpp +++ b/src/evo/assetlocktx.cpp @@ -7,7 +7,6 @@ #include #include -#include #include #include @@ -134,7 +133,7 @@ bool CAssetUnlockPayload::VerifySig(const uint256& msgHash, gsl::not_nullqc->quorumHash, requestId, msgHash); + if (const uint256 signHash = llmq::BuildSignHash(llmqType, quorum->qc->quorumHash, requestId, msgHash); quorumSig.VerifyInsecure(quorum->qc->quorumPublicKey, signHash)) { return true; } diff --git a/src/evo/cbtx.cpp b/src/evo/cbtx.cpp index 8f81e5f69f2d..b67d8439b7ad 100644 --- a/src/evo/cbtx.cpp +++ b/src/evo/cbtx.cpp @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include #include @@ -199,9 +199,9 @@ auto CachedGetQcHashesQcIndexedHashes(const CBlockIndex* pindexPrev, const llmq: qcIndexedHashes_cached.clear(); for (const auto& [llmqType, vecBlockIndexes] : quorums) { - const auto& llmq_params_opt = llmq::GetLLMQParams(llmqType); + const auto& llmq_params_opt = Params().GetLLMQ(llmqType); assert(llmq_params_opt.has_value()); - bool rotation_enabled = llmq::utils::IsQuorumRotationEnabled(llmq_params_opt.value(), pindexPrev); + bool rotation_enabled = llmq::IsQuorumRotationEnabled(llmq_params_opt.value(), pindexPrev); auto& vec_hashes = qcHashes_cached[llmqType]; vec_hashes.reserve(vecBlockIndexes.size()); auto& map_indexed_hashes = qcIndexedHashes_cached[llmqType]; @@ -265,13 +265,13 @@ bool CalcCbTxMerkleRootQuorums(const CBlock& block, const CBlockIndex* pindexPre // having null commitments is ok but we don't use them here, move to the next tx continue; } - const auto& llmq_params_opt = llmq::GetLLMQParams(opt_qc->commitment.llmqType); + const auto& llmq_params_opt = Params().GetLLMQ(opt_qc->commitment.llmqType); if (!llmq_params_opt.has_value()) { return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-qc-commitment-type-calc-cbtx-quorummerkleroot"); } const auto& llmq_params = llmq_params_opt.value(); - auto qcHash = ::SerializeHash(opt_qc->commitment); - if (llmq::utils::IsQuorumRotationEnabled(llmq_params, pindexPrev)) { + const auto qcHash = ::SerializeHash(opt_qc->commitment); + if (llmq::IsQuorumRotationEnabled(llmq_params, pindexPrev)) { auto& map_indexed_hashes = qcIndexedHashes[opt_qc->commitment.llmqType]; map_indexed_hashes[opt_qc->commitment.quorumIndex] = qcHash; } else { @@ -298,7 +298,7 @@ bool CalcCbTxMerkleRootQuorums(const CBlock& block, const CBlockIndex* pindexPre vec_hashes_final.reserve(CalcHashCountFromQCHashes(qcHashes)); for (const auto& [llmqType, vec_hashes] : qcHashes) { - const auto& llmq_params_opt = llmq::GetLLMQParams(llmqType); + const auto& llmq_params_opt = Params().GetLLMQ(llmqType); assert(llmq_params_opt.has_value()); if (vec_hashes.size() > size_t(llmq_params_opt->signingActiveQuorumCount)) { return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "excess-quorums-calc-cbtx-quorummerkleroot"); diff --git a/src/evo/deterministicmns.cpp b/src/evo/deterministicmns.cpp index 4c74975ed078..3cca9b4b64f8 100644 --- a/src/evo/deterministicmns.cpp +++ b/src/evo/deterministicmns.cpp @@ -912,7 +912,7 @@ bool CDeterministicMNManager::BuildNewListFromBlock(const CBlock& block, gsl::no return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-qc-payload"); } if (!opt_qc->commitment.IsNull()) { - const auto& llmq_params_opt = llmq::GetLLMQParams(opt_qc->commitment.llmqType); + const auto& llmq_params_opt = Params().GetLLMQ(opt_qc->commitment.llmqType); if (!llmq_params_opt.has_value()) { return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-qc-commitment-type"); } diff --git a/src/evo/mnhftx.cpp b/src/evo/mnhftx.cpp index 9c44e2a0d9dc..14a940274cd9 100644 --- a/src/evo/mnhftx.cpp +++ b/src/evo/mnhftx.cpp @@ -8,7 +8,6 @@ #include #include #include -#include #include #include @@ -93,7 +92,7 @@ bool MNHFTx::Verify(const uint256& quorumHash, const uint256& requestId, const u const Consensus::LLMQType& llmqType = Params().GetConsensus().llmqTypeMnhf; const auto quorum = llmq::quorumManager->GetQuorum(llmqType, quorumHash); - const uint256 signHash = llmq::utils::BuildSignHash(llmqType, quorum->qc->quorumHash, requestId, msgHash); + const uint256 signHash = llmq::BuildSignHash(llmqType, quorum->qc->quorumHash, requestId, msgHash); if (!sig.VerifyInsecure(quorum->qc->quorumPublicKey, signHash)) { return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-mnhf-invalid"); } diff --git a/src/governance/object.cpp b/src/governance/object.cpp index 912903f8a53b..7439f3ac42a3 100644 --- a/src/governance/object.cpp +++ b/src/governance/object.cpp @@ -10,7 +10,6 @@ #include #include #include -#include #include #include #include diff --git a/src/governance/vote.cpp b/src/governance/vote.cpp index 76b761fa81a4..1c16d0930b3d 100644 --- a/src/governance/vote.cpp +++ b/src/governance/vote.cpp @@ -8,7 +8,6 @@ #include #include #include -#include #include #include #include diff --git a/src/init.cpp b/src/init.cpp index 9548a6573c13..f9cce0c60c3b 100644 --- a/src/init.cpp +++ b/src/init.cpp @@ -97,9 +97,9 @@ #include #include #include +#include #include #include -#include #include #include @@ -1424,8 +1424,8 @@ bool AppInitParameterInteraction(const ArgsManager& args) } try { - const bool fRecoveryEnabled{llmq::utils::QuorumDataRecoveryEnabled()}; - const bool fQuorumVvecRequestsEnabled{llmq::utils::GetEnabledQuorumVvecSyncEntries().size() > 0}; + const bool fRecoveryEnabled{llmq::QuorumDataRecoveryEnabled()}; + const bool fQuorumVvecRequestsEnabled{llmq::GetEnabledQuorumVvecSyncEntries().size() > 0}; if (!fRecoveryEnabled && fQuorumVvecRequestsEnabled) { InitWarning(Untranslated("-llmq-qvvec-sync set but recovery is disabled due to -llmq-data-recovery=0")); } diff --git a/src/llmq/blockprocessor.cpp b/src/llmq/blockprocessor.cpp index d6e123fd35b9..524e80c48946 100644 --- a/src/llmq/blockprocessor.cpp +++ b/src/llmq/blockprocessor.cpp @@ -4,6 +4,7 @@ #include #include +#include #include #include @@ -27,8 +28,8 @@ static void PreComputeQuorumMembers(const CBlockIndex* pindex, bool reset_cache = false) { - for (const Consensus::LLMQParams& params : llmq::utils::GetEnabledQuorumParams(pindex->pprev)) { - if (llmq::utils::IsQuorumRotationEnabled(params, pindex) && (pindex->nHeight % params.dkgInterval == 0)) { + for (const Consensus::LLMQParams& params : llmq::GetEnabledQuorumParams(pindex->pprev)) { + if (llmq::IsQuorumRotationEnabled(params, pindex) && (pindex->nHeight % params.dkgInterval == 0)) { llmq::utils::GetAllQuorumMembers(params.type, pindex, reset_cache); } } @@ -67,7 +68,7 @@ PeerMsgRet CQuorumBlockProcessor::ProcessMessage(const CNode& peer, std::string_ return tl::unexpected{100}; } - const auto& llmq_params_opt = GetLLMQParams(qc.llmqType); + const auto& llmq_params_opt = Params().GetLLMQ(qc.llmqType); if (!llmq_params_opt.has_value()) { LogPrint(BCLog::LLMQ, "CQuorumBlockProcessor::%s -- invalid commitment type %d from peer=%d\n", __func__, ToUnderlying(qc.llmqType), peer.GetId()); @@ -165,7 +166,7 @@ bool CQuorumBlockProcessor::ProcessBlock(const CBlock& block, gsl::not_nullpprev)) { + for (const Consensus::LLMQParams& params : GetEnabledQuorumParams(pindex->pprev)) { // skip these checks when replaying blocks after the crash if (m_chainstate.m_chain.Tip() == nullptr) { break; @@ -181,7 +182,7 @@ bool CQuorumBlockProcessor::ProcessBlock(const CBlock& block, gsl::not_null numCommitmentsInNewBlock) { return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-qc-missing"); } - if (llmq::utils::IsQuorumRotationEnabled(params, pindex)) { + if (IsQuorumRotationEnabled(params, pindex)) { LogPrintf("[ProcessBlock] h[%d] numCommitmentsRequired[%d] numCommitmentsInNewBlock[%d]\n", pindex->nHeight, numCommitmentsRequired, numCommitmentsInNewBlock); } } @@ -217,7 +218,7 @@ bool CQuorumBlockProcessor::ProcessCommitment(int nHeight, const uint256& blockH { AssertLockHeld(cs_main); - const auto& llmq_params_opt = GetLLMQParams(qc.llmqType); + const auto& llmq_params_opt = Params().GetLLMQ(qc.llmqType); if (!llmq_params_opt.has_value()) { LogPrint(BCLog::LLMQ, "CQuorumBlockProcessor::%s -- invalid commitment type %d\n", __func__, ToUnderlying(qc.llmqType)); return false; @@ -276,7 +277,7 @@ bool CQuorumBlockProcessor::ProcessCommitment(int nHeight, const uint256& blockH return true; } - bool rotation_enabled = utils::IsQuorumRotationEnabled(llmq_params, pQuorumBaseBlockIndex); + bool rotation_enabled = IsQuorumRotationEnabled(llmq_params, pQuorumBaseBlockIndex); if (rotation_enabled) { LogPrint(BCLog::LLMQ, "[ProcessCommitment] height[%d] pQuorumBaseBlockIndex[%d] quorumIndex[%d] qversion[%d] Built\n", @@ -326,10 +327,10 @@ bool CQuorumBlockProcessor::UndoBlock(const CBlock& block, gsl::not_nullnHeight, int(qc.quorumIndex))); } else { m_evoDb.Erase(BuildInversedHeightKey(qc.llmqType, pindex->nHeight)); @@ -367,14 +368,14 @@ bool CQuorumBlockProcessor::GetCommitmentsFromBlock(const CBlock& block, gsl::no } auto& qc = *opt_qc; - const auto& llmq_params_opt = GetLLMQParams(qc.commitment.llmqType); + const auto& llmq_params_opt = Params().GetLLMQ(qc.commitment.llmqType); if (!llmq_params_opt.has_value()) { // should not happen as it was verified before processing the block return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-qc-commitment-type"); } // only allow one commitment per type and per block (This was changed with rotation) - if (!utils::IsQuorumRotationEnabled(llmq_params_opt.value(), pindex)) { + if (!IsQuorumRotationEnabled(llmq_params_opt.value(), pindex)) { if (ret.count(qc.commitment.llmqType) != 0) { return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-qc-dup"); } @@ -421,7 +422,7 @@ size_t CQuorumBlockProcessor::GetNumCommitmentsRequired(const Consensus::LLMQPar assert(nHeight <= m_chainstate.m_chain.Height() + 1); const auto *const pindex = m_chainstate.m_chain.Height() < nHeight ? m_chainstate.m_chain.Tip() : m_chainstate.m_chain.Tip()->GetAncestor(nHeight); - bool rotation_enabled = utils::IsQuorumRotationEnabled(llmqParams, pindex); + bool rotation_enabled = IsQuorumRotationEnabled(llmqParams, pindex); size_t quorums_num = rotation_enabled ? llmqParams.signingActiveQuorumCount : 1; size_t ret{0}; @@ -574,7 +575,7 @@ std::optional CQuorumBlockProcessor::GetLastMinedCommitments std::vector> CQuorumBlockProcessor::GetLastMinedCommitmentsPerQuorumIndexUntilBlock(Consensus::LLMQType llmqType, const CBlockIndex* pindex, size_t cycle) const { - const auto& llmq_params_opt = GetLLMQParams(llmqType); + const auto& llmq_params_opt = Params().GetLLMQ(llmqType); assert(llmq_params_opt.has_value()); std::vector> ret; @@ -626,7 +627,7 @@ std::map> CQuorumBlockProce for (const auto& params : Params().GetConsensus().llmqs) { auto& v = ret[params.type]; v.reserve(params.signingActiveQuorumCount); - if (utils::IsQuorumRotationEnabled(params, pindex)) { + if (IsQuorumRotationEnabled(params, pindex)) { std::vector> commitments = GetLastMinedCommitmentsPerQuorumIndexUntilBlock(params.type, pindex, 0); std::transform(commitments.begin(), commitments.end(), std::back_inserter(v), [](const std::pair& p) { return p.second; }); @@ -705,7 +706,7 @@ std::optional> CQuorumBlockProcessor::GetMineableC assert(nHeight <= m_chainstate.m_chain.Height() + 1); const auto *const pindex = m_chainstate.m_chain.Height() < nHeight ? m_chainstate.m_chain.Tip() : m_chainstate.m_chain.Tip()->GetAncestor(nHeight); - bool rotation_enabled = utils::IsQuorumRotationEnabled(llmqParams, pindex); + bool rotation_enabled = IsQuorumRotationEnabled(llmqParams, pindex); bool basic_bls_enabled{DeploymentActiveAfter(pindex, Params().GetConsensus(), Consensus::DEPLOYMENT_V19)}; size_t quorums_num = rotation_enabled ? llmqParams.signingActiveQuorumCount : 1; diff --git a/src/llmq/chainlocks.cpp b/src/llmq/chainlocks.cpp index 7330fd5f1c8e..5ba131bc7ec7 100644 --- a/src/llmq/chainlocks.cpp +++ b/src/llmq/chainlocks.cpp @@ -5,7 +5,6 @@ #include #include #include -#include #include #include diff --git a/src/llmq/commitment.cpp b/src/llmq/commitment.cpp index 2184f6ac58ca..c637a117dedf 100644 --- a/src/llmq/commitment.cpp +++ b/src/llmq/commitment.cpp @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -35,14 +36,14 @@ void LogPrintfFinalCommitment(Types... out) { bool CFinalCommitment::Verify(gsl::not_null pQuorumBaseBlockIndex, bool checkSigs) const { - const auto& llmq_params_opt = GetLLMQParams(llmqType); + const auto& llmq_params_opt = Params().GetLLMQ(llmqType); if (!llmq_params_opt.has_value()) { LogPrintfFinalCommitment("q[%s] invalid llmqType=%d\n", quorumHash.ToString(), ToUnderlying(llmqType)); return false; } const auto& llmq_params = llmq_params_opt.value(); - const uint16_t expected_nversion{CFinalCommitment::GetVersion(utils::IsQuorumRotationEnabled(llmq_params, pQuorumBaseBlockIndex), + const uint16_t expected_nversion{CFinalCommitment::GetVersion(IsQuorumRotationEnabled(llmq_params, pQuorumBaseBlockIndex), DeploymentActiveAfter(pQuorumBaseBlockIndex, Params().GetConsensus(), Consensus::DEPLOYMENT_V19))}; if (nVersion == 0 || nVersion != expected_nversion) { LogPrintfFinalCommitment("q[%s] invalid nVersion=%d expectednVersion\n", quorumHash.ToString(), nVersion, expected_nversion); @@ -111,7 +112,7 @@ bool CFinalCommitment::Verify(gsl::not_null pQuorumBaseBlock // sigs are only checked when the block is processed if (checkSigs) { - uint256 commitmentHash = utils::BuildCommitmentHash(llmq_params.type, quorumHash, validMembers, quorumPublicKey, quorumVvecHash); + uint256 commitmentHash = BuildCommitmentHash(llmq_params.type, quorumHash, validMembers, quorumPublicKey, quorumVvecHash); if (LogAcceptCategory(BCLog::LLMQ)) { std::stringstream ss3; for (const auto &mn: members) { @@ -146,7 +147,7 @@ bool CFinalCommitment::Verify(gsl::not_null pQuorumBaseBlock bool CFinalCommitment::VerifyNull() const { - const auto& llmq_params_opt = GetLLMQParams(llmqType); + const auto& llmq_params_opt = Params().GetLLMQ(llmqType); if (!llmq_params_opt.has_value()) { LogPrintfFinalCommitment("q[%s]invalid llmqType=%d\n", quorumHash.ToString(), ToUnderlying(llmqType)); return false; @@ -181,9 +182,9 @@ bool CheckLLMQCommitment(const CTransaction& tx, gsl::not_nullnHeight, ToUnderlying(qcTx.commitment.llmqType)); + LogPrintfFinalCommitment("h[%d] GetLLMQ failed for llmqType[%d]\n", pindexPrev->nHeight, ToUnderlying(qcTx.commitment.llmqType)); return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-qc-commitment-type"); } @@ -235,4 +236,17 @@ bool CheckLLMQCommitment(const CTransaction& tx, gsl::not_null& validMembers, const CBLSPublicKey& pubKey, + const uint256& vvecHash) +{ + CHashWriter hw(SER_GETHASH, 0); + hw << llmqType; + hw << blockHash; + hw << DYNBITSET(validMembers); + hw << pubKey; + hw << vvecHash; + return hw.GetHash(); +} + } // namespace llmq diff --git a/src/llmq/commitment.h b/src/llmq/commitment.h index 15a066ed5379..2355fc661980 100644 --- a/src/llmq/commitment.h +++ b/src/llmq/commitment.h @@ -173,6 +173,8 @@ class CFinalCommitmentTxPayload bool CheckLLMQCommitment(const CTransaction& tx, gsl::not_null pindexPrev, TxValidationState& state); +uint256 BuildCommitmentHash(Consensus::LLMQType llmqType, const uint256& blockHash, const std::vector& validMembers, const CBLSPublicKey& pubKey, const uint256& vvecHash); + } // namespace llmq #endif // BITCOIN_LLMQ_COMMITMENT_H diff --git a/src/llmq/context.cpp b/src/llmq/context.cpp index 834aa8063c85..78cd705b68b7 100644 --- a/src/llmq/context.cpp +++ b/src/llmq/context.cpp @@ -17,7 +17,6 @@ #include #include #include -#include #include LLMQContext::LLMQContext(CChainState& chainstate, CConnman& connman, CEvoDB& evo_db, CSporkManager& sporkman, CTxMemPool& mempool, diff --git a/src/llmq/debug.cpp b/src/llmq/debug.cpp index 6e4e5677c2c6..d6b272bd41c7 100644 --- a/src/llmq/debug.cpp +++ b/src/llmq/debug.cpp @@ -19,7 +19,7 @@ UniValue CDKGDebugSessionStatus::ToJson(int quorumIndex, int detailLevel) const { UniValue ret(UniValue::VOBJ); - if (!GetLLMQParams(llmqType).has_value() || quorumHash.IsNull()) { + if (!Params().GetLLMQ(llmqType).has_value() || quorumHash.IsNull()) { return ret; } @@ -118,7 +118,7 @@ UniValue CDKGDebugStatus::ToJson(int detailLevel) const // TODO Support array of sessions UniValue sessionsArrJson(UniValue::VARR); for (const auto& p : sessions) { - const auto& llmq_params_opt = GetLLMQParams(p.first.first); + const auto& llmq_params_opt = Params().GetLLMQ(p.first.first); if (!llmq_params_opt.has_value()) { continue; } diff --git a/src/llmq/dkgsession.cpp b/src/llmq/dkgsession.cpp index 943c28c6435a..000216e0eaf9 100644 --- a/src/llmq/dkgsession.cpp +++ b/src/llmq/dkgsession.cpp @@ -7,6 +7,8 @@ #include #include #include +#include +#include #include #include @@ -100,7 +102,7 @@ bool CDKGSession::Init(gsl::not_null _pQuorumBaseBlockIndex, CDKGLogger logger(*this, __func__); - if (LogAcceptCategory(BCLog::LLMQ) && utils::IsQuorumRotationEnabled(params, m_quorum_base_block_index)) { + if (LogAcceptCategory(BCLog::LLMQ) && IsQuorumRotationEnabled(params, m_quorum_base_block_index)) { int cycleQuorumBaseHeight = m_quorum_base_block_index->nHeight - quorumIndex; const CBlockIndex* pCycleQuorumBaseBlockIndex = m_quorum_base_block_index->GetAncestor(cycleQuorumBaseHeight); std::stringstream ss; @@ -448,7 +450,7 @@ void CDKGSession::VerifyAndComplain(CDKGPendingMessages& pendingMessages) void CDKGSession::VerifyConnectionAndMinProtoVersions() const { - if (!utils::IsQuorumPoseEnabled(params.type)) { + if (!IsQuorumPoseEnabled(params.type)) { return; } @@ -463,7 +465,7 @@ void CDKGSession::VerifyConnectionAndMinProtoVersions() const protoMap.emplace(verifiedProRegTxHash, pnode->nVersion); }); - bool fShouldAllMembersBeConnected = utils::IsAllMembersConnectedEnabled(params.type); + bool fShouldAllMembersBeConnected = IsAllMembersConnectedEnabled(params.type); for (const auto& m : members) { if (m->dmn->proTxHash == myProTxHash) { continue; @@ -995,7 +997,7 @@ void CDKGSession::SendCommitment(CDKGPendingMessages& pendingMessages) (*qc.quorumVvecHash.begin())++; } - uint256 commitmentHash = utils::BuildCommitmentHash(qc.llmqType, qc.quorumHash, qc.validMembers, qc.quorumPublicKey, qc.quorumVvecHash); + uint256 commitmentHash = BuildCommitmentHash(qc.llmqType, qc.quorumHash, qc.validMembers, qc.quorumPublicKey, qc.quorumVvecHash); if (lieType == 2) { (*commitmentHash.begin())++; @@ -1224,11 +1226,11 @@ std::vector CDKGSession::FinalizeCommitments() fqc.quorumPublicKey = first.quorumPublicKey; fqc.quorumVvecHash = first.quorumVvecHash; - const bool isQuorumRotationEnabled{utils::IsQuorumRotationEnabled(params, m_quorum_base_block_index)}; + const bool isQuorumRotationEnabled{IsQuorumRotationEnabled(params, m_quorum_base_block_index)}; fqc.nVersion = CFinalCommitment::GetVersion(isQuorumRotationEnabled, DeploymentActiveAfter(m_quorum_base_block_index, Params().GetConsensus(), Consensus::DEPLOYMENT_V19)); fqc.quorumIndex = isQuorumRotationEnabled ? quorumIndex : 0; - uint256 commitmentHash = utils::BuildCommitmentHash(fqc.llmqType, fqc.quorumHash, fqc.validMembers, fqc.quorumPublicKey, fqc.quorumVvecHash); + uint256 commitmentHash = BuildCommitmentHash(fqc.llmqType, fqc.quorumHash, fqc.validMembers, fqc.quorumPublicKey, fqc.quorumVvecHash); std::vector aggSigs; std::vector aggPks; diff --git a/src/llmq/dkgsession.h b/src/llmq/dkgsession.h index 04da988367fd..12fa48831d5d 100644 --- a/src/llmq/dkgsession.h +++ b/src/llmq/dkgsession.h @@ -10,14 +10,16 @@ #include #include -#include #include +#include #include class UniValue; class CInv; class CConnman; +class CDeterministicMN; +using CDeterministicMNCPtr = std::shared_ptr; namespace llmq { @@ -191,7 +193,7 @@ class CDKGPrematureCommitment [[nodiscard]] uint256 GetSignHash() const { - return utils::BuildCommitmentHash(llmqType, quorumHash, validMembers, quorumPublicKey, quorumVvecHash); + return BuildCommitmentHash(llmqType, quorumHash, validMembers, quorumPublicKey, quorumVvecHash); } }; diff --git a/src/llmq/dkgsessionhandler.cpp b/src/llmq/dkgsessionhandler.cpp index 4cbe4532b5a3..543526ffd1ac 100644 --- a/src/llmq/dkgsessionhandler.cpp +++ b/src/llmq/dkgsessionhandler.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -110,7 +111,7 @@ void CDKGSessionHandler::UpdatedBlockTip(const CBlockIndex* pindexNew) { //AssertLockNotHeld(cs_main); //Indexed quorums (greater than 0) are enabled with Quorum Rotation - if (quorumIndex > 0 && !utils::IsQuorumRotationEnabled(params, pindexNew)) { + if (quorumIndex > 0 && !IsQuorumRotationEnabled(params, pindexNew)) { return; } LOCK(cs); diff --git a/src/llmq/dkgsessionmgr.cpp b/src/llmq/dkgsessionmgr.cpp index 1bb62da95be6..2f94a4dc549b 100644 --- a/src/llmq/dkgsessionmgr.cpp +++ b/src/llmq/dkgsessionmgr.cpp @@ -4,7 +4,8 @@ #include #include -#include +#include +#include #include #include @@ -13,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -35,7 +37,7 @@ CDKGSessionManager::CDKGSessionManager(CBLSWorker& _blsWorker, CChainState& chai spork_manager(sporkManager), m_peerman(peerman) { - if (!fMasternodeMode && !utils::IsWatchQuorumsEnabled()) { + if (!fMasternodeMode && !IsWatchQuorumsEnabled()) { // Regular nodes do not care about any DKG internals, bail out return; } @@ -172,7 +174,7 @@ void CDKGSessionManager::UpdatedBlockTip(const CBlockIndex* pindexNew, bool fIni } } -void CDKGSessionManager::ProcessMessage(CNode& pfrom, const CQuorumManager& quorum_manager, const std::string& msg_type, CDataStream& vRecv) +void CDKGSessionManager::ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRecv) { static Mutex cs_indexedQuorumsCache; static std::map> indexedQuorumsCache GUARDED_BY(cs_indexedQuorumsCache); @@ -198,7 +200,7 @@ void CDKGSessionManager::ProcessMessage(CNode& pfrom, const CQuorumManager& quor return; } - if ((!fMasternodeMode && !utils::IsWatchQuorumsEnabled())) { + if ((!fMasternodeMode && !IsWatchQuorumsEnabled())) { // regular non-watching nodes should never receive any of these m_peerman->Misbehaving(pfrom.GetId(), 10); return; @@ -216,7 +218,7 @@ void CDKGSessionManager::ProcessMessage(CNode& pfrom, const CQuorumManager& quor vRecv.Rewind(sizeof(uint256)); vRecv.Rewind(sizeof(uint8_t)); - const auto& llmq_params_opt = GetLLMQParams(llmqType); + const auto& llmq_params_opt = Params().GetLLMQ(llmqType); if (!llmq_params_opt.has_value()) { LogPrintf("CDKGSessionManager -- invalid llmqType [%d]\n", ToUnderlying(llmqType)); m_peerman->Misbehaving(pfrom.GetId(), 100); @@ -245,14 +247,14 @@ void CDKGSessionManager::ProcessMessage(CNode& pfrom, const CQuorumManager& quor return; } - if (!utils::IsQuorumTypeEnabled(llmqType, quorum_manager, pQuorumBaseBlockIndex->pprev)) { + if (!IsQuorumTypeEnabled(llmqType, pQuorumBaseBlockIndex->pprev)) { LogPrintf("CDKGSessionManager -- llmqType [%d] quorums aren't active\n", ToUnderlying(llmqType)); m_peerman->Misbehaving(pfrom.GetId(), 100); return; } quorumIndex = pQuorumBaseBlockIndex->nHeight % llmq_params.dkgInterval; - int quorumIndexMax = utils::IsQuorumRotationEnabled(llmq_params, pQuorumBaseBlockIndex) ? + int quorumIndexMax = IsQuorumRotationEnabled(llmq_params, pQuorumBaseBlockIndex) ? llmq_params.signingActiveQuorumCount - 1 : 0; if (quorumIndex > quorumIndexMax) { @@ -496,7 +498,7 @@ void CDKGSessionManager::CleanupOldContributions() const } cnt_all++; const CBlockIndex* pindexQuorum = m_chainstate.m_blockman.LookupBlockIndex(std::get<2>(k)); - if (pindexQuorum == nullptr || m_chainstate.m_chain.Tip()->nHeight - pindexQuorum->nHeight > utils::max_store_depth(params)) { + if (pindexQuorum == nullptr || m_chainstate.m_chain.Tip()->nHeight - pindexQuorum->nHeight > params.max_store_depth()) { // not found or too old batch.Erase(k); cnt_old++; diff --git a/src/llmq/dkgsessionmgr.h b/src/llmq/dkgsessionmgr.h index e5db884bdbd5..ea72fc588b83 100644 --- a/src/llmq/dkgsessionmgr.h +++ b/src/llmq/dkgsessionmgr.h @@ -24,7 +24,6 @@ class UniValue; namespace llmq { -class CQuorumManager; class CDKGSessionManager { @@ -74,7 +73,7 @@ class CDKGSessionManager void UpdatedBlockTip(const CBlockIndex *pindexNew, bool fInitialDownload); - void ProcessMessage(CNode& pfrom, const CQuorumManager& quorum_manager, const std::string& msg_type, CDataStream& vRecv); + void ProcessMessage(CNode& pfrom, const std::string& msg_type, CDataStream& vRecv); bool AlreadyHave(const CInv& inv) const; bool GetContribution(const uint256& hash, CDKGContribution& ret) const; bool GetComplaint(const uint256& hash, CDKGComplaint& ret) const; diff --git a/src/llmq/ehf_signals.cpp b/src/llmq/ehf_signals.cpp index 697b6a9d0753..343020c389ae 100644 --- a/src/llmq/ehf_signals.cpp +++ b/src/llmq/ehf_signals.cpp @@ -6,11 +6,11 @@ #include #include #include -#include #include #include +#include #include #include #include // g_txindex @@ -65,7 +65,7 @@ void CEHFSignalsHandler::trySignEHFSignal(int bit, const CBlockIndex* const pind const uint256 requestId = mnhfPayload.GetRequestId(); const Consensus::LLMQType& llmqType = Params().GetConsensus().llmqTypeMnhf; - const auto& llmq_params_opt = llmq::GetLLMQParams(llmqType); + const auto& llmq_params_opt = Params().GetLLMQ(llmqType); if (!llmq_params_opt.has_value()) { return; } diff --git a/src/llmq/instantsend.cpp b/src/llmq/instantsend.cpp index e44d4e7a6249..c5e3227b43b7 100644 --- a/src/llmq/instantsend.cpp +++ b/src/llmq/instantsend.cpp @@ -5,9 +5,8 @@ #include #include -#include -#include #include +#include #include #include @@ -694,7 +693,7 @@ void CInstantSendManager::TrySignInstantSendLock(const CTransaction& tx) } { - const auto &llmq_params_opt = GetLLMQParams(llmqType); + const auto &llmq_params_opt = Params().GetLLMQ(llmqType); assert(llmq_params_opt); LOCK(cs_main); const auto dkgInterval = llmq_params_opt->dkgInterval; @@ -785,7 +784,7 @@ void CInstantSendManager::ProcessMessageInstantSendLock(const CNode& pfrom, cons // Deterministic islocks MUST use rotation based llmq auto llmqType = Params().GetConsensus().llmqTypeDIP0024InstantSend; - const auto& llmq_params_opt = GetLLMQParams(llmqType); + const auto& llmq_params_opt = Params().GetLLMQ(llmqType); assert(llmq_params_opt); if (blockIndex->nHeight % llmq_params_opt->dkgInterval != 0) { m_peerman->Misbehaving(pfrom.GetId(), 100); @@ -864,7 +863,7 @@ bool CInstantSendManager::ProcessPendingInstantSendLocks() //TODO Investigate if leaving this is ok auto llmqType = Params().GetConsensus().llmqTypeDIP0024InstantSend; - const auto& llmq_params_opt = GetLLMQParams(llmqType); + const auto& llmq_params_opt = Params().GetLLMQ(llmqType); assert(llmq_params_opt); const auto& llmq_params = llmq_params_opt.value(); auto dkgInterval = llmq_params.dkgInterval; @@ -935,7 +934,7 @@ std::unordered_set CInstantSendManager::ProcessPend // should not happen, but if one fails to select, all others will also fail to select return {}; } - uint256 signHash = utils::BuildSignHash(llmq_params.type, quorum->qc->quorumHash, id, islock->txid); + uint256 signHash = BuildSignHash(llmq_params.type, quorum->qc->quorumHash, id, islock->txid); batchVerifier.PushMessage(nodeId, hash, signHash, islock->sig.Get(), quorum->qc->quorumPublicKey); verifyCount++; diff --git a/src/llmq/options.cpp b/src/llmq/options.cpp new file mode 100644 index 000000000000..447e1dc160b0 --- /dev/null +++ b/src/llmq/options.cpp @@ -0,0 +1,189 @@ +// Copyright (c) 2018-2023 The Dash Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +static constexpr int TESTNET_LLMQ_25_67_ACTIVATION_HEIGHT = 847000; + +namespace llmq +{ + +static bool EvalSpork(Consensus::LLMQType llmqType, int64_t spork_value) +{ + if (spork_value == 0) { + return true; + } + if (spork_value == 1 && llmqType != Consensus::LLMQType::LLMQ_100_67 && llmqType != Consensus::LLMQType::LLMQ_400_60 && llmqType != Consensus::LLMQType::LLMQ_400_85) { + return true; + } + return false; +} + +bool IsAllMembersConnectedEnabled(Consensus::LLMQType llmqType) +{ + return EvalSpork(llmqType, sporkManager->GetSporkValue(SPORK_21_QUORUM_ALL_CONNECTED)); +} + +bool IsQuorumPoseEnabled(Consensus::LLMQType llmqType) +{ + return EvalSpork(llmqType, sporkManager->GetSporkValue(SPORK_23_QUORUM_POSE)); +} + + +bool IsQuorumRotationEnabled(const Consensus::LLMQParams& llmqParams, gsl::not_null pindex) +{ + if (!llmqParams.useRotation) { + return false; + } + + int cycleQuorumBaseHeight = pindex->nHeight - (pindex->nHeight % llmqParams.dkgInterval); + if (cycleQuorumBaseHeight < 1) { + return false; + } + // It should activate at least 1 block prior to the cycle start + return DeploymentActiveAfter(pindex->GetAncestor(cycleQuorumBaseHeight - 1), Params().GetConsensus(), Consensus::DEPLOYMENT_DIP0024); +} + +bool QuorumDataRecoveryEnabled() +{ + return gArgs.GetBoolArg("-llmq-data-recovery", DEFAULT_ENABLE_QUORUM_DATA_RECOVERY); +} + +bool IsWatchQuorumsEnabled() +{ + static bool fIsWatchQuroumsEnabled = gArgs.GetBoolArg("-watchquorums", DEFAULT_WATCH_QUORUMS); + return fIsWatchQuroumsEnabled; +} + +std::map GetEnabledQuorumVvecSyncEntries() +{ + std::map mapQuorumVvecSyncEntries; + for (const auto& strEntry : gArgs.GetArgs("-llmq-qvvec-sync")) { + Consensus::LLMQType llmqType = Consensus::LLMQType::LLMQ_NONE; + QvvecSyncMode mode{QvvecSyncMode::Invalid}; + std::istringstream ssEntry(strEntry); + std::string strLLMQType, strMode, strTest; + const bool fLLMQTypePresent = std::getline(ssEntry, strLLMQType, ':') && strLLMQType != ""; + const bool fModePresent = std::getline(ssEntry, strMode, ':') && strMode != ""; + const bool fTooManyEntries = static_cast(std::getline(ssEntry, strTest, ':')); + if (!fLLMQTypePresent || !fModePresent || fTooManyEntries) { + throw std::invalid_argument(strprintf("Invalid format in -llmq-qvvec-sync: %s", strEntry)); + } + + if (auto optLLMQParams = ranges::find_if_opt(Params().GetConsensus().llmqs, + [&strLLMQType](const auto& params){return params.name == strLLMQType;})) { + llmqType = optLLMQParams->type; + } else { + throw std::invalid_argument(strprintf("Invalid llmqType in -llmq-qvvec-sync: %s", strEntry)); + } + if (mapQuorumVvecSyncEntries.count(llmqType) > 0) { + throw std::invalid_argument(strprintf("Duplicated llmqType in -llmq-qvvec-sync: %s", strEntry)); + } + + int32_t nMode; + if (ParseInt32(strMode, &nMode)) { + switch (nMode) { + case (int32_t)QvvecSyncMode::Always: + mode = QvvecSyncMode::Always; + break; + case (int32_t)QvvecSyncMode::OnlyIfTypeMember: + mode = QvvecSyncMode::OnlyIfTypeMember; + break; + default: + mode = QvvecSyncMode::Invalid; + break; + } + } + if (mode == QvvecSyncMode::Invalid) { + throw std::invalid_argument(strprintf("Invalid mode in -llmq-qvvec-sync: %s", strEntry)); + } + mapQuorumVvecSyncEntries.emplace(llmqType, mode); + } + return mapQuorumVvecSyncEntries; +} + +bool IsQuorumTypeEnabled(Consensus::LLMQType llmqType, gsl::not_null pindexPrev) +{ + return IsQuorumTypeEnabledInternal(llmqType, pindexPrev, std::nullopt); +} + +bool IsQuorumTypeEnabledInternal(Consensus::LLMQType llmqType, gsl::not_null pindexPrev, + std::optional optDIP0024IsActive) +{ + const Consensus::Params& consensusParams = Params().GetConsensus(); + + const bool fDIP0024IsActive{optDIP0024IsActive.value_or(DeploymentActiveAfter(pindexPrev, consensusParams, Consensus::DEPLOYMENT_DIP0024))}; + switch (llmqType) + { + case Consensus::LLMQType::LLMQ_DEVNET: + return true; + case Consensus::LLMQType::LLMQ_50_60: + if (Params().NetworkIDString() == CBaseChainParams::TESTNET) return true; + // fall through + case Consensus::LLMQType::LLMQ_TEST_INSTANTSEND: + return !fDIP0024IsActive; + + case Consensus::LLMQType::LLMQ_TEST: + case Consensus::LLMQType::LLMQ_TEST_PLATFORM: + case Consensus::LLMQType::LLMQ_400_60: + case Consensus::LLMQType::LLMQ_400_85: + case Consensus::LLMQType::LLMQ_DEVNET_PLATFORM: + return true; + + case Consensus::LLMQType::LLMQ_TEST_V17: { + return DeploymentActiveAfter(pindexPrev, consensusParams, Consensus::DEPLOYMENT_TESTDUMMY); + } + case Consensus::LLMQType::LLMQ_100_67: + return DeploymentActiveAfter(pindexPrev, consensusParams, Consensus::DEPLOYMENT_DIP0020); + + case Consensus::LLMQType::LLMQ_60_75: + case Consensus::LLMQType::LLMQ_DEVNET_DIP0024: + case Consensus::LLMQType::LLMQ_TEST_DIP0024: { + return fDIP0024IsActive; + } + case Consensus::LLMQType::LLMQ_25_67: + return pindexPrev->nHeight >= TESTNET_LLMQ_25_67_ACTIVATION_HEIGHT; + + default: + throw std::runtime_error(strprintf("%s: Unknown LLMQ type %d", __func__, ToUnderlying(llmqType))); + } + + // Something wrong with conditions above, they are not consistent + assert(false); +} + +std::vector GetEnabledQuorumTypes(gsl::not_null pindex) +{ + std::vector ret; + ret.reserve(Params().GetConsensus().llmqs.size()); + for (const auto& params : Params().GetConsensus().llmqs) { + if (IsQuorumTypeEnabled(params.type, pindex)) { + ret.push_back(params.type); + } + } + return ret; +} + +std::vector> GetEnabledQuorumParams(gsl::not_null pindex) +{ + std::vector> ret; + ret.reserve(Params().GetConsensus().llmqs.size()); + + std::copy_if(Params().GetConsensus().llmqs.begin(), Params().GetConsensus().llmqs.end(), std::back_inserter(ret), + [&pindex](const auto& params){return IsQuorumTypeEnabled(params.type, pindex);}); + + return ret; +} +} // namespace llmq diff --git a/src/llmq/options.h b/src/llmq/options.h new file mode 100644 index 000000000000..17e85dc0f113 --- /dev/null +++ b/src/llmq/options.h @@ -0,0 +1,53 @@ +// Copyright (c) 2018-2023 The Dash Core developers +// Distributed under the MIT software license, see the accompanying +// file COPYING or http://www.opensource.org/licenses/mit-license.php. + +#ifndef BITCOIN_LLMQ_OPTIONS_H +#define BITCOIN_LLMQ_OPTIONS_H + +#include +#include + +#include +#include +#include + +class CBlockIndex; + +namespace llmq +{ + +enum class QvvecSyncMode { + Invalid = -1, + Always = 0, + OnlyIfTypeMember = 1, +}; + +static constexpr bool DEFAULT_ENABLE_QUORUM_DATA_RECOVERY{true}; + +// If true, we will connect to all new quorums and watch their communication +static constexpr bool DEFAULT_WATCH_QUORUMS{false}; + +bool IsAllMembersConnectedEnabled(Consensus::LLMQType llmqType); +bool IsQuorumPoseEnabled(Consensus::LLMQType llmqType); + +bool IsQuorumRotationEnabled(const Consensus::LLMQParams& llmqParams, gsl::not_null pindex); + +/// Returns the state of `-llmq-data-recovery` +bool QuorumDataRecoveryEnabled(); + +/// Returns the state of `-watchquorums` +bool IsWatchQuorumsEnabled(); + +/// Returns the parsed entries given by `-llmq-qvvec-sync` +std::map GetEnabledQuorumVvecSyncEntries(); + +bool IsQuorumTypeEnabled(Consensus::LLMQType llmqType, gsl::not_null pindexPrev); +bool IsQuorumTypeEnabledInternal(Consensus::LLMQType llmqType, gsl::not_null pindexPrev, std::optional optDIP0024IsActive); + +std::vector GetEnabledQuorumTypes(gsl::not_null pindex); +std::vector> GetEnabledQuorumParams(gsl::not_null pindex); + +} // namespace llmq + +#endif // BITCOIN_LLMQ_OPTIONS_H diff --git a/src/llmq/params.h b/src/llmq/params.h index 4d2cfae9e0f2..69fddfac0220 100644 --- a/src/llmq/params.h +++ b/src/llmq/params.h @@ -113,6 +113,18 @@ struct LLMQParams { // How many members should we try to send all sigShares to before we give up. int recoveryMembers; +public: + + [[ nodiscard ]] constexpr int max_cycles(int quorums_count) const + { + return useRotation ? quorums_count / signingActiveQuorumCount : quorums_count; + } + + // For how many blocks recent DKG info should be kept + [[ nodiscard ]] constexpr int max_store_depth() const + { + return max_cycles(keepOldKeys) * dkgInterval; + } }; //static_assert(std::is_trivial_v, "LLMQParams is not a trivial type"); diff --git a/src/llmq/quorums.cpp b/src/llmq/quorums.cpp index 1df6594f8779..6e99b231e7ba 100644 --- a/src/llmq/quorums.cpp +++ b/src/llmq/quorums.cpp @@ -7,6 +7,8 @@ #include #include #include +#include +#include #include #include @@ -218,11 +220,11 @@ void CQuorumManager::Stop() void CQuorumManager::TriggerQuorumDataRecoveryThreads(const CBlockIndex* pIndex) const { - if ((!fMasternodeMode && !utils::IsWatchQuorumsEnabled()) || !utils::QuorumDataRecoveryEnabled() || pIndex == nullptr) { + if ((!fMasternodeMode && !IsWatchQuorumsEnabled()) || !QuorumDataRecoveryEnabled() || pIndex == nullptr) { return; } - const std::map mapQuorumVvecSync = utils::GetEnabledQuorumVvecSyncEntries(); + const std::map mapQuorumVvecSync = GetEnabledQuorumVvecSyncEntries(); LogPrint(BCLog::LLMQ, "CQuorumManager::%s -- Process block %s\n", __func__, pIndex->GetBlockHash().ToString()); @@ -275,7 +277,7 @@ void CQuorumManager::UpdatedBlockTip(const CBlockIndex* pindexNew, bool fInitial CheckQuorumConnections(params, pindexNew); } - if (fMasternodeMode || utils::IsWatchQuorumsEnabled()) { + if (fMasternodeMode || IsWatchQuorumsEnabled()) { // Cleanup expired data requests LOCK(cs_data_requests); auto it = mapQuorumDataRequests.begin(); @@ -294,14 +296,14 @@ void CQuorumManager::UpdatedBlockTip(const CBlockIndex* pindexNew, bool fInitial void CQuorumManager::CheckQuorumConnections(const Consensus::LLMQParams& llmqParams, const CBlockIndex* pindexNew) const { - if (!fMasternodeMode && !utils::IsWatchQuorumsEnabled()) return; + if (!fMasternodeMode && !IsWatchQuorumsEnabled()) return; auto lastQuorums = ScanQuorums(llmqParams.type, pindexNew, (size_t)llmqParams.keepOldConnections); auto connmanQuorumsToDelete = connman.GetMasternodeQuorums(llmqParams.type); // don't remove connections for the currently in-progress DKG round - if (utils::IsQuorumRotationEnabled(llmqParams, pindexNew)) { + if (IsQuorumRotationEnabled(llmqParams, pindexNew)) { int cycleIndexTipHeight = pindexNew->nHeight % llmqParams.dkgInterval; int cycleQuorumBaseHeight = pindexNew->nHeight - cycleIndexTipHeight; std::stringstream ss; @@ -369,7 +371,7 @@ CQuorumPtr CQuorumManager::BuildQuorumFromCommitment(const Consensus::LLMQType l } assert(qc->quorumHash == pQuorumBaseBlockIndex->GetBlockHash()); - const auto& llmq_params_opt = GetLLMQParams(llmqType); + const auto& llmq_params_opt = Params().GetLLMQ(llmqType); assert(llmq_params_opt.has_value()); auto quorum = std::make_shared(llmq_params_opt.value(), blsWorker); auto members = utils::GetAllQuorumMembers(qc->llmqType, pQuorumBaseBlockIndex); @@ -451,7 +453,7 @@ bool CQuorumManager::RequestQuorumData(CNode* pfrom, Consensus::LLMQType llmqTyp LogPrint(BCLog::LLMQ, "CQuorumManager::%s -- pfrom is not a verified masternode\n", __func__); return false; } - if (!GetLLMQParams(llmqType).has_value()) { + if (!Params().GetLLMQ(llmqType).has_value()) { LogPrint(BCLog::LLMQ, "CQuorumManager::%s -- Invalid llmqType: %d\n", __func__, ToUnderlying(llmqType)); return false; } @@ -493,12 +495,12 @@ std::vector CQuorumManager::ScanQuorums(Consensus::LLMQType llmqTyp std::vector CQuorumManager::ScanQuorums(Consensus::LLMQType llmqType, const CBlockIndex* pindexStart, size_t nCountRequested) const { - if (pindexStart == nullptr || nCountRequested == 0 || !utils::IsQuorumTypeEnabled(llmqType, *this, pindexStart)) { + if (pindexStart == nullptr || nCountRequested == 0 || !IsQuorumTypeEnabled(llmqType, pindexStart)) { return {}; } gsl::not_null pindexStore{pindexStart}; - const auto& llmq_params_opt = GetLLMQParams(llmqType); + const auto& llmq_params_opt = Params().GetLLMQ(llmqType); assert(llmq_params_opt.has_value()); // Quorum sets can only change during the mining phase of DKG. @@ -531,7 +533,7 @@ std::vector CQuorumManager::ScanQuorums(Consensus::LLMQType llmqTyp // And we only do this for max_cycles() of the most recent quorums // because signing by old quorums requires the exact quorum hash to be specified // and quorum scanning isn't needed there. - scanQuorumsCache.try_emplace(llmq.type, utils::max_cycles(llmq, llmq.keepOldConnections) * (llmq.dkgMiningWindowEnd - llmq.dkgMiningWindowStart)); + scanQuorumsCache.try_emplace(llmq.type, llmq.max_cycles(llmq.keepOldConnections) * (llmq.dkgMiningWindowEnd - llmq.dkgMiningWindowStart)); } } auto& cache = scanQuorumsCache[llmqType]; @@ -699,7 +701,7 @@ PeerMsgRet CQuorumManager::ProcessMessage(CNode& pfrom, const std::string& msg_t } } - if (!GetLLMQParams(request.GetLLMQType()).has_value()) { + if (!Params().GetLLMQ(request.GetLLMQType()).has_value()) { return sendQDATA(CQuorumDataRequest::Errors::QUORUM_TYPE_INVALID, request_limit_exceeded); } @@ -744,7 +746,7 @@ PeerMsgRet CQuorumManager::ProcessMessage(CNode& pfrom, const std::string& msg_t } if (msg_type == NetMsgType::QDATA) { - if ((!fMasternodeMode && !utils::IsWatchQuorumsEnabled()) || pfrom.GetVerifiedProRegTxHash().IsNull()) { + if ((!fMasternodeMode && !IsWatchQuorumsEnabled()) || pfrom.GetVerifiedProRegTxHash().IsNull()) { return errorHandler("Not a verified masternode and -watchquorums is not enabled"); } @@ -1033,7 +1035,7 @@ void CQuorumManager::StartCleanupOldQuorumDataThread(const CBlockIndex* pIndex) // window and it's better to have more room so we pick next cycle. // dkgMiningWindowStart for small quorums is 10 i.e. a safe block to start // these calculations is at height 576 + 24 * 2 + 10 = 576 + 58. - if ((!fMasternodeMode && !utils::IsWatchQuorumsEnabled()) || pIndex == nullptr || (pIndex->nHeight % 576 != 58)) { + if ((!fMasternodeMode && !IsWatchQuorumsEnabled()) || pIndex == nullptr || (pIndex->nHeight % 576 != 58)) { return; } @@ -1055,7 +1057,7 @@ void CQuorumManager::StartCleanupOldQuorumDataThread(const CBlockIndex* pIndex) auto& cache = cleanupQuorumsCache[params.type]; const CBlockIndex* pindex_loop{pIndex}; std::set quorum_keys; - while (pindex_loop != nullptr && pIndex->nHeight - pindex_loop->nHeight < utils::max_store_depth(params)) { + while (pindex_loop != nullptr && pIndex->nHeight - pindex_loop->nHeight < params.max_store_depth()) { uint256 quorum_key; if (cache.get(pindex_loop->GetBlockHash(), quorum_key)) { quorum_keys.insert(quorum_key); diff --git a/src/llmq/quorums.h b/src/llmq/quorums.h index ba009e0de5af..1605271b77a3 100644 --- a/src/llmq/quorums.h +++ b/src/llmq/quorums.h @@ -35,9 +35,6 @@ namespace llmq class CDKGSessionManager; class CQuorumBlockProcessor; -// If true, we will connect to all new quorums and watch their communication -static constexpr bool DEFAULT_WATCH_QUORUMS{false}; - /** * Object used as a key to store CQuorumDataRequest */ diff --git a/src/llmq/signing.cpp b/src/llmq/signing.cpp index 97e9019da768..b47cb2483dea 100644 --- a/src/llmq/signing.cpp +++ b/src/llmq/signing.cpp @@ -4,15 +4,16 @@ #include -#include #include -#include +#include +#include #include #include #include #include #include +#include #include #include #include @@ -564,7 +565,7 @@ bool CSigningManager::GetRecoveredSigForGetData(const uint256& hash, CRecoveredS if (!db.GetRecoveredSigByHash(hash, ret)) { return false; } - if (!utils::IsQuorumActive(ret.getLlmqType(), qman, ret.getQuorumHash())) { + if (!IsQuorumActive(ret.getLlmqType(), qman, ret.getQuorumHash())) { // we don't want to propagate sigs from inactive quorums return false; } @@ -619,7 +620,7 @@ bool CSigningManager::PreVerifyRecoveredSig(const CQuorumManager& quorum_manager retBan = false; auto llmqType = recoveredSig.getLlmqType(); - if (!GetLLMQParams(llmqType).has_value()) { + if (!Params().GetLLMQ(llmqType).has_value()) { retBan = true; return false; } @@ -631,7 +632,7 @@ bool CSigningManager::PreVerifyRecoveredSig(const CQuorumManager& quorum_manager recoveredSig.getQuorumHash().ToString()); return false; } - if (!utils::IsQuorumActive(llmqType, quorum_manager, quorum->qc->quorumHash)) { + if (!IsQuorumActive(llmqType, quorum_manager, quorum->qc->quorumHash)) { return false; } @@ -649,8 +650,9 @@ void CSigningManager::CollectPendingRecoveredSigsToVerify( return; } + // TODO: refactor it to remove duplicated code with `CSigSharesManager::CollectPendingSigSharesToVerify` std::unordered_set, StaticSaltedHasher> uniqueSignHashes; - utils::IterateNodesRandom(pendingRecoveredSigs, [&]() { + IterateNodesRandom(pendingRecoveredSigs, [&]() { return uniqueSignHashes.size() < maxUniqueSessions; }, [&](NodeId nodeId, std::list>& ns) { if (ns.empty()) { @@ -689,7 +691,7 @@ void CSigningManager::CollectPendingRecoveredSigsToVerify( it = v.erase(it); continue; } - if (!utils::IsQuorumActive(llmqType, qman, quorum->qc->quorumHash)) { + if (!IsQuorumActive(llmqType, qman, quorum->qc->quorumHash)) { LogPrint(BCLog::LLMQ, "CSigningManager::%s -- quorum %s not active anymore, node=%d\n", __func__, recSig->getQuorumHash().ToString(), nodeId); it = v.erase(it); @@ -894,7 +896,7 @@ bool CSigningManager::AsyncSignIfMember(Consensus::LLMQType llmqType, CSigShares // This gives a slight risk of not getting enough shares to recover a signature // But at least it shouldn't be possible to get conflicting recovered signatures // TODO fix this by re-signing when the next block arrives, but only when that block results in a change of the quorum list and no recovered signature has been created in the mean time - const auto& llmq_params_opt = GetLLMQParams(llmqType); + const auto& llmq_params_opt = Params().GetLLMQ(llmqType); assert(llmq_params_opt.has_value()); quorum = SelectQuorumForSigning(llmq_params_opt.value(), qman, id); } else { @@ -1010,7 +1012,7 @@ CQuorumCPtr CSigningManager::SelectQuorumForSigning(const Consensus::LLMQParams& pindexStart = ::ChainActive()[startBlockHeight]; } - if (utils::IsQuorumRotationEnabled(llmq_params, pindexStart)) { + if (IsQuorumRotationEnabled(llmq_params, pindexStart)) { auto quorums = quorum_manager.ScanQuorums(llmq_params.type, pindexStart, poolSize); if (quorums.empty()) { return nullptr; @@ -1056,21 +1058,41 @@ CQuorumCPtr CSigningManager::SelectQuorumForSigning(const Consensus::LLMQParams& bool CSigningManager::VerifyRecoveredSig(Consensus::LLMQType llmqType, const CQuorumManager& quorum_manager, int signedAtHeight, const uint256& id, const uint256& msgHash, const CBLSSignature& sig, const int signOffset) { - const auto& llmq_params_opt = GetLLMQParams(llmqType); + const auto& llmq_params_opt = Params().GetLLMQ(llmqType); assert(llmq_params_opt.has_value()); auto quorum = SelectQuorumForSigning(llmq_params_opt.value(), quorum_manager, id, signedAtHeight, signOffset); if (!quorum) { return false; } - uint256 signHash = utils::BuildSignHash(llmqType, quorum->qc->quorumHash, id, msgHash); + uint256 signHash = BuildSignHash(llmqType, quorum->qc->quorumHash, id, msgHash); return sig.VerifyInsecure(quorum->qc->quorumPublicKey, signHash); } uint256 CSigBase::buildSignHash() const { - return utils::BuildSignHash(llmqType, quorumHash, id, msgHash); + return BuildSignHash(llmqType, quorumHash, id, msgHash); +} + +uint256 BuildSignHash(Consensus::LLMQType llmqType, const uint256& quorumHash, const uint256& id, const uint256& msgHash) +{ + CHashWriter h(SER_GETHASH, 0); + h << llmqType; + h << quorumHash; + h << id; + h << msgHash; + return h.GetHash(); } +bool IsQuorumActive(Consensus::LLMQType llmqType, const CQuorumManager& qman, const uint256& quorumHash) +{ + // sig shares and recovered sigs are only accepted from recent/active quorums + // we allow one more active quorum as specified in consensus, as otherwise there is a small window where things could + // fail while we are on the brink of a new quorum + const auto& llmq_params_opt = Params().GetLLMQ(llmqType); + assert(llmq_params_opt.has_value()); + auto quorums = qman.ScanQuorums(llmqType, llmq_params_opt->keepOldConnections); + return ranges::any_of(quorums, [&quorumHash](const auto& q){ return q->qc->quorumHash == quorumHash; }); +} } // namespace llmq diff --git a/src/llmq/signing.h b/src/llmq/signing.h index 1849b4899bc6..cf1eb54cfe6b 100644 --- a/src/llmq/signing.h +++ b/src/llmq/signing.h @@ -232,6 +232,41 @@ class CSigningManager // Verifies a recovered sig that was signed while the chain tip was at signedAtTip static bool VerifyRecoveredSig(Consensus::LLMQType llmqType, const CQuorumManager& quorum_manager, int signedAtHeight, const uint256& id, const uint256& msgHash, const CBLSSignature& sig, int signOffset = SIGN_HEIGHT_OFFSET); }; + +template +void IterateNodesRandom(NodesContainer& nodeStates, Continue&& cont, Callback&& callback, FastRandomContext& rnd) +{ + std::vector rndNodes; + rndNodes.reserve(nodeStates.size()); + for (auto it = nodeStates.begin(); it != nodeStates.end(); ++it) { + rndNodes.emplace_back(it); + } + if (rndNodes.empty()) { + return; + } + Shuffle(rndNodes.begin(), rndNodes.end(), rnd); + + size_t idx = 0; + while (!rndNodes.empty() && cont()) { + auto nodeId = rndNodes[idx]->first; + auto& ns = rndNodes[idx]->second; + + if (callback(nodeId, ns)) { + idx = (idx + 1) % rndNodes.size(); + } else { + rndNodes.erase(rndNodes.begin() + idx); + if (rndNodes.empty()) { + break; + } + idx %= rndNodes.size(); + } + } +} + +uint256 BuildSignHash(Consensus::LLMQType llmqType, const uint256& quorumHash, const uint256& id, const uint256& msgHash); + +bool IsQuorumActive(Consensus::LLMQType llmqType, const CQuorumManager& qman, const uint256& quorumHash); + } // namespace llmq #endif // BITCOIN_LLMQ_SIGNING_H diff --git a/src/llmq/signing_shares.cpp b/src/llmq/signing_shares.cpp index b69678473873..7567da2bf31a 100644 --- a/src/llmq/signing_shares.cpp +++ b/src/llmq/signing_shares.cpp @@ -4,10 +4,10 @@ #include +#include #include #include #include -#include #include #include @@ -99,7 +99,7 @@ std::string CBatchedSigShares::ToInvString() const static void InitSession(CSigSharesNodeState::Session& s, const uint256& signHash, CSigBase from) { - const auto& llmq_params_opt = GetLLMQParams(from.getLlmqType()); + const auto& llmq_params_opt = Params().GetLLMQ(from.getLlmqType()); assert(llmq_params_opt.has_value()); const auto& llmq_params = llmq_params_opt.value(); @@ -299,7 +299,7 @@ void CSigSharesManager::ProcessMessage(const CNode& pfrom, const CSporkManager& bool CSigSharesManager::ProcessMessageSigSesAnn(const CNode& pfrom, const CSigSesAnn& ann) { auto llmqType = ann.getLlmqType(); - if (!GetLLMQParams(llmqType).has_value()) { + if (!Params().GetLLMQ(llmqType).has_value()) { return false; } if (ann.getSessionId() == UNINITIALIZED_SESSION_ID || ann.getQuorumHash().IsNull() || ann.getId().IsNull() || ann.getMsgHash().IsNull()) { @@ -330,7 +330,7 @@ bool CSigSharesManager::ProcessMessageSigSesAnn(const CNode& pfrom, const CSigSe bool CSigSharesManager::VerifySigSharesInv(Consensus::LLMQType llmqType, const CSigSharesInv& inv) { - const auto& llmq_params_opt = GetLLMQParams(llmqType); + const auto& llmq_params_opt = Params().GetLLMQ(llmqType); return llmq_params_opt.has_value() && (inv.inv.size() == size_t(llmq_params_opt->size)); } @@ -461,7 +461,7 @@ void CSigSharesManager::ProcessMessageSigShare(NodeId fromId, const CSigShare& s if (!quorum) { return; } - if (!utils::IsQuorumActive(sigShare.getLlmqType(), qman, quorum->qc->quorumHash)) { + if (!IsQuorumActive(sigShare.getLlmqType(), qman, quorum->qc->quorumHash)) { // quorum is too old return; } @@ -510,7 +510,7 @@ bool CSigSharesManager::PreVerifyBatchedSigShares(const CQuorumManager& quorum_m { retBan = false; - if (!utils::IsQuorumActive(session.llmqType, quorum_manager, session.quorum->qc->quorumHash)) { + if (!IsQuorumActive(session.llmqType, quorum_manager, session.quorum->qc->quorumHash)) { // quorum is too old return false; } @@ -565,7 +565,7 @@ void CSigSharesManager::CollectPendingSigSharesToVerify( // the whole verification process std::unordered_set, StaticSaltedHasher> uniqueSignHashes; - utils::IterateNodesRandom(nodeStates, [&]() { + IterateNodesRandom(nodeStates, [&]() { return uniqueSignHashes.size() < maxUniqueSessions; }, [&](NodeId nodeId, CSigSharesNodeState& ns) { if (ns.pendingIncomingSigShares.Empty()) { @@ -698,7 +698,7 @@ void CSigSharesManager::ProcessSigShare(const CSigShare& sigShare, const CConnma // prepare node set for direct-push in case this is our sig share std::set quorumNodes; - if (!utils::IsAllMembersConnectedEnabled(llmqType) && sigShare.getQuorumMember() == quorum->GetMemberIndex(WITH_LOCK(activeMasternodeInfoCs, return activeMasternodeInfo.proTxHash))) { + if (!IsAllMembersConnectedEnabled(llmqType) && sigShare.getQuorumMember() == quorum->GetMemberIndex(WITH_LOCK(activeMasternodeInfoCs, return activeMasternodeInfo.proTxHash))) { quorumNodes = connman.GetMasternodeQuorumNodes(sigShare.getLlmqType(), sigShare.getQuorumHash()); } @@ -712,7 +712,7 @@ void CSigSharesManager::ProcessSigShare(const CSigShare& sigShare, const CConnma if (!sigShares.Add(sigShare.GetKey(), sigShare)) { return; } - if (!utils::IsAllMembersConnectedEnabled(llmqType)) { + if (!IsAllMembersConnectedEnabled(llmqType)) { sigSharesQueuedToAnnounce.Add(sigShare.GetKey(), true); } @@ -753,7 +753,7 @@ void CSigSharesManager::TryRecoverSig(const CQuorumCPtr& quorum, const uint256& { LOCK(cs); - auto signHash = utils::BuildSignHash(quorum->params.type, quorum->qc->quorumHash, id, msgHash); + auto signHash = BuildSignHash(quorum->params.type, quorum->qc->quorumHash, id, msgHash); const auto* sigSharesForSignHash = sigShares.GetAllForSignHash(signHash); if (sigSharesForSignHash == nullptr) { return; @@ -857,7 +857,7 @@ void CSigSharesManager::CollectSigSharesToRequest(std::unordered_mapsecond)* invMap = nullptr; for (auto& [signHash, session] : nodeState.sessions) { - if (utils::IsAllMembersConnectedEnabled(session.llmqType)) { + if (IsAllMembersConnectedEnabled(session.llmqType)) { continue; } @@ -903,7 +903,7 @@ void CSigSharesManager::CollectSigSharesToRequest(std::unordered_mapsize); } @@ -928,7 +928,7 @@ void CSigSharesManager::CollectSigSharesToSend(std::unordered_mapsecond)* sigSharesToSend2 = nullptr; for (auto& [signHash, session] : nodeState.sessions) { - if (utils::IsAllMembersConnectedEnabled(session.llmqType)) { + if (IsAllMembersConnectedEnabled(session.llmqType)) { continue; } @@ -982,7 +982,7 @@ void CSigSharesManager::CollectSigSharesToSendConcentrated(std::unordered_map().count(); for (auto& [_, signedSession] : signedSessions) { - if (!utils::IsAllMembersConnectedEnabled(signedSession.quorum->params.type)) { + if (!IsAllMembersConnectedEnabled(signedSession.quorum->params.type)) { continue; } @@ -1052,7 +1052,7 @@ void CSigSharesManager::CollectSigSharesToAnnounce(std::unordered_mapgetLlmqType()); + const auto& llmq_params_opt = Params().GetLLMQ(sigShare->getLlmqType()); assert(llmq_params_opt.has_value()); inv.Init(llmq_params_opt->size); } @@ -1261,7 +1261,7 @@ void CSigSharesManager::Cleanup() // Find quorums which became inactive for (auto it = quorums.begin(); it != quorums.end(); ) { - if (utils::IsQuorumActive(it->first.first, qman, it->first.second)) { + if (IsQuorumActive(it->first.first, qman, it->first.second)) { it->second = qman.GetQuorum(it->first.first, it->first.second); ++it; } else { @@ -1477,7 +1477,7 @@ void CSigSharesManager::SignPendingSigShares() auto sigShare = *opt_sigShare; ProcessSigShare(sigShare, connman, pQuorum); - if (utils::IsAllMembersConnectedEnabled(pQuorum->params.type)) { + if (IsAllMembersConnectedEnabled(pQuorum->params.type)) { LOCK(cs); auto& session = signedSessions[sigShare.GetSignHash()]; session.sigShare = sigShare; @@ -1531,12 +1531,12 @@ std::optional CSigSharesManager::CreateSigShare(const CQuorumCPtr& qu // causes all known sigShares to be re-announced void CSigSharesManager::ForceReAnnouncement(const CQuorumCPtr& quorum, Consensus::LLMQType llmqType, const uint256& id, const uint256& msgHash) { - if (utils::IsAllMembersConnectedEnabled(llmqType)) { + if (IsAllMembersConnectedEnabled(llmqType)) { return; } LOCK(cs); - auto signHash = utils::BuildSignHash(llmqType, quorum->qc->quorumHash, id, msgHash); + auto signHash = BuildSignHash(llmqType, quorum->qc->quorumHash, id, msgHash); if (const auto *const sigs = sigShares.GetAllForSignHash(signHash)) { for (const auto& [quorumMemberIndex, _] : *sigs) { // re-announce every sigshare to every node diff --git a/src/llmq/snapshot.cpp b/src/llmq/snapshot.cpp index 49ab16182209..d460d2749616 100644 --- a/src/llmq/snapshot.cpp +++ b/src/llmq/snapshot.cpp @@ -9,7 +9,6 @@ #include #include -#include #include #include @@ -137,7 +136,7 @@ bool BuildQuorumRotationInfo(const CGetQuorumRotationInfo& request, CQuorumRotat Consensus::LLMQType llmqType = Params().GetConsensus().llmqTypeDIP0024InstantSend; // Since the returned quorums are in reversed order, the most recent one is at index 0 - const auto& llmq_params_opt = GetLLMQParams(llmqType); + const auto& llmq_params_opt = Params().GetLLMQ(llmqType); assert(llmq_params_opt.has_value()); const int cycleLength = llmq_params_opt->dkgInterval; diff --git a/src/llmq/utils.cpp b/src/llmq/utils.cpp index b6dfb92de777..5f170221d8a4 100644 --- a/src/llmq/utils.cpp +++ b/src/llmq/utils.cpp @@ -4,10 +4,9 @@ #include -#include +#include #include -#include #include #include #include @@ -15,18 +14,22 @@ #include #include #include -#include #include #include #include #include #include -#include #include #include -static constexpr int TESTNET_LLMQ_25_67_ACTIVATION_HEIGHT = 847000; +class CBLSSignature; +namespace llmq +{ +class CQuorum; +using CQuorumPtr = std::shared_ptr; +using CQuorumCPtr = std::shared_ptr; +} /** * Forward declarations @@ -70,7 +73,7 @@ static std::pair GetMNUsageBySnapsho static void BuildQuorumSnapshot(const Consensus::LLMQParams& llmqParams, const CDeterministicMNList& allMns, const CDeterministicMNList& mnUsedAtH, std::vector& sortedCombinedMns, CQuorumSnapshot& quorumSnapshot, int nHeight, std::vector& skipList, const CBlockIndex* pCycleQuorumBaseBlockIndex); -uint256 GetHashModifier(const Consensus::LLMQParams& llmqParams, gsl::not_null pCycleQuorumBaseBlockIndex) +static uint256 GetHashModifier(const Consensus::LLMQParams& llmqParams, gsl::not_null pCycleQuorumBaseBlockIndex) { ASSERT_IF_DEBUG(pCycleQuorumBaseBlockIndex->nHeight % llmqParams.dkgInterval == 0); const CBlockIndex* pWorkBlockIndex = pCycleQuorumBaseBlockIndex->GetAncestor(pCycleQuorumBaseBlockIndex->nHeight - 8); @@ -100,7 +103,7 @@ std::vector GetAllQuorumMembers(Consensus::LLMQType llmqTy static std::map, StaticSaltedHasher>> mapQuorumMembers GUARDED_BY(cs_members); static RecursiveMutex cs_indexed_members; static std::map, std::vector, StaticSaltedHasher>> mapIndexedQuorumMembers GUARDED_BY(cs_indexed_members); - if (!IsQuorumTypeEnabled(llmqType, *llmq::quorumManager, pQuorumBaseBlockIndex->pprev)) { + if (!IsQuorumTypeEnabled(llmqType, pQuorumBaseBlockIndex->pprev)) { return {}; } std::vector quorumMembers; @@ -116,7 +119,7 @@ std::vector GetAllQuorumMembers(Consensus::LLMQType llmqTy } } - const auto& llmq_params_opt = GetLLMQParams(llmqType); + const auto& llmq_params_opt = Params().GetLLMQ(llmqType); assert(llmq_params_opt.has_value()); const auto& llmq_params = llmq_params_opt.value(); @@ -172,7 +175,7 @@ std::vector GetAllQuorumMembers(Consensus::LLMQType llmqTy std::vector ComputeQuorumMembers(Consensus::LLMQType llmqType, const CBlockIndex* pQuorumBaseBlockIndex) { bool EvoOnly = (Params().GetConsensus().llmqTypePlatform == llmqType) && IsV19Active(pQuorumBaseBlockIndex); - const auto& llmq_params_opt = GetLLMQParams(llmqType); + const auto& llmq_params_opt = Params().GetLLMQ(llmqType); assert(llmq_params_opt.has_value()); if (llmq_params_opt->useRotation || pQuorumBaseBlockIndex->nHeight % llmq_params_opt->dkgInterval != 0) { ASSERT_IF_DEBUG(false); @@ -631,64 +634,6 @@ std::pair GetMNUsageBySnapshot(const return std::make_pair(usedMNs, nonUsedMNs); } -uint256 BuildCommitmentHash(Consensus::LLMQType llmqType, const uint256& blockHash, - const std::vector& validMembers, const CBLSPublicKey& pubKey, - const uint256& vvecHash) -{ - CHashWriter hw(SER_GETHASH, 0); - hw << llmqType; - hw << blockHash; - hw << DYNBITSET(validMembers); - hw << pubKey; - hw << vvecHash; - return hw.GetHash(); -} - -uint256 BuildSignHash(Consensus::LLMQType llmqType, const uint256& quorumHash, const uint256& id, const uint256& msgHash) -{ - CHashWriter h(SER_GETHASH, 0); - h << llmqType; - h << quorumHash; - h << id; - h << msgHash; - return h.GetHash(); -} - -static bool EvalSpork(Consensus::LLMQType llmqType, int64_t spork_value) -{ - if (spork_value == 0) { - return true; - } - if (spork_value == 1 && llmqType != Consensus::LLMQType::LLMQ_100_67 && llmqType != Consensus::LLMQType::LLMQ_400_60 && llmqType != Consensus::LLMQType::LLMQ_400_85) { - return true; - } - return false; -} - -bool IsAllMembersConnectedEnabled(Consensus::LLMQType llmqType) -{ - return EvalSpork(llmqType, sporkManager->GetSporkValue(SPORK_21_QUORUM_ALL_CONNECTED)); -} - -bool IsQuorumPoseEnabled(Consensus::LLMQType llmqType) -{ - return EvalSpork(llmqType, sporkManager->GetSporkValue(SPORK_23_QUORUM_POSE)); -} - -bool IsQuorumRotationEnabled(const Consensus::LLMQParams& llmqParams, gsl::not_null pindex) -{ - if (!llmqParams.useRotation) { - return false; - } - - int cycleQuorumBaseHeight = pindex->nHeight - (pindex->nHeight % llmqParams.dkgInterval); - if (cycleQuorumBaseHeight < 1) { - return false; - } - // It should activate at least 1 block prior to the cycle start - return DeploymentActiveAfter(pindex->GetAncestor(cycleQuorumBaseHeight - 1), Params().GetConsensus(), Consensus::DEPLOYMENT_DIP0024); -} - uint256 DeterministicOutboundConnection(const uint256& proTxHash1, const uint256& proTxHash2) { // We need to deterministically select who is going to initiate the connection. The naive way would be to simply @@ -907,152 +852,6 @@ void AddQuorumProbeConnections(const Consensus::LLMQParams& llmqParams, gsl::not } } -bool IsQuorumActive(Consensus::LLMQType llmqType, const CQuorumManager& qman, const uint256& quorumHash) -{ - // sig shares and recovered sigs are only accepted from recent/active quorums - // we allow one more active quorum as specified in consensus, as otherwise there is a small window where things could - // fail while we are on the brink of a new quorum - const auto& llmq_params_opt = GetLLMQParams(llmqType); - assert(llmq_params_opt.has_value()); - auto quorums = qman.ScanQuorums(llmqType, llmq_params_opt->keepOldConnections); - return ranges::any_of(quorums, [&quorumHash](const auto& q){ return q->qc->quorumHash == quorumHash; }); -} - -bool IsQuorumTypeEnabled(Consensus::LLMQType llmqType, const CQuorumManager& qman, gsl::not_null pindexPrev) -{ - return IsQuorumTypeEnabledInternal(llmqType, qman, pindexPrev, std::nullopt, std::nullopt); -} - -bool IsQuorumTypeEnabledInternal(Consensus::LLMQType llmqType, const CQuorumManager& qman, gsl::not_null pindexPrev, - std::optional optDIP0024IsActive, std::optional optHaveDIP0024Quorums) -{ - const Consensus::Params& consensusParams = Params().GetConsensus(); - - const bool fDIP0024IsActive{optDIP0024IsActive.value_or(DeploymentActiveAfter(pindexPrev, consensusParams, Consensus::DEPLOYMENT_DIP0024))}; - switch (llmqType) - { - case Consensus::LLMQType::LLMQ_DEVNET: - return true; - case Consensus::LLMQType::LLMQ_50_60: - if (Params().NetworkIDString() == CBaseChainParams::TESTNET) return true; - // fall through - case Consensus::LLMQType::LLMQ_TEST_INSTANTSEND: { - if (!fDIP0024IsActive) return true; - - const bool fHaveDIP0024Quorums{optHaveDIP0024Quorums.value_or(!qman.ScanQuorums( - consensusParams.llmqTypeDIP0024InstantSend, pindexPrev, 1).empty())}; - return !fHaveDIP0024Quorums; - } - case Consensus::LLMQType::LLMQ_TEST: - case Consensus::LLMQType::LLMQ_TEST_PLATFORM: - case Consensus::LLMQType::LLMQ_400_60: - case Consensus::LLMQType::LLMQ_400_85: - case Consensus::LLMQType::LLMQ_DEVNET_PLATFORM: - return true; - - case Consensus::LLMQType::LLMQ_TEST_V17: { - return DeploymentActiveAfter(pindexPrev, consensusParams, Consensus::DEPLOYMENT_TESTDUMMY); - } - case Consensus::LLMQType::LLMQ_100_67: - return DeploymentActiveAfter(pindexPrev, consensusParams, Consensus::DEPLOYMENT_DIP0020); - - case Consensus::LLMQType::LLMQ_60_75: - case Consensus::LLMQType::LLMQ_DEVNET_DIP0024: - case Consensus::LLMQType::LLMQ_TEST_DIP0024: { - return fDIP0024IsActive; - } - case Consensus::LLMQType::LLMQ_25_67: - return pindexPrev->nHeight >= TESTNET_LLMQ_25_67_ACTIVATION_HEIGHT; - - default: - throw std::runtime_error(strprintf("%s: Unknown LLMQ type %d", __func__, ToUnderlying(llmqType))); - } - - // Something wrong with conditions above, they are not consistent - assert(false); -} - -std::vector GetEnabledQuorumTypes(gsl::not_null pindex) -{ - std::vector ret; - ret.reserve(Params().GetConsensus().llmqs.size()); - for (const auto& params : Params().GetConsensus().llmqs) { - if (IsQuorumTypeEnabled(params.type, *llmq::quorumManager, pindex)) { - ret.push_back(params.type); - } - } - return ret; -} - -std::vector> GetEnabledQuorumParams(gsl::not_null pindex) -{ - std::vector> ret; - ret.reserve(Params().GetConsensus().llmqs.size()); - - std::copy_if(Params().GetConsensus().llmqs.begin(), Params().GetConsensus().llmqs.end(), std::back_inserter(ret), - [&pindex](const auto& params){return IsQuorumTypeEnabled(params.type, *llmq::quorumManager, pindex);}); - - return ret; -} - -bool QuorumDataRecoveryEnabled() -{ - return gArgs.GetBoolArg("-llmq-data-recovery", DEFAULT_ENABLE_QUORUM_DATA_RECOVERY); -} - -bool IsWatchQuorumsEnabled() -{ - static bool fIsWatchQuroumsEnabled = gArgs.GetBoolArg("-watchquorums", DEFAULT_WATCH_QUORUMS); - return fIsWatchQuroumsEnabled; -} - -std::map GetEnabledQuorumVvecSyncEntries() -{ - std::map mapQuorumVvecSyncEntries; - for (const auto& strEntry : gArgs.GetArgs("-llmq-qvvec-sync")) { - Consensus::LLMQType llmqType = Consensus::LLMQType::LLMQ_NONE; - QvvecSyncMode mode{QvvecSyncMode::Invalid}; - std::istringstream ssEntry(strEntry); - std::string strLLMQType, strMode, strTest; - const bool fLLMQTypePresent = std::getline(ssEntry, strLLMQType, ':') && strLLMQType != ""; - const bool fModePresent = std::getline(ssEntry, strMode, ':') && strMode != ""; - const bool fTooManyEntries = static_cast(std::getline(ssEntry, strTest, ':')); - if (!fLLMQTypePresent || !fModePresent || fTooManyEntries) { - throw std::invalid_argument(strprintf("Invalid format in -llmq-qvvec-sync: %s", strEntry)); - } - - if (auto optLLMQParams = ranges::find_if_opt(Params().GetConsensus().llmqs, - [&strLLMQType](const auto& params){return params.name == strLLMQType;})) { - llmqType = optLLMQParams->type; - } else { - throw std::invalid_argument(strprintf("Invalid llmqType in -llmq-qvvec-sync: %s", strEntry)); - } - if (mapQuorumVvecSyncEntries.count(llmqType) > 0) { - throw std::invalid_argument(strprintf("Duplicated llmqType in -llmq-qvvec-sync: %s", strEntry)); - } - - int32_t nMode; - if (ParseInt32(strMode, &nMode)) { - switch (nMode) { - case (int32_t)QvvecSyncMode::Always: - mode = QvvecSyncMode::Always; - break; - case (int32_t)QvvecSyncMode::OnlyIfTypeMember: - mode = QvvecSyncMode::OnlyIfTypeMember; - break; - default: - mode = QvvecSyncMode::Invalid; - break; - } - } - if (mode == QvvecSyncMode::Invalid) { - throw std::invalid_argument(strprintf("Invalid mode in -llmq-qvvec-sync: %s", strEntry)); - } - mapQuorumVvecSyncEntries.emplace(llmqType, mode); - } - return mapQuorumVvecSyncEntries; -} - template void InitQuorumsCache(CacheType& cache, bool limit_by_connections) { @@ -1069,9 +868,4 @@ template void InitQuorumsCache GetLLMQParams(Consensus::LLMQType llmqType) -{ - return Params().GetLLMQ(llmqType); -} - } // namespace llmq diff --git a/src/llmq/utils.h b/src/llmq/utils.h index a19e1981d769..08db78467c4b 100644 --- a/src/llmq/utils.h +++ b/src/llmq/utils.h @@ -5,15 +5,13 @@ #ifndef BITCOIN_LLMQ_UTILS_H #define BITCOIN_LLMQ_UTILS_H -#include - -#include -#include +#include #include -#include #include +#include -#include +#include +#include #include class CConnman; @@ -21,34 +19,16 @@ class CBlockIndex; class CDeterministicMN; class CDeterministicMNList; using CDeterministicMNCPtr = std::shared_ptr; -class CBLSPublicKey; namespace llmq { -class CQuorumManager; -class CQuorumSnapshot; - -static const bool DEFAULT_ENABLE_QUORUM_DATA_RECOVERY = true; - -enum class QvvecSyncMode { - Invalid = -1, - Always = 0, - OnlyIfTypeMember = 1, -}; - namespace utils { // includes members which failed DKG std::vector GetAllQuorumMembers(Consensus::LLMQType llmqType, gsl::not_null pQuorumBaseBlockIndex, bool reset_cache = false); -uint256 GetHashModifier(const Consensus::LLMQParams& llmqParams, gsl::not_null pCycleQuorumBaseBlockIndex); -uint256 BuildCommitmentHash(Consensus::LLMQType llmqType, const uint256& blockHash, const std::vector& validMembers, const CBLSPublicKey& pubKey, const uint256& vvecHash); -uint256 BuildSignHash(Consensus::LLMQType llmqType, const uint256& quorumHash, const uint256& id, const uint256& msgHash); - -bool IsAllMembersConnectedEnabled(Consensus::LLMQType llmqType); -bool IsQuorumPoseEnabled(Consensus::LLMQType llmqType); uint256 DeterministicOutboundConnection(const uint256& proTxHash1, const uint256& proTxHash2); std::set GetQuorumConnections(const Consensus::LLMQParams& llmqParams, gsl::not_null pQuorumBaseBlockIndex, const uint256& forMember, bool onlyOutbound); std::set GetQuorumRelayMembers(const Consensus::LLMQParams& llmqParams, gsl::not_null pQuorumBaseBlockIndex, const uint256& forMember, bool onlyOutbound); @@ -57,72 +37,11 @@ std::set CalcDeterministicWatchConnections(Consensus::LLMQType llmqType, bool EnsureQuorumConnections(const Consensus::LLMQParams& llmqParams, gsl::not_null pQuorumBaseBlockIndex, CConnman& connman, const uint256& myProTxHash); void AddQuorumProbeConnections(const Consensus::LLMQParams& llmqParams, gsl::not_null pQuorumBaseBlockIndex, CConnman& connman, const uint256& myProTxHash); -bool IsQuorumActive(Consensus::LLMQType llmqType, const CQuorumManager& qman, const uint256& quorumHash); -bool IsQuorumTypeEnabled(Consensus::LLMQType llmqType, const CQuorumManager& qman, gsl::not_null pindexPrev); -bool IsQuorumTypeEnabledInternal(Consensus::LLMQType llmqType, const CQuorumManager& qman, gsl::not_null pindexPrev, std::optional optDIP0024IsActive, std::optional optHaveDIP0024Quorums); - -std::vector GetEnabledQuorumTypes(gsl::not_null pindex); -std::vector> GetEnabledQuorumParams(gsl::not_null pindex); - -bool IsQuorumRotationEnabled(const Consensus::LLMQParams& llmqParams, gsl::not_null pindex); - -/// Returns the state of `-llmq-data-recovery` -bool QuorumDataRecoveryEnabled(); - -/// Returns the state of `-watchquorums` -bool IsWatchQuorumsEnabled(); - -/// Returns the parsed entries given by `-llmq-qvvec-sync` -std::map GetEnabledQuorumVvecSyncEntries(); - -template -void IterateNodesRandom(NodesContainer& nodeStates, Continue&& cont, Callback&& callback, FastRandomContext& rnd) -{ - std::vector rndNodes; - rndNodes.reserve(nodeStates.size()); - for (auto it = nodeStates.begin(); it != nodeStates.end(); ++it) { - rndNodes.emplace_back(it); - } - if (rndNodes.empty()) { - return; - } - Shuffle(rndNodes.begin(), rndNodes.end(), rnd); - - size_t idx = 0; - while (!rndNodes.empty() && cont()) { - auto nodeId = rndNodes[idx]->first; - auto& ns = rndNodes[idx]->second; - - if (callback(nodeId, ns)) { - idx = (idx + 1) % rndNodes.size(); - } else { - rndNodes.erase(rndNodes.begin() + idx); - if (rndNodes.empty()) { - break; - } - idx %= rndNodes.size(); - } - } -} - template void InitQuorumsCache(CacheType& cache, bool limit_by_connections = true); -[[ nodiscard ]] static constexpr int max_cycles(const Consensus::LLMQParams& llmqParams, int quorums_count) -{ - return llmqParams.useRotation ? quorums_count / llmqParams.signingActiveQuorumCount : quorums_count; -} - -[[ nodiscard ]] static constexpr int max_store_depth(const Consensus::LLMQParams& llmqParams) -{ - // For how many blocks recent DKG info should be kept - return max_cycles(llmqParams, llmqParams.keepOldKeys) * llmqParams.dkgInterval; -} - } // namespace utils -[[ nodiscard ]] const std::optional GetLLMQParams(Consensus::LLMQType llmqType); - } // namespace llmq #endif // BITCOIN_LLMQ_UTILS_H diff --git a/src/miner.cpp b/src/miner.cpp index 54f629fe9263..05c867851ccf 100644 --- a/src/miner.cpp +++ b/src/miner.cpp @@ -32,7 +32,7 @@ #include #include #include -#include +#include #include #include #include @@ -156,7 +156,7 @@ std::unique_ptr BlockAssembler::CreateNewBlock(const CScript& sc : pblock->GetBlockTime(); if (fDIP0003Active_context) { - for (const Consensus::LLMQParams& params : llmq::utils::GetEnabledQuorumParams(pindexPrev)) { + for (const Consensus::LLMQParams& params : llmq::GetEnabledQuorumParams(pindexPrev)) { std::vector vqcTx; if (quorum_block_processor.GetMineableCommitmentsTx(params, nHeight, diff --git a/src/net_processing.cpp b/src/net_processing.cpp index f2889fbbe3de..b8836fb3a224 100644 --- a/src/net_processing.cpp +++ b/src/net_processing.cpp @@ -57,6 +57,7 @@ #include #include #include +#include #include #include #include @@ -3085,7 +3086,7 @@ void PeerManagerImpl::ProcessMessage( // Tell our peer that he should send us CoinJoin queue messages m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::SENDDSQUEUE, true)); // Tell our peer that he should send us intra-quorum messages - if (llmq::utils::IsWatchQuorumsEnabled() && m_connman.IsMasternodeQuorumNode(&pfrom)) { + if (llmq::IsWatchQuorumsEnabled() && m_connman.IsMasternodeQuorumNode(&pfrom)) { m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::QWATCH)); } } @@ -4353,7 +4354,7 @@ void PeerManagerImpl::ProcessMessage( ProcessPeerMsgRet(m_govman.ProcessMessage(pfrom, m_connman, msg_type, vRecv), pfrom); ProcessPeerMsgRet(CMNAuth::ProcessMessage(pfrom, m_connman, msg_type, vRecv), pfrom); ProcessPeerMsgRet(m_llmq_ctx->quorum_block_processor->ProcessMessage(pfrom, msg_type, vRecv), pfrom); - m_llmq_ctx->qdkgsman->ProcessMessage(pfrom, *m_llmq_ctx->qman, msg_type, vRecv); + m_llmq_ctx->qdkgsman->ProcessMessage(pfrom, msg_type, vRecv); ProcessPeerMsgRet(m_llmq_ctx->qman->ProcessMessage(pfrom, msg_type, vRecv), pfrom); m_llmq_ctx->shareman->ProcessMessage(pfrom, *sporkManager, msg_type, vRecv); m_llmq_ctx->sigman->ProcessMessage(pfrom, msg_type, vRecv); diff --git a/src/rpc/quorums.cpp b/src/rpc/quorums.cpp index 40b80142b408..37059788f1fb 100644 --- a/src/rpc/quorums.cpp +++ b/src/rpc/quorums.cpp @@ -20,10 +20,12 @@ #include #include #include +#include #include #include #include #include +#include #include #include @@ -74,8 +76,8 @@ static UniValue quorum_list(const JSONRPCRequest& request, const ChainstateManag CBlockIndex* pindexTip = WITH_LOCK(cs_main, return chainman.ActiveChain().Tip()); - for (const auto& type : llmq::utils::GetEnabledQuorumTypes(pindexTip)) { - const auto& llmq_params_opt = llmq::GetLLMQParams(type); + for (const auto& type : llmq::GetEnabledQuorumTypes(pindexTip)) { + const auto& llmq_params_opt = Params().GetLLMQ(type); CHECK_NONFATAL(llmq_params_opt.has_value()); UniValue v(UniValue::VARR); @@ -139,8 +141,8 @@ static UniValue quorum_list_extended(const JSONRPCRequest& request, const Chains CBlockIndex* pblockindex = nHeight != -1 ? WITH_LOCK(cs_main, return chainman.ActiveChain()[nHeight]) : WITH_LOCK(cs_main, return chainman.ActiveChain().Tip()); - for (const auto& type : llmq::utils::GetEnabledQuorumTypes(pblockindex)) { - const auto& llmq_params_opt = llmq::GetLLMQParams(type); + for (const auto& type : llmq::GetEnabledQuorumTypes(pblockindex)) { + const auto& llmq_params_opt = Params().GetLLMQ(type); CHECK_NONFATAL(llmq_params_opt.has_value()); const auto& llmq_params = llmq_params_opt.value(); UniValue v(UniValue::VARR); @@ -240,7 +242,7 @@ static UniValue quorum_info(const JSONRPCRequest& request, const LLMQContext& ll quorum_info_help(request); Consensus::LLMQType llmqType = (Consensus::LLMQType)ParseInt32V(request.params[0], "llmqType"); - if (!llmq::GetLLMQParams(llmqType).has_value()) { + if (!Params().GetLLMQ(llmqType).has_value()) { throw JSONRPCError(RPC_INVALID_PARAMETER, "invalid LLMQ type"); } @@ -297,11 +299,11 @@ static UniValue quorum_dkgstatus(const JSONRPCRequest& request, const Chainstate UniValue minableCommitments(UniValue::VARR); UniValue quorumArrConnections(UniValue::VARR); - for (const auto& type : llmq::utils::GetEnabledQuorumTypes(pindexTip)) { - const auto& llmq_params_opt = llmq::GetLLMQParams(type); + for (const auto& type : llmq::GetEnabledQuorumTypes(pindexTip)) { + const auto& llmq_params_opt = Params().GetLLMQ(type); CHECK_NONFATAL(llmq_params_opt.has_value()); const auto& llmq_params = llmq_params_opt.value(); - bool rotation_enabled = llmq::utils::IsQuorumRotationEnabled(llmq_params, pindexTip); + bool rotation_enabled = llmq::IsQuorumRotationEnabled(llmq_params, pindexTip); int quorums_num = rotation_enabled ? llmq_params.signingActiveQuorumCount : 1; for (const int quorumIndex : irange::range(quorums_num)) { @@ -401,8 +403,8 @@ static UniValue quorum_memberof(const JSONRPCRequest& request, const ChainstateM } UniValue result(UniValue::VARR); - for (const auto& type : llmq::utils::GetEnabledQuorumTypes(pindexTip)) { - const auto& llmq_params_opt = llmq::GetLLMQParams(type); + for (const auto& type : llmq::GetEnabledQuorumTypes(pindexTip)) { + const auto& llmq_params_opt = Params().GetLLMQ(type); CHECK_NONFATAL(llmq_params_opt.has_value()); size_t count = llmq_params_opt->signingActiveQuorumCount; if (scanQuorumsCount != -1) { @@ -524,7 +526,7 @@ static UniValue quorum_sigs_cmd(const JSONRPCRequest& request, const LLMQContext Consensus::LLMQType llmqType = (Consensus::LLMQType)ParseInt32V(request.params[0], "llmqType"); - const auto& llmq_params_opt = llmq::GetLLMQParams(llmqType); + const auto& llmq_params_opt = Params().GetLLMQ(llmqType); if (!llmq_params_opt.has_value()) { throw JSONRPCError(RPC_INVALID_PARAMETER, "invalid LLMQ type"); } @@ -597,7 +599,7 @@ static UniValue quorum_sigs_cmd(const JSONRPCRequest& request, const LLMQContext throw JSONRPCError(RPC_INVALID_PARAMETER, "quorum not found"); } - uint256 signHash = llmq::utils::BuildSignHash(llmqType, quorum->qc->quorumHash, id, msgHash); + uint256 signHash = llmq::BuildSignHash(llmqType, quorum->qc->quorumHash, id, msgHash); return sig.VerifyInsecure(quorum->qc->quorumPublicKey, signHash); } } else if (cmd == "quorumhasrecsig") { @@ -637,7 +639,7 @@ static UniValue quorum_selectquorum(const JSONRPCRequest& request, const LLMQCon quorum_selectquorum_help(request); Consensus::LLMQType llmqType = (Consensus::LLMQType)ParseInt32V(request.params[0], "llmqType"); - const auto& llmq_params_opt = llmq::GetLLMQParams(llmqType); + const auto& llmq_params_opt = Params().GetLLMQ(llmqType); if (!llmq_params_opt.has_value()) { throw JSONRPCError(RPC_INVALID_PARAMETER, "invalid LLMQ type"); } @@ -986,7 +988,7 @@ static UniValue verifyislock(const JSONRPCRequest& request) auto llmqType = Params().GetConsensus().llmqTypeDIP0024InstantSend; // First check against the current active set, if it fails check against the last active set - const auto& llmq_params_opt = llmq::GetLLMQParams(llmqType); + const auto& llmq_params_opt = Params().GetLLMQ(llmqType); CHECK_NONFATAL(llmq_params_opt.has_value()); int signOffset{llmq_params_opt->dkgInterval}; return llmq_ctx.sigman->VerifyRecoveredSig(llmqType, *llmq_ctx.qman, signHeight, id, txid, sig, 0) || diff --git a/src/rpc/rawtransaction.cpp b/src/rpc/rawtransaction.cpp index 72586fcb7d40..fc19beb11a82 100644 --- a/src/rpc/rawtransaction.cpp +++ b/src/rpc/rawtransaction.cpp @@ -48,7 +48,6 @@ #include #include #include -#include #include #include diff --git a/src/test/evo_utils_tests.cpp b/src/test/evo_utils_tests.cpp index dcf4e95fed63..1810f5aef14e 100644 --- a/src/test/evo_utils_tests.cpp +++ b/src/test/evo_utils_tests.cpp @@ -4,10 +4,8 @@ #include -#include #include -#include -#include +#include #include @@ -15,38 +13,32 @@ #include -/* TODO: rename this file and test to llmq_utils_test */ +/* TODO: rename this file and test to llmq_options_test */ BOOST_AUTO_TEST_SUITE(evo_utils_tests) -void Test(llmq::CQuorumManager& qman, NodeContext& node) +void Test(NodeContext& node) { - using namespace llmq::utils; + using namespace llmq; auto tip = node.chainman->ActiveTip(); const auto& consensus_params = Params().GetConsensus(); - BOOST_CHECK_EQUAL(IsQuorumTypeEnabledInternal(consensus_params.llmqTypeDIP0024InstantSend, qman, tip, false, false), false); - BOOST_CHECK_EQUAL(IsQuorumTypeEnabledInternal(consensus_params.llmqTypeDIP0024InstantSend, qman, tip, true, false), true); - BOOST_CHECK_EQUAL(IsQuorumTypeEnabledInternal(consensus_params.llmqTypeDIP0024InstantSend, qman, tip, true, true), true); - BOOST_CHECK_EQUAL(IsQuorumTypeEnabledInternal(consensus_params.llmqTypeChainLocks, qman, tip, false, false), true); - BOOST_CHECK_EQUAL(IsQuorumTypeEnabledInternal(consensus_params.llmqTypeChainLocks, qman, tip, true, false), true); - BOOST_CHECK_EQUAL(IsQuorumTypeEnabledInternal(consensus_params.llmqTypeChainLocks, qman, tip, true, true), true); - BOOST_CHECK_EQUAL(IsQuorumTypeEnabledInternal(consensus_params.llmqTypePlatform, qman, tip, false, false), Params().IsTestChain()); - BOOST_CHECK_EQUAL(IsQuorumTypeEnabledInternal(consensus_params.llmqTypePlatform, qman, tip, true, false), Params().IsTestChain()); - BOOST_CHECK_EQUAL(IsQuorumTypeEnabledInternal(consensus_params.llmqTypePlatform, qman, tip, true, true), Params().IsTestChain()); - BOOST_CHECK_EQUAL(IsQuorumTypeEnabledInternal(consensus_params.llmqTypeMnhf, qman, tip, false, false), true); - BOOST_CHECK_EQUAL(IsQuorumTypeEnabledInternal(consensus_params.llmqTypeMnhf, qman, tip, true, false), true); - BOOST_CHECK_EQUAL(IsQuorumTypeEnabledInternal(consensus_params.llmqTypeMnhf, qman, tip, true, true), true); + BOOST_CHECK_EQUAL(IsQuorumTypeEnabledInternal(consensus_params.llmqTypeDIP0024InstantSend, tip, false), false); + BOOST_CHECK_EQUAL(IsQuorumTypeEnabledInternal(consensus_params.llmqTypeDIP0024InstantSend, tip, true), true); + BOOST_CHECK_EQUAL(IsQuorumTypeEnabledInternal(consensus_params.llmqTypeChainLocks, tip, false ), true); + BOOST_CHECK_EQUAL(IsQuorumTypeEnabledInternal(consensus_params.llmqTypeChainLocks, tip, true), true); + BOOST_CHECK_EQUAL(IsQuorumTypeEnabledInternal(consensus_params.llmqTypePlatform, tip, false), Params().IsTestChain()); + BOOST_CHECK_EQUAL(IsQuorumTypeEnabledInternal(consensus_params.llmqTypePlatform, tip, true), Params().IsTestChain()); + BOOST_CHECK_EQUAL(IsQuorumTypeEnabledInternal(consensus_params.llmqTypeMnhf, tip, false), true); + BOOST_CHECK_EQUAL(IsQuorumTypeEnabledInternal(consensus_params.llmqTypeMnhf, tip, true), true); } BOOST_FIXTURE_TEST_CASE(utils_IsQuorumTypeEnabled_tests_regtest, RegTestingSetup) { - assert(m_node.llmq_ctx->qman); - Test(*m_node.llmq_ctx->qman, m_node); + Test(m_node); } BOOST_FIXTURE_TEST_CASE(utils_IsQuorumTypeEnabled_tests_mainnet, TestingSetup) { - assert(m_node.llmq_ctx->qman); - Test(*m_node.llmq_ctx->qman, m_node); + Test(m_node); } BOOST_AUTO_TEST_SUITE_END() diff --git a/test/functional/feature_llmq_rotation.py b/test/functional/feature_llmq_rotation.py index b7308fdaf697..54e05709322d 100755 --- a/test/functional/feature_llmq_rotation.py +++ b/test/functional/feature_llmq_rotation.py @@ -158,13 +158,12 @@ def run_test(self): q_100_0 = QuorumId(100, int(quorum_info_0_0["quorumHash"], 16)) q_102_0 = QuorumId(102, int(quorum_info_0_0["quorumHash"], 16)) - q_104_0 = QuorumId(104, int(quorum_info_0_0["quorumHash"], 16)) q_103_0_0 = QuorumId(103, int(quorum_info_0_0["quorumHash"], 16)) q_103_0_1 = QuorumId(103, int(quorum_info_0_1["quorumHash"], 16)) b_1 = self.nodes[0].getbestblockhash() - expectedDeleted = [h_100_0, h_104_0] - expectedNew = [q_100_0, q_102_0, q_104_0, q_103_0_0, q_103_0_1] + expectedDeleted = [h_100_0] + expectedNew = [q_100_0, q_102_0, q_103_0_0, q_103_0_1] quorumList = self.test_getmnlistdiff_quorums(b_0, b_1, quorumList, expectedDeleted, expectedNew) self.log.info("Wait for chainlock") diff --git a/test/lint/lint-circular-dependencies.sh b/test/lint/lint-circular-dependencies.sh index d60ad8960e82..8ac4c0d8beff 100755 --- a/test/lint/lint-circular-dependencies.sh +++ b/test/lint/lint-circular-dependencies.sh @@ -33,10 +33,10 @@ EXPECTED_CIRCULAR_DEPENDENCIES=( "governance/classes -> governance/governance -> governance/classes" "governance/governance -> governance/object -> governance/governance" "governance/governance -> masternode/sync -> governance/governance" - "llmq/quorums -> llmq/utils -> llmq/quorums" "llmq/chainlocks -> llmq/instantsend -> llmq/chainlocks" "llmq/chainlocks -> llmq/instantsend -> net_processing -> llmq/chainlocks" "llmq/dkgsessionmgr -> net_processing -> llmq/dkgsessionmgr" + "llmq/dkgsessionmgr -> net_processing -> llmq/quorums -> llmq/dkgsessionmgr" "llmq/instantsend -> net_processing -> llmq/instantsend" "llmq/instantsend -> txmempool -> llmq/instantsend" "llmq/instantsend -> validation -> llmq/instantsend" @@ -74,6 +74,7 @@ EXPECTED_CIRCULAR_DEPENDENCIES=( "llmq/dkgsession -> llmq/dkgsessionmgr -> llmq/dkgsession" "llmq/chainlocks -> validation -> llmq/chainlocks" "coinjoin/coinjoin -> llmq/chainlocks -> net -> coinjoin/coinjoin" + "evo/deterministicmns -> llmq/utils -> llmq/snapshot -> evo/simplifiedmns -> evo/deterministicmns" "evo/deterministicmns -> llmq/utils -> net -> evo/deterministicmns" "policy/policy -> policy/settings -> policy/policy" "evo/specialtxman -> validation -> evo/specialtxman" @@ -81,10 +82,11 @@ EXPECTED_CIRCULAR_DEPENDENCIES=( "consensus/tx_verify -> evo/assetlocktx -> llmq/signing -> net_processing -> txmempool -> consensus/tx_verify" "evo/assetlocktx -> llmq/signing -> net_processing -> txmempool -> evo/assetlocktx" + "evo/simplifiedmns -> llmq/blockprocessor -> llmq/utils -> llmq/snapshot -> evo/simplifiedmns" + "llmq/blockprocessor -> llmq/utils -> llmq/snapshot -> llmq/blockprocessor" "llmq/context -> llmq/dkgsessionmgr -> net_processing -> llmq/context" - "llmq/dkgsession -> llmq/dkgsessionmgr -> llmq/quorums -> llmq/dkgsession" - "llmq/dkgsessionmgr -> llmq/quorums -> llmq/dkgsessionmgr" - "llmq/snapshot -> llmq/utils -> llmq/snapshot" + "llmq/dkgsession -> llmq/dkgsessionmgr -> net_processing -> llmq/quorums -> llmq/dkgsession" + "llmq/commitment -> llmq/utils -> llmq/snapshot -> llmq/commitment" "spork -> validation -> spork" "governance/governance -> validation -> governance/governance" "evo/deterministicmns -> validationinterface -> governance/vote -> evo/deterministicmns"